第五章:Go语言大模型调用框架 - Eino (ADK多智能体编排)
·
1. 什么是ADK
ADK 是 Eino 框架中 adk 包提供的高层 Agent 开发工具包,全称 Agent Development Kit。它的定位很明确:让你用最少的代码构建多 Agent 协作系统。
在 ADK 出现之前,如果你想让多个 Agent 协作,得自己用 Graph 编排——定义节点、连边、写条件路由、处理数据传递。这种方式很灵活,但写起来啰嗦,而且多 Agent 协作有很多通用的模式(顺序执行、并行执行、循环迭代),每次都从头画 Graph 显然是重复劳动。
2. agent 调用示例
package main
import (
"context"
"fmt"
"io"
"github.com/cloudwego/eino-ext/components/model/openai"
"github.com/cloudwego/eino/adk"
"log"
)
func main() {
ctx := context.Background()
// 创建大模型实例
model, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
BaseURL: "https://api-inference.modelscope.cn/v1/",
APIKey: "xxx", // api_key
Model: "Qwen/Qwen3.5-35B-A3B",
})
if err != nil {
log.Fatalf("创建 ChatModel 失败: %v", err)
}
// 创建chatModelAgent
agent, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "translator",
Description: "一个专业的中英互译助手",
Instruction: "你是一个专业的{role}助手。用户发送{lang1}时翻译成{lang2},发送{lang2}时翻译成{lang1}。翻译要准确、自然、符合目标语言的表达习惯。",
Model: model,
})
if err != nil {
log.Fatalf("创建 ChatModelAgent 失败: %v", err)
}
// runner 运行
runner := adk.NewRunner(ctx, adk.RunnerConfig{
Agent: agent,
// 开启流式模式 EnableStreaming: true,
})
// 使用 Query 快捷方法发送问题
iter := runner.Query(ctx, "Go语言是世界上最好的编程语言。", adk.WithSessionValues(map[string]any{
"role": "翻译",
"lang1": "中文",
"lang2": "英语",
}))
for {
event, ok := iter.Next()
if !ok {
break
}
if event.Err != nil {
log.Fatalf("执行出错: %v", event.Err)
}
if event.Output != nil && event.Output.MessageOutput != nil {
mv := event.Output.MessageOutput
if mv.IsStreaming && mv.MessageStream != nil {
// 流式模式:从 MessageStream 逐块读取
for {
msg, err := mv.MessageStream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("读取流失败: %v", err)
}
fmt.Print(msg.Content)
}
} else if mv.Message != nil {
// 非流式模式:直接取完整消息
fmt.Print(mv.Message.Content)
}
}
}
fmt.Println()
}
3. 多智能体编排示例 (串式调用)
package main
import (
"context"
"fmt"
"github.com/cloudwego/eino-ext/components/model/openai"
"github.com/cloudwego/eino/adk"
"log"
)
// 多agent 应用示例
func main() {
ctx := context.Background()
// 创建大模型实例
model, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
BaseURL: "https://api-inference.modelscope.cn/v1/",
APIKey: "xxx", // api_key
Model: "Qwen/Qwen3.5-35B-A3B",
})
if err != nil {
log.Fatalf("创建 ChatModel 失败: %v", err)
}
// 创建agent
analyst, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "analyst",
Description: "分析文章质量问题的专家",
Instruction: `你是一个文章质量分析师。请仔细阅读用户提供的文章,从以下维度分析问题:
1. 逻辑结构是否清晰
2. 用词是否准确
3. 是否有语病或歧义
4. 表达是否简洁有力
请列出具体的问题清单,每个问题说明位置和改进建议。`,
Model: model,
})
if err != nil {
log.Fatal(err)
}
editor, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "editor",
Description: "文章编辑专家",
Instruction: `你是一个专业的文章编辑。你会收到一篇原文以及质量分析师的改进建议。
请根据这些建议对原文进行润色修改,输出修改后的完整文章。
修改时保持原文的核心意思不变,重点优化表达质量。`,
Model: model,
})
if err != nil {
log.Fatal(err)
}
// 用 SequentialAgent 把两个 Agent 串起来
agent, err := adk.NewSequentialAgent(ctx, &adk.SequentialAgentConfig{
Name: "article_polisher",
Description: "文章润色流水线",
SubAgents: []adk.Agent{analyst, editor},
})
if err != nil {
return
}
// 创建 Runner 运行整个流水线
runner := adk.NewRunner(ctx, adk.RunnerConfig{Agent: agent})
article := `Go语言是很好的语言。它的并发性能很强大。
goroutine让并发编程变得简单了很多。
而且Go的编译速度也很快,部署也方便,只需要一个二进制文件就行了。
总之Go是一门值得学习的语言。`
iter := runner.Query(ctx, "请帮我润色以下文章:\n\n"+article)
for {
event, ok := iter.Next()
if !ok {
break
}
if event.Err != nil {
log.Fatalf("执行出错: %v", event.Err)
}
if event.Output != nil && event.Output.MessageOutput != nil {
fmt.Printf("\n===== [%s] 输出 =====\n%s\n",
event.AgentName,
event.Output.MessageOutput.Message.Content)
}
}
}
4. 带工具的ChatModelAgent
package main
import (
"context"
"fmt"
"log"
"math"
"os"
"github.com/cloudwego/eino-ext/components/model/openai"
"github.com/cloudwego/eino/adk"
"github.com/cloudwego/eino/components/tool"
"github.com/cloudwego/eino/components/tool/utils"
"github.com/cloudwego/eino/compose"
)
// 计算器工具的参数
type CalcParams struct {
Operation string `json:"operation" jsonschema:"description=运算类型,必须是以下之一: add(加法) sub(减法) mul(乘法) div(除法) sqrt(开方) pow(幂运算),required"`
A float64 `json:"a" jsonschema:"description=第一个操作数,required"`
B float64 `json:"b" jsonschema:"description=第二个操作数(sqrt时可省略)"`
}
// 计算器工具函数
func calculate(ctx context.Context, params *CalcParams) (string, error) {
var result float64
switch params.Operation {
case "add":
result = params.A + params.B
case "sub":
result = params.A - params.B
case "mul":
result = params.A * params.B
case "div":
if params.B == 0 {
return "错误:除数不能为零", nil
}
result = params.A / params.B
case "sqrt":
result = math.Sqrt(params.A)
case "pow":
result = math.Pow(params.A, params.B)
default:
return fmt.Sprintf("不支持的运算类型: %s", params.Operation), nil
}
return fmt.Sprintf("计算结果: %.4f", result), nil
}
func main() {
ctx := context.Background()
chatModel, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
BaseURL: "https://api-inference.modelscope.cn/v1/",
APIKey: "xxx", // api_key
Model: "Qwen/Qwen3.5-35B-A3B",
})
if err != nil {
log.Fatal(err)
}
// 创建工具
calcTool, err := utils.InferTool(
"calculator",
"数学计算器,支持加减乘除、开方、幂运算。必须指定 operation 和操作数",
calculate,
)
if err != nil {
log.Fatal(err)
}
// 创建带工具的 ChatModelAgent
agent, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "math_assistant",
Description: "一个数学计算助手,能够进行各种数学运算",
Instruction: "你是一个数学助手。当用户提出数学计算问题时,使用 calculator 工具进行精确计算,不要自己心算。",
Model: chatModel,
ToolsConfig: adk.ToolsConfig{
ToolsNodeConfig: compose.ToolsNodeConfig{
Tools: []tool.BaseTool{calcTool},
},
},
})
if err != nil {
log.Fatal(err)
}
runner := adk.NewRunner(ctx, adk.RunnerConfig{Agent: agent})
iter := runner.Query(ctx, "请帮我计算:(15.7 + 3.3) 的平方根,然后再乘以 2.5")
for {
event, ok := iter.Next()
if !ok {
break
}
if event.Err != nil {
log.Fatal(event.Err)
}
// 打印 Agent 名称和输出
if event.Output != nil && event.Output.MessageOutput != nil {
fmt.Printf("[%s] %s\n", event.AgentName, event.Output.MessageOutput.Message.Content)
}
}
}
5. 并行执行多个agent
package main
import (
"context"
"fmt"
"github.com/cloudwego/eino-ext/components/model/openai"
"github.com/cloudwego/eino/adk"
"io"
"log"
)
func main() {
ctx := context.Background()
// 创建大模型基础
model, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
BaseURL: "https://api-inference.modelscope.cn/v1/",
APIKey: "xxxx", // api_key
Model: "Qwen/Qwen3.5-35B-A3B",
})
if err != nil {
log.Fatalf("创建 ChatModel 失败: %v", err)
}
// Agent 1:性能分析师
performanceAnalyst, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "performance_analyst",
Description: "性能分析师",
Instruction: "你是一个专业的性能分析师。请根据用户提供的性能测试报告,分析性能瓶颈,并给出改进建议。",
Model: model,
})
if err != nil {
log.Fatal(err)
}
// Agent 2: 安全分析师
securityAnalyst, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "security_analyst",
Description: "安全分析师",
Instruction: "你是一个专业的安全分析师。请根据用户提供的安全测试报告,分析安全风险,并给出改进建议。",
Model: model,
})
if err != nil {
log.Fatal(err)
}
// Agent 3: 可维护性分析师
maintainabilityAnalyst, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "maintainability_analyst",
Description: "可维护性分析师",
Instruction: "你是一个专业的可维护性分析师。请根据用户提供的代码,分析代码可维护性,并给出改进建议。",
Model: model,
})
if err != nil {
log.Fatal(err)
}
// 用 ParallelAgent 让三个分析师同时工作
multiAnalyzer, err := adk.NewParallelAgent(ctx, &adk.ParallelAgentConfig{
Name: "multi_analyzer",
Description: "多视角技术方案分析器",
SubAgents: []adk.Agent{performanceAnalyst, securityAnalyst, maintainabilityAnalyst},
})
if err != nil {
return
}
runner := adk.NewRunner(ctx, adk.RunnerConfig{
Agent: multiAnalyzer,
EnableStreaming: true, // 开启流模式
})
iter := runner.Query(ctx, "我计划用 Redis 作为用户Session的存储方案,替代当前的基于Cookie的方案。请分析这个方案。")
for {
event, ok := iter.Next()
if !ok {
break
}
if event.Err != nil {
log.Fatalf("执行出错: %v", event.Err)
}
if event.Output != nil && event.Output.MessageOutput != nil {
/*fmt.Printf("\n===== [%s] 分析 =====\n%s\n",
event.AgentName,
event.Output.MessageOutput.Message.Content)*/
// 使用流式输出
mv := event.Output.MessageOutput
if mv.IsStreaming && mv.MessageStream != nil {
for {
msg, err := mv.MessageStream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("读取流失败: %v", err)
}
fmt.Print(msg.Content)
}
}
}
}
fmt.Println("执行完成")
}
6. LoopAgeng 循环编排
LoopAgent 即循环编排,让子 Agent 反复执行,直到某个退出条件被满足或者达到最大迭代次数。这在需要"迭代优化"的场景下非常有用——比如让 Agent 反复审核和修改内容,直到质量达标。
package main
import (
"context"
"fmt"
"github.com/cloudwego/eino-ext/components/model/openai"
"github.com/cloudwego/eino/adk"
"log"
)
// 循环调用
func main() {
ctx := context.Background()
// 模型
model, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
BaseURL: "https://api-inference.modelscope.cn/v1/",
APIKey: "xxx", // api_key
Model: "Qwen/Qwen3.5-35B-A3B",
})
if err != nil {
log.Fatalf("创建 ChatModel 失败: %v", err)
}
// Agent 1:代码生成/修改者
codeGenerator, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "generator",
Description: "根据需求编写或修改Go代码",
Instruction: `你是一个Go开发者。
- 如果是第一次收到需求,请编写完整的Go代码实现
- 如果收到了代码审核意见,请根据意见修改代码并输出修改后的完整代码
- 只输出代码和简要说明,不要输出无关内容`,
Model: model,
})
if err != nil {
log.Fatal(err)
}
// Agent 2:代码审核者
codeReviewer, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "reviewer",
Description: "审核Go代码质量",
Instruction: `你是一个严格的Go代码审核专家。请审核代码的以下方面:
1. 错误处理是否完善
2. 是否有潜在的并发安全问题
3. 命名是否规范
4. 代码是否简洁高效
如果代码质量合格,请回复"APPROVED: "加上审核通过的理由。
如果不合格,请列出具体问题和修改建议。`,
Model: model,
})
if err != nil {
log.Fatal(err)
}
oneRound, err := adk.NewSequentialAgent(ctx, &adk.SequentialAgentConfig{
Name: "code_generator_reviewer",
Description: "代码生成/修改/审核流水线",
SubAgents: []adk.Agent{codeGenerator, codeReviewer},
})
if err != nil {
log.Fatal(err)
}
// 用 LoopAgent 循环执行,最多迭代 3 次
loopAgent, err := adk.NewLoopAgent(ctx, &adk.LoopAgentConfig{
Name: "code_generator_reviewer_loop",
Description: "代码生成/修改/审核流水线循环执行",
SubAgents: []adk.Agent{oneRound},
MaxIterations: 3,
})
if err != nil {
log.Fatal(err)
}
runner := adk.NewRunner(ctx, adk.RunnerConfig{Agent: loopAgent})
iter := runner.Query(ctx, "请用Go写一个线程安全的LRU Cache,支持Get和Put操作,容量为构造参数")
round := 0
for {
event, ok := iter.Next()
if !ok {
break
}
if event.Err != nil {
log.Fatalf("执行出错: %v", event.Err)
}
if event.Output != nil && event.Output.MessageOutput != nil {
if event.AgentName == "reviewer" {
round++
fmt.Printf("\n===== 第 %d 轮审核 [%s] =====\n", round, event.AgentName)
} else {
fmt.Printf("\n===== [%s] =====\n", event.AgentName)
}
fmt.Println(event.Output.MessageOutput.Message.Content)
}
}
}
7. TooAgent 工具委派
ADK 提供了一个非常强大的能力:通过 adk.NewAgentTool 把一个 Agent 包装成 Tool,然后绑定到另一个 Agent 上。这意味着上层 Agent 可以像调用普通工具一样"委派"任务给下层 Agent——上层 Agent 决定什么时候需要委派、委派什么任务,下层 Agent 负责具体执行。
package main
import (
"context"
"fmt"
"github.com/cloudwego/eino-ext/components/model/openai"
"github.com/cloudwego/eino/adk"
"github.com/cloudwego/eino/components/tool"
"github.com/cloudwego/eino/compose"
"io"
"log"
)
func main() {
ctx := context.Background()
// 创建大模型基础
model, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
BaseURL: "https://api-inference.modelscope.cn/v1/",
APIKey: "xxx", // api_key
Model: "Qwen/Qwen3.5-35B-A3B",
})
if err != nil {
log.Fatalf("创建 ChatModel 失败: %v", err)
}
// 创建子agent 1: 翻译专家
trnslator, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "translator",
Description: "将文本翻译成指定语言。输入格式:目标语言|待翻译文本",
Instruction: "你是一个翻译专家。用户会发送'目标语言|文本'格式的内容,请将文本翻译成指定语言。只输出翻译结果,不要输出其他内容。",
Model: model,
})
if err != nil {
return
}
// 创建子agent2: 文案写手
copywriter, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "copywriter",
Description: "根据主题和风格要求撰写营销文案",
Instruction: "你是一个创意文案写手。根据用户给出的主题和风格要求,撰写简短有力的营销文案。",
Model: model,
})
if err != nil {
return
}
// 把子 Agent 包装成 Tool
translatorTool := adk.NewAgentTool(ctx, trnslator)
copywriterTool := adk.NewAgentTool(ctx, copywriter)
// 主 Agent:项目经理,根据需求委派任务给不同的子 Agent
manager, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "manager",
Description: "任务调度经理",
Instruction: `你是一个项目经理。用户会提出各种内容创作需求。
你手下有两个专家:
- translator:翻译专家,负责翻译任务
- copywriter:文案写手,负责撰写营销文案
请根据用户需求判断应该委派给哪个专家,并将任务分发出去。
如果需求涉及多个专家,请分别调用。`,
Model: model,
ToolsConfig: adk.ToolsConfig{
ToolsNodeConfig: compose.ToolsNodeConfig{
Tools: []tool.BaseTool{translatorTool, copywriterTool},
},
},
})
if err != nil {
log.Fatalf("创建 Agent 失败: %v", err)
}
runner := adk.NewRunner(ctx, adk.RunnerConfig{
Agent: manager,
EnableStreaming: true,
})
results := runner.Query(ctx, "请帮我写一段关于'Go语言云原生开发'的营销文案,然后把它翻译成英文")
for {
event, ok := results.Next()
if !ok {
break
}
if event.Err != nil {
log.Fatalf("执行出错: %v", event.Err)
}
/*if event.Output != nil && event.Output.MessageOutput != nil {
fmt.Printf("[%s] %s\n\n", event.AgentName, event.Output.MessageOutput.Message.Content)
}*/
mv := event.Output.MessageOutput
if mv.IsStreaming && mv.MessageStream != nil {
for {
rec, err := mv.MessageStream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("读取流失败: %v", err)
}
fmt.Print(rec.Content)
}
}
}
fmt.Println("执行完成")
}
8. 结合之前的示例,进行汇总
通过三个专家评审Agent并行执行,得到不同的评审结果,然后进行汇总,最终得到一份完整的评审报告。
package main
import (
"context"
"fmt"
"github.com/cloudwego/eino-ext/components/model/openai"
"github.com/cloudwego/eino/adk"
"log"
)
func main() {
ctx := context.Background()
chatModel, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
BaseURL: "https://api-inference.modelscope.cn/v1/",
APIKey: "xxxx", //api_key
Model: "Qwen/Qwen3.5-35B-A3B",
})
if err != nil {
log.Fatal(err)
}
// ===== 第一阶段:三个并行分析师 =====
perfAgent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "perf_reviewer",
Description: "性能评审专家",
Instruction: `你是性能评审专家。请从性能维度评审用户提出的技术方案,输出格式:
【性能评分】1-10分
【核心发现】列出2-3个关键点
【改进建议】如有性能风险,给出具体建议`,
Model: chatModel,
})
secAgent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "sec_reviewer",
Description: "安全评审专家",
Instruction: `你是安全评审专家。请从安全维度评审用户提出的技术方案,输出格式:
【安全评分】1-10分
【核心发现】列出2-3个关键点
【改进建议】如有安全风险,给出具体建议`,
Model: chatModel,
})
costAgent, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "cost_reviewer",
Description: "成本评审专家",
Instruction: `你是成本评审专家。请从成本维度评审用户提出的技术方案,输出格式:
【成本评分】1-10分
【核心发现】列出2-3个关键点
【改进建议】如有成本优化空间,给出具体建议`,
Model: chatModel,
})
// 并行执行三个评审
parallelReview, _ := adk.NewParallelAgent(ctx, &adk.ParallelAgentConfig{
Name: "parallel_review",
Description: "并行技术评审",
SubAgents: []adk.Agent{perfAgent, secAgent, costAgent},
})
// ===== 第二阶段:综合汇总 =====
summarizer, _ := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "summarizer",
Description: "评审报告汇总专家",
Instruction: `你是技术评审委员会主席。你会收到三位专家(性能、安全、成本)的独立评审意见。
请综合所有评审意见,生成一份结构化的最终评审报告,格式如下:
# 技术方案评审报告
## 综合评分
(三个维度的加权平均,权重:性能40%、安全35%、成本25%)
## 各维度概要
(简要汇总每个维度的核心发现)
## 关键风险
(列出最需要关注的风险项)
## 最终结论
(通过/有条件通过/不通过,并说明理由)
## 行动项
(按优先级列出需要落实的改进项)`,
Model: chatModel,
})
// ===== 组装完整流水线 =====
fullPipeline, _ := adk.NewSequentialAgent(ctx, &adk.SequentialAgentConfig{
Name: "tech_review_system",
Description: "完整技术方案评审系统",
SubAgents: []adk.Agent{parallelReview, summarizer},
})
// ===== 运行 =====
runner := adk.NewRunner(ctx, adk.RunnerConfig{Agent: fullPipeline})
proposal := `技术方案:将公司核心交易系统从单体架构迁移到微服务架构
关键设计决策:
1. 使用 Kubernetes 作为容器编排平台
2. 服务间通信采用 gRPC + Protobuf
3. 数据库从单一 MySQL 拆分为每个服务独立的数据库(Database per Service)
4. 引入 Apache Kafka 作为异步消息队列
5. 使用 Istio 服务网格处理流量治理
6. API Gateway 使用 Kong
预计影响范围:核心交易链路、用户中心、库存管理、支付系统`
iter := runner.Query(ctx, "请评审以下技术方案:\n\n"+proposal)
for {
event, ok := iter.Next()
if !ok {
break
}
if event.Err != nil {
log.Fatal(event.Err)
}
if event.Output != nil && event.Output.MessageOutput != nil {
fmt.Printf("\n========== [%s] ==========\n%s\n",
event.AgentName,
event.Output.MessageOutput.Message.Content)
}
}
}
来源于: 秀才的进阶之路
更多推荐



所有评论(0)