vault backup: 2026-04-29 18:54:02
This commit is contained in:
@@ -1,14 +1,23 @@
|
||||
---
|
||||
Description: ""
|
||||
tags: [eino, ai-development, go, quickstart]
|
||||
create time: 2026-04-29 14:30
|
||||
date: "2026-03-24"
|
||||
lastmod: ""
|
||||
tags: []
|
||||
title: 第一章:ChatModel 与 Message(Console)
|
||||
weight: 1
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
本章是 Eino 快速入门系列的第一章,带你理解 Eino 的 Component 抽象设计,并通过最简代码实现一次 ChatModel 调用(支持流式输出)。你将掌握 `schema.Message` 的基本用法,为后续构建完整的 ChatWithEino Agent 打下基础。
|
||||
|
||||
---
|
||||
|
||||
## Eino 框架简介
|
||||
|
||||
> [!question] 思考一下
|
||||
> 如果你要开发一个 AI 应用,需要支持 OpenAI、Claude、豆包等多个模型,你会如何设计代码架构才能让切换模型变得简单?
|
||||
|
||||
**Eino 是什么?**
|
||||
|
||||
Eino 是一个 Go 语言实现的 AI 应用开发框架(Agent Development Kit),旨在帮助开发者快速构建可扩展、可维护的 AI 应用。
|
||||
@@ -103,8 +112,35 @@ type BaseChatModel interface {
|
||||
|
||||
本章只涉及 `ChatModel`,后续章节会逐步引入 `Tool`、`Retriever` 等 Component。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
class Component {
|
||||
<<interface>>
|
||||
}
|
||||
class ChatModel {
|
||||
<<interface>>
|
||||
+Generate()
|
||||
+Stream()
|
||||
}
|
||||
class Tool {
|
||||
<<interface>>
|
||||
+Execute()
|
||||
}
|
||||
class Retriever {
|
||||
<<interface>>
|
||||
+Retrieve()
|
||||
}
|
||||
Component <|-- ChatModel
|
||||
Component <|-- Tool
|
||||
Component <|-- Retriever
|
||||
note for ChatModel "本章重点学习"
|
||||
```
|
||||
|
||||
## schema.Message:对话的基本单位
|
||||
|
||||
> [!tip] 核心概念
|
||||
> `Message` 是 Eino 对话系统的基石。理解 Message 的结构和角色语义,是掌握整个对话流程的关键。
|
||||
|
||||
`Message` 是 Eino 里对话数据的基本结构:
|
||||
|
||||
```go
|
||||
@@ -116,6 +152,16 @@ type Message struct {
|
||||
}
|
||||
```
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[Message] --> B[Role]
|
||||
A --> C[Content]
|
||||
A --> D[ToolCalls]
|
||||
B --> E["system / user / assistant / tool"]
|
||||
C --> F["文本内容"]
|
||||
D --> G["工具调用指令"]
|
||||
```
|
||||
|
||||
常用构造函数:
|
||||
|
||||
```go
|
||||
@@ -127,10 +173,15 @@ schema.ToolMessage("tool result", "call_id")
|
||||
|
||||
**角色语义:**
|
||||
|
||||
- `system`:系统指令,通常放在 messages 最前面
|
||||
- `user`:用户输入
|
||||
- `assistant`:模型回复
|
||||
- `tool`:工具调用结果(后续章节涉及)
|
||||
| 角色 | 用途 | 典型位置 |
|
||||
|------|------|----------|
|
||||
| `system` | 系统指令,定义模型行为 | messages 最前面 |
|
||||
| `user` | 用户输入 | 交替出现 |
|
||||
| `assistant` | 模型回复 | 交替出现 |
|
||||
| `tool` | 工具调用结果 | 工具调用后(后续章节) |
|
||||
|
||||
> [!warning] 常见错误
|
||||
> 注意 `system` 消息应该放在 messages 数组的最前面,而不是中间或末尾。这是大多数 LLM 的要求。
|
||||
|
||||
## 前置条件
|
||||
|
||||
@@ -181,42 +232,77 @@ go run ./cmd/ch01 -- "用一句话解释 Eino 的 Component 设计解决了什
|
||||
|
||||
按执行顺序:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[开始] --> B[创建 ChatModel]
|
||||
B --> C["构造 messages 数组"]
|
||||
C --> D[调用 Stream 方法]
|
||||
D --> E{接收数据块}
|
||||
E -->|EOF| F[结束]
|
||||
E -->|有数据| G[打印 chunk.Content]
|
||||
G --> E
|
||||
```
|
||||
|
||||
1. **创建 ChatModel**:根据 `MODEL_TYPE` 环境变量选择 OpenAI 或 Ark 实现
|
||||
2. **构造输入 messages**:`SystemMessage(instruction)` + `UserMessage(query)`
|
||||
3. **调用 Stream**:所有 ChatModel 实现都必须支持 `Stream()`,返回 `StreamReader[*Message]`
|
||||
4. **打印结果**:迭代 `StreamReader` 逐帧打印 assistant 回复
|
||||
|
||||
关键代码片段(**注意:这是简化后的代码片段,不能直接运行****,完整代码请参考** [cmd/ch01/main.go](https://github.com/cloudwego/eino-examples/blob/main/quickstart/chatwitheino/cmd/ch01/main.go)):
|
||||
关键代码片段(**注意:这是简化后的代码片段,不能直接运行,完整代码请参考** [cmd/ch01/main.go](https://github.com/cloudwego/eino-examples/blob/main/quickstart/chatwitheino/cmd/ch01/main.go)):
|
||||
|
||||
```go
|
||||
// 构造输入
|
||||
// 1. 构造输入消息数组
|
||||
// system 消息定义模型行为,user 消息包含用户问题
|
||||
messages := []*schema.Message{
|
||||
schema.SystemMessage(instruction),
|
||||
schema.UserMessage(query),
|
||||
schema.SystemMessage(instruction), // 系统指令
|
||||
schema.UserMessage(query), // 用户输入
|
||||
}
|
||||
|
||||
// 调用 Stream(所有 ChatModel 都必须实现)
|
||||
// 2. 调用 Stream 方法(所有 ChatModel 都必须实现)
|
||||
// 返回 StreamReader,用于逐块读取流式输出
|
||||
stream, err := cm.Stream(ctx, messages)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer stream.Close()
|
||||
defer stream.Close() // 确保资源释放
|
||||
|
||||
// 3. 循环接收流式数据
|
||||
for {
|
||||
chunk, err := stream.Recv()
|
||||
chunk, err := stream.Recv() // 读取下一个数据块
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
break // 流结束
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Print(chunk.Content)
|
||||
fmt.Print(chunk.Content) // 实时打印内容(不换行)
|
||||
}
|
||||
```
|
||||
|
||||
> [!note] 流式输出的优势
|
||||
> 使用 `Stream` 而不是 `Generate`,可以让用户更早看到响应,提升交互体验。这类似于 ChatGPT 的逐字显示效果。
|
||||
|
||||
## 本章小结
|
||||
|
||||
- **Component 接口**:定义可替换、可组合、可测试的能力边界
|
||||
- **Message**:对话数据的基本单位,通过角色区分语义
|
||||
- **ChatModel**:最基础的 Component,提供 `Generate` 和 `Stream` 两个核心方法
|
||||
- **实现选择**:通过环境变量或配置切换 OpenAI/Ark 等不同实现,业务代码无需改动
|
||||
| 核心概念 | 说明 | 本章要点 |
|
||||
|----------|------|----------|
|
||||
| **Component 接口** | 定义可替换、可组合、可测试的能力边界 | 通过接口实现解耦,支持多模型切换 |
|
||||
| **Message** | 对话数据的基本单位,通过角色区分语义 | 使用构造函数创建消息 |
|
||||
| **ChatModel** | 最基础的 Component | 提供 `Generate` 和 `Stream` 方法 |
|
||||
| **实现选择** | 通过环境变量或配置切换不同实现 | 业务代码无需改动 |
|
||||
|
||||
> [!success] 学习成果
|
||||
> 完成本章后,你应该能够:
|
||||
> - 理解 Eino 的 Component 设计理念
|
||||
> - 使用 ChatModel 进行单次对话调用
|
||||
> - 掌握 Message 的构造和使用方法
|
||||
> - 运行示例代码并观察流式输出
|
||||
|
||||
## 下一章预告
|
||||
|
||||
[[Eino/quick_start/chapter_02_agent_and_runner|第二章:Agent 与 Runner]] 将引入执行抽象,实现多轮对话和会话管理。
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[Eino/quick_start/chapter_02_agent_and_runner]]
|
||||
- [[Eino/README]]
|
||||
|
||||
Reference in New Issue
Block a user