ADK 框架结构

Eino ADK 的整体模块构成,如下图所示:

Agent Interface

Eino ADK 的核心成员是 Agent 抽象(Agent Interface),ADK 的所有功能设计均围绕 Agent 抽象展开。

Agent 核心行为抽象大致可描述为:

从入参中 AgentInput、AgentRunOption 和 可选的 Context Session,获取任务详情及相关数据

执行任务,并将执行过程、执行结果输出到 AgenEvent Iterator

执行任务时,可通过 Context 中的 Session 暂存数据

1
2
3
4
5
6
type Agent interface {
Name(ctx context.Context) string
Description(ctx context.Context) string
Run(ctx context.Context, input *AgentInput) *AsyncIterator[*AgentEvent]
}

在 Agent Run 的实现中,一般是 Future 模式的异步执行,大体分成三步,具体可参考 adk.ChatModelAgent 中 Run 方法的实现:

  1. 创建一对 Iterator、Generator
  2. 启动 Agent 的异步任务,并传入 Generator,处理 AgentInput。在这个异步任务中,产生新的事件时,写入到 Generator 中,供 Agent 调用方在 Iterator 中消费
  3. 启动任务后,返回 Iterator

Agent 扩展行为抽象大致可描述为:

Agent 既可添加子 Agent,也可添加父 Agent,即作为 父 Agent 的 子 Agent

Agent 在执行任务时,可根据需要将任务转让(Transfer)给其 父 Agent 或 子 Agent

1
2
3
4
5
6
type OnSubAgents interface {
OnSetSubAgents(ctx context.Context, subAgents []Agent) error
OnSetAsSubAgent(ctx context.Context, parent Agent) error

OnDisallowTransferToParent(ctx context.Context) error
}

中心化的运行状态管理:

在 ADK 组合产物的运行中,每个 Agent 均可通过 context 中的 Session map[string]any 存取一些数据,Session 对所有 Agent 可见。Session 的生命周期对应着 ADK 组合产物的一次运行的生命周期(Interrupt&Resume 视为同一个生命周期)。

1
2
3
4
5
6
7
func SetSessionValue(ctx context.Context, key string, value any) {
// omit code
}

func GetSessionValue(ctx context.Context, key string) (any, bool) {
// omit code
}

Agent Compose

围绕 Agent 抽象,提供多种简单易用、场景丰富的组合原语,可支撑开发丰富多样的 Multi-Agent 协同策略,比如 Supervisor、Plan-Execute、Group-Chat 等 Multi-Agent 场景。从而实现不同的 Agent 分工合作模式,处理更复杂的任务。

Agent 协作过程中,可能存在的协作原语:

  • Agent 间协作方式
协助方式 描述
Transfer 直接将任务转让给另外一个 Agent,本 Agent 则执行结束后退出,不关心转让 Agent 的任务执行状态
ToolCall(AgentAsTool) 将 Agent 当成 ToolCall 调用,等待 Agent 的响应,并可获取被调用Agent 的输出结果,进行下一轮处理
  • AgentInput 的上下文策略
上下文策略 描述
上游 Agent 全对话 获取本 Agent 的上游 Agent 的完整对话记录
全新任务描述 忽略掉上游 Agent 的完整对话记录,给出一个全新的任务总结,作为子 Agent 的 AgentInput 输入
  • 决策自主性
决策自主性 描述
自主决策 在 Agent 内部,基于其可选的下游 Agent, 如需协助时,自主选择下游 Agent 进行协助。 一般来说,Agent 内部是基于 LLM 进行决策,不过即使是基于预设逻辑进行选择,从 Agent 外部看依然视为自主决策
预设决策 事先预设好一个Agent 执行任务后的下一个 Agent。 Agent 的执行顺序是事先确定、可预测的

接下来简要说明下,Agent Compose 下的不同的组合原语。

决策自主性 描述
自主决策 在 Agent 内部,基于其可选的下游 Agent, 如需协助时,自主选择下游 Agent 进行协助。 一般来说,Agent 内部是基于 LLM 进行决策,不过即使是基于预设逻辑进行选择,从 Agent 外部看依然视为自主决策
预设决策 事先预设好一个Agent 执行任务后的下一个 Agent。 Agent 的执行顺序是事先确定、可预测的

接下来简要说明下,Agent Compose 下的不同的组合原语。

SubAgents

  • Agent 间协作方式:Transfer
  • AgentInput 的上下文策略:上游 Agent 全对话
  • 决策自主性:自主决策

将用户提供的 agent 作为 父 Agent,用户提供的 subAgents 列表作为 子 Agents,组合而成可自主决策的 Agent,其中的 Name 和 Description 作为该 Agent 的名称标识和描述。

  • 当前限定一个 Agent 只能有一个 父 Agent
  • 可采用 SetSubAgents 函数,构建 「多叉树」 形式的 Multi-Agent
  • 在这个「多叉树」中,AgentName 需要保持唯一
1
2
3
func SetSubAgents(ctx context.Context, agent Agent, subAgents []Agent) (Agent, error) {
// omit code
}

image-20250909122346667

Workflow

提供了 顺序、并行和循环三种工作流模式,供用户灵活组合出不同的工作流图

在 Workflow Agent 中,每个 Agent 拿到相同的 AgentInput 输入,按照预先设定好的拓扑结构所表达的顺序依次运行

