Google Developers Blog(RSS)
精选
67AI 编辑部评分,满分 100

ADK Go 2.0 发布:构建可靠的多智能体应用,新增基于图的工作流引擎、人工参与循环与动态编排

2026-07-01 01:17· 47天前
AI 导读

Agent Development Kit (ADK) for Go 2.0 发布,引入了一类基于图的工作流引擎,用于组合复杂多智能体应用。新版本内置人工参与循环(HITL)编排、使用纯 Go 代码的动态执行、以及指数退避重试等自动弹性特性。统一执行模型后,单智能体应用与复杂图均运行在同一运行时上,简化了遥测与状态持久化。

推荐理由

Google 给 Go 生态补上了多智能体编排的关键一环,图工作流引擎和人机协同直接内置,比之前拼积木的方式可靠很多,做 Agent 的 Go 开发者值得跟进。

正文 · AI 翻译

ADK for Go 2.0:以图结构构建智能体工作流

构建真实世界的智能体应用很少像发送单条提示词那么简单。生产环境中的智能体必须进行分类、分支、扇出、请求人工审批、失败重试,并循环执行直至完成。将这种复杂编排表达为临时控制流会很快变得脆弱。

自 1.0 版本发布以来,Go 语言的智能体开发工具包(ADK)帮助 Go 开发者以简洁、地道的 API 构建生产级智能体——强类型、iter.Seq2 事件流,以及能自然融入现有 Go 服务的运行时。这一基础取得了真正的成功,也正因如此,下一步的演进才成为可能。

今天,我们很高兴地分享 ADK for Go 2.0。其核心亮点是一种全新的、一等公民式的多智能体应用组合方式:基于图的 workflow 引擎。与之相伴的还有作为内置原语的人机协同(HITL)、用纯 Go 编写的动态编排、LLM 智能体模式,以及一个将所有功能统一起来的节点运行时——单个智能体和完整图结构现在运行在相同的执行模型上。

如果你关注过 Python ADK 2.0,那么对此会感到熟悉:这是相同的以图优先的方向,但从零开始设计,使其具有 Go 语言的感觉。

为什么采用图结构?

真实的智能体应用很少是单条提示词。它们需要进行分类、分支、扇出到专业智能体、收集结果、请求人工审批、失败重试,并循环执行直至完成。将这种逻辑表达为临时控制流会很快变得脆弱。

ADK 2.0 让你能够将应用的形态描述为由边连接的节点图,并将执行交给一个调度器,该调度器知道如何并发运行、持久化状态、暂停等待人工介入,以及稍后恢复执行——即使在进程重启后也能做到。以下是将节点串联在一起的简单方式:

import "google.golang.org/adk/v2/workflow"

upper  := workflow.NewFunctionNode("upper",  upperFn,  cfg)
suffix := workflow.NewFunctionNode("suffix", suffixFn, cfg)

edges := workflow.Chain(workflow.Start, upper, suffix)

wf, _ := workflowagent.New(workflowagent.Config{
    Name:  "simple_sequence_workflow",
    Edges: edges,
})

Go

那个 wf 就是一个 agent.Agent。它在你已经使用的同一个 runner、launcher 和 console 中运行——无需特殊框架,无需新服务器。图结构本身就是一个智能体。

构建模块

适用于一切的节点

节点是任何实现了 Node 接口的工作单元。你很少需要手动编写该接口——ADK 为常见场景提供了类型化的节点构造函数:

  • 函数节点封装了一个普通的带类型 Go 函数。泛型会自动为你推断输入/输出模式:
workflow.NewFunctionNode("classify",
    func(ctx agent.Context, in string) (Category, error) { ... }, cfg)

Go

  • 发射型函数节点是那些额外获得一个 emit 回调的函数节点,因此单个函数可以流式传输事件或暂停等待人工介入,而无需降级为动态节点:
workflow.NewEmittingFunctionNode("progress",
    func(ctx agent.Context, in Job, emit func(*session.Event) error) (Result, error) { ... }, cfg)

Go

  • 智能体节点可以将任意 `agent.Agent`(例如 `LlmAgent`)放入图中。
  • 工具节点将 `tool.Tool` 转换为图中的一个步骤。
  • 汇合节点是扇入屏障:它们等待所有前驱节点,然后将它们的输出以一个映射(map)的形式交给你。
  • 动态节点让你在代码中进行编排(下文将详细介绍)。
  • 工作流节点将整个子工作流嵌入为单个节点——图是可以组合的。
  • 并行工作器会针对列表中的每一项并发运行一个节点,并汇总结果。
  • 状态绑定节点(`NewFunctionNodeFromState`)通过 `state:"<key>"` 标签,将选定的会话状态值直接拉取到一个带类型的 Params 结构体中——无需手动进行状态传递。

边、路由以及你需要的形状

边连接节点,并且可以携带路由条件。一个节点会发射一个路由值;匹配的边会触发。仅这一个概念就能提供你所需的所有控制流形状:

b := workflow.NewEdgeBuilder()
b.AddRoutes(router, map[string]workflow.Node{
    "question":    answerNode,
    "statement":   commentNode,
    "exclamation": reactNode,
})
b.AddFanOut(planner, researchA, researchB, researchC) // parallel branches
b.AddFanIn(join, researchA, researchB, researchC)       // gather results

Go

顺序链、条件路由器、扇出/扇入、嵌套子图,甚至循环(已完成的节点可以被重新触发,因此循环是一等公民)——全部通过边和路由实现。标准路由包括 StringRoute、IntRoute、BoolRoute、MultiRoute,以及在没有其他匹配项时触发的 Default 路由。如需更深入的配置,请利用 Route 接口。

让大语言模型来引导图

最有用的模式之一是将模型用作路由器的“大脑”。LlmAgent 对用户消息进行分类;一个简单的函数发射匹配的路由;图将任务分派给正确的处理器:

User -> What time is it?    Agent -> question     answering question...
User -> Hello world!        Agent -> exclamation  reacting to exclamation...
User -> The sky is blue.    Agent -> statement    commenting on statement...

纯文本

模型做出决策;图使其变得可靠、可观测且可恢复。(参见 examples/workflow/routing/llm/。)

动态编排——用纯 Go 实现

有时执行顺序直到运行时才能确定:它取决于数据、循环次数,或者模型刚刚说了什么。为此,ADK 2.0 提供了动态节点,其中的编排主体是普通的 Go 代码,通过调用 `RunNode(...)` 来运行每个子节点:

greeter := workflow.NewDynamicNode("greeter_workflow",
    func(nc agent.Context, in string, emit func(*session.Event) error) (string, error) {
        return workflow.RunNode[string](nc, greeterNode, in)
    },
    workflow.NodeConfig{},
)

Go

循环、条件判断、累加、动态列表的扇出——所有这些都用你熟悉的 Go 语言来表达。诸如 `WithRunID`、`WithUseSubBranch`、`WithUseAsOutput` 和 `WithIsolationScope` 等选项,让你能够精确控制子节点身份、历史隔离和输出委派。这是 Python ADK 动态图在 Go 语言中的对应实现。

内置人工介入机制

生产环境中的智能体通常需要人类在运行过程中批准、纠正或提供某些信息。在 ADK 2.0 中,任何节点都可以暂停图执行并向人类提问——工作流会持久等待答案:

event := workflow.NewRequestInputEvent(ctx, session.RequestInput{
    InterruptID:    "approve_refund",
    Message:        "Approve a $200 refund? (yes/no)",
    ResponseSchema: schema,
})
// yield the event; the node moves to "waiting"

Go

当人类在后续轮次中回复时,工作流恢复执行。你可以选择恢复方式:

  • 交接——答案直接流向下一个节点。
  • 重新进入——暂停的节点重新运行,通过 `ctx.ResumedInput(...)` 获取人类的响应。

恢复过程是持久的。运行状态保存在会话中,ADK 甚至可以通过扫描会话历史来重建暂停的工作流——因此工作流可以在进程重启后恢复,甚至跨不同运行时恢复,因为中断格式与 Python ADK 共享。响应会按照模式进行验证,恢复操作是幂等的,当出现问题时你会收到明确的错误信息(`ErrInvalidResumeResponse`、`ErrNothingToResume`)。

控制台启动器和 Web UI 都原生支持人工介入机制,能够展示工具确认提示和工作流输入请求。

无需样板代码的弹性

每个节点都可以携带带有指数退避和抖动的重试策略——无需外部依赖:

cfg := workflow.NodeConfig{ RetryConfig: workflow.DefaultRetryConfig() }
// 5 attempts, 1s initial delay, 60s cap, 2x backoff, full jitter

Go

为每个节点添加超时设置,使用 `WithMaxConcurrency(n)` 限制图级别的并发数,并隔离并行分支,使一个分支的交互不会泄漏到另一个分支的 LLM 提示词历史中。调度器会为你处理 goroutine、通道、背压和取消操作。

智能体模式与统一运行时

ADK 2.0 为 LLM 智能体引入了多种模式——聊天模式、任务模式和单轮模式——因此协调器可以与用户聊天,同时子智能体静默完成任务或执行单次操作。根据每个智能体的角色,会自动安装相应的辅助工具(`finish_task`、`single_turn`、`task`)。

在底层,运行器现在通过驱动工作流的同一节点运行时,驱动一个纯粹的 LlmAgent。其回报是:单智能体应用和完整图共享同一个执行模型,并且人机交互现在也能用于纯粹的 LLM 智能体——而不仅限于工作流内部。

我们还简化了编程模型:ToolContext 和 CallbackContext 现在统一为单一的 agent.Context——无论你是在编写工具、回调还是图节点,只需学习这一种类型——并且节点/智能体的执行会显示在一条一致的遥测跨度树中,这样你就能准确看到你的图执行了哪些操作。

从 1.0 升级

ADK 2.0 是高度增量的——整个工作流引擎都是你可以选择接入的新包。在统一运行时的过程中,有一些新的且不兼容的变更;每个变更都有简单、机械式的修复方法:

  • 节点和节点函数的签名现在接收 `agent.Context`。如果你编写节点或节点函数,请将第一个参数从 `agent.InvocationContext` 改为 `agent.Context`(它内嵌了 InvocationContext,因此你使用的所有方法仍然有效):
// before:  func(ctx agent.InvocationContext, in string) (string, error)
// after:   func(ctx agent.Context,           in string) (string, error)

Go

  • 统一的上下文。ToolContext、CallbackContext 已不复存在——工具、回调和工作流节点都直接接收 agent.Context。如果你在测试中模拟过上下文,`agent/context_mock.go` 仍然保留;请使用该文件中的 `StrictContextMock` 作为你的测试替身。
  • 自定义的 `InvocationContext` 实现需要两个方法:`IsolationScope()` 和 `ResumedInput(id string)`。大多数代码会内嵌提供的实现,并免费获得这些方法。
  • 事件流更加丰富。事件现在携带节点字段(IsolationScope、Output、Routes、RequestedInput)和一个元数据字段(NodeInfo)。如果你在测试中断言确切的 `session.Event` 相等性,请预期这些新字段;自定义会话存储应持久化它们。
  • `llmagent.New` 可能会安装特定模式的工具。如果你设置了子智能体模式,有效的工具集会反映这些模式;任务模式下的智能体不能用作静态图节点。
  • `session.NewEvent` 接收一个上下文。其签名现在是 `NewEvent(ctx context.Context, invocationID string)`。通过将已在作用域内的 `context.Context` 作为第一个参数传入,来迁移调用点。

以上就是全部列表。`runner.Run/RunLive`、`agenttool` 以及 LLM 智能体回调的公开签名保持不变。如需查看分步的修改前后对比说明,请参阅 ADK Go 2.0 迁移指南。

立即体验

快速上手 ADK 2.0 的最佳方式是查看新的工作流示例:

go run ./examples/workflow/basic/
go run ./examples/workflow/routing/llm/      # LLM-as-router
go run ./examples/workflow/dynamic/hitl/     # dynamic + human-in-the-loop
go run ./examples/workflow/hitl_rerun/       # HITL with re-entry resume
go run ./examples/workflow/complex/          # a larger, multi-shape graph

Shell

ADK 1.0 已经证明,用 Go 语言构建严肃的智能体可以既简洁又高效。ADK 2.0 则更进一步:将这些智能体组合成可靠、可观测、可恢复的工作流——以图结构的形式,用地道的 Go 语言实现,并在关键时刻让人参与其中。

