Files
memind/docs/architecture/chat-task-intent-layer-review-20260828.md
T
john 3df2c62c3c docs(architecture): add chat-to-task intent layer review and low-impact plan.
Document R1–R3 root causes in the H5 direct/agent routing path, reject the Task Runtime approach, and define a phased rollout with Memory V2 compatibility constraints.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 17:34:59 +08:00

29 KiB
Raw Blame History

聊天 ↔ 任务执行意图层评估与改造方案

日期: 2026-08-28

状态: 设计评估(只读核查完成,未改动任何代码)

适用范围:

  • H5 聊天主链路的路由层:chat-intent-routeragent-run-gatewaydirect-chat-service
  • direct chat 与 Goose agent 之间的会话身份、上下文传递与升级路径。
  • 「用户正常聊天 → 系统识别意图 → 触发任务执行」这一交互闭环。

非目标:

  • 不重写 Goose,不改 goosed 协议。
  • 不引入新的任务存储模型或新框架。
  • 不改变现有发布闸门与回归守卫规则。
  • 不重复 H5 Session 架构方案 中已落地的 session broker / SSE replay 能力。

0. 结论

被评估的原方案(引入 Task Resolver + Task State Machine + Working Memory 的「Task Runtime」)方向正确但不是最优解:它假设「意图飘忽」源于缺少任务控制层,而代码核查显示,真实根因是路由层的三个具体缺陷。

核查确认的三个根因:

编号 问题 性质
R1 direct chat 的历史不进入 Goose 执行输入 上下文单向丢失
R2 纯聊天会话中 LLM 意图识别永不启动 吸收态死区
R3 兜底安全网对 router 判定的 direct_chat 主动放行,且 prompt 指示模型谎报「已交由后台」 误判被放大并对用户不可见

其中 R2 是决定性的MEMIND_CHAT_LLM_ROUTER_ENABLED=1 在 103 生产已开启,但在纯聊天会话里那个 LLM 根本不会被调用。语义意图识别目前实际由正则承担。

Task Runtime 无法解决 R1R3 中的任何一个。 因此本文提出替代路线:先修复路由层缺陷,让意图识别真正生效;Task 抽象留待有数据支撑后再增量引入。

0.1 与相关文档的关系

文档 关系
H5 Session 架构方案 本文在其 control plane / execution runtime 划分之上,处理 chat↔agent 的路由与上下文缺口
Intent Transaction Layer 设计 ITL 管有副作用的创建动作(提醒/定时)的 Draft→Confirm→Commit;本文管多轮对话中的任务识别与执行移交,两者并列,不应合并进同一分类器
SSE 断线续播守卫 本文 P2 触及 agent-run-gateway session 路径,改动须重跑该守卫
Orchestrator 边界 本文不改变 Portal = control plane、Goose/Orchestrator = execution 的划分

1. 被评估的原方案

原方案主张把架构从 H5 → Goose → LLM → Tools 升级为在 H5 与 Goose 之间插入 Intent Gateway / Task Controller,核心为三件事:

  1. Task Resolver — 每轮先判断本句与当前任务的关系(SAME / MODIFY / NEW / CANCEL / AMBIGUOUS),用小模型输出严格 JSON。
  2. Task State MachineNEW → UNDERSTANDING → PLANNING → EXECUTING → WAITING_USER → COMPLETED,状态由程序控制,LLM 无权变更。
  3. Working Memory — 结构化的 goal / constraints / decisions / pending_questions,作为权威状态;conversation history 降级为「证据」。

配套还包括 Intent Lock(相似度阈值 0.8 / 0.5)与 Goal → Task → Step 树。

2. 对原方案的评估

2.1 未量化根因就动架构

整个方案建立在「意图飘忽」的主观描述上。没有漂移基线指标,就无法判断根因,也无法证明改造有效。这是最需要先补的一环。

2.2 Task Resolver 修不了已确认的根因

即便 relation 判定 100% 准确、task state 完美维护:

  • R1 仍在:Goose 依旧收不到 direct 轮次的原文。
  • R2 仍在:Resolver 本身要在路由之后才有意义,而路由在聊天会话里已提前锁死。

Resolver 输出的结构化摘要反而会成为唯一信息源,正是 2.5 所述的权威倒置。

2.3 每轮新增阻塞 LLM 调用

