一、ChatModel 基础使用 🤖

1.1 什么是 ChatModel 🤔

ChatModel 是 Eino 框架中封装的 大模型对话核心组件,专门用于处理与大语言模型(LLM)的交互逻辑。它就像一个 “智能对话翻译官”,帮你屏蔽不同大模型(如 OpenAI、Anthropic、本地化模型等)的底层差异,提供统一、简洁的 API 来实现对话生成、流式输出、多轮上下文管理等功能。

简单说:有了 ChatModel,你不用关心不同厂商的接口格式差异,专注写业务逻辑就行啦~ ✨

1.2 ChatModel 的核心能力 🚀

Eino 的 ChatModel 内置了三大核心能力,覆盖绝大多数对话场景:

  1. 统一接口适配 🧩:一套代码兼容主流大模型,切换模型无需修改业务逻辑

  2. 灵活输出模式 ⚡:支持一次性完整输出 + 流式增量输出(打字机效果)

  3. 配置化调参 🔧:通过简单配置调整温度(temperature)、最大 tokens 等模型参数

二、基础案例:Generate 生成 📝

在开始案例前,确保你已经:

  1. 安装 Eino 框架:go get github.com/eino-lang/eino

  2. 配置大模型密钥(如 OpenAI API Key):可通过环境变量或配置文件设置

2.1 单轮对话 💬

单轮对话是最简单的场景:用户发送一个问题,模型返回一个回答,无需维护历史上下文。

package main

import (
    "context"
    "log"
    "os"

    "github.com/cloudwego/eino-ext/components/model/openai"
    "github.com/cloudwego/eino/schema"
)

const DOUBAO_BASE_URL = "https://ark.cn-beijing.volces.com/api/v3"
const DOUBAO_MODEL_NAME = "doubao-seed-1-6-flash-250828"

func main() {
    ctx := context.Background()

    key := os.Getenv("DOUBAO_API_KEY")
    if key == "" {
        log.Fatal("DOUBAO_API_KEY environment variable is required")
    }

    chatModel, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
        BaseURL: DOUBAO_BASE_URL,
        Model:   DOUBAO_MODEL_NAME,
        APIKey:  key,
    })
    if err != nil {
        log.Fatalf("创建OpenAI聊天模型失败: %v", err)
    }

    message := []*schema.Message{
        schema.SystemMessage("你是一个专业的助手总是能够简练的总结知识点"),
        schema.UserMessage("请介绍一下Go语言的特点"),
    }

    //调用大模型并生成响应
    response, err := chatModel.Generate(ctx, message)
    if err != nil {
        panic(err)
    }
    println("model: ", response.Content)
}

2.2 多轮对话 🔄

多轮对话需要维护历史上下文,让模型能 “记住” 之前的对话内容。下面用 scan 实现交互式多轮对话,支持用户连续输入。

package main

import (
    "bufio"
    "context"
    "log"
    "os"

    "github.com/cloudwego/eino-ext/components/model/openai"
    "github.com/cloudwego/eino/schema"
)

const DOUBAO_BASE_URL = "https://ark.cn-beijing.volces.com/api/v3"
const DOUBAO_MODEL_NAME = "doubao-seed-1-6-flash-250828"

func main() {
    ctx := context.Background()

    // 读取API密钥
    key := os.Getenv("DOUBAO_API_KEY")
    if key == "" {
        log.Fatal("DOUBAO_API_KEY environment variable is required")
    }

    // 创建聊天模型
    chatModel, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
        BaseURL: DOUBAO_BASE_URL,
        Model:   DOUBAO_MODEL_NAME,
        APIKey:  key,
    })
    if err != nil {
        log.Fatalf("创建OpenAI聊天模型失败: %v", err)
    }

    // 初始化聊天历史,包含系统提示(只添加一次)
    chatHistory := []*schema.Message{
        schema.SystemMessage("你是一个专业的助手,总是能够简练的总结知识点,回答简洁明了"),
    }

    // 创建Scanner读取用户输入
    scanner := bufio.NewScanner(os.Stdin)
    log.Println("多轮对话已启动,输入 'exit' 退出程序")
    log.Println("请输入你的问题:")

    // 循环处理多轮对话
    for {
        // 读取用户输入
        print("用户:")
        if !scanner.Scan() {
            break // 输入结束(如Ctrl+D)
        }
        userInput := scanner.Text()

        // 处理退出命令
        if userInput == "exit" || userInput == "quit" {
            log.Println("对话结束,再见!")
            break
        }

        // 忽略空输入
        if userInput == "" {
            log.Println("请输入有效的问题内容")
            continue
        }

        // 将用户输入添加到聊天历史
        chatHistory = append(chatHistory, schema.UserMessage(userInput))

        // 调用大模型生成响应
        log.Println("正在思考...")
        response, err := chatModel.Generate(ctx, chatHistory)
        if err != nil {
            log.Printf("调用大模型失败:%v", err)
            // 移除本次失败的用户输入,避免影响后续对话
            chatHistory = chatHistory[:len(chatHistory)-1]
            continue
        }

        // 将模型响应添加到聊天历史(保持上下文)
        chatHistory = append(chatHistory, schema.AssistantMessage(response.Content, nil))

        // 输出结果
        println("助手:", response.Content)
        println("------------------------------")
    }

    // 检查Scanner错误
    if err := scanner.Err(); err != nil {
        log.Printf("读取用户输入失败:%v", err)
    }
}