我们迫不及待想看到你的作品。

—— ADK for Go 团队

来源:Google Developers Blog(RSS) · developers.googleblog.com

ADK Go 2.0 发布:构建可靠的多智能体应用,新增基于图的工作流引擎、人工参与循环与动态编排

Google Developers Blog(RSS)·2026-07-01 01:17·47天前
AI 导读

Agent Development Kit (ADK) for Go 2.0 发布,引入了一类基于图的工作流引擎,用于组合复杂多智能体应用。新版本内置人工参与循环(HITL)编排、使用纯 Go 代码的动态执行、以及指数退避重试等自动弹性特性。统一执行模型后,单智能体应用与复杂图均运行在同一运行时上,简化了遥测与状态持久化。

正文 · AI 翻译

ADK for Go 2.0:以图结构构建智能体工作流

构建真实世界的智能体应用很少像发送单条提示词那么简单。生产环境中的智能体必须进行分类、分支、扇出、请求人工审批、失败重试,并循环执行直至完成。将这种复杂编排表达为临时控制流会很快变得脆弱。

自 1.0 版本发布以来,Go 语言的智能体开发工具包(ADK)帮助 Go 开发者以简洁、地道的 API 构建生产级智能体——强类型、iter.Seq2 事件流,以及能自然融入现有 Go 服务的运行时。这一基础取得了真正的成功,也正因如此,下一步的演进才成为可能。

今天,我们很高兴地分享 ADK for Go 2.0。其核心亮点是一种全新的、一等公民式的多智能体应用组合方式:基于图的 workflow 引擎。与之相伴的还有作为内置原语的人机协同(HITL)、用纯 Go 编写的动态编排、LLM 智能体模式,以及一个将所有功能统一起来的节点运行时——单个智能体和完整图结构现在运行在相同的执行模型上。

如果你关注过 Python ADK 2.0,那么对此会感到熟悉:这是相同的以图优先的方向,但从零开始设计,使其具有 Go 语言的感觉。

为什么采用图结构?

真实的智能体应用很少是单条提示词。它们需要进行分类、分支、扇出到专业智能体、收集结果、请求人工审批、失败重试,并循环执行直至完成。将这种逻辑表达为临时控制流会很快变得脆弱。

ADK 2.0 让你能够将应用的形态描述为由边连接的节点图,并将执行交给一个调度器,该调度器知道如何并发运行、持久化状态、暂停等待人工介入,以及稍后恢复执行——即使在进程重启后也能做到。以下是将节点串联在一起的简单方式:

import "google.golang.org/adk/v2/workflow"

upper  := workflow.NewFunctionNode("upper",  upperFn,  cfg)
suffix := workflow.NewFunctionNode("suffix", suffixFn, cfg)

edges := workflow.Chain(workflow.Start, upper, suffix)

wf, _ := workflowagent.New(workflowagent.Config{
    Name:  "simple_sequence_workflow",
    Edges: edges,
})

Go

那个 wf 就是一个 agent.Agent。它在你已经使用的同一个 runner、launcher 和 console 中运行——无需特殊框架,无需新服务器。图结构本身就是一个智能体。

构建模块

适用于一切的节点

节点是任何实现了 Node 接口的工作单元。你很少需要手动编写该接口——ADK 为常见场景提供了类型化的节点构造函数:

  • 函数节点封装了一个普通的带类型 Go 函数。泛型会自动为你推断输入/输出模式:
workflow.NewFunctionNode("classify",
    func(ctx agent.Context, in string) (Category, error) { ... }, cfg)

Go

  • 发射型函数节点是那些额外获得一个 emit 回调的函数节点,因此单个函数可以流式传输事件或暂停等待人工介入,而无需降级为动态节点:
workflow.NewEmittingFunctionNode("progress",
    func(ctx agent.Context, in Job, emit func(*session.Event) error) (Result, error) { ... }, cfg)