Resolver 在关键路径上增加一次调用,带来延迟与新失败模式。配合 Intent Lock 后,分类错误会被放大:原本错一轮即自愈,改为锁定 N 轮,用户需显式挣脱。「偶发漂移」被换成「确定性卡死」,后者体感更差。

2.4 硬 FSM 过度设定

UNDERSTANDINGPLANNING 是不可观测的内部状态,外部无法可靠判定进入/退出。真实对话不服从该链(随时插话、回退、并行两件事),最终会退化为大量转移补丁。GPT 系产品均未采用显式 task FSM。

2.5 Working Memory 权威化是危险倒置

一旦 WM 权威且不再发送完整历史,WM 漏写某个约束时模型无法从原文恢复。GPT 的做法相反:完整上下文是权威,结构化记忆只是 hint,抽取错了仍可被原文纠正。

2.6 Intent Lock 阈值是魔数陷阱

>0.8 / 0.5~0.8 / <0.5 的阈值不可跨 domain 迁移。原方案自身已给出反例(「换个话题,帮我看看 Mac」embedding 仍高相似)。叠加 rules 与小模型兜底后,embedding 层已无净贡献,只剩调参负担。

2.7 会成为第四套任务模型

现状已有 h5_agent_runsh5_goal_checkpointsh5_unified_tasks、orchestrator run 四套并存。AGENTS.md 已点名 gateway 边界偏厚。Goal→Task→Step 树依赖高质量任务分解,属于过早抽象。

3. GPT 的实际做法(对照)

维度 GPT 的做法
任务状态 不维护外部 FSM,整个 thread 即状态
轮次延续 无 relation classifier,模型看到完整线程自然延续
记忆 扁平事实注入,不是状态机
工具选择 模型自选,靠 tool description 质量,不靠外部 router
显式任务对象 只给 Deep Research / Tasks / Agent mode,且用户显式创建,不靠推断
路由 路由的是算力fast vs thinking),不是任务身份
上下文压缩 滚动摘要,不是手写 schema

核心推论:GPT 的稳定性来自「不切断上下文」+「不每轮重判」,而非「更强的控制层」。 原方案的两个主要动作恰好反向:切断上下文(WM 替代历史)+ 加强重判(每轮 Resolver)。


4. 代码核查结论

以下均为 main416bf7a2)只读核查,附 file:line 证据。

4.1 R1:上下文单向丢失

割裂是不对称的:

翻转方向 Goose / LLM 能否看到上一轮 性质
agent → direct 通常能(经 snapshot 回写) 有竞态窗口,且仅 12 条
direct → agent 确定看不到 真实 gap

h5direct_ 会话升级时,旧 transcript 只写入 DB

  • agent-run-gateway.mjs:2071-2089persistSessionTranscriptMessagesh5_conversation_messages
  • agent-run-gateway.mjs:2094-2105 — 同 Goose session 上的 direct 轮次同理

h5_conversation_messages 仅用于 GET 展示修复(conversation-repair.mjs:243-251),不进入 Goose 推理输入。Portal 每轮只 submit 当前一条消息(tkmind-proxy.mjs:2095-2098),Goose 依赖自己服务端的会话历史——但 direct 轮次从未写入 Goose。

关键发现:修复所需机制已存在且久经验证。 buildFreshSessionContextagent-run-gateway.mjs:202-22416 条 / 12000 字符)与 appendFreshSessionContext 已在三处使用:

调用点 场景
agent-run-gateway.mjs:2117 session compaction 后
agent-run-gateway.mjs:2157 session rotation 后
agent-run-gateway.mjs:2268 poisoned session 恢复

唯独没有接到 direct → agent 升级路径。 这不是缺架构,是一条已验证能力没接上入口。

4.2 R1 衍生:四条路径的历史窗口口径不一

路径 窗口 位置
direct chat LLM 12 条 direct-chat-service.mjs:145
router 分类 8 轮 / 4000 字符,且跳过 h5direct_* chat-intent-router.mjs:724
session rotation 16 条 / 12000 字符 agent-run-gateway.mjs:202
Goose agent 服务端全量

router 明确跳过 h5direct_* 快照,意味着上一轮若是 direct chat,router 做路由判断时看不到它。这直接解释短消息漂移。

4.3 R2:意图识别吸收态(决定性问题)

