Google ADK Java 1.2 核心机制与实战 Demo
本文基于源码
/com/google/adk/google-adk/1.2.0/google-adk-1.2.0-sources.jar阅读整理,同时参考 ADK 在线文档。需要注意:在线文档会持续演进,可能展示高于1.2.0的 API 或新增能力。本文讨论的源码级实现细节,以 ADK Java1.2.0为准。
1. 先用一句话理解 ADK
ADK 可以理解成一个"Agent 应用运行时":你把模型、提示词、工具、子 Agent、会话服务、插件等组件交给它,它负责把一次用户请求变成一串可观察、可持久化、可扩展的 Event。
最小运行链路是:
text
用户输入 Content
-> Runner.runAsync(userId, sessionId, content)
-> SessionService 读取/创建 Session
-> Runner 把用户消息追加成 user Event
-> InvocationContext 携带 session、services、plugins、runConfig
-> BaseAgent.runAsync(...)
-> LlmAgent / SequentialAgent / ParallelAgent / LoopAgent 执行
-> 产出 Event 流
-> Runner 把 Event 回写 Session,并触发 Plugin
这条链路里最关键的概念只有五个:
| 概念 | 通俗解释 | 源码类 |
|---|---|---|
| Agent | 干活的人或流程节点 | BaseAgent、LlmAgent、SequentialAgent、ParallelAgent、LoopAgent |
| Runner | 调度器和执行入口 | Runner、InMemoryRunner |
| Session | 一条对话线程 | Session、State、BaseSessionService |
| Event | 执行过程留下的记录 | Event、EventActions |
| Tool/Plugin/Callback | 扩展点 | FunctionTool、ToolContext、Plugin、Callbacks |
官方文档也把这些列为 ADK 的核心原语:Agent、Tool、Callbacks、Session/State、Memory、Artifact、Planning、Model、Event、Runner。
2. Agent:ADK 的执行单元
BaseAgent 是所有 Agent 的基类。源码里它做了几件基础但很重要的事:
- 校验 Agent 名称,禁止空名称和保留名称
user。 - 维护父子树关系,
subAgents会自动设置parentAgent。 - 统一执行模板:先触发 before-agent 插件和回调,再执行子类的
runAsyncImpl,最后触发 after-agent 插件和回调。 - 每次执行都会从父
InvocationContext拷贝一个新 context,并把当前 agent 和 branch 信息写进去。
也就是说,BaseAgent 提供的是"生命周期骨架",真正干活的是各个子类。
2.1 LlmAgent:会调用模型的 Agent
LlmAgent 是最常用的智能 Agent。源码中的 Builder 支持:
| 能力 | 说明 |
|---|---|
model(...) |
指定模型名称或 BaseLlm 实例 |
instruction(...) |
当前 Agent 的任务指令 |
globalInstruction(...) |
全局指令 |
tools(...) |
注入 BaseTool 或 BaseToolset |
outputKey(...) |
把最终回复写入 session state |
planning(...) |
开启规划能力 |
maxSteps(...) |
限制模型-工具循环步数 |
inputSchema(...) / outputSchema(...) |
约束输入输出结构 |
| model/tool/agent callbacks | 在模型、工具、Agent 生命周期中插入自定义逻辑 |
codeExecutor(...) |
代码执行能力 |
最常见的 Java 写法是直接用 Builder 创建 LlmAgent:
java
LlmAgent llmAgent = LlmAgent.builder()
.name("javaTutor")
.description("回答 Java 学习问题")
.model("gemini-2.5-flash")
.instruction("你是一个 Java 技术导师,回答要准确、简洁、带例子。")
.outputKey("answer")
.build();
如果你使用 Spring AI,也可以通过 google-adk-spring-ai 模块把 Spring AI 的 ChatModel 适配成 ADK 可调用的模型;但这属于集成选择,不影响 ADK 自身的 Agent 执行机制。
outputKey 值得单独说一下。LlmAgent 在源码中会检查事件是否是 finalResponse(),如果是,就把最终文本写入 event.actions().stateDelta()。随后 Runner 把事件追加到 Session,SessionService 再把 stateDelta 合并进当前会话状态。这样后续 Agent 就可以通过 state 读取上一步结果。
2.2 Workflow Agent:不靠模型做编排
ADK 1.2.0 的 SequentialAgent、ParallelAgent、LoopAgent 都是确定性编排节点。它们自己不问模型"下一步怎么走",而是按固定源码逻辑调度子 Agent。
| Agent | 源码执行逻辑 | 适合场景 |
|---|---|---|
SequentialAgent |
Flowable.fromIterable(subAgents()).concatMap(...) |
分析 -> 生成 -> 审查等流水线 |
ParallelAgent |
为分支设置 branch,然后 Flowable.merge(...) |
多路研究、多方案生成、多视角分析 |
LoopAgent |
子 Agent 串行执行后 repeat(...),直到 maxIterations 或 escalate |
生成-检查-修正这类迭代流程 |
这也是理解 ADK workflow 的关键:workflow agent 是"确定性控制器",不是"LLM 决策器"。官方文档也强调 template workflow agents 根据预定义逻辑控制子 Agent 的执行顺序,具有可预测的执行模式。
3. Runner:一次请求真正从这里开始
Runner 是 ADK 的执行引擎。InMemoryRunner 只是一个便捷封装,它默认装配:
text
InMemoryArtifactService
InMemorySessionService
InMemoryMemoryService
所以 InMemoryRunner 很适合本地开发、单机 demo、单元测试,但不适合直接承担生产级持久化。进程重启后,内存里的 Session、State、Memory 都会丢失。
源码里 Runner.runAsync(...) 的主要步骤是:
- 按
appName + userId + sessionId从SessionService读取会话。 - 如果配置允许,也可以自动创建会话。
- 构造
InvocationContext,把 Session、Agent、Services、PluginManager、RunConfig 放进去。 - 触发
onUserMessageCallback,允许插件改写用户输入。 - 把用户输入追加成一个
author=user的Event。 - 重新读取更新后的 Session。
- 执行当前应该运行的 Agent。
- 把 Agent 产出的每个
Event追加回 Session。 - 对每个事件触发
onEventCallback。 - 执行完成后触发
afterRunCallback,并按配置压缩历史事件。
这里有一个工程细节很重要:同一个 sessionId 上的请求会被 activeSessionCompletables 串行化。也就是说,同一会话里的多次 runAsync 不会随意并发交错,这对维护上下文一致性很关键。
4. Session、State、Event:ADK 的上下文账本
很多 Agent 框架最难调试的地方是:模型到底看到了什么、工具何时被调用、状态什么时候变了。ADK 的答案是把过程事件化。
4.1 Session 是一条会话线程
Session 持有:
java
private final String id;
private final String appName;
private final String userId;
private final State state;
private final List<Event> events;
private Instant lastUpdateTime;
这说明 Session 不只是"聊天 ID",它同时保存历史事件和当前状态。官方文档也把 Session 描述为当前 conversation thread,包含本次交互中的 Events 和临时 State。
4.2 State 是当前会话内的工作内存
State 实现了 ConcurrentMap<String, Object>,内部有两个 map:
text
state: 当前完整状态
delta: 本次新增、修改、删除的状态变更
当你 put、replace、remove 时,State 会同步记录 delta。这样 ADK 可以把"当前状态"和"本次事件造成的状态变化"分开处理。
State 里有三个前缀常量:
| 前缀 | 含义 |
|---|---|
app: |
应用级状态 |
user: |
用户级状态 |
temp: |
临时状态 |
4.3 Event 是可观察、可回放的执行记录
Event 代表执行过程中发生的一件事,例如:
| Event 内容 | 例子 |
|---|---|
| 用户消息 | author=user,content 是用户输入 |
| 模型回复 | author=agentName,content 是模型输出 |
| 工具调用 | content 中包含 functionCall |
| 工具返回 | content 中包含 functionResponse |
| 状态变化 | actions.stateDelta |
| 工作流控制 | actions.escalate、actions.transferToAgent |
| 流式片段 | partial=true |
Event.finalResponse() 的判断也很实用:没有 function call、没有 function response、不是 partial、没有尾部代码执行结果,就可以认为这是最终回复。业务侧常见的同步接口会消费 Flowable<Event>,再用 event.stringifyContent() 抽取内容。
5. Tool:让 Agent 能做事,而不只是聊天
BaseTool 是 ADK 工具基类。它定义了两个核心动作:
declaration():把工具描述成模型能理解的函数声明。runAsync(args, toolContext):实际执行工具。
FunctionTool 是最常用的工具包装器。它通过 Java 反射读取方法签名,结合 @Schema 注解生成 function declaration,再在模型调用工具时把参数转换为 Java 方法参数。
官方 Java Quickstart 的模式是:
java
LlmAgent.builder()
.name("hello-time-agent")
.description("Tells the current time in a specified city")
.instruction("Use the getCurrentTime tool.")
.model("gemini-flash-latest")
.tools(FunctionTool.create(HelloTimeAgent.class, "getCurrentTime"))
.build();
ADK 1.2.0 里还有一个非常适合理解 Loop 的内置工具:ExitLoopTool。它的核心就是:
java
toolContext.setActions(
toolContext.actions().toBuilder()
.escalate(true)
.skipSummarization(true)
.build());
这解释了为什么 LoopAgent 不是解析 "PASS/FAIL" 文本来停止,而是看事件动作:只要某个事件带有 actions.escalate=true,循环就会停止。
6. Plugin 与 Callback:两类扩展点
ADK 有两层拦截机制:
| 扩展点 | 作用范围 | 适合用途 |
|---|---|---|
| Callback | 绑定在某个 Agent 上 | 单个 Agent 的输入校验、模型请求改写、工具结果修正 |
| Plugin | 注册在 Runner 上,全局生效 | 日志、审计、权限、风控、缓存、指标、统一响应改写 |
Plugin 接口覆盖的生命周期很完整:
| 阶段 | 方法 |
|---|---|
| 用户消息进入 | onUserMessageCallback |
| Runner 开始 | beforeRunCallback |
| Agent 前后 | beforeAgentCallback、afterAgentCallback |
| 模型前后和异常 | beforeModelCallback、afterModelCallback、onModelErrorCallback |
| 工具前后和异常 | beforeToolCallback、afterToolCallback、onToolErrorCallback |
| 事件产出 | onEventCallback |
| Runner 结束 | afterRunCallback |
| 资源释放 | close |
源码里的 PluginManager 会按注册顺序执行插件。返回 Maybe 的回调采用"第一个非空结果即提前结束"的策略,所以插件顺序会影响最终行为。
7. 实战 Demo:用 Java 写一个"生成-审查-通过即退出"的循环 Agent
下面这个 demo 刻意选择一个能体现 ADK 核心机制的场景:让一个 Agent 生成答案,让另一个 Agent 审查答案。如果审查通过,就调用 exit_loop 工具退出循环;如果不通过,就继续下一轮,最多循环 3 次。
这个例子覆盖了:
LlmAgent调模型。LoopAgent做确定性循环。SequentialAgent把"循环"和"最终总结"串起来。outputKey把中间结果写入State。ExitLoopTool通过EventActions.escalate=true控制循环停止。Runner + Session + Event完成一次请求执行。
7.1 Maven 依赖
本文 demo 使用的是 1.2.0:
xml
<dependency>
<groupId>com.google.adk</groupId>
<artifactId>google-adk</artifactId>
<version>1.2.0</version>
</dependency>
如果你直接照官方 Quickstart 新建项目,页面示例可能已经使用更新版本。学习机制时可以看新版;复现本文源码细节时请使用 1.2.0。
7.2 Demo 代码
java
package demo;
import com.google.adk.agents.BaseAgent;
import com.google.adk.agents.LlmAgent;
import com.google.adk.agents.LoopAgent;
import com.google.adk.agents.RunConfig;
import com.google.adk.agents.SequentialAgent;
import com.google.adk.events.Event;
import com.google.adk.runner.InMemoryRunner;
import com.google.adk.sessions.Session;
import com.google.adk.tools.ExitLoopTool;
import com.google.genai.types.Content;
import com.google.genai.types.Part;
import io.reactivex.rxjava3.core.Flowable;
public class ReviewLoopDemo {
public static void main(String[] args) {
BaseAgent rootAgent = buildAgent();
InMemoryRunner runner = new InMemoryRunner(rootAgent, "review-loop-demo");
Session session = runner.sessionService()
.createSession(runner.appName(), "user-001")
.blockingGet();
Content userMessage = Content.fromParts(Part.fromText("""
请写一段 150 字以内的 Java Optional 使用建议。
要求:通俗、准确、包含一个典型误区。
"""));
Flowable<Event> events = runner.runAsync(
session.userId(),
session.id(),
userMessage,
RunConfig.builder().build());
events.blockingForEach(event -> {
System.out.printf(
"[author=%s, final=%s, escalate=%s]%n",
event.author(),
event.finalResponse(),
event.actions().escalate().orElse(false));
String text = event.stringifyContent();
if (!text.isBlank()) {
System.out.println(text);
System.out.println();
}
});
}
private static BaseAgent buildAgent() {
LlmAgent writer = LlmAgent.builder()
.name("writer")
.description("生成第一版技术说明")
.model("gemini-2.5-flash")
.instruction("""
你是 Java 技术作者。
根据用户要求写一段短说明。
输出必须简洁、准确、适合初学者。
""")
.outputKey("draft")
.build();
LlmAgent reviewer = LlmAgent.builder()
.name("reviewer")
.description("审查技术说明,合格时退出循环")
.model("gemini-2.5-flash")
.instruction("""
你是严格的 Java 审稿人。
请审查 session state 中的 {draft}。
如果 draft 同时满足:
1. 150 字以内;
2. 对 Optional 的描述准确;
3. 包含一个典型误区;
4. 对初学者友好;
你必须先给出 PASS,然后调用 exit_loop 工具。
如果不满足,请给出 FAIL 和需要修改的原因,不要调用工具。
""")
.tools(ExitLoopTool.INSTANCE)
.build();
LoopAgent reviewLoop = LoopAgent.builder()
.name("reviewLoop")
.description("反复生成和审查,直到 reviewer 通过或达到最大次数")
.subAgents(writer, reviewer)
.maxIterations(3)
.build();
LlmAgent summarizer = LlmAgent.builder()
.name("summarizer")
.description("输出最终答案")
.model("gemini-2.5-flash")
.instruction("""
你是最终答复 Agent。
请读取 session state 中的 {draft}。
直接输出当前最终版,不要解释流程。
""")
.build();
return SequentialAgent.builder()
.name("root")
.description("生成、审查、总结")
.subAgents(reviewLoop, summarizer)
.build();
}
}
7.3 这段代码背后的执行过程
text
Runner 收到用户问题
-> 追加 user Event
-> SequentialAgent(root)
-> LoopAgent(reviewLoop), 最多 3 轮
-> writer 生成 draft,并通过 outputKey 写入 stateDelta["draft"]
-> reviewer 读取 {draft}
-> 不通过:输出 FAIL,循环进入下一轮
-> 通过:调用 exit_loop
-> ToolContext.actions.escalate = true
-> Event.actions.escalate = true
-> LoopAgent.takeUntil(...) 停止
-> summarizer 读取 {draft} 输出最终结果
-> Runner 把所有 Event 回写 Session
关键点不是"reviewer 输出了 PASS",而是"reviewer 调用了 exit_loop 工具,工具把 escalate 写进 EventActions"。这就是 ADK 里文本语义和流程控制的分界线:文本给人看,EventActions 给运行时看。
7.4 Demo 的工程提醒
InMemoryRunner的 Session、Memory、Artifact 都是内存实现,重启会丢。LoopAgent不会自动解析自然语言判断是否停止,必须通过 tool、callback 或自定义 Agent 写入escalate。outputKey只在finalResponse()为 true 时保存最终文本。调用exit_loop后循环会在工具返回事件处停止,所以不要假设 reviewer 还能再输出一段可保存的最终审查文本。- 多个并行分支不要写同一个
outputKey,否则会有覆盖风险。 - 生产环境建议把
SessionService、MemoryService、ArtifactService换成可持久化实现,并加上 Plugin 做审计、权限和指标。
8. ADK Java 1.2 的 YAML 配置能力
除了用 Builder 手写 Agent,ADK Java 1.2.0 源码里还提供了一套 YAML 配置加载能力,入口是:
java
BaseAgent rootAgent = ConfigAgentUtils.fromConfig("agents/root.yaml");
InMemoryRunner runner = new InMemoryRunner(rootAgent, "yaml-demo");
示例代码需要的核心 import 是:
java
import com.google.adk.agents.BaseAgent;
import com.google.adk.agents.ConfigAgentUtils;
import com.google.adk.runner.InMemoryRunner;
这套能力的定位要说清楚:源码注释里标了 Config agent features are not yet ready for public use.,所以在 1.2.0 中更适合当作实验性配置能力理解。它的价值在于把 Agent 树、workflow、工具引用、callback 引用从 Java Builder 代码里抽出来,便于阅读和调整。
8.1 YAML 到 Agent 的加载过程
ConfigAgentUtils.fromConfig(...) 的源码流程是:
text
读取 YAML 文件
-> YamlPreprocessor 把 snake_case key 转成 camelCase
-> 先反序列化成 BaseAgentConfig,读取 agent_class
-> ComponentRegistry.resolveAgentClass(agent_class)
-> 根据 Agent 类型选择具体 Config 类
LlmAgentConfig / SequentialAgentConfig / ParallelAgentConfig / LoopAgentConfig
-> 再次反序列化 YAML
-> 反射调用 XxxAgent.fromConfig(config, configAbsPath)
-> 递归解析 sub_agents、tools、callbacks
-> 返回 BaseAgent
其中 YamlPreprocessor 很实用:你可以在 YAML 里写更自然的 agent_class、output_key、max_iterations,它会转成 Java 对象需要的 agentClass、outputKey、maxIterations。
agent_class 不写时默认是 LlmAgent。ComponentRegistry 默认预注册了 ADK 核心 Agent 类,所以 LlmAgent、SequentialAgent、ParallelAgent、LoopAgent 这些简单名可以直接用;自定义 Agent 则需要提前注册到 ComponentRegistry,或者使用能被 registry 解析的类名。
8.2 LlmAgent YAML 示例
writer.yaml:
yaml
agent_class: LlmAgent
name: writer
description: 生成第一版技术说明
model: gemini-2.5-flash
instruction: |
你是 Java 技术作者。
根据用户要求写一段短说明。
输出必须简洁、准确、适合初学者。
output_key: draft
这个文件会被加载为 LlmAgentConfig,再由 LlmAgent.fromConfig(...) 创建 LlmAgent。在 1.2.0 里,LlmAgentConfig 支持的主要字段包括:
| YAML 字段 | Java 配置字段 | 作用 |
|---|---|---|
agent_class |
agentClass |
Agent 类型,例如 LlmAgent |
name |
name |
Agent 名称 |
description |
description |
Agent 描述 |
model |
model |
模型名称 |
instruction |
instruction |
任务指令 |
output_key |
outputKey |
把最终回复写入 session state |
tools |
tools |
工具或工具集引用 |
include_contents |
includeContents |
是否携带历史内容 |
generate_content_config |
generateContentConfig |
透传模型生成配置 |
disallow_transfer_to_parent |
disallowTransferToParent |
禁止向父 Agent 转交 |
disallow_transfer_to_peers |
disallowTransferToPeers |
禁止向同级 Agent 转交 |
before_agent_callbacks / after_agent_callbacks |
agent callbacks | Agent 前后回调 |
before_model_callbacks / after_model_callbacks |
model callbacks | 模型前后回调 |
before_tool_callbacks / after_tool_callbacks |
tool callbacks | 工具前后回调 |
8.3 Workflow YAML 示例
review-loop.yaml:
yaml
agent_class: LoopAgent
name: reviewLoop
description: 反复生成和审查,直到通过或达到最大次数
max_iterations: 3
sub_agents:
- config_path: writer.yaml
- config_path: reviewer.yaml
root.yaml:
yaml
agent_class: SequentialAgent
name: root
description: 生成、审查、总结
sub_agents:
- config_path: review-loop.yaml
- config_path: summarizer.yaml
sub_agents 支持两种引用方式:
| 写法 | 含义 |
|---|---|
config_path: writer.yaml |
从另一个 YAML 文件递归加载子 Agent,支持相对路径 |
code: someRegisteredAgent |
从 ComponentRegistry 里读取已注册的 Agent 实例 |
这种拆分方式比较适合多 Agent 应用:每个 LLM Agent 一个 YAML,workflow YAML 只负责组织结构。
8.4 Tool 和 Callback 如何配置
在 YAML 中,tools 是一组 ToolConfig:
yaml
tools:
- name: com.google.adk.tools.ExitLoopTool.INSTANCE
- name: com.example.tools.SearchTool
args:
endpoint: https://search.example.com
timeout_ms: 3000
源码里的 ToolResolver 会按顺序尝试:
- 从
ComponentRegistry解析已注册的 tool/toolset 实例。 - 如果
name像 Java 全限定名,尝试通过反射读取静态字段,例如com.google.adk.tools.ExitLoopTool.INSTANCE。 - 尝试把
name当成BaseTool子类,使用默认构造器创建。 - 如果提供了
args,要求工具类提供静态fromConfig(ToolArgsConfig, String)工厂方法。 - 对
BaseToolset也有类似解析逻辑。
ComponentRegistry 默认还预注册了几个常用工具实例,例如 google_search、code_execution、exit_loop、url_context、google_maps_grounding。因此退出循环工具也可以写成:
yaml
tools:
- name: exit_loop
Callback 引用也不是直接在 YAML 里写 Java 代码,而是写注册名:
yaml
before_model_callbacks:
- name: safetyGuard
after_tool_callbacks:
- name: auditToolResult
这些名字会通过 ComponentRegistry 解析成对应 callback 实例。因此,YAML 配置负责声明结构和引用,真正的 Java 对象仍然需要提前注册或能被反射创建。
8.5 YAML 配置的边界
ADK Java 1.2.0 的 YAML 能力适合描述 Agent 树和基础参数,但不要把它理解成完整的低代码编排语言。
| 能力 | 1.2.0 YAML 支持情况 |
|---|---|
创建 LlmAgent |
支持 |
创建 SequentialAgent / ParallelAgent / LoopAgent |
支持 |
用 sub_agents.config_path 组合多文件 Agent 树 |
支持 |
| 引用注册过的 Agent / Tool / Callback | 支持 |
配置 output_key、tools、generate_content_config |
支持 |
| 声明 if/else、switch、DAG 条件边 | 不支持 |
让 LoopAgent 自动解析 PASS/FAIL 文本停止 |
不支持,仍需要 tool/callback/custom agent 写入 escalate |
| 配置 Runner、SessionService、MemoryService、ArtifactService | 这套 Agent YAML 不负责,需要 Java 代码装配 Runner |
一句话总结:YAML 负责"声明 Agent 是谁、怎么连、带哪些工具和回调";Runner、会话服务、持久化、部署等运行时设施,仍然建议用 Java 代码显式装配。
9. 附录:ADK 能力组件速查表
| 能力组件 | 关键类/概念 | Java 1.2.0 状态 | 用途 | 使用建议 |
|---|---|---|---|---|
| 基础 Agent | BaseAgent |
支持 | 所有 Agent 的生命周期模板和父子树管理 | 自定义确定性节点时继承它 |
| LLM Agent | LlmAgent |
支持 | 调用模型、工具、规划、保存输出 | 常规智能任务首选 |
| 串行工作流 | SequentialAgent |
支持 | 子 Agent 逐个执行 | 适合流水线 |
| 并行工作流 | ParallelAgent |
支持 | 子 Agent 并发执行并合并事件流 | 注意 branch 和 outputKey 冲突 |
| 循环工作流 | LoopAgent |
支持 | 子 Agent 重复执行 | 停止依赖 maxIterations 或 escalate |
| Agent 树 | parentAgent、subAgents、rootAgent() |
支持 | 组织多 Agent 层级 | Agent 名称必须唯一 |
| 动态路由/转交 | transferToAgent、AutoFlow |
支持基础能力 | LLM 决定转交给父/同级 Agent | 复杂业务需加约束和观测 |
| 执行入口 | Runner |
支持 | 编排 Session、Agent、Plugin、Service | 生产中优先 Builder 和持久化服务 |
| 本地运行器 | InMemoryRunner |
支持 | 快速创建内存版 Runner | 适合 demo,不适合生产持久化 |
| 运行配置 | RunConfig |
支持 | 控制运行参数、流式、工具执行模式等 | 按接口场景显式传入 |
| 调用上下文 | InvocationContext |
支持 | 贯穿一次 invocation 的上下文对象 | Tool、Callback、Plugin 读取运行时信息 |
| 会话 | Session |
支持 | 保存会话 ID、用户、应用、状态、事件 | 作为一条对话线程管理 |
| 会话服务 | BaseSessionService、InMemorySessionService、VertexAiSessionService |
支持 | 创建、读取、追加事件、管理会话 | 生产换持久化实现 |
| 状态 | State |
支持 | 当前 Session 内工作内存和 delta 跟踪 | 用 outputKey 或 callback/tool 写入 |
| 长期记忆 | BaseMemoryService、InMemoryMemoryService |
支持 | 跨 Session 检索长期信息 | 用户画像、长期偏好、知识摘要 |
| 事件 | Event |
支持 | 用户消息、模型回复、工具调用、状态变化 | 调试和前端流式输出的核心 |
| 事件动作 | EventActions |
支持 | 状态变更、artifact 变更、转交、升级、确认请求 | 流程控制不要只依赖文本 |
| 内容 | Content |
支持 | 一条消息 | 由多个 Part 组成 |
| 消息片段 | Part |
支持 | 文本、函数调用、函数响应、文件/图片等 | 多模态入口使用它 |
| 工具基类 | BaseTool |
支持 | 工具声明和执行抽象 | 自定义复杂工具时继承 |
| 函数工具 | FunctionTool |
支持 | 把 Java 方法包装成模型可调用工具 | 参数建议加 @Schema |
| 长耗时工具 | LongRunningFunctionTool |
支持 | 处理需要异步确认或长时间执行的任务 | 适合工单、审批、外部任务 |
| Agent 作为工具 | AgentTool |
支持 | 让一个 Agent 被另一个 Agent 当工具调用 | 适合封装子能力 |
| 退出循环工具 | ExitLoopTool |
支持 | 设置 escalate=true 退出 Loop |
条件循环的标准做法 |
| 工具上下文 | ToolContext |
支持 | 工具访问 actions、memory、confirmation | 工具需要影响流程时使用 |
| 工具集 | BaseToolset |
支持 | 动态提供一组工具 | 适合 MCP、外部系统工具集合 |
| MCP 工具 | McpToolset、McpAsyncToolset、McpTool |
支持 | 接入 MCP Server 暴露的工具 | 适合外部工具生态 |
| 内置搜索/地图等工具 | GoogleSearchTool、GoogleMapsTool、VertexAiSearchTool 等 |
支持部分 | 搜索、地图、企业检索 | 视模型和平台权限使用 |
| 模型抽象 | BaseLlm、Model、LlmRegistry |
支持 | 屏蔽底层模型提供商差异 | 多模型接入从这里扩展 |
| Gemini 模型 | Gemini |
支持 | Google Gemini 接入 | 官方默认路线 |
| Claude/Apigee/Chat 模型适配 | Claude、ApigeeLlm、chat/* |
支持 | 非 Gemini 或网关接入 | 结合企业网关治理 |
| Spring AI 适配 | google-adk-spring-ai、SpringAI |
支持 | 把 Spring AI ChatModel 接入 ADK | 适合 Spring 项目 |
| Agent callback | beforeAgentCallback、afterAgentCallback |
支持 | 单 Agent 前后处理 | 局部逻辑用 callback |
| Model callback | beforeModelCallback、afterModelCallback、onModelErrorCallback |
支持 | 模型请求改写、响应审计、异常兜底 | 做 prompt 注入、缓存、降级 |
| Tool callback | beforeToolCallback、afterToolCallback、onToolErrorCallback |
支持 | 工具权限、参数校验、结果修正 | 生产必须加审计和权限 |
| Plugin | Plugin、BasePlugin、PluginManager |
支持 | Runner 全局拦截器 | 横切能力优先用 Plugin |
| 日志插件 | LoggingPlugin |
支持 | 记录运行过程 | 本地调试和审计 |
| 上下文过滤插件 | ContextFilterPlugin |
支持 | 控制上下文内容 | 控制成本和隐私 |
| 全局指令插件 | GlobalInstructionPlugin |
支持 | 注入全局要求 | 安全、风格、合规提示 |
| BigQuery 分析插件 | BigQueryAgentAnalyticsPlugin |
支持 | 事件和行为分析 | 企业观测场景 |
| Artifact | BaseArtifactService、InMemoryArtifactService |
支持 | 保存文件、图片、代码、报告等二进制产物 | 多模态和文件生成场景 |
| 输入文件落盘 | saveInputBlobsAsArtifacts |
支持 | 把 inline bytes 保存成 artifact | 大文件不要长期塞进 prompt |
| 代码执行 | BaseCodeExecutor、BuiltInCodeExecutionTool |
支持 | 让 Agent 生成并执行代码 | 注意沙箱和权限 |
| 规划 | planning |
支持 | 复杂任务拆解 | 需要配合 maxSteps 和工具观测 |
| 结构化输入输出 | inputSchema、outputSchema |
支持 | 限定模型输入输出结构 | 面向 API 集成时优先使用 |
| 流式执行 | runLive、LiveRequestQueue、ActiveStreamingTool |
支持部分 | 实时文本/音频/工具流 | Java 1.2 中 workflow live 支持不完整 |
| 事件压缩 | EventsCompactionConfig、SlidingWindowEventCompactor |
支持 | 控制长会话上下文长度 | 长对话生产环境需要 |
| Dev UI | google-adk-dev、AdkWebServer |
支持 | 本地调试 Agent | 只用于开发调试 |
| 评估 | 官方 CLI/Dev UI evaluation | 生态支持 | 多轮数据集评估 Agent 质量 | 生产前应建立回归集 |
| 部署 | 官方运行时/Cloud Run/GKE 等 | 生态支持 | 上线 Agent 应用 | Java 项目需结合自身服务框架 |
| A2A | A2A Protocol 文档与组件 | 生态支持 | Agent 间协议互操作 | 多 Agent 跨系统协作时关注 |
10. 参考资料
- ADK Technical Overview: https://adk.dev/get-started/about/
- ADK Java Quickstart: https://adk.dev/get-started/java/
- ADK Agents: https://adk.dev/agents/
- ADK Template Agent Workflows: https://adk.dev/agents/workflow-agents/
- ADK Session, State, Memory: https://adk.dev/sessions/
- ADK Function Tools: https://adk.dev/tools-custom/function-tools/
- ADK Callbacks: https://adk.dev/callbacks/
- ADK Plugins: https://adk.dev/plugins/
- ADK Java API Reference: https://adk.dev/api-reference/java/
- 本地源码:
~/.m2/repository/com/google/adk/google-adk/1.2.0/google-adk-1.2.0-sources.jar