🤖 Eino ChatModel 组件完全指南
📖 基本介绍
ChatModel
组件是一个用于与大语言模型交互的核心组件。它的主要作用是将用户的输入消息发送给语言模型,并获取模型的响应。这个组件在 AI 应用开发中扮演着**“大脑”**的角色。
🎯 核心价值
在传统的应用开发中,我们只能处理结构化数据和预定义逻辑。而 ChatModel 组件让我们能够:
传统应用:固定逻辑 + 结构化数据 ❌
AI 应用:智能推理 + 自然语言理解 ✅
🚀 主要应用场景
- 💬 自然语言对话: 构建智能聊天机器人和对话系统
- 📝 文本生成和补全: 自动生成文章、代码、创意内容等
- 🛠️ 工具调用的参数生成: 智能分析用户需求并调用相应工具
- 🎭 多模态交互: 处理文本、图片、音频等多种输入形式
- 🤖 智能Agent系统: 作为Agent的推理引擎,驱动复杂决策
- 📊 内容分析和理解: 文本分类、情感分析、信息提取等
🔧 核心接口
ChatModel
组件提供了简洁而强大的接口设计:
基础接口
type BaseChatModel interface {
Generate(ctx context.Context, input []*schema.Message, opts ...Option) (*schema.Message, error)
Stream(ctx context.Context, input []*schema.Message, opts ...Option) (
*schema.StreamReader[*schema.Message], error)
}
工具调用接口
type ToolCallingChatModel interface {
BaseChatModel
// WithTools 返回绑定了指定工具的新实例
// 此方法不会修改当前实例,使并发使用更安全
WithTools(tools []*schema.ToolInfo) (ToolCallingChatModel, error)
}
接口详解
📤 Generate 方法
- 功能: 生成完整的模型响应
- 输入:
ctx
: 上下文对象,用于传递请求级别信息和 Callback Managerinput
: 输入消息列表 ([]*schema.Message
)opts
: 可选参数,用于配置模型行为
- 输出:
*schema.Message
: 模型生成的响应消息error
: 生成过程中的错误信息
🌊 Stream 方法
- 功能: 以流式方式生成模型响应
- 参数: 与 Generate 方法相同
- 输出:
*schema.StreamReader[*schema.Message]
: 模型响应的流式读取器error
: 生成过程中的错误信息
🛠️ WithTools 方法
- 功能: 为模型绑定可用的工具
- 输入:
tools
- 工具信息列表 - 输出:
ToolCallingChatModel
: 绑定了工具后的新实例error
: 绑定过程中的错误信息
📨 Message 结构体
Message
是模型交互的基本数据结构,支持丰富的消息类型:
type Message struct {
// Role 表示消息的角色(system/user/assistant/tool)
Role RoleType
// Content 是消息的文本内容
Content string
// MultiContent 是多模态内容,支持文本、图片、音频等
MultiContent []ChatMessagePart
// Name 是消息的发送者名称
Name string
// ToolCalls 是 assistant 消息中的工具调用信息
ToolCalls []ToolCall
// ToolCallID 是 tool 消息的工具调用 ID
ToolCallID string
// ResponseMeta 包含响应的元信息
ResponseMeta *ResponseMeta
// Extra 用于存储额外信息
Extra map[string]any
}
🎭 消息角色类型
- 🔧 system: 系统消息,用于设定AI的行为和角色
- 👤 user: 用户消息,来自用户的输入
- 🤖 assistant: AI助手消息,模型的回复
- 🛠️ tool: 工具消息,工具执行的结果
🎨 多模态支持
Message
结构体支持多种内容类型:
- 📝 文本内容: 通过
Content
字段 - 🖼️ 图片内容: 通过
MultiContent
支持图像输入 - 🎵 音频内容: 支持音频文件处理
- 📹 视频内容: 支持视频文件分析
- 📎 文件内容: 支持各种文档格式
⚙️ 配置选项 (Options)
ChatModel
组件提供了丰富的配置选项来控制模型行为:
通用选项
type Options struct {
// Temperature 控制输出的随机性 (0.0-2.0)
Temperature *float32
// MaxTokens 控制生成的最大 token 数量
MaxTokens *int
// Model 指定使用的模型名称
Model *string
// TopP 控制输出的多样性 (0.0-1.0)
TopP *float32
// Stop 指定停止生成的条件
Stop []string
}
选项设置方法
// 设置温度 - 控制创造性
model.WithTemperature(0.7) // 0.0=确定性, 1.0=平衡, 2.0=高创造性
// 设置最大 token 数 - 控制响应长度
model.WithMaxTokens(2000)
// 设置模型名称 - 选择特定模型
model.WithModel("gpt-4")
// 设置 top_p 值 - 控制词汇选择范围
model.WithTopP(0.9)
// 设置停止词 - 定义生成结束条件
model.WithStop([]string{"\n\n", "结束"})
参数调优指南
参数 | 推荐值 | 适用场景 |
---|---|---|
Temperature | 0.1-0.3 | 事实性回答、代码生成 |
Temperature | 0.7-0.9 | 创意写作、头脑风暴 |
MaxTokens | 500-1000 | 简短回答 |
MaxTokens | 2000-4000 | 详细分析、长文生成 |
TopP | 0.9-0.95 | 平衡质量和多样性 |
🛠️ 使用方式
1. 单独使用
这是最直接的使用方式,适合简单的对话和文本生成场景:
import (
"context"
"fmt"
"io"
"github.com/cloudwego/eino-ext/components/model/ark"
"github.com/cloudwego/eino/components/model"
"github.com/cloudwego/eino/schema"
)
func basicChatModelExample() {
ctx := context.Background()
// 1. 初始化模型 (以ARK为例)
cm, err := ark.NewChatModel(ctx, &ark.ChatModelConfig{
APIKey: "YOUR_API_KEY",
Model: "doubao-pro-4k",
Timeout: 30 * time.Second,
})
if err != nil {
log.Fatal("初始化模型失败:", err)
}
// 2. 准备输入消息
messages := []*schema.Message{
{
Role: schema.System,
Content: "你是一个有帮助的AI助手,请用简洁明了的方式回答问题。",
},
{
Role: schema.User,
Content: "请解释什么是机器学习?",
},
}
// 3. 生成响应
response, err := cm.Generate(ctx, messages,
model.WithTemperature(0.7),
model.WithMaxTokens(1000),
)
if err != nil {
log.Fatal("生成响应失败:", err)
}
// 4. 处理响应
fmt.Printf("AI回复: %s\n", response.Content)
// 5. 流式生成示例
fmt.Println("\n=== 流式生成 ===")
streamResult, err := cm.Stream(ctx, messages)
if err != nil {
log.Fatal("流式生成失败:", err)
}
defer streamResult.Close()
for {
chunk, err := streamResult.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Printf("接收流式数据出错: %v", err)
break
}
// 实时输出响应片段
fmt.Print(chunk.Content)
}
fmt.Println()
}
2. 在编排中使用 (推荐)
与其他 Eino 组件结合使用,构建复杂的 AI 工作流:
import (
"github.com/cloudwego/eino/schema"
"github.com/cloudwego/eino/compose"
)
func orchestrationExample() {
ctx := context.Background()
// 1. 初始化 ChatModel
cm, err := ark.NewChatModel(ctx, &ark.ChatModelConfig{
APIKey: "YOUR_API_KEY",
Model: "doubao-pro-4k",
})
if err != nil {
log.Fatal("初始化模型失败:", err)
}
// 2. 在 Chain 中使用
chain := compose.NewChain[[]*schema.Message, *schema.Message]()
chain.AppendChatModel(cm)
// 编译并运行
runnable, err := chain.Compile(ctx)
if err != nil {
log.Fatal("编译链失败:", err)
}
messages := []*schema.Message{
{Role: schema.User, Content: "你好!"},
}
result, err := runnable.Invoke(ctx, messages)
if err != nil {
log.Fatal("执行链失败:", err)
}
fmt.Printf("链式处理结果: %s\n", result.Content)
// 3. 在 Graph 中使用
graph := compose.NewGraph[[]*schema.Message, *schema.Message]()
graph.AddChatModelNode("chat_model", cm)
// 设置图的流程
graph.AddEdge(compose.START, "chat_model")
graph.AddEdge("chat_model", compose.END)
graphRunnable, err := graph.Compile(ctx)
if err != nil {
log.Fatal("编译图失败:", err)
}
graphResult, err := graphRunnable.Invoke(ctx, messages)
if err != nil {
log.Fatal("执行图失败:", err)
}
fmt.Printf("图式处理结果: %s\n", graphResult.Content)
}
3. 工具调用集成
展示如何将 ChatModel 与工具系统集成:
func toolCallingExample() {
ctx := context.Background()
// 1. 创建工具
tools := []tool.InvokableTool{
// 假设已经实现了计算器工具
NewCalculatorTool(),
NewWeatherTool(),
}
// 2. 初始化支持工具调用的模型
cm, err := ark.NewChatModel(ctx, &ark.ChatModelConfig{
APIKey: "YOUR_API_KEY",
Model: "doubao-pro-4k",
})
if err != nil {
log.Fatal("初始化模型失败:", err)
}
// 3. 绑定工具到模型
toolInfos := make([]*schema.ToolInfo, 0, len(tools))
for _, tool := range tools {
info, err := tool.Info(ctx)
if err != nil {
log.Printf("获取工具信息失败: %v", err)
continue
}
toolInfos = append(toolInfos, info)
}
// 使用 BindTools 方法绑定工具
cm.BindTools(toolInfos)
// 4. 发送需要工具调用的消息
messages := []*schema.Message{
{
Role: schema.System,
Content: "你是一个智能助手,可以使用工具来帮助用户解决问题。",
},
{
Role: schema.User,
Content: "请帮我计算 123 * 456 的结果,然后查询北京今天的天气。",
},
}
// 5. 生成响应(可能包含工具调用)
response, err := cm.Generate(ctx, messages)
if err != nil {
log.Fatal("生成响应失败:", err)
}
// 6. 处理工具调用
if len(response.ToolCalls) > 0 {
fmt.Printf("模型请求调用 %d 个工具:\n", len(response.ToolCalls))
for _, toolCall := range response.ToolCalls {
fmt.Printf("- 工具: %s, 参数: %s\n",
toolCall.Function.Name,
toolCall.Function.Arguments)
// 这里可以执行实际的工具调用
// result := executeTool(toolCall)
}
} else {
fmt.Printf("直接回复: %s\n", response.Content)
}
}
📊 回调机制 (Callbacks)
回调机制允许开发者在 ChatModel
的生命周期关键点注入自定义逻辑,用于监控、日志记录和性能分析。
回调事件
OnStart
: 在模型开始生成时触发OnEnd
: 在模型成功生成响应后触发OnError
: 在发生错误时触发OnStream
: 在流式生成过程中触发(每个chunk)
使用示例
import "github.com/cloudwego/eino/callbacks"
func callbackExample() {
ctx := context.Background()
// 1. 创建回调处理器
handler := &callbacks.ChatModelCallbackHandler{
OnStart: func(ctx context.Context, info *callbacks.ChatModelStartInfo) {
fmt.Printf("[回调] 开始生成,模型: %s, 消息数: %d\n",
info.Model, len(info.Messages))
},
OnEnd: func(ctx context.Context, info *callbacks.ChatModelEndInfo) {
fmt.Printf("[回调] 生成完成,耗时: %v, Token使用: %d\n",
info.Duration, info.TokenUsage.TotalTokens)
},
OnError: func(ctx context.Context, info *callbacks.ChatModelErrorInfo) {
fmt.Printf("[回调] 生成失败: %v\n", info.Error)
},
OnStream: func(ctx context.Context, info *callbacks.ChatModelStreamInfo) {
fmt.Printf("[回调] 流式数据: %s\n", info.Chunk.Content)
},
}
callbackHandler := callbacks.NewHandlerHelper().ChatModel(handler).Handler()
// 2. 在编排中使用回调
chain := compose.NewChain[[]*schema.Message, *schema.Message]()
chain.AppendChatModel(cm)
runnable, _ := chain.Compile(ctx)
messages := []*schema.Message{
{Role: schema.User, Content: "你好!"},
}
// 3. 带回调执行
result, err := runnable.Invoke(ctx, messages,
compose.WithCallbacks(callbackHandler),
)
if err != nil {
log.Printf("执行失败: %v", err)
return
}
fmt.Printf("最终结果: %s\n", result.Content)
}
高级回调应用
// 性能监控回调
type PerformanceMonitor struct {
startTime time.Time
metrics map[string]interface{}
}
func (p *PerformanceMonitor) CreateHandler() *callbacks.ChatModelCallbackHandler {
return &callbacks.ChatModelCallbackHandler{
OnStart: func(ctx context.Context, info *callbacks.ChatModelStartInfo) {
p.startTime = time.Now()
p.metrics = make(map[string]interface{})
p.metrics["model"] = info.Model
p.metrics["input_messages"] = len(info.Messages)
},
OnEnd: func(ctx context.Context, info *callbacks.ChatModelEndInfo) {
duration := time.Since(p.startTime)
p.metrics["duration_ms"] = duration.Milliseconds()
p.metrics["total_tokens"] = info.TokenUsage.TotalTokens
p.metrics["tokens_per_second"] = float64(info.TokenUsage.TotalTokens) / duration.Seconds()
// 发送到监控系统
p.sendMetrics()
},
OnError: func(ctx context.Context, info *callbacks.ChatModelErrorInfo) {
p.metrics["error"] = info.Error.Error()
p.metrics["status"] = "failed"
p.sendMetrics()
},
}
}
func (p *PerformanceMonitor) sendMetrics() {
// 发送指标到监控系统(如 Prometheus、DataDog 等)
fmt.Printf("性能指标: %+v\n", p.metrics)
}
🎯 实际应用示例
1. 智能客服系统
type CustomerServiceBot struct {
chatModel model.BaseChatModel
knowledge []string // 知识库
}
func NewCustomerServiceBot(cm model.BaseChatModel) *CustomerServiceBot {
return &CustomerServiceBot{
chatModel: cm,
knowledge: []string{
"我们的营业时间是周一到周五 9:00-18:00",
"退货政策:7天无理由退货",
"配送时间:1-3个工作日",
},
}
}
func (bot *CustomerServiceBot) HandleCustomerQuery(ctx context.Context, query string) (string, error) {
// 构建系统提示
systemPrompt := fmt.Sprintf(`你是一个专业的客服助手。
知识库信息:
%s
请根据知识库信息回答用户问题,如果知识库中没有相关信息,请礼貌地告知用户联系人工客服。`,
strings.Join(bot.knowledge, "\n"))
messages := []*schema.Message{
{Role: schema.System, Content: systemPrompt},
{Role: schema.User, Content: query},
}
response, err := bot.chatModel.Generate(ctx, messages,
model.WithTemperature(0.3), // 较低温度确保回答准确
model.WithMaxTokens(500),
)
if err != nil {
return "", err
}
return response.Content, nil
}
2. 代码生成助手
type CodeGenerator struct {
chatModel model.BaseChatModel
}
func NewCodeGenerator(cm model.BaseChatModel) *CodeGenerator {
return &CodeGenerator{chatModel: cm}
}
func (cg *CodeGenerator) GenerateCode(ctx context.Context, requirement string, language string) (string, error) {
systemPrompt := fmt.Sprintf(`你是一个专业的%s程序员。
请根据用户需求生成高质量的代码,要求:
1. 代码结构清晰,注释完整
2. 遵循最佳实践和编码规范
3. 包含必要的错误处理
4. 提供使用示例`, language)
messages := []*schema.Message{
{Role: schema.System, Content: systemPrompt},
{Role: schema.User, Content: fmt.Sprintf("请用%s实现:%s", language, requirement)},
}
response, err := cg.chatModel.Generate(ctx, messages,
model.WithTemperature(0.2), // 低温度确保代码准确性
model.WithMaxTokens(2000),
)
if err != nil {
return "", err
}
return response.Content, nil
}
// 使用示例
func codeGeneratorExample() {
ctx := context.Background()
cm, _ := ark.NewChatModel(ctx, &ark.ChatModelConfig{
APIKey: "YOUR_API_KEY",
Model: "doubao-pro-4k",
})
generator := NewCodeGenerator(cm)
code, err := generator.GenerateCode(ctx,
"实现一个线程安全的计数器",
"Go")
if err != nil {
log.Fatal(err)
}
fmt.Println("生成的代码:")
fmt.Println(code)
}
3. 多轮对话管理
type ConversationManager struct {
chatModel model.BaseChatModel
history []*schema.Message
maxHistory int
}
func NewConversationManager(cm model.BaseChatModel) *ConversationManager {
return &ConversationManager{
chatModel: cm,
history: make([]*schema.Message, 0),
maxHistory: 10, // 保持最近10轮对话
}
}
func (cm *ConversationManager) Chat(ctx context.Context, userInput string) (string, error) {
// 添加用户消息到历史
userMessage := &schema.Message{
Role: schema.User,
Content: userInput,
}
cm.history = append(cm.history, userMessage)
// 构建完整的对话历史
messages := make([]*schema.Message, 0, len(cm.history)+1)
// 添加系统提示
systemMessage := &schema.Message{
Role: schema.System,
Content: "你是一个友好的AI助手,能够记住对话历史并提供连贯的回复。",
}
messages = append(messages, systemMessage)
// 添加历史对话(限制长度)
startIdx := 0
if len(cm.history) > cm.maxHistory {
startIdx = len(cm.history) - cm.maxHistory
}
messages = append(messages, cm.history[startIdx:]...)
// 生成回复
response, err := cm.chatModel.Generate(ctx, messages,
model.WithTemperature(0.7),
model.WithMaxTokens(1000),
)
if err != nil {
return "", err
}
// 添加AI回复到历史
cm.history = append(cm.history, response)
// 清理过长的历史
if len(cm.history) > cm.maxHistory*2 {
cm.history = cm.history[len(cm.history)-cm.maxHistory:]
}
return response.Content, nil
}
func (cm *ConversationManager) ClearHistory() {
cm.history = make([]*schema.Message, 0)
}
func (cm *ConversationManager) GetHistoryLength() int {
return len(cm.history)
}
🔧 最佳实践
1. 性能优化
连接池管理
type ChatModelPool struct {
models chan model.BaseChatModel
config *ark.ChatModelConfig
}
func NewChatModelPool(size int, config *ark.ChatModelConfig) *ChatModelPool {
pool := &ChatModelPool{
models: make(chan model.BaseChatModel, size),
config: config,
}
// 预创建模型实例
for i := 0; i < size; i++ {
cm, err := ark.NewChatModel(context.Background(), config)
if err != nil {
log.Printf("创建模型实例失败: %v", err)
continue
}
pool.models <- cm
}
return pool
}
func (p *ChatModelPool) Get() model.BaseChatModel {
return <-p.models
}
func (p *ChatModelPool) Put(cm model.BaseChatModel) {
select {
case p.models <- cm:
default:
// 池已满,丢弃实例
}
}
请求批处理
type BatchProcessor struct {
chatModel model.BaseChatModel
batchSize int
timeout time.Duration
}
func (bp *BatchProcessor) ProcessBatch(ctx context.Context, requests []ChatRequest) ([]ChatResponse, error) {
responses := make([]ChatResponse, len(requests))
// 并发处理批次
var wg sync.WaitGroup
semaphore := make(chan struct{}, bp.batchSize)
for i, req := range requests {
wg.Add(1)
go func(index int, request ChatRequest) {
defer wg.Done()
semaphore <- struct{}{} // 获取信号量
defer func() { <-semaphore }() // 释放信号量
ctx, cancel := context.WithTimeout(ctx, bp.timeout)
defer cancel()
response, err := bp.chatModel.Generate(ctx, request.Messages)
responses[index] = ChatResponse{
Response: response,
Error: err,
}
}(i, req)
}
wg.Wait()
return responses, nil
}
2. 错误处理和重试
type ResilientChatModel struct {
chatModel model.BaseChatModel
maxRetries int
retryDelay time.Duration
backoffRate float64
}
func NewResilientChatModel(cm model.BaseChatModel) *ResilientChatModel {
return &ResilientChatModel{
chatModel: cm,
maxRetries: 3,
retryDelay: time.Second,
backoffRate: 2.0,
}
}
func (rcm *ResilientChatModel) Generate(ctx context.Context, messages []*schema.Message, opts ...model.Option) (*schema.Message, error) {
var lastErr error
delay := rcm.retryDelay
for attempt := 0; attempt <= rcm.maxRetries; attempt++ {
if attempt > 0 {
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-time.After(delay):
delay = time.Duration(float64(delay) * rcm.backoffRate)
}
}
response, err := rcm.chatModel.Generate(ctx, messages, opts...)
if err == nil {
return response, nil
}
lastErr = err
// 判断是否应该重试
if !shouldRetry(err) {
break
}
log.Printf("第 %d 次尝试失败: %v", attempt+1, err)
}
return nil, fmt.Errorf("重试 %d 次后仍然失败: %w", rcm.maxRetries, lastErr)
}
func shouldRetry(err error) bool {
// 根据错误类型判断是否应该重试
if strings.Contains(err.Error(), "timeout") {
return true
}
if strings.Contains(err.Error(), "rate limit") {
return true
}
if strings.Contains(err.Error(), "server error") {
return true
}
return false
}
3. 监控和日志
type MonitoredChatModel struct {
chatModel model.BaseChatModel
metrics *Metrics
logger *log.Logger
}
type Metrics struct {
TotalRequests int64
SuccessRequests int64
FailedRequests int64
TotalTokens int64
AverageLatency time.Duration
mu sync.RWMutex
}
func (mcm *MonitoredChatModel) Generate(ctx context.Context, messages []*schema.Message, opts ...model.Option) (*schema.Message, error) {
startTime := time.Now()
// 记录请求开始
mcm.metrics.mu.Lock()
mcm.metrics.TotalRequests++
mcm.metrics.mu.Unlock()
mcm.logger.Printf("[ChatModel] 开始处理请求,消息数: %d", len(messages))
// 执行实际请求
response, err := mcm.chatModel.Generate(ctx, messages, opts...)
// 记录结果
duration := time.Since(startTime)
mcm.metrics.mu.Lock()
if err != nil {
mcm.metrics.FailedRequests++
mcm.logger.Printf("[ChatModel] 请求失败,耗时: %v, 错误: %v", duration, err)
} else {
mcm.metrics.SuccessRequests++
if response.ResponseMeta != nil && response.ResponseMeta.Usage != nil {
mcm.metrics.TotalTokens += int64(response.ResponseMeta.Usage.TotalTokens)
}
mcm.logger.Printf("[ChatModel] 请求成功,耗时: %v", duration)
}
// 更新平均延迟
mcm.updateAverageLatency(duration)
mcm.metrics.mu.Unlock()
return response, err
}
func (mcm *MonitoredChatModel) updateAverageLatency(newLatency time.Duration) {
// 简单的移动平均
if mcm.metrics.AverageLatency == 0 {
mcm.metrics.AverageLatency = newLatency
} else {
mcm.metrics.AverageLatency = (mcm.metrics.AverageLatency + newLatency) / 2
}
}
func (mcm *MonitoredChatModel) GetMetrics() Metrics {
mcm.metrics.mu.RLock()
defer mcm.metrics.mu.RUnlock()
return *mcm.metrics
}
4. 配置管理
type ChatModelConfig struct {
Provider string `yaml:"provider"` // ark, openai, etc.
Model string `yaml:"model"` // 模型名称
APIKey string `yaml:"api_key"` // API密钥
BaseURL string `yaml:"base_url"` // 基础URL
Temperature float32 `yaml:"temperature"` // 温度
MaxTokens int `yaml:"max_tokens"` // 最大token数
Timeout time.Duration `yaml:"timeout"` // 超时时间
Retries int `yaml:"retries"` // 重试次数
}
type ChatModelFactory struct {
configs map[string]*ChatModelConfig
}
func NewChatModelFactory(configFile string) (*ChatModelFactory, error) {
data, err := ioutil.ReadFile(configFile)
if err != nil {
return nil, err
}
var configs map[string]*ChatModelConfig
if err := yaml.Unmarshal(data, &configs); err != nil {
return nil, err
}
return &ChatModelFactory{configs: configs}, nil
}
func (factory *ChatModelFactory) CreateChatModel(ctx context.Context, name string) (model.BaseChatModel, error) {
config, exists := factory.configs[name]
if !exists {
return nil, fmt.Errorf("配置 %s 不存在", name)
}
switch config.Provider {
case "ark":
return ark.NewChatModel(ctx, &ark.ChatModelConfig{
APIKey: config.APIKey,
Model: config.Model,
BaseURL: config.BaseURL,
Temperature: config.Temperature,
MaxTokens: config.MaxTokens,
Timeout: config.Timeout,
})
case "openai":
// 实现 OpenAI 模型创建
return nil, fmt.Errorf("OpenAI 提供商暂未实现")
default:
return nil, fmt.Errorf("不支持的提供商: %s", config.Provider)
}
}
🚨 常见问题和解决方案
1. Token 限制问题
问题: 输入或输出超过模型的 token 限制
解决方案:
func truncateMessages(messages []*schema.Message, maxTokens int) []*schema.Message {
// 简单的截断策略:保留系统消息和最近的用户消息
if len(messages) <= 2 {
return messages
}
result := make([]*schema.Message, 0)
// 保留系统消息
for _, msg := range messages {
if msg.Role == schema.System {
result = append(result, msg)
break
}
}
// 从后往前添加消息,直到接近 token 限制
estimatedTokens := 0
for i := len(messages) - 1; i >= 0; i-- {
msg := messages[i]
if msg.Role == schema.System {
continue
}
// 粗略估算 token 数(1 token ≈ 4 字符)
msgTokens := len(msg.Content) / 4
if estimatedTokens+msgTokens > maxTokens {
break
}
result = append([]*schema.Message{msg}, result...)
estimatedTokens += msgTokens
}
return result
}
2. 速率限制处理
问题: API 调用频率过高导致限流
解决方案:
type RateLimiter struct {
limiter *rate.Limiter
}
func NewRateLimiter(requestsPerSecond float64) *RateLimiter {
return &RateLimiter{
limiter: rate.NewLimiter(rate.Limit(requestsPerSecond), 1),
}
}
func (rl *RateLimiter) Wait(ctx context.Context) error {
return rl.limiter.Wait(ctx)
}
type RateLimitedChatModel struct {
chatModel model.BaseChatModel
rateLimiter *RateLimiter
}
func (rlcm *RateLimitedChatModel) Generate(ctx context.Context, messages []*schema.Message, opts ...model.Option) (*schema.Message, error) {
// 等待速率限制
if err := rlcm.rateLimiter.Wait(ctx); err != nil {
return nil, err
}
return rlcm.chatModel.Generate(ctx, messages, opts...)
}
3. 内存泄漏预防
问题: 长时间运行导致内存泄漏
解决方案:
type ManagedChatModel struct {
chatModel model.BaseChatModel
cleanup func()
}
func NewManagedChatModel(ctx context.Context, config *ark.ChatModelConfig) (*ManagedChatModel, error) {
cm, err := ark.NewChatModel(ctx, config)
if err != nil {
return nil, err
}
managed := &ManagedChatModel{
chatModel: cm,
}
// 设置清理函数
managed.cleanup = func() {
// 清理资源
if closer, ok := cm.(io.Closer); ok {
closer.Close()
}
}
// 注册清理函数
runtime.SetFinalizer(managed, (*ManagedChatModel).finalize)
return managed, nil
}
func (mcm *ManagedChatModel) finalize() {
if mcm.cleanup != nil {
mcm.cleanup()
}
}
func (mcm *ManagedChatModel) Close() {
mcm.finalize()
runtime.SetFinalizer(mcm, nil)
}
📚 相关资源
- 官方文档: Eino ChatModel 使用说明
- GitHub 仓库: cloudwego/eino