Claude Code 用 "分层注入 + 可选上下文(system-reminder)+ 按需能力加载(skills)+ 隔离执行(sub-agent)" 把上下文工程系统化:既解决"上下文太长/指令过载"的工程问题,也试图把 prompt injection 风险隔离在可控边界内。
0. 背景与动机
-
文中引用了两条推文观点:与其叫"提示词工程",更准确的是上下文工程------核心是把"恰好足够"的信息放入上下文窗口,让模型能走到下一步。
-
作者认为 Claude Code 是目前最复杂、实现最精密但也最不透明的工业级 LLM 应用案例之一。
-
逆向方式(文中提到两种):
-
用 mitmproxy 拦截 Claude Code 与服务端之间的 API 调用
-
让 Claude Code 自己输出它收到的系统提示词片段
-
-
结论之一:在用户输入到达模型前,Claude Code 会注入至少 5 层额外信息。
1. 总览:Claude Code 的"多层注入系统"(5 层)
作者把 Claude Code 的上下文组织抽象为五层,每层解决一类问题,尽量互不干扰:
-
Layer 1:System Prompt(系统提示词)
-
安全规则、工具使用规则、输出格式等
-
特点:全会话有效、用户不可修改
-
-
Layer 2:CLAUDE.md(项目约定)+ System-Reminder(包装机制)
-
项目规范 / 代码风格 / 团队约定等
-
特点:每条消息前注入(更像"长期背景/规范")
-
-
Layer 3:Slash Commands(斜杠命令)
-
用户显式触发的"单次注入工作流"
-
特点:单次轮次有效、把一整段工作流指令注入当前消息
-
-
Layer 4:Skills(技能)
-
模型按需加载的"专业指令集"
-
特点:模型自主决定是否加载;加载后把 SKILL.md 的内容注入对话继续执行
-
-
Layer 5:Sub-Agents(子 Agent)
-
完全隔离的新对话/新上下文
-
特点:隔离执行,只返回最终结果,中间过程不可见
-
2. 为什么要分层注入?
2.1 类比:LLM 像操作系统
-
文中类比:LLM 像新型操作系统
-
LLM = CPU
-
上下文窗口 = RAM
-
-
RAM 有限:系统必须决定
-
什么信息放进上下文
-
什么时候加载
-
什么时候丢弃
-
2.2 "指令过载"问题
-
文中提到:系统提示词大约有几十条独立指令,已接近模型可靠遵循的上限。
-
如果把 CLAUDE.md + Skills 全量内容 + 工具定义都塞进系统提示词,指令数量可能暴涨,导致:
-
遗忘
-
冲突
-
无视
-
2.3 分层策略的直觉
-
永远存在的规则放系统层(Layer 1)
-
可能相关但不一定相关的项目约定放 Layer 2(并用 system-reminder 允许"可忽略")
-
一次性任务用 Layer 3 注入
-
可复用能力按需用 Layer 4 加载
-
需要隔离执行的任务用 Layer 5 开新对话/沙箱
3. Layer 2 重点:CLAUDE.md 与 System-Reminder
3.1 注入方式:用 <system-reminder> 包裹
-
文中展示:Claude Code 会把 CLAUDE.md 包进
<system-reminder>标签里注入。 -
关键语义(文中意思):
-
"下面这些内容可能相关也可能不相关"
-
"除非高度相关,否则不要回应/不要遵循这些上下文"
-
3.2 为什么这样设计?
-
CLAUDE.md 是用户可控的:可能很长、很细、甚至自相矛盾
-
如果强制模型对其中所有内容都当成硬指令,会:
-
干扰当前任务
-
造成冲突和决策困难
-
增加响应变慢/成本变高
-
-
system-reminder 的价值:给模型一个"合法忽略"机制,把它更像"上下文背景"而不是"必须执行的命令"。
3.3 CLAUDE.md 的层级(文中提到 3 层)
-
全局级:
~/.claude/CLAUDE.md(所有项目共享) -
项目级:
./CLAUDE.md(当前项目专用) -
目录级:
./subdir/CLAUDE.md(特定目录专用) -
三层合并,并用类似下面的标记区分来源(文中示例形式):
xml
<claude_md source="global">
...
</claude_md>
<claude_md source="project">
...
</claude_md>
4. Layer 3:Slash Commands(斜杠命令)
4.1 工作机制(以 /commit 为例)
-
用户输入
/commit -
系统不会把它当成"真的命令执行",而是:
-
替换变量(如
{commit_message}占位符) -
把完整工作流指令注入到当前消息
-
-
注入内容类似一个 checklist/workflow(文中示例):
-
git status / diff / log
-
分析 staged changes
-
起草 commit message
-
4.2 与 Skills 的区别(文中一句话总结)
-
Slash Commands:用户发起的注入
-
Skills:模型发起的注入
5. Layer 4:Skills(按需加载的"指令包")
5.1 Skill 的形态
-
每个 Skill 是一个
SKILL.md文件(文中截图示例:code-review) -
启动时:系统只加载"可用 skills 的描述"(不是完整内容)到系统提示词中:
- Available skills: code-review / refactor / test-generator ...
5.2 调用方式(文中展示了类似工具调用)
json
{
"name": "Skill",
"arguments": {
"skill": "code-review"
}
}
5.3 关键细节:Skills 不是子 Agent
-
Skills 是"把新指令注入当前对话,然后继续"
-
没有:
-
新进程
-
隔离环境
-
独立上下文
-
-
好处:扩展能力同时避免上下文膨胀(不用把所有技能全文长期塞进 system prompt)
6. Layer 5:Sub-Agents(隔离执行)
6.1 触发形式(文中展示 Task 调用)
json
{
"name": "Task",
"arguments": {
"subagent_type": "Explore",
"prompt": "Find all files that handle authentication"
}
}
6.2 隔离机制(文中关键词)
-
Sub-Agents 在 V8 Isolate(V8 隔离沙箱)里运行:与主 Agent 的 JS 执行环境隔离
-
还有 Seccomp syscall 白名单等限制:
-
不能 ptrace
-
不能直接访问网络
-
不能读取主 Agent 之外的文件
-
不能再生成子 Agent
-
-
设计意图:即使子 Agent 被 prompt injection 影响,能干的坏事也有限
-
子 Agent 只把最终结果返回给主 Agent,中间过程不可见
7. 五层之间的关系(图的含义整理)
从"用户请求"到"Claude 拿到完整上下文"的路径大致是:
-
Layer 1(系统规则)始终存在
-
Layer 2(项目约定/提醒)每条消息都可能附带
-
Layer 3(Slash)若用户显式触发则注入一次性工作流
-
Layer 4(Skills)若模型判断需要则加载并注入专业指令
-
Layer 5(Sub-agent)若需要隔离执行则开新对话跑完再回传结果
8. System-Reminder 不止用于 CLAUDE.md
文中列了 <system-reminder> 可能出现的 5 种场景(要点):
- CLAUDE.md 注入:每条消息都可能有
- TodoWrite 后:自动注入任务列表更新
- 部分工具调用结果:用 system-reminder 包裹
- 可用 Skills 的描述:也可能用该标签包
- 对话开始时:注入
git status快照(文中提到)
核心作用:明确告诉模型"什么是上下文、什么是指令",并允许对上下文做选择性使用。
9. ConnectOnion:把 system-reminder 做成可配置插件(文中介绍)
文中提到:Claude Code 的触发逻辑是内置的、用户不可见不可改;ConnectOnion 把这套机制做成开源插件,用户可看可改可加。
9.1 事件钩子(文中:9 个事件,覆盖 Agent 执行阶段)
覆盖大致包括:
- 用户输入后
- LLM 调用前/后
- 工具执行前/后
- 错误处理
- 任务完成
(并强调:覆盖每个阶段)
9.2 system-reminder 插件监听 after_each_tool
-
工具执行完成 → 触发 after_each_tool
-
插件检查触发条件:
-
工具名是否匹配(如 write_file)
-
路径模式是否匹配(如
*.py)
-
-
匹配则追加 system-reminder,让 LLM 在看到"工具结果"同时也看到"提醒"
9.3 system-reminder 配置文件示例(YAML + reminder)
yaml
---
name: test-reminder
triggers:
- tool: write_file
path_pattern: "*.py"
---
<system-reminder>
Consider running tests to verify your changes.
This is a gentle reminder - ignore if not applicable.
</system-reminder>
10. 安全视角:上下文注入 vs Prompt Injection
10.1 观点:它们是同一技术的两面
-
开发者:用 CLAUDE.md / Skills 做"正当注入"来扩展能力
-
攻击者:用同样机制注入恶意指令(prompt injection)
10.2 文中提到的安全作者与结论(按文意记录)
-
Simon Willison:强调 prompt injection 的核心挑战在于模型会信任"听起来可信的 token",从而引发 confused deputy 之类风险。
-
Johann Rehberger("AI Bug 之月"):
-
文中说他在 2025 年 8 月每天发布一份 AI 漏洞报告持续一个月
-
测试多种主流 AI 编程助手,均存在 prompt injection 问题
-
其中有一份报告专门针对 Claude Code,提到 DNS 数据外泄:
-
Claude Code 执行命令前会询问确认,但有一组命令被预批准:
ping / nslookup / host / dig -
攻击者可构造域名,把敏感信息编码进 DNS 查询中(文中提到 base64 形式)
-
-
还提到跨 Agent 攻击与相关演讲主题(按文中描述记录)
-
11. Claude Code 的防御(文中:6 层安全门控 + 若干机制)
11.1 每次工具调用都要过的 6 层验证(文中列举)
-
UI 层 XSS 过滤(最外层)
-
Router ACL 验证消息合法性
-
工具白名单(文中写:只允许 14 个工具)
-
参数 Schema 校验(文中写:Zod)
-
OS Syscall:Seccomp 过滤系统调用
-
输出:TEE(可信执行环境)+ Token 脱敏
11.2 WebFetch 限制(文中例子)
- 引用 web sources 时每段最多 125 字符(避免整段复制恶意提示词)
11.3 Sub-agent 隔离
- 就算 prompt injection 成功,子 Agent 仍被沙箱限制,难以访问敏感资源
11.4 读后写强制(Write 工具)
- Write 工具要求先 Read,防止被诱导覆盖重要文件(文中意思)