跳转至

Model 模块

概述

Model 模块是 tRPC-Agent-Go 框架的大语言模型抽象层,提供了统一的 LLM 接口设计,目前支持 OpenAI 兼容的 API 调用。通过标准化的接口设计,开发者可以灵活切换不同的模型提供商,实现模型的无缝集成和调用。该模块已验证兼容公司内外大多数 OpenAI-like 接口。

Model 模块具有以下核心特性:

  • 统一接口抽象:提供标准化的 Model 接口,屏蔽不同模型提供商的差异
  • 流式响应支持:原生支持流式输出,实现实时交互体验
  • 多模态能力:支持文本、图像、音频等多模态内容处理
  • 完整错误处理:提供双层错误处理机制,区分系统错误和 API 错误
  • 可扩展配置:支持丰富的自定义配置项,满足不同场景需求

快速开始

在 Agent 中使用 Model

import (
    "trpc.group/trpc-go/trpc-agent-go/agent/llmagent"
    "trpc.group/trpc-go/trpc-agent-go/model"
    "trpc.group/trpc-go/trpc-agent-go/model/openai"
    "trpc.group/trpc-go/trpc-agent-go/runner"
    "trpc.group/trpc-go/trpc-agent-go/tool"
)

func main() {
    // 1. 创建模型实例
    modelInstance := openai.New("deepseek-chat", 
        openai.WithExtraFields(map[string]interface{}{
            "tool_choice": "auto", // 自动选择工具
        }),
    )

    // 2. 配置生成参数
    genConfig := model.GenerationConfig{
        MaxTokens:   intPtr(2000),
        Temperature: floatPtr(0.7),
        Stream:      true, // 启用流式输出
    }

    // 3. 创建 Agent 并集成模型
    agent := llmagent.New(
        "chat-assistant",
        llmagent.WithModel(modelInstance),
        llmagent.WithDescription("一个有用的助手"),
        llmagent.WithInstruction("你是一个智能助手,在需要时使用工具。"),
        llmagent.WithGenerationConfig(genConfig),
        llmagent.WithTools([]tool.Tool{calculatorTool, timeTool}),
    )

    // 4. 创建 Runner 并运行
    r := runner.NewRunner("app-name", agent)
    eventChan, err := r.Run(ctx, userID, sessionID, model.NewUserMessage("Hello"))
    if err != nil {
        log.Fatal(err)
    }

    // 5. 处理响应事件
    for event := range eventChan {
        // 处理流式响应、工具调用等
    }
}

示例代码位于 examples/runner

使用方式与平台接入指南

Model 模块支持多种使用方式和平台接入。以下是基于 Runner 示例的常见使用场景:

快速启动

1
2
3
4
5
# 基础使用:通过环境变量配置,直接运行
cd examples/runner
export OPENAI_BASE_URL="https://api.deepseek.com/v1"
export OPENAI_API_KEY="your-api-key"
go run main.go -model deepseek-chat

平台接入配置

所有平台的接入方式都遵循相同模式,只需配置不同的环境变量或直接在代码中设置:

环境变量方式(推荐):

export OPENAI_BASE_URL="平台API地址"
export OPENAI_API_KEY="API密钥"

代码方式

1
2
3
4
model := openai.New("模型名称",
    openai.WithBaseURL("平台API地址"),
    openai.WithAPIKey("API密钥"),
)

支持的平台及其配置

以下是各平台的配置示例,分为环境变量配置和代码配置两种方式:

环境变量配置

runner 示例中支持通过命令行参数(-model)指定模型名称,实际上是在 openai.New() 时传入模型名称。

# OpenAI 平台
export OPENAI_API_KEY="sk-..."
cd examples/runner
go run main.go -model gpt-4o-mini

# OpenAI API 兼容
export OPENAI_BASE_URL="https://api.deepseek.com/v1"
export OPENAI_API_KEY="your-api-key"
cd examples/runner
go run main.go -model deepseek-chat

代码配置方式

在自己的代码中直接使用 Model 时的配置方式:

1
2
3
4
5
6
model := openai.New("deepseek-chat",
    openai.WithBaseURL("https://api.deepseek.com/v1"),
    openai.WithAPIKey("your-api-key"),
)

// 其他平台配置类似,只需修改模型名称、BaseURL和APIKey,无需额外字段

核心接口设计

Model 接口

// Model 是所有语言模型必须实现的接口
type Model interface {
    // 生成内容,支持流式响应
    GenerateContent(ctx context.Context, request *Request) (<-chan *Response, error)

    // 返回模型基本信息
    Info() Info
}

// 模型信息结构
type Info struct {
    Name string // 模型名称
}

Request 结构

// Request 表示发送给模型的请求
type Request struct {
    // 消息列表,包含系统指令、用户输入和助手回复
    Messages []Message `json:"messages"`

    // 生成配置(内联到请求中)
    GenerationConfig `json:",inline"`

    // 工具列表
    Tools map[string]tool.Tool `json:"-"`
}

// GenerationConfig 包含生成参数配置
type GenerationConfig struct {
    // 是否使用流式响应
    Stream bool `json:"stream"`

    // 温度参数 (0.0-2.0)
    Temperature *float64 `json:"temperature,omitempty"`

    // 最大生成令牌数
    MaxTokens *int `json:"max_tokens,omitempty"`

    // Top-P 采样参数
    TopP *float64 `json:"top_p,omitempty"`

    // 停止生成的标记
    Stop []string `json:"stop,omitempty"`

    // 频率惩罚
    FrequencyPenalty *float64 `json:"frequency_penalty,omitempty"`

    // 存在惩罚
    PresencePenalty *float64 `json:"presence_penalty,omitempty"`

    // 推理努力程度 ("low", "medium", "high")
    ReasoningEffort *string `json:"reasoning_effort,omitempty"`

    // 是否启用思考模式
    ThinkingEnabled *bool `json:"-"`

    // 思考模式的最大令牌数
    ThinkingTokens *int `json:"-"`
}

Response 结构

// Response 表示模型返回的响应
type Response struct {
    // OpenAI 兼容字段
    ID                string   `json:"id,omitempty"`
    Object            string   `json:"object,omitempty"`
    Created           int64    `json:"created,omitempty"`
    Model             string   `json:"model,omitempty"`
    SystemFingerprint *string  `json:"system_fingerprint,omitempty"`
    Choices           []Choice `json:"choices,omitempty"`
    Usage             *Usage   `json:"usage,omitempty"`

    // 错误信息
    Error *ResponseError `json:"error,omitempty"`

    // 内部字段
    Timestamp time.Time `json:"-"`
    Done      bool      `json:"-"`
    IsPartial bool      `json:"-"`
}

// ResponseError 表示 API 级别的错误
type ResponseError struct {
    Message string    `json:"message"`
    Type    ErrorType `json:"type"`
    Param   string    `json:"param,omitempty"`
    Code    string    `json:"code,omitempty"`
}

直接使用 Model

import (
    "context"
    "fmt"

    "trpc.group/trpc-go/trpc-agent-go/model"
    "trpc.group/trpc-go/trpc-agent-go/model/openai"
)

func main() {
    // 创建模型实例
    llm := openai.New("deepseek-chat")

    // 构建请求
    temperature := 0.7
    maxTokens := 1000

    request := &model.Request{
        Messages: []model.Message{
            model.NewSystemMessage("你是一个专业的AI助手。"),
            model.NewUserMessage("介绍一下Go语言的并发特性。"),
        },
        GenerationConfig: model.GenerationConfig{
            Temperature: &temperature,
            MaxTokens:   &maxTokens,
            Stream:      false,
        },
    }

    // 调用模型
    ctx := context.Background()
    responseChan, err := llm.GenerateContent(ctx, request)
    if err != nil {
        fmt.Printf("系统错误: %v\n", err)
        return
    }

    // 处理响应
    for response := range responseChan {
        if response.Error != nil {
            fmt.Printf("API错误: %s\n", response.Error.Message)
            return
        }

        if len(response.Choices) > 0 {
            fmt.Printf("回复: %s\n", response.Choices[0].Message.Content)
        }

        if response.Done {
            break
        }
    }
}

流式输出

// 流式请求配置
request := &model.Request{
    Messages: []model.Message{
        model.NewSystemMessage("你是一个创意故事讲述者。"),
        model.NewUserMessage("写一个关于机器人学习绘画的短故事。"),
    },
    GenerationConfig: model.GenerationConfig{
        Stream: true,  // 启用流式输出
    },
}

// 处理流式响应
responseChan, err := llm.GenerateContent(ctx, request)
if err != nil {
    return err
}

for response := range responseChan {
    if response.Error != nil {
        fmt.Printf("错误: %s", response.Error.Message)
        return
    }

    if len(response.Choices) > 0 && response.Choices[0].Delta.Content != "" {
        fmt.Print(response.Choices[0].Delta.Content)
    }

    if response.Done {
        break
    }
}

高级参数配置

// 使用高级生成参数
temperature := 0.3
maxTokens := 2000
topP := 0.9
presencePenalty := 0.2
frequencyPenalty := 0.5
reasoningEffort := "high"

request := &model.Request{
    Messages: []model.Message{
        model.NewSystemMessage("你是一个专业的技术文档撰写者。"),
        model.NewUserMessage("解释微服务架构的优缺点。"),
    },
    GenerationConfig: model.GenerationConfig{
        Temperature:      &temperature,
        MaxTokens:        &maxTokens,
        TopP:             &topP,
        PresencePenalty:  &presencePenalty,
        FrequencyPenalty: &frequencyPenalty,
        ReasoningEffort:  &reasoningEffort,
        Stream:           true,
    },
}

多模态内容

// 读取图像文件
imageData, _ := os.ReadFile("image.jpg")

// 创建多模态消息
request := &model.Request{
    Messages: []model.Message{
        model.NewSystemMessage("你是一个图像分析专家。"),
        {
            Role: model.RoleUser,
            ContentParts: []model.ContentPart{
                {
                    Type: model.ContentTypeText,
                    Text: stringPtr("这张图片中有什么?"),
                },
                {
                    Type: model.ContentTypeImage,
                    Image: &model.Image{
                        Data:   imageData,
                        Format: "jpeg",
                    },
                },
            },
        },
    },
}

高级功能

1. 回调函数

// 设置请求前回调函数
model := openai.New("deepseek-chat",
    openai.WithChatRequestCallback(func(ctx context.Context, req *openai.ChatCompletionNewParams) {
        // 请求发送前被调用
        log.Printf("发送请求: 模型=%s, 消息数=%d", req.Model, len(req.Messages))
    }),

    // 设置响应回调函数(非流式)
    openai.WithChatResponseCallback(func(ctx context.Context, 
        req *openai.ChatCompletionNewParams, 
        resp *openai.ChatCompletion) {
        // 收到完整响应时调用
        log.Printf("收到响应: ID=%s, 使用Token=%d", 
            resp.ID, resp.Usage.TotalTokens)
    }),

    // 设置流式响应回调函数
    openai.WithChatChunkCallback(func(ctx context.Context,
        req *openai.ChatCompletionNewParams,
        chunk *openai.ChatCompletionChunk) {
        // 收到每个流式响应块时调用
        log.Printf("收到流式块: ID=%s", chunk.ID)
    }),
)