Sequential

  • Agent 间协作方式:Transfer
  • AgentInput 的上下文策略:上游 Agent 全对话
  • 决策自主性:预设决策

将用户提供的 SubAgents 列表,组合成按照顺序依次执行的 Sequential Agent,其中的 Name 和 Description 作为 Sequential Agent 的名称标识和描述。

Sequential Agent 执行时,将 SubAgents 列表,按照顺序依次执行,直至将所有 Agent 执行一遍后结束。

注: 由于 Agent 只能获取到上游 Agent 的全对话,后执行的 Agent 看不到先执行的 Agent 的 AgentEvent 输出。

1
2
3
4
5
6
7
8
9
type SequentialAgentConfig struct {
Name string
Description string
SubAgents []Agent
}

func NewSequentialAgent(ctx context.Context, config *SequentialAgentConfig) (Agent, error) {
// omit code
}

image-20250909122414334

Parallel

  • Agent 间协作方式:Transfer
  • AgentInput 的上下文策略:上游 Agent 全对话
  • 决策自主性:预设决策

将用户提供的 SubAgents 列表,组合成基于相同上下文,并发执行的 Parallel Agent,其中的 Name 和 Description 作为 Parallel Agent 的名称标识和描述。

Parallel Agent 执行时,将 SubAgents 列表,并发执行,待所有 Agent 执行完成后结束。

1
2
3
4
5
6
7
8
9
type ParallelAgentConfig struct {
Name string
Description string
SubAgents []Agent
}

func NewParallelAgent(ctx context.Context, config *ParallelAgentConfig) (Agent, error) {
// omit code
}

Loop

  • Agent 间协作方式:Transfer
  • AgentInput 的上下文策略:上游 Agent 全对话
  • 决策自主性:预设决策

将用户提供的 SubAgents 列表,按照数组顺序依次执行,循环往复,组合成 Loop Agent,其中的 Name 和 Description 作为 Loop Agent 的名称标识和描述。

Loop Agent 执行时,将 SubAgents 列表,按照顺序依次执行,并循环往复,直至配置的最大迭代次数为止。

1
2
3
4
5
6
7
8
9
10
11
type LoopAgentConfig struct {
Name string
Description string
SubAgents []Agent

MaxIterations int
}

func NewLoopAgent(ctx context.Context, config *LoopAgentConfig) (Agent, error) {
// omit code
}

image-20250909122445696

AgentAsTool

  • Agent 间协作方式:ToolCall
  • AgentInput 的上下文策略:全新任务描述
  • 决策自主性:自主决策

将一个 Agent 转换成 Tool,被其他的 Agent 当成普通的 Tool 使用。

注:一个 Agent 能否将其他 Agent 当成 Tool 进行调用,取决于自身的实现。adk 中提供的 ChatModelAgent 支持 AgentAsTool 的功能

1
2
3
func NewAgentTool(_ context.Context, agent Agent, options ...AgentToolOption) tool.BaseTool {
// omit code
}

下图展示了 Agent1 把 Agent2、Agent3 当成 Tool 进行调用的过程,类似 Function Stack Call,即在 Agent1 运行过程中,将 Agent2、Agent3 当成工具函数来进行调用。

  • AgentAsTool 可作为 Supervisor Multi-Agent 的一种实现方式

image-20250909122513626

Single Agent

Built-In Single Agent

ChatModelAgent

ChatModelAgent 实现了 ReAct 范式的 Agent,基于 Eino 中的 Graph 编排出 ReAct Agent 控制流,通过 callbacks.Handler 导出 ReAct Agent 运行过程中产生的事件,转换成 AgentEvent 返回。

想要进一步了解 ChatModelAgent,请看:Eino ADK: ChatModelAgent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type ChatModelAgentConfig struct {
Name string
Description string
Instruction string

Model model.ToolCallingChatModel

ToolsConfig ToolsConfig

// optional
GenModelInput GenModelInput

// Exit tool. Optional, defaults to nil, which will generate an Exit Action.
// The built-in implementation is 'ExitTool'
Exit tool.BaseTool

// optional
OutputKey string
}

func NewChatModelAgent(_ context.Context, config *ChatModelAgentConfig) (*ChatModelAgent, error) {
// omit code
}

Agent 运行

AgentRunner 是 Agent 的执行器。

通过 ADK 框架,编排组合出的 Multi-Agent,推荐采用 adk.NewRunner 包装执行。 只有通过 Runner 执行 agent 时,才可以使用 ADK 的如下功能:

  • Interrupt & Resume
  • 切面机制
  • Context 环境的预处理
1
2
3
4
5
6
7
type RunnerConfig struct {
EnableStreaming bool
}

func NewRunner(_ context.Context, conf RunnerConfig) *Runner {
// omit code
}

Agent 运行示例

Agent 执行时,通过 adk.NewRunner 包装执行,方便使用 adk 提供的各种扩展能力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
func runWithRunner() {
ctx := context.Background()

// 创建 Runner
runner := adk.NewRunner(ctx, adk.RunnerConfig{
EnableStreaming: true,
})

// 执行代理
messages := []adk.Message{
schema.UserMessage("What's the weather like today?"),
}

events := runner.Run(ctx, agent, messages)
for {
event, ok := events.Next()
if !ok {
break
}

// 处理事件
handleEvent(event)
}
}

参考

https://www.cloudwego.io/zh/docs/eino/core_modules/eino_adk/outline/