0. 从「记忆回放」到「记忆进化」

前两篇我们把 memory system 拆成了两半:第 4 篇讲「为什么要有」(context window 不够、跨 session 知识断片、verification 没有 anchor),第 5 篇讲「怎么存怎么取」(文件式 storage、index 注入、读时 verify、与 prompt cache 的合作)。

但如果故事到这里就结束,memory 只是一个录音机——你昨天说过什么、做过什么,今天能播放出来。这远远不够。一个真正可用于生产的 agent 必须做到一件事:犯过的错不再犯第二次。这才叫「记忆进化」(memory evolution)。

录音机和进化的区别在于一个闭环

tool 失败  →  hook 捕获  →  写入 memory  →  下次 session
system prompt assembly 时读到  →  agent 行为改变  →  下次成功

任何一个齿轮缺位,闭环就断。本文沿着这条闭环,依次拆四个齿轮:

  1. Hooks——闭环的 capture 端,把 runtime 信号引到 memory;
  2. MCP——独立于本地 memory 的第二条记忆通道,让团队级最佳实践跨 agent 注入;
  3. CLAUDE.md——项目契约,把人类约定固化为 system prompt 的一部分;
  4. Skills + Plugins——把好行为制度化,从「每次重新发现」升级为「永久封装」。

本文是系列第 6 篇,也是终篇。文末会回顾整条主线,并埋一个彩蛋:当你把这套纪律推到极致,下一步就是领域特化 agent(domain-specialized agents)。


1. Hooks:Memory 反馈环的注入点

整个闭环里,Hook 是离 runtime 最近的一环。在 claw-code 的 Rust 工作区里,它的定义集中在两个文件:

  • rust/crates/runtime/src/hooks.rs:定义 HookEvent 枚举和分发器。
  • rust/crates/plugins/src/hooks.rs:plugin 侧的 hook 协议适配。

我们关心三类事件:

1
2
3
4
5
pub enum HookEvent {
    PreToolUse { tool: String, input: Value },
    PostToolUse { tool: String, input: Value, output: Value },
    PostToolUseFailure { tool: String, input: Value, error: String },
}

Hook 的返回值结构(PDF §8.5)允许它做四件事:

  1. 追加 message——把一段文字加到对话里;
  2. 注入 additionalContext——在下一轮 system prompt assembly 时被读取;
  3. 阻断 continuation——直接终止 agent 的 next step;
  4. 更新 MCP tool output——在 output 走回 model 之前重写它。

请注意第 2 条。additionalContext 不只能影响下一个 turn,它可以被持久化。当 hook 同时把这条 context 追加到 MEMORY.md,下次 session 启动时 system prompt assembly 会再次读到它——这就是闭环的 capture 端。

最自然的应用是 PostToolUseFailure

1
2
3
4
def on_post_tool_use_failure(tool, input, error):
    line = f"- [debug] tool {tool} failed: {error[:80]} on {today()}"
    append_to_memory(line)
    return {"additionalContext": f"Note: {tool} just failed because {error}. Avoid repeating."}

这一段不到 5 行代码,但它跨越了两个时间尺度:additionalContext 解决本 session 的连续犯错(同一个 turn 里别再调一次失败的 tool),append_to_memory 解决跨 session 的重复犯错(明天另一个 worktree 启动时就知道)。

工程上要记住一句话:Hook 是 memory 唯一可信的 writer。直接让 LLM 自己写 memory 容易引入幻觉(claim without evidence),但 hook 拿到的是真实的 tool 调用结果——它写下去的失败原因是事实,不是叙述。


2. MCP:第二条记忆通道

MCP(Model Context Protocol)通常被介绍为「让外部服务暴露 tool」。但从 memory 的视角看,它是第二条独立的记忆通道

PDF §7.5 描述 claw-code 的 system prompt assembly 时,会调用 getMcpInstructionsSection(mcpClients):把每个连接的 MCP server 在握手阶段给出的 instructions 字段,拼成 prompt 的一段。

这意味着一台 MCP server 可以同时 ship 两样东西:

  • tool schema:它能干什么;
  • operator-style instructions:它应该怎么被使用——一段自然语言指南、约定、避坑提示。

为什么这是「第二条记忆通道」?因为本地 MEMORY.md用户/项目维度的,每个仓库、每个开发者都可能不一样;而 MCP instructions 是服务维度的,由提供方维护,跨所有连接它的 agent 共享。

