08 · PreToolUse / UserPromptSubmit Hook · 意图检测自动联动¶
v0.8 新增 · 2026-06-14 目标: 把 PM 的 5 步手动操作压缩到 1 句话 → 自动触发整套体系
1. 价值主张¶
当前痛点(v0.7): PM 接到新项目要手动跑 5 步:
1. lesson_lookup_hook.py --query "..." 拉历史教训
2. 判断要不要 spawn_new_base.py --customer ...
3. 决定 invoke 哪个 skill(三类业务 × 6 领域共 18 组合)
4. 看历史踩坑 md 找类似项目
5. 起 .env / settings 配置
v0.8 目标(本 hook): PM 一句话 "我做 LegalCo 法律教案" → hook 自动:
- 检测意图(领域=法律, 业务类别=第二类知识教案, 甲方=LegalCo)
- 注入历史教训 top 5(SBERT 检索)
- 提示是否建专属 base(查 customer_bases.csv 看是否新甲方)
- 推荐 invoke agent-knowledge-task skill
- 把意图注入 Claude 上下文供下游决策
收益: 流程零摩擦,新员工也能立项即用,所有 PM 决策都有历史教训垫底。
2. Hook 类型选型¶
| Hook 类型 | 触发时机 | 能否注入上下文 | 是否阻塞 | 适合本场景? |
|---|---|---|---|---|
UserPromptSubmit |
用户提交 prompt 之后, 工具调用之前 | ✅ additionalContext |
可阻塞 (exit 2) | ✅ 首选 |
PreToolUse |
每个工具调用前 | ❌ 只能改参数 | 可阻塞 | ❌ 每次工具都触发, 噪音大 |
SessionStart |
会话开启时 | ✅ | 否 | ❌ 与具体项目无关 |
结论: 用 UserPromptSubmit(任务清单原名 PreToolUse 是泛指 "请求前 hook" 的口语化, 实际更精准是 UserPromptSubmit)。
3. 触发场景清单¶
3.1 三类业务关键词¶
| 触发短语 (正则) | 业务类别 | 推荐 skill |
|---|---|---|
我做.*(12 ?案例|出题|垂域出题|案例.*ECC[-\s]?\d+) |
一 | ecc-vert-case |
我做.*(知识教案|领域知识|6 ?领域) |
二 | agent-knowledge-task |
我做.*(agent.*基准|端到端评测|L3 ?基准|SWE[-\s]?bench) |
三 | agent-benchmark-lab |
3.2 六领域关键词(第二类用)¶
| 触发短语 | 领域 |
|---|---|
金融\|风控\|量化\|财报\|宏观经济 |
金融 |
法律\|法条\|案例分析\|合同\|司法 |
法律 |
医疗\|临床\|药物\|医学影像\|循证 |
医疗 |
工程\|CAD\|结构计算\|电路\|编程自动化 |
工程 |
农业\|作物\|病虫害\|土壤\|精准农业 |
农业 |
3.3 甲方识别¶
正则: (?:为|给|帮)([A-Z][A-Za-z0-9]+|[一-龥]{2,8})(?:.*?)(?:做|开发|交付)
样例: - "为 LegalCo 做法律教案" → customer=LegalCo - "给 AgentTrain 出 12 案例" → customer=AgentTrain - "帮深圳XX公司做评测" → customer=深圳XX公司
匹配后查 ~/Downloads/customer_bases.csv — 若不存在则提示 spawn_new_base.py。
4. Hook 协议 (Claude Code)¶
4.1 输入 (stdin JSON)¶
{
"hook_event_name": "UserPromptSubmit",
"session_id": "xxx",
"transcript_path": "/path/to/transcript.jsonl",
"cwd": "C:\\Users\\chunx",
"prompt": "我做 LegalCo 法律教案"
}
4.2 输出 (stdout JSON)¶
{
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "<auto-injected by ecc-intent-detector>\n意图: 第二类知识教案 / 领域=法律 / 甲方=LegalCo (新甲方,建议 spawn_new_base)\n\n=== 历史教训 top 3 (SBERT) ===\n[1] score=0.834 · ecc-shared/audit-mock/01_对抗审查报告.md · 知识密度审计\n 第二类知识教案要求每题 ≥5 个 Knowledge Points + ≥200 字背景知识...\n...\n\n=== 推荐 invoke ===\n- skill: agent-knowledge-task\n- 模板: ~/.claude/skills/ecc-shared/sop/04_5角色SOP教程.md (角色2 教案人)\n\n=== 下一步建议 ===\n1. python ~/.claude/skills/ecc-shared/scripts/spawn_new_base.py --customer LegalCo\n2. python ~/.claude/skills/ecc-shared/scripts/knowledge_skeleton_generator.py --domain 法律\n</auto-injected>"
}
}
4.3 阻塞策略 — 不阻塞¶
- exit 0, 静默注入
- 不打断用户 prompt
- 用户可忽略也可采纳建议
5. 实现拆分¶
| 模块 | 文件 | 职责 |
|---|---|---|
| 意图识别引擎 | scripts/intent_detector.py |
正则匹配 + 关键词扫 → Intent dataclass |
| Hook 入口 | scripts/user_prompt_submit_hook.py |
读 stdin JSON, 调 intent_detector + lesson_indexer_v2, 输出 stdout JSON |
| 单测 | scripts/test_intent_detector.py |
pytest, 覆盖 9 类触发场景 |
| Settings | ~/.claude/settings.json 注册 hook |
(用户级或项目级) |
6. Intent 数据结构¶
from dataclasses import dataclass
@dataclass(frozen=True)
class Intent:
category: str | None # "一" / "二" / "三" / None
skill: str | None # "ecc-vert-case" / "agent-knowledge-task" / "agent-benchmark-lab"
domain: str | None # "金融" / "法律" / "医疗" / "工程" / "农业" / "其他"
customer: str | None # 甲方简称
is_new_customer: bool # 查 customer_bases.csv 后判定
confidence: float # 0.0 ~ 1.0 (匹配规则数)
matched_phrases: tuple[str, ...] # 触发的短语
7. 测试用例(B2 阶段写)¶
| ID | 输入 prompt | 期望 category / skill / domain / customer |
|---|---|---|
| T1 | "我做 12 案例 ECC-2026-007" | 一 / ecc-vert-case / None / None |
| T2 | "我做 CAD 知识教案" | 二 / agent-knowledge-task / 工程 / None |
| T3 | "我做 LegalCo 法律教案" | 二 / agent-knowledge-task / 法律 / LegalCo (新) |
| T4 | "我做 agent 端到端评测 L3 基准" | 三 / agent-benchmark-lab / None / None |
| T5 | "为 AgentTrain 做评测" | 三 / agent-benchmark-lab / None / AgentTrain (老) |
| T6 | "帮医疗甲方做循证医学教案" | 二 / agent-knowledge-task / 医疗 / None |
| T7 | "你好" | None / None / None / None (零匹配, 不注入) |
| T8 | "我做金融风控建模" | 二 / agent-knowledge-task / 金融 / None |
| T9 | "我做 SWE-bench 真跑" | 三 / agent-benchmark-lab / None / None |
8. 部署 — settings.json 配置¶
8.1 用户级 (~/.claude/settings.json)¶
{
"hooks": {
"UserPromptSubmit": [
{
"command": "python C:/Users/chunx/.claude/skills/ecc-shared/scripts/user_prompt_submit_hook.py",
"description": "ECC 意图检测 - 自动注入历史教训和推荐",
"timeout": 5000
}
]
}
}
8.2 性能预算¶
- 冷启动 SBERT: ~3 秒(load model + load embedding)
- 检测 + 检索: <500 ms
- 总 timeout: 5 秒
- 降级: 超时直接 exit 0 无输出, 不阻塞用户
8.3 关闭开关¶
环境变量 ECC_INTENT_HOOK_DISABLED=1 可临时关闭(脚本第一行检查)。
9. 与现有 19+1 脚本的集成¶
| 上游/下游 | 集成方式 |
|---|---|
lesson_indexer_v2.py |
hook 调 search(query, top_k=3) 函数(已模块化) |
lesson_lookup_hook.py |
弃用(本 hook 是其升级版) |
spawn_new_base.py |
hook 仅提示, 不自动调用(避免意外建 base) |
customer_bases.csv |
hook 读它判定 is_new_customer |
10. v0.8 完成判定 (B3 端到端测)¶
用户在 Claude Code 输入: "我做 LegalCo 法律教案"
预期看到的 additionalContext:
✓ 业务类别: 第二类知识教案
✓ 领域: 法律
✓ 甲方: LegalCo (老甲方, base_token=A5JzbN8iLabehnsmRVAcFHFqn5f)
✓ 历史教训 top 3
✓ 推荐 invoke agent-knowledge-task
✓ 下一步: knowledge_skeleton_generator --domain 法律
作者: chunx + claude (v0.8 Track B1)
下一步: B2 写 intent_detector.py + user_prompt_submit_hook.py + 9 用例 pytest
关联: SOP 主文档 01_统一SOP主文档.md 第 5 章 PM 流程