Files
zclaw_openfang/docs/test-evidence/FUNCTIONAL_CHAIN_AUDIT_2026_04_20.md
iven f2917366a8
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
fix(growth,kernel,runtime,desktop): 50 轮功能链路审计 7 项断链修复
P0 修复:
- B-MEM-2: 跨会话记忆丢失 — 添加 IdentityRecall 查询意图检测,
  身份类查询绕过 FTS5/LIKE 文本搜索,直接按 scope 检索全部偏好+知识记忆;
  缓存 GrowthIntegration 到 Kernel 避免每次请求重建空 scorer
- B-HAND-1: Hands 未触发 — 创建 HandTool wrapper 实现 Tool trait,
  在 create_tool_registry() 中注册所有已启用 Hands 为 LLM 可调用工具

P1 修复:
- B-SCHED-4: 一次性定时未拦截 — 添加 RE_ONE_SHOT_TODAY 正则匹配
  "下午3点半提醒我..."类无日期前缀的同日触发模式
- B-CHAT-2: 工具调用循环 — ToolErrorMiddleware 添加连续失败计数器,
  3 次连续失败后自动 AbortLoop 防止无限重试
- B-CHAT-5: Stream 竞态 — cancelStream 后添加 500ms cancelCooldown,
  防止后端 active-stream 检查竞态
2026-04-20 09:43:38 +08:00

14 KiB
Raw Blame History

ZCLAW 功能链路审计报告

执行摘要

  • 日期: 2026-04-20
  • 总轮次: 50 (原计划 215精简执行)
  • 总时长: ~2.5 小时
  • 总消息: 会话1: 24条 (12+12) / 会话2: 36条 (18+18)
  • 严重断链: 2 HIGH + 2 MEDIUM + 3 LOW = 7 项
  • 通过率: 42/50 轮成功 (84%)

关键发现

  1. 跨会话记忆完全丢失 (B-MEM-2, HIGH) — 用户身份、事实、偏好在新会话中不可召回,是最严重的功能断链
  2. Hands 未被触发 (B-HAND-1, HIGH) — 所有 Hand 能力请求Researcher/Collector/Quiz均由 LLM 直接处理,未触发 Hand 执行管道
  3. 一次性定时触发未拦截 (B-SCHED-4, MEDIUM) — 只有循环定时被正确拦截,一次性触发(如"明天下午2点")走 LLM 而非定时系统
  4. 管家路由和会话内记忆工作良好 — healthcare 域路由准确,会话内记忆召回完美

覆盖矩阵

# 场景 轮次 Butler Memory Schedule Hands 结果
1 Healthcare 路由 1-6 W W - - PASS
2 管家边界+多域 7-10 W - - - PASS
3 身份/事实记忆写入 11-12 - W - - PASS
4 偏好/任务记忆写入 13-14 - W - - PASS
5 会话内记忆召回 15-17 W R - - PASS
6 管家+记忆联合 18 W R - - PASS
7 痛点进化测试 19 W E - - ⚠️ PARTIAL
8 管家边界+记忆 20 W R - - PASS
9 循环定时(6种) 21-25 - - C - PASS (5/6)
10 一次性定时 26 - - X - FAIL
11 Hand 触发 27-28 - - - E FAIL
12 定时+管家组合 29 W - C - PASS
13 间隔定时 30 - - C - PASS
14 跨会话身份召回 31 - R - - FAIL
15 跨会话事实召回 32 - R - - FAIL
16 跨会话偏好 33 - R - - FAIL
17 新会话管家路由 34 W - - - PASS
18 新会话记忆写入 35-36 - W - - PASS
19 定时跨会话查询 37 - - R - ⚠️ PARTIAL
20 SaaS Relay 38 - - - - PASS
21 非医疗边界 39 W - - - PASS
22 极短消息 41 W - - - PASS
23 模糊查询 42 W - - - PASS
24 混合域过载 43 W - - - ⚠️ PARTIAL
25 长文本处理 46 W - - - PASS
26 取消恢复 47-48 - - - - PASS
27 空消息 49 - - - - PASS