工程价值非常大。设想一家公司有内部 DevOps MCP server:

1
2
3
4
// MCP server 握手返回
{
  "instructions": "Always run `internal-deploy --dry-run` before any prod deploy.\nNever skip the staging gate.\nIf `kube-ctx` shows prod, require human confirmation."
}

这段话不需要每个团队成员手动加进自己的 CLAUDE.md——只要他们的 agent 连了这台 MCP server,下一轮 system prompt assembly 时这段约定就自动注入。MCP 让「公司级最佳实践」获得了一个集中维护、跨 agent 自动分发的载体。

放回闭环里看,MEMORY.mdbottom-up 的(hook 从 runtime 失败里学到),MCP instructions 是 top-down 的(团队从经验里写下)。两条通道在 system prompt assembly 时合流。


3. CLAUDE.md:项目契约

如果说 MEMORY.md 是 agent 的工作笔记、MCP instructions 是服务说明书,那么 CLAUDE.md项目契约——人类对 agent 在「这个仓库里应该怎么干」的明确约定。

我们直接看 claw-code 自己的 CLAUDE.md(仓库根目录):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Detected stack
- Languages: Rust.
- Frameworks: none detected from the supported starter markers.

## Verification
- Run Rust verification from `rust/`: `cargo fmt`, `cargo clippy --workspace --all-targets -- -D warnings`, `cargo test --workspace`
- `src/` and `tests/` are both present; update both surfaces together when behavior changes.

## Repository shape
- `rust/` contains the Rust workspace and active CLI/runtime implementation.
- `src/` contains source files that should stay consistent with generated guidance and tests.
- `tests/` contains validation surfaces that should be reviewed alongside code changes.

## Working agreement
- Prefer small, reviewable changes and keep generated bootstrap files aligned with actual repo workflows.
- Keep shared defaults in `.claude.json`; reserve `.claude/settings.local.json` for machine-local overrides.
- Do not overwrite existing `CLAUDE.md` content automatically; update it intentionally when repo workflows change.

短、操作化、可执行。值得逐段品:

  • Detected stack:把「这是个 Rust 项目」写成事实,省掉 agent 每次启动时去 sniff Cargo.toml
  • Verification:三条命令——cargo fmtcargo clippy --workspace --all-targets -- -D warningscargo test --workspace——这是「写完代码以后必须跑什么」的契约。第 5 篇讲过,这种可执行 anchor 让 verification 可以自我验证。
  • Repository shape:明确 rust/src/tests/ 三处的关系。
  • Working agreement:四条工作约定,最后一条是真正的元规则——

Do not overwrite existing CLAUDE.md content automatically; update it intentionally when repo workflows change.

这条是整篇文档的灵魂。它在说:memory 是 workflow 的一部分,不只是 workflow 的描述。当工作流变了,CLAUDE.md 必须被有意识地更新;反过来,CLAUDE.md 的更新也是工作流变化的官方公告。

把三条通道并排看:

通道维护者作用域更新频率
MEMORY.mdhook 自动 + 人工项目/用户每次 session
MCP instructions服务提供方跨 agent服务版本
CLAUDE.md人类有意识项目workflow 变更时

三者在 system prompt assembly 阶段合流,给 agent 一个多源、有层次的上下文


4. 协同图景

把上面四节合起来,每一个 turn 实际上长这样:

flowchart LR
  subgraph "Each Turn"
    SP[System prompt assembly] --> CMD[CLAUDE.md + MEMORY.md + MCP instructions]
    CMD --> AG[Agent decides]
    AG --> T[Tool exec]
    T --> H[PostToolUse hook]
    H -->|additionalContext / updatedInput| AG
    H -->|append finding| MEM[(Memory files)]
  end
  MEM -. next session .-> CMD
  Plugin[(Plugin/Skill state dirs)] -. next session .-> CMD

注意两条虚线——它们才是「进化」。实线是单 session 内部的回放,虚线是跨 session 的进化。一个 agent 是「录音机」还是「学习者」,区别就在那两条虚线是否真正连通。


5. 长周期失败模式(必须警惕的 4 种)

把闭环画出来容易,运行一年不出问题难。下面四种是工程上反复踩到的坑:

5.1 Silent drift:PromptCacheEvent.unexpected=true 但 fingerprint 稳定

