Output Styles:系统提示词层的身份切换与协作人格重塑
从定义开始
Output Styles(输出样式)的本质并非简单的回复模板,也不是在既有回答上贴一层“更详细”或“更简洁”的显示皮肤。在 Claude Code 的底层实现中,它实际上是主代理(Primary Agent)系统提示词(System Prompt)层面的身份切换开关。
默认状态下,Claude Code 运行在 Default 模式,其 System Prompt 是一套经过精细调优的软件工程协作规范。一旦用户切换到 Explanatory、Learning 或自定义样式,系统并不是在对话末尾追加要求,而是直接改写了 Claude 的“人设”和“协作逻辑”。这种机制允许用户在“极致高效的编码机器”与“耐心细致的编程导师”之间一键切换,甚至可以通过自定义样式打造完全贴合团队特定工作流的协作人格。
实现细节
这套机制的运作分为样式发现、优先级决策与 Prompt 注入三个阶段。
多维样式的发现
系统会从三个维度搜集可用的输出样式:
- 内建样式:定义在
claude-code-opensource/src/constants/outputStyles.ts中,包括Explanatory和Learning。 - 外部文件样式:通过
loadOutputStylesDir.ts扫描.claude/output-styles/*.md、~/.claude/output-styles/*.md以及受管配置目录。Markdown 文件的 Frontmatter(如name、description、keep-coding-instructions)会被解析为样式参数,正文则作为 Prompt 片段。 - 插件样式:插件可以通过其 Manifest 指定额外的样式路径。插件样式的命名空间通常为
pluginName:styleName,以防冲突。
强制覆盖与优先级
在决定“当前会话生效哪个样式”时,getOutputStyleConfig() 遵循以下逻辑:
- 插件强制优先:如果某个启用中的插件声明了
forceForPlugin: true的样式,它会直接绕过用户设置强制生效。 - 用户偏好退守:若无插件强制,则读取
settings.outputStyle。 - 默认回退:若未配置,则回归到标准的软件工程协作模式(
Default)。
System Prompt 的动态重组
真正的重头戏在 claude-code-opensource/src/constants/prompts.ts。当生成最终的 System Prompt 时,样式配置会从根本上改变提示词结构:
- 自我定位改写:非默认模式下,开场白不再强调“帮助完成软件工程任务”,而是声明“按照特定输出样式响应”。
- 协作逻辑剔除:这是最重要的边界——除非样式配置了
keep-coding-instructions: true,否则系统会剔除掉默认的编码任务规范(如“读取文件、验证、保持简洁”等约束)。这也是为什么某些自定义样式可能会让 Claude 变得“不那么会写代码”的底层原因。 - 运行时挂载:为了让模型在长对话中保持警觉,非默认样式还会作为一个
output_style类型的 Attachment 挂载到会话中,充当实时的上下文提醒。
实战注意事项
第一,它是“重塑”而非“追加”。自定义 Style 默认会拿掉标准的 Coding 指令集。如果你希望在保持导师风格的同时让 Claude 依然遵循严格的编码规范,必须在样式的 Frontmatter 中显式声明 keep-coding-instructions: true。
第二,插件拥有“截胡”权。即便你在 /config 中选好了样式,带强制属性的插件样式仍能在运行时将其覆盖,这在安全审计或特定自动化流插件中非常常见。
第三,非会话内热替换。虽然修改设置后会立即写盘,但由于 System Prompt 是在会话初始化时构建的,稳定的语义通常要求新开一个会话或在下次启动后才完全体现变更效果。
第四,命令行的隐退。在最新版本中,传统的 /output-style 独立命令已趋于隐藏(Deprecated),推荐通过 /config 菜单或直接编辑 settings.local.json 来进行管理。
第五,与 CLAUDE.md 的层级区别。Output Styles 定义的是“你是谁”和“你如何说话”;而 CLAUDE.md 定义的是“在这个项目里你需要遵循哪些具体操作指令”。前者更底层,直接影响模型的推理偏好。
相关主题
如果你打算为团队定制一套 Code Review 专用样式,建议参考 loadOutputStylesDir.ts 中的 Markdown 格式要求。
如果你发现开启某个样式后 Claude 的工具调用能力下降,应检查 prompts.ts 中关于 keepCodingInstructions 的过滤逻辑。
如果你对插件如何动态注入样式感兴趣,可以深入研究 loadPluginOutputStyles.ts 的实现细节。
源码锚点
claude-code-opensource/src/constants/outputStyles.ts: 内建样式定义与全局优先级决策入口。
📄 src/constants/outputStyles.ts — 内建样式定义与全局优先级决策入口。
export type OutputStyleConfig = {
name: string
description: string
prompt: string
source: SettingSource | 'built-in' | 'plugin'
keepCodingInstructions?: boolean
/**
* If true, this output style will be automatically applied when the plugin is enabled.
* Only applicable to plugin output styles.
* When multiple plugins have forced output styles, only one is chosen (logged via debug).
*/
forceForPlugin?: boolean
}claude-code-opensource/src/outputStyles/loadOutputStylesDir.ts: 外部 Markdown 样式的加载与 Frontmatter 解析。
📄 src/outputStyles/loadOutputStylesDir.ts — 外部 Markdown 样式的加载与 Frontmatter 解析。
extractDescriptionFromMarkdown,
loadMarkdownFilesForSubdir,
} from '../utils/markdownConfigLoader.js'
import { clearPluginOutputStyleCache } from '../utils/plugins/loadPluginOutputStyles.js'claude-code-opensource/src/constants/prompts.ts: 样式如何干预 System Prompt 的拼装,尤其是默认编码指令的剔除逻辑。
📄 src/constants/prompts.ts — 样式如何干预 System Prompt 的拼装,尤其是默认编码指令的剔除逻辑。
DANGEROUS_uncachedSystemPromptSection,
resolveSystemPromptSections,
} from './systemPromptSections.js'
import { SLEEP_TOOL_NAME } from '../tools/SleepTool/prompt.js'claude-code-opensource/src/utils/plugins/loadPluginOutputStyles.ts: 插件样式的发现与强制生效机制。
📄 src/utils/plugins/loadPluginOutputStyles.ts — 插件样式的发现与强制生效机制。
async function loadOutputStylesFromDirectory(
outputStylesPath: string,
pluginName: string,
loadedPaths: Set<string>,
): Promise<OutputStyleConfig[]> {
const styles: OutputStyleConfig[] = []
await walkPluginMarkdown(
outputStylesPath,
async fullPath => {
const style = await loadOutputStyleFromFile(
fullPath,
pluginName,
loadedPaths,
)
if (style) styles.push(style)
},
{ logLabel: 'output-styles' },
)
return styles
}claude-code-opensource/src/components/OutputStylePicker.tsx:/configUI 与运行时样式表的对接点。
📄 src/components/OutputStylePicker.tsx — `/config` UI 与运行时样式表的对接点。
const DEFAULT_OUTPUT_STYLE_LABEL = 'Default';
const DEFAULT_OUTPUT_STYLE_DESCRIPTION = 'Claude completes coding tasks efficiently and provides concise responses';
function mapConfigsToOptions(styles: {
[styleName: string]: OutputStyleConfig | null;
}): OptionWithDescription[] {
return Object.entries(styles).map(([style, config]) => ({
label: config?.name ?? DEFAULT_OUTPUT_STYLE_LABEL,
value: style,
description: config?.description ?? DEFAULT_OUTPUT_STYLE_DESCRIPTION
}));
}