12 · Eino:Go 语言里最完整的 Agent 框架
| 仓库 | cloudwego/eino |
| Star | 12.7k |
| 版本 | v0.9.15(v0.10 alpha 开发中) |
| 语言 | Go(1.18+,重度依赖泛型) |
| 许可证 | Apache 2.0 |
| 出品 | 字节跳动 CloudWeGo |
| 层级 | Framework + 内建 Runtime 能力 |
| 一句话 | 借鉴 LangChain 和 Google ADK,但按 Go 的方式重做一遍 —— 编译期类型安全是它最大的不同 |

图片来源:cloudwego/eino
一、Go 团队为什么需要它
大量高并发后端服务是 Go 写的。把 Agent 能力塞进去,之前只有两条路:裸调 HTTP API 自己写循环,或者起个 Python 服务做跨语言调用。Eino 提供了第三条:在 Go 里用和 LangChain 同级别的抽象。
Go 生态的可选项:
| 选项 | Star | 评价 |
|---|---|---|
| Eino | 12.7k | 最完整,有 ADK、DeepAgent、Graph、HITL |
| ADK Go | 8.7k | Google 官方,和 ADK Python 概念一致 |
| 裸 SDK + 手写循环 | —— | 简单场景够用 |
二、最快的路径:ChatModelAgent
// ① 造一个 ChatModel 组件。换供应商就换这个构造函数(claude / gemini / ark / ollama…),
// 后面的代码一个字都不用改 —— 这是 Eino 组件抽象的意义
chatModel, _ := openai.NewChatModel(ctx, &openai.ChatModelConfig{
Model: "gpt-4o",
APIKey: os.Getenv("OPENAI_API_KEY"),
})
// ② 包成一个 Agent。ReAct 循环(要不要调工具、什么时候收尾)在内部处理
agent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Model: chatModel,
})
// ③ Runner 负责执行。Query 返回一个迭代器,而不是一次性结果
runner := adk.NewRunner(ctx, adk.RunnerConfig{Agent: agent})
iter := runner.Query(ctx, "Hello, who are you?")
for {
event, ok := iter.Next() // 每次拿一个事件:模型说话、调工具、工具返回……
if !ok { // ok == false 表示流结束
break
}
fmt.Println(event.Message.Content)
}
加工具:
agent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Model: chatModel,
// 嵌套两层是因为工具在底层其实是编排图里的一个「工具节点」,
// adk 只是把 compose 层的配置透传下去。写起来啰嗦,但两层是同一套东西
ToolsConfig: adk.ToolsConfig{
ToolsNodeConfig: compose.ToolsNodeConfig{
Tools: []tool.BaseTool{weatherTool, calculatorTool},
},
},
})
ReAct 循环在内部处理 —— 什么时候调工具、什么时候回答,由 Agent 自己决定。

图片来源:cloudwego/eino
三、DeepAgent:Go 世界里的 Harness
Eino 内建了 DeepAgent —— 本专题里除 DeepAgents 和 Claude Agent SDK 之外,唯一自带 Harness 层的框架,也是唯一的 Go 实现:
deepAgent, _ := deep.New(ctx, &deep.Config{
ChatModel: chatModel,
// 子 Agent:主 Agent 会把子任务派给它们,各自在独立上下文里干活
SubAgents: []adk.Agent{researchAgent, codeAgent},
ToolsConfig: adk.ToolsConfig{
ToolsNodeConfig: compose.ToolsNodeConfig{
// shell / python / 搜索三件套 —— 长任务型 Agent 的标配
Tools: []tool.BaseTool{shellTool, pythonTool, webSearchTool},
},
},
})
// 用法和普通 Agent 完全一样,区别在于它会先拆解任务、列计划、再逐步执行
runner := adk.NewRunner(ctx, adk.RunnerConfig{Agent: deepAgent})
iter := runner.Query(ctx, "Analyze the sales data in report.csv and generate a summary chart")
它会拆解问题、委派子 Agent、跟踪进度,并能跑 shell、执行 Python、搜网页。能力对标 DeepAgents,语言是 Go。
四、Composition:编译期类型安全的图
需要精确控制流程时,用 compose 建图:
// 泛型参数把整张图的输入 / 输出类型钉死。节点之间类型对不上 → 编译不过,
// 而不是等到运行时第 40 分钟才炸 —— 这是 Eino 相对 Python 框架最大的不同
graph := compose.NewGraph[*Input, *Output]()
// 三种节点:Lambda 是你自己的 Go 函数,ChatModel 是模型调用,
// 另外还有 ToolsNode、Retriever、Embedding 等组件节点
graph.AddLambdaNode("validate", validateFn) // 确定性代码:先校验
graph.AddChatModelNode("generate", chatModel) // 交给模型
graph.AddLambdaNode("format", formatFn) // 确定性代码:整理输出
// 连边,START / END 是框架内置的起止哨兵
graph.AddEdge(compose.START, "validate")
graph.AddEdge("validate", "generate")
graph.AddEdge("generate", "format")
graph.AddEdge("format", compose.END)
runnable, _ := graph.Compile(ctx) // 编译:这一步会做完整的类型和结构校验
result, _ := runnable.Invoke(ctx, input) // 执行

图片来源:cloudwego/eino
这是 Eino 相对 Python 框架最大的差异
compose.NewGraph[*Input, *Output]() 这个泛型签名意味着:节点之间类型对不上,编译不过。
| Eino(Go 泛型) | LangGraph(Python) | |
|---|---|---|
| 类型检查 | 编译期 | 运行时(TypedDict 只是提示) |
| 节点接错类型 | 编译报错 | 跑到那一步才炸 |
| 重构 | 编译器帮你找全所有影响点 | 靠测试和运气 |
| 代价 | 泛型签名啰嗦,灵活度低 | 写起来快 |
对生产系统来说,「跑到第 40 分钟才发现节点类型对不上」和「编译时就报错」,差的不是一点半点。 这是静态语言在 Agent 编排上的真实优势。
图可以变成工具
// 把上面那张确定性的图,包装成一个「工具」。
// 后两个参数是工具名和描述 —— 模型就靠这段描述决定什么时候用它
tool, _ := graphtool.NewInvokableGraphTool(graph, "data_pipeline", "Process and validate data")
agent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Model: chatModel,
ToolsConfig: adk.ToolsConfig{
ToolsNodeConfig: compose.ToolsNodeConfig{Tools: []tool.BaseTool{tool}},
},
})
// 效果:流水线内部 100% 确定可控(还有编译期类型保证),
// 而「什么时候跑这条流水线」交给模型判断 —— 混合控制的一种优雅写法
这一步很关键:把确定性流程封装成图,再作为工具交给自主 Agent,由模型决定什么时候用。这正是 01 D2 维度 说的「混合控制」的一种优雅实现 —— 确定性的部分完全可控,不确定的部分交给模型决定调不调用。
五、流式处理:框架替你处理拼接与复制
这是 Eino 一个很务实的设计:编排过程中的流处理由框架自动完成 —— 流的拼接(concatenate)、装箱(boxing)、合并(merge)、复制(copy),在节点之间传数据时自动做。

图片来源:cloudwego/eino
组件只需要实现对自己有意义的流式范式,其余框架兜底。 比如一个 Retriever 不需要支持流式输入,框架会自动把上游的流拼成完整值再喂给它。
在 Go 里手写这套(channel 的扇出、复制、生命周期管理)是很容易出 bug 的活,框架接管掉是实实在在的价值。
六、Callback 切面
在固定切点注入日志、tracing、metrics:
| 切点 | 时机 |
|---|---|
OnStart | 组件开始 |
OnEnd | 组件结束 |
OnError | 出错 |
OnStartWithStreamInput | 流式输入开始 |
OnEndWithStreamOutput | 流式输出结束 |
作用范围覆盖 components、graphs、agents。这是 Go 版的「中间件」 —— 对照 LangChain Middleware 和 Spring AI Advisors,三家解决的是同一个问题。
七、Interrupt / Resume
任何 agent 或 tool 都能暂停执行等待人工输入,并从检查点恢复。框架处理状态持久化和路由。
这个能力对齐了 LangGraph 的 interrupt,在 Go 生态里是独一份。对照 01 D6 维度,属于最强的那一档(状态落盘、可跨进程恢复)。
八、项目结构与生态

图片来源:cloudwego/eino
| 仓库 | 内容 |
|---|---|
| eino | 类型定义、流式机制、组件抽象、编排、Agent 实现、切面机制 |
| eino-ext | 组件实现、callback handler、评测器、提示词优化器 |
| eino-ext/devops | 可视化开发与调试 |
| eino-examples | 示例应用与最佳实践 |
组件实现覆盖 OpenAI、Claude、Gemini、Ark(火山方舟)、Ollama、Elasticsearch 等。
九、需要清楚的短板
| 短板 | 说明 |
|---|---|
| 版本仍是 0.x | v0.9.15,API 可能变;生产要锁版本 |
| 生态规模 | eino-ext 799 star,集成数量远不及 LangChain |
| 英文社区薄 | 文档中文更全,用户群在飞书;国际社区活跃 度有限 |
| 泛型样板代码 | compose.NewGraph[*Input, *Output]() 这类签名在复杂图里会变长 |
| Harness 层新 | DeepAgent 是新加的,成熟度不及 DeepAgents |
| 火山系倾向 | 组件里字节 / 火山引擎的集成最完整,其他家看情况 |
十、什么时候用 / 什么时候别用
用它,如果
- 后端主体是 Go —— 这一条基本就决定了
- 要把 Agent 塞进高并发 Go 服务 —— 不用为此引入 Python 运行时
- 看重编译期类型安全 —— 这是它相对所有 Python 框架的结构性优势
- 需要 Go 里的 HITL / 断点续跑 —— 目前 Go 生态唯一成熟的实现
- 在字节 / 火山引擎生态里 —— Ark 集成最完整
别用它,如果
- 团队是 Python / Java —— 没理由为框架换语言
- 需要最广的第三方集成 —— 差距是数量级的
- 需要 API 长期稳定 —— 0.x 版本号是 个诚实的信号
- 依赖英文社区支持 —— 遇到问题主要靠读源码和中文文档
十一、Eino 与 ADK Go 怎么选
| Eino | ADK Go | |
|---|---|---|
| Star | 12.7k | 8.7k |
| 出品 | 字节 CloudWeGo | |
| 特色 | 泛型类型安全编排、自动流处理、DeepAgent | 与 ADK Python 概念一致、A2A、Agent Engine 部署 |
| 适合 | 通用 Go 后端,尤其国内 | 已在 GCP / 已用 ADK Python 的团队 |
多语言一致性重要就选 ADK Go,Go 侧工程质量和本地化支持重要就选 Eino。