Skip to content

全局 Insight 汇总

本文档汇总 Claude Code 系统提示词中的关键设计洞察,分为架构、编码准则、安全、Agent 系统和输出控制五大类别。每条 Insight 包含原则描述、来源定位、设计意图分析和复用建议。


原则: 通过 SYSTEM_PROMPT_DYNAMIC_BOUNDARY 将系统提示词分为跨用户可缓存的静态部分和会话特定的动态部分。

来源: src/constants/prompts.ts 中的 getSystemPrompt() 函数和 SYSTEM_PROMPT_DYNAMIC_BOUNDARY 常量;src/utils/api.ts 中的 splitSysPromptPrefix() 消费此标记。

为什么这么设计: 系统提示词约 40K+ tokens,如果每个用户每次请求都重新处理,推理成本极高。静态部分(身份定义、系统规则、编码准则等)对所有用户完全相同,可以使用 cacheScope: 'global' 在 API 层面跨组织共享 KV cache。动态部分(环境信息、语言偏好、MCP 指令等)因会话而异,不参与全局缓存。一个简单的字符串标记就实现了这个分离,不需要复杂的缓存框架。

复用建议: 在任何使用大量系统提示词的 LLM 应用中,将提示词分为”应用级不变”和”用户/会话级可变”两部分。不变部分放在 system prompt 数组的前面,利用 API 的 prompt caching 特性(如 Anthropic 的 cacheScope 或 OpenAI 的 cached prompt prefix)。注意:任何条件分支如果放入静态区域,都会指数级增加缓存变体(2^N 分支 = 2^N 种 hash),必须严格审查。


原则: systemPromptSection() 将提示词模块化,每个 section 独立计算、独立缓存,通过 resolveSystemPromptSections() 批量解析,/clear/compact 时统一重置。DANGEROUS_uncachedSystemPromptSection() 以命名恫吓的方式标识会破坏 prompt cache 的 section。

来源: src/constants/systemPromptSections.ts 中定义了 systemPromptSection()DANGEROUS_uncachedSystemPromptSection()resolveSystemPromptSections()

为什么这么设计: 动态 section 的计算成本各不相同(有的需要读文件系统,有的需要查询环境),且更新频率不同。注册制让每个 section 只在首次需要时计算,之后缓存结果直到显式清除。DANGEROUS_ 前缀是有意的代码审查信号——开发者看到这个前缀会自然地追问”为什么需要每次都重新计算”,从而减少不必要的缓存破坏。

复用建议: 在 section 数量多、更新频率各异的系统提示词中,使用注册制替代”每次拼接所有内容”。关键设计要点:

  • 每个 section 有唯一名称,用于缓存 key
  • 区分”计算一次”和”每次重算”两种模式
  • 用命名约定(如 DANGEROUS_unsafe_)标识高成本操作,降低滥用概率

原则: buildEffectiveSystemPrompt() 实现 6 层优先级(Override > Coordinator > Agent > Custom > Default > Append),精确控制不同运行模式下使用哪套提示词。

来源: src/utils/systemPrompt.ts 中的 buildEffectiveSystemPrompt() 函数。

为什么这么设计: Claude Code 有多种运行模式——交互式、自动循环(loop)、协调器、自定义 Agent、SDK 嵌入等。每种模式对提示词有不同需求,但不能为每种模式维护一套完整提示词。优先级链让不同模式”覆盖”默认行为,而 Append 层保证某些通用指令(如安全约束)始终存在。Override 作为最高优先级,不允许 Append,确保 loop 模式可以完全控制行为。

复用建议: 在多模式 LLM 应用中,用优先级链替代 if-else 嵌套。设计要点:

  • 明确每个层级是”替换”还是”叠加”
  • 最高优先级应该是”完全替换”(用于自动化场景需要精确控制)
  • 最低优先级应该是”始终追加”(用于安全约束等不可绕过的指令)
  • 注意互斥关系(如 Coordinator 和 Agent 不应同时激活)

原则: 系统提示词明确禁止三种 LLM 常见的过度工程行为:

  1. 不加多余功能、不加防御性代码——“Don’t add error handling for scenarios that can’t happen”
  2. 不创建一次性抽象——“Three similar lines of code is better than a premature abstraction”
  3. 不为假设性未来需求设计——“Don’t design for hypothetical future requirements”

来源: getSimpleDoingTasksSection() 中的 codeStyleSubitems 数组,每一条都针对 LLM 的具体倾向。