第 5 篇讲过 prompt cache fingerprint 的作用。问题是:fingerprint 稳定不等于语义稳定。当上游 model 静默升级、tokenizer 微调、模板渲染顺序换了,可能 fingerprint 一致但 cache 命中率突然崩盘——unexpected=true 比例飙升。

现象:钱包黑洞。每个 turn 的 prefill cost 翻倍,但 agent 行为看似没变。

防线:把 cache_hit_rate 作为 SLI 持久化到 metrics,跨周做趋势告警,而不是只盯单 session。

5.2 Identity loss:post-compaction 的健康探针失败

run_session_health_probe() 是 compaction 之后的强制 sanity check(PDF 第 6 章)。当它失败,意味着 agent 在压缩之后不知道自己是谁了——project root 丢了、当前任务 id 丢了、CLAUDE.md 摘要被吞掉。

现象:agent 突然开始问「我们刚才在做什么?」或者用通用模板回答原本有项目特化答案的问题。

防线:把健康探针失败当作强制 hard-stop,要求人工介入或回滚到上一个 checkpoint,绝不能让它继续 silently 跑。

5.3 Repeated mistake loop:PostToolUseFailure 没写 memory

这是闭环最常见的断点。Hook 触发了、错误信息也拿到了,但没有 append 到 MEMORY.md——可能是 hook 实现忘了,可能是写入路径权限问题,可能是 atomic write 失败被吞了 exception。

现象:同样的 tool 错误一周内被 agent 触发 50 次,每次都是「初次见面」。

防线:把「failure → memory write」做成 contract test,pre-merge 强制跑一次注入失败的回归 case。

5.4 Verification avoidance + 80% illusion(PDF §6.7)

最隐蔽。Memory 里只存 claim 不存 evidence——「我已经修复了这个 bug」「测试通过了」「部署成功了」。下一次 session 读到这些 claim 当事实信,连锁失败。

PDF §6.7 把它叫做「Verification Avoidance」:agent 倾向于声称完成而不是证明完成。配合 80%-of-the-way illusion——做完 80% 就感觉做完了——memory 就会沉淀一堆假阳性。

防线:memory 写入必须配 evidence anchor。例如「✓ test suite passed」必须带上 cargo test --workspace 的实际 stdout 摘要或 exit code,不能只写一句「passed」。这就是为什么 claw-code 的 CLAUDE.md 里要把 cargo fmt / cargo clippy / cargo test 写明——这些命令本身就是 evidence 生成器。


6. Skills + Plugins:把好行为制度化

闭环跑顺了之后,下一个问题是:怎么让好行为不依赖个体灵感

PDF §7 给出的答案是 Skills + Plugins。

Skills 是 prompt-native 的 workflow 包,每个 skill 是一个 markdown 文件,frontmatter 声明它需要哪些 tool、什么条件下激活。例如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
---
name: rust-pr-review
allowed-tools: ["bash", "read_file"]
trigger: "when reviewing a Rust PR"
---

1. Run `cargo fmt --check` and report diffs.
2. Run `cargo clippy --workspace --all-targets -- -D warnings`.
3. Run `cargo test --workspace`.
4. Summarize failures with file:line anchors.

这不是 memory,但它复用了 memory 的纪律:把「应该怎么做」固化成可执行 anchor。Skill 的好处是条件性 context 注入——只有匹配 trigger 时才占 prompt 预算,不像 CLAUDE.md 永远在场。

Plugins 是 Skill 的分发载体(PDF §7.2,相关代码在 claw-code 的 src/utils/plugins/loadPluginCommands.ts)。Plugin 在加载时会暴露一组环境变量给 skill 使用:

  • ${CLAUDE_PLUGIN_ROOT}:plugin 安装目录;
  • ${CLAUDE_PLUGIN_DATA}:plugin 的可写数据目录(可以放跨 session 的状态);
  • ${CLAUDE_SKILL_DIR}:当前 skill 的资源目录;
  • ${CLAUDE_SESSION_ID}:当前 session 的唯一 id;
  • ${user_config.X}:用户在 plugin manifest 里声明的可配置项。

注意 ${CLAUDE_PLUGIN_DATA}——它就是 plugin 自己的「memory 抽屉」。Memory / Skill / Plugin 三者的关系可以这样理解:

Memory 沉淀经验,Skill 把经验封装成可调用的动作,Plugin 把动作做成可分发的包。

闭环到这里就 self-reinforcing 了:runtime 失败 → hook 写 memory → 经验稳定后被人手 promote 成 skill → skill 被打包成 plugin → plugin 在团队里分发 → 整个团队的 agent 直接拿到「现成的好行为」,不必每个人重新踩一遍坑。


7. 代码 demo:三个 turn 看 memory 进化

完整代码在 cli-agent/code/06-memory-evolution-and-agent/memory_evolution.py。它 stdlib only、<150 LOC,用最小模型还原前文的闭环。

核心结构:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Agent:
    system_prompt_sections = [
        BASE_INSTRUCTIONS,
        load("CLAUDE.md"),
        load("MEMORY.md"),       # ← 闭环的 read 端
        MCP_INSTRUCTIONS,
    ]

    def on_post_tool_use(self, tool, args, result):
        if not result.ok:
            append_memory(f"- [debug] tool {tool} failed for {result.reason} on {today}")
        elif tool.startswith("verify_") and result.ok:
            append_memory(f"- [verified] {tool}({args}) -> {result.value} on {today}")

跑 3 个 turn:

  • Turn 1:agent 调用 deploy(env="prod"),hook 截获错误「missing dry-run gate」,append 到 MEMORY.md
  • Turn 2:新 session 启动,system prompt assembly 把上一条 lesson 注入。Agent 看到后改先跑 verify_dry_run
  • Turn 3:dry-run 通过,verified 事实也被记下。deploy 这次成功。

每个 turn 之间打印 MEMORY.md 的 diff,进化轨迹一目了然。读者可以直接 python memory_evolution.py 跑起来看。


8. 系列回顾 + 下一步可以做什么

到这里,整个《CLI Agent 深入浅出》系列就走完了。回看 6 篇主线:

  1. 第 1 篇 · 工业级 Agentic Workflow 总览——主循环、turn 边界、显式控制流为什么重要。
  2. 第 2 篇 · Tool 与 Permission——tool surface 的设计,permission boundary 是 trust 的边界。
  3. 第 3 篇 · Subagent / Plan / Worktree——并行隔离的三种姿势,沙箱即纪律。
  4. 第 4 篇 · Memory System 之 Why——为什么单靠 context window 撑不住,memory 是 verification 的 anchor。
  5. 第 5 篇 · Memory 的存储、检索与失效——文件式 storage、index 注入、读时 verify、与 prompt cache 的合作。
  6. 第 6 篇 · Memory 与 Agent 的协同演化(本篇)——Hooks/MCP/CLAUDE.md/Skills+Plugins 四个齿轮把闭环 self-reinforcing。

如果只能记一句话,那就是:

工业级 agent = 显式控制流 + 类型化记忆 + 可观测闭环。

显式控制流让你在每一个 turn 都知道控制权在谁手里;类型化记忆让你的 context 不再是字符串拼贴而是有 schema 的事实库;可观测闭环让你的 agent 跑得越久越聪明而不是越漂移。

下一步可以做什么?把这套纪律推到极致,最自然的方向是领域特化 agent(domain-specialized agents):

  • DB ops agentCLAUDE.md 写明 schema 约束、verification 是 explain plan、memory 沉淀慢查询模式、MCP 通道暴露内部 query gateway。
  • SRE agent:hooks 直接挂在 incident channel,memory 沉淀 postmortem 关键字,skill 封装 runbook,plugin 跨团队分发。
  • Scientific computing agent:CLAUDE.md 写实验规范,verification 是 reproducibility check,memory 存 hyperparameter trace + dataset fingerprint。

通用 agent 解决「能做」,领域特化 agent 解决「做对」。当一个领域里的失败模式被 hook 充分捕获、被 memory 充分沉淀、被 skill 充分封装、被 plugin 充分分发,这个领域的 agent 就真的能上生产了——这正是工业级 agent 这个词最终的意义。

愿你写出的 agent,下次 session 比这次更聪明一点。


引用

  • claw-code: rust/crates/runtime/src/hooks.rsrust/crates/plugins/src/hooks.rs
  • claw-code 仓库根 CLAUDE.md(本文 §3 完整引用)
  • claw-code: src/utils/plugins/loadPluginCommands.ts(PDF §7.2)
  • PDF §6.7(Verification 纪律)、§7(Skills/Plugins)、§7.5(MCP instructions)、§8.5(Hook 回馈)
  • 本系列 1–5 篇