vault backup: 2026-04-29 18:54:02
This commit is contained in:
@@ -1,30 +1,27 @@
|
||||
---
|
||||
Description: ""
|
||||
date: "2026-03-12"
|
||||
lastmod: ""
|
||||
tags: []
|
||||
tags: [eino, ai-development, go, quickstart, memory, session]
|
||||
create time: 2026-04-29 15:30
|
||||
title: 第三章:Memory 与 Session(持久化对话)
|
||||
weight: 3
|
||||
---
|
||||
|
||||
本章目标:实现对话历史的持久化存储,支持跨进程恢复会话。
|
||||
## 概述
|
||||
|
||||
> **⚠️ 重要说明:业务层概念 vs 框架概念**
|
||||
在第二章掌握了多轮对话的实现后,我们面临一个关键问题:**对话历史只存在于内存中,进程退出后一切归零**。本章引入 **Memory 与 Session** 机制,让对话历史能够持久化保存并跨进程恢复,为构建真正的智能助手奠定基础。
|
||||
|
||||
> 本章介绍的 **Memory、Session、Store 是业务层概念**,**不是 Eino 框架的核心组件**。
|
||||
|
||||
>
|
||||
|
||||
> 换句话说,Eino 框架只负责"如何处理消息",而"如何存储消息"完全由业务层决定。本章提供的实现只是一个简单的参考示例,你可以根据自己的业务需求选择完全不同的存储方案(数据库、Redis、云存储等)。
|
||||
> [!warning] 重要概念区分:业务层 vs 框架层
|
||||
> 本章介绍的 **Memory、Session、Store 是业务层概念**,**不是 Eino 框架的核心组件**。Eino 框架只负责"如何处理消息",而"如何存储消息"完全由业务层决定。本章提供的实现只是一个参考示例,你可以根据自己的需求选择数据库、Redis、云存储等方案。
|
||||
|
||||
## 代码位置
|
||||
|
||||
- 入口代码:[cmd/ch03/main.go](https://github.com/cloudwego/eino-examples/blob/main/quickstart/chatwitheino/cmd/ch03/main.go)
|
||||
- Memory 实现:[mem/store.go](https://github.com/cloudwego/eino-examples/blob/main/quickstart/chatwitheino/mem/store.go)
|
||||
- Store 实现:[mem/store.go](https://github.com/cloudwego/eino-examples/blob/main/quickstart/chatwitheino/mem/store.go)
|
||||
|
||||
---
|
||||
|
||||
## 前置条件
|
||||
|
||||
与第一章一致:需要配置一个可用的 ChatModel(OpenAI 或 Ark)。
|
||||
与第二章一致:需要配置一个可用的 ChatModel(OpenAI 或 Ark)。
|
||||
|
||||
## 运行
|
||||
|
||||
@@ -53,9 +50,15 @@ Session saved: 083d16da-6b13-4fe6-afb0-c45d8f490ce1
|
||||
Resume with: go run ./cmd/ch03 --session 083d16da-6b13-4fe6-afb0-c45d8f490ce1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
<!-- @block-anchor:overview:start -->
|
||||
<!-- @block-anchor:overview:end -->
|
||||
|
||||
## 从内存到持久化:为什么需要 Memory
|
||||
|
||||
第二章我们实现了多轮对话,但有一个问题:**对话历史只存在于内存中**。
|
||||
> [!question] 思考一下
|
||||
> 第二章我们实现了多轮对话,但存在一个问题——如果进程退出、机器重启,之前聊的内容还会在吗?
|
||||
|
||||
**内存存储的局限:**
|
||||
|
||||
@@ -71,12 +74,17 @@ Resume with: go run ./cmd/ch03 --session 083d16da-6b13-4fe6-afb0-c45d8f490ce1
|
||||
|
||||
**简单类比:**
|
||||
|
||||
- **内存存储** = "草稿纸"(进程退出就没了)
|
||||
- **Memory** = "笔记本"(永久保存,随时翻阅)
|
||||
| 方式 | 比喻 | 特点 |
|
||||
|------|------|------|
|
||||
| 内存存储 | "草稿纸" | 进程退出就没了 |
|
||||
| Memory | "笔记本" | 永久保存,随时翻阅 |
|
||||
|
||||
---
|
||||
|
||||
## 关键概念
|
||||
|
||||
> **再次强调**:以下 Session、Store 等概念都是**业务层实现**,用于管理对话历史的存储。Eino 框架本身不提供这些组件,而是由业务层负责管理消息列表,然后将消息传递给 `adk.Runner` 进行处理。
|
||||
> [!tip] 重要提示
|
||||
> 以下 Session、Store 等概念都是**业务层实现**,用于管理对话历史的存储。Eino 框架本身不提供这些组件,而是由业务层负责管理消息列表,然后将消息传递给 `adk.Runner` 进行处理。
|
||||
|
||||
### Session(业务层概念)
|
||||
|
||||
@@ -129,10 +137,12 @@ type Store struct {
|
||||
|
||||
**为什么用 JSONL?**
|
||||
|
||||
- **简单**:每行一个 JSON 对象,易于读写
|
||||
- **可扩展**:可以追加新消息,无需重写整个文件
|
||||
- **可读性好**:可以用文本编辑器直接查看
|
||||
- **容错性强**:单行损坏不影响其他行
|
||||
| 特性 | 说明 |
|
||||
|------|------|
|
||||
| **简单** | 每行一个 JSON 对象,易于读写 |
|
||||
| **可扩展** | 可以追加新消息,无需重写整个文件 |
|
||||
| **可读性好** | 可以用文本编辑器直接查看 |
|
||||
| **容错性强** | 单行损坏不影响其他行 |
|
||||
|
||||
## Memory 的实现(业务层示例)
|
||||
|
||||
@@ -184,134 +194,137 @@ if err := session.Append(assistantMsg); err != nil {
|
||||
}
|
||||
```
|
||||
|
||||
**关键代码片段(**注意:这是简化后的代码片段,不能直接运行,完整代码请参考** [cmd/ch03/main.go](https://github.com/cloudwego/eino-examples/blob/main/quickstart/chatwitheino/cmd/ch03/main.go)):
|
||||
### 关键代码解析
|
||||
|
||||
完整流程可以浓缩为以下核心片段:
|
||||
|
||||
```go
|
||||
// 创建或恢复 Session
|
||||
// 1. 创建或恢复 Session
|
||||
session, err := store.GetOrCreate(sessionID)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 用户输入
|
||||
// 2. 读取用户输入并追加到会话
|
||||
userMsg := schema.UserMessage(line)
|
||||
if err := session.Append(userMsg); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 调用 Agent
|
||||
// 3. 获取全部历史,送入 Agent 处理
|
||||
history := session.GetMessages()
|
||||
events := runner.Run(ctx, history)
|
||||
content := collectAssistantFromEvents(events)
|
||||
|
||||
// 保存助手回复
|
||||
// 4. 收集回复并存回会话
|
||||
assistantMsg := schema.AssistantMessage(content, nil)
|
||||
if err := session.Append(assistantMsg); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
|
||||
> [!note] 简化说明
|
||||
> 以上代码已省略错误处理之外的细节(如命令行参数解析、事件流消费等),不能直接运行。完整代码请参考 [cmd/ch03/main.go](https://github.com/cloudwego/eino-examples/blob/main/quickstart/chatwitheino/cmd/ch03/main.go)。
|
||||
|
||||
## Session 与 Agent 的关系:业务层与框架层的协作
|
||||
|
||||
**关键理解:**
|
||||
> [!tip] 理解要点
|
||||
> - **Session 是业务层概念**:由你的代码实现和管理,负责存储和加载对话历史
|
||||
> - **Agent(Runner)是框架层概念**:由 Eino 框架提供,负责处理消息并生成回复
|
||||
> - **两者的交互点**:业务层通过 `session.GetMessages()` 获取消息列表,传递给 `runner.Run(ctx, history)` 进行处理
|
||||
|
||||
- **Session 是业务层概念**:由业务代码实现和管理,负责存储和加载对话历史
|
||||
- **Agent(Runner)是框架层概念**:由 Eino 框架提供,负责处理消息并生成回复
|
||||
- **两者的交互点**:业务层通过 `session.GetMessages()` 获取消息列表,传递给 `runner.Run(ctx, history)` 进行处理
|
||||
**数据流示意图:**
|
||||
|
||||
**架构分层:**
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A["用户输入"] --> B["session.Append()<br/>保存用户消息"]
|
||||
B --> C["session.GetMessages()<br/>获取完整历史"]
|
||||
C --> D["runner.Run(history)<br/>Agent 处理消息"]
|
||||
D --> E["收集助手回复"]
|
||||
E --> F["session.Append()<br/>保存助手消息"]
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 业务层(你的代码) │
|
||||
│ ┌─────────────┐ ┌──────────────┐ ┌───────────────┐ │
|
||||
│ │ Session │───→│ GetMessages() │───→│ runner.Run() │ │
|
||||
│ │ (存储) │ │ (消息列表) │ │ (框架调用) │ │
|
||||
│ └─────────────┘ └──────────────┘ └───────────────┘ │
|
||||
│ ↑ │ │
|
||||
│ │ ↓ │
|
||||
│ ┌─────────────┐ ┌───────────────┐ │
|
||||
│ │ Append() │←─────────────────────│ 助手回复 │ │
|
||||
│ │ (保存消息) │ └───────────────┘ │
|
||||
│ └─────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ 框架层(Eino 框架) │
|
||||
│ ┌───────────────────────────────────────────────────────┐ │
|
||||
│ │ adk.Runner:接收消息列表,调用 ChatModel,返回回复 │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
style B fill:#e8f5e9
|
||||
style C fill:#e8f5e9
|
||||
style F fill:#e8f5e9
|
||||
style D fill:#fff3e0
|
||||
```
|
||||
|
||||
**流程图:**
|
||||
**分层面貌:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────┐
|
||||
│ 用户输入 │
|
||||
└─────────────────────────────────────────┘
|
||||
↓
|
||||
┌──────────────────────┐
|
||||
│ session.Append() │
|
||||
│ 保存用户消息 │
|
||||
└──────────────────────┘
|
||||
↓
|
||||
┌──────────────────────┐
|
||||
│ session.GetMessages()│
|
||||
│ 获取完整历史 │
|
||||
└──────────────────────┘
|
||||
↓
|
||||
┌──────────────────────┐
|
||||
│ runner.Run(history) │
|
||||
│ Agent 处理消息 │
|
||||
└──────────────────────┘
|
||||
↓
|
||||
┌──────────────────────┐
|
||||
│ 收集助手回复 │
|
||||
└──────────────────────┘
|
||||
↓
|
||||
┌──────────────────────┐
|
||||
│ session.Append() │
|
||||
│ 保存助手消息 │
|
||||
└──────────────────────┘
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph biz_layer["业务层 — 你的代码"]
|
||||
S1["Session<br/>持久化存储"]
|
||||
S2["GetMessages()"]
|
||||
S3["Append()<br/>保存消息"]
|
||||
S1 --> S2
|
||||
S3 -.->|"回写"| S1
|
||||
end
|
||||
|
||||
subgraph frame_layer["框架层 — Eino"]
|
||||
R1["runner.Run()"]
|
||||
end
|
||||
|
||||
S2 --> R1
|
||||
R1 -->|"助手回复"| S3
|
||||
|
||||
style S1 fill:#e3f2fd
|
||||
style S2 fill:#e3f2fd
|
||||
style S3 fill:#e3f2fd
|
||||
style R1 fill:#fff3e0
|
||||
style biz_layer fill:none,stroke:#90caf9
|
||||
style frame_layer fill:none,stroke:#ffcc80
|
||||
```
|
||||
|
||||
## 本章小结
|
||||
|
||||
**框架层 vs 业务层:**
|
||||
| 核心概念 | 定位 | 说明 |
|
||||
|----------|------|------|
|
||||
| **Memory** | 业务层 | 对话历史的持久化存储,支持跨进程恢复 |
|
||||
| **Session** | 业务层 | 一次完整的对话会话,包含 ID、创建时间、消息列表 |
|
||||
| **Store** | 业务层 | 管理多个 Session 的存储,支持创建、获取、列表、删除 |
|
||||
| **JSONL 格式** | 业务层 | 简单的文件格式,易于读写和扩展 |
|
||||
| **adk.Runner** | 框架层 | 接收消息列表,调用 ChatModel,返回回复 |
|
||||
|
||||
- **Eino 框架层**:提供 `adk.Runner`、`schema.Message` 等基础抽象,不关心消息如何存储
|
||||
- **业务层(本章实现)**:Memory/Session/Store 是业务层概念,用于管理对话历史的存储
|
||||
> [!success] 学习成果
|
||||
> 完成本章后,你应该能够:
|
||||
> - 理解 Memory/Session/Store 的业务层职责
|
||||
> - 知道如何将对话历史持久化为 JSONL 文件
|
||||
> - 明白业务层与框架层的协作边界
|
||||
> - 根据业务需求选择合适的存储方案
|
||||
|
||||
**业务层概念:**
|
||||
|
||||
- **Memory**:对话历史的持久化存储,支持跨进程恢复
|
||||
- **Session**:一次完整的对话会话,包含 ID、创建时间、消息列表
|
||||
- **Store**:管理多个 Session 的存储,支持创建、获取、列表、删除
|
||||
- **JSONL 格式**:简单的文件格式,易于读写和扩展
|
||||
|
||||
**业务层与框架层的交互:**
|
||||
|
||||
- 业务层负责存储消息,通过 `session.GetMessages()` 获取消息列表
|
||||
- 将消息列表传递给框架层的 `runner.Run(ctx, history)` 进行处理
|
||||
- 收集框架层返回的回复,再由业务层保存到存储中
|
||||
|
||||
> **💡 提示**:本章的实现只是众多存储方案中的一种简单示例。在实际项目中,你可以根据业务需求选择数据库、Redis、云存储等方案,甚至可以实现更复杂的功能如会话过期清理、搜索、分享等。
|
||||
---
|
||||
|
||||
## 扩展思考:业务层存储方案的选择
|
||||
|
||||
本章提供的 JSONL 文件存储方案适合简单的单机应用。在实际业务中,你可能需要考虑其他存储方案:
|
||||
|
||||
**其他存储实现:**
|
||||
<table>
|
||||
<tr><td>存储方案</td><td>适用场景</td><td>优势</td><td>劣势</td></tr>
|
||||
<tr><td><strong>JSONL 文件</strong></td><td>单机应用、开发调试</td><td>零依赖,简单直观</td><td>不支持并发、分布式</td></tr>
|
||||
<tr><td><strong>SQLite / LevelDB</strong></td><td>桌面端应用</td><td>轻量级嵌入式数据库</td><td>不适合高并发写入</td></tr>
|
||||
<tr><td><strong>MySQL / PostgreSQL</strong></td><td>服务端部署</td><td>成熟稳定,功能丰富</td><td>运维成本较高</td></tr>
|
||||
<tr><td><strong>Redis</strong></td><td>分布式、高频访问</td><td>性能极高,支持过期策略</td><td>数据需额外持久化</td></tr>
|
||||
<tr><td><strong>S3 / OSS</strong></td><td>海量冷数据归档</td><td>成本极低,无限扩展</td><td>不适合频繁查询</td></tr>
|
||||
</table>
|
||||
|
||||
- 数据库存储(MySQL、PostgreSQL、MongoDB)
|
||||
- Redis 存储(支持分布式)
|
||||
- 云存储(S3、OSS)
|
||||
**高级功能展望:**
|
||||
|
||||
**高级功能:**
|
||||
- 会话过期清理(TTL 自动删除)
|
||||
- 会话全文搜索
|
||||
- 会话导出 / 导入
|
||||
- 会话分享(生成公开链接)
|
||||
|
||||
- 会话过期清理
|
||||
- 会话搜索
|
||||
- 会话导出/导入
|
||||
- 会话分享
|
||||
> [!tip] Middleware 联动
|
||||
> 当对话非常长时,单纯增加存储容量是不够的。第五章介绍的 **Summarization Middleware** 可以在调用 Agent 之前自动压缩历史消息,有效控制 Token 消耗。
|
||||
|
||||
---
|
||||
|
||||
## 下一章预告
|
||||
|
||||
[[Eino/quick_start/chapter_04_tool_and_filesystem|第四章:Tool 与文件系统]] 将为 Agent 添加文件访问能力,让智能助手能够读取代码仓库中的真实内容。
|
||||
|
||||
## 关联笔记
|
||||
|
||||
- [[Eino/quick_start/chapter_02_chatmodelagent_runner_agentevent]]
|
||||
- [[Eino/quick_start/chapter_04_tool_and_filesystem]]
|
||||
|
||||
Reference in New Issue
Block a user