ADK架构总览:模块化设计与核心组件

ADK Go架构总览:模块化设计与核心组件

1. 什么是 ADK

ADK(Agent Development Kit)是 Google 开源的智能体开发工具包。它的目标是让智能体开发更像传统的软件开发:有清晰的接口、模块化的组件、可测试的代码。

ADK 支持多种语言:Python、Go、TypeScript 和 Java。其中,Go 版本特别适合构建需要高性能和并发处理能力的云原生智能体应用。

根据 pkg.go.dev 的官方文档,ADK 的核心价值在于:

ADK applies software development principles to AI agent creation, making it easier to build, deploy, and orchestrate agentic architectures.

简单来说,ADK 把软件工程的最佳实践(接口设计、模块化、可测试性)应用到智能体开发中。

1.1 核心概念

根据 ADK 官方文档,ADK 围绕以下关键概念构建:

  • Agent(智能体) :执行特定任务的基本工作单元。智能体可以使用语言模型(LLMAgent)进行复杂推理,或者作为确定性的执行控制器(工作流智能体:SequentialAgentParallelAgentLoopAgent)。
  • Tool(工具):赋予智能体对话之外的能力,让它可以调用外部 API、搜索信息、运行代码或调用其他服务。
  • Callbacks(回调):在智能体执行过程中的特定点运行的自定义代码片段,用于检查、日志记录或行为修改。
  • Session Management(会话管理) :处理单个对话的上下文(Session),包括对话历史(Events)和智能体的工作记忆(State)。
  • Memory(记忆):让智能体跨多个会话回忆关于用户的信息,提供长期上下文(区别于短期会话状态)。
  • Artifact Management(制品管理):允许智能体保存、加载和管理与会话或用户相关的文件或二进制数据(如图像、PDF)。
  • Event(事件):会话中发生的事情的基本通信单元(用户消息、智能体回复、工具使用),形成对话历史。
  • Runner(运行器):管理执行流程的引擎,根据事件编排智能体交互,并与后端服务协调。

1.2 核心特性

根据 pkg.go.dev 官方 README 和 ADK 官方文档,ADK Go 具有以下核心特性:

  1. 地道的 Go(Idiomatic Go):设计上充分利用 Go 语言的特性,让代码写起来自然顺畅。Go 的并发模型(goroutine)、强类型系统、接口组合都在框架中得到了体现。
  2. 丰富的工具生态(Rich Tool Ecosystem) :提供预置工具、自定义函数工具、以及集成现有工具的能力。智能体可以拥有多样化的能力,支持将自定义函数(FunctionTool)和其他智能体(AgentTool)作为工具使用。
  3. 代码优先开发(Code-First Development):直接用 Go 代码定义智能体逻辑、工具和编排。这带来了极致的灵活性、可测试性和版本控制能力。
  4. 模块化多智能体系统(Modular Multi-Agent Systems) :通过组合多个专用智能体,设计可扩展的应用。支持层次化的多智能体系统,智能体可以通过 LLM 驱动的转移或显式的 AgentTool 调用来协调复杂任务。
  5. 灵活的编排(Flexible Orchestration) :使用内置的工作流智能体(SequentialAgentParallelAgentLoopAgent)以及 LLM 驱动的动态路由来定义复杂的智能体工作流。
  6. 随处部署(Deploy Anywhere):轻松容器化并部署智能体,对 Google Cloud Run 等云原生环境有良好支持。
  7. 原生流式支持(Native Streaming Support):支持双向流式传输(文本和音频),构建实时交互体验。

1.3 与其他框架的区别

ADK Go 不是一个把所有功能都封装好的"黑盒"。它是一套精心设计的"乐高积木"。你定义一个"查询数据库"的工具时,就是在写一个标准的 Go 函数。它的输入输出类型、错误处理、外部依赖,都在代码里一目了然。这种透明度和可控性,对于构建生产级的多智能体系统至关重要。

1.4 从一个实际问题出发

假设你要构建一个 AI 智能体应用。这个应用需要:

  1. 能够理解用户的问题并给出回答
  2. 可以调用外部工具(如搜索、计算等)
  3. 能够记住对话历史,进行多轮对话
  4. 支持多个智能体协作完成复杂任务
  5. 可以灵活切换不同的语言模型
  6. 能够调用远程智能体(A2A)
  7. 支持长期记忆(跨会话)
  8. 管理文件和制品(Artifacts)
  9. 易于部署到不同的环境

如果从零开始实现,你需要:定义智能体的接口和行为、实现工具调用机制、设计会话管理系统、构建多智能体编排框架、抽象语言模型接口、添加插件系统用于横切关注点、实现远程智能体通信(A2A)、构建长期记忆服务、设计制品管理系统。

这正是 ADK 要解决的问题。ADK 将上述所有功能模块化,让开发者可以专注于业务逻辑。

1.5 快速入门:五分钟构建第一个智能体

根据 官方快速入门 的示例,用 ADK Go 构建一个智能体只需要三步。

首先,需要导入以下包:

go 复制代码
import (
    "context"
    "log"
    "os"

    "google.golang.org/adk/agent"
    "google.golang.org/adk/agent/llmagent"
    "google.golang.org/adk/cmd/launcher"
    "google.golang.org/adk/cmd/launcher/full"
    "google.golang.org/adk/model/gemini"
    "google.golang.org/adk/tool"
    "google.golang.org/adk/tool/geminitool"
    "google.golang.org/genai"
)

第一步:创建模型

go 复制代码
// 创建一个 Gemini 模型实例,传入模型名称和 API Key
// 这个模型实例实现了 model.LLM 接口,可以被任何智能体使用
model, err := gemini.NewModel(ctx, "gemini-2.5-flash", &genai.ClientConfig{
    // APIKey 从环境变量中读取 Google API 密钥
    APIKey: os.Getenv("GOOGLE_API_KEY"),
})

第二步:创建智能体

go 复制代码
// 使用 llmagent.New 创建一个基于 LLM 的智能体
timeAgent, err := llmagent.New(llmagent.Config{
    // Name 是智能体的唯一标识,用于路由和转移
    Name:        "hello_time_agent",
    // Model 是上面创建的 Gemini 模型实例
    Model:       model,
    // Description 描述智能体的职责,帮助 LLM 在多智能体场景中理解何时转移
    Description: "Tells the current time in a specified city.",
    // Instruction 是系统指令,告诉 LLM 如何扮演这个角色
    Instruction: "You are a helpful assistant that tells the current time in a city.",
    // Tools 是智能体可以使用的工具列表
    Tools: []tool.Tool{
        // geminitool.GoogleSearch 提供 Google 搜索能力
        geminitool.GoogleSearch{},
    },
})

第三步:启动运行

go 复制代码
// 创建启动器配置,包含智能体加载器
config := &launcher.Config{
    // AgentLoader 使用 SingleLoader 包装单个智能体
    AgentLoader: agent.NewSingleLoader(timeAgent),
}

// 创建全功能启动器,同时支持控制台和 Web 模式
// full.NewLauncher() 内部组合了 console 和 web 启动器
// web 启动器又包含 webui、a2a、pubsub、eventarc、api 子启动器
l := full.NewLauncher()
// Execute 解析命令行参数并启动智能体服务
if err = l.Execute(ctx, config, os.Args[1:]); err != nil {
    // 启动失败时打印错误信息和命令行语法帮助
    log.Fatalf("Run failed: %v\n\n%s", err, l.CommandLineSyntax())
}

运行智能体:

bash 复制代码
# 命令行模式:启动交互式终端对话
go run agent.go

# Web 界面模式:启动 Web UI 进行对话(需要先加载环境变量:source .env)
go run agent.go web api webui

注意:ADK Web UI 仅用于开发和调试,不建议在生产环境中使用。

这个示例展示了 ADK Go 的核心设计理念:代码优先。你不需要写配置文件,不需要拖拽 UI,所有逻辑都在 Go 代码中清晰可见。

系统要求:Go 1.24.4 或更高版本,ADK Go v0.2.0 或更高版本。

2. 架构总览

2.1 智能体调用的三层层级模型

理解 ADK 的架构,首先要理解它的三层执行层级。这个模型定义在 context.go 的注释中,是整个框架的核心概念。
#mermaid-svg-NjVYCEMS4vode66e{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NjVYCEMS4vode66e .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NjVYCEMS4vode66e .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NjVYCEMS4vode66e .error-icon{fill:#552222;}#mermaid-svg-NjVYCEMS4vode66e .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NjVYCEMS4vode66e .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NjVYCEMS4vode66e .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NjVYCEMS4vode66e .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NjVYCEMS4vode66e .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NjVYCEMS4vode66e .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NjVYCEMS4vode66e .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NjVYCEMS4vode66e .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NjVYCEMS4vode66e .marker.cross{stroke:#333333;}#mermaid-svg-NjVYCEMS4vode66e svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NjVYCEMS4vode66e p{margin:0;}#mermaid-svg-NjVYCEMS4vode66e .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NjVYCEMS4vode66e .cluster-label text{fill:#333;}#mermaid-svg-NjVYCEMS4vode66e .cluster-label span{color:#333;}#mermaid-svg-NjVYCEMS4vode66e .cluster-label span p{background-color:transparent;}#mermaid-svg-NjVYCEMS4vode66e .label text,#mermaid-svg-NjVYCEMS4vode66e span{fill:#333;color:#333;}#mermaid-svg-NjVYCEMS4vode66e .node rect,#mermaid-svg-NjVYCEMS4vode66e .node circle,#mermaid-svg-NjVYCEMS4vode66e .node ellipse,#mermaid-svg-NjVYCEMS4vode66e .node polygon,#mermaid-svg-NjVYCEMS4vode66e .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NjVYCEMS4vode66e .rough-node .label text,#mermaid-svg-NjVYCEMS4vode66e .node .label text,#mermaid-svg-NjVYCEMS4vode66e .image-shape .label,#mermaid-svg-NjVYCEMS4vode66e .icon-shape .label{text-anchor:middle;}#mermaid-svg-NjVYCEMS4vode66e .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NjVYCEMS4vode66e .rough-node .label,#mermaid-svg-NjVYCEMS4vode66e .node .label,#mermaid-svg-NjVYCEMS4vode66e .image-shape .label,#mermaid-svg-NjVYCEMS4vode66e .icon-shape .label{text-align:center;}#mermaid-svg-NjVYCEMS4vode66e .node.clickable{cursor:pointer;}#mermaid-svg-NjVYCEMS4vode66e .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NjVYCEMS4vode66e .arrowheadPath{fill:#333333;}#mermaid-svg-NjVYCEMS4vode66e .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NjVYCEMS4vode66e .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NjVYCEMS4vode66e .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NjVYCEMS4vode66e .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NjVYCEMS4vode66e .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NjVYCEMS4vode66e .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NjVYCEMS4vode66e .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NjVYCEMS4vode66e .cluster text{fill:#333;}#mermaid-svg-NjVYCEMS4vode66e .cluster span{color:#333;}#mermaid-svg-NjVYCEMS4vode66e div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NjVYCEMS4vode66e .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NjVYCEMS4vode66e rect.text{fill:none;stroke-width:0;}#mermaid-svg-NjVYCEMS4vode66e .icon-shape,#mermaid-svg-NjVYCEMS4vode66e .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NjVYCEMS4vode66e .icon-shape p,#mermaid-svg-NjVYCEMS4vode66e .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NjVYCEMS4vode66e .icon-shape .label rect,#mermaid-svg-NjVYCEMS4vode66e .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NjVYCEMS4vode66e .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NjVYCEMS4vode66e .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NjVYCEMS4vode66e :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 持续运行直到

不再请求转移
🔄 Invocation(一次调用)--- 由 runner.Run() 处理
📞 Agent Call 2
... 继续执行 ...
📞 Agent Call 1 --- 由 agent.Run() 处理
📌 Step 2
① call_llm

调用 LLM
② transfer

转移到另一个智能体
📌 Step 1
① call_llm

调用 LLM
② call_tool

执行工具
✅ 最终响应

这三层的含义是:

  • Invocation(调用) :从用户消息开始,到最终响应结束。一次调用可以包含一个或多个智能体调用。它由 runner.Run() 处理。一次调用会持续运行,直到智能体不再请求转移到另一个智能体。
  • Agent Call(智能体调用) :由 agent.Run() 处理。一个智能体调用可以包含一个或多个步骤。智能体调用在 agent.Run() 结束时结束。
  • Step(步骤):一个步骤只调用一次 LLM 并返回其响应。如果 LLM 请求工具调用,步骤也会调用工具并返回工具响应。函数响应的总结被视为另一个步骤,因为它需要再次调用 LLM。

这个层级模型解释了为什么 ADK 能支持复杂的多智能体协作:一次用户消息可以触发多个智能体的链式调用,每个智能体内部又可以进行多轮的 LLM 推理和工具调用。

2.2 整体架构图

ADK Go 采用模块化设计,将智能体开发分解为多个独立的组件。这些组件通过接口进行交互,具有高度的可扩展性和可替换性。
#mermaid-svg-MkknHV3y8YxKdmut{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MkknHV3y8YxKdmut .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MkknHV3y8YxKdmut .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MkknHV3y8YxKdmut .error-icon{fill:#552222;}#mermaid-svg-MkknHV3y8YxKdmut .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MkknHV3y8YxKdmut .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MkknHV3y8YxKdmut .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MkknHV3y8YxKdmut .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MkknHV3y8YxKdmut .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MkknHV3y8YxKdmut .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MkknHV3y8YxKdmut .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MkknHV3y8YxKdmut .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MkknHV3y8YxKdmut .marker.cross{stroke:#333333;}#mermaid-svg-MkknHV3y8YxKdmut svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MkknHV3y8YxKdmut p{margin:0;}#mermaid-svg-MkknHV3y8YxKdmut .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MkknHV3y8YxKdmut .cluster-label text{fill:#333;}#mermaid-svg-MkknHV3y8YxKdmut .cluster-label span{color:#333;}#mermaid-svg-MkknHV3y8YxKdmut .cluster-label span p{background-color:transparent;}#mermaid-svg-MkknHV3y8YxKdmut .label text,#mermaid-svg-MkknHV3y8YxKdmut span{fill:#333;color:#333;}#mermaid-svg-MkknHV3y8YxKdmut .node rect,#mermaid-svg-MkknHV3y8YxKdmut .node circle,#mermaid-svg-MkknHV3y8YxKdmut .node ellipse,#mermaid-svg-MkknHV3y8YxKdmut .node polygon,#mermaid-svg-MkknHV3y8YxKdmut .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MkknHV3y8YxKdmut .rough-node .label text,#mermaid-svg-MkknHV3y8YxKdmut .node .label text,#mermaid-svg-MkknHV3y8YxKdmut .image-shape .label,#mermaid-svg-MkknHV3y8YxKdmut .icon-shape .label{text-anchor:middle;}#mermaid-svg-MkknHV3y8YxKdmut .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MkknHV3y8YxKdmut .rough-node .label,#mermaid-svg-MkknHV3y8YxKdmut .node .label,#mermaid-svg-MkknHV3y8YxKdmut .image-shape .label,#mermaid-svg-MkknHV3y8YxKdmut .icon-shape .label{text-align:center;}#mermaid-svg-MkknHV3y8YxKdmut .node.clickable{cursor:pointer;}#mermaid-svg-MkknHV3y8YxKdmut .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MkknHV3y8YxKdmut .arrowheadPath{fill:#333333;}#mermaid-svg-MkknHV3y8YxKdmut .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MkknHV3y8YxKdmut .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MkknHV3y8YxKdmut .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MkknHV3y8YxKdmut .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MkknHV3y8YxKdmut .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MkknHV3y8YxKdmut .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MkknHV3y8YxKdmut .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MkknHV3y8YxKdmut .cluster text{fill:#333;}#mermaid-svg-MkknHV3y8YxKdmut .cluster span{color:#333;}#mermaid-svg-MkknHV3y8YxKdmut div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MkknHV3y8YxKdmut .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MkknHV3y8YxKdmut rect.text{fill:none;stroke-width:0;}#mermaid-svg-MkknHV3y8YxKdmut .icon-shape,#mermaid-svg-MkknHV3y8YxKdmut .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MkknHV3y8YxKdmut .icon-shape p,#mermaid-svg-MkknHV3y8YxKdmut .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MkknHV3y8YxKdmut .icon-shape .label rect,#mermaid-svg-MkknHV3y8YxKdmut .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MkknHV3y8YxKdmut .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MkknHV3y8YxKdmut .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MkknHV3y8YxKdmut :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 基础设施层
ADK 核心层
用户应用层
用户代码
Runner
Agent 接口
LLMAgent
WorkflowAgents
RemoteAgent
SequentialAgent
ParallelAgent
LoopAgent
Tool 接口
FunctionTool
GeminiTool
AgentTool
SkillToolset
MCPToolset
ExitLoopTool
LoadMemoryTool
LoadArtifactsTool
Session Service
InMemory
Model 接口
Gemini
Apigee
Plugin 接口
LoggingPlugin
RetryAndReflect
FunctionCallModifier
ArtifactService
InMemory
GCS
MemoryService
InMemory
VertexAI
外部 Session 存储

Database / Redis
外部 Artifact 存储

GCS / S3
A2A Protocol

2.3 核心组件概览

ADK Go 包含以下核心组件:

组件 职责 关键文件
Agent 智能体的抽象接口,定义智能体的基本行为 agent.go
LLMAgent 基于 LLM 的智能体,实现 ReAct 循环 llmagent.go
WorkflowAgents 工作流智能体,编排多个子智能体 sequentialagent, parallelagent, loopagent
RemoteAgent 远程智能体,通过 A2A 协议调用外部智能体 remoteagent
Tool 工具接口,定义智能体可以调用的能力 tool.go
FunctionTool 将 Go 函数包装为工具,支持泛型和自动 Schema 生成 function.go
AgentTool 将智能体包装为工具,支持智能体组合 agent_tool.go
Session 会话管理,保存对话历史和状态 session.go
Model 语言模型抽象,支持多种模型后端 llm.go
Runner 执行引擎,协调所有组件的运行 runner.go
Plugin 插件系统,处理横切关注点 plugin.go
Artifact 制品管理,保存和加载文件 artifact
Memory 记忆服务,跨会话检索信息 memory

2.4 ADK v1.4.0 模块列表

根据 pkg.go.dev 的官方文档,ADK Go 当前最新版本为 v1.4.0(发布于 2026 年 5 月 29 日)。这个版本包含了丰富的功能模块:

模块分类 包路径 功能说明
智能体核心 agent 智能体基础接口和实现
agent/llmagent 基于 LLM 的智能体,实现 ReAct 循环
agent/remoteagent 远程智能体(A2A 协议 v1)
agent/remoteagent/v2 远程智能体(A2A 协议 v2)
工作流智能体 agent/workflowagents/sequentialagent 顺序执行子智能体
agent/workflowagents/parallelagent 并行执行子智能体
agent/workflowagents/loopagent 循环执行子智能体
工具系统 tool 工具接口和工具集
tool/functiontool Go 函数包装为工具
tool/agenttool 智能体包装为工具
tool/geminitool Gemini 原生工具(如 Google 搜索)
tool/skilltoolset Skill 工具集
tool/mcptoolset MCP 协议工具集
tool/exitlooptool 退出循环工具
tool/preloadmemorytool 预加载记忆工具
tool/loadmemorytool 加载记忆工具
tool/loadartifactstool 加载制品工具
会话管理 session 会话、状态、事件管理
模型抽象 model LLM 接口定义
model/gemini Gemini 模型实现
model/apigee Apigee 网关模型
插件系统 plugin 插件接口和管理器
plugin/loggingplugin 日志插件
plugin/retryandreflect 重试与反思插件
plugin/functioncallmodifier 函数调用修改插件
制品服务 artifact 制品管理接口
artifact/gcsartifact GCS 制品存储实现
记忆服务 memory 长期记忆接口
memory/vertexai Vertex AI 记忆实现
执行引擎 runner 智能体运行器
CLI 工具 cmd/adkgo ADK Go 命令行工具
启动器 cmd/launcher/console 控制台启动器
cmd/launcher/web Web 启动器
cmd/launcher/web/api REST API 子启动器(web 子包)
cmd/launcher/web/a2a A2A 协议子启动器(web 子包)
cmd/launcher/universal 通用启动器(同时包含 console 和 web)
cmd/launcher/full 全功能启动器(开发 + 生产)
cmd/launcher/prod 生产环境启动器(仅 REST API + A2A)
cmd/launcher/agentengine Agent Engine 部署启动器

3. 设计哲学:接口驱动的模块化

ADK Go 的核心设计哲学是接口驱动的模块化。每个组件都通过接口定义行为,具体实现可以灵活替换。

3.1 Agent 接口

从最核心的 Agent 接口开始:

go 复制代码
// Agent 接口定义 --- ADK 的核心抽象,所有智能体都必须实现此接口
type Agent interface {
    // Name 返回智能体的名称,用于标识和路由
    Name() string
    // Description 返回智能体的描述,帮助 LLM 理解何时转移给此智能体
    Description() string
    // Run 执行智能体,返回事件迭代器供流式消费
    // Go 1.22+ 的 iterator 模式,支持按需产出事件
    Run(InvocationContext) iter.Seq2[*session.Event, error]
    // SubAgents 返回所有子智能体
    SubAgents() []Agent
    // FindAgent 在整个智能体树中递归查找指定名称的智能体
    FindAgent(name string) Agent
    // FindSubAgent 仅在直接子智能体中查找
    FindSubAgent(name string) Agent
    // internal 返回内部实现,用于揭示 Agent 的具体类型和状态
    // 注意:这是一个未导出方法,仅框架内部使用
    internal() *agent
}

这个接口定义了智能体的基本行为:

  • Name()Description():标识智能体,用于路由和描述
  • Run():核心执行方法,接收 InvocationContext,返回事件迭代器
  • SubAgents()FindAgent()FindSubAgent():支持子智能体和智能体树管理
  • internal():内部方法,返回 *agent 指针,用于框架内部访问智能体的私有状态

注意:当前 ADK 文档明确说明"未来版本将允许直接实现此接口,目前请使用 agent.New() 创建自定义智能体"。

注意 Run 方法返回的是 iter.Seq2[*session.Event, error]。这是 Go 1.22 引入的 iterator 模式,它允许智能体产生一系列事件,而不是一次性返回所有结果。
事件迭代器 Agent Runner 用户 事件迭代器 Agent Runner 用户 #mermaid-svg-zsCR4HAEw5N2W91o{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zsCR4HAEw5N2W91o .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zsCR4HAEw5N2W91o .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zsCR4HAEw5N2W91o .error-icon{fill:#552222;}#mermaid-svg-zsCR4HAEw5N2W91o .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zsCR4HAEw5N2W91o .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zsCR4HAEw5N2W91o .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zsCR4HAEw5N2W91o .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zsCR4HAEw5N2W91o .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zsCR4HAEw5N2W91o .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zsCR4HAEw5N2W91o .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zsCR4HAEw5N2W91o .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zsCR4HAEw5N2W91o .marker.cross{stroke:#333333;}#mermaid-svg-zsCR4HAEw5N2W91o svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zsCR4HAEw5N2W91o p{margin:0;}#mermaid-svg-zsCR4HAEw5N2W91o .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-zsCR4HAEw5N2W91o text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-zsCR4HAEw5N2W91o .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-zsCR4HAEw5N2W91o .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-zsCR4HAEw5N2W91o .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-zsCR4HAEw5N2W91o .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-zsCR4HAEw5N2W91o #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-zsCR4HAEw5N2W91o .sequenceNumber{fill:white;}#mermaid-svg-zsCR4HAEw5N2W91o #sequencenumber{fill:#333;}#mermaid-svg-zsCR4HAEw5N2W91o #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-zsCR4HAEw5N2W91o .messageText{fill:#333;stroke:none;}#mermaid-svg-zsCR4HAEw5N2W91o .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-zsCR4HAEw5N2W91o .labelText,#mermaid-svg-zsCR4HAEw5N2W91o .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-zsCR4HAEw5N2W91o .loopText,#mermaid-svg-zsCR4HAEw5N2W91o .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-zsCR4HAEw5N2W91o .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-zsCR4HAEw5N2W91o .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-zsCR4HAEw5N2W91o .noteText,#mermaid-svg-zsCR4HAEw5N2W91o .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-zsCR4HAEw5N2W91o .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-zsCR4HAEw5N2W91o .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-zsCR4HAEw5N2W91o .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-zsCR4HAEw5N2W91o .actorPopupMenu{position:absolute;}#mermaid-svg-zsCR4HAEw5N2W91o .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-zsCR4HAEw5N2W91o .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-zsCR4HAEw5N2W91o .actor-man circle,#mermaid-svg-zsCR4HAEw5N2W91o line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-zsCR4HAEw5N2W91o :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} loop 每个事件 Run() Run(ctx) 返回事件迭代器 yield(event, err) 返回事件

这种设计的好处是:

  1. 流式输出:支持实时流式响应,不需要等待所有结果
  2. 惰性计算:事件按需生成,节省资源
  3. 优雅退出:消费者可以随时停止迭代

3.2 接口隔离原则

ADK Go 遵循接口隔离原则------每个接口只定义必要的方法,不强迫实现不需要的功能。

go 复制代码
// Session 接口定义会话的基本操作
type Session interface {
    // ID 返回会话的唯一标识符
    ID() string
    // AppName 返回所属应用的名称
    AppName() string
    // UserID 返回会话所属用户的标识符
    UserID() string
    // State 返回会话的读写状态
    State() State
    // Events 返回会话中的所有事件
    Events() Events
    // LastUpdateTime 返回会话的最后更新时间
    LastUpdateTime() time.Time
}

// ReadonlyState 接口定义只读的状态访问
// 不需要修改权限的组件可以使用这个更窄的接口
type ReadonlyState interface {
    // Get 根据键名获取状态值
    Get(string) (any, error)
    // All 返回所有状态键值对的迭代器
    All() iter.Seq2[string, any]
}

ReadonlyState 只提供读取方法,不需要修改权限的组件可以使用这个接口,体现了接口隔离原则。

3.3 组合优于继承

ADK Go 大量使用组合模式,而不是继承。

go 复制代码
// llmAgent 是基于 LLM 的智能体实现,通过组合复用多个组件
type llmAgent struct {
    // agent.Agent 嵌入基础智能体,获得 Agent 接口的默认行为(Name/Description/SubAgents/FindAgent)
    agent.Agent
    // llminternal.State 组合 LLM 智能体的内部状态管理
    llminternal.State
    // model 是底层的 LLM 模型实例
    model                 model.LLM
    // instruction 是系统指令,告诉 LLM 如何扮演这个角色
    instruction           string
    // inputSchema/outputSchema 是输入输出的 JSON Schema 约束
    inputSchema           *jsonschema.Schema
    outputSchema          *jsonschema.Schema
    // 回调函数列表,用于在各个执行阶段插入自定义逻辑
    beforeModelCallbacks  []llminternal.BeforeModelCallback
    afterModelCallbacks   []llminternal.AfterModelCallback
    onModelErrorCallbacks []llminternal.OnModelErrorCallback
    beforeToolCallbacks   []llminternal.BeforeToolCallback
    afterToolCallbacks    []llminternal.AfterToolCallback
    onToolErrorCallbacks  []llminternal.OnToolErrorCallback
}

llmAgent 的创建过程体现了组合模式的优势:

  1. 基础智能体创建 :通过 agent.New() 创建一个基础智能体实例,传入名称、描述、子智能体和自定义的 run 函数
  2. 嵌入基础智能体 :将基础智能体嵌入到 llmAgent 中,获得 Agent 接口的所有默认实现
  3. 设置智能体类型 :通过 agentinternal.Reveal() 获取内部状态,设置 AgentType = TypeLLMAgent
  4. 初始化 LLM 状态 :填充 llminternal.State 的字段,包括模型、工具、指令等

这种设计使得 llmAgent 可以专注于 LLM 相关的逻辑,而不需要重复实现 Agent 接口的通用方法。

4. 核心执行流程

4.1 ReAct 循环

一个典型的智能体执行流程:
#mermaid-svg-rEyaHHrKC4CAIH2l{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-rEyaHHrKC4CAIH2l .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-rEyaHHrKC4CAIH2l .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-rEyaHHrKC4CAIH2l .error-icon{fill:#552222;}#mermaid-svg-rEyaHHrKC4CAIH2l .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-rEyaHHrKC4CAIH2l .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-rEyaHHrKC4CAIH2l .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-rEyaHHrKC4CAIH2l .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-rEyaHHrKC4CAIH2l .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-rEyaHHrKC4CAIH2l .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-rEyaHHrKC4CAIH2l .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-rEyaHHrKC4CAIH2l .marker{fill:#333333;stroke:#333333;}#mermaid-svg-rEyaHHrKC4CAIH2l .marker.cross{stroke:#333333;}#mermaid-svg-rEyaHHrKC4CAIH2l svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-rEyaHHrKC4CAIH2l p{margin:0;}#mermaid-svg-rEyaHHrKC4CAIH2l .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-rEyaHHrKC4CAIH2l .cluster-label text{fill:#333;}#mermaid-svg-rEyaHHrKC4CAIH2l .cluster-label span{color:#333;}#mermaid-svg-rEyaHHrKC4CAIH2l .cluster-label span p{background-color:transparent;}#mermaid-svg-rEyaHHrKC4CAIH2l .label text,#mermaid-svg-rEyaHHrKC4CAIH2l span{fill:#333;color:#333;}#mermaid-svg-rEyaHHrKC4CAIH2l .node rect,#mermaid-svg-rEyaHHrKC4CAIH2l .node circle,#mermaid-svg-rEyaHHrKC4CAIH2l .node ellipse,#mermaid-svg-rEyaHHrKC4CAIH2l .node polygon,#mermaid-svg-rEyaHHrKC4CAIH2l .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-rEyaHHrKC4CAIH2l .rough-node .label text,#mermaid-svg-rEyaHHrKC4CAIH2l .node .label text,#mermaid-svg-rEyaHHrKC4CAIH2l .image-shape .label,#mermaid-svg-rEyaHHrKC4CAIH2l .icon-shape .label{text-anchor:middle;}#mermaid-svg-rEyaHHrKC4CAIH2l .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-rEyaHHrKC4CAIH2l .rough-node .label,#mermaid-svg-rEyaHHrKC4CAIH2l .node .label,#mermaid-svg-rEyaHHrKC4CAIH2l .image-shape .label,#mermaid-svg-rEyaHHrKC4CAIH2l .icon-shape .label{text-align:center;}#mermaid-svg-rEyaHHrKC4CAIH2l .node.clickable{cursor:pointer;}#mermaid-svg-rEyaHHrKC4CAIH2l .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-rEyaHHrKC4CAIH2l .arrowheadPath{fill:#333333;}#mermaid-svg-rEyaHHrKC4CAIH2l .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-rEyaHHrKC4CAIH2l .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-rEyaHHrKC4CAIH2l .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rEyaHHrKC4CAIH2l .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-rEyaHHrKC4CAIH2l .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rEyaHHrKC4CAIH2l .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-rEyaHHrKC4CAIH2l .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-rEyaHHrKC4CAIH2l .cluster text{fill:#333;}#mermaid-svg-rEyaHHrKC4CAIH2l .cluster span{color:#333;}#mermaid-svg-rEyaHHrKC4CAIH2l div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-rEyaHHrKC4CAIH2l .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-rEyaHHrKC4CAIH2l rect.text{fill:none;stroke-width:0;}#mermaid-svg-rEyaHHrKC4CAIH2l .icon-shape,#mermaid-svg-rEyaHHrKC4CAIH2l .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-rEyaHHrKC4CAIH2l .icon-shape p,#mermaid-svg-rEyaHHrKC4CAIH2l .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-rEyaHHrKC4CAIH2l .icon-shape .label rect,#mermaid-svg-rEyaHHrKC4CAIH2l .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-rEyaHHrKC4CAIH2l .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-rEyaHHrKC4CAIH2l .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-rEyaHHrKC4CAIH2l :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

工具调用
直接回答
用户输入
Runner.Run
会话存在?
获取会话
创建会话
追加用户消息事件
查找目标智能体
创建调用上下文
执行智能体
循环: ReAct
调用 LLM
LLM 返回
执行工具
工具响应事件
最终响应事件
结束
返回事件序列
持久化事件
返回结果

整个流程可以分为几个阶段:

阶段一:会话管理

Runner 首先检查会话是否存在。如果不存在,会创建新会话。然后将用户消息追加为事件。

阶段二:智能体路由

Runner 根据会话历史和当前消息,决定由哪个智能体来处理请求。这支持智能体转移和多智能体协作。

阶段三:ReAct 循环

对于 LLMAgent,核心是 ReAct(Reason + Act)循环:

  1. 调用 LLM 获取响应
  2. 如果响应包含工具调用,则执行工具
  3. 将工具执行结果作为新的输入,再次调用 LLM
  4. 重复直到 LLM 直接给出回答

阶段四:事件持久化

所有事件都会被持久化到会话服务中,确保对话历史不会丢失。

4.2 事件驱动架构

ADK 的核心是事件驱动架构。所有的状态变化和交互都通过事件来传递。

go 复制代码
// Event 结构体定义了事件的核心数据结构
type Event struct {
    // LLMResponse 是 LLM 的原始响应(嵌入),包含内容、工具调用等
    model.LLMResponse
    // ID 是事件的唯一标识符
    ID           string
    // Timestamp 是事件创建的时间戳
    Timestamp    time.Time
    // InvocationID 是调用 ID,同一调用中的所有事件共享此 ID
    InvocationID string
    // Branch 是分支路径,用于多智能体场景中的事件隔离
    Branch       string
    // Author 是事件作者,取值是用户标识或智能体名称
    Author       string
    // Actions 是事件附带的动作,如状态修改、智能体转移等
    Actions      EventActions
    // LongRunningToolIDs 是长时间运行的工具 ID 列表
    LongRunningToolIDs []string
}

事件包含几个关键字段:

字段 作用
LLMResponse LLM 的原始响应(嵌入)
ID 事件唯一标识
InvocationID 调用 ID,同一调用的事件共享
Branch 分支路径,用于多智能体隔离
Author 事件作者(用户或智能体名称)
Actions 事件附带的动作

4.3 EventActions:事件的副作用

EventActions 定义了事件可以触发的动作:

go 复制代码
// EventActions 定义了事件可以触发的副作用动作
type EventActions struct {
    // StateDelta 是状态变更映射,键值对会合并到会话状态中
    StateDelta                 map[string]any
    // ArtifactDelta 是制品变更映射,键是文件名,值是版本号
    ArtifactDelta              map[string]int64
    // RequestedToolConfirmations 是需要人工确认的工具调用
    RequestedToolConfirmations map[string]toolconfirmation.ToolConfirmation
    // SkipSummarization 标记是否跳过摘要生成
    SkipSummarization          bool
    // TransferToAgent 指定要转移到的目标智能体名称
    TransferToAgent            string
    // Escalate 标记是否升级或退出循环
    Escalate                   bool
}

通过 EventActions,智能体可以:

  • 修改会话状态(StateDelta
  • 更新制品(ArtifactDelta
  • 请求人工确认(RequestedToolConfirmations
  • 跳过摘要(SkipSummarization
  • 转移到其他智能体(TransferToAgent
  • 升级/退出循环(Escalate

这种设计使得事件不仅是数据记录,还可以携带"命令"。

5. 三级状态作用域

ADK 支持三级状态作用域,通过键前缀来区分:

go 复制代码
// 状态键前缀常量,定义了三种作用域
const (
    // KeyPrefixApp 是应用级状态的前缀,所有用户所有会话共享
    KeyPrefixApp  string = "app:"
    // KeyPrefixTemp 是临时状态的前缀,仅当前调用可见,调用结束即销毁
    KeyPrefixTemp string = "temp:"
    // KeyPrefixUser 是用户级状态的前缀,同一用户的所有会话共享
    KeyPrefixUser string = "user:"
)

#mermaid-svg-XDVCgCQu2VXy0iEZ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XDVCgCQu2VXy0iEZ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XDVCgCQu2VXy0iEZ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XDVCgCQu2VXy0iEZ .error-icon{fill:#552222;}#mermaid-svg-XDVCgCQu2VXy0iEZ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XDVCgCQu2VXy0iEZ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XDVCgCQu2VXy0iEZ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XDVCgCQu2VXy0iEZ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XDVCgCQu2VXy0iEZ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XDVCgCQu2VXy0iEZ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XDVCgCQu2VXy0iEZ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XDVCgCQu2VXy0iEZ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XDVCgCQu2VXy0iEZ .marker.cross{stroke:#333333;}#mermaid-svg-XDVCgCQu2VXy0iEZ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XDVCgCQu2VXy0iEZ p{margin:0;}#mermaid-svg-XDVCgCQu2VXy0iEZ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XDVCgCQu2VXy0iEZ .cluster-label text{fill:#333;}#mermaid-svg-XDVCgCQu2VXy0iEZ .cluster-label span{color:#333;}#mermaid-svg-XDVCgCQu2VXy0iEZ .cluster-label span p{background-color:transparent;}#mermaid-svg-XDVCgCQu2VXy0iEZ .label text,#mermaid-svg-XDVCgCQu2VXy0iEZ span{fill:#333;color:#333;}#mermaid-svg-XDVCgCQu2VXy0iEZ .node rect,#mermaid-svg-XDVCgCQu2VXy0iEZ .node circle,#mermaid-svg-XDVCgCQu2VXy0iEZ .node ellipse,#mermaid-svg-XDVCgCQu2VXy0iEZ .node polygon,#mermaid-svg-XDVCgCQu2VXy0iEZ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XDVCgCQu2VXy0iEZ .rough-node .label text,#mermaid-svg-XDVCgCQu2VXy0iEZ .node .label text,#mermaid-svg-XDVCgCQu2VXy0iEZ .image-shape .label,#mermaid-svg-XDVCgCQu2VXy0iEZ .icon-shape .label{text-anchor:middle;}#mermaid-svg-XDVCgCQu2VXy0iEZ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XDVCgCQu2VXy0iEZ .rough-node .label,#mermaid-svg-XDVCgCQu2VXy0iEZ .node .label,#mermaid-svg-XDVCgCQu2VXy0iEZ .image-shape .label,#mermaid-svg-XDVCgCQu2VXy0iEZ .icon-shape .label{text-align:center;}#mermaid-svg-XDVCgCQu2VXy0iEZ .node.clickable{cursor:pointer;}#mermaid-svg-XDVCgCQu2VXy0iEZ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XDVCgCQu2VXy0iEZ .arrowheadPath{fill:#333333;}#mermaid-svg-XDVCgCQu2VXy0iEZ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XDVCgCQu2VXy0iEZ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XDVCgCQu2VXy0iEZ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XDVCgCQu2VXy0iEZ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XDVCgCQu2VXy0iEZ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XDVCgCQu2VXy0iEZ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XDVCgCQu2VXy0iEZ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XDVCgCQu2VXy0iEZ .cluster text{fill:#333;}#mermaid-svg-XDVCgCQu2VXy0iEZ .cluster span{color:#333;}#mermaid-svg-XDVCgCQu2VXy0iEZ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XDVCgCQu2VXy0iEZ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XDVCgCQu2VXy0iEZ rect.text{fill:none;stroke-width:0;}#mermaid-svg-XDVCgCQu2VXy0iEZ .icon-shape,#mermaid-svg-XDVCgCQu2VXy0iEZ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XDVCgCQu2VXy0iEZ .icon-shape p,#mermaid-svg-XDVCgCQu2VXy0iEZ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XDVCgCQu2VXy0iEZ .icon-shape .label rect,#mermaid-svg-XDVCgCQu2VXy0iEZ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XDVCgCQu2VXy0iEZ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XDVCgCQu2VXy0iEZ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XDVCgCQu2VXy0iEZ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 临时状态
temp:calculation_result
会话级状态
current_topic
workflow_step
用户级状态
user:preferences
user:profile
应用级状态
app:config
app:stats

作用域 前缀 共享范围 生命周期
应用级 app: 所有用户所有会话 应用运行期间
用户级 user: 同一用户的所有会话 用户存在期间
会话级 无前缀 仅当前会话 会话期间
临时 temp: 仅当前调用 调用结束即销毁

这种设计非常实用。例如:

  • app:total_users:记录应用的总用户数(应用级)
  • user:language:用户的语言偏好(用户级)
  • current_task:当前对话的任务(会话级)
  • temp:temp_result:计算的临时结果(临时)

6. 核心组件详解

6.1 六种智能体类型

根据 state.go 的定义,ADK 内部把智能体分为六种类型:

go 复制代码
// 智能体类型常量,定义了所有支持的智能体种类
const (
    // TypeLLMAgent 是 LLM 驱动的智能体,支持 ReAct 循环和工具调用
    TypeLLMAgent        Type = "LLMAgent"
    // TypeLoopAgent 是循环工作流智能体,循环执行子智能体直到触发 Escalate
    TypeLoopAgent       Type = "LoopAgent"
    // TypeSequentialAgent 是顺序工作流智能体,按顺序逐个执行子智能体
    TypeSequentialAgent Type = "SequentialAgent"
    // TypeParallelAgent 是并行工作流智能体,使用 errgroup 并发执行子智能体
    TypeParallelAgent   Type = "ParallelAgent"
    // TypeCustomAgent 是用户自定义智能体,实现 Agent 接口即可
    TypeCustomAgent     Type = "CustomAgent"
    // TypeRemoteAgent 是远程智能体,通过 A2A 协议与远程智能体通信
    TypeRemoteAgent     Type = "RemoteAgent"
)
类型 包路径 核心特征
LLMAgent agent/llmagent 由 LLM 驱动,支持 ReAct 循环、工具调用、智能体转移
SequentialAgent agent/workflowagents/sequentialagent 按顺序执行子智能体,不涉及 LLM
ParallelAgent agent/workflowagents/parallelagent 并行执行子智能体,使用 errgroup 管理
LoopAgent agent/workflowagents/loopagent 循环执行子智能体,支持 Escalate 退出
CustomAgent 用户实现 实现 Agent 接口的自定义智能体
RemoteAgent agent/remoteagent/v2 通过 A2A 协议与远程智能体通信

工作流智能体(Sequential、Parallel、Loop)不调用 LLM,它们只负责编排子智能体的执行顺序。这使得它们非常适合确定性流程,不消耗 token,执行速度快。

6.2 多智能体架构

ADK 支持构建复杂的多智能体系统。智能体可以组织成树状结构:
#mermaid-svg-AbwKGBDu4a2EohM3{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AbwKGBDu4a2EohM3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AbwKGBDu4a2EohM3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AbwKGBDu4a2EohM3 .error-icon{fill:#552222;}#mermaid-svg-AbwKGBDu4a2EohM3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AbwKGBDu4a2EohM3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AbwKGBDu4a2EohM3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AbwKGBDu4a2EohM3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AbwKGBDu4a2EohM3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AbwKGBDu4a2EohM3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AbwKGBDu4a2EohM3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AbwKGBDu4a2EohM3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AbwKGBDu4a2EohM3 .marker.cross{stroke:#333333;}#mermaid-svg-AbwKGBDu4a2EohM3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AbwKGBDu4a2EohM3 p{margin:0;}#mermaid-svg-AbwKGBDu4a2EohM3 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-AbwKGBDu4a2EohM3 .cluster-label text{fill:#333;}#mermaid-svg-AbwKGBDu4a2EohM3 .cluster-label span{color:#333;}#mermaid-svg-AbwKGBDu4a2EohM3 .cluster-label span p{background-color:transparent;}#mermaid-svg-AbwKGBDu4a2EohM3 .label text,#mermaid-svg-AbwKGBDu4a2EohM3 span{fill:#333;color:#333;}#mermaid-svg-AbwKGBDu4a2EohM3 .node rect,#mermaid-svg-AbwKGBDu4a2EohM3 .node circle,#mermaid-svg-AbwKGBDu4a2EohM3 .node ellipse,#mermaid-svg-AbwKGBDu4a2EohM3 .node polygon,#mermaid-svg-AbwKGBDu4a2EohM3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-AbwKGBDu4a2EohM3 .rough-node .label text,#mermaid-svg-AbwKGBDu4a2EohM3 .node .label text,#mermaid-svg-AbwKGBDu4a2EohM3 .image-shape .label,#mermaid-svg-AbwKGBDu4a2EohM3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-AbwKGBDu4a2EohM3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-AbwKGBDu4a2EohM3 .rough-node .label,#mermaid-svg-AbwKGBDu4a2EohM3 .node .label,#mermaid-svg-AbwKGBDu4a2EohM3 .image-shape .label,#mermaid-svg-AbwKGBDu4a2EohM3 .icon-shape .label{text-align:center;}#mermaid-svg-AbwKGBDu4a2EohM3 .node.clickable{cursor:pointer;}#mermaid-svg-AbwKGBDu4a2EohM3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-AbwKGBDu4a2EohM3 .arrowheadPath{fill:#333333;}#mermaid-svg-AbwKGBDu4a2EohM3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-AbwKGBDu4a2EohM3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-AbwKGBDu4a2EohM3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AbwKGBDu4a2EohM3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-AbwKGBDu4a2EohM3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AbwKGBDu4a2EohM3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-AbwKGBDu4a2EohM3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-AbwKGBDu4a2EohM3 .cluster text{fill:#333;}#mermaid-svg-AbwKGBDu4a2EohM3 .cluster span{color:#333;}#mermaid-svg-AbwKGBDu4a2EohM3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-AbwKGBDu4a2EohM3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-AbwKGBDu4a2EohM3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-AbwKGBDu4a2EohM3 .icon-shape,#mermaid-svg-AbwKGBDu4a2EohM3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AbwKGBDu4a2EohM3 .icon-shape p,#mermaid-svg-AbwKGBDu4a2EohM3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-AbwKGBDu4a2EohM3 .icon-shape .label rect,#mermaid-svg-AbwKGBDu4a2EohM3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AbwKGBDu4a2EohM3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-AbwKGBDu4a2EohM3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-AbwKGBDu4a2EohM3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} RootAgent
分析智能体
写作智能体
审查智能体
远程智能体
数据提取工具
代码生成工具
风格检查工具
安全检查工具
外部服务

智能体之间可以通过三种方式协作:

  1. LLM 驱动的动态路由:智能体通过 LLM 推理,决定将任务交给哪个子智能体
  2. 工作流智能体:通过预定义的工作流编排智能体(顺序、并行、循环)
  3. 远程智能体调用:通过 A2A 协议调用外部智能体

6.3 ADK 2.0 的演进方向

根据 ADK 官方文档,ADK 2.0(目前 Python Beta 版)引入了三个关键特性:

  1. 基于图的工作流(Graph-based Workflows):构建确定性的智能体工作流,更精细控制任务路由和执行
  2. 协作智能体(Collaborative Agents):通过协调者智能体和多个子智能体协同工作
  3. 动态工作流(Dynamic Workflows):使用基于代码的逻辑构建复杂工作流,包括迭代循环和基于决策的分支

虽然这些特性目前仅在 Python 版本中提供,但它们代表了 ADK 的演进方向。Go 版本的 LoopAgent、ParallelAgent 和 SequentialAgent 已经提供了类似的能力,未来可能会进一步对齐 ADK 2.0 的特性。

6.4 远程智能体(A2A)

ADK Go 支持远程智能体调用,通过 A2A(Agent-to-Agent)协议实现。远程智能体允许你调用运行在不同进程或不同主机上的智能体。

go 复制代码
// A2AConfig 定义远程智能体的配置
type A2AConfig struct {
    // Name 是远程智能体的名称
    Name        string
    // Description 是远程智能体的描述
    Description string
    // AgentCard 是远程智能体的名片,描述其能力和位置
    AgentCard         *a2a.AgentCard
    // AgentCardProvider 动态提供 AgentCard
    AgentCardProvider AgentCardProvider
    // BeforeAgentCallbacks 是智能体执行前的回调列表
    BeforeAgentCallbacks []agent.BeforeAgentCallback
    // AfterAgentCallbacks 是智能体执行后的回调列表
    AfterAgentCallbacks  []agent.AfterAgentCallback
    // BeforeRequestCallbacks 是 A2A 请求发送前的回调列表
    BeforeRequestCallbacks  []BeforeA2ARequestCallback
    // AfterRequestCallbacks 是 A2A 请求发送后的回调列表
    AfterRequestCallbacks   []AfterA2ARequestCallback
    // Converter 是 A2A 事件与 ADK 事件之间的转换器
    Converter A2AEventConverter
    // ClientProvider 提供 A2A 客户端实例
    ClientProvider      A2AClientProvider
    // MessageSendConfig 是消息发送的配置
    MessageSendConfig   *a2a.SendMessageConfig
}

远程智能体的核心流程:
远程智能体 A2A客户端 本地智能体 远程智能体 A2A客户端 本地智能体 #mermaid-svg-QjR3j1R0naSIYxzy{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QjR3j1R0naSIYxzy .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QjR3j1R0naSIYxzy .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QjR3j1R0naSIYxzy .error-icon{fill:#552222;}#mermaid-svg-QjR3j1R0naSIYxzy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QjR3j1R0naSIYxzy .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QjR3j1R0naSIYxzy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QjR3j1R0naSIYxzy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QjR3j1R0naSIYxzy .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QjR3j1R0naSIYxzy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QjR3j1R0naSIYxzy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QjR3j1R0naSIYxzy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QjR3j1R0naSIYxzy .marker.cross{stroke:#333333;}#mermaid-svg-QjR3j1R0naSIYxzy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QjR3j1R0naSIYxzy p{margin:0;}#mermaid-svg-QjR3j1R0naSIYxzy .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QjR3j1R0naSIYxzy text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-QjR3j1R0naSIYxzy .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-QjR3j1R0naSIYxzy .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-QjR3j1R0naSIYxzy .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-QjR3j1R0naSIYxzy .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-QjR3j1R0naSIYxzy #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-QjR3j1R0naSIYxzy .sequenceNumber{fill:white;}#mermaid-svg-QjR3j1R0naSIYxzy #sequencenumber{fill:#333;}#mermaid-svg-QjR3j1R0naSIYxzy #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-QjR3j1R0naSIYxzy .messageText{fill:#333;stroke:none;}#mermaid-svg-QjR3j1R0naSIYxzy .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QjR3j1R0naSIYxzy .labelText,#mermaid-svg-QjR3j1R0naSIYxzy .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-QjR3j1R0naSIYxzy .loopText,#mermaid-svg-QjR3j1R0naSIYxzy .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-QjR3j1R0naSIYxzy .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-QjR3j1R0naSIYxzy .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-QjR3j1R0naSIYxzy .noteText,#mermaid-svg-QjR3j1R0naSIYxzy .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-QjR3j1R0naSIYxzy .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QjR3j1R0naSIYxzy .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QjR3j1R0naSIYxzy .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-QjR3j1R0naSIYxzy .actorPopupMenu{position:absolute;}#mermaid-svg-QjR3j1R0naSIYxzy .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-QjR3j1R0naSIYxzy .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-QjR3j1R0naSIYxzy .actor-man circle,#mermaid-svg-QjR3j1R0naSIYxzy line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-QjR3j1R0naSIYxzy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} SendMessage(req) HTTP/gRPC 请求 执行智能体逻辑 事件流 session.Event

A2A 的关键特性:

  • AgentCard:描述远程智能体的能力和位置
  • 流式支持:支持双向流式通信
  • 回调机制:支持请求前后的回调
  • 事件转换:自动转换 A2A 事件和 ADK 事件

6.5 记忆服务(Memory Service)

记忆服务提供跨会话的长期知识存储和检索能力。

go 复制代码
// Service 接口定义记忆服务的核心操作
type Service interface {
    // AddSessionToMemory 将整个会话内容添加到记忆库中
    AddSessionToMemory(ctx context.Context, s session.Session) error
    // SearchMemory 根据搜索请求检索相关记忆
    SearchMemory(ctx context.Context, req *SearchRequest) (*SearchResponse, error)
}

记忆服务的工作流程:
#mermaid-svg-Kjy019rPd0rcQHwb{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Kjy019rPd0rcQHwb .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Kjy019rPd0rcQHwb .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Kjy019rPd0rcQHwb .error-icon{fill:#552222;}#mermaid-svg-Kjy019rPd0rcQHwb .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Kjy019rPd0rcQHwb .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Kjy019rPd0rcQHwb .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Kjy019rPd0rcQHwb .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Kjy019rPd0rcQHwb .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Kjy019rPd0rcQHwb .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Kjy019rPd0rcQHwb .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Kjy019rPd0rcQHwb .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Kjy019rPd0rcQHwb .marker.cross{stroke:#333333;}#mermaid-svg-Kjy019rPd0rcQHwb svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Kjy019rPd0rcQHwb p{margin:0;}#mermaid-svg-Kjy019rPd0rcQHwb .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Kjy019rPd0rcQHwb .cluster-label text{fill:#333;}#mermaid-svg-Kjy019rPd0rcQHwb .cluster-label span{color:#333;}#mermaid-svg-Kjy019rPd0rcQHwb .cluster-label span p{background-color:transparent;}#mermaid-svg-Kjy019rPd0rcQHwb .label text,#mermaid-svg-Kjy019rPd0rcQHwb span{fill:#333;color:#333;}#mermaid-svg-Kjy019rPd0rcQHwb .node rect,#mermaid-svg-Kjy019rPd0rcQHwb .node circle,#mermaid-svg-Kjy019rPd0rcQHwb .node ellipse,#mermaid-svg-Kjy019rPd0rcQHwb .node polygon,#mermaid-svg-Kjy019rPd0rcQHwb .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Kjy019rPd0rcQHwb .rough-node .label text,#mermaid-svg-Kjy019rPd0rcQHwb .node .label text,#mermaid-svg-Kjy019rPd0rcQHwb .image-shape .label,#mermaid-svg-Kjy019rPd0rcQHwb .icon-shape .label{text-anchor:middle;}#mermaid-svg-Kjy019rPd0rcQHwb .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Kjy019rPd0rcQHwb .rough-node .label,#mermaid-svg-Kjy019rPd0rcQHwb .node .label,#mermaid-svg-Kjy019rPd0rcQHwb .image-shape .label,#mermaid-svg-Kjy019rPd0rcQHwb .icon-shape .label{text-align:center;}#mermaid-svg-Kjy019rPd0rcQHwb .node.clickable{cursor:pointer;}#mermaid-svg-Kjy019rPd0rcQHwb .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Kjy019rPd0rcQHwb .arrowheadPath{fill:#333333;}#mermaid-svg-Kjy019rPd0rcQHwb .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Kjy019rPd0rcQHwb .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Kjy019rPd0rcQHwb .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Kjy019rPd0rcQHwb .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Kjy019rPd0rcQHwb .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Kjy019rPd0rcQHwb .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Kjy019rPd0rcQHwb .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Kjy019rPd0rcQHwb .cluster text{fill:#333;}#mermaid-svg-Kjy019rPd0rcQHwb .cluster span{color:#333;}#mermaid-svg-Kjy019rPd0rcQHwb div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Kjy019rPd0rcQHwb .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Kjy019rPd0rcQHwb rect.text{fill:none;stroke-width:0;}#mermaid-svg-Kjy019rPd0rcQHwb .icon-shape,#mermaid-svg-Kjy019rPd0rcQHwb .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Kjy019rPd0rcQHwb .icon-shape p,#mermaid-svg-Kjy019rPd0rcQHwb .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Kjy019rPd0rcQHwb .icon-shape .label rect,#mermaid-svg-Kjy019rPd0rcQHwb .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Kjy019rPd0rcQHwb .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Kjy019rPd0rcQHwb .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Kjy019rPd0rcQHwb :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 会话完成
AddSessionToMemory
提取会话事件内容
存储到记忆库
用户新请求
SearchMemory
执行语义搜索
返回相关记忆条目
注入到 LLM 上下文

记忆服务支持两种实现:

  • InMemory:内存实现,适合开发测试(不进行向量化,直接存储文本内容)
  • VertexAI:基于 Google Cloud Vertex AI 的生产级实现(支持向量化和语义搜索)

6.6 制品服务(Artifact Service)

制品服务管理文件和二进制数据,支持智能体生成和使用文件。它提供了完整的版本控制能力,每个文件可以有多个版本。

go 复制代码
// Service 接口定义制品服务的核心操作
type Service interface {
    // Save 保存文件,每次保存都会生成新版本
    Save(ctx context.Context, req *SaveRequest) (*SaveResponse, error)
    // Load 加载文件的最新版本或指定版本
    Load(ctx context.Context, req *LoadRequest) (*LoadResponse, error)
    // Delete 删除文件
    Delete(ctx context.Context, req *DeleteRequest) error
    // List 列出所有文件
    List(ctx context.Context, req *ListRequest) (*ListResponse, error)
    // Versions 列出文件的所有版本
    Versions(ctx context.Context, req *VersionsRequest) (*VersionsResponse, error)
    // GetArtifactVersion 获取文件的特定版本
    GetArtifactVersion(ctx context.Context, req *GetArtifactVersionRequest) (*GetArtifactVersionResponse, error)
}

制品服务的核心特性:

  • 版本控制:每次保存都会生成新版本,可以访问历史版本
  • 作用域隔离 :支持会话级和用户级两种作用域(会话级文件名无前缀,用户级以 user: 前缀开头)
  • 类型支持 :支持文本和二进制数据(通过 genai.Part

典型使用场景:智能体生成图片、文档等文件;用户上传文件供智能体分析;在会话之间共享文件;追踪文件变更历史。

支持的实现:

  • InMemory:内存实现,适合开发测试
  • GCS:Google Cloud Storage 实现,生产环境使用

6.7 插件系统

ADK 的插件系统允许在不修改核心代码的情况下添加横切关注点:

go 复制代码
// Plugin 结构体定义了插件的完整回调列表
type Plugin struct {
    // name 是插件的名称
    name string
    // onUserMessageCallback 在收到用户消息时调用
    onUserMessageCallback OnUserMessageCallback
    // onEventCallback 在收到事件时调用
    onEventCallback       OnEventCallback
    // beforeRunCallback 在 Run 执行前调用
    beforeRunCallback BeforeRunCallback
    // afterRunCallback 在 Run 执行后调用
    afterRunCallback  AfterRunCallback
    // beforeAgentCallback 在智能体执行前调用
    beforeAgentCallback agent.BeforeAgentCallback
    // afterAgentCallback 在智能体执行后调用
    afterAgentCallback  agent.AfterAgentCallback
    // beforeModelCallback 在 LLM 调用前调用
    beforeModelCallback  llmagent.BeforeModelCallback
    // afterModelCallback 在 LLM 调用后调用
    afterModelCallback   llmagent.AfterModelCallback
    // onModelErrorCallback 在 LLM 调用出错时调用
    onModelErrorCallback llmagent.OnModelErrorCallback
    // beforeToolCallback 在工具调用前调用
    beforeToolCallback  llmagent.BeforeToolCallback
    // afterToolCallback 在工具调用后调用
    afterToolCallback   llmagent.AfterToolCallback
    // onToolErrorCallback 在工具调用出错时调用
    onToolErrorCallback llmagent.OnToolErrorCallback
    // closeFunc 是插件关闭时的清理函数
    closeFunc func() error
}

插件可以在各个关键节点介入:

  • 用户消息处理前后
  • Run 执行前后
  • 智能体执行前后
  • LLM 调用前后
  • 工具调用前后

内置插件包括:

  • LoggingPlugin:记录日志
  • RetryAndReflect:错误重试和反思
  • FunctionCallModifier:修改函数调用

6.8 模型抽象

ADK 通过 LLM 接口抽象不同的语言模型:

go 复制代码
// LLM 接口定义语言模型的抽象,所有模型实现都必须满足此接口
type LLM interface {
    // Name 返回模型的名称
    Name() string
    // GenerateContent 生成内容,stream 参数控制是否流式输出
    // 返回事件迭代器,每个事件包含 LLM 响应或错误
    GenerateContent(ctx context.Context, req *LLMRequest, stream bool) iter.Seq2[*LLMResponse, error]
}

目前支持:

  • Gemini:Google 的大语言模型
  • Apigee:通过 Apigee 网关访问其他模型

这种抽象使得切换模型非常容易,只需更换实现即可。

6.9 部署灵活性

ADK Go 支持多种部署方式:
#mermaid-svg-aYQHixKr95abKG83{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-aYQHixKr95abKG83 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-aYQHixKr95abKG83 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-aYQHixKr95abKG83 .error-icon{fill:#552222;}#mermaid-svg-aYQHixKr95abKG83 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-aYQHixKr95abKG83 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-aYQHixKr95abKG83 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-aYQHixKr95abKG83 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-aYQHixKr95abKG83 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-aYQHixKr95abKG83 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-aYQHixKr95abKG83 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-aYQHixKr95abKG83 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-aYQHixKr95abKG83 .marker.cross{stroke:#333333;}#mermaid-svg-aYQHixKr95abKG83 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-aYQHixKr95abKG83 p{margin:0;}#mermaid-svg-aYQHixKr95abKG83 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-aYQHixKr95abKG83 .cluster-label text{fill:#333;}#mermaid-svg-aYQHixKr95abKG83 .cluster-label span{color:#333;}#mermaid-svg-aYQHixKr95abKG83 .cluster-label span p{background-color:transparent;}#mermaid-svg-aYQHixKr95abKG83 .label text,#mermaid-svg-aYQHixKr95abKG83 span{fill:#333;color:#333;}#mermaid-svg-aYQHixKr95abKG83 .node rect,#mermaid-svg-aYQHixKr95abKG83 .node circle,#mermaid-svg-aYQHixKr95abKG83 .node ellipse,#mermaid-svg-aYQHixKr95abKG83 .node polygon,#mermaid-svg-aYQHixKr95abKG83 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-aYQHixKr95abKG83 .rough-node .label text,#mermaid-svg-aYQHixKr95abKG83 .node .label text,#mermaid-svg-aYQHixKr95abKG83 .image-shape .label,#mermaid-svg-aYQHixKr95abKG83 .icon-shape .label{text-anchor:middle;}#mermaid-svg-aYQHixKr95abKG83 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-aYQHixKr95abKG83 .rough-node .label,#mermaid-svg-aYQHixKr95abKG83 .node .label,#mermaid-svg-aYQHixKr95abKG83 .image-shape .label,#mermaid-svg-aYQHixKr95abKG83 .icon-shape .label{text-align:center;}#mermaid-svg-aYQHixKr95abKG83 .node.clickable{cursor:pointer;}#mermaid-svg-aYQHixKr95abKG83 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-aYQHixKr95abKG83 .arrowheadPath{fill:#333333;}#mermaid-svg-aYQHixKr95abKG83 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-aYQHixKr95abKG83 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-aYQHixKr95abKG83 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aYQHixKr95abKG83 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-aYQHixKr95abKG83 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aYQHixKr95abKG83 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-aYQHixKr95abKG83 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-aYQHixKr95abKG83 .cluster text{fill:#333;}#mermaid-svg-aYQHixKr95abKG83 .cluster span{color:#333;}#mermaid-svg-aYQHixKr95abKG83 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-aYQHixKr95abKG83 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-aYQHixKr95abKG83 rect.text{fill:none;stroke-width:0;}#mermaid-svg-aYQHixKr95abKG83 .icon-shape,#mermaid-svg-aYQHixKr95abKG83 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-aYQHixKr95abKG83 .icon-shape p,#mermaid-svg-aYQHixKr95abKG83 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-aYQHixKr95abKG83 .icon-shape .label rect,#mermaid-svg-aYQHixKr95abKG83 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-aYQHixKr95abKG83 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-aYQHixKr95abKG83 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-aYQHixKr95abKG83 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 云部署
本地开发
自定义部署
REST API Server
Docker 容器
Console 模式
Web UI
Cloud Run
Vertex AI Agent Engine
adk console
adk web
adk deploy cloudrun
adk deploy agentengine

通过 adkgo CLI 工具,可以轻松地将智能体部署到不同环境。

7. 模块依赖与启动流程

7.1 模块依赖关系图

#mermaid-svg-OfXX53M2aIbkdmpD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-OfXX53M2aIbkdmpD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-OfXX53M2aIbkdmpD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-OfXX53M2aIbkdmpD .error-icon{fill:#552222;}#mermaid-svg-OfXX53M2aIbkdmpD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OfXX53M2aIbkdmpD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-OfXX53M2aIbkdmpD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OfXX53M2aIbkdmpD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OfXX53M2aIbkdmpD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-OfXX53M2aIbkdmpD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OfXX53M2aIbkdmpD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OfXX53M2aIbkdmpD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OfXX53M2aIbkdmpD .marker.cross{stroke:#333333;}#mermaid-svg-OfXX53M2aIbkdmpD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OfXX53M2aIbkdmpD p{margin:0;}#mermaid-svg-OfXX53M2aIbkdmpD .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-OfXX53M2aIbkdmpD .cluster-label text{fill:#333;}#mermaid-svg-OfXX53M2aIbkdmpD .cluster-label span{color:#333;}#mermaid-svg-OfXX53M2aIbkdmpD .cluster-label span p{background-color:transparent;}#mermaid-svg-OfXX53M2aIbkdmpD .label text,#mermaid-svg-OfXX53M2aIbkdmpD span{fill:#333;color:#333;}#mermaid-svg-OfXX53M2aIbkdmpD .node rect,#mermaid-svg-OfXX53M2aIbkdmpD .node circle,#mermaid-svg-OfXX53M2aIbkdmpD .node ellipse,#mermaid-svg-OfXX53M2aIbkdmpD .node polygon,#mermaid-svg-OfXX53M2aIbkdmpD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-OfXX53M2aIbkdmpD .rough-node .label text,#mermaid-svg-OfXX53M2aIbkdmpD .node .label text,#mermaid-svg-OfXX53M2aIbkdmpD .image-shape .label,#mermaid-svg-OfXX53M2aIbkdmpD .icon-shape .label{text-anchor:middle;}#mermaid-svg-OfXX53M2aIbkdmpD .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-OfXX53M2aIbkdmpD .rough-node .label,#mermaid-svg-OfXX53M2aIbkdmpD .node .label,#mermaid-svg-OfXX53M2aIbkdmpD .image-shape .label,#mermaid-svg-OfXX53M2aIbkdmpD .icon-shape .label{text-align:center;}#mermaid-svg-OfXX53M2aIbkdmpD .node.clickable{cursor:pointer;}#mermaid-svg-OfXX53M2aIbkdmpD .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-OfXX53M2aIbkdmpD .arrowheadPath{fill:#333333;}#mermaid-svg-OfXX53M2aIbkdmpD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-OfXX53M2aIbkdmpD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-OfXX53M2aIbkdmpD .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OfXX53M2aIbkdmpD .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-OfXX53M2aIbkdmpD .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OfXX53M2aIbkdmpD .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-OfXX53M2aIbkdmpD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-OfXX53M2aIbkdmpD .cluster text{fill:#333;}#mermaid-svg-OfXX53M2aIbkdmpD .cluster span{color:#333;}#mermaid-svg-OfXX53M2aIbkdmpD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-OfXX53M2aIbkdmpD .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-OfXX53M2aIbkdmpD rect.text{fill:none;stroke-width:0;}#mermaid-svg-OfXX53M2aIbkdmpD .icon-shape,#mermaid-svg-OfXX53M2aIbkdmpD .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-OfXX53M2aIbkdmpD .icon-shape p,#mermaid-svg-OfXX53M2aIbkdmpD .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-OfXX53M2aIbkdmpD .icon-shape .label rect,#mermaid-svg-OfXX53M2aIbkdmpD .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-OfXX53M2aIbkdmpD .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-OfXX53M2aIbkdmpD .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-OfXX53M2aIbkdmpD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 启动器
扩展模块
服务模块
核心模块
外部依赖
a2a-go
genai-go
OpenTelemetry
Google Cloud Storage
Google Cloud Pub/Sub/EventArc
agent

(智能体接口)
model

(模型抽象)
tool

(工具系统)
session

(会话管理)
runner

(执行引擎)
memory

(记忆服务)
artifact

(制品服务)
telemetry

(遥测服务)
plugin

(插件系统)
configurable

(声明式配置)
server

(REST API)
launcher

(启动器接口)
universal
console
web
full

7.2 依赖注入链

ADK-Go 的依赖注入采用手动方式,通过 Config 结构体层层传递。依赖的解析顺序如下:

  1. 会话服务(必需):最先创建,作为其他服务的基础
  2. 智能体(必需):在创建 Runner 时传入
  3. 制品服务 (可选):在 Runner 执行时按需创建 Artifacts 包装器
  4. 记忆服务 (可选):在 Runner 执行时按需创建 Memory 包装器
  5. 插件管理器(可选):在 Runner 创建时初始化

具体的依赖注入发生在 runner.New() 中:

go 复制代码
// New 创建一个新的 Runner 实例
func New(cfg Config) (*Runner, error) {
    // 验证必需参数:根智能体不能为空
    if cfg.Agent == nil {
        return nil, fmt.Errorf("root agent is required")
    }
    // 验证必需参数:会话服务不能为空
    if cfg.SessionService == nil {
        return nil, fmt.Errorf("session service is required")
    }
    // 构建智能体父子关系树,用于后续的智能体路由
    parents, err := parentmap.New(cfg.Agent)
    if err != nil {
        return nil, fmt.Errorf("failed to create agent tree: %w", err)
    }
    // 创建插件管理器,传入插件列表和关闭超时时间
    pluginManager, err := plugininternal.NewPluginManager(plugininternal.PluginConfig{
        Plugins:      cfg.PluginConfig.Plugins,
        CloseTimeout: cfg.PluginConfig.CloseTimeout,
    })
    if err != nil {
        return nil, fmt.Errorf("failed to create plugin manager: %w", err)
    }
    // 组装 Runner 结构体,包含所有依赖
    return &Runner{
        appName:           cfg.AppName,
        rootAgent:         cfg.Agent,
        sessionService:    cfg.SessionService,
        artifactService:   cfg.ArtifactService,
        memoryService:     cfg.MemoryService,
        parents:           parents,
        pluginManager:     pluginManager,
        autoCreateSession: cfg.AutoCreateSession,
    }, nil
}

Runner 在执行时,会按以下顺序解析和使用服务:
#mermaid-svg-i9zlpywKjXtmNTxp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-i9zlpywKjXtmNTxp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-i9zlpywKjXtmNTxp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-i9zlpywKjXtmNTxp .error-icon{fill:#552222;}#mermaid-svg-i9zlpywKjXtmNTxp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-i9zlpywKjXtmNTxp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-i9zlpywKjXtmNTxp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-i9zlpywKjXtmNTxp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-i9zlpywKjXtmNTxp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-i9zlpywKjXtmNTxp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-i9zlpywKjXtmNTxp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-i9zlpywKjXtmNTxp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-i9zlpywKjXtmNTxp .marker.cross{stroke:#333333;}#mermaid-svg-i9zlpywKjXtmNTxp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-i9zlpywKjXtmNTxp p{margin:0;}#mermaid-svg-i9zlpywKjXtmNTxp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-i9zlpywKjXtmNTxp .cluster-label text{fill:#333;}#mermaid-svg-i9zlpywKjXtmNTxp .cluster-label span{color:#333;}#mermaid-svg-i9zlpywKjXtmNTxp .cluster-label span p{background-color:transparent;}#mermaid-svg-i9zlpywKjXtmNTxp .label text,#mermaid-svg-i9zlpywKjXtmNTxp span{fill:#333;color:#333;}#mermaid-svg-i9zlpywKjXtmNTxp .node rect,#mermaid-svg-i9zlpywKjXtmNTxp .node circle,#mermaid-svg-i9zlpywKjXtmNTxp .node ellipse,#mermaid-svg-i9zlpywKjXtmNTxp .node polygon,#mermaid-svg-i9zlpywKjXtmNTxp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-i9zlpywKjXtmNTxp .rough-node .label text,#mermaid-svg-i9zlpywKjXtmNTxp .node .label text,#mermaid-svg-i9zlpywKjXtmNTxp .image-shape .label,#mermaid-svg-i9zlpywKjXtmNTxp .icon-shape .label{text-anchor:middle;}#mermaid-svg-i9zlpywKjXtmNTxp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-i9zlpywKjXtmNTxp .rough-node .label,#mermaid-svg-i9zlpywKjXtmNTxp .node .label,#mermaid-svg-i9zlpywKjXtmNTxp .image-shape .label,#mermaid-svg-i9zlpywKjXtmNTxp .icon-shape .label{text-align:center;}#mermaid-svg-i9zlpywKjXtmNTxp .node.clickable{cursor:pointer;}#mermaid-svg-i9zlpywKjXtmNTxp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-i9zlpywKjXtmNTxp .arrowheadPath{fill:#333333;}#mermaid-svg-i9zlpywKjXtmNTxp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-i9zlpywKjXtmNTxp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-i9zlpywKjXtmNTxp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-i9zlpywKjXtmNTxp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-i9zlpywKjXtmNTxp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-i9zlpywKjXtmNTxp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-i9zlpywKjXtmNTxp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-i9zlpywKjXtmNTxp .cluster text{fill:#333;}#mermaid-svg-i9zlpywKjXtmNTxp .cluster span{color:#333;}#mermaid-svg-i9zlpywKjXtmNTxp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-i9zlpywKjXtmNTxp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-i9zlpywKjXtmNTxp rect.text{fill:none;stroke-width:0;}#mermaid-svg-i9zlpywKjXtmNTxp .icon-shape,#mermaid-svg-i9zlpywKjXtmNTxp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-i9zlpywKjXtmNTxp .icon-shape p,#mermaid-svg-i9zlpywKjXtmNTxp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-i9zlpywKjXtmNTxp .icon-shape .label rect,#mermaid-svg-i9zlpywKjXtmNTxp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-i9zlpywKjXtmNTxp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-i9zlpywKjXtmNTxp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-i9zlpywKjXtmNTxp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是



Runner.Run
SessionService.Get/Create
findAgentToRun
构建上下文
ArtifactService?
创建 Artifacts 包装器
跳过
MemoryService?
创建 Memory 包装器
跳过
创建 InvocationContext
agent.Run

7.3 启动器系统架构

ADK-Go 的启动器(Launcher)系统是整个框架的入口层。它负责解析命令行参数,初始化各种服务,然后启动智能体。启动器系统采用三层设计,从上到下分别是:通用启动器(Universal)、具体启动器(Console/Web)、子启动器(SubLauncher)。

Launcher 和 SubLauncher 接口 定义在 launcher.go 中:

go 复制代码
// Launcher 是运行 ADK 应用的主接口
// 它负责解析命令行参数并执行相应的逻辑
type Launcher interface {
    // Execute 解析命令行参数并运行启动器
    Execute(ctx context.Context, config *Config, args []string) error
    // CommandLineSyntax 返回描述命令行标志和参数的字符串
    CommandLineSyntax() string
}

// SubLauncher 是可以组合在父启动器中的启动器接口
// 每个 SubLauncher 对应一种特定的操作模式(例如 'console' 或 'web')
type SubLauncher interface {
    // Keyword 返回激活此子启动器的命令行关键字
    Keyword() string
    // Parse 解析子启动器的参数,返回任何未解析的参数
    Parse(args []string) ([]string, error)
    // CommandLineSyntax 返回描述子启动器命令行标志和参数的字符串
    CommandLineSyntax() string
    // SimpleDescription 提供子启动器功能的简短一行描述
    SimpleDescription() string
    // Run 执行子启动器的主要逻辑
    Run(ctx context.Context, config *Config) error
}

Config 结构体作为依赖注入的容器,把所有依赖统一管理:

go 复制代码
// Config 包含 Web 和 Console 执行的参数:会话、制品、智能体等
type Config struct {
    // SessionService 会话服务(必需):管理对话历史和状态
    SessionService   session.Service
    // ArtifactService 制品服务(可选):管理文件上传和下载
    ArtifactService  artifact.Service
    // MemoryService 记忆服务(可选):管理长期记忆和语义搜索
    MemoryService    memory.Service
    // AgentLoader 智能体加载器(必需):加载和路由智能体
    AgentLoader      agent.Loader
    // A2AOptions A2A 协议选项(可选):配置 A2A 服务
    A2AOptions       []a2asrv.RequestHandlerOption
    // PluginConfig 插件配置(可选):管理插件
    PluginConfig     runner.PluginConfig
    // TelemetryOptions 遥测选项(可选):配置 OpenTelemetry
    TelemetryOptions []telemetry.Option
}

Universal 通用启动器 是一个路由器。它根据命令行参数选择正确的子启动器。路由逻辑很简单:如果用户在命令行输入 console,就路由到 Console 启动器;如果输入 web,就路由到 Web 启动器;如果什么都不输入,默认使用第一个注册的启动器。

go 复制代码
// uniLauncher 包含子启动器的信息
type uniLauncher struct {
    // chosenLauncher 是解析命令行参数后选定的启动器
    chosenLauncher launcher.SubLauncher
    // sublaunchers 是所有注册的子启动器列表
    sublaunchers   []launcher.SubLauncher
}

// NewLauncher 返回一个新的通用启动器
// 启动器列表的第一个元素将作为默认启动器(如果没有指定参数)
func NewLauncher(sublaunchers ...launcher.SubLauncher) launcher.Launcher {
    return &uniLauncher{
        sublaunchers: sublaunchers,
    }
}

// parse 解析参数并记住稍后应该运行哪个子启动器
func (l *uniLauncher) parse(args []string) ([]string, error) {
    // 步骤 1:构建关键字到子启动器的映射
    keyToSublauncher := make(map[string]launcher.SubLauncher)
    for _, sub := range l.sublaunchers {
        // 检查关键字是否重复
        if _, ok := keyToSublauncher[sub.Keyword()]; ok {
            return nil, fmt.Errorf("子启动器的关键字必须唯一,发现重复: '%s'", sub.Keyword())
        }
        keyToSublauncher[sub.Keyword()] = sub
    }
    // 步骤 2:检查是否有子启动器
    if len(l.sublaunchers) == 0 {
        return args, fmt.Errorf("没有子启动器来解析参数")
    }
    // 步骤 3:默认使用第一个启动器
    l.chosenLauncher = l.sublaunchers[0]
    // 步骤 4:如果没有参数,执行默认启动器
    if len(args) == 0 {
        return l.chosenLauncher.Parse(args)
    }
    // 步骤 5:有参数,尝试匹配关键字
    key := args[0]
    if keyLauncher, ok := keyToSublauncher[key]; ok {
        // 找到匹配,使用它,继续解析时不包含匹配的关键字
        l.chosenLauncher = keyLauncher
        return l.chosenLauncher.Parse(args[1:])
    }
    // 步骤 6:没有找到匹配,让默认启动器解析所有参数
    return l.chosenLauncher.Parse(args)
}

Console 启动器实现了终端交互式对话。它最精妙的地方在于流式模式的自动检测。当用户在终端里直接运行时,能看到逐字流式输出;当输出被重定向到文件或管道时,自动切换到非流式模式。

go 复制代码
// consoleConfig 包含控制台启动器的命令行参数
type consoleConfig struct {
    // streamingMode 是流式输出模式
    streamingMode       agent.StreamingMode
    // streamingModeString 是流式模式的字符串表示
    streamingModeString string
    // otelToCloud 控制是否将遥测数据发送到云端
    otelToCloud         bool
    // shutdownTimeout 是关闭超时时间
    shutdownTimeout     time.Duration
}

// consoleLauncher 允许从控制台应用与智能体交互
type consoleLauncher struct {
    // flags 是命令行标志集
    flags  *flag.FlagSet
    // config 是控制台配置
    config *consoleConfig
}

流式模式智能检测:

go 复制代码
// 智能检测流式模式:根据标准输出是否为终端设备来决定
defaultStreamingMode := l.config.streamingMode
if defaultStreamingMode == "" {
    // 检查标准输出是否是终端设备(字符设备)
    if fi, err := os.Stdout.Stat(); err == nil && (fi.Mode()&os.ModeCharDevice) != 0 {
        // 终端设备 → 使用 SSE 流式输出
        defaultStreamingMode = agent.StreamingModeSSE
    } else {
        // 管道/文件 → 非流式输出,避免输出中大量重复增量文本
        defaultStreamingMode = agent.StreamingModeNone
    }
}

Web 启动器 本身只是一个 HTTP 服务器框架。它的真正功能由子启动器(SubLauncher)提供。子启动器通过 SetupSubrouters 方法向路由器注册自己的路由。

go 复制代码
// SetupSubrouters 为 Web 启动器设置子路由
func (a *apiLauncher) SetupSubrouters(router *mux.Router, config *launcher.Config) error {
    // 创建 REST API 服务器,传入所有依赖服务
    restServer, err := adkrest.NewServer(adkrest.ServerConfig{
        SessionService:  config.SessionService,
        MemoryService:   config.MemoryService,
        AgentLoader:     config.AgentLoader,
        ArtifactService: config.ArtifactService,
        SSEWriteTimeout: a.config.sseWriteTimeout,
        PluginConfig:    config.PluginConfig,
    })
    // 添加 CORS 中间件
    corsHandler := corsWithArgs(a.config.frontendAddress)(restServer)
    // 注册路由到主路由器
    router.Methods("GET", "POST", "DELETE", "OPTIONS").PathPrefix(a.config.pathPrefix).Handler(http.StripPrefix(a.config.pathPrefix, corsHandler))
    return nil
}

Web 启动器支持以下子启动器:

子启动器 关键词 源文件 功能
API api web/api/api.go 提供 REST API 接口,支持 CORS
A2A a2a web/a2a/a2a.go 提供 A2A 协议接口,支持 JSON-RPC
WebUI webui web/webui/webui.go 提供内置 Web UI 界面
PubSub pubsub web/pubsub/pubsub.go Google Cloud Pub/Sub 触发器
EventArc eventarc web/eventarc/eventarc.go Google Cloud Eventarc 触发器

Full 全功能启动器是所有启动器的组合体。它把 Console 和 Web(包含所有子启动器)全部注册到 Universal 中。

go 复制代码
// NewLauncher 返回具有所有内置选项的通用启动器
func NewLauncher() launcher.Launcher {
    return universal.NewLauncher(
        // 控制台启动器
        console.NewLauncher(),
        // Web 启动器,包含所有子启动器
        web.NewLauncher(
            webui.NewLauncher(),    // Web UI 子启动器
            a2a.NewLauncher(),       // A2A 子启动器
            pubsub.NewLauncher(),    // PubSub 子启动器
            eventarc.NewLauncher(),  // EventArc 子启动器
            api.NewLauncher(),       // API 子启动器
        ),
    )
}

启动器系统体现了几个优秀的设计原则:

  1. 关注点分离:每个启动器只负责一种运行模式,互不干扰
  2. 可组合性 :通过 SubLauncher 接口,Web 启动器可以无限扩展
  3. 默认优先:Universal 启动器在无参数时使用第一个注册的启动器
  4. 参数透传:每个启动器只消费自己关心的参数,其余参数继续向下传递
  5. 依赖注入Config 结构体统一管理所有服务依赖

7.4 完整启动流程

从源码到运行的完整流程:
agent.Agent session.Service runner.New console.Launcher universal.Launcher full.NewLauncher 用户代码 agent.Agent session.Service runner.New console.Launcher universal.Launcher full.NewLauncher 用户代码 #mermaid-svg-oQCXBk9uQhZDIks4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-oQCXBk9uQhZDIks4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-oQCXBk9uQhZDIks4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-oQCXBk9uQhZDIks4 .error-icon{fill:#552222;}#mermaid-svg-oQCXBk9uQhZDIks4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-oQCXBk9uQhZDIks4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-oQCXBk9uQhZDIks4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-oQCXBk9uQhZDIks4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-oQCXBk9uQhZDIks4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-oQCXBk9uQhZDIks4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-oQCXBk9uQhZDIks4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-oQCXBk9uQhZDIks4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-oQCXBk9uQhZDIks4 .marker.cross{stroke:#333333;}#mermaid-svg-oQCXBk9uQhZDIks4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-oQCXBk9uQhZDIks4 p{margin:0;}#mermaid-svg-oQCXBk9uQhZDIks4 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-oQCXBk9uQhZDIks4 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-oQCXBk9uQhZDIks4 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-oQCXBk9uQhZDIks4 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-oQCXBk9uQhZDIks4 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-oQCXBk9uQhZDIks4 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-oQCXBk9uQhZDIks4 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-oQCXBk9uQhZDIks4 .sequenceNumber{fill:white;}#mermaid-svg-oQCXBk9uQhZDIks4 #sequencenumber{fill:#333;}#mermaid-svg-oQCXBk9uQhZDIks4 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-oQCXBk9uQhZDIks4 .messageText{fill:#333;stroke:none;}#mermaid-svg-oQCXBk9uQhZDIks4 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-oQCXBk9uQhZDIks4 .labelText,#mermaid-svg-oQCXBk9uQhZDIks4 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-oQCXBk9uQhZDIks4 .loopText,#mermaid-svg-oQCXBk9uQhZDIks4 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-oQCXBk9uQhZDIks4 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-oQCXBk9uQhZDIks4 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-oQCXBk9uQhZDIks4 .noteText,#mermaid-svg-oQCXBk9uQhZDIks4 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-oQCXBk9uQhZDIks4 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-oQCXBk9uQhZDIks4 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-oQCXBk9uQhZDIks4 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-oQCXBk9uQhZDIks4 .actorPopupMenu{position:absolute;}#mermaid-svg-oQCXBk9uQhZDIks4 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-oQCXBk9uQhZDIks4 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-oQCXBk9uQhZDIks4 .actor-man circle,#mermaid-svg-oQCXBk9uQhZDIks4 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-oQCXBk9uQhZDIks4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} full.NewLauncher() console.NewLauncher() universal.NewLauncher(console, web) Execute(ctx, config, args) parse(args) → 选择 console Run(ctx, config) runner.New(runner.Config) parentmap.New(agent) 返回 Runner Run(ctx, userID, sessionID, msg) Get/Create(session) findAgentToRun(session, msg) Run(ctx, session, msg) iter.Seq2Event, error 返回事件迭代器 循环输出事件

关键步骤详解

步骤一:启动器创建 ------用户代码调用 full.NewLauncher() 时,系统会创建完整的启动器层级。所有子启动器在此时被实例化,但它们的 Run 方法还没有被调用。

步骤二:命令行参数解析 ------Execute 方法调用 parse,经过:根据第一个参数匹配子启动器关键词、调用匹配到的子启动器的 Parse 方法、子启动器解析自己的 FlagSet、返回未解析的参数。

步骤三:Runner 创建 ------在 Console 启动器中,runner.New() 被调用。这个函数做了三件事:验证必需参数(Agent 和 SessionService)、构建智能体父子关系树(parentmap.New)、创建插件管理器(plugininternal.NewPluginManager)。

步骤四:Runner.Run 执行 ------Runner.Run() 是核心执行入口。它返回一个事件迭代器(iter.Seq2[*session.Event, error])。Console 启动器通过 for event, err := range runner.Run(...) 循环消费这个迭代器,每收到一个事件就打印到终端。

步骤五:智能体路由 ------findAgentToRun 方法根据会话历史决定由哪个智能体来处理请求。它从最新的事件开始向前搜索,找到最近一个非用户事件,然后查找该事件的作者是否对应一个可转移的智能体。

步骤六:事件循环 ------智能体执行后,事件通过迭代器逐个返回。Runner 对每个事件做三件事:通过插件管理器处理事件(pluginManager.ProcessEvent)、如果不是部分事件,持久化到会话服务、通过 yield 返回给调用者。

步骤七:响应输出------Console 启动器接收事件后,根据流式模式决定如何输出:SSE 模式始终打印部分响应,最终响应只打印增量部分;非流式模式直接打印完整文本。

完整的运行时序图:
Session服务 Tool Model Agent Runner Console启动器 用户 Session服务 Tool Model Agent Runner Console启动器 用户 #mermaid-svg-XINIa41TOMJ5MqtG{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XINIa41TOMJ5MqtG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XINIa41TOMJ5MqtG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XINIa41TOMJ5MqtG .error-icon{fill:#552222;}#mermaid-svg-XINIa41TOMJ5MqtG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XINIa41TOMJ5MqtG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XINIa41TOMJ5MqtG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XINIa41TOMJ5MqtG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XINIa41TOMJ5MqtG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XINIa41TOMJ5MqtG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XINIa41TOMJ5MqtG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XINIa41TOMJ5MqtG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XINIa41TOMJ5MqtG .marker.cross{stroke:#333333;}#mermaid-svg-XINIa41TOMJ5MqtG svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XINIa41TOMJ5MqtG p{margin:0;}#mermaid-svg-XINIa41TOMJ5MqtG .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-XINIa41TOMJ5MqtG text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-XINIa41TOMJ5MqtG .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-XINIa41TOMJ5MqtG .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-XINIa41TOMJ5MqtG .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-XINIa41TOMJ5MqtG .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-XINIa41TOMJ5MqtG #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-XINIa41TOMJ5MqtG .sequenceNumber{fill:white;}#mermaid-svg-XINIa41TOMJ5MqtG #sequencenumber{fill:#333;}#mermaid-svg-XINIa41TOMJ5MqtG #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-XINIa41TOMJ5MqtG .messageText{fill:#333;stroke:none;}#mermaid-svg-XINIa41TOMJ5MqtG .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-XINIa41TOMJ5MqtG .labelText,#mermaid-svg-XINIa41TOMJ5MqtG .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-XINIa41TOMJ5MqtG .loopText,#mermaid-svg-XINIa41TOMJ5MqtG .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-XINIa41TOMJ5MqtG .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-XINIa41TOMJ5MqtG .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-XINIa41TOMJ5MqtG .noteText,#mermaid-svg-XINIa41TOMJ5MqtG .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-XINIa41TOMJ5MqtG .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-XINIa41TOMJ5MqtG .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-XINIa41TOMJ5MqtG .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-XINIa41TOMJ5MqtG .actorPopupMenu{position:absolute;}#mermaid-svg-XINIa41TOMJ5MqtG .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-XINIa41TOMJ5MqtG .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-XINIa41TOMJ5MqtG .actor-man circle,#mermaid-svg-XINIa41TOMJ5MqtG line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-XINIa41TOMJ5MqtG :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} loop 每个事件 输入消息 Run(userID, sessionID, msg) Get(sessionID) 返回会话 findAgentToRun() Run(ctx, session, msg) GenerateContent(ctx, prompt) 返回响应(含工具调用) Execute(toolCall) 返回工具结果 构建最终响应 发送事件(迭代器) 插件处理 Persist(event) 返回事件 输出响应

8. 跨语言 SDK 互操作

ADK 支持 Python、Go、TypeScript 和 Java 四种语言。不同语言的智能体之间如何通信?ADK-Go 提供了两种互操作机制:REST API 和 A2A 协议。

8.1 跨语言互操作架构

#mermaid-svg-yAM2lJdFHX7ly01Q{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yAM2lJdFHX7ly01Q .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yAM2lJdFHX7ly01Q .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yAM2lJdFHX7ly01Q .error-icon{fill:#552222;}#mermaid-svg-yAM2lJdFHX7ly01Q .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yAM2lJdFHX7ly01Q .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yAM2lJdFHX7ly01Q .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yAM2lJdFHX7ly01Q .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yAM2lJdFHX7ly01Q .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yAM2lJdFHX7ly01Q .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yAM2lJdFHX7ly01Q .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yAM2lJdFHX7ly01Q .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yAM2lJdFHX7ly01Q .marker.cross{stroke:#333333;}#mermaid-svg-yAM2lJdFHX7ly01Q svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yAM2lJdFHX7ly01Q p{margin:0;}#mermaid-svg-yAM2lJdFHX7ly01Q .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-yAM2lJdFHX7ly01Q .cluster-label text{fill:#333;}#mermaid-svg-yAM2lJdFHX7ly01Q .cluster-label span{color:#333;}#mermaid-svg-yAM2lJdFHX7ly01Q .cluster-label span p{background-color:transparent;}#mermaid-svg-yAM2lJdFHX7ly01Q .label text,#mermaid-svg-yAM2lJdFHX7ly01Q span{fill:#333;color:#333;}#mermaid-svg-yAM2lJdFHX7ly01Q .node rect,#mermaid-svg-yAM2lJdFHX7ly01Q .node circle,#mermaid-svg-yAM2lJdFHX7ly01Q .node ellipse,#mermaid-svg-yAM2lJdFHX7ly01Q .node polygon,#mermaid-svg-yAM2lJdFHX7ly01Q .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yAM2lJdFHX7ly01Q .rough-node .label text,#mermaid-svg-yAM2lJdFHX7ly01Q .node .label text,#mermaid-svg-yAM2lJdFHX7ly01Q .image-shape .label,#mermaid-svg-yAM2lJdFHX7ly01Q .icon-shape .label{text-anchor:middle;}#mermaid-svg-yAM2lJdFHX7ly01Q .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yAM2lJdFHX7ly01Q .rough-node .label,#mermaid-svg-yAM2lJdFHX7ly01Q .node .label,#mermaid-svg-yAM2lJdFHX7ly01Q .image-shape .label,#mermaid-svg-yAM2lJdFHX7ly01Q .icon-shape .label{text-align:center;}#mermaid-svg-yAM2lJdFHX7ly01Q .node.clickable{cursor:pointer;}#mermaid-svg-yAM2lJdFHX7ly01Q .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yAM2lJdFHX7ly01Q .arrowheadPath{fill:#333333;}#mermaid-svg-yAM2lJdFHX7ly01Q .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yAM2lJdFHX7ly01Q .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yAM2lJdFHX7ly01Q .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yAM2lJdFHX7ly01Q .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yAM2lJdFHX7ly01Q .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yAM2lJdFHX7ly01Q .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yAM2lJdFHX7ly01Q .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yAM2lJdFHX7ly01Q .cluster text{fill:#333;}#mermaid-svg-yAM2lJdFHX7ly01Q .cluster span{color:#333;}#mermaid-svg-yAM2lJdFHX7ly01Q div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yAM2lJdFHX7ly01Q .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yAM2lJdFHX7ly01Q rect.text{fill:none;stroke-width:0;}#mermaid-svg-yAM2lJdFHX7ly01Q .icon-shape,#mermaid-svg-yAM2lJdFHX7ly01Q .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yAM2lJdFHX7ly01Q .icon-shape p,#mermaid-svg-yAM2lJdFHX7ly01Q .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yAM2lJdFHX7ly01Q .icon-shape .label rect,#mermaid-svg-yAM2lJdFHX7ly01Q .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yAM2lJdFHX7ly01Q .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yAM2lJdFHX7ly01Q .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yAM2lJdFHX7ly01Q :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 客户端
Go 服务端
REST API
REST API
REST API
REST API
A2A
A2A
A2A
ADK-Go
REST API Server
A2A Server
HTTP 端口
A2A 端口
Python SDK
TypeScript SDK
Java SDK
cURL
其他 ADK-Go 实例

8.2 REST API 暴露

REST API 是最直接的互操作方式。任何能发送 HTTP 请求的语言都可以调用 ADK-Go 智能体。启动 REST API 服务:

bash 复制代码
# 启动 Web API 模式,监听 8080 端口
go run agent.go web api --port 8080

REST API 提供了以下端点:

端点 方法 功能 使用场景
/api/v1/sessions POST 创建会话 初始化对话
/api/v1/sessions/{id} GET 获取会话详情 查看对话历史
/api/v1/sessions/{id}/messages POST 发送消息(SSE) 实时流式调用智能体
/api/v1/artifacts POST 上传制品 文件上传
/api/v1/artifacts/{id} GET 下载制品 文件下载
/api/v1/memory/items POST 创建记忆项 长期记忆管理

Python 调用示例

python 复制代码
# 导入 requests 库用于 HTTP 请求
import requests

# 创建会话:向 API 发送创建会话请求
resp = requests.post("http://localhost:8080/api/v1/sessions", json={
    "app_name": "my-app",  # 应用名称
    "user_id": "user-123"  # 用户标识
})
# 从响应中提取会话 ID
session_id = resp.json()["session"]["id"]

# 发送消息(SSE 流式):使用 sseclient 处理流式响应
import sseclient
resp = requests.post(
    f"http://localhost:8080/api/v1/sessions/{session_id}/messages",
    json={"content": {"parts": [{"text": "你好,请帮我查询天气"}]}},
    stream=True  # 启用流式模式
)
# 创建 SSE 客户端,逐事件处理响应
client = sseclient.SSEClient(resp)
for event in client.events():
    # 打印每个事件的原始数据
    print(event.data)

Python 通过 REST API 调用 Go 智能体的完整流程:
Go Agent Runner REST API Server Python SDK Go Agent Runner REST API Server Python SDK #mermaid-svg-24aItYjxraiS5EqS{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-24aItYjxraiS5EqS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-24aItYjxraiS5EqS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-24aItYjxraiS5EqS .error-icon{fill:#552222;}#mermaid-svg-24aItYjxraiS5EqS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-24aItYjxraiS5EqS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-24aItYjxraiS5EqS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-24aItYjxraiS5EqS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-24aItYjxraiS5EqS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-24aItYjxraiS5EqS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-24aItYjxraiS5EqS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-24aItYjxraiS5EqS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-24aItYjxraiS5EqS .marker.cross{stroke:#333333;}#mermaid-svg-24aItYjxraiS5EqS svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-24aItYjxraiS5EqS p{margin:0;}#mermaid-svg-24aItYjxraiS5EqS .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-24aItYjxraiS5EqS text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-24aItYjxraiS5EqS .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-24aItYjxraiS5EqS .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-24aItYjxraiS5EqS .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-24aItYjxraiS5EqS .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-24aItYjxraiS5EqS #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-24aItYjxraiS5EqS .sequenceNumber{fill:white;}#mermaid-svg-24aItYjxraiS5EqS #sequencenumber{fill:#333;}#mermaid-svg-24aItYjxraiS5EqS #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-24aItYjxraiS5EqS .messageText{fill:#333;stroke:none;}#mermaid-svg-24aItYjxraiS5EqS .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-24aItYjxraiS5EqS .labelText,#mermaid-svg-24aItYjxraiS5EqS .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-24aItYjxraiS5EqS .loopText,#mermaid-svg-24aItYjxraiS5EqS .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-24aItYjxraiS5EqS .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-24aItYjxraiS5EqS .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-24aItYjxraiS5EqS .noteText,#mermaid-svg-24aItYjxraiS5EqS .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-24aItYjxraiS5EqS .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-24aItYjxraiS5EqS .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-24aItYjxraiS5EqS .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-24aItYjxraiS5EqS .actorPopupMenu{position:absolute;}#mermaid-svg-24aItYjxraiS5EqS .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-24aItYjxraiS5EqS .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-24aItYjxraiS5EqS .actor-man circle,#mermaid-svg-24aItYjxraiS5EqS line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-24aItYjxraiS5EqS :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} loop 事件流 POST /api/v1/sessions/{id}/messages Run(userID, sessionID, msg) Run(ctx, session, msg) 事件 SSE 事件 SSE 响应 聚合事件 → 完整响应

8.3 A2A 协议互操作

A2A(Agent-to-Agent)协议是 Google 推出的智能体间通信标准协议。启动 A2A 服务:

bash 复制代码
# 启动 A2A 协议服务,监听 8081 端口
go run agent.go web a2a --port 8081

A2A 协议的核心组件是 AgentCard。它就像一个"智能体名片",告诉其他智能体:我是谁、我能做什么、怎么联系我。其他语言的 SDK 只需要知道这个 AgentCard 的 URL,就可以通过 JSON-RPC 协议调用 Go 智能体。

A2A 协议的核心特性:

  • 智能体发现:通过 AgentCard 标准机制发现远程智能体
  • 能力描述:AgentCard 包含智能体的工具列表和描述
  • 事件流:原生支持流式事件传递
  • 双向通信:支持智能体间的双向消息传递
  • 错误处理:内置的错误重试和故障转移机制

A2A 调用流程:
远程智能体(Go) AgentCard 本地智能体(Python) 远程智能体(Go) AgentCard 本地智能体(Python) #mermaid-svg-lOBe5X6BkBY4Xx4I{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-lOBe5X6BkBY4Xx4I .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-lOBe5X6BkBY4Xx4I .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-lOBe5X6BkBY4Xx4I .error-icon{fill:#552222;}#mermaid-svg-lOBe5X6BkBY4Xx4I .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-lOBe5X6BkBY4Xx4I .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-lOBe5X6BkBY4Xx4I .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-lOBe5X6BkBY4Xx4I .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-lOBe5X6BkBY4Xx4I .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-lOBe5X6BkBY4Xx4I .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-lOBe5X6BkBY4Xx4I .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-lOBe5X6BkBY4Xx4I .marker{fill:#333333;stroke:#333333;}#mermaid-svg-lOBe5X6BkBY4Xx4I .marker.cross{stroke:#333333;}#mermaid-svg-lOBe5X6BkBY4Xx4I svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-lOBe5X6BkBY4Xx4I p{margin:0;}#mermaid-svg-lOBe5X6BkBY4Xx4I .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-lOBe5X6BkBY4Xx4I text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-lOBe5X6BkBY4Xx4I .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-lOBe5X6BkBY4Xx4I .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-lOBe5X6BkBY4Xx4I .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-lOBe5X6BkBY4Xx4I .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-lOBe5X6BkBY4Xx4I #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-lOBe5X6BkBY4Xx4I .sequenceNumber{fill:white;}#mermaid-svg-lOBe5X6BkBY4Xx4I #sequencenumber{fill:#333;}#mermaid-svg-lOBe5X6BkBY4Xx4I #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-lOBe5X6BkBY4Xx4I .messageText{fill:#333;stroke:none;}#mermaid-svg-lOBe5X6BkBY4Xx4I .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-lOBe5X6BkBY4Xx4I .labelText,#mermaid-svg-lOBe5X6BkBY4Xx4I .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-lOBe5X6BkBY4Xx4I .loopText,#mermaid-svg-lOBe5X6BkBY4Xx4I .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-lOBe5X6BkBY4Xx4I .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-lOBe5X6BkBY4Xx4I .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-lOBe5X6BkBY4Xx4I .noteText,#mermaid-svg-lOBe5X6BkBY4Xx4I .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-lOBe5X6BkBY4Xx4I .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-lOBe5X6BkBY4Xx4I .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-lOBe5X6BkBY4Xx4I .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-lOBe5X6BkBY4Xx4I .actorPopupMenu{position:absolute;}#mermaid-svg-lOBe5X6BkBY4Xx4I .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-lOBe5X6BkBY4Xx4I .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-lOBe5X6BkBY4Xx4I .actor-man circle,#mermaid-svg-lOBe5X6BkBY4Xx4I line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-lOBe5X6BkBY4Xx4I :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} GET /agent-card 返回 AgentCard JSON JSON-RPC 请求 执行智能体逻辑 JSON-RPC 响应(事件流)

8.4 REST API 与 A2A 协议的区别

维度 REST API A2A 协议
通信协议 HTTP REST JSON-RPC over HTTP
智能体发现 无标准机制 AgentCard 标准发现
流式支持 SSE(Server-Sent Events) 原生流式支持
适用场景 任意语言客户端调用 智能体间互相调用
标准化程度 ADK 自定义 A2A 开放标准
工具调用 通过 SSE 事件 通过 A2A 消息格式

REST API 更适合外部客户端(如 Web 前端)调用智能体。A2A 协议更适合智能体之间的协作,因为它提供了标准化的智能体发现和能力描述机制。

8.5 与其他语言版本的对比

语言 定位 优势
Python 全功能,快速开发 丰富的生态,易于原型开发
Go 云原生,高性能 并发能力强,适合生产环境
TypeScript Web 前端集成 直接在浏览器运行
Java 企业级集成 成熟的企业生态

Go 版本特别适合构建需要高性能和并发处理能力的智能体应用。

9. 扩展点与插件生态

ADK-Go 的设计哲学是"开箱即用,但高度可扩展"。框架提供了多个级别的扩展点。

9.1 扩展点全景图

#mermaid-svg-gPpCcgU6jC9jWMXM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gPpCcgU6jC9jWMXM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gPpCcgU6jC9jWMXM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gPpCcgU6jC9jWMXM .error-icon{fill:#552222;}#mermaid-svg-gPpCcgU6jC9jWMXM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gPpCcgU6jC9jWMXM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gPpCcgU6jC9jWMXM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gPpCcgU6jC9jWMXM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gPpCcgU6jC9jWMXM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gPpCcgU6jC9jWMXM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gPpCcgU6jC9jWMXM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gPpCcgU6jC9jWMXM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gPpCcgU6jC9jWMXM .marker.cross{stroke:#333333;}#mermaid-svg-gPpCcgU6jC9jWMXM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gPpCcgU6jC9jWMXM p{margin:0;}#mermaid-svg-gPpCcgU6jC9jWMXM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gPpCcgU6jC9jWMXM .cluster-label text{fill:#333;}#mermaid-svg-gPpCcgU6jC9jWMXM .cluster-label span{color:#333;}#mermaid-svg-gPpCcgU6jC9jWMXM .cluster-label span p{background-color:transparent;}#mermaid-svg-gPpCcgU6jC9jWMXM .label text,#mermaid-svg-gPpCcgU6jC9jWMXM span{fill:#333;color:#333;}#mermaid-svg-gPpCcgU6jC9jWMXM .node rect,#mermaid-svg-gPpCcgU6jC9jWMXM .node circle,#mermaid-svg-gPpCcgU6jC9jWMXM .node ellipse,#mermaid-svg-gPpCcgU6jC9jWMXM .node polygon,#mermaid-svg-gPpCcgU6jC9jWMXM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gPpCcgU6jC9jWMXM .rough-node .label text,#mermaid-svg-gPpCcgU6jC9jWMXM .node .label text,#mermaid-svg-gPpCcgU6jC9jWMXM .image-shape .label,#mermaid-svg-gPpCcgU6jC9jWMXM .icon-shape .label{text-anchor:middle;}#mermaid-svg-gPpCcgU6jC9jWMXM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gPpCcgU6jC9jWMXM .rough-node .label,#mermaid-svg-gPpCcgU6jC9jWMXM .node .label,#mermaid-svg-gPpCcgU6jC9jWMXM .image-shape .label,#mermaid-svg-gPpCcgU6jC9jWMXM .icon-shape .label{text-align:center;}#mermaid-svg-gPpCcgU6jC9jWMXM .node.clickable{cursor:pointer;}#mermaid-svg-gPpCcgU6jC9jWMXM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gPpCcgU6jC9jWMXM .arrowheadPath{fill:#333333;}#mermaid-svg-gPpCcgU6jC9jWMXM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gPpCcgU6jC9jWMXM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gPpCcgU6jC9jWMXM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gPpCcgU6jC9jWMXM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gPpCcgU6jC9jWMXM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gPpCcgU6jC9jWMXM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gPpCcgU6jC9jWMXM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gPpCcgU6jC9jWMXM .cluster text{fill:#333;}#mermaid-svg-gPpCcgU6jC9jWMXM .cluster span{color:#333;}#mermaid-svg-gPpCcgU6jC9jWMXM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gPpCcgU6jC9jWMXM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gPpCcgU6jC9jWMXM rect.text{fill:none;stroke-width:0;}#mermaid-svg-gPpCcgU6jC9jWMXM .icon-shape,#mermaid-svg-gPpCcgU6jC9jWMXM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gPpCcgU6jC9jWMXM .icon-shape p,#mermaid-svg-gPpCcgU6jC9jWMXM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gPpCcgU6jC9jWMXM .icon-shape .label rect,#mermaid-svg-gPpCcgU6jC9jWMXM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gPpCcgU6jC9jWMXM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gPpCcgU6jC9jWMXM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gPpCcgU6jC9jWMXM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 核心
扩展层
服务层
智能体层
自定义 Agent
自定义 Model
自定义 Tool
自定义 SessionService
自定义 MemoryService
自定义 ArtifactService
插件系统
Web 子启动器
声明式配置
Runner

9.2 自定义智能体

ADK-Go 提供了 agent.New() 构造函数,允许开发者创建自定义智能体。

go 复制代码
// New 创建一个自定义智能体,接收 Config 配置结构体
// 返回 Agent 实例和可能的错误
func New(cfg Config) (Agent, error)

// Config 是创建智能体的配置结构体
type Config struct {
    // Name 是智能体名称,必须非空,在智能体树中唯一
    // 不能是 "user",因为这是保留给终端用户输入的
    Name string
    // Description 是智能体能力的描述
    // LLM 使用此描述来决定是否将控制权转移给此智能体
    // 建议使用一行描述
    Description string
    // SubAgents 是此智能体可以委托任务的子智能体列表
    // ADK 会自动设置每个子智能体的父智能体,以允许跨树转移
    SubAgents []Agent
    // BeforeAgentCallbacks 是在智能体开始运行前顺序调用的回调列表
    // 如果任何回调返回非 nil 内容或错误,则跳过智能体运行和剩余回调
    BeforeAgentCallbacks []BeforeAgentCallback
    // Run 是定义智能体行为的函数,接收 InvocationContext,返回事件迭代器
    Run func(InvocationContext) iter.Seq2[*session.Event, error]
    // AfterAgentCallbacks 是在智能体完成运行后顺序调用的回调列表
    // 如果任何回调返回非 nil 内容或错误,则创建新事件并跳过剩余回调
    AfterAgentCallbacks []AfterAgentCallback
}

开发者只需要实现 Run 函数,就可以创建完全自定义的智能体。Run 函数接收 InvocationContext 而不是原始参数,这提供了对会话、记忆、制品等的完整访问能力。

自定义智能体示例

go 复制代码
// 创建一个自定义智能体,传入 Config 配置结构体
myAgent, err := agent.New(agent.Config{
    // Name 是智能体的唯一标识
    Name: "my-custom-agent",
    // Description 描述智能体的能力,用于多智能体转移决策
    Description: "处理外部服务调用的自定义智能体",
    // SubAgents 可以添加子智能体,支持智能体转移
    SubAgents: []agent.Agent{},
    // Run 函数定义智能体的核心行为
    Run: func(ctx agent.InvocationContext) iter.Seq2[*session.Event, error] {
        // 返回一个迭代器函数,通过 yield 逐个产出事件
        return func(yield func(*session.Event, error) bool) {
            // 1. 从调用上下文中获取用户消息
            userContent := ctx.UserContent()
            // 2. 提取用户消息文本
            userText := extractText(userContent)
            // 3. 调用外部服务获取响应
            response := callExternalService(userText)
            // 4. 创建事件,传入调用 ID
            event := session.NewEvent(ctx.InvocationID())
            // 5. 设置事件作者为当前智能体
            event.Author = ctx.Agent().Name()
            // 6. 设置事件内容,包含响应文本
            event.LLMResponse = model.LLMResponse{
                Content: &genai.Content{
                    Parts: []genai.Part{genai.Text(response)},
                },
            }
            // 7. 通过 yield 返回事件
            yield(event, nil)
        }
    },
})
if err != nil {
    log.Fatalf("Failed to create custom agent: %v", err)
}

9.3 插件系统扩展

插件系统是 ADK-Go 最强大的扩展机制。一个插件可以在多个不同节点介入执行流程。

go 复制代码
// Plugin 结构体定义了插件的完整回调列表
// 使用 plugin.New(cfg) 创建插件实例,其中 cfg 是 plugin.Config 类型
type Plugin struct {
    // name 是插件的名称(小写,未导出)
    name string
    // onUserMessageCallback 在收到用户消息时调用
    onUserMessageCallback OnUserMessageCallback
    // onEventCallback 在收到事件时调用,可以修改事件或返回错误
    onEventCallback       OnEventCallback
    // beforeRunCallback 在 Run 执行前调用,如果返回内容则跳过执行
    beforeRunCallback BeforeRunCallback
    // afterRunCallback 在 Run 执行后调用
    afterRunCallback  AfterRunCallback
    // beforeAgentCallback 在智能体执行前调用
    beforeAgentCallback agent.BeforeAgentCallback
    // afterAgentCallback 在智能体执行后调用
    afterAgentCallback  agent.AfterAgentCallback
    // beforeModelCallback 在 LLM 调用前调用,可以修改请求
    beforeModelCallback  llmagent.BeforeModelCallback
    // afterModelCallback 在 LLM 调用后调用
    afterModelCallback   llmagent.AfterModelCallback
    // onModelErrorCallback 在 LLM 调用出错时调用
    onModelErrorCallback llmagent.OnModelErrorCallback
    // beforeToolCallback 在工具调用前调用
    beforeToolCallback  llmagent.BeforeToolCallback
    // afterToolCallback 在工具调用后调用
    afterToolCallback   llmagent.AfterToolCallback
    // onToolErrorCallback 在工具调用出错时调用
    onToolErrorCallback llmagent.OnToolErrorCallback
    // closeFunc 是插件关闭时的清理函数
    closeFunc func() error
}

这些回调节点覆盖了从用户消息到 LLM 调用到工具执行的完整生命周期。开发者可以:

  • beforeModelCallback 中修改 LLM 请求(如添加额外的上下文)
  • afterToolCallback 中记录工具调用结果
  • onEventCallback 中实现自定义错误重试逻辑
  • beforeRunCallback 中实现请求预处理或短路逻辑

插件注册方式

go 复制代码
// 创建 Runner 时注册插件
runner, err := runner.New(runner.Config{
    // Agent 是根智能体
    Agent:          myAgent,
    // SessionService 是会话服务
    SessionService: sessionService,
    // PluginConfig 配置插件列表
    PluginConfig: runner.PluginConfig{
        Plugins: []*plugin.Plugin{
            // 日志插件
            loggingPlugin,
            // 重试插件
            retryPlugin,
        },
    },
})

9.4 Web 子启动器

Web 启动器的 SubLauncher 接口允许开发者添加自定义的 HTTP 路由和服务。

go 复制代码
// SubLauncher 定义 Web 子启动器接口
type SubLauncher interface {
    // Keyword 返回激活此子启动器的命令行关键字
    Keyword() string
    // Parse 解析子启动器的参数
    Parse(args []string) ([]string, error)
    // CommandLineSyntax 返回命令行语法描述
    CommandLineSyntax() string
    // SimpleDescription 提供简短描述
    SimpleDescription() string
    // Run 执行子启动器逻辑
    Run(ctx context.Context, config *launcher.Config) error
    // SetupSubrouters 注册路由到主路由器
    SetupSubrouters(router *mux.Router, config *launcher.Config) error
}

开发者可以实现 SetupSubrouters 方法来注册自定义路由。例如,可以添加一个健康检查端点、自定义的 WebSocket 端点,或者集成第三方服务。

自定义 Web 子启动器示例

go 复制代码
// healthCheckLauncher 是一个健康检查子启动器
type healthCheckLauncher struct{}

// Keyword 返回命令行关键字 "health"
func (h *healthCheckLauncher) Keyword() string { return "health" }
// Parse 直接返回参数,不做额外解析
func (h *healthCheckLauncher) Parse(args []string) ([]string, error) { return args, nil }
// CommandLineSyntax 返回空字符串
func (h *healthCheckLauncher) CommandLineSyntax() string { return "" }
// SimpleDescription 返回简短描述
func (h *healthCheckLauncher) SimpleDescription() string { return "健康检查端点" }
// Run 不执行任何操作
func (h *healthCheckLauncher) Run(ctx context.Context, config *launcher.Config) error { return nil }
// SetupSubrouters 注册健康检查路由
func (h *healthCheckLauncher) SetupSubrouters(router *mux.Router, config *launcher.Config) error {
    // 注册 /health GET 端点,返回状态码 200 和 JSON 格式的状态信息
    router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
        w.Write([]byte(`{"status": "ok"}`))
    }).Methods("GET")
    return nil
}

9.5 服务接口替换

所有核心服务都是通过接口定义的,可以被替换为自定义实现。

go 复制代码
// session.Service 接口定义会话服务的核心操作
type Service interface {
    // Create 创建新会话
    Create(ctx context.Context, req *CreateRequest) (*CreateResponse, error)
    // Get 获取会话详情
    Get(ctx context.Context, req *GetRequest) (*GetResponse, error)
    // List 列出会话
    List(ctx context.Context, req *ListRequest) (*ListResponse, error)
    // Delete 删除会话
    Delete(ctx context.Context, req *DeleteRequest) error
    // AppendEvent 将事件追加到会话,并移除事件中的临时状态键
    AppendEvent(ctx context.Context, s Session, e *Event) error
}

// memory.Service 接口定义记忆服务的核心操作
type Service interface {
    // AddSessionToMemory 将整个会话内容添加到记忆库中
    // 一个会话在其生命周期中可以被多次添加
    AddSessionToMemory(ctx context.Context, s session.Session) error
    // SearchMemory 根据搜索请求检索相关记忆
    // 如果没有匹配,返回空切片
    SearchMemory(ctx context.Context, req *SearchRequest) (*SearchResponse, error)
}

// artifact.Service 接口定义制品服务的核心操作
type Service interface {
    // Save 保存制品到制品服务存储
    // 制品由应用名、用户ID、会话ID和文件名唯一标识
    // 保存后返回修订版本ID来标识制品版本
    Save(ctx context.Context, req *SaveRequest) (*SaveResponse, error)
    // Load 从存储中加载制品
    // 制品由应用名、用户ID、会话ID和文件名唯一标识
    Load(ctx context.Context, req *LoadRequest) (*LoadResponse, error)
    // Delete 删除制品,删除不存在的条目不是错误
    Delete(ctx context.Context, req *DeleteRequest) error
    // List 列出会话中的所有制品文件名
    List(ctx context.Context, req *ListRequest) (*ListResponse, error)
    // Versions 列出制品的所有版本
    Versions(ctx context.Context, req *VersionsRequest) (*VersionsResponse, error)
    // GetArtifactVersion 获取制品特定版本的元数据
    GetArtifactVersion(ctx context.Context, req *GetArtifactVersionRequest) (*GetArtifactVersionResponse, error)
}

例如,你可以实现一个基于 Redis 的会话服务,或者一个基于 PostgreSQL 的制品服务。只要实现了对应的接口,就可以无缝替换默认的内存实现。

自定义服务替换示例

go 复制代码
// 使用自定义会话服务(基于 Redis 的实现)
customSessionService := &RedisSessionService{}

// 创建 Runner,注入所有自定义服务
runner, err := runner.New(runner.Config{
    // Agent 是根智能体
    Agent:          myAgent,
    // SessionService 使用自定义 Redis 会话服务
    SessionService: customSessionService,
    // ArtifactService 使用自定义 PostgreSQL 制品服务
    ArtifactService: &PostgreSQLArtifactService{},
    // MemoryService 使用自定义向量数据库记忆服务
    MemoryService:   &VectorDBMemoryService{},
})

9.6 与其他 Go Agent 框架的对比

特性 ADK-Go LangChain Go Eino (ByteDance)
接口驱动 是,核心设计 部分
插件系统 10 个回调节点 回调函数 组件编排
多智能体 树形 + 工作流 + A2A 基础支持 图编排
A2A 协议 原生支持
工具生态 7 种工具类型 丰富 丰富
流式处理 原生 Go iterator 回调 流式管道
会话管理 内置服务 内存 内置
云原生 一等公民 一般 一般
学习曲线 中等 中等

ADK-Go 的优势在于:

  1. A2A 原生支持:这是 Google 提出的开放标准,ADK-Go 是参考实现
  2. 接口隔离:每个接口只定义必要的方法,保证了松耦合
  3. Go 原生设计:充分使用 Go 1.22+ 的 iterator、泛型等特性
  4. 插件系统:10 个回调节点覆盖了完整的执行生命周期