TL;DR: Eino 是 Go 版的 LangChain。本文介绍
ChatModel.Generate()非流式调用和ChatModel.Stream()流式调用,以及如何通过schema.Message构建多轮对话。
Eino - 字节跳动 CloudWeGo 团队开源的 Go 语言 AI 应用开发框架。
- GitHub: github.com/cloudwego/e...
- 适用版本:Go 1.21+
环境准备
1. Go 版本要求
bash
go version # 需要 Go 1.21+
2. 创建项目
bash
mkdir ai-agent-go && cd ai-agent-go
go mod init ai-agent-go
3. 安装依赖
bash
# Eino 核心包
go get github.com/cloudwego/eino@latest
# 火山引擎豆包模型(国内推荐)
go get github.com/cloudwego/eino-ext/components/model/ark@latest
# 自动加载 .env 文件
go get github.com/joho/godotenv@latest
4. 获取 API Key
本文使用火山引擎豆包(字节跳动的大模型服务),Eino 原生支持,国内访问稳定。
- 访问 火山引擎控制台
- 创建推理接入点(Endpoint)
- 获取 API Key
5. 配置环境变量
在项目根目录创建 .env 文件:
bash
ARK_API_KEY=你的API密钥
ARK_MODEL_ID=ep-xxxxxxxx
⚠️ 记得把
.env加入.gitignore,避免泄露密钥!
Hello Eino:第一次调用大模型
最简代码
创建文件 cmd/01_hello_llm/main.go:
go
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/cloudwego/eino-ext/components/model/ark"
"github.com/cloudwego/eino/schema"
"github.com/joho/godotenv"
)
func init() {
godotenv.Load() // 自动加载 .env 文件
}
func main() {
ctx := context.Background()
// 1. 创建 ChatModel
chatModel, err := ark.NewChatModel(ctx, &ark.ChatModelConfig{
APIKey: os.Getenv("ARK_API_KEY"),
Model: os.Getenv("ARK_MODEL_ID"),
})
if err != nil {
log.Fatalf("创建ChatModel失败: %v", err)
}
// 2. 准备消息
messages := []*schema.Message{
{
Role: schema.User,
Content: "你好!请用一句话介绍什么是AI Agent",
},
}
// 3. 生成回复
response, err := chatModel.Generate(ctx, messages)
if err != nil {
log.Fatalf("生成失败: %v", err)
}
fmt.Println("🤖 AI回复:", response.Content)
}
运行:
bash
go run cmd/01_hello_llm/main.go
消息格式
Eino 使用 schema.Message 表示消息,这是与大模型交互的基本单位:
go
// 四种消息角色
schema.System // 系统提示(设定 AI 的行为)
schema.User // 用户输入
schema.Assistant // AI 回复
schema.Tool // 工具返回结果
// 便捷创建方法
schema.SystemMessage("你是一个助手")
schema.UserMessage("你好")
schema.AssistantMessage("你好!有什么可以帮你的?", nil)
带 System 提示的对话
System 消息用于设定 AI 的角色和行为:
go
messages := []*schema.Message{
schema.SystemMessage("你是一个专业的Go语言专家,回答要简洁专业"),
schema.UserMessage("Go的goroutine和线程有什么区别?"),
}
// 使用 Option 调整模型参数
response, err := chatModel.Generate(ctx, messages,
model.WithTemperature(0.7), // 创造性程度(0-1)
model.WithMaxTokens(500), // 最大输出长度
)
流式输出
Stream() 方法实现边生成边返回,适合聊天界面:
go
// 使用 Stream 方法
streamReader, err := chatModel.Stream(ctx, messages)
if err != nil {
log.Fatal(err)
}
defer streamReader.Close()
fmt.Print("🤖 AI: ")
for {
chunk, err := streamReader.Recv()
if err == io.EOF {
break // 流结束
}
if err != nil {
log.Fatal(err)
}
fmt.Print(chunk.Content) // 实时输出每个字
}
fmt.Println()
多轮对话
关键:每次调用时传入完整的对话历史。
go
// 对话历史
history := []*schema.Message{
schema.SystemMessage("你是一个友好的AI助手,会记住对话内容"),
}
scanner := bufio.NewScanner(os.Stdin)
fmt.Println("💬 多轮对话(输入 'quit' 退出)")
for {
fmt.Print("\n你: ")
scanner.Scan()
input := strings.TrimSpace(scanner.Text())
if input == "quit" {
break
}
// 添加用户消息到历史
history = append(history, schema.UserMessage(input))
// 生成回复(传入完整历史)
response, err := chatModel.Generate(ctx, history)
if err != nil {
log.Printf("生成失败: %v", err)
continue
}
// 添加 AI 回复到历史
history = append(history, response)
fmt.Println("AI:", response.Content)
}
Trade-offs
| 方法 | 适用场景 | 不适用场景 |
|---|---|---|
Generate() |
后台批量处理、需要完整结果再处理 | 实时聊天界面(用户体验差) |
Stream() |
聊天界面、长文本生成 | 需要原子性结果的场景 |
| 多轮对话(传完整历史) | 需要上下文的对话 | 历史过长时会超出 token 限制 |
Eino vs 直接调用 API:
- Eino 提供统一抽象,切换模型只需改配置
- 直接调用 API 更轻量,但换模型需要改代码
总结
| 方法 | 用途 |
|---|---|
Generate() |
非流式调用,等待完整响应 |
Stream() |
流式调用,边生成边返回 |
schema.Message |
消息结构,支持 System/User/Assistant/Tool 四种角色 |