实现一个最简 LLM 应用

本指南将帮助你快速上手使用 Eino 框架中的 ChatModel 构建一个简单的 LLM 应用。我们将通过实现一个"程序员鼓励师"的例子,来展示如何使用 ChatModel。

💡 本文中示例的代码片段详见:flow/eino-examples/quickstart/chatflow/eino-examples/quickstart/chat

ChatModel 简介

ChatModel 是 Eino 框架中对对话大模型的抽象,它提供了统一的接口来与不同的大模型服务(如 OpenAI、Ollama 等)进行交互。

组件更详细的介绍参考: Eino: ChatModel 使用说明

Messages 的结构和使用

在 Eino 中,对话是通过 schema.Message 来表示的,这是 Eino 对一个对话消息的抽象定义。每个 Message 包含以下重要字段:

  • Role: 消息的角色,可以是:
    • system: 系统指令,用于设定模型的行为和角色
    • user: 用户的输入
    • assistant: 模型的回复
    • tool: 工具调用的结果
  • Content: 消息的具体内容

实现程序员鼓励师

让我们通过实现一个程序员鼓励师来学习如何使用 ChatModel。这个助手不仅能提供技术建议,还能在程序员感到难过时给予心理支持。

1. 创建对话模板

Eino 提供了强大的模板化功能来构建要输入给大模型的消息:

  1. 模版渲染,支持三种模版格式:

    • FString:Python 风格的简单字符串格式化(例如:“你好,{name}!")
    • Jinja2:支持丰富表达式的 Jinja2 风格模板(例如:“你好,{{name}}!")
    • GoTemplate:Go 语言内置的 text/template 格式(例如:“你好,{{.name}}!")
  2. 消息占位符:支持插入一组消息(如对话历史)

// optional=false 表示必需的消息列表,在模版输入中找不到对应变量会报错
schema.MessagesPlaceholder("chat_history", false)

更详细的组件介绍可参考: Eino: ChatTemplate 使用说明

下面是完整的 FString 格式 + 消息占位符的对话模板创建及使用代码:

// template.go
package main

import (
    "context"
    "fmt"
    "log"

    "github.com/cloudwego/eino/components/prompt"
    "github.com/cloudwego/eino/schema"
)

func createTemplate() prompt.ChatTemplate {
    // 创建模板,使用 FString 格式
    return prompt.FromMessages(schema.FString,
       // 系统消息模板
       schema.SystemMessage("你是一个{role}。你需要用{style}的语气回答问题。你的目标是帮助程序员保持积极乐观的心态,提供技术建议的同时也要关注他们的心理健康。"),

       // 插入需要的对话历史(新对话的话这里不填)
       schema.MessagesPlaceholder("chat_history", true),

       // 用户消息模板
       schema.UserMessage("问题: {question}"),
    )
}

func createMessagesFromTemplate() ([]*schema.Message, error) {
    template := createTemplate()

    // 使用模板生成消息
    return template.Format(context.Background(), map[string]any{
       "role":     "程序员鼓励师",
       "style":    "积极、温暖且专业",
       "question": "我的代码一直报错,感觉好沮丧,该怎么办?",
       // 对话历史(这个例子里模拟两轮对话历史)
       "chat_history": []*schema.Message{
          schema.UserMessage("你好"),
          schema.AssistantMessage("嘿!我是你的程序员鼓励师!记住,每个优秀的程序员都是从 Debug 中成长起来的。有什么我可以帮你的吗?", nil),
          schema.UserMessage("我觉得自己写的代码太烂了"),
          schema.AssistantMessage("每个程序员都经历过这个阶段!重要的是你在不断学习和进步。让我们一起看看代码,我相信通过重构和优化,它会变得更好。记住,Rome wasn't built in a day,代码质量是通过持续改进来提升的。", nil),
       },
    })
}

// 输出结果
//func main() {
//    messages, err := createMessagesFromTemplate()
//    if err != nil {
//       log.Fatal(err)
//    }
//    fmt.Printf("formatted message: %v", messages)
//}
// formatted message: [system: 你是一个程序员鼓励师。你需要用积极、温暖且专业的语气回答问题。你的目标是帮助程序员保持积极乐观的心态,提供技术建议的同时也要关注他们的心理健康。 user: 你好 assistant: 嘿!我是你的程序员鼓励师!记住,每个优秀的程序员都是从 Debug 中成长起来的。有什么我可以帮你的吗? user: 我觉得自己写的代码太烂了 assistant: 每个程序员都经历过这个阶段!重要的是你在不断学习和进步。让我们一起看看代码,我相信通过重构和优化,它会变得更好。记住,Rome wasn't built in a day,代码质量是通过持续改进来提升的。 user: 问题: 我的代码一直报错,感觉好沮丧,该怎么办?]

2. 创建并使用 ChatModel

ChatModel 是 Eino 框架中最核心的组件之一,它提供了与各种大语言模型交互的统一接口。Eino 目前支持以下大语言模型的实现:

  • OpenAI:支持 GPT-3.5/GPT-4 等模型 (同样支持 azure 提供的 openai 服务)
  • Ollama:支持本地部署的开源模型
  • Ark:火山引擎上的模型服务 (例如字节的豆包大模型)
  • 更多模型正在支持中

支持的模型可以参考:Eino: 生态集成

下面我们以 OpenAI 和 Ollama 为例,展示如何创建和使用 ChatModel:

使用 OpenAI (和下方 ollama 2 选 1)

import (
    "context"
    "fmt"
    
    "github.com/cloudwego/eino-ext/components/model/openai"
)

func main() {
    messages, err := createMessagesFromTemplate()
    if err != nil {
       log.Fatal(err)
    }
    // 创建 OpenAI ChatModel, 假设使用 openai 官方服务。
    chatModel, err := openai.NewChatModel(context.Background(), &openai.ChatModelConfig{
       Model:  "gpt-4o",         // 使用的模型版本
       APIKey: "<your-api-key>", // OpenAI API 密钥
    })
    if err != nil {
       log.Fatal(err)
    }

    // 使用 Generate 获取完整回复
    response, err := chatModel.Generate(context.Background(), messages)
    if err != nil {
       log.Fatal(err)
    }

    fmt.Println(response.Content) 
    // 输出模型回复
    //完全理解你的感受,调试代码有时候会让人倍感挫折。然而,这也是学习和成长的绝佳机会。首先,深呼吸,给自己一点时间放松一下。然后,我们可以循序渐进地解决问题:
    //
    //1. **阅读错误信息**:它通常会给出很有用的线索,告诉你出错的文件、行数以及可能的原因。
    //
    //2. **检查最近的更改**:有时候最近的修改可能导致了错误。
    //
    //3. **分而治之**:把问题分解成小部分,逐步检查代码,看看哪里可能出了错。
    //
    //4. **利用调试器**:调试器是程序员的好朋友,可以让你一步一步运行代码观察变量的变化。
    //
    //5. **寻求帮助**:别忘了,编程社区是非常乐于助人的,你总能在像Stack Overflow这样的论坛上找到有人遇到过类似的问题。
    //
    //最后,不要对自己太苛刻,每次解决一个错误,你都在成为更强的程序员。你一定可以克服这个困难的!加油!🌟
}

OpenAI ChatModel 的详细信息可以参考:ChatModel - OpenAI

使用 Ollama(和上方 openai 2 选 1)

Ollama 支持在本地运行开源模型,适合对数据隐私有要求或需要离线使用的场景。

import (
    "context"
    "fmt"
    
    "github.com/cloudwego/eino-ext/components/model/ollama"
)

func main() {
    messages, err := createMessagesFromTemplate()
    if err != nil {
       _log_.Fatal(err)
    }
    // 创建 Ollama ChatModel
    chatModel, err := ollama.NewChatModel(context.Background(), &ollama.ChatModelConfig{
        BaseURL: "http://localhost:11434", // Ollama 服务地址
        Model: "llama2",                   // 模型名称
    })
    if err != nil {
        log.Fatal(err)
    }
    
    // 使用 Generate 获取完整回复
    response, err := chatModel.Generate(context.Background(), messages)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(response.Content)  // 输出模型回复
}

OpenAI 相关信息,可以参考:ChatModel - Ollama

无论使用哪种实现,ChatModel 都提供了一致的接口,这意味着你可以轻松地在不同的模型之间切换,而无需修改大量代码。

3. 处理流式响应

在实际应用中,有很多场景需要使用流式响应,主要的场景例如「提升用户体验」:像 ChatGPT 一样逐字输出,让用户能够更早看到响应开始。

对于需要流式输出的场景,可以使用 ChatModel 的 Stream 方法:

import (
    "context"
    "fmt"
    "io"
    "log"

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

func main() {
    messages, err := createMessagesFromTemplate()
    if err != nil {
       _log_.Fatal(err)
    }
    // 创建 OpenAI ChatModel, 假设使用 openai 官方服务。
    chatModel, err := _openai_.NewChatModel(_context_.Background(), &_openai_._ChatModelConfig_{
       Model:  "gpt-4o",         // 使用的模型版本
       APIKey: "<your-api-key>", // OpenAI API 密钥
    })
    if err != nil {
       _log_.Fatal(err)
    }


    // 使用 Stream 获取流式响应
    stream, err := chatModel.Stream(context.Background(), messages)
    if err != nil {
        log.Fatal(err)
    }
    
    // 处理流式响应
    for {
        chunk, err := stream.Recv()
        if err == io.EOF {
            // stream结束
            break
        }
        if err != nil {
            log.Fatal(err)
        }
        
        // 处理响应片段
        fmt.Print(chunk.Content)
    }
}

总结

本示例通过一个程序员鼓励师的案例,展示了如何使用 Eino 框架构建 LLM 应用。从 ChatModel 的创建到消息模板的使用,再到实际的对话实现,相信你已经对 Eino 框架有了基本的了解。无论是选择 OpenAI、Ollama 还是其他模型实现,Eino 都提供了统一且简单的使用方式。希望这个示例能帮助你快速开始构建自己的 LLM 应用。

关联阅读


最后修改 January 20, 2025 : update (18ca48e)