路由为「规则优先,规则返回 null 才进 LLM」,而规则兜底硬判 direct_chat

  • chat-intent-router.mjs:1366-1370 — 兜底 direct_chatconfidence 0.72

唯一能把控制权交给 LLM router 的开关是 shouldDeferActiveTaskRoutingToLlm,其第一行即要求存在活跃 agent 任务:

  • chat-intent-router.mjs:365if (!activeTaskContext?.hasRecentAgentTask) return false;

activeTaskContext 在聊天会话中恒为 null,两道门都关着:

  • agent-run-gateway.mjs:646-649isDirectChatSessionId(sessionId) 直接返回 null
  • agent-run-gateway.mjs:675-679 — 上一轮非 agent route 则返回 null

形成闭环:

新对话
  ↓ 无活跃 agent 任务
规则兜底 → direct_chat
  ↓
创建 h5direct_ 会话
  ↓ isDirectChatSessionId → activeTaskContext = null
shouldDeferActiveTaskRoutingToLlm = false
  ↓
规则兜底 → direct_chat
  ↓
(永远循环)

这是一个吸收态。 103 生产虽已设置 MEMIND_CHAT_LLM_ROUTER_ENABLED=1 / SHADOW=0,但在纯聊天会话中该 LLM 不会被调用。语义意图识别实际由正则承担;唯一逃逸口是命中 OBVIOUS_AGENT_PATTERNS 等硬模式,或用户手动开启深度推理。

4.4 R3:安全网失效与谎报

direct-chat-service 的兜底检查对 router 判定的 direct_chat 主动放行:

  • direct-chat-service.mjs:199-201routingDecision !== 'direct_chat' && requiresTaskExecution(...)

即:误判概率最高的来源(0.72 兜底)享受最高信任级别。

同时 system prompt 指示模型谎报:

  • direct-chat-service.mjs:141 — 「简要说明已交由后台任务处理或请用户确认具体任务」

direct chat 无任何工具、无任何升级路径,实际什么都没排队。用户以为任务在跑,等待无果后回来追问,而追问那一轮因 4.3 的吸收态大概率仍是 direct_chat。这条链路能完整解释「意图飘忽」的用户体感。

4.5 交互质量评分

维度 评分 说明
用户可以正常聊天 良好 规则 fast-path,延迟低,有记忆
聊天流畅度 中等 direct chat 非流式(llm-providers.mjs:1670 stream:false),前端 600ms 轮询
聊天中识别意图 语义识别不启动,只剩正则
识别后触发执行 同轮无法升级;提示语谎报
误判后恢复 「不对,你去执行」在 h5direct_ 会话不触发延续
Agent 执行体验 良好 真 SSE、工具卡片、loading tips 齐全

5. 改造方案:Context Stability First

按 ROI 排序。P0–P1 不增加任何每轮 LLM 调用。

实施路径见 §11 最低影响实施方案 本章描述目标形态,§11 描述推荐的落地顺序与降风险取舍;两者冲突时以 §11 为准。P2 的实现方式在 §11.4 被修订。

P0 · 观测先行(零生产风险)

先把「漂移」变成可测数字。数据源已存在,无需新埋点

指标 数据源
0.72 兜底占比 intent_routed 事件的 reason / confidence
direct→agent 升级频率 direct_session_escalated_to_deep_reasoning
丢上下文的 agent 回答量 portal_direct_transcript_persisted
direct chat 放行的任务类请求 direct_chat_skipped / direct_chat_completed
route flip / skill flip 率 同 session 内 intent_routed 序列
短消息路由分布 ≤6 字消息的 intent_routed

外加人工标注 100 条真实漂移 case 做归因。没有 P0,后续每层改动都无法证伪。

P1 · 打通 direct → agent 上下文

复用已验证能力,不引入新抽象:

步骤 内容 风险
P1.1 升级路径接入 appendFreshSessionContext 低,复用 rotation 同款函数
P1.2 router transcript 不再跳过 h5direct_* 快照
P1.3 统一 12 / 8 / 16 三个窗口口径 低,需回归

P2 · 打破吸收态:让模型自己声明要执行

这是解 R2 + R3 的核心动作,也是与 GPT 做法一致的方向。

