From 21d6fe5b5f0a943c9354e569d1feb1aadde519d4 Mon Sep 17 00:00:00 2001 From: Losita <2810873701@qq.com> Date: Sat, 14 Mar 2026 18:19:11 +0800 Subject: [PATCH] =?UTF-8?q?Version:=200.5.5.dev.260314=20=F0=9F=9A=80=20?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BA=86=20README=20=E4=B8=AD=E7=9A=84=20Mer?= =?UTF-8?q?maid=20=E5=9B=BE=EF=BC=8C=E7=A1=AE=E4=BF=9D=E4=B8=8E=E5=BD=93?= =?UTF-8?q?=E5=89=8D=E9=9A=8F=E5=8F=A3=E8=AE=B0=E7=9A=84=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E9=93=BE=E8=B7=AF=E4=B8=80=E8=87=B4=E3=80=82=20=F0=9F=93=9A=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=86=E5=8A=9F=E8=83=BD=E5=86=B3=E7=AD=96?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=EF=BC=88docs/=E5=8A=9F=E8=83=BD=E5=86=B3?= =?UTF-8?q?=E7=AD=96=E8=AE=B0=E5=BD=95=EF=BC=89=EF=BC=8C=E5=B9=B6=E4=B8=94?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E4=BA=86=E6=AD=A4=E6=AC=A1=20AI=20=E9=9A=8F?= =?UTF-8?q?=E5=8F=A3=E8=AE=B0=E5=8A=9F=E8=83=BD=E7=9A=84=E5=B7=A5=E7=A8=8B?= =?UTF-8?q?=E5=86=B3=E7=AD=96=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 63 +++++++++-------- docs/功能决策记录/AI随口记_决策记录.md | 98 ++++++++++++++++++++++++++ docs/功能决策记录/功能决策记录模板.md | 69 ++++++++++++++++++ 3 files changed, 202 insertions(+), 28 deletions(-) create mode 100644 docs/功能决策记录/AI随口记_决策记录.md create mode 100644 docs/功能决策记录/功能决策记录模板.md diff --git a/README.md b/README.md index b1dbae3..7aec86d 100644 --- a/README.md +++ b/README.md @@ -358,44 +358,51 @@ $$Gap = \frac{TotalAvailableSlots - (TaskCount \times 2)}{TaskCount + 1}$$ flowchart TD A[用户消息进入 /agent/chat] --> B[规范会话ID + 选模型] B --> C[确保会话存在
Redis会话状态检查
必要时回源DB创建] - C --> D[quick_note.request.accepted
推送reasoning状态块] - D --> E[意图识别节点
quick_note.intent.analyzing] - E --> F{是否随口记意图} - F -- 否 --> X[回落普通聊天链路] - F -- 是 --> G[时间抽取与校验
quick_note.deadline.validating] - G --> H{时间是否有效} - H -- 否 --> I[返回纠错文案
不写库
quick_note.failed] - H -- 是 --> J[优先级评估
quick_note.priority.evaluating] - J --> K[调用写库工具
quick_note.persisting] - K --> L{写入是否成功} - L -- 否 --> M[按重试策略处理
最终失败则返回错误文案] - L -- 是 --> N[quick_note.persisted] - N --> O[quick_note.reply.polishing
AI生成贴题轻松跟进句] - O --> P[拼接最终正文
一次性content输出] - P --> Q[后置持久化
user+assistant写Redis
并写outbox/DB] + C --> D[模型控制码路由
action=quick_note/chat] + D --> E{route是否命中quick_note} + E -- 否 --> X[普通聊天链路
StreamChat流式输出] + E -- 是 --> F[quick_note.request.accepted
推送reasoning状态块] + F --> G[跳过二次意图判定
直接进入聚合规划] + G --> H[单请求聚合规划
生成title/deadline/priority/banter] + H --> I[时间校验
quick_note.deadline.validating] + I --> J{时间是否有效} + J -- 否 --> K[返回纠错文案
不写库
quick_note.failed] + J -- 是 --> L{优先级是否有效} + L -- 是 --> M[复用聚合优先级] + L -- 否 --> N[本地优先级兜底
不再二次调用模型] + M --> O[调用写库工具
quick_note.persisting] + N --> O + O --> P{task_id是否有效} + P -- 否 --> Q[按重试策略处理
最终返回失败文案] + P -- 是 --> R[quick_note.persisted] + R --> S[拼接最终正文
优先复用聚合banter
一次性content输出] + S --> T[后置持久化
user+assistant写Redis
并写outbox/DB] + X --> T ``` ### 2) 总分流图(消息识别后的去向) ```mermaid flowchart TD - A[用户消息进入 AgentChat] --> B{是否命中任务/提醒关键词} + A[用户消息进入 AgentChat] --> B[模型控制码路由
action=quick_note/chat] + B --> C{路由是否成功解析} - B -- 否 --> C[尝试随口记graph(静默)] - C --> D{是随口记意图?} - D -- 是 --> E[执行随口记写库链路
返回一次性正文] - D -- 否 --> F[普通聊天链路
StreamChat token流式输出] + C -- 是 --> D{action=quick_note?} + D -- 否 --> E[普通聊天链路
StreamChat token流式输出] + D -- 是 --> F[随口记快路径
跳过二次意图判定] + F --> G[单请求聚合规划
+本地时间校验/优先级兜底] + G --> H[写库工具落库
task_id有效校验] + H --> I[返回一次性正文] - B -- 是 --> G[开启reasoning状态推送] - G --> H[执行随口记graph(带阶段状态)] - H --> I{是随口记意图?} - I -- 是 --> J[执行随口记写库链路
返回一次性正文] - I -- 否 --> K[推送fallback状态
回落普通聊天StreamChat] + C -- 否 --> J[随口记兜底路径
恢复二次意图判定] + J --> K{是否随口记意图} + K -- 否 --> L[普通聊天链路
StreamChat token流式输出] + K -- 是 --> M[执行随口记写库链路
返回一次性正文] E --> Z[后置持久化
Redis + outbox/DB] - F --> Z - J --> Z - K --> Z + I --> Z + L --> Z + M --> Z ``` # 6 前端实现 diff --git a/docs/功能决策记录/AI随口记_决策记录.md b/docs/功能决策记录/AI随口记_决策记录.md new file mode 100644 index 0000000..86e6b26 --- /dev/null +++ b/docs/功能决策记录/AI随口记_决策记录.md @@ -0,0 +1,98 @@ +# 功能决策记录(FDR):AI随口记 + +## 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、重试策略)。 diff --git a/docs/功能决策记录/功能决策记录模板.md b/docs/功能决策记录/功能决策记录模板.md new file mode 100644 index 0000000..c82e3f2 --- /dev/null +++ b/docs/功能决策记录/功能决策记录模板.md @@ -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. 复盘结论(上线后补充) +- 实际效果: +- 与预期偏差: +- 后续是否需要二次决策: