eino-chap3-store
“框架层概念” vs “业务层概念”
一句话总结
- 框架层概念 = Eino 框架已经帮你写好的代码和抽象,你直接
import来用 - 业务层概念 = 你自己写的(或示例项目帮你写的)代码,用来满足你的具体业务需求
用一个生活类比来理解
想象你在用微信开发框架做一个聊天应用:
| 框架层(微信SDK提供) | 业务层(你自己写) | |
|---|---|---|
| 谁提供的 | 微信团队 | 你(开发者) |
| 举例 | 发送消息API、接收消息API | 聊天记录保存到数据库、用户管理 |
| 能不能换 | 不能换(框架就是这样设计的) | 随便换(用MySQL还是Redis你自己决定) |
| 所有人都一样吗 | 是的,所有开发者用同一套API | 不是,每个项目的业务逻辑都不同 |
在 Eino 项目中的具体对应
框架层概念(Eino 框架提供的)
这些是你 import 进来就能用的,所有使用 Eino 的项目都一样:
1 | import ( |
| 框架层概念 | 说明 | 代码中的体现 |
|---|---|---|
schema.Message |
消息的标准格式(角色+内容) | schema.UserMessage(line) |
adk.ChatModelAgent |
智能体抽象 | adk.NewChatModelAgent(...) |
adk.Runner |
Agent 的执行器 | runner.Run(ctx, history) |
adk.AgentEvent |
事件流中的事件单元 | events.Next() |
adk.AsyncIterator |
流式事件迭代器 | for { event, ok := events.Next() } |
这些东西是 Eino 框架的核心设计,你不需要自己实现,也不能随意修改它们的行为。
业务层概念(示例项目自己写的)
这些是 mem/store.go 中示例项目自己实现的代码:
1 | import ( |
| 业务层概念 | 说明 | 代码中的体现 |
|---|---|---|
mem.Store |
管理多个会话的存储 | store, err := mem.NewStore(sessionDir) |
mem.Session |
一次对话会话 | session, err := store.GetOrCreate(sessionID) |
session.Append() |
追加消息到会话 | session.Append(userMsg) |
session.GetMessages() |
获取历史消息 | history := session.GetMessages() |
| JSONL 文件格式 | 消息的存储格式 | 磁盘上的 .jsonl 文件 |
这些东西是这个示例项目自己设计的,Eino 框架完全不知道它们的存在。
从代码中直观感受
看 main.go 中对话循环的核心代码(第 95~117 行):
1 | // ========== 业务层:保存用户消息 ========== |
用一张流程图来看两层之间的边界:
1 | graph LR |
交接点就是 []*schema.Message(消息列表)——这是两层之间唯一的”通信协议”。
为什么要区分这两层?
核心原因:框架不应该替你决定业务细节
Eino 框架的设计哲学是:
框架只负责”如何处理消息”,不管”如何存储消息”。
这意味着:
| 问题 | 谁负责 | 为什么 |
|---|---|---|
| 消息怎么发给模型? | 框架层 | 所有项目都一样 |
| 流式输出怎么处理? | 框架层 | 所有项目都一样 |
| 对话历史存在哪里? | 业务层 | 每个项目不同 |
| 用什么格式存储? | 业务层 | 每个项目不同 |
| Session 怎么管理? | 业务层 | 每个项目不同 |
实际好处:业务层可以随意替换
本章用的是 JSONL 文件存储,但你完全可以换成其他方案,框架层的代码一行都不用改:
1 | // 方案 1:JSONL 文件(本章的实现) |
对比第二章和第三章
| 维度 | 第二章 (ch02) | 第三章 (ch03) |
|---|---|---|
| 历史存储 | history 变量(内存) |
session(JSONL 文件) |
| 进程退出后 | 历史丢失 | 历史保留 |
| 能否恢复会话 | ❌ 不能 | ✅ --session <id> 恢复 |
| 框架层代码 | runner.Run(ctx, history) |
runner.Run(ctx, history) |
| 框架层有变化吗? | — | 完全没变! |
注意最后一行:框架层的代码完全一样。变化的只是业务层——从”内存变量”换成了”JSONL 文件”。这就是分层的好处。
总结
| 框架层 | 业务层 | |
|---|---|---|
| 谁写的 | Eino 框架团队 | 你(开发者) |
| 在哪里 | github.com/cloudwego/eino/... |
你的项目代码(如 mem/store.go) |
| 能不能换 | 不能(框架的核心设计) | 随便换(JSONL→MySQL→Redis…) |
| 本章的例子 | adk.Runner、schema.Message、adk.AgentEvent |
mem.Store、mem.Session、JSONL 文件 |
| 职责 | 处理消息、调用模型、返回回复 | 存储消息、管理会话、持久化 |
一句话记住:框架管”算”,业务管”存”。两者通过 []*schema.Message(消息列表)这个”接口”连接起来。
All articles on this blog are licensed under CC BY-NC-SA 4.0 unless otherwise stated.