为什么这么设计: LLM 天然倾向于”过度热心”——添加错误处理、创建抽象、预留扩展点。这在独立写代码时可能看起来”专业”,但在实际代码库中会引入不必要的复杂性、偏离代码库风格、增加审查负担。这三条规则精准对冲了 LLM 的这个倾向,将其从”写理想代码”拉回到”写符合上下文的代码”。

复用建议: 在任何 LLM 编码助手的系统提示词中加入类似约束。关键不是泛泛地说”keep it simple”,而是列出具体的反模式:“不要 X”比”要简洁”更有效。根据你的模型和使用场景,观察 LLM 最常犯的过度工程模式,然后用具体的 NEVER 规则对冲。


原则: “默认不写评论。只在 WHY 不明显时写。不解释 WHAT(好的命名已经做到了)。不引用当前任务/修复/调用者(这些属于 PR 描述,会随代码演变而腐烂)。不删除已有评论(可能编码了你看不到的约束)。”

来源: getSimpleDoingTasksSection()codeStyleSubitems 的 ant-only 部分,标注为 @[MODEL LAUNCH]: Update comment writing for Capybara

为什么这么设计: LLM(尤其是较新的模型如 Capybara/Opus 4.6)倾向于过度注释——为每个函数写 docstring、为每行逻辑加注释。这对代码审查者来说是噪音。“默认不写”是对这个倾向的硬性对冲,而”只在 WHY 不明显时写”给出了唯一的例外——隐藏约束、微妙的不变量、特定 bug 的 workaround。

复用建议: 在编码助手提示词中明确注释策略。不要使用”write appropriate comments”这种模糊指引,而是给出决策树:默认不写 → 只有 WHY 不明显时写 → 不解释 WHAT → 不引用瞬时上下文。这个策略可以根据项目风格调整(比如公共 API 的 docstring 可能是必需的)。


原则: “禁止虚假阳性(测试失败时声称通过)、禁止压缩失败结果以制造绿色报告、禁止将未完成的工作标记为完成。同时禁止虚假谦虚——确认通过的结果不需要加限定词,完成的工作不需要降级为’部分完成’。目标是准确报告,不是防御性报告。”