2.3 流式输出 ⚡

流式输出是指模型边生成边返回结果,模拟 “打字机” 效果,提升用户体验(尤其适合长文本生成)。

package main

import (
    "bufio"
    "context"
    "log"
    "os"

    "github.com/cloudwego/eino-ext/components/model/openai"
    "github.com/cloudwego/eino/schema"
)

const DOUBAO_BASE_URL = "https://ark.cn-beijing.volces.com/api/v3"
const DOUBAO_MODEL_NAME = "doubao-seed-1-6-flash-250828"

func main() {
    ctx := context.Background()

    // 读取API密钥
    key := os.Getenv("DOUBAO_API_KEY")
    if key == "" {
        log.Fatal("DOUBAO_API_KEY environment variable is required")
    }

    // 创建聊天模型
    chatModel, err := openai.NewChatModel(ctx, &openai.ChatModelConfig{
        BaseURL: DOUBAO_BASE_URL,
        Model:   DOUBAO_MODEL_NAME,
        APIKey:  key,
    })
    if err != nil {
        log.Fatalf("创建OpenAI聊天模型失败: %v", err)
    }

    // 初始化聊天历史,包含系统提示(只添加一次)
    chatHistory := []*schema.Message{
        schema.SystemMessage("你是一个专业的助手,总是能够简练的总结知识点,回答简洁明了"),
    }

    // 创建Scanner读取用户输入
    scanner := bufio.NewScanner(os.Stdin)
    log.Println("多轮对话已启动,输入 'exit' 退出程序")
    log.Println("请输入你的问题:")

    // 循环处理多轮对话
    for {
        // 读取用户输入
        print("用户:")
        if !scanner.Scan() {
            break // 输入结束(如Ctrl+D)
        }
        userInput := scanner.Text()

        // 处理退出命令
        if userInput == "exit" || userInput == "quit" {
            log.Println("对话结束,再见!")
            break
        }

        // 忽略空输入
        if userInput == "" {
            log.Println("请输入有效的问题内容")
            continue
        }

        // 将用户输入添加到聊天历史
        chatHistory = append(chatHistory, schema.UserMessage(userInput))

        // 调用大模型生成响应
        log.Println("正在思考...")
        stream, err := chatModel.Stream(ctx, chatHistory)
        if err != nil {
            log.Printf("调用大模型失败:%v", err)
            // 移除本次失败的用户输入,避免影响后续对话
            chatHistory = chatHistory[:len(chatHistory)-1]
            continue
        }

        defer stream.Close()

        // 收集流式响应的完整内容
        var fullResponse string
        for {
            chunk, err := stream.Recv()
            if err != nil {
                // EOF 是正常的流结束标志,不是错误
                if err.Error() != "EOF" {
                    log.Printf("流式请求失败:%v", err)
                }
                break
            }
            print(chunk.Content)
            fullResponse += chunk.Content
        }

        // 将模型响应添加到聊天历史(保持上下文)
        chatHistory = append(chatHistory, schema.AssistantMessage(fullResponse, nil))

        // 输出结果
        println()
        println("------------------------------")
    }

    // 检查Scanner错误
    if err := scanner.Err(); err != nil {
        log.Printf("读取用户输入失败:%v", err)
    }
}