返回博客

让 AI 编码助手从每次对话中学习

每次用 AI 工具处理一个有难度的 bug,事后你可能会感叹「这个思路挺有用的」,然后关掉窗口,下次遇到同类问题还是从零开始——AI 也是如此。每次会话结束,那些「它学会的」模式就随着上下文消失了。

这个问题本质上不是 AI 的记忆问题,而是工程流程问题:有没有一个机制,在会话结束时把值得保留的模式提炼出来,写到某个可被下一次会话读到的地方?

用 Stop Hook 做批量收割

最简单的切入点是 Claude Code 的 Stop hook。每次会话自然结束时,它会触发一个脚本:

{
  "hooks": {
    "Stop": [{
      "matcher": "*",
      "hooks": [{
        "type": "command",
        "command": "~/.claude/skills/continuous-learning/evaluate-session.sh"
      }]
    }]
  }
}

脚本做的事情很简单:读取本次会话的完整 transcript,判断是否够长(比如 10 条以上),然后识别几类值得沉淀的模式:

  • 错误解决路径(error_resolution
  • 用户对 AI 的纠正行为(user_corrections)——这是最有价值的信号
  • 绕过框架 / 库 quirk 的技巧(workarounds
  • 调试手法(debugging_techniques
  • 项目专属约定(project_specific

识别到的模式以 skill 文件的形式写到 ~/.claude/skills/learned/,下次会话开始时自动加载。

这套方案的优点是轻量:只在会话结束时跑一次,不增加每条消息的延迟,也不消耗上下文窗口。

最有价值的信号

用户对 AI 的纠正行为(「不对,应该这样」「你理解偏了」)是最高信噪比的学习素材——它明确标出了 AI 的盲点在哪里,而这类信号在普通对话记录里往往被忽视。

v1 的天花板:skill 是概率性的

用了一段时间后会发现一个问题:skill 并不是每次都会被触发,触发率大约在 50%~80% 之间。原因是 skill 依赖会话上下文里的语义匹配,而语义匹配本质上是模糊的。

更严格的观察方案是 Homunculus v2 的思路——用 PreToolUsePostToolUse hook 替代 Stop hook 做实时观察。这样每一次工具调用都被记录,观察是 100% 可靠的。

提取的单位也从「skill」变成更细粒度的「直觉(instinct)」:

| 维度 | v1(Stop hook) | v2(实时 hook) | |------|----------------|----------------| | 观察时机 | 会话结束后批量 | 每次工具调用实时 | | 分析主体 | 主上下文内处理 | 独立 background agent(轻量模型) | | 沉淀单位 | 完整 skill | 原子 instinct(带置信度 0.3~0.9) | | 演化路径 | 直接写 skill 文件 | instinct 聚类 → 晋升为 skill/命令/agent | | 置信衰减 | 无 | 有(被反驳则降权) |

原子直觉的设计有点像 A/B 测试里的多臂老虎机:每条 instinct 都有一个置信分,被后续行为验证则升权,被推翻则降权,累积到阈值才晋升为 skill。这让学到的东西更鲁棒,而不是一次写入就永久生效。

取舍:选哪条路?

两个方案的核心取舍是成本 vs 可靠性

  • Stop hook 方案成本极低,适合个人日常使用,漏掉一些模式也无所谓;
  • 实时 hook + background agent 方案捕获率更高,但每次工具调用都有额外开销,需要为分析 agent 付费,且系统复杂度明显上升。

如果你只是想「比没有强」,Stop hook 已经够用。如果你在构建一个需要持续演化的 AI 工程系统,实时观察 + 置信度管理的架构才值得投入。

还有一个常被忽略的过滤维度:哪些模式不值得沉淀。一次性 API 故障、外部服务的临时问题、简单笔误——这类噪音混进 skill 库会降低整体质量。显式维护一份 ignore_patterns 清单和维护 patterns_to_detect 同样重要。

一句话心法

让系统在每次结束时留下一行脚印,比靠人工复盘更可持续——关键是把「沉淀」变成工程流程里的一个节点,而不是一件需要意志力的事。