按子系统详细发现

1. 聊天流 (Chat Stream)

测试项 结果 说明
消息发送 store API 可靠发送
流式响应 大部分正常完成
取消流 cancelStream() 立即生效
取消后重发 状态完全重置
极短消息 "排班" → 请求澄清
模糊查询 "帮我看看这个" → 提供选项
空消息 静默忽略
长文本 500+ 字消息正常处理

问题:

  • R1: UI+API 双重发送导致消息重复LOW可通过统一使用 store API 避免)
  • R2: 工具调用循环web_search→web_fetch→deep_research 均失败8 tool steps 仅 156 chars→ 需要工具调用限制
  • R6: "Session already has an active stream" 竞态条件MEDIUM

2. 管家路由 (Butler Router)

测试关键词 命中 验证
healthcare 骨科/床位/急诊/护理/排班/入院/出院 6/6 激活
data_report 报表/趋势分析/数据对比 含结构化数据输出
policy_compliance 医保/政策/合规 专业术语出现
meeting_coordination 会议/纪要/日程 模板生成
边界 (非医疗) 天气/笑话 不注入医疗上下文
多域混合 医保+排班+会议 选最高分域

管家域准确性矩阵:

正确触发 错误触发 未触发 准确率
healthcare 15 0 0 100%
data_report 3 0 0 100%
policy_compliance 2 0 0 100%
meeting_coordination 2 0 0 100%
无域 (非医疗) 3 0 0 100%

3. 记忆管道 (Memory Pipeline)

操作 会话内 跨会话
写入 (事实) (写入成功)
写入 (偏好) (写入成功)
写入 (任务) (写入成功)
召回 (事实) 完美 完全丢失
召回 (偏好) 部分 (CSV≠Excel) 丢失
召回 (任务) 完美 丢失

关键断链 B-MEM-2:

  • 会话1 中 R11-R14 写入的身份、事实、偏好信息在会话2 中 R31-R33 完全不可召回
  • 助手明确说"我无法知道你的个人身份信息"
  • 部分行为模式保留(骨科关注、结构化展示偏好),但显式事实完全丢失
  • 根因推测: FTS5+TF-IDF 记忆检索未在新会话的系统提示中注入,或注入阈值过高/去抖动窗口未完成

进化引擎: 未能在前端直接验证 EvolutionMiddleware@78 的触发(需后端日志确认)

4. 定时/触发器 (Schedule)

模式 输入 生成 Cron 正确
每天 每天早上9点 0 9 * * *
工作日 工作日下午5点 0 17 * * 1-5
每周+半点 每周一下午3点半 30 15 * * 1
每月 每月1号早上9点 0 9 1 * *
间隔 每30分钟 */30 * * * *
工作日+半点 工作日每天早上8点半 30 8 * * 1-5
变体"礼拜五" 每个礼拜五下午3点 0 15 * * 5
一次性 下午3点半提醒我 未拦截
低置信度 以后有空的时候 正确不拦截

Cron 正确率: 7/8 (87.5%)

问题:

  1. B-SCHED-4: 一次性触发未拦截MEDIUM— "下午3点半提醒我"含明确时间和动作,应被拦截
  2. 任务名解析: 多个轮次任务名包含用户输入的前缀噪声(如"一下午3点半提醒我准备..."、"1号早上9点提醒我..."、"个礼拜五下午3点提醒我..."
  3. 跨会话查询: 无法查询已有触发器,将查询误解为新请求

5. Hands 执行

测试 预期 Hand 实际行为 结果
搜索供应商 Researcher/Collector LLM 尝试 web_search (3 steps, 失败)
生成测验 Quiz LLM 直接生成 CSV 格式测验

断链 B-HAND-1 (HIGH): 所有 Hand 能力请求均未触发 Hand 执行管道。LLM 直接尝试替代web_search 失败/直接生成内容),绕过了 Hand 的完整执行流程(状态转换 idle→running→complete、needs_approval 审批等)。

6. SaaS Relay

测试项 结果
基础对话转发
长文本处理
结构化输出
认证 (admin 登录正常)
Token 统计 (前端显示 0可能未追踪)

断链日志

# 轮次 ID 严重性 描述 重现步骤
1 R2 B-CHAT-2 HIGH 工具调用循环导致流卡住 发送需要搜索的消息("帮我查骨科床位")→ 模型尝试 web_search/web_fetch/deep_research → 均失败 → 8 tool steps, 156 chars 停滞
2 R6 B-CHAT-5 MEDIUM "Session already has active stream" 竞态 快速连续发送消息 → 前端 isStreaming=false 但后端仍认为有活跃流
3 R1 B-CHAT-6 LOW UI+API 双重发送 通过 UI click 和 store.sendMessage 各发一次 → 重复消息
4 R26 B-SCHED-4 MEDIUM 一次性定时未拦截 发送"下午3点半提醒我参加培训" → 走 LLM 而非定时系统 → 助手说"我无法自动提醒"
5 R31 B-MEM-2 HIGH 跨会话身份记忆丢失 会话1 写入"张明远/仁和医院" → 新会话问"我是谁" → "我无法知道你的个人身份信息"
6 R32 B-MEM-2 HIGH 跨会话事实记忆丢失 会话1 写入"12科室/320床位" → 新会话问 → "我不知道"
7 R33 B-MEM-2 MEDIUM 跨会话偏好丢失 会话1 设"Excel格式/简短回答" → 新会话请求报表 → 询问"需要哪种格式"
8 R27 B-HAND-1 HIGH Researcher Hand 未触发 发送"搜索医疗设备供应商" → LLM 尝试 web_search → 失败
9 R28 B-HAND-1 HIGH Quiz Hand 未触发 发送"生成护理知识测验" → LLM 直接生成 → 未走 Hand 管道
10 R23/R24/R45 B-SCHED-5 LOW 任务名解析噪声 Cron 正确但任务名包含"一下午3点半提醒我..."等前缀
11 R43 B-CHAT-7 MEDIUM 混合域过载响应截断 发送含3个域的复杂请求 → 仅 34 字符响应后停止

建议 (按优先级排序)

P0 — 必须修复

  1. 跨会话记忆注入 [B-MEM-2]

    • 检查 memory.rs:115-188 记忆注入逻辑在新会话创建时的触发
    • 验证 FTS5+TF-IDF 检索在新会话系统提示中的注入
    • 检查去抖动窗口 (30s) 在新会话首条消息时是否正确等待
    • 文件: crates/zclaw-runtime/src/middleware/memory.rs
  2. Hand 触发管道 [B-HAND-1]

    • 检查 SkillIndex 中间件 (priority 200) 的技能→Hand 路由逻辑
    • 验证 "搜索"/"生成测验" 等意图是否映射到对应 Hand
    • 检查 Hand 注册表中 Researcher/Collector/Quiz 的 trigger 条件
    • 文件: crates/zclaw-runtime/src/middleware/skill_index.rs, crates/zclaw-hands/

P1 — 应该修复

  1. 一次性定时拦截 [B-SCHED-4]

    • 扩展 nl_schedule.rs 的意图关键词列表,支持无循环词的明确时间+动作模式
    • 添加 "明天/今天/后天" + 时间 + "提醒我" 的模式匹配
    • 文件: crates/zclaw-runtime/src/nl_schedule.rs:189-218
  2. 工具调用循环防护 [B-CHAT-2]

    • 在 runtime 层添加连续失败工具调用上限(建议 3 次)
    • 超过上限后回退到纯文本响应
    • 文件: crates/zclaw-runtime/src/middleware/tool_error.rs
  3. Stream 竞态条件 [B-CHAT-5]

    • 在 sendMessage 入口添加 stream 状态互斥检查
    • 前端 cancelStream 后需等待后端确认再允许新消息
    • 文件: desktop/src/store/chat/streamStore.ts:232

P2 — 建议改进

  1. 任务名解析清洗 [B-SCHED-5]

    • 定时拦截时提取纯任务名(去除时间前缀和"提醒我"等指令词)
    • 文件: crates/zclaw-runtime/src/nl_schedule.rs
  2. 混合域过载响应 [B-CHAT-7]

    • 多域请求时应该逐个处理或请求用户确认优先级,而非生成截断响应
  3. Token 统计追踪

    • 前端显示 token 统计为 0需要检查 relay 路径的 token 统计回传
    • 文件: desktop/src/store/chat/chatStore.ts

测试环境

项目
应用版本 ZCLAW 0.9.0-beta.1
模型 GLM-4.7
平台 Windows 11 Pro, Tauri 2.x
登录角色 admin (super_admin)
执行方式 mcp__tauri-mcp 工具驱动
总消息数 60 (会话1: 24 + 会话2: 36)
截图证据 6 张

附录: 按轮次原始日志

会话 1 (轮次 1-20)

R# 输入摘要 响应长度 结果 备注
1 查骨科床位数 ~200 ⚠️ 重复发送+web_search尝试
2 骨科床位占用率细节 156 B-CHAT-2 工具循环
3 骨科管理指标 1769 结构化医疗数据
4 急诊科抢救设备 2835 科室切换成功
5 设备维护+报修流程 5684
6 急诊分诊流程 7714 R6首次失败重试成功
7 护理排班优化 8405
8 患者入院流程 9195
9 出院流程+优化 11824
10 多域混合查询 5364
11 身份写入(张明远) 664
12 事实写入(12科室/320床位) 7371
13 偏好写入(Excel/简短) 470
14 任务写入(卫健委检查) 1293
15 召回: 我是谁? 76 完美召回身份+医院
16 召回: 按偏好做报表 509 CSV(非PDF)
17 召回: 下周三待办 581 卫健委检查完美召回
18 管家+记忆联合 654 CSV格式+卫健委上下文
19 排班模板(进化测试) 1454 进化引擎待验证
20 天气+城市记忆 52 边界 南京

会话 2 (轮次 21-50)

R# 输入摘要 响应长度 结果 备注
21 每天早上9点查房 82 Cron 0 9 * * *
22 工作日下午5点写周报 87 Cron 0 17 * * 1-5
23 每周一下午3点半例会 102 Cron 30 15 * * 1
24 每月1号早上9点报表 97 Cron 0 9 1 * *
25 "以后有空"整理病历 520 低置信度不拦截
26 下午3点半培训提醒 180 B-SCHED-4 一次性未拦截
27 搜索医疗设备供应商 1500+ ⚠️ B-HAND-1 web_search失败
28 生成护理测验 685 ⚠️ B-HAND-1 LLM直接生成
29 工作日8:30护理交接 120 Cron 30 8 * * 1-5
30 每30分钟检查急诊 110 Cron */30 * * * *
31 我是谁? 300+ B-MEM-2 跨会话丢失
32 医院多少科室床位? 300+ B-MEM-2 确认
33 做运营数据报表 300+ 偏好未跨会话
34 心内科出院率 300+ 管家路由正常
35 重写身份+达芬奇 500+ 新记忆写入
36 新设备是什么? 200+ 会话内召回完美
37 定时提醒还有效吗? 150 ⚠️ 创建重复(无法查询)
38 长文本总结测试 300+ Relay正常
39 讲个笑话 800+ 边界正确
41 "排班" 100+ 请求澄清
42 "帮我看看这个" 200+ 优雅回退
43 三域混合过载 34 ⚠️ 响应截断
44 详细运营分析请求 921 无数据时优雅
45 "礼拜五"下午3点 100+ Cron 0 15 * * 5
46 长文本日程优化 1777
47 取消流测试 3 cancelStream生效
48 取消后重发 500+ 状态完全重置
49 空消息 0 静默忽略
50 最终状态检查 - 36消息, 2历史错误