You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
eino-examples/quickstart/chatwithdoc/docs/ch01_chatmodel_agent_consol...

140 lines
4.3 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
title: "第一章ChatModel 与 MessageConsole"
---
本章目标:理解 Eino 的 Component 抽象,用最小代码调用一次 ChatModel支持流式输出并掌握 `schema.Message` 的基本用法。
## 代码位置
- 入口代码:[cmd/ch01/main.go](https://github.com/cloudwego/eino/blob/main/examples/quickstart/chatwithdoc/cmd/ch01/main.go)
## 为什么需要 Component 接口
Eino 定义了一组 Component 接口(`ChatModel`、`Tool`、`Retriever`、`Loader` 等),每个接口描述一类可替换的能力:
```go
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)
}
```
**接口带来的好处:**
1. **实现可替换**`eino-ext` 提供了 OpenAI、Ark、Claude、Ollama 等多种实现,业务代码只依赖接口,切换模型只需改构造逻辑。
2. **编排可组合**Agent、Graph、Chain 等编排层只依赖 Component 接口,不关心具体实现。你可以把 OpenAI 换成 Ark编排代码无需改动。
3. **测试可 Mock**:接口天然支持 mock单元测试不需要真实调用模型。
本章只涉及 `ChatModel`,后续章节会逐步引入 `Tool`、`Retriever` 等 Component。
## schema.Message对话的基本单位
`Message` 是 Eino 里对话数据的基本结构:
```go
type Message struct {
Role RoleType // system / user / assistant / tool
Content string // 文本内容
ToolCalls []ToolCall // 仅 assistant 消息可能有
// ...
}
```
常用构造函数:
```go
schema.SystemMessage("You are a helpful assistant.")
schema.UserMessage("What is the weather today?")
schema.AssistantMessage("I don't know.", nil) // 第二个参数是 ToolCalls
schema.ToolMessage("tool result", "call_id")
```
**角色语义:**
- `system`:系统指令,通常放在 messages 最前面
- `user`:用户输入
- `assistant`:模型回复
- `tool`:工具调用结果(后续章节涉及)
## 前置条件
- Go 版本:与本目录 `go.mod` 一致
- 一个可调用的 ChatModel默认使用 OpenAI也支持 Ark
### 方式 AOpenAI默认
```bash
export OPENAI_API_KEY="..."
export OPENAI_MODEL="gpt-4.1-mini"
# 可选:
# OPENAI_BASE_URL代理或兼容服务
# OPENAI_BY_AZURE=true使用 Azure OpenAI
```
### 方式 BArk
```bash
export MODEL_TYPE="ark"
export ARK_API_KEY="..."
export ARK_MODEL="..."
# 可选ARK_BASE_URL
```
## 运行
`examples/quickstart/chatwithdoc` 目录下执行:
```bash
go run ./cmd/ch01 -- "用一句话解释 Eino 的 Component 设计解决了什么问题?"
```
输出示例(流式逐步打印):
```text
[assistant] Eino 的 Component 设计通过定义统一接口...
```
## 入口代码做了什么
按执行顺序:
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/blob/main/examples/quickstart/chatwithdoc/cmd/ch01/main.go)
```go
// 构造输入
messages := []*schema.Message{
schema.SystemMessage(instruction),
schema.UserMessage(query),
}
// 调用 Stream所有 ChatModel 都必须实现)
stream, err := cm.Stream(ctx, messages)
if err != nil {
log.Fatal(err)
}
defer stream.Close()
for {
chunk, err := stream.Recv()
if errors.Is(err, io.EOF) {
break
}
if err != nil {
log.Fatal(err)
}
fmt.Print(chunk.Content)
}
```
## 本章小结
- **Component 接口**:定义可替换、可组合、可测试的能力边界
- **Message**:对话数据的基本单位,通过角色区分语义
- **ChatModel**:最基础的 Component提供 `Generate``Stream` 两个核心方法
- **实现选择**:通过环境变量或配置切换 OpenAI/Ark 等不同实现,业务代码无需改动