<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Ai on elonnzhang</title><link>https://jiabin.dev/categories/ai/</link><description>Recent content in Ai on elonnzhang</description><generator>Hugo</generator><language>zh-CN</language><lastBuildDate>Wed, 23 Sep 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://jiabin.dev/categories/ai/index.xml" rel="self" type="application/rss+xml"/><item><title>Agent Development Kit (ADK) · 13 - Session Vertex AI</title><link>https://jiabin.dev/blog/adk-session-vertexai/</link><pubDate>Wed, 23 Sep 2026 00:00:00 +0800</pubDate><guid>https://jiabin.dev/blog/adk-session-vertexai/</guid><description>&lt;h1 id="adk-go-源码阅读笔记--vertex-ai-session远端后端怎样保持-session-契约"&gt;ADK-Go 源码阅读笔记 · Vertex AI Session：远端后端怎样保持 Session 契约&lt;/h1&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;源码基准：&lt;a href="https://github.com/google/adk-go/tree/v2.4.0"&gt;ADK-Go v2.4.0&lt;/a&gt;&lt;/strong&gt;，commit &lt;code&gt;4e57df40cbd35f055ba654b03ffb0e509fdd754a&lt;/code&gt;。以下“当前实现”均指此版本。&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://jiabin.dev/blog/adk/"&gt;返回 ADK 源码阅读合集&lt;/a&gt; · 前置阅读：&lt;a href="https://jiabin.dev/blog/adk-session-event/"&gt;Session、Event 与 State&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-session-inmemory/"&gt;InMemory&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-session-database/"&gt;Database&lt;/a&gt; · 配套阅读：&lt;a href="https://jiabin.dev/blog/adk-runner/"&gt;Runner&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-server/"&gt;Server&lt;/a&gt;。&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;&lt;code&gt;session.Service&lt;/code&gt; 是 Runner 依赖的抽象，但不同后端并不提供相同的性能和事务语义。InMemory 把对象放在进程内，Database 把对象编码进本地数据库；&lt;code&gt;session/vertexai&lt;/code&gt; 则把 Session、Event 和 State 映射到 Vertex AI Agent Engine 的 RPC。&lt;/p&gt;&#10;&lt;p&gt;这篇文章只追踪这个适配层，不把 Agent Engine 当成另一个 Runner。Runner 仍然负责 invocation 和事件消费，Vertex AI service 负责远端 Session 的创建、读取、列举、删除及追加。&lt;/p&gt;&#10;&lt;h2 id="一源码入口与阅读地图"&gt;一、源码入口与阅读地图&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;入口&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;源码&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;要回答的问题&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;构造&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/session/vertexai/vertexai.go#L34-L56"&gt;&lt;code&gt;session/vertexai/vertexai.go#L34-L56&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Project、Location、ReasoningEngine 怎样变成 Service？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Service&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/session/vertexai/vertexai.go#L58-L155"&gt;&lt;code&gt;vertexai.go#L58-L155&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;五个公开操作如何委托远端 client？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;本地句柄&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/session/vertexai/session.go#L29-L91"&gt;&lt;code&gt;session.go#L29-L91&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;远端 Session 返回后，Runner 持有的对象保存什么？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;State&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/session/vertexai/session.go#L116-L154"&gt;&lt;code&gt;session.go#L116-L154&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;State 的读写是否需要再次 RPC？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;RPC 映射&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/session/vertexai/vertexai_client.go#L69-L110"&gt;&lt;code&gt;vertexai_client.go#L69-L110&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Create 如何映射 Agent Engine resource？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Get 并发&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/session/vertexai/vertexai.go#L69-L114"&gt;&lt;code&gt;vertexai.go#L69-L114&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Session 元数据和 Events 如何同时读取？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;runner.Run&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ session.Service&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ▼&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vertexAiService&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├─ vertexAiClient.Get/Create/List/Delete&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├─ Vertex AI Agent Engine RPC&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └─ localSession（本地句柄与快照）&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├─ State() → 本地 map + mutex&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └─ Events() → 本地切片快照&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="二接口与数据远端资源加本地句柄"&gt;二、接口与数据：远端资源加本地句柄&lt;/h2&gt;&#10;&lt;h3 id="1-配置中的-appname-不是-reasoning-engine-id"&gt;1. 配置中的 AppName 不是 Reasoning Engine ID&lt;/h3&gt;&#10;&lt;p&gt;&lt;code&gt;VertexAIServiceConfig&lt;/code&gt; 要求 ProjectID、Location 和 ReasoningEngine。创建 Session 时，client 会根据 &lt;code&gt;req.AppName&lt;/code&gt; 解析对应的 Agent Engine resource，再把 &lt;code&gt;req.UserID&lt;/code&gt;、初始 State 和可选 SessionID 转成 &lt;code&gt;CreateSessionRequest&lt;/code&gt;（&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/session/vertexai/vertexai_client.go#L69-L105"&gt;&lt;code&gt;vertexai_client.go#L69-L105&lt;/code&gt;&lt;/a&gt;）。因此一个 service 可以服务多个 app，但每个 app 必须能解析到自己的 reasoning engine。&lt;/p&gt;</description></item><item><title>Agent Development Kit (ADK) · 20 - Auth、Telemetry 与 Platform</title><link>https://jiabin.dev/blog/adk-infrastructure/</link><pubDate>Wed, 23 Sep 2026 00:00:00 +0800</pubDate><guid>https://jiabin.dev/blog/adk-infrastructure/</guid><description>&lt;h1 id="adk-go-源码阅读笔记--authtelemetry-与-platform横切能力怎样进入一次运行"&gt;ADK-Go 源码阅读笔记 · Auth、Telemetry 与 Platform：横切能力怎样进入一次运行&lt;/h1&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;源码基准：&lt;a href="https://github.com/google/adk-go/tree/v2.4.0"&gt;ADK-Go v2.4.0&lt;/a&gt;&lt;/strong&gt;，commit &lt;code&gt;4e57df40cbd35f055ba654b03ffb0e509fdd754a&lt;/code&gt;。本文的“当前实现”均指这个版本。&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://jiabin.dev/blog/adk/"&gt;返回 ADK 源码阅读合集&lt;/a&gt; · 配套阅读：&lt;a href="https://jiabin.dev/blog/adk-runner/"&gt;Runner&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-context/"&gt;Context&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-plugin/"&gt;Plugin&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-server/"&gt;Server&lt;/a&gt;。&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;ADK 的主链文章通常从 Runner 开始：取得 Session，运行 Agent，保存 Event。但真实应用还要解决三类横切问题：工具访问外部服务时用谁的凭据，运行过程怎样被观测，以及事件里的时间戳和 ID 怎样在测试中变得可控。&lt;/p&gt;&#10;&lt;p&gt;这三件事分别落在 &lt;code&gt;auth&lt;/code&gt;、&lt;code&gt;telemetry&lt;/code&gt; 和 &lt;code&gt;platform&lt;/code&gt; 包。它们都不负责调用模型，也不拥有 Session；它们通过接口和 &lt;code&gt;context.Context&lt;/code&gt; 进入调用树，把能力交给真正的请求、事件或服务。&lt;/p&gt;&#10;&lt;p&gt;&lt;span class="ann ann-n ann-amber" data-note="横切能力不是隐式全局状态"&gt;凭据和测试 provider 都沿着 context 或对象边界传递&lt;/span&gt;。因此“配置了 ADC”不等于每个 HTTP 请求都会自动带 token，“初始化了 Telemetry”也不等于已经注册成全局 provider。&lt;/p&gt;&#10;&lt;h2 id="阅读前先分清三个层次"&gt;阅读前先分清三个层次&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;层次&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;负责什么&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;不负责什么&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;auth.CredentialProvider&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;在一次请求上下文中解析可用凭据&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不发送 HTTP 请求&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;auth.Credential&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;把已解析凭据写入 HTTP headers&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不决定何时刷新或重试&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;auth.Transport&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;每次 &lt;code&gt;RoundTrip&lt;/code&gt; 解析并应用凭据&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不替调用方管理用户授权&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;telemetry.Providers&lt;/code&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;持有 OTel tracer/logger provider，注册和关闭&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不自动创建业务 span&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;code&gt;platform&lt;/code&gt; provider&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;为当前 context 提供时间、UUID 和任务调度策略&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不改变包级默认行为&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="一源码入口与阅读地图"&gt;一、源码入口与阅读地图&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;阅读顺序&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;源码&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;要回答的问题&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/auth/credential.go#L25-L120"&gt;&lt;code&gt;auth/credential.go#L25-L120&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;一个凭据怎样写到请求头？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;2&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/auth/providers.go#L29-L178"&gt;&lt;code&gt;auth/providers.go#L29-L178&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Static token、ADC、Service Account 的解析边界是什么？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;3&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/auth/transport.go#L22-L75"&gt;&lt;code&gt;auth/transport.go#L22-L75&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;provider 何时被调用，Request 是否会被原地修改？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;4&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/telemetry/telemetry.go#L28-L119"&gt;&lt;code&gt;telemetry/telemetry.go#L28-L119&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;OTel provider 怎样创建、注册和关闭？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;5&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/telemetry/config.go#L55-L136"&gt;&lt;code&gt;telemetry/config.go#L55-L136&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Cloud 导出和自定义 processor 怎样组合？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;6&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/platform/time.go#L22-L50"&gt;&lt;code&gt;platform/time.go#L22-L50&lt;/code&gt;&lt;/a&gt;、&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/platform/uuid.go#L23-L52"&gt;&lt;code&gt;uuid.go#L23-L52&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;时间和 ID 的 provider 如何只影响当前调用树？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;7&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/platform/exec.go#L22-L94"&gt;&lt;code&gt;platform/exec.go#L22-L94&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;模型工具并发怎样替换为宿主自己的 TaskRunner？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;8&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/auth/gcp/client.go#L203-L370"&gt;&lt;code&gt;auth/gcp/client.go#L203-L370&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Agent Identity / IAM Connector 的 transport client 如何轮询和映射凭据？&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;agent.Context / request.Context&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── auth.Transport.RoundTrip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ├─ CredentialProvider.Credential&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ├─ Credential.Apply&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ └─ Base.RoundTrip&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── session.NewEvent / other ADK code&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ├─ platform.Now(ctx)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ └─ platform.NewUUID(ctx)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── telemetry.New → Providers.SetGlobalOtelProviders&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └─ Providers.Shutdown&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="二核心接口与数据"&gt;二、核心接口与数据&lt;/h2&gt;&#10;&lt;h3 id="1-providercredentialtransport-是三次分工"&gt;1. Provider、Credential、Transport 是三次分工&lt;/h3&gt;&#10;&lt;p&gt;&lt;code&gt;CredentialProvider&lt;/code&gt; 只返回一个实现 &lt;code&gt;Apply(http.Header)&lt;/code&gt; 的 &lt;code&gt;Credential&lt;/code&gt;。例如 &lt;code&gt;BearerCredential&lt;/code&gt; 设置 &lt;code&gt;Authorization: Bearer ...&lt;/code&gt;，&lt;code&gt;APIKeyCredential&lt;/code&gt; 设置调用方指定的 header；&lt;code&gt;OAuth2Credential&lt;/code&gt; 则在每次 &lt;code&gt;Apply&lt;/code&gt; 时从 &lt;code&gt;TokenSource&lt;/code&gt; 取得 token（&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/auth/credential.go#L47-L95"&gt;&lt;code&gt;credential.go#L47-L95&lt;/code&gt;&lt;/a&gt;）。&lt;/p&gt;</description></item><item><title>Agent Development Kit (ADK) · 06 - Runner</title><link>https://jiabin.dev/blog/adk-runner/</link><pubDate>Mon, 21 Sep 2026 00:00:00 +0800</pubDate><guid>https://jiabin.dev/blog/adk-runner/</guid><description>&lt;h1 id="adk-go-源码阅读笔记--runner一次输入的执行持久化与恢复"&gt;ADK-Go 源码阅读笔记 · Runner：一次输入的执行、持久化与恢复&lt;/h1&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;源码基准：&lt;a href="https://github.com/google/adk-go/tree/v2.4.0"&gt;ADK-Go v2.4.0&lt;/a&gt;&lt;/strong&gt;，commit &lt;code&gt;4e57df40cbd35f055ba654b03ffb0e509fdd754a&lt;/code&gt;。本文的“当前实现”均指这个版本。&lt;/p&gt;&#10;&lt;p&gt;范围：普通 Run 的两条执行路径、消息与 Plugin、HITL、Live 和 Context Compaction。模型与工具内部循环见 Flow，数据库内部存储见 Session 配套文章。&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://jiabin.dev/blog/adk/"&gt;返回 ADK 源码阅读合集&lt;/a&gt; · 配套阅读：&lt;a href="https://jiabin.dev/blog/adk-agent/"&gt;Agent&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-flow/"&gt;Flow&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-context/"&gt;Context&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-plugin/"&gt;Plugin&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-workflow/"&gt;Workflow&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-session-event/"&gt;Session Event&lt;/a&gt;。&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;用户问“杭州天气怎么样”，Agent 可以调用工具并产出答案，但应用还需要决定：这条输入属于哪个会话、由哪个 Agent 接着回答、工具结果何时保存、用户确认回来后从哪里继续，以及前端断开后还执行哪些收尾。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Runner 把输入、运行环境、事件持久化和恢复入口接成一条调用链。&lt;/strong&gt; 它不直接实现模型推理，却决定 Agent 产生的记录怎样进入 Session、怎样经过 Plugin、怎样交到调用方。&lt;/p&gt;&#10;&lt;p&gt;本文回答三个问题：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;Runner 为一次输入创建哪些对象，它们被谁读取和修改？&lt;/li&gt;&#10;&lt;li&gt;用户消息、模型 FunctionCall、工具结果、最终答案如何按序保存并流出？&lt;/li&gt;&#10;&lt;li&gt;错误、提前停止、长任务恢复、Live 和压缩分别改变哪一段协议？&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="阅读前先分清这些词"&gt;阅读前先分清这些词&lt;/h3&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;术语&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;本文中的含义&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;易混淆之处&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Runner&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;长期持有 root Agent、服务、Plugin 和配置的运行器&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不是每次模型调用都新建&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Session&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;App + User + SessionID 关联的历史与状态&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;一个 Session 可以有多次 invocation&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Invocation&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;一次执行关联的逻辑 ID&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;暂停和恢复可能共用 ID&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;普通 Run&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;返回一个迭代函数，range 时才执行&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;非 LLM root 与 LLM root 内部路径不同&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Node runtime&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;LLM root 的合成 workflow / 节点运行路径&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不代表所有 root 都进入它&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Partial&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;流式过程中尚未形成完整记录的响应&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;final 判断和 partial 标志不是同一件事&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;AppendEvent&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;服务收到一条待记录事件&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不等于跨工具、artifact、数据库的原子事务&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="贯穿示例"&gt;贯穿示例&lt;/h3&gt;&#10;&lt;p&gt;主线使用 &lt;code&gt;AppName=weather_app&lt;/code&gt;、&lt;code&gt;userID=user-1&lt;/code&gt;、&lt;code&gt;sessionID=session-1&lt;/code&gt;，root 为 chat 模式 &lt;code&gt;weather_agent&lt;/code&gt;。输入是“杭州天气怎么样”，模型先请求 &lt;code&gt;get_weather(city=&amp;quot;Hangzhou&amp;quot;)&lt;/code&gt;，工具返回 &lt;code&gt;temperature=26&lt;/code&gt;，第二次模型调用生成中文回答。&lt;/p&gt;</description></item><item><title>Agent Development Kit (ADK) · 01 - Overview</title><link>https://jiabin.dev/blog/adk-overview/</link><pubDate>Sun, 20 Sep 2026 00:00:00 +0800</pubDate><guid>https://jiabin.dev/blog/adk-overview/</guid><description>&lt;h1 id="adk-go-源码阅读笔记--overview从一次请求看懂整个框架"&gt;ADK-Go 源码阅读笔记 · Overview：从一次请求看懂整个框架&lt;/h1&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;源码版本：&lt;a href="https://github.com/google/adk-go/tree/v2.4.0"&gt;ADK-Go v2.4.0&lt;/a&gt;&lt;/strong&gt;，commit &lt;code&gt;4e57df40cbd35f055ba654b03ffb0e509fdd754a&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://jiabin.dev/blog/adk/"&gt;系列目录&lt;/a&gt; · 下一篇：&lt;a href="https://jiabin.dev/blog/adk-quickstart/"&gt;Quickstart&lt;/a&gt; · 执行主线：&lt;a href="https://jiabin.dev/blog/adk-runner/"&gt;Runner&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-flow/"&gt;Flow&lt;/a&gt;。&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;用户问“杭州现在多少度”，模型输出一个 &lt;code&gt;get_weather&lt;/code&gt; 调用，工具返回 &lt;code&gt;26°C&lt;/code&gt;，模型再组织成自然语言回答。这里至少发生了两次模型请求、一次工具执行和多次事件追加。&lt;/p&gt;&#10;&lt;p&gt;ADK-Go 把这些工作分给不同组件：Agent 描述行为，Runner 驱动执行，Flow 连接模型和工具，服务保存历史与状态。&lt;span class="ann ann-n ann-amber" data-note="先记住分工"&gt;一次模型响应只是 Agent 运行过程中的一步&lt;/span&gt;。&lt;/p&gt;&#10;&lt;p&gt;这篇总览围绕三个问题展开：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;从程序入口到模型、工具和数据库，中间有哪些边界？&lt;/li&gt;&#10;&lt;li&gt;一次输入怎样变成事件，工具结果又怎样进入下一次模型请求？&lt;/li&gt;&#10;&lt;li&gt;接口抽象提供了什么，又有哪些必须结合具体实现理解的限制？&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="一源码入口与阅读地图"&gt;一、源码入口与阅读地图&lt;/h2&gt;&#10;&lt;p&gt;ADK-Go 是用 Go 代码构建 Agent 应用的框架。应用通过构造函数组合 Agent、Model、Tool、服务和运行入口，不需要先把整个应用写成一份声明式工作流。&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;阅读层次&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;文件 / 入口&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;解决的问题&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;应用示例&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/examples/quickstart/main.go"&gt;&lt;code&gt;examples/quickstart/main.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;最小应用怎样装配&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;启动入口&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/cmd/launcher/launcher.go"&gt;&lt;code&gt;cmd/launcher/launcher.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;console / web 如何共用应用配置&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Agent 契约&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/agent/agent.go#L35-L76"&gt;&lt;code&gt;agent/agent.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;什么对象可以被执行&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;请求驱动&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/runner/runner.go#L536-L610"&gt;&lt;code&gt;runner/runner.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;一次输入如何进入运行时&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;模型工具循环&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/internal/llminternal/base_flow.go#L612-L745"&gt;&lt;code&gt;internal/llminternal/base_flow.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;模型提出调用后由谁执行&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;会话记录&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/session/session.go"&gt;&lt;code&gt;session/session.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;历史、状态和事件如何表达&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;图调度&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/workflow/scheduler.go"&gt;&lt;code&gt;workflow/scheduler.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;节点、事件和恢复如何协调&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;先把模块放在同一张结构图上：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Application&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +-- Launcher / HTTP handler / 自定义入口&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | v&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | Runner &amp;lt;------ SessionService&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | | &amp;lt;--------- ArtifactService / MemoryService&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | v&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | InvocationContext：绑定本次执行所需的对象&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | v&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | Agent / node runtime&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | +-- LlmAgent --&amp;gt; Flow --&amp;gt; Model&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | | | |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | | +&amp;lt;- Tool &amp;lt;-+ FunctionCall&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | +-- 自定义 Agent / Workflow / 远程 Agent&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +-- Plugin：在已接入的生命周期边界观察或改变行为&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Model 适配器与 Tool 的业务实现可以替换，运行层仍围绕请求、响应和事件协作。但是模型共用接口并不意味着所有 provider 支持相同工具、多模态或流式能力。&lt;/p&gt;</description></item><item><title>Agent Development Kit (ADK) · 02 - 初见 ADK</title><link>https://jiabin.dev/blog/adk-quickstart/</link><pubDate>Sun, 20 Sep 2026 00:00:00 +0800</pubDate><guid>https://jiabin.dev/blog/adk-quickstart/</guid><description>&lt;h1 id="adk-go-源码阅读笔记--quickstart一个-main-函数怎样启动-agent-应用"&gt;ADK-Go 源码阅读笔记 · Quickstart：一个 main 函数怎样启动 Agent 应用&lt;/h1&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;源码版本：&lt;a href="https://github.com/google/adk-go/tree/v2.4.0"&gt;ADK-Go v2.4.0&lt;/a&gt;&lt;/strong&gt;，commit &lt;code&gt;4e57df40cbd35f055ba654b03ffb0e509fdd754a&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://jiabin.dev/blog/adk/"&gt;系列目录&lt;/a&gt; · 前置阅读：&lt;a href="https://jiabin.dev/blog/adk-overview/"&gt;Overview&lt;/a&gt; · 后续阅读：&lt;a href="https://jiabin.dev/blog/adk-launcher/"&gt;Launcher&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-model/"&gt;Model&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-agent/"&gt;Agent&lt;/a&gt;。&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;一个能回答天气问题的程序，为什么既要创建 Model，又要创建 Agent，还要经过 Loader 和 Launcher？因为这几个对象回答的是不同问题：调用哪个模型、如何组织行为、如何找到应用入口、用户通过什么界面交互。&lt;/p&gt;&#10;&lt;p&gt;官方 Quickstart 把这条装配链放在一个 &lt;code&gt;main&lt;/code&gt; 中。先看它的结构，再跟踪用户输入到达以后发生的事情，就能把配置代码与运行代码分开。&lt;/p&gt;&#10;&lt;h2 id="一源码入口与阅读地图"&gt;一、源码入口与阅读地图&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;文件 / 符号&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;在这个例子中的职责&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/examples/quickstart/main.go#L18-L65"&gt;examples/quickstart/main.go&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;创建模型、Agent、Loader 与 Launcher&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/model/gemini/gemini.go#L49-L80"&gt;gemini.NewModel&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;创建 Gemini SDK client 和模型适配器&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/agent/llmagent/llmagent.go#L39-L137"&gt;llmagent.New&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;把配置装配为 LlmAgent&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/agent/loader.go#L50-L76"&gt;agent.NewSingleLoader&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;用一个 Agent 提供加载入口&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/cmd/launcher/full/full.go#L30-L33"&gt;full.NewLauncher&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;提供 console 与 web 两类启动方式&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/cmd/launcher/console/console.go#L71-L121"&gt;console.Run&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;创建 Session 和 Runner，进入输入循环&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;构造阶段&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; genai.ClientConfig&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; v&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; gemini.NewModel -&amp;gt; llmagent.New -&amp;gt; NewSingleLoader&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; v&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; launcher.Config&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;运行阶段 v&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; os.Args[1:] ----------------&amp;gt; Launcher.Execute&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; console 或 web 入口&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Runner / Agent&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;span class="ann ann-n ann-amber" data-note="装配不等于执行"&gt;创建了 Agent 对象，还不代表模型已经生成过一次回答&lt;/span&gt;。模型请求通常要等到入口收到输入并消费运行事件时才发生。&lt;/p&gt;</description></item><item><title>Agent Development Kit (ADK) · 03 - Launcher</title><link>https://jiabin.dev/blog/adk-launcher/</link><pubDate>Sun, 20 Sep 2026 00:00:00 +0800</pubDate><guid>https://jiabin.dev/blog/adk-launcher/</guid><description>&lt;h1 id="adk-go-源码阅读笔记--launcher从命令行到-runner"&gt;ADK-Go 源码阅读笔记 · Launcher：从命令行到 Runner&lt;/h1&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;源码版本：&lt;a href="https://github.com/google/adk-go/tree/v2.4.0"&gt;ADK-Go v2.4.0&lt;/a&gt;&lt;/strong&gt;，commit &lt;code&gt;4e57df40cbd35f055ba654b03ffb0e509fdd754a&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://jiabin.dev/blog/adk/"&gt;系列目录&lt;/a&gt; · 前置阅读：&lt;a href="https://jiabin.dev/blog/adk-quickstart/"&gt;Quickstart&lt;/a&gt; · 后续阅读：&lt;a href="https://jiabin.dev/blog/adk-runner/"&gt;Runner&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-flow/"&gt;Flow&lt;/a&gt;。&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;Launcher 是 ADK 应用的进程入口层。它处理命令行参数、校验进程级配置、选择运行方式，并把同一份 AgentLoader、SessionService、Plugin 和鉴权配置交给 console 或 web 子入口。&lt;/p&gt;&#10;&lt;p&gt;它不负责模型推理，也不负责工具执行。&lt;span class="ann ann-n ann-amber" data-note="Launcher 负责进来"&gt;Launcher 选择怎么进入应用，Runner 才驱动一次 Agent 运行&lt;/span&gt;。&lt;/p&gt;&#10;&lt;h2 id="一源码入口与阅读地图"&gt;一、源码入口与阅读地图&lt;/h2&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;层次&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;文件 / 符号&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;作用&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;顶层契约&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/cmd/launcher/launcher.go#L34-L116"&gt;&lt;code&gt;cmd/launcher/launcher.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Launcher、SubLauncher、Config&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;选择器&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/cmd/launcher/universal/universal.go#L34-L101"&gt;&lt;code&gt;cmd/launcher/universal/universal.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;按第一个关键词选择入口&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;预设组合&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/cmd/launcher/full/full.go#L30-L33"&gt;&lt;code&gt;cmd/launcher/full/full.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;console + 全部 web 子入口&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;生产组合&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/cmd/launcher/prod/prod.go#L22-L31"&gt;&lt;code&gt;cmd/launcher/prod/prod.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;REST API + A2A&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;终端运行&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/cmd/launcher/console/console.go#L71-L121"&gt;&lt;code&gt;cmd/launcher/console/console.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Session、Runner、stdin 循环&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;HTTP 运行&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/cmd/launcher/web/web.go#L174-L274"&gt;&lt;code&gt;cmd/launcher/web/web.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;router、sublauncher、HTTP server&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;REST 挂载&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/cmd/launcher/web/api/api.go#L250-L315"&gt;&lt;code&gt;cmd/launcher/web/api/api.go&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;创建 &lt;code&gt;adkrest.Server&lt;/code&gt; 并挂到 path prefix&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;整体关系可以先压缩成一张图：&lt;/p&gt;</description></item><item><title>Agent Development Kit (ADK) · 04 - Model</title><link>https://jiabin.dev/blog/adk-model/</link><pubDate>Sun, 20 Sep 2026 00:00:00 +0800</pubDate><guid>https://jiabin.dev/blog/adk-model/</guid><description>&lt;h1 id="adk-go-源码阅读笔记--model统一接口怎样连接不同模型服务"&gt;ADK-Go 源码阅读笔记 · Model：统一接口怎样连接不同模型服务&lt;/h1&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;源码版本：&lt;a href="https://github.com/google/adk-go/tree/v2.4.0"&gt;ADK-Go v2.4.0&lt;/a&gt;&lt;/strong&gt;，commit &lt;code&gt;4e57df40cbd35f055ba654b03ffb0e509fdd754a&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://jiabin.dev/blog/adk/"&gt;系列目录&lt;/a&gt; · 配套阅读：&lt;a href="https://jiabin.dev/blog/adk-quickstart/"&gt;Quickstart&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-flow/"&gt;Flow&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-tool/"&gt;Tool&lt;/a&gt;。&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;Flow 已经准备好用户消息、历史、指令和工具声明，下一步要把请求交给模型服务。Gemini 和 OpenAI 的请求字段、角色、函数调用与流式事件并不相同；Model 层把这些差异放在适配器中处理，向上提供统一的 &lt;code&gt;LLMRequest → LLMResponse&lt;/code&gt; 接口。&lt;/p&gt;&#10;&lt;p&gt;&lt;span class="ann ann-n ann-amber" data-note="统一入口，不是功能同一"&gt;实现了同一个 LLM 接口，不代表所有模型支持相同的配置和工具&lt;/span&gt;。这篇文章围绕一次天气函数调用，说明统一数据怎样跨过 provider 边界，以及信息在转换中如何被保留或拒绝。&lt;/p&gt;&#10;&lt;h2 id="一源码入口与阅读地图"&gt;一、源码入口与阅读地图&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;model/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─ llm.go LLM / LLMRequest / LLMResponse&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─ registry.go 模型名正则 -&amp;gt; Factory&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─ gemini/gemini.go GenAI SDK 适配器&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├─ openaimodel/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├─ openai.go Responses API 调用与流式收尾&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├─ request.go 请求、消息、配置转换&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├─ tools.go 函数声明与 tool choice&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├─ response.go 返回内容、usage、结束原因&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └─ stream.go Responses 事件 -&amp;gt; GenAI 中间结构&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└─ apigee/apigee.go 配置代理后委托 Gemini adapter&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;入口 / 文件&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;阅读时要回答的问题&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/model/llm.go#L25-L68"&gt;model/llm.go&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;上层到底传什么、收到什么&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/internal/llminternal/base_flow.go#L815-L899"&gt;Flow.callLLM&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;哪些 callback 返回后不再调用模型&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/model/gemini/gemini.go#L87-L159"&gt;gemini.GenerateContent&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;普通调用和流式调用如何选择&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/model/openaimodel/request.go#L36-L86"&gt;buildOpenAIParams&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;通用请求如何转换成 Responses 参数&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/model/openaimodel/stream.go"&gt;streamTranslator&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;provider 的 delta 事件怎样转成通用 part&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/internal/llminternal/stream_aggregator.go"&gt;streamingResponseAggregator&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;增量和完整响应怎样共存&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;&lt;a href="https://github.com/google/adk-go/blob/v2.4.0/model/registry.go"&gt;model.Register / NewLLM&lt;/a&gt;&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;字符串名称怎样解析成实例&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="二核心接口与数据结构"&gt;二、核心接口与数据结构&lt;/h2&gt;&#10;&lt;h3 id="1-两个方法的公共契约"&gt;1. 两个方法的公共契约&lt;/h3&gt;&#10;&lt;p&gt;下面是接口与请求结构的源码摘录：&lt;/p&gt;</description></item><item><title>Agent Development Kit (ADK) · 07 - Flow</title><link>https://jiabin.dev/blog/adk-flow/</link><pubDate>Sun, 20 Sep 2026 00:00:00 +0800</pubDate><guid>https://jiabin.dev/blog/adk-flow/</guid><description>&lt;h1 id="adk-go-源码阅读笔记--flow一次-llm-agent-回合是怎样跑完的"&gt;ADK-Go 源码阅读笔记 · Flow：一次 LLM Agent 回合是怎样跑完的&lt;/h1&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;源码版本：&lt;a href="https://github.com/google/adk-go/tree/v2.4.0"&gt;ADK-Go v2.4.0&lt;/a&gt;&lt;/strong&gt;，commit &lt;code&gt;4e57df40cbd35f055ba654b03ffb0e509fdd754a&lt;/code&gt;。以下“当前实现”均指这个版本。&lt;/p&gt;&#10;&lt;p&gt;&lt;a href="https://jiabin.dev/blog/adk/"&gt;返回源码阅读合集&lt;/a&gt; · 配套阅读：&lt;a href="https://jiabin.dev/blog/adk-runner/"&gt;Runner&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-context/"&gt;Context&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-tool/"&gt;Tool&lt;/a&gt;、&lt;a href="https://jiabin.dev/blog/adk-plugin/"&gt;Plugin&lt;/a&gt;。相关模块的阅读顺序见合集。&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;用户问“杭州天气怎么样”，模型返回 &lt;code&gt;get_weather(city=&amp;quot;Hangzhou&amp;quot;)&lt;/code&gt;。到这里，天气查询还没有执行，用户也还没有得到答案。程序还必须找到工具、执行代码、把结果交回模型，并判断是否还要继续调用模型。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;Flow 就是把这些阶段接起来的内部控制层。&lt;/strong&gt; 它让一次模型调用成为可以反复“请求 → 执行 → 反馈”的 Agent 运行过程。理解它，关键是同时追踪控制流和数据：下一步由谁触发，上一轮结果又通过什么对象进入下一步。&lt;/p&gt;&#10;&lt;p&gt;本文回答三个问题：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;谁创建 Flow，它依赖哪些接口和数据？&lt;/li&gt;&#10;&lt;li&gt;一条模型 FunctionCall 如何变成工具结果，再进入下一次模型请求？&lt;/li&gt;&#10;&lt;li&gt;Flow 与 Runner、Model、Tool 之间的职责边界在哪里？&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;主线先看普通 &lt;code&gt;Run&lt;/code&gt; 的一次工具调用闭环；SSE、确认、transfer 和 Live 放到第四节展开。本文不是 Workflow scheduler 或 Session 数据库实现的完整说明。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;阅读准备。&lt;/strong&gt; 只需要了解 Go 的接口、指针、map，以及大语言模型的 Function Calling：模型输出函数名和参数，实际函数由应用执行。如果不熟悉 &lt;code&gt;iter.Seq2&lt;/code&gt;，第三节会结合代码解释；无需先掌握 ADK 的全部模块。&lt;/p&gt;&#10;&lt;p&gt;先约定几个容易混用的词：&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;术语&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;本文中的含义&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th&gt;天气例子中的数量&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Session&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;持续保存多次交互的会话及其历史、状态&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;1 个，可以继续提问&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Invocation&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;一次执行上下文所关联的运行；恢复路径可能沿用原 invocation ID&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;普通无暂停路径为 1 次&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Flow step&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;一次 &lt;code&gt;runOneStep&lt;/code&gt;：准备请求、消费模型响应、处理工具及后续动作&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;通常 2 步&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;模型调用&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;真正进入 &lt;code&gt;GenerateContent&lt;/code&gt;；BeforeModel 可使它被跳过&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;本例 2 次&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Event&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;一条向上返回的运行记录，可能承载文本、函数调用、结果或控制信息&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;主线为用户输入、调用、结果、答案 4 条；外层还可能有控制事件&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Partial / final&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;Partial 表示响应尚未聚合完成；&lt;code&gt;IsFinalResponse()&lt;/code&gt; 是事件的结束判定方法&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td&gt;不是“每条 Event 都是一轮模型调用”&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;第一次阅读可先读第一至第三节，再看第五至第七节；第四节用于沿具体问题深入。文中标为“源码摘录”的代码对应固定 tag；省略外围代码会明确说明。“伪代码”“示意数据”和教学示例不冒充源码原文。&lt;/p&gt;</description></item><item><title>ADK-Go 源码阅读系列</title><link>https://jiabin.dev/blog/adk/</link><pubDate>Sat, 19 Sep 2026 00:00:00 +0800</pubDate><guid>https://jiabin.dev/blog/adk/</guid><description>&lt;h1 id="adk-go-源码阅读合集"&gt;ADK-Go 源码阅读合集&lt;/h1&gt;&#10;&lt;p&gt;用户发来一句“杭州天气怎么样”，从接收输入到给出答案，中间会经历模型请求、工具执行、事件保存和下一轮推理。多 Agent、人工确认、流式输出和长会话则会改变这条路径。&lt;/p&gt;&#10;&lt;p&gt;这个系列沿着一次请求追踪 ADK-Go 的实现：&lt;strong&gt;谁创建对象，谁调用接口，数据在哪一步变成事件，结果又如何成为下一次输入。&lt;/strong&gt; 各篇聚焦一个模块，并用相邻模块的实际调用方说明它的边界。&lt;/p&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;系列源码基准：&lt;a href="https://github.com/google/adk-go/tree/v2.4.0"&gt;ADK-Go v2.4.0&lt;/a&gt;&lt;/strong&gt;，commit &lt;code&gt;4e57df40cbd35f055ba654b03ffb0e509fdd754a&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;各篇使用同一版本的接口、实现和调用方。普通 Run、Live、不同模型适配器与存储后端的行为分别说明；一种运行方式的结论不自动适用于其他方式。&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h2 id="阅读路线"&gt;阅读路线&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Overview / Quickstart&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Launcher / Model / Agent&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Runner → Flow → Tool&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Context → Session / Event&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Memory / Plugin / Workflow&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Artifact → Server → Registry&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Auth / Telemetry / Platform&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果还不了解 ADK，先读 Overview 和 Quickstart；如果已写过简单 Agent，可从 Flow 的天气示例进入，再沿 &lt;code&gt;Runner → Tool → Context → Session&lt;/code&gt; 追踪它上下游的实现。&lt;/p&gt;</description></item><item><title>Attention 背后的数学：Q、K、V 白话详解</title><link>https://jiabin.dev/blog/attention-qkv/</link><pubDate>Mon, 31 Aug 2026 00:00:00 +0800</pubDate><guid>https://jiabin.dev/blog/attention-qkv/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;基于 Outcome School 文章《Math behind Attention - Q, K, and V》的中文整理与扩展讲解。&lt;/p&gt;&#10;&lt;p&gt;原文链接：https://outcomeschool.com/blog/math-behind-attention-qkv&lt;/p&gt;&#10;&lt;p&gt;原文作者：Amit Shekhar&lt;/p&gt;&#10;&lt;p&gt;原文页面标注日期：2026 年 4 月 3 日&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h2 id="一句话理解-attention"&gt;一句话理解 Attention&lt;/h2&gt;&#10;&lt;p&gt;Attention 可以理解成：&lt;/p&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;每个词都先问一句：“当前情况下，我应该重点参考哪些词？”然后根据相关程度，从其他词那里提取信息，形成一个包含上下文的新表示。&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;例如句子：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;I love AI&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;处理 &lt;code&gt;I&lt;/code&gt; 时，模型可能会发现 &lt;code&gt;love&lt;/code&gt; 和它关系比较大，于是给 &lt;code&gt;love&lt;/code&gt; 更高权重；处理 &lt;code&gt;AI&lt;/code&gt; 时，也可能重点参考 &lt;code&gt;love&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;完整公式是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Attention(Q, K, V)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;= softmax(Q × Kᵀ / √dₖ) × V&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这条公式可以拆成 6 步：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;文字&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓ embedding&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;数字向量 X&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;生成 Q、K、V&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Q 和 K 做匹配&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Softmax 转成权重&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;用权重加权混合 V&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;得到包含上下文的新向量&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;p&gt;&lt;img src="https://jiabin.dev/assets/img/attention-qkv-detailed.svg" alt=""&gt;&lt;/p&gt;</description></item><item><title>梁文锋投资人会议文字稿（修订版）</title><link>https://jiabin.dev/blog/liang/</link><pubDate>Thu, 23 Jul 2026 00:00:00 +0800</pubDate><guid>https://jiabin.dev/blog/liang/</guid><description>&lt;p&gt;梁文锋投资人会议文字稿修正稿&lt;/p&gt;&#10;&lt;h2 id="文章"&gt;文章&lt;/h2&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;仅在原稿上修正了错别字、错误术语和逻辑不通顺的地方&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;会议时间：5月20日 会议时长：4 小时 会议目的：DeepSeek 创始人梁文锋与投资人交流会&lt;/p&gt;&#10;&lt;p&gt;我以及我们公司的其他同事，我们一开始来做这个公司，初衷是没有想到说我最后要赚多少钱，要到资本市场上去，要上市，要怎么样的，所以我们是没有这个初衷的。&lt;/p&gt;&#10;&lt;p&gt;最开始的几十个人完全没有这么想过。如果他这么想，他就不会来。所以总体讲，我们是怀着一个对这个世界非常大的善意来做这个事情，然后我们觉得这是对人类有用的，这是一个金钱以外的事情。&lt;/p&gt;&#10;&lt;p&gt;当然，到了后面，这个事情发现利益非常大之后，又有其他的诱惑，这个是另外的事情。但是我们出发的初衷、我们的愿景，以及我们保持到现在的这个愿景，不是按照一个商业利益最大化的方式来做的。我觉得这点比较关键。&lt;/p&gt;&#10;&lt;p&gt;大概二十年前的时候，在管理上我最崇拜的是杰克·韦尔奇，就是 GE 的前 CEO。现在回来看，他说的大部分东西可能都已经不对了，但是他最重要的一点说对了：一个公司最重要的是它的愿景。&lt;/p&gt;&#10;&lt;p&gt;管理一个大公司，靠的不是你的规章制度，靠的是愿景。愿景是什么呢？愿景不是挂在墙上的标语，愿景是你怎么做，不是怎么说，就是你怎么实际运行。反正杰克·韦尔奇说的原话我忘了，大概是这个意思。&lt;/p&gt;&#10;&lt;p&gt;所以，我们是怎么管理这么多人、怎么组织起来的？其实我们没有组织，就是愿景驱动的，靠一个愿景来组织。我们是没有组织的。&lt;/p&gt;&#10;&lt;p&gt;这个有好处，也有坏处。未来我们会想办法扬长避短，但这个是我们的特色。我们并不是以一个&amp;quot;我要实现什么 KPI、没有考核&amp;quot;的方式来做，只有愿景。&lt;/p&gt;&#10;&lt;p&gt;这个愿景甚至也不是成文的，并不是写出来的，没有写出来过任何东西。这个愿景是在我们做事情的方法、我们对待这个世界的态度里。可能我们公司每个人对这个愿景的理解也不一样，可能每一个人的愿景也是有差别的，但是在一个大的方向上是一致的。&lt;/p&gt;&#10;&lt;p&gt;我觉得还是怀着对这个世界非常大的善意，然后想做一点事情。我们是用这个来组织起来的。&lt;/p&gt;&#10;&lt;p&gt;接下来我先讲，讲完之后大家再提问。我可能会围绕着这个愿景来讲后面的事情。这个愿景是真的，不是编出来的，我们是真的这么想，真的这么做的。否则你没法解释我们的很多事情。&lt;/p&gt;&#10;&lt;p&gt;这个愿景为什么我们这么坚持开源？因为这个愿景本身就要求开源。你没有这个愿景，你没法把人组织起来。&lt;/p&gt;&#10;&lt;p&gt;比如说，智谱也开源，但是智谱的开源跟我们的开源不一样。智谱的开源有一种被迫的感觉，他们觉得这不是本意，但是对我们来讲，这就是我们的本意。&lt;/p&gt;&#10;&lt;p&gt;然后在开源这个事情上面，我们一开始就想得非常清楚。首先，第一个就是愿景；第二个，我们认为要把 AI 这个事情在商业上做成，开源是有好处的。&lt;/p&gt;&#10;&lt;p&gt;这听起来有点矛盾，有点违反直觉，因为在历史上，开源跟商业化都是有冲突的。但我觉得 AI 跟以前不一样。因为在历史上，一个软件公司，它的市场一年可能就几十亿美金，你开源了，它就没有了，可能就只剩下几千万或几亿美金了。&lt;/p&gt;&#10;&lt;p&gt;但是 AI 这个事情足够大，最终它可能得占掉人类社会 GDP 的百分之十，比如说。那么它其实是一个非常大的数字。一个人独占这个事情，你不可能独占这个事情，你一定得跟别人分享，否则你肯定活不下来。&lt;/p&gt;&#10;&lt;p&gt;这跟之前开源做一个软件可能是不一样的，因为那个软件的市场就没那么大。但是 AI 这个事情实在太大了。如果说我们想独占这个利益，那么一定是要被历史抛弃的。我觉得最主要这是一个客观的规律，这是一个历史观。&lt;/p&gt;&#10;&lt;p&gt;并不是说我不开源，我就能够独占这个市场，这在理论上就不符合客观事实。你一定会遇到很多阻力，一定会有其他的方法阻止你实现这个目标。&lt;/p&gt;&#10;&lt;p&gt;在这种情况下，我觉得不一定要按照传统的商业思维。你需要有一套机制来确保你自己能够获得的利益是有限的，那么你才有可能做成。需要克制，我觉得是需要克制。&lt;/p&gt;&#10;&lt;p&gt;如果说我们想在我们手上把 AI 这个事情做成，首先第一个，我觉得是需要克制的。不能够想着人类 GDP 的百分之多少都归我了，或者说中国 GDP 百分之多少都归我了。你越这么想，越做不成。&lt;/p&gt;&#10;&lt;p&gt;所以我们从一开始就觉得需要克制。你越克制，你越有可能能够做成这层事。这是一个商业上的考量，当然这是一个宏观的考虑。&lt;/p&gt;&#10;&lt;p&gt;我觉得这是符合直觉的，至少是符合我的直觉，或者说至少我是真的这么想的。我们并没有非常多的其他优势，我们没有什么本事，我们并没有比别人有钱，也没有说我们人员比其他公司更好，其实没有的。&lt;/p&gt;&#10;&lt;p&gt;你想，我们两年前成立这个公司的时候，我们又没有很多钱，又没有很多卡，又没有什么知名度，又没有什么号召力，我们就是一群非常平凡的人。&lt;/p&gt;&#10;&lt;p&gt;[00:11:49]&lt;/p&gt;&#10;&lt;p&gt;我真的就是一群平凡的人。如果说喜欢的一个叙事是一群平凡的人做出了不平凡的事情，而不是一群天才做出了不平凡的事情，这个跟我们的克制是很有关系的，跟我们的克制、跟我们的愿景是一脉相承的。&lt;/p&gt;&#10;&lt;p&gt;那么，开源跟商业化会不会有冲突？我觉得在 AI 这个事情上面，你不克制，你就做不成。&lt;/p&gt;&#10;&lt;p&gt;开源是属于克制的一部分，那么我们的克制不仅表现在开源上面，我们还表现在很多方面上。但总体上来讲，我们是不用考虑开不开源这个事，不用考虑要不要克制这个事情。&lt;/p&gt;&#10;&lt;p&gt;你越克制，可能就越容易做成，或者说至少到目前为止是印证的，到目前为止是能解释得通的。否则没有办法能够解释为什么我们能够做成：我们并没有什么武器，起点又非常低，资源又非常少，我们的人其实也就是随机的一群平凡的人。我自己也就是一个大学毕业的学生，也不是最顶级的那个学校毕业的。&lt;/p&gt;&#10;&lt;p&gt;这个克制也是我们愿景里的一部分。AI 这个事情太大了，利益太大了。我们非常克制，只要能够做成，最后利益都会非常大。你随便分一点，利益就非常大，所以现在根本不用考虑拿这里面的哪一部分利益、怎么拿，我觉得根本不用考虑这件事情，因为这个利益足够大了。&lt;/p&gt;&#10;&lt;p&gt;你只要分一点点，就已经很足够了。所以我们之前说，我们只赚取一个合理的利润，只看你的意愿，而不是利润最大化，这个是不一样的。这不是我们的 API 定价。我们 API 定价觉得一个合理的利润，大概是我们到市场上买一批设备回来，十个月收回成本，我觉得这是一个合理的利润。&lt;/p&gt;&#10;&lt;p&gt;在当前的情况下，考虑到你有风险、还有前期的投入等等，如果一个服务器我们在财务上按照三年或者五年的摊销，但在商业上，我们觉得大概十个月收回成本，我们觉得够了，OK，我们觉得够了。所以这个是我们现在 API 定价的逻辑。我们的 V3.2 Flash 跟其他的，都是十个月收回设备的成本。&lt;/p&gt;</description></item></channel></rss>