Eino--ADK的Agent底层核心抽象规范
ADK (Agent Development Kit,智能体开发套件)是 Eino 提供的一套标准化 Agent 开发抽象层,不管你写什么类型智能体(单 Agent、多 Agent 协作、工具调用、循环 Agent),全都统一实现一套 TypedAgent 接口,框架就能统一调度、流式消费、多智能体互通。
所有代码基于 Go 泛型设计,用泛型区分两种消息格式:传统 *schema.Message / 新版结构化 *schema.AgenticMessage。
一、最顶层核心:TypedAgent 接口
type TypedAgent[M MessageType] interface {
Name(ctx context.Context) string
Description(ctx context.Context) string
Run(ctx context.Context, input *TypedAgentInput[M], options ...AgentRunOption) *AsyncIterator[*TypedAgentEvent[M]]
}
type Agent = TypedAgent[*schema.Message] // 日常99%场景用这个别名
三个方法分工极其清晰,类比成「员工」更好理解:
- Name():员工姓名,全局唯一标识,多 Agent 调度时用来区分是谁在干活
- Description():员工简历 / 能力介绍
- 框架自动读取;
- 多 Agent 协作时,别的 Agent 靠这段描述知道能不能把任务交给它;
- Run():干活的入口函数,最核心
- 入参:input 用户对话历史、是否开流式输出;options 本次运行临时配置;
- 返回:AsyncIterator 异步事件流(源源不断产出执行过程事件)。
MessageType 泛型约束(两种消息模式二选一)
type MessageType interface {
*schema.Message | *schema.AgenticMessage
}
- *schema.Message:传统对话消息,文本、工具调用、普通聊天,完整兼容所有 Eino 组件(ChatModel、工具、记忆),日常开发首选,别名 Agent 就是它;
- *schema.AgenticMessage:v0.9 新结构,结构化内容块,适合复杂多 Agent 分层、强结构化输出场景,偏高级用法。
文档里所有带 TypedXXX[M] 的结构体,都有不带 Typed 的简写别名,不用每次写长泛型:
| 泛型完整类型 | 日常简写别名 |
|---|---|
| TypedAgent[*schema.Message] | Agent |
| TypedAgentInput | AgentInput |
| TypedAgentEvent | AgentEvent |
| TypedAgentOutput | AgentOutput |
| TypedMessageVariant | MessageVariant |
二、Run 入参:TypedAgentInput / AgentInput(传给 Agent 的任务信息)
type TypedAgentInput[M MessageType] struct {
Messages []M
EnableStreaming bool
}
- Messages []M
对话上下文,等价大模型 Chat 请求:包含用户提问、历史聊天、工具返回结果、系统提示词。Agent 读取这段对话做推理。 - EnableStreaming bool
流式开关:- true:尽量分段输出(打字机效果,逐字返回);
- false:全部推理完一次性返回完整结果;
不支持流式的 Agent(比如纯工具执行、静态决策 Agent)会自动忽略这个字段。
三、Run 返回:AsyncIterator 异步事件迭代器(流式结果载体)
3.1 作用
Agent.Run 不会阻塞主线程,内部开 goroutine 执行逻辑,一边跑一边不断发送事件 Event,外部通过迭代器循环读取实时消息、工具动作、中断、报错。
3.2 标准使用模板(消费 Agent 输出)
运行
// 启动Agent,拿到事件迭代器
iter := agent.Run(ctx, input)
// 循环读取所有运行事件
for {
event, ok := iter.Next()
if !ok {
// 迭代器关闭,Agent执行完毕,退出循环
break
}
// 处理每一步事件:打印文字、捕获工具调用、监听中断、处理报错
}
iter.Next() 是阻塞调用:没有新事件就卡住,直到有输出 / 执行结束。
3.3 Agent 内部如何生成迭代器?(自定义 Agent 必写模板)
这个迭代器是自定义的
func (m *MyAgent) Run(ctx context.Context, input *adk.AgentInput, opts ...adk.AgentRunOption) *adk.AsyncIterator[*adk.AgentEvent] {
// 创建一对:迭代器(对外返回) + 生成器(内部发事件)
iter, gen := adk.NewAsyncIteratorPair[*adk.AgentEvent]()
go func() {
defer gen.Close() // Agent逻辑结束自动关闭流
// 业务逻辑:大模型推理、循环调用工具、多Agent跳转
// 产出事件发送给迭代器
gen.Send(&adk.AgentEvent{/*填充事件内容*/})
}()
return iter
}
简单理解:gen 是「生产者」往里面塞事件,iter 是「消费者」外部循环读取,goroutine 实现异步不阻塞。
四、核心产出物:TypedAgentEvent / AgentEvent(运行全流程事件)
Run 流里每一条数据都是 Event,记录这一步发生了什么:
type TypedAgentEvent[M MessageType] struct {
AgentName string // 当前执行的Agent名字
RunPath []RunStep // 执行链路(记录走了哪些Agent、步骤,用于日志/追踪)
Output *TypedAgentOutput[M] // 本轮输出内容(文字/结构化消息)
Action *AgentAction // 协作控制信号:中断、跳转、退出循环
Err error // 运行报错
}
拆分两个重点子结构体:TypedAgentOutput、AgentAction
4.1 TypedAgentOutput:本次 Agent 输出内容
type TypedAgentOutput[M MessageType] struct {
MessageOutput *TypedMessageVariant[M] // 标准对话消息(文字、工具返回)
CustomizedOutput any // 自定义业务输出,任意类型结构体
}
- MessageOutput:标准聊天输出,最常用;
- CustomizedOutput:扩展字段,你可以塞自己业务数据(比如订单 ID、检索文档),框架不干涉。
TypedMessageVariant:统一兼容「流式 / 一次性」消息
type TypedMessageVariant[M MessageType] struct {
IsStreaming bool
Message M // 非流式完整消息
MessageStream *schema.StreamReader[M] // 流式分段数据流
Role schema.RoleType // 传统消息角色(assistant/tool)
AgenticRole schema.AgenticRoleType // 结构化消息专用角色
ToolName string
}
核心开关 IsStreaming:
- IsStreaming = false:一次性结果,直接读 Message 完整对话;
- IsStreaming = true:流式打字机效果,从 MessageStream 循环读取分段字符;
Role / AgenticRole 互斥: - 用 *schema.Message(默认 Agent)只看 Role、ToolName;
- 用 *schema.AgenticMessage 结构化消息只看 AgenticRole。
4.2 AgentAction:多 Agent 协作控制信号(调度指令)
决定Agent的行为动作的参数
Event 里的 Action 是用来控制整个智能体系统流转的,不需要返回消息,只发控制指令:
type AgentAction struct {
Exit bool // 整个多Agent系统直接结束
Interrupted *InterruptInfo // 暂停运行,保存状态,后续可以恢复Resume
TransferToAgent *TransferToAgentAction // 废弃方案:直接转让任务给其他Agent(不推荐)
BreakLoop *BreakLoopAction // 终止LoopAgent循环(循环思考智能体)
CustomizedAction any // 自定义控制信号
}
逐个解释场景:
- Exit = true:任务彻底完成,所有 Agent 全部停止;
- Interrupted:中途暂停(比如需要用户补充信息、人机交互),保存现场,外部拿到数据后可以恢复执行;
- BreakLoop:专门给循环 Agent(思考 - 工具调用循环)用,满足条件跳出循环;
- TransferToAgent(不推荐):旧方案硬编码跳转 Agent,官方推荐新方案:把其他 Agent 包装成工具 AgentAsTool,更规范、兼容框架调度;
- CustomizedAction:自定义控制逻辑,比如标记需要检索知识库、发起审批。
五、AgentRunOption:单次 Run 运行的临时配置
作用:每次调用 agent.Run() 可以传入可变参数,只对本次执行生效,不污染 Agent 全局配置。
5.1 框架内置通用 Option
- WithSessionValues(map[string]any)
多 Agent 共享上下文 KV 存储,所有 Agent 在同一次任务里都能读写这份数据(全局会话缓存); - WithCallbacks(…)
注册回调钩子,监听 Agent 生命周期事件(开始执行、输出消息、工具调用、报错); - WithCancel()
开启取消能力,ctx cancel 时可以中断 Agent 运行,配套 Loop 循环、中断恢复逻辑。
5.2 自定义业务 Option(重点实操)
框架支持给你的自定义 Agent 增加专属配置,示例:
运行
// 1. 定义自定义配置结构体
type myOptions struct {
modelName string
}
// 2. 包装成标准AgentRunOption构造函数
func WithModelName(name string) adk.AgentRunOption {
return adk.WrapImplSpecificOptFn(func(t *myOptions) {
t.modelName = name
})
}
在 Agent.Run 内部读取自定义配置:
运行
func (m *MyAgent) Run(ctx context.Context, input *adk.AgentInput, opts ...adk.AgentRunOption) *adk.AsyncIterator[*adk.AgentEvent] {
// 从opts列表中提取自定义配置
o := adk.GetImplSpecificOptions(&myOptions{}, opts...)
fmt.Println(o.modelName) // 使用本次传入的模型名称
}
5.3 DesignateAgent:给指定 Agent 单独生效的 Option
同一个多 Agent 系统里,多个 Agent 共享一组 opts 时,可以限定某条配置只给特定 Agent 生效:
运行
// 这个SessionKV配置只对name="agent_1"的Agent生效
opt := adk.WithSessionValues(map[string]any{"key": "val"}).DesignateAgent("agent_1")
六、全局语言设置 adk.SetLanguage
运行
adk.SetLanguage(adk.LanguageChinese) // 默认LanguageEnglish英文
- 作用:修改 Eino ADK内置组件自带提示词的语言,比如文件检索、总结、内置工具、ChatModelAgent 这些框架自带 Agent 的系统提示;
- 局限:只管框架内置提示词,你自己写的自定义 Instruction、提示词不会自动翻译,需要自己处理中英文;
- 使用时机:程序 main 初始化阶段一次性设置,全局生效。
七、整体的一套完整流程大致梳理
下面是一个大致的流程,并非详细:
- 程序启动 main:adk.SetLanguage(adk.LanguageChinese) 设置中文;
- 自定义智能体 MyAgent,实现 adk.Agent(TypedAgent [*schema.Message])接口;
- 实现 Name、Description;
- 实现 Run 方法,内部创建 AsyncIterator,goroutine 执行业务;
- 发起调用,组装输入:
运行
input := &adk.AgentInput{
Messages: []*schema.Message{用户提问+历史对话},
EnableStreaming: true,
}
// 传入通用+自定义配置
opts := []adk.AgentRunOption{
adk.WithSessionValues(map[string]any{"user_id": "123"}),
WithModelName("gpt-4o"),
}
// 启动Agent,拿到异步事件流
iter := myAgent.Run(ctx, input, opts...)
- 循环消费事件流:
- 收到 Event.Err:捕获异常;
- Event.Output.MessageOutput:读取大模型输出文字(流式 / 完整);
- Event.Action:判断是否中断、退出、跳出循环、切换 Agent;
- 全部事件读取完毕,迭代器关闭,本次 Agent 执行结束。
总的来说,上述内容讲的是Eino ADK 如何用一套统一 Go 泛型接口,标准化所有 AI 智能体的定义、入参、异步流式输出、多智能体协作控制、运行时配置,是开发 Go 版 LLM Agent 的底层基础规范。
更多推荐

所有评论(0)