来源: getSimpleDoingTasksSection() 中 ant-only 部分,标注为 @[MODEL LAUNCH]: False-claims mitigation for Capybara v8 (29-30% FC rate vs v4's 16.7%)

为什么这么设计: 数据驱动——Capybara v8 的虚假声称率(29-30%)比 v4(16.7%)高出近一倍。模型有两个对称的问题:一是过度乐观(声称成功但实际失败),二是过度谦虚(实际成功但加不必要的限定词)。两者都浪费用户时间——前者导致信任崩塌,后者导致不必要的复查。“准确报告,非防御性报告”一句话概括了期望的行为。

复用建议: 在任何需要 LLM 报告工作结果的场景中(CI/CD 集成、自动化测试、代码审查),明确禁止两个方向的失实:过度乐观和过度悲观。给出具体示例比抽象要求更有效——“never claim ‘all tests pass’ when output shows failures”比”be accurate”更能改变行为。


原则: Bash 工具的 Git 操作提示词包含多条 NEVER 规则:不更新 git config、不运行破坏性命令(push —force、reset —hard、checkout .、restore .、clean -f、branch -D)除非用户明确请求、不跳过 hooks(—no-verify)、不 force push 到 main/master、始终创建新 commit 而非 amend(防止 pre-commit hook 失败后 amend 覆盖之前的 commit)。

来源: Bash 工具的 # Committing changes with git section,每条规则都有对应的失败场景解释。

为什么这么设计: Git 操作的不可逆性极高——force push 可以覆盖他人工作,reset —hard 可以丢失未提交修改,amend 可以破坏历史。LLM 倾向于”解决问题最快的方式”——遇到冲突就 git checkout .,遇到 hook 失败就 --no-verify。每条 NEVER 规则都对应一个真实的生产事故场景。特别值得注意的是 amend 规则的推理:pre-commit hook 失败意味着 commit 没有发生,此时 --amend 会修改前一个 commit,可能丢失之前的修改。

复用建议: 在任何允许 LLM 执行 Git 操作的工具中:

  1. 白名单制:默认禁止所有写操作,按需开放
  2. NEVER 规则必须附带”为什么”——模型理解后果比记住规则更可靠
  3. 区分”用户明确请求”和”模型自主决定”的操作权限
  4. amend 陷阱是一个容易被忽视的 edge case,值得显式处理

原则: Bash 工具默认在沙箱环境中运行,通过 dangerouslyDisableSandbox 参数允许绕过。提示词要求模型”只在沙箱限制导致失败时才设置此参数,且首先尝试在沙箱内完成任务”。

来源: Bash 工具描述中的 dangerouslyDisableSandbox 参数说明。

为什么这么设计: 安全默认(secure by default)——大多数命令不需要沙箱外权限,只有少数场景(如 Docker 操作、某些系统级命令)需要绕过。dangerouslyDisableSandbox 的命名和 DANGEROUS_uncachedSystemPromptSection 一样,是有意的命名恫吓——每次使用都是一个”我真的需要这个”的有意识决定。

复用建议: 在 LLM 工具设计中采用”安全默认 + 显式升级”模式:

  • 默认权限最小化
  • 升级路径必须显式声明(参数名应传达风险,如 DANGEROUS_unsafe_force_
  • 提示词中明确”先尝试受限方式,只有失败时才升级”

原则: “仔细考虑操作的可逆性和爆炸半径。本地可逆操作可自由执行。难以逆转、影响共享系统、或有破坏性风险的操作,执行前需确认。暂停确认的成本很低,而不想要的操作的成本(丢失工作、发送消息、删除分支)可能很高。”

来源: getActionsSection() 函数,完整定义了高风险操作的分类(破坏性操作、难以逆转操作、影响他人操作、上传到第三方)和处理策略。

为什么这么设计: 这是 Claude Code 最核心的安全哲学之一——不是禁止所有风险操作(那会让工具无用),而是建立一个决策框架:操作 = f(可逆性, 影响范围)。可逆且局部的(编辑文件、运行测试)→ 自由执行;不可逆或共享的(push、发消息、删分支)→ 先确认。这个框架比”列举所有危险命令”更具可扩展性。

复用建议: 在 LLM 工具权限设计中建立类似的二维决策矩阵:

局部影响 共享影响
可逆操作 → 自动执行 → 通知后执行
不可逆操作 → 确认后执行 → 必须确认

将此框架写入系统提示词,比穷举所有命令更有效。


原则: “协助授权安全测试、防御安全、CTF 挑战和教育场景。拒绝破坏性技术、DoS 攻击、大规模目标、供应链攻击或用于恶意目的的检测逃避。双用途安全工具(C2 框架、凭证测试、漏洞开发)需要清晰的授权上下文。”

来源: src/constants/cyberRiskInstruction.ts,由 Safeguards 团队独立维护,修改需要专门审批。

为什么这么设计: 安全工具是经典的双用途问题——渗透测试工具既用于防御也可用于攻击。Claude Code 的策略不是”禁止所有安全相关操作”,而是要求”授权上下文”——渗透测试约定、CTF 竞赛、安全研究、防御用例。这让 Claude Code 对安全专业人员仍然有用,同时拒绝明显的恶意用途。

复用建议: 安全相关的提示词应该:

  1. 由专门的安全团队维护(不是功能开发者)
  2. 有独立的审批流程(文件头注释中明确写明联系人)
  3. 区分”工具”和”意图”——同一个工具在不同上下文中可能是合法或非法的
  4. 要求”授权上下文”而非一刀切禁止

原则: 验证 Agent 的核心指令是:“你的工作不是确认实现能运行——而是尝试打破它。“验证 Agent 被告知自己有两个已知失败模式:(1)验证逃避——找理由不运行检查,直接写”PASS”;(2)被前 80% 迷惑——看到光鲜的 UI 或通过的测试就倾向于通过,忽略一半按钮没功能、状态刷新后消失等问题。

来源: src/tools/AgentTool/built-in/verificationAgent.ts 中的 VERIFICATION_SYSTEM_PROMPT

为什么这么设计: 经典的验证偏差——验证者天然倾向于确认而非否定(尤其是 LLM)。通过明确告知 Agent 自己的失败模式(元认知注入),强迫它与自身倾向对抗。“调用者可能通过重新运行你的命令来抽查”增加了被发现的压力。“没有命令输出的 PASS 会被拒绝”消除了”读代码后声称 PASS”的逃避路径。

复用建议: 在 LLM 验证/审查场景中:

  1. 明确告知 Agent 它的已知偏差(LLM 对自身倾向的元认知可以部分对冲偏差)
  2. 要求可审计证据(命令输出、截图),不接受”我看了代码,没问题”
  3. 设计”抽查”机制——即使不真的抽查,告知存在抽查也能改变行为
  4. 给出具体的验证策略分类(前端、后端、CLI、基础设施等),而非泛泛的”请验证”

Insight 12:Fork vs Agent 上下文策略

Section titled “Insight 12:Fork vs Agent 上下文策略”

原则: Fork 子 Agent 继承父上下文的全部对话历史和系统提示词(cache-identical API prefixes),适合需要理解上下文的后台工作;传统 subagent 从零开始,使用自己的系统提示词和精简工具集。两者互斥于 Coordinator 模式。

来源: src/tools/AgentTool/forkSubagent.ts 中的 isForkSubagentEnabled() 和 Fork agent 定义;src/constants/prompts.tsgetAgentToolSection() 对两种模式的不同描述。

为什么这么设计: Fork 和 Agent 是两个不同的优化目标:

  • Fork(继承上下文):适合”把当前工作的一部分并行化”——子 Agent 需要理解对话上下文,继承缓存可以避免重新处理系统提示词
  • Agent(从零开始):适合”专门化任务委派”——探索、验证等场景有自己的提示词和受限工具集,不需要父上下文

Fork 描述为”runs in the background and keeps its tool output out of your context”——核心价值不只是并行,更是”防止子任务的大量输出污染主上下文窗口”。

复用建议: 在多 Agent 系统中区分两种子 Agent 模式:

  1. 继承型(Fork):共享上下文,适合并行化当前工作的子任务
  2. 独立型(Agent):独立上下文,适合需要专门能力/权限的任务
  3. 两者不应混用——同一个任务要么需要上下文,要么不需要

原则: 协调器的核心职责是”理解后再分发”——在研究 Worker 报告结果后,必须理解发现、识别方案,然后写出包含具体文件路径、行号和修改内容的提示词。明确禁止”Based on your findings, fix the auth bug”这种懒惰委派。

来源: src/coordinator/coordinatorMode.tsgetCoordinatorSystemPrompt() 的 Section 5 “Writing Worker Prompts”。

为什么这么设计: LLM 作为协调器时最容易犯的错误是”传话筒”——把一个 Worker 的输出原样转发给另一个 Worker。这浪费 tokens、引入歧义,且无法验证质量。“永远不要写 ‘based on your findings‘“是一个精确的反模式检测器——这个短语的存在几乎总意味着协调器没有真正理解内容。

复用建议: 在协调器/编排器的提示词中:

  1. 明确定义”合成”的标准(必须包含文件路径、行号、具体修改内容)
  2. 给出反模式示例(比正面示例更有效——LLM 更容易理解”不要这样做”)
  3. 区分”研究”和”实现”阶段——研究是发散的,实现需要精确的 spec

原则: 探索 Agent 被设定为严格只读——不仅在提示词中禁止修改操作,工具层面也移除了 Write/Edit 等工具(“You do NOT have access to file editing tools - attempting to edit files will fail”)。

来源: src/tools/AgentTool/built-in/exploreAgent.tsgetExploreSystemPrompt() 和工具配置中排除写操作工具。

为什么这么设计: 仅靠提示词约束不可靠——模型可能”合理化”为什么需要写文件(“我需要创建一个临时脚本来搜索”)。通过在工具层面移除写操作能力,确保即使提示词被”说服”,操作也无法执行。这是”defense in depth”(纵深防御)的体现——提示词约束是第一层,工具禁用是第二层。

复用建议: 在需要 Agent 权限隔离的场景中:

  1. 提示词 + 工具双重约束:提示词说明意图,工具配置强制执行
  2. 不要只依赖提示词——LLM 可以被”说服”绕过提示词约束
  3. 工具层面的约束应该和提示词一致——如果提示词说”只读”,就不要提供写工具

原则: 内部用户(ant)获得完全不同的输出效率指导——长段落的”Communicating with the user”(约 300 词),强调理解、上下文恢复、线性可读性;外部用户获得精简的”Output efficiency”(约 100 词),强调”Go straight to the point”。

来源: getOutputEfficiencySection() 函数,通过 process.env.USER_TYPE === 'ant' 分支。

为什么这么设计: 内部用户(Anthropic 开发者)深度使用 Claude Code 进行日常工程工作,他们更在意”理解后一次做对”而非”快速获得可能需要追问的简短回答”。外部用户通常进行较短的交互,更在意响应速度和简洁性。同一个模型在不同提示词下的行为差异,比切换不同模型更可控。

复用建议: 根据用户群体差异化输出指导:

  • 重度用户/专家:强调理解和一次性完整(减少来回追问)
  • 轻度用户/新手:强调简洁和直接(降低认知负担)
  • 通过用户分群而非一刀切,可以在同一模型上实现最优体验

原则: “工具调用之间文本 <=25 词。最终回复 <=100 词,除非任务需要更多细节。“——具体数字比定性描述(“be concise”)更有效。

来源: getSystemPrompt() 中 ant-only 的 numeric_length_anchors section。代码注释说明研究显示”~1.2% output token reduction vs qualitative ‘be concise’”。

为什么这么设计: LLM 对定性指令(“简洁”、“简短”、“直接”)的响应不稳定——“简洁”对不同上下文意味着不同的长度。数值锚点提供了具体的校准点——即使模型不会严格遵守 25 词限制,数字本身改变了模型对”合适长度”的内部分布。1.2% 的 output token 减少在规模化运营下是显著的成本优化。

复用建议: 在需要控制 LLM 输出长度的场景中:

  1. 用具体数字替代定性描述(“最多 3 句话”而非”简短回答”)
  2. 数字不需要精确——它们是锚点而非硬性限制
  3. 在不同场景给出不同的数值锚点(工具间 vs 最终回复)
  4. 先 A/B 测试再全量(Claude Code 也是 ant-only 先验证)

原则: “不要使用 Bash 运行命令,当存在相关的专用工具时。使用专用工具允许用户更好地理解和审查你的工作。这对于帮助用户至关重要。“——专用工具(Read/Write/Edit/Glob/Grep)优先于通用工具(Bash)。

来源: getUsingYourToolsSection() 函数中的第一条规则,用大写标注”This is CRITICAL”。

为什么这么设计: 这不仅是功能问题,更是审查和安全问题:

  1. 可审查性Read("foo.ts")Bash("cat foo.ts") 更容易审查和理解意图
  2. 权限控制:专用工具有更精细的权限模型(沙箱策略不同于文件读写权限)
  3. 用户体验:专用工具的输出有特定的渲染格式,比 Bash 的原始输出更易读
  4. 安全性Bash("cat foo.ts && rm -rf /") 可以注入危险命令,Read("foo.ts") 不能

复用建议: 在 LLM 工具设计中:

  1. 为常见操作提供专用工具,而非让模型用通用工具(如 code interpreter)完成所有事
  2. 在提示词中明确工具优先级——模型会倾向于使用”能完成所有事”的通用工具
  3. 专用工具的设计应该让审查更容易,而非仅仅让执行更方便

原则: “只在用户明确要求时使用 emoji。在所有沟通中避免 emoji,除非被要求。“——这条规则出现在系统提示词和子 Agent 增强提示词中,重复两次。

来源: getSimpleToneAndStyleSection() 中的第一条规则;enhanceSystemPromptWithEnvDetails() 中的 notes 再次强调。

为什么这么设计: LLM(尤其是经过 RLHF 的模型)倾向于使用 emoji 来表达友好和亲和力。但在专业软件工程场景中,emoji 通常被视为不专业或干扰性的。更重要的是,emoji 在终端渲染中可能出现宽度计算错误(特别是在 monospace 字体中)、在代码审查中造成噪音、在 git commit message 中不符合多数项目规范。反 emoji 默认的重复强调(系统提示词 + 子 Agent 提示词都有)表明这是一个模型容易”回弹”的行为——需要强化约束。

复用建议: 在专业场景的 LLM 提示词中:

  1. 显式禁止 emoji 默认(模型不会自动推断”专业场景不需要 emoji”)
  2. 保留”用户明确要求时可以使用”的例外——这比完全禁止更合理
  3. 如果约束容易被模型忽视,在多个位置重复(系统提示词 + 工具描述 + 子 Agent 提示词)

这 18 条 Insight 可以归纳为三个核心原则:

  1. 精确 > 模糊:具体数字 > 定性描述,NEVER 规则 > 建议规则,反模式示例 > 正面指引
  2. 纵深防御:提示词约束 + 工具层面约束 + 命名恫吓 + 审查机制,多层叠加
  3. 对冲 LLM 倾向:过度工程 → 反过度工程三连;过度乐观 → 忠实报告规则;过度友好 → 反 emoji;验证偏差 → 对抗式验证

这些不是通用的 LLM 提示词最佳实践,而是针对 Claude Code 这个特定场景(专业软件工程 CLI 工具)经过反复迭代和 A/B 测试得出的工程决策。复用时需要根据自己的场景和模型行为进行调整。