现状是「回合开始前用外部分类器猜」。改为「让回答问题的那个模型自己决定调工具」:给 direct chat 一个工具 execute_task

  • direct chat 保留纯文本快速回答能力,闲聊体验不变。
  • 当它判断需要执行时,不再输出「已交由后台处理」这句谎话,而是发出一次结构化调用。
  • gateway 收到该调用 → 走升级路径 → 真正交给 Goose(并经 P1 带上完整聊天历史)。

收益:

  1. 意图识别由掌握完整上下文的那个模型做,信息量远超前置分类器。
  2. 不新增每轮 LLM 调用 —— 复用本来就要发的那次 completion。
  3. 不依赖 activeTaskContext —— 彻底绕开吸收态。
  4. prompt 不再需要撒谎,「已交由后台」变成真的。
  5. 与「工具由模型选,不靠外部 router」的判断一致。

同时移除 direct-chat-service.mjs:199direct_chat 的无条件放行,让 requiresTaskExecution 在所有路由下都生效,作为第二道网。

P3 · 非对称延续策略

注意:不可照搬对称的「默认延续」,那会让 R2 更严重(聊天会话里默认延续 = 永远聊下去)。正确形态是非对称的:

方向 策略 理由
agent → agent 强延续 防止任务执行中途掉回聊天
chat → chat 不延续 必须每轮保持对升级信号敏感
chat → agent 低门槛 当前是死区,需主动打开
agent → chat 需明确信号 防止任务被闲聊打断

同时把 resolveActiveTaskContexth5direct_ 的硬返回 null 放宽,使「不对,你去执行」类纠正在聊天会话中也能生效。

P4 · Conversation State Card(轻量、非权威、异步)

Finish 后异步抽取,下轮注入 prompt

【当前上下文】
目标:选购 25L 车载冰箱
已知约束:MPV / 宽度≤60cm / 压缩机制冷
候选:英得尔 KD25

与原方案 Working Memory 的四个关键差异:

  • 非权威:历史仍照常发送,Card 丢失不影响正确性。
  • 异步:不在请求关键路径,不增加延迟。
  • 扁平:仅 facts + constraints 两个列表,无 FSM、无 step 树。
  • 可降级:抽取失败则不注入,静默退化。

形态上可与既有 goal-run-context.mjs:10buildGoalContextEnvelope 并列注入。

P5 · 显式长任务对象(复用 Goal Run)

用户显式发起的长任务才创建 task 对象,且用户可见可控。不推断、不自动建、不新建表——直接复用 goal-run-service + h5_goal_checkpoints

P6 · 聊天流式输出(体验项,可并行)

direct chat 当前 stream:false + 前端 600ms 轮询,长回答等待感明显差于 agent 路径。改为 token 流式可显著提升闲聊体验,与路由问题正交,可独立排期。


6. 明确不做

  • 不做每轮阻塞式 Task Resolver LLM 调用。
  • 不做 UNDERSTANDING / PLANNING 等不可观测状态。
  • 不做 embedding 相似度阈值锁。
  • 不把 conversation 降级为「证据」。
  • 不新建第四套 task 存储模型。

7. 两案对比

维度 原方案(Task Runtime 本方案(Context Stability First
每轮额外 LLM 调用 1 次(阻塞) 0 次
新增存储 Task Runtime 表 + WM 无(P4 可复用 snapshot 扩展字段)
能否解 R1 是(P1
能否解 R2 是(P2
能否解 R3 是(P2
错误自愈 差(lock 放大错误) 好(下轮即恢复)
上下文权威源 Working Memory 完整会话历史
与 GPT 做法 相反 一致
可证伪 无基线指标 P0 先建基线
首个收益出现 三模块全做完之后 P1 完成即可见

8. 落地顺序与验证

阶段 内容 验证
P0 观测基线 只读,无需回归
P1 上下文打通 npm run verify:h5-session-patches
P2 execute_task 升级机制 新增 direct→agent 升级用例;verify:h5-session-patches
P3 非对称延续 chat-intent-router.test.mjs 扩充;短消息路由用例
P4 State Card 异步路径,失败降级用例
P5 Goal Run 归并 灰度开关内验证
P6 流式输出 前端 SSE 用例

每阶段独立灰度、独立回归,符合 AGENTS.md 的单分支闭环与发布闸门要求。原方案「三模块一起上」在该治理下难以安全交付。

9. 演进留口

若 P0 归因数据显示漂移主因确实是「多步任务状态丢失」而非上述 R1–R3,再引入原方案的 Task State 抽象。届时它将是有证据支撑的增量,而非先建大厦再找用途。

原方案的 Goal → Task → Step 抽象本身没有错,错的是它的引入时机与权威地位

10. 证据索引

结论 位置
规则兜底硬判 direct_chat chat-intent-router.mjs:1366-1370
LLM router 唯一入口需活跃任务 chat-intent-router.mjs:359-366
h5direct_ 会话无 activeTaskContext agent-run-gateway.mjs:646-649
上一轮非 agent 则无 activeTaskContext agent-run-gateway.mjs:675-679
升级仅持久化到 DB agent-run-gateway.mjs:2071-20892094-2105
DB 仅用于展示修复 conversation-repair.mjs:243-251
Goose 只收当前消息 tkmind-proxy.mjs:2095-2098
历史注入能力已存在 agent-run-gateway.mjs:202-224、调用点 2117 / 2157 / 2268
安全网对 direct_chat 放行 direct-chat-service.mjs:199-201
prompt 指示谎报已交后台 direct-chat-service.mjs:141
direct chat 非流式 llm-providers.mjs:1670
direct chat 历史窗口 12 条 direct-chat-service.mjs:145
router 跳过 h5direct 快照 agent-run-gateway.mjs:705-706
规则命中即短路,LLM 拿不到控制权 chat-intent-router.mjs:1737
shadow 模式可零行为变更观测 chat-intent-router.mjs:1786-1809
LLM 覆盖需过 minConfidence chat-intent-router.mjs:1812-1824
router 对非召回问题不调 Memory V2 memory-intervention.mjs:20-22 + chat-intent-router.mjs:1522-1528

11. 最低影响实施方案(推荐落地路径)

§5 描述目标形态,本章描述怎么落地才能把回归风险压到最低。核心思路:不一次做完 P0–P6,只修已证实的缺口,每步单独灰度、单独回滚、不碰 Memory V2 写链。

11.1 六条硬约束(全程遵守)

# 约束 目的
C1 Memory V2 只读,不改 write / compact / 候选 / lifecycle 避免候选提取污染
C2 记忆召回问题永远走 direct_chat(保留 chat-intent-router.mjs:1237 硬规则) 不碰已验证的 recall 链路
C3 不收紧 direct-chat-service.mjs:199direct_chat 的豁免 避免闲聊被大批踢进 agent
C4 State Card 不进 orchestration、不进 remember-recent 避免 [Memory Context] 自我复制
C5 每步独立 feature flag + 可观测事件 可灰度、可回滚
C6 升级轮次的 memory resolve 使用 sessionId 避免 episodic 线索断档

11.2 阶段 A · 观测(零改动)

对应 §5 的 P0。只读统计,不改任何路由逻辑。

关键指标:0.72 兜底占比、direct_session_escalated_to_deep_reasoning 频率、升级后 agent_memory_resolved.injectionEnabled=false 占比、memory recall 是否 100% direct_chat。

没有阶段 A,后续所有改动都无法证伪。

11.3 阶段 B · 只补上下文

对应 §5 的 P1,但只做 P1.1,暂不做 P1.2 / P1.3。

只改一件事:direct→agent 升级时,把 snapshot 历史经 appendFreshSessionContext 注入 Goose 输入。

刻意不做:不改 router 兜底、不改 canHandle、不改 preferDirectChat、不碰 Memory V2 resolve、不引入 execute_task

Memory V2 兼容(C6):

升级后 agent 首轮 resolve 应使用 escalatedDirectSessionId
而非新建的 Goose sessionId,直到确认 episodic 为 user-scoped。

FlagMEMIND_DIRECT_ESCALATION_CONTEXT_ENABLED(默认 0+ canary 名单。
降级:flag 关或注入失败 → 完全退回现有行为。

预期影响:闲聊无变化;Memory V2 无变化;升级后 agent 不再「失忆」;仅升级轮次略增 token。

11.4 阶段 C · 打开语义识别(对 §5 P2 的修订)

这是本章对原方案改动最大的一节。

11.4.1 为什么不用「更多升级短语 + 深度推理开关」

一个直觉上更安全的做法是:不动路由,只扩充 OBVIOUS_AGENT_PATTERNS,并引导用户手动开深度推理。

否决理由: §4.3 论证的 R2 是「语义识别不启动,只剩正则」,而该做法是再加正则,并把判断责任推给用户。风险确实最低,但它不修复 R2,只是把死区包装得更礼貌。产品诉求「聊天中自动识别意图并执行」仍然落空。

保留价值:作为逃逸通道而非主机制。

11.4.2 为什么暂缓 execute_task

§5 P2 提出给 direct chat 一个 execute_task 工具。方向正确,但当前 llm-providers.mjscreateChatCompletion 不支持 tools / tool_calls,落地需同时改:direct chat 的 function calling、同轮切 agent 的状态机、run 事件与 UI 时序、sessionId 切换、计费与 Finish 对齐。

风险集中且互相耦合,不适合作为第一刀。暂缓,不否决。

11.4.3 采用:让已有 LLM router 在聊天会话可达

代码核查显示,语义识别失效的原因是一行短路

chat-intent-router.mjs:1737
  if (ruleResult) return finalizeWithCoercion(ruleResult);

规则一旦返回结果,LLM 分支永远拿不到控制权;而规则兜底恒返回 direct_chat:1366-1370)。

因此最小改动是:让 0.72 兜底在「歧义闸门」通过时返回 null,把控制权交给已经部署好的 LLM router。

歧义闸门复用既有纯函数,不新增判断逻辑:

通过闸门 = 非 memory recall
        且 非 FAQ / 寒暄 / 纯文字创作(isExplicitDirectChatOnlyText 已覆盖)
        且 文本长度达阈值

这样做的优势:

  1. 零新基础设施 —— shadow 模式、canary 名单、minConfidence 覆盖闸门均已就位。
  2. 可零行为变更观测 —— policy.shadowMode 下只记录 wouldChangeRoute,路由完全不变(:1786-1809)。这同时补齐了阶段 A 缺失的「LLM 会怎么判」这一维数据。
  3. 覆盖有闸门 —— LLM 置信度低于 minConfidence(生产 0.65)时自动退回 baseline:1812-1824)。
  4. 不增加 Memory V2 负载 —— router 对非召回问题 resolveMemoryInterventionMode 返回 SKIPlimit<=0 时直接返回空 context,不调用 memoryV2.resolve

11.4.4 三步灰度

步骤 配置 行为 判据
C-1 闸门开 + MEMIND_CHAT_LLM_ROUTER_SHADOW=1 路由不变,仅记录 统计 wouldChangeRoute 比例
C-2 SHADOW=0 + canary 名单 小范围生效 agent 触发率增幅、误判反馈
C-3 移除 canary 全量 同上 + 成本曲线

任一步指标超阈值即回退上一步。新增 flag:MEMIND_CHAT_ROUTER_CHAT_SESSION_DEFER_ENABLED(默认 0)。

11.4.5 成本与延迟

这是本阶段唯一真实代价:通过闸门的聊天轮次会多一次小模型 router 调用(生产为 deepseek-chat),在 direct chat 应答前引入约数百毫秒。

缓解:歧义闸门收窄触发面;沿用既有 policy.timeoutMs 超时降级;C-1 阶段先用 shadow 数据估算实际触发比例再决定是否推进。

11.4.6 同步做:去掉谎报

独立于路由改动,属纯文案修改,零回归面:

direct-chat-service.mjs:141
  「简要说明已交由后台任务处理」
→ 明确说明当前只能文字讨论,并给出可用的升级方式

阶段 C 生效后,该文案应再次收敛——升级由系统完成时,不应继续提示用户手动操作。

11.5 阶段 D · 可选纠偏

仅当阶段 A/C 数据显示「短句纠偏失败」占比超过阈值时才做。

范围收窄为:session 为 h5direct_ 上一轮 direct_chat_completed 命中 AGENT_TASK_FOLLOWUP_PATTERNS → 强制 agent,并复用阶段 B 的上下文注入。

不做:全面放宽 resolveActiveTaskContexth5direct_ 的 null 返回;不做 chat→chat 默认延续。

需一并评估 preferDirectChat 的 sticky 行为(agent-run-gateway.mjs:1871-1874):只要 session 仍是 h5direct_*,即使 router 判 agent,仍可能优先尝试 direct chat。纠偏链路若不处理这一点会不完整。

11.6 明确后置

后置理由
execute_task tool calling 需改 LLM 层 + 同轮状态机 + UI 时序,耦合最重(§11.4.2)
收紧 requiresTaskExecution 豁免 会大幅增加 agent 流量,且可能使 Memory 注入倒退(§12.2
P1.2 router 读 h5direct_ transcript 与阶段 C 效果重叠,应在 C 之后单独评估
P1.3 统一 12/8/16 窗口 独立回归面,收益不确定
P4 State Card 阶段 B 已补上下文,边际收益下降;且有 Memory V2 污染风险
P6 流式输出 体验收益明确但动前后端 Finish 时序,应独立排期

11.7 阶段对照与验收

阶段 对应 §5 风险 验收标准
A 观测 P0 拿到 0.72 兜底占比与升级频率基线
B 上下文 P1.1 升级后 Goose 输入含 prior contextmemory recall 仍 100% directverify:h5-session-patches 通过
C 语义识别 P2(修订) 中,可灰度 shadow wouldChangeRoute 在预期区间;canary 期 agent 触发率增幅低于阈值;RESOLVED_INJECTED 比例不下降
D 纠偏 P3(收窄) 「不对你去执行」在 h5direct_ 可进 agent;误触发率低于阈值

回归范围(除 verify:h5-session-patches 外):chat-intent-router.test.mjsdirect-chat-service.test.mjsagent-run-gateway.test.mjs,以及 scripts/verify-world-cup-flow-e2e.mjs(该脚本显式断言不应出现 direct_chat_completed,对阶段 C 敏感)。


12. Memory V2 兼容性

12.1 现状:三条独立注入路径

路径 位置 触发条件 开关
Router chat-intent-router.mjs:1537-1548 仅记忆召回问题(非召回为 SKIP MEMIND_CHAT_ROUTER_MEMORY_ENABLED,默认开
Direct chat direct-chat-service.mjs:302-312 每轮limit=5 不依赖 agent 开关
Agent agent-run-gateway.mjs:1790-1818 注入进 [Memory Context] MEMORY_AGENT_RESOLVE_ENABLED默认关

关键不对称:direct chat 每轮必 resolveagent 默认不注入。

12.2 各阶段影响

阶段 对 Memory V2 的影响
A 观测
B 上下文 低。仅拼接历史文本,不走 resolve/write。风险点是 sessionId 变更导致 episodic 断档 → 由 C6 约束覆盖
C 语义识别 低于直觉。router 对非召回问题不调 memoryV2.resolve,故不增加负载。真实风险是流量从 direct(必注入)转向 agent(默认不注入),可能造成记忆注入率下降
D 纠偏 同 C,量级更小
后置项 State Card 若与 [Memory Context] 混写,可能触发候选提取污染(见 Memory V2 候选与生命周期守卫 记录的旧记忆自我复制问题)

12.3 不会被破坏的行为

候选表与 lifecycle、pgvector、admin 配置、remember-recent / sync API、fail-open 语义、goosed 零改动承诺——本方案均不触及。

记忆召回硬规则(chat-intent-router.mjs:1237)保证「你记得我上次说的吗」类问题不会被阶段 C 误判进 agent;isExplicitDirectChatOnlyText 亦已将 memory recall 纳入排除集(:337)。

12.4 强制要求

  1. 阶段 B/C 上线前记录 baselineagent_memory_resolvedRESOLVED_INJECTEDRECALL_HIT 在两条路径上的分布。
  2. 阶段 C 推进到 C-2 之前,确认目标 canary 用户的 MEMORY_AGENT_RESOLVE_ENABLED 覆盖情况;否则「任务能执行了,但记忆注入变少」。
  3. 阶段 B 升级路径的 memory resolve 使用旧 sessionIdC6)。
  4. 任何 State Card 类注入严禁进入 write 链(C1 / C4)。

13. 修订记录

日期 变更
2026-08-28 初版:R1R3 根因核查、原 Task Runtime 方案评估、P0P6 目标形态
2026-08-28 增补 §11 最低影响实施方案:将 P2 的实现方式从 execute_task 修订为「让已有 LLM router 在聊天会话可达」,暂缓 tool callingP1 收窄为仅 P1.1P3 收窄为仅 h5direct_ 纠偏
2026-08-28 增补 §12 Memory V2 兼容性:三条注入路径现状、各阶段影响、四条强制要求