Go

  • 智能体节点可以将任意 `agent.Agent`(例如 `LlmAgent`)放入图中。
  • 工具节点将 `tool.Tool` 转换为图中的一个步骤。
  • 汇合节点是扇入屏障:它们等待所有前驱节点,然后将它们的输出以一个映射(map)的形式交给你。
  • 动态节点让你在代码中进行编排(下文将详细介绍)。
  • 工作流节点将整个子工作流嵌入为单个节点——图是可以组合的。
  • 并行工作器会针对列表中的每一项并发运行一个节点,并汇总结果。
  • 状态绑定节点(`NewFunctionNodeFromState`)通过 `state:"<key>"` 标签,将选定的会话状态值直接拉取到一个带类型的 Params 结构体中——无需手动进行状态传递。

边、路由以及你需要的形状

边连接节点,并且可以携带路由条件。一个节点会发射一个路由值;匹配的边会触发。仅这一个概念就能提供你所需的所有控制流形状:

b := workflow.NewEdgeBuilder()
b.AddRoutes(router, map[string]workflow.Node{
    "question":    answerNode,
    "statement":   commentNode,
    "exclamation": reactNode,
})
b.AddFanOut(planner, researchA, researchB, researchC) // parallel branches
b.AddFanIn(join, researchA, researchB, researchC)       // gather results

Go

顺序链、条件路由器、扇出/扇入、嵌套子图,甚至循环(已完成的节点可以被重新触发,因此循环是一等公民)——全部通过边和路由实现。标准路由包括 StringRoute、IntRoute、BoolRoute、MultiRoute,以及在没有其他匹配项时触发的 Default 路由。如需更深入的配置,请利用 Route 接口。

让大语言模型来引导图

最有用的模式之一是将模型用作路由器的“大脑”。LlmAgent 对用户消息进行分类;一个简单的函数发射匹配的路由;图将任务分派给正确的处理器:

User -> What time is it?    Agent -> question     answering question...
User -> Hello world!        Agent -> exclamation  reacting to exclamation...
User -> The sky is blue.    Agent -> statement    commenting on statement...

纯文本

模型做出决策;图使其变得可靠、可观测且可恢复。(参见 examples/workflow/routing/llm/。)

动态编排——用纯 Go 实现

有时执行顺序直到运行时才能确定:它取决于数据、循环次数,或者模型刚刚说了什么。为此,ADK 2.0 提供了动态节点,其中的编排主体是普通的 Go 代码,通过调用 `RunNode(...)` 来运行每个子节点:

greeter := workflow.NewDynamicNode("greeter_workflow",
    func(nc agent.Context, in string, emit func(*session.Event) error) (string, error) {
        return workflow.RunNode[string](nc, greeterNode, in)
    },
    workflow.NodeConfig{},
)

Go

循环、条件判断、累加、动态列表的扇出——所有这些都用你熟悉的 Go 语言来表达。诸如 `WithRunID`、`WithUseSubBranch`、`WithUseAsOutput` 和 `WithIsolationScope` 等选项,让你能够精确控制子节点身份、历史隔离和输出委派。这是 Python ADK 动态图在 Go 语言中的对应实现。

内置人工介入机制

生产环境中的智能体通常需要人类在运行过程中批准、纠正或提供某些信息。在 ADK 2.0 中,任何节点都可以暂停图执行并向人类提问——工作流会持久等待答案:

event := workflow.NewRequestInputEvent(ctx, session.RequestInput{
    InterruptID:    "approve_refund",
    Message:        "Approve a $200 refund? (yes/no)",
    ResponseSchema: schema,
})
// yield the event; the node moves to "waiting"

Go

当人类在后续轮次中回复时,工作流恢复执行。你可以选择恢复方式:

  • 交接——答案直接流向下一个节点。
  • 重新进入——暂停的节点重新运行,通过 `ctx.ResumedInput(...)` 获取人类的响应。

恢复过程是持久的。运行状态保存在会话中,ADK 甚至可以通过扫描会话历史来重建暂停的工作流——因此工作流可以在进程重启后恢复,甚至跨不同运行时恢复,因为中断格式与 Python ADK 共享。响应会按照模式进行验证,恢复操作是幂等的,当出现问题时你会收到明确的错误信息(`ErrInvalidResumeResponse`、`ErrNothingToResume`)。

控制台启动器和 Web UI 都原生支持人工介入机制,能够展示工具确认提示和工作流输入请求。

无需样板代码的弹性

每个节点都可以携带带有指数退避和抖动的重试策略——无需外部依赖:

cfg := workflow.NodeConfig{ RetryConfig: workflow.DefaultRetryConfig() }
// 5 attempts, 1s initial delay, 60s cap, 2x backoff, full jitter

Go

为每个节点添加超时设置,使用 `WithMaxConcurrency(n)` 限制图级别的并发数,并隔离并行分支,使一个分支的交互不会泄漏到另一个分支的 LLM 提示词历史中。调度器会为你处理 goroutine、通道、背压和取消操作。

智能体模式与统一运行时

ADK 2.0 为 LLM 智能体引入了多种模式——聊天模式、任务模式和单轮模式——因此协调器可以与用户聊天,同时子智能体静默完成任务或执行单次操作。根据每个智能体的角色,会自动安装相应的辅助工具(`finish_task`、`single_turn`、`task`)。

在底层,运行器现在通过驱动工作流的同一节点运行时,驱动一个纯粹的 LlmAgent。其回报是:单智能体应用和完整图共享同一个执行模型,并且人机交互现在也能用于纯粹的 LLM 智能体——而不仅限于工作流内部。

我们还简化了编程模型:ToolContext 和 CallbackContext 现在统一为单一的 agent.Context——无论你是在编写工具、回调还是图节点,只需学习这一种类型——并且节点/智能体的执行会显示在一条一致的遥测跨度树中,这样你就能准确看到你的图执行了哪些操作。

从 1.0 升级

ADK 2.0 是高度增量的——整个工作流引擎都是你可以选择接入的新包。在统一运行时的过程中,有一些新的且不兼容的变更;每个变更都有简单、机械式的修复方法:

  • 节点和节点函数的签名现在接收 `agent.Context`。如果你编写节点或节点函数,请将第一个参数从 `agent.InvocationContext` 改为 `agent.Context`(它内嵌了 InvocationContext,因此你使用的所有方法仍然有效):
// before:  func(ctx agent.InvocationContext, in string) (string, error)
// after:   func(ctx agent.Context,           in string) (string, error)

Go

  • 统一的上下文。ToolContext、CallbackContext 已不复存在——工具、回调和工作流节点都直接接收 agent.Context。如果你在测试中模拟过上下文,`agent/context_mock.go` 仍然保留;请使用该文件中的 `StrictContextMock` 作为你的测试替身。
  • 自定义的 `InvocationContext` 实现需要两个方法:`IsolationScope()` 和 `ResumedInput(id string)`。大多数代码会内嵌提供的实现,并免费获得这些方法。
  • 事件流更加丰富。事件现在携带节点字段(IsolationScope、Output、Routes、RequestedInput)和一个元数据字段(NodeInfo)。如果你在测试中断言确切的 `session.Event` 相等性,请预期这些新字段;自定义会话存储应持久化它们。
  • `llmagent.New` 可能会安装特定模式的工具。如果你设置了子智能体模式,有效的工具集会反映这些模式;任务模式下的智能体不能用作静态图节点。
  • `session.NewEvent` 接收一个上下文。其签名现在是 `NewEvent(ctx context.Context, invocationID string)`。通过将已在作用域内的 `context.Context` 作为第一个参数传入,来迁移调用点。

以上就是全部列表。`runner.Run/RunLive`、`agenttool` 以及 LLM 智能体回调的公开签名保持不变。如需查看分步的修改前后对比说明,请参阅 ADK Go 2.0 迁移指南。

立即体验

快速上手 ADK 2.0 的最佳方式是查看新的工作流示例:

go run ./examples/workflow/basic/
go run ./examples/workflow/routing/llm/      # LLM-as-router
go run ./examples/workflow/dynamic/hitl/     # dynamic + human-in-the-loop
go run ./examples/workflow/hitl_rerun/       # HITL with re-entry resume
go run ./examples/workflow/complex/          # a larger, multi-shape graph

Shell

ADK 1.0 已经证明,用 Go 语言构建严肃的智能体可以既简洁又高效。ADK 2.0 则更进一步:将这些智能体组合成可靠、可观测、可恢复的工作流——以图结构的形式,用地道的 Go 语言实现,并在关键时刻让人参与其中。

我们迫不及待想看到你的作品。

—— ADK for Go 团队

来源:Google Developers Blog(RSS)· developers.googleblog.com