使用 Eino ADK 调用 DeepSeek 大模型

1
2
1、Eino ADK Agent 工具调用
2、大模型流式输出

安装框架依赖

Eino 框架 0.5.0 版本才正式支持 ADK 功能、所以先要升级为最新的框架版本

1
go get -v -u github.com/cloudwego/eino@latest

Eino ADK 介绍

Eino ADK(Agent Development Kit) 参考 Google-ADK 设计的智能体开发套件;
提供了 Go 语言 Agent 开发灵活的组合框架、支持 Agent、Multi-Agent 功能,并为多个Agent交互场景沉淀了通用的上下文传递、事件流分发和转换、任务控制权转让、中断与恢复、通用切片等能力;

Eino ADK的核心特点

1
2
3
4
5
6
1、灵活的Agent抽象:支持 ChatModel Agent、Workflow Agent 等多种 Agent 类型;
2、多Agent协作:支持 Sequential、Loop、Parallel 等多种工作流模式;
3、任务控制权转让:Agent之间可以动态转让任务;
4、中断与恢复:支持 CheckPoint 机制、实现任务中断与恢复;
5、时间流处理:提供异步的事件流处理,支持流式输出;
6、通用切片能力:支持 Callback、监控等切面功能;

Eino ADK的应用场景

1
2
3
4
1、只能助手和客服系统:客服系统和智能助手;
2、工作流系统:可以实现多步骤、多Agent协作的复杂任务;
3、任务规划和执行:Plan-Execute-Replan 模式的任务处理;
4、多Agent系统:Supervisor Agent 管理多个子Agent;

Eino ADK支持的Agent类型

1
2
3
4
1、ChatModelAgent:基于 ChatModel 的 Agent,支持工具调用;
2、SequentialAgent:顺序执行多个子Agent;
3、LoopAgent:循环执行多个子Agent、支持迭代优化;
4、Plan-Execute Agent:并行执行多个子Agent;

使用 Eino ADK 调用大模型实例

安装框架组件依赖
1
2
3
4
5
6
7
go get github.com/joho/godotenv
go get github.com/cloudwego/eino/adk
go get github.com/cloudwego/eino/schema
go get github.com/cloudwego/eino/compose
go get github.com/cloudwego/eino/components/tool
go get github.com/cloudwego/eino/components/tool/utils
go get github.com/cloudwego/eino-ext/components/model/deepseek
Eino ADK 调用 DeepSeek 配置
1
2
3
4
# .env
DEEPSEEK_API_KEY="sk-d840add2ae604c33ad350781f24fddf0"
DEEPSEEK_BASE_URL="https://api.deepseek.com"
DEEPSEEK_MODEL="deepseek-v4-pro"
完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// @package    : main
// @file : main.go
// @author : hqd8080
// @contact : hanquanding@163.com
// @time : 2025/9/27
// @description: main

package main

import (
"context"
"fmt"
"io"
"log"
"os"
"time"

"github.com/cloudwego/eino-ext/components/model/deepseek"
"github.com/cloudwego/eino/adk"
"github.com/cloudwego/eino/components/tool"
"github.com/cloudwego/eino/components/tool/utils"
"github.com/cloudwego/eino/compose"
"github.com/cloudwego/eino/schema"
"github.com/joho/godotenv"
)

func main() {
// 加载环境变量
if err := godotenv.Load(".env"); err != nil {
panic(err)
}

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// 初始化模型、工具、Agent 和 Runner
chatModel, err := deepseek.NewChatModel(ctx, &deepseek.ChatModelConfig{
APIKey: os.Getenv("DEEPSEEK_API_KEY"),
BaseURL: os.Getenv("DEEPSEEK_BASE_URL"),
Model: os.Getenv("DEEPSEEK_MODEL"),
})
if err != nil {
log.Fatalf("newChatModel err: %v", err)
}

timeTool := utils.NewTool(
&schema.ToolInfo{
Name: "get_current_time",
Desc: "获取服务器当前时间",
ParamsOneOf: schema.NewParamsOneOfByParams(map[string]*schema.ParameterInfo{}),
},
func(ctx context.Context, params map[string]any) (string, error) {
return time.Now().Format(time.DateTime), nil
},
)

agent, err := adk.NewChatModelAgent(ctx, &adk.ChatModelAgentConfig{
Name: "hqd8080",
Description: "你是一位友好的 AI 助手",
Instruction: "你是一位人工智能助手,请用简洁明了的方式回答问题",
Model: chatModel,
ToolsConfig: adk.ToolsConfig{
ToolsNodeConfig: compose.ToolsNodeConfig{
Tools: []tool.BaseTool{timeTool},
},
},
MaxIterations: 10, // 最多执行 10 次工具函数调用
})
if err != nil {
log.Fatalf("newChatModelAgent err:%v", err)
}

runner := adk.NewRunner(ctx, adk.RunnerConfig{
Agent: agent,
EnableStreaming: true, // 流式输出
})

query := "你好,请介绍一下 deepseek!、现在几点了?"

contentCh := make(chan string)
errCh := make(chan error)

// 启动一个 goroutine 执行查询与流处理
go func() {
// 确保 goroutine 退出时关闭所有 channel 通知主 goroutine 结束
defer close(contentCh)
defer close(errCh)

iter := runner.Query(ctx, query)
for {
event, ok := iter.Next()
if !ok {
break // 所有事件已处理完毕
}
if event.Err != nil {
// 发生错误时通过 errCh 传递,并终止 goroutine
errCh <- event.Err
return
}

// 处理流式输出
if event.Output != nil && event.Output.MessageOutput != nil {
if event.Output.MessageOutput.IsStreaming {
stream := event.Output.MessageOutput.MessageStream
for {
msg, err := stream.Recv()
if err != nil {
if err == io.EOF {
break // 当前流结束
}
// 流读取错误也通过 errCh 传递
errCh <- fmt.Errorf("failed to recv message: %w", err)
return
}
if msg != nil && msg.Content != "" {
// 将内容片段发送到 contentCh
contentCh <- msg.Content
}
}
}
}
}
}()

// 主 goroutine 负责消费 channel 并输出结果
for {
select {
case content, ok := <-contentCh:
if !ok {
// contentCh 已关闭,检查是否有未处理的错误
err, ok := <-errCh
if ok && err != nil {
log.Fatalf("query err: %v", err)
}
return // 正常结束
}
fmt.Print(content)
case err, ok := <-errCh:
if ok && err != nil {
// 收到错误立即终止
log.Fatalf("query err: %v", err)
}
}
}
}