改 Agent 的系统提示:Claude Code 官方允许改到什么程度
有个需求很常见:我想让它别再用软件工程师那一套说话,或者反过来,我想在它原本的行为上再压一条团队规矩。这时候真正要搞清楚的不是「怎么写提示词」,而是官方到底开了哪几个口子给你改、哪几层是你碰不到的。
Claude Code 官方文档把这件事拆在两页里:code.claude.com/docs/en/agent-sdk/modifying-system-prompts 讲 SDK 侧的起点与四种定制方法,code.claude.com/docs/en/output-styles 讲持久化的那一档,另外 code.claude.com/docs/en/cli-reference 里有一节「System prompt flags」讲 CLI 侧。下面按「一次会话的系统提示是怎么攒出来的」这条线走一遍,把可改与不可改的边界标出来。
起点有三个,而且默认的那个不是你以为的那个
《Modifying system prompts》页写明,Agent SDK 的系统提示有三个起点:
- Minimal default:TypeScript 侧不设
systemPrompt、Python 侧不设system_prompt时,SDK 用一个最小提示,只覆盖工具调用,不含 Claude Code 的编码规范、回复风格和项目上下文。 claude_codepreset:Claude Code CLI 用的那一整套完整系统提示。文档列出它包含工具使用说明、代码风格与格式规范、回复语气与详略规则、安全与防护指令,以及工作目录和环境的上下文。- Custom string:你自己写的一整段,SDK 只发你给的内容。
这里有个很容易翻车的口径差:文档明说,minimal default 这个行为和 claude -p 不一样——CLI 默认用的是完整的 Claude Code 提示。也就是说,你从命令行迁到 SDK、什么都没配,行为不是「一样」而是「掉了一大截」。文档给的处置是显式设 preset:
systemPrompt: { type: "preset", preset: "claude_code" }
Python 侧对应写法是 system_prompt={"type": "preset", "preset": "claude_code"}。
往上加:append 这一档
确定起点之后,第一档改法是只加不减。SDK 侧在 preset 对象里加 append:
systemPrompt: {
type: "preset",
preset: "claude_code",
append: "Always include detailed docstrings and type hints in Python code."
}
文档对这一档的定性很直白:preset 里的东西一样都不去掉,你的指令接在后面,所以这是风险最低的一种定制。
CLI 侧对应的是那一节里的四个 flag,文档写明这四个在交互与非交互模式下都能用:--system-prompt、--system-prompt-file、--append-system-prompt、--append-system-prompt-file。其中前两个是整体替换,后两个是追加。文档同时写明两条组合规则:--system-prompt 与 --system-prompt-file 互斥;append 类的两个可以和任一替换 flag 一起用。
claude --append-system-prompt "Always use TypeScript"
claude --append-system-prompt-file ./style-rules.txt
以上命令为官方文档中给出的示例,未经实测,以官方文档与 --help 的实际输出为准。
整体替换:你接管的东西比想象的多
第二档是把默认提示整段换掉。SDK 侧给 systemPrompt 传字符串,CLI 侧用 --system-prompt 或 --system-prompt-file。
这一档文档反复提醒的是代价。CLI 参考页那一节写得最直接:替换会丢掉默认提示的全部内容,包括工具使用指导和安全指令,你的任务还需要什么就得自己补上。《Modifying system prompts》页末尾那张四方法对照表也是同一个口径——Default tools 这一行,前三种方法都是 Preserved,只有 Custom systemPrompt 是 Lost (unless included);Built-in safety 一行,前三种 Maintained,自定义那一列是 Must be added;Environment context 一行,自定义是 Must be provided。
这三行连起来看就是这一档的真实边界:官方允许你替换,但没有为你保留任何兜底。要不要走到这一档,文档给的判断标准是你的产品离 Claude Code 有多远——文档自述的衡量维度是四条:surface(输出是不是由触发它的人在终端里看)、identity(要不要以 Claude Code 的身份出现)、permission model(是不是每一步都有人审批)、以及是不是非编码任务。文档还专门点了一句:无人值守的编码自动化(比如修 lint、审 diff 的 CI 任务)仍然属于 preset 适用的场景,因为 preset 本来就是为这类工作写的。
唯一一处「分块替换」:keep-coding-instructions
前两档是全有全无。真正有意思的是中间那一档——output style。
《Output styles》页写明,output style 直接修改 Claude Code 的系统提示,机制是把每个 output style 的自定义指令加到系统提示末尾,并且在对话过程中会持续触发提醒让 Claude 遵守这些指令。关键在于它带一个开关:
自定义 output style 会去掉 Claude Code 内建的软件工程指令(比如如何界定改动范围、如何写注释、如何验证工作),除非把
keep-coding-instructions设为true。
这是我们在这两页文档里能核到的、唯一一个可以只替换系统提示中某一块而保留其余部分的官方开关。它的默认值是 false(文档 frontmatter 表格里写明的默认值,随版本可能变动)。文档给的取舍标准也很清楚:还在写代码、只是想换个沟通方式,就设 true;干脆不做软件工程了(写作助手、数据分析),就别设。
frontmatter 一共四个字段:name、description、keep-coding-instructions、force-for-plugin。最后那个是 plugin 专用的,文档写明它会覆盖用户自己的 outputStyle 设置,且多个启用的 plugin 都设了它时,Claude Code 用最先加载的那一个。团队装了一堆 plugin 又发现风格不对,先查这里。
文件放三个层级:用户级 ~/.claude/output-styles、项目级 .claude/output-styles、以及 managed settings 目录下的 .claude/output-styles。项目级还有一条嵌套规则:从工作目录到仓库根之间每一个 .claude/output-styles/ 都会加载,同名时用离工作目录最近的那个。
内建的除 Default 外还有三个:Proactive、Explanatory、Learning。这里有一处值得单独记住的界限——文档写明 Proactive 给的自主执行引导比 auto mode 更强,但它不改变你的 permission mode,也就是说「什么能不问就跑」仍然由 permission mode 说了算。别把它当权限开关用。
CLAUDE.md 根本不在这条路上
这是最常被误解的一处。文档写明:SDK 读 CLAUDE.md 之后,是把内容注入到对话里当项目上下文,而不是塞进系统提示,所以它跟你选哪种系统提示配置互不干扰。《Output styles》页的对照表也是同一说法——CLAUDE.md 的机制是「在系统提示之后加一条 user message」。
由此还带出一个提示缓存上的结论,文档明写:CLAUDE.md 的内容不影响系统提示的缓存,因为它压根不在系统提示里。
CLAUDE.md 加载与否由 setting source 决定,不由 claude_code preset 决定:'project' 加载工作目录下的 CLAUDE.md 或 .claude/CLAUDE.md,'user' 加载 ~/.claude/CLAUDE.md。query() 的默认选项两个源都开;一旦你显式设了 settingSources / setting_sources,就得自己把需要的源列进去——传空数组它就不加载了。
改完什么时候生效
output style 是会话启动时读一次的。《Output styles》页写明改动要在 /clear 之后或新会话里才生效;code.claude.com/docs/en/prompt-caching 那页说得更完整:会话中途通过 /config 或 outputStyle 设置改它,既不会让缓存失效,也不会生效,Claude 继续用启动时加载的那个,新的要等下一次 /clear 或重启。
还有一条作用域边界:output style 只作用于主对话。subagent 跑的是自己的系统提示,所以 style 改不到它;fork 是例外,因为 fork 继承父级完整的系统提示。
有条件才生效、以及已经废弃的
几处必须照实标出来的限制:
excludeDynamicSections(Python 侧exclude_dynamic_sections):把工作目录、是否 git 仓库、平台、当前 shell、OS 版本、auto memory 路径这些每会话不同的上下文,从系统提示挪到第一条 user message,让不同机器上的相同配置能共用一份缓存。文档写明它要求@anthropic-ai/claude-agent-sdkv0.2.98 或更高,Python 侧claude-agent-sdkv0.1.58 或更高;并且只对 preset 对象形式有效,systemPrompt传字符串时无效。文档同时写明代价:那些信息仍然到得了 Claude,但放在 user message 里比放在系统提示里权重略低。CLI 侧对应 flag 是--exclude-dynamic-system-prompt-sections,文档写明它只在默认系统提示下起作用,设了--system-prompt或--system-prompt-file时会被忽略。/output-style命令已废弃:文档写明该独立命令在 v2.1.73 被 deprecated、在 v2.1.91 被移除,改用/config或直接编辑outputStyle设置。- Python SDK 没有以编程方式选 output style 的选项——这是文档原话。TypeScript 侧要通过传给
query()的settings对象里设outputStyle(文档特别注明它不是Options的顶层字段)。纯代码部署又写不了.claude/settings.local.json时,文档给的替代是改用append或自定义提示字符串。 - 桌面端:文档写明在桌面 app 里跑
/config打开的是 Settings > Claude Code,而不是终端里那个菜单,所以要靠直接写设置文件里的outputStyle字段。
Windows 与 Linux/macOS 的差别
只有一处,但它会在你把提示写长之后突然咬人。
Python SDK 的字符串形式 system_prompt 是作为 CLI 子进程的一个命令行参数传下去的,所以它受操作系统命令行长度限制约束,在发出任何 API 请求之前就会在进程启动阶段失败。文档写明:Linux 上单个参数超限会以 Argument list too long 报错;Windows 上限制的是整条命令行,因此字符串形式会在更低的门槛上就失败。也就是说同一段提示,Linux/macOS 上还能跑,挪到 Windows 就可能起不来,而且报错发生在你看到任何模型响应之前。
文档给的处置是改用文件形式:
system_prompt={"type": "file", "path": "..."}
Python 参考页写明这个形式映射到 CLI 的 --system-prompt-file flag。提示一旦写长,直接上文件形式,别赌参数长度。
把边界收一下
可以改的:在 preset 后面追加(append / 两个 append flag);整体替换(自定义字符串 / --system-prompt / --system-prompt-file);通过 output style 把指令追加到系统提示末尾,并用 keep-coding-instructions 决定是否保留内建的软件工程指令;用 excludeDynamicSections 挪动动态段落的位置。
在这两页文档里核不到的:把 preset 拆开只删其中某一项(除了 keep-coding-instructions 覆盖的软件工程指令那一块,官方文档没有提供更细的粒度);让 output style 作用到 subagent(fork 除外);在 Python SDK 里以编程方式切换 output style。这些不是「做不到」的断言,只是官方文档没有说明这一点,遇到需求别按猜的实现来设计。
该产品迭代频繁,上面涉及的命令、配置项与默认值都随版本变动,动手前请以官方文档最新内容为准。
本文依据 Claude Code 官方文档(code.claude.com/docs)于 2026-08-17 的公开内容整理。
该产品闭源,本文只复述官方文档写明的机制,不推断其内部实现;
我们没有对文中涉及的功能做过实测,因此不涉及界面外观、操作手感与运行速度的任何描述。
该产品迭代频繁,文中涉及的命令、配置项与默认值随版本变动,请以官方文档最新内容为准。
本文不涉及价格、额度与限流的具体数值,相关信息请以官方定价与用量说明页为准。
安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。