v1.7 Session 会话机制 + 多工作区隔离 + Reporter 抽象

This commit is contained in:
zhuyongxin
2026-05-29 14:09:12 +08:00
parent 3e91c7d0a1
commit e480c5c55e
6 changed files with 424 additions and 120 deletions
+25
View File
@@ -65,6 +65,31 @@ func main() {
## 版本历史
### v1.7 — Session 会话机制 + 多工作区隔离 + Reporter 抽象
#### 变更
- **Session 会话机制** — 新增 `Session` 结构体,维护完整的对话历史(`[]schema.Message`),通过 `RWMutex` 实现线程安全的并发读写。全局 `SessionManager` 支持多会话隔离(`GetOrCreate`),基于 `map[string]*Session` 路由
- **Working Memory 滑动窗口** — `GetWorkingMemory(limit)` 从后往前截取最近 N 条消息作为"短期工作记忆",并实现孤儿 ToolResult 防线:截断后若首条消息是孤立的工具响应(对应 ToolCall 已被丢弃),自动舍弃防止 API 400
- **Reporter 输出抽象** — 新增 `Reporter` 接口(`OnThinking` / `OnToolCall` / `OnToolResult` / `OnMessage`),将引擎输出与展现层解耦。`TerminalReporter` 是首个实现,引擎不再直接 `fmt.Printf`
- **WorkDir 从 Engine 下沉到 Session** — 引擎不再持有工作目录,WorkDir 跟随 Session 走。一个引擎实例可同时服务多个不同工作区的会话(多工作区复用单引擎)
- **Run 签名重构** — `Run(ctx, userPrompt)` → `Run(ctx, session, reporter)`,会话成为一等公民
- **引擎循环改造** — 每轮从 Session 的 Working Memory 构建上下文,工具执行结果实时 `Append` 回 Session,ReAct 循环结束后挂起等待人类下一条指令
#### 踩坑记录
| 问题 | 原因 | 解决 |
|---|---|---|
| 多会话并发操作同一目录文件冲突 | 两个 Session 的 WorkDir 相同,工具同时读写 | WorkDir 绑定 Session,不同会话指向不同工作区 |
| 截断 Working Memory 后 API 报 400 | 丢弃了携带 ToolCall 的 Assistant 消息,但留下了对应的 ToolResult | `GetWorkingMemory` 检测并丢弃首部的孤儿 ToolResult |
| `fmt.Printf` 无法适配飞书/钉钉/WebUI 等输出目标 | 引擎与终端输出硬耦合 | 抽象 Reporter 接口,`TerminalReporter` 仅为首个实现 |
#### 经验教训
1. **WorkDir 属于会话而非引擎** — 将工作目录从 Engine 移到 Session,一个引擎实例就能同时服务多个隔离的工作区(`project_front` / `project_back`),架构不变代码不变
2. **Working Memory 不是全量历史** — 大模型 API 有 context window 上限,截取最近 N 条消息既控制成本又保持对话连贯。截断时必须保证 ToolCall / ToolResult 成对存在,否则 API 直接报错
3. **Reporter 是引擎可移植的关键** — 引擎只负责"推理 + 调工具",不关心输出到哪里。CLI、飞书、WebUI 只需各自实现 Reporter 接口,引擎零改动
### v1.5 — Edit 工具 + 四级容错替换 + 多工具并发执行
#### 变更