Version: 0.5.5.dev.260314

🚀 更新了 README 中的 Mermaid 图,确保与当前随口记的业务链路一致。
📚 新增了功能决策记录(docs/功能决策记录),并且记录了此次 AI 随口记功能的工程决策。
This commit is contained in:
Losita
2026-03-14 18:19:11 +08:00
parent 0b7d1b999c
commit 21d6fe5b5f
3 changed files with 202 additions and 28 deletions

View File

@@ -358,44 +358,51 @@ $$Gap = \frac{TotalAvailableSlots - (TaskCount \times 2)}{TaskCount + 1}$$
flowchart TD
A[用户消息进入 /agent/chat] --> B[规范会话ID + 选模型]
B --> C[确保会话存在<br/>Redis会话状态检查<br/>必要时回源DB创建]
C --> D[quick_note.request.accepted<br/>推送reasoning状态块]
D --> E[意图识别节点<br/>quick_note.intent.analyzing]
E --> F{是否随口记意图}
F -- --> X[回落普通聊天链路]
F -- 是 --> G[时间抽取与校验<br/>quick_note.deadline.validating]
G --> H{时间是否有效}
H -- 否 --> I[返回纠错文案<br/>不写库<br/>quick_note.failed]
H -- 是 --> J[优先级评估<br/>quick_note.priority.evaluating]
J --> K[调用写库工具<br/>quick_note.persisting]
K --> L{写入是否成功}
L -- --> M[按重试策略处理<br/>最终失败则返回错误文案]
L -- --> N[quick_note.persisted]
N --> O[quick_note.reply.polishing<br/>AI生成贴题轻松跟进句]
O --> P[拼接最终正文<br/>一次性content输出]
P --> Q[后置持久化<br/>user+assistant写Redis<br/>并写outbox/DB]
C --> D[模型控制码路由<br/>action=quick_note/chat]
D --> E{route是否命中quick_note}
E -- 否 --> X[普通聊天链路<br/>StreamChat流式输出]
E -- --> F[quick_note.request.accepted<br/>推送reasoning状态块]
F --> G[跳过二次意图判定<br/>直接进入聚合规划]
G --> H[单请求聚合规划<br/>生成title/deadline/priority/banter]
H --> I[时间校验<br/>quick_note.deadline.validating]
I --> J{时间是否有效}
J -- 否 --> K[返回纠错文案<br/>不写库<br/>quick_note.failed]
J -- 是 --> L{优先级是否有效}
L -- --> M[复用聚合优先级]
L -- --> N[本地优先级兜底<br/>不再二次调用模型]
M --> O[调用写库工具<br/>quick_note.persisting]
N --> O
O --> P{task_id是否有效}
P -- 否 --> Q[按重试策略处理<br/>最终返回失败文案]
P -- 是 --> R[quick_note.persisted]
R --> S[拼接最终正文<br/>优先复用聚合banter<br/>一次性content输出]
S --> T[后置持久化<br/>user+assistant写Redis<br/>并写outbox/DB]
X --> T
```
### 2) 总分流图(消息识别后的去向)
```mermaid
flowchart TD
A[用户消息进入 AgentChat] --> B{是否命中任务/提醒关键词}
A[用户消息进入 AgentChat] --> B[模型控制码路由<br/>action=quick_note/chat]
B --> C{路由是否成功解析}
B -- --> C[尝试随口记graph静默]
C --> D{是随口记意图?}
D -- 是 --> E[执行随口记写库链路<br/>返回一次性正文]
D -- 否 --> F[普通聊天链路<br/>StreamChat token流式输出]
C -- --> D{action=quick_note?}
D -- 否 --> E[普通聊天链路<br/>StreamChat token流式输出]
D -- 是 --> F[随口记快路径<br/>跳过二次意图判定]
F --> G[单请求聚合规划<br/>+本地时间校验/优先级兜底]
G --> H[写库工具落库<br/>task_id有效校验]
H --> I[返回一次性正文]
B -- --> G[开启reasoning状态推送]
G --> H[执行随口记graph带阶段状态]
H --> I{是随口记意图?}
I -- 是 --> J[执行随口记写库链路<br/>返回一次性正文]
I -- 否 --> K[推送fallback状态<br/>回落普通聊天StreamChat]
C -- --> J[随口记兜底路径<br/>恢复二次意图判定]
J --> K{是否随口记意图}
K -- 否 --> L[普通聊天链路<br/>StreamChat token流式输出]
K -- 是 --> M[执行随口记写库链路<br/>返回一次性正文]
E --> Z[后置持久化<br/>Redis + outbox/DB]
F --> Z
J --> Z
K --> Z
I --> Z
L --> Z
M --> Z
```
# 6 前端实现

View File

@@ -0,0 +1,98 @@
# 功能决策记录FDRAI随口记
## 1. 基本信息
- 记录编号FDR-2026-03-AGENT-QUICK-NOTE
- 功能名称AI 随口记(日程/任务自动识别与写入)
- 记录日期2026-03-14
- 决策状态:已采纳
- 负责人:项目协作实现(你 + Codex
- 关联模块:`/agent/chat`、Agent Graph、任务写库工具、Redis 会话缓存、Outbox 持久化链路
## 2. 背景与问题
- 业务背景:用户希望在聊天中“顺口一句”就能完成任务记录,例如“明天上午 9 点交实验报告”。
- 初始问题:
- 仅关键词触发的分流策略存在误判,容易出现“该走随口记没走到 / 不该走却走到了”。
- 多次模型调用(意图识别、时间归一化、优先级评估、润色回复)导致整体耗时偏长。
- 曾出现“回复显示安排成功但数据库未写入”的一致性问题,影响用户信任。
- 相对时间理解依赖当前时间上下文,未显式给模型当前时间时易解析失败或落空。
- 不做此决策的后果:用户体验不稳定、链路不可解释、面试叙述难以自洽(无法清晰说明可靠性与性能权衡)。
## 3. 决策目标
- 目标 1让“聊天入口 + 任务执行”在用户视角尽量无感切换,减少误判与等待焦虑。
- 目标 2保证写入成功才返回成功避免“假成功”。
- 目标 3在不破坏现有流式聊天主链路的前提下提升随口记链路可维护性与可解释性。
- 非目标:本次不做多 Agent 并发编排、不做复杂工作流引擎分布式扩展。
## 4. 备选方案
### 方案 A继续以关键词匹配为主分流
- 描述:命中词则进随口记,否则普通聊天。
- 优点:实现简单,速度快。
- 缺点:语义覆盖不足,边界表达极易误判;可维护性差(词库不断膨胀)。
### 方案 B完全依赖 Graph 二次意图判断
- 描述:所有请求先入图,再判断是否是随口记。
- 优点:逻辑统一,准确性相对高。
- 缺点:普通聊天也要先走较重流程,体验退化,整体成本高。
### 方案 C采纳模型控制码路由 + Graph 兜底 + 单请求聚合规划
- 描述:
- 先用同模型做轻量路由(返回 `quick_note/chat` 控制码);
- 路由命中则走随口记快路径,跳过重复判定;
- 路由失败或异常时回退到 Graph 兜底判定;
- 随口记核心规划改为单请求聚合(时间、优先级、回复语气一次产出),减少多轮 LLM 往返。
- 优点:体验与鲁棒性平衡更好,误判可兜底,耗时可控。
- 缺点:需要更严格的超时与错误处理,提示词质量直接影响路由稳定性。
## 5. 最终决策
- 采纳方案:方案 C。
- 关键理由:
- 兼顾速度(快路径)与可靠性(兜底路径);
- 明确“成功响应必须以真实写库成功为前提”;
- 对现有项目侵入较小,保留后续扩展到完整 Agent 编排的空间。
## 6. 关键实现约束(本次落地口径)
- 路由层:
- 由模型返回控制码判断走向(`quick_note``chat`
- 路由失败时允许进入 Graph 兜底,不直接让请求失败。
- 执行层(随口记):
- 使用“单请求聚合规划”,将时间归一化、优先级评估、回复素材生成整合为一次模型调用;
- 对时间字段执行本地校验,非法日期不写库,返回纠错信息;
- 优先级保留本地兜底,避免因模型输出波动导致链路中断。
- 一致性层:
- 数据库写入结果作为成功唯一依据,`task_id` 无效即判失败;
- 修复“成功回复未写入 Redis 会话缓存”的问题,确保会话上下文与持久化语义一致。
- 交互层:
- 在 OpenAI 兼容流式输出下,阶段提示暂伪装为“思考块”形态,保证现有调试工具可读;
- 最终正文一次性输出,不做伪流式分片刷屏。
## 7. 与 Outbox 链路的协同决策
- 保持“后置写 Outbox”策略聊天主响应优先持久化异步化。
- 移除“首次同步投 Kafka”机制避免把 Broker 投递耗时绑定到当前请求。
- 结论:当前请求仅承担必要同步成本(如 Redis 与写 Outbox 入库Kafka 分发交由后台扫描器处理。
## 8. 风险与应对
- 风险 1路由模型超时导致分流不稳定。
- 应对:独立路由超时控制 + 失败回退 Graph 兜底,避免整链路崩溃。
- 风险 2模型输出日期格式不规范导致脏数据。
- 应对Go 侧严格日期校验,校验失败直接返回用户修正,不写库。
- 风险 3用户感知“等待无反馈”。
- 应对:增加阶段状态提示(请求接收、意图分析、时间校验、写库中、写库完成)。
## 9. 验证与回滚
- 验证方式:
- 正常样例:绝对时间、相对时间(依赖当前时间)均应正确入库;
- 异常样例:非法日期必须失败且不写库;
- 一致性样例:成功后 Redis 会话能看到助手反馈。
- 成功判定标准:
- 不再出现“秒回成功但 DB 无记录”;
- 路由失败时仍可由兜底链路完成任务;
- 交互可见阶段反馈,用户等待感降低。
- 回滚方案:
- 路由逻辑可回退到纯聊天 + 手动触发工具;
- 保留 Graph 兜底能力,避免单点策略失效。
## 10. 后续优化项
- 增加路由与执行链路的结构化指标命中率、误判率、平均耗时、P95/P99
- 对“随口记回复风格”做可配置化(幽默程度、长度、正式度)。
- 后续接前端时,将临时“思考块伪装”升级为正式阶段事件协议,避免兼容层长期存在。
- 当工具数量增长后,考虑从单技能图演进到可插拔技能编排目录(按技能隔离 prompt、schema、重试策略

View File

@@ -0,0 +1,69 @@
# 功能决策记录模板FDR
## 1. 基本信息
- 记录编号:
- 功能名称:
- 记录日期:
- 决策状态:(提议 / 已采纳 / 已废弃)
- 负责人:
- 关联需求 / Issue
## 2. 背景与问题
- 业务背景:
- 现状问题:
- 不做此决策的后果:
## 3. 决策目标
- 目标 1
- 目标 2
- 非目标(明确本次不解决什么):
## 4. 备选方案
### 方案 A
- 描述:
- 优点:
- 缺点:
- 复杂度 / 成本:
### 方案 B
- 描述:
- 优点:
- 缺点:
- 复杂度 / 成本:
### 方案 C如有
- 描述:
- 优点:
- 缺点:
- 复杂度 / 成本:
## 5. 最终决策
- 采纳方案:
- 关键理由:
## 6. 影响范围
- 涉及模块:
- 数据与存储影响:
- 接口 / 协议影响:
- 监控与日志影响:
## 7. 风险与应对
- 风险 1
- 应对策略:
- 风险 2
- 应对策略:
## 8. 验证与回滚
- 验证方式:
- 成功判定标准:
- 回滚方案:
## 9. 里程碑与后续计划
- 里程碑 1
- 里程碑 2
- 后续优化项:
## 10. 复盘结论(上线后补充)
- 实际效果:
- 与预期偏差:
- 后续是否需要二次决策: