Claude Code 用“分层注入 + 可选上下文(system-reminder)+ 按需能力加载(skills)+ 隔离执行(sub-agent)”把上下文工程系统化:既解决“上下文太长/指令过载”的工程问题,也试图把 prompt injection 风险隔离在可控边界内。
原文分析见https://www.xiaohongshu.com/explore/697db619000000002103f9d8?app_platform=android&ignoreEngage=true&app_version=9.18.0&share_from_user_hidden=true&xsec_source=app_share&type=normal&xsec_token=CBxMKJy5YYZh_lCVmElZOwOhH2HHwOT1LfB0EE3QVwuxQ=&author_share=1&xhsshare=&shareRedId=ODw6MTY4Ozs2NzUyOTgwNjY2OTo1S0k8&apptime=1769910444&share_id=b4a5e8045791490f8fd574c1804150da&share_channel=wechat
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(特定目录专用)三层合并,并用类似下面的标记区分来源(文中示例形式):
<claude_mdsource="global">...</claude_md><claude_mdsource="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 调用方式(文中展示了类似工具调用)
{"name":"Skill","arguments":{"skill":"code-review"}}5.3 关键细节:Skills 不是子 Agent
Skills 是“把新指令注入当前对话,然后继续”
没有:
新进程
隔离环境
独立上下文
好处:扩展能力同时避免上下文膨胀(不用把所有技能全文长期塞进 system prompt)
6. Layer 5:Sub-Agents(隔离执行)
6.1 触发形式(文中展示 Task 调用)
{"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)
---name:test-remindertriggers:-tool:write_filepath_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,防止被诱导覆盖重要文件(文中意思)