Skip to main content

机制 4:System Prompt - 分段组装 vs 模板系统

如何构建一个 10KB 的 System Prompt?


核心问题

System Prompt 通常很大(5-10KB),包含:

  • 身份定义
  • 能力说明
  • 行为规范
  • 项目上下文
  • 环境信息

如何组织和管理?


Claude Code 的方案:分段组装

架构设计

// src/services/api/claude.ts
async function buildSystemPrompt(): Promise<SystemPrompt> {
const sections: string[] = []

// 1. 静态部分(缓存)
sections.push(identitySection)
sections.push(capabilitiesSection)
sections.push(responseStyleSection)
sections.push(codingQuestionsSection)
sections.push(rulesSection)

// 2. 动态部分(不缓存)
const claudeMd = await findClaudeMd()
if (claudeMd) {
sections.push(`# claudeMd\n${claudeMd}`)
}

const gitStatus = await getGitStatus()
sections.push(`# gitStatus\n${gitStatus}`)

sections.push(`# currentDate\n${new Date().toISOString()}`)

sections.push(environmentSection)

// 3. 组装
return sections.filter(Boolean).join('\n\n')
}

静态部分(缓存)

// src/constants/system.ts
export const identitySection = `
<identity>
You are Kiro, an AI assistant and IDE built to assist developers.

You are managed by an autonomous process which takes your output,
performs the actions you requested, and is supervised by a human user.

You talk like a human, not like a bot.
</identity>
`.trim()

export const capabilitiesSection = `
<capabilities>
- Knowledge about the user's system context
- Recommend edits to the local file system
- Recommend shell commands
- Provide software focused assistance
- Use available web related tools
- Guide users on best practices
</capabilities>
`.trim()

export const responseStyleSection = `
<response_style>
- Be concise and direct
- Don't repeat yourself
- Use bullet points for readability
- Don't use markdown headers
- Don't bold text
</response_style>
`.trim()

Prompt Cache 优化

// 使用 cache_control 标记可缓存部分
const systemPrompt = [
{
type: "text",
text: identitySection,
cache_control: { type: "ephemeral" } // 缓存
},
{
type: "text",
text: capabilitiesSection,
cache_control: { type: "ephemeral" } // 缓存
},
{
type: "text",
text: responseStyleSection,
cache_control: { type: "ephemeral" } // 缓存
},
{
type: "text",
text: rulesSection,
cache_control: { type: "ephemeral" } // 缓存
},
{
type: "text",
text: claudeMdContent,
cache_control: { type: "ephemeral" } // 缓存(项目规范)
},
{
type: "text",
text: gitStatus // 不缓存(动态变化)
},
{
type: "text",
text: currentDate // 不缓存(每天变化)
}
]

成本优化

第 1 次调用:7500 tokens × $0.003 / 1K = $0.0225
后续调用:7500 tokens × $0.0003 / 1K = $0.00225(缓存命中)
节省:90%

Codex 的方案:模板系统

架构设计

// codex-rs/core/src/system_prompt.rs
pub struct SystemPromptBuilder {
templates: HashMap<String, String>,
context: Context,
}

impl SystemPromptBuilder {
pub fn new(context: Context) -> Self {
let mut templates = HashMap::new();

// 加载模板
templates.insert("identity".to_string(), IDENTITY_TEMPLATE.to_string());
templates.insert("capabilities".to_string(), CAPABILITIES_TEMPLATE.to_string());
templates.insert("rules".to_string(), RULES_TEMPLATE.to_string());

Self { templates, context }
}

pub fn build(&self) -> String {
let mut sections = Vec::new();

// 1. 静态模板
sections.push(self.render_template("identity"));
sections.push(self.render_template("capabilities"));
sections.push(self.render_template("rules"));

// 2. 动态内容
if let Some(config) = &self.context.config {
sections.push(format!("# Project Config\n{}", config));
}

if let Some(git) = &self.context.git_status {
sections.push(format!("# Git Status\n{}", git));
}

sections.push(format!("# Current Date\n{}", self.context.date));

// 3. 组装
sections.join("\n\n")
}

fn render_template(&self, name: &str) -> String {
self.templates.get(name)
.map(|t| self.interpolate(t))
.unwrap_or_default()
}

fn interpolate(&self, template: &str) -> String {
// 简单的变量替换
template
.replace("{{user}}", &self.context.user)
.replace("{{cwd}}", &self.context.cwd)
}
}

模板定义

// codex-rs/core/src/templates/identity.rs
pub const IDENTITY_TEMPLATE: &str = r#"
<identity>
You are an AI coding assistant.

Current user: {{user}}
Working directory: {{cwd}}

You help developers write, understand, and improve code.
</identity>
"#;

pub const CAPABILITIES_TEMPLATE: &str = r#"
<capabilities>
- Read and write files
- Execute shell commands
- Search code
- Analyze code structure
- Suggest improvements
</capabilities>
"#;

pub const RULES_TEMPLATE: &str = r#"
<rules>
- Be concise and direct
- Use tools instead of describing actions
- Don't repeat yourself
- Focus on the task at hand
</rules>
"#;

对比分析

1. 组织方式

维度Claude CodeCodex
方式分段组装模板系统
存储常量字符串模板文件
动态内容直接拼接变量插值
复杂度

Claude Code(简单拼接)

const prompt = [
section1,
section2,
dynamicContent,
].join('\n\n')

Codex(模板渲染)

let prompt = template
.replace("{{var1}}", value1)
.replace("{{var2}}", value2)

2. 缓存策略

Claude Code

// 精细控制每个部分
{
type: "text",
text: section,
cache_control: { type: "ephemeral" } // 可选
}

Codex

// 整体缓存或不缓存
// 需要手动分割静态和动态部分

Claude Code 更灵活

  • 可以精确控制哪些部分缓存
  • Anthropic API 原生支持

3. 可维护性

Claude Code

// 每个部分独立管理
export const identitySection = `...`
export const rulesSection = `...`

// 易于修改单个部分

Codex

// 模板文件独立
pub const IDENTITY_TEMPLATE: &str = r#"..."#;
pub const RULES_TEMPLATE: &str = r#"..."#;

// 支持从文件加载

都很好维护

  • 模块化
  • 易于修改

4. 性能对比

操作Claude CodeCodex差距
构建时间~5ms~3ms1.7 倍
内存占用~20KB~10KB2 倍
缓存命中90% 节省需手动实现-

动态内容注入

Claude Code

// 项目上下文
const claudeMd = await findClaudeMd()
if (claudeMd) {
sections.push({
type: "text",
text: `# claudeMd\n${claudeMd}`,
cache_control: { type: "ephemeral" }
})
}

// Git 状态
const gitStatus = await getGitStatus()
sections.push({
type: "text",
text: `# gitStatus\n${gitStatus}`
})

// 当前日期
sections.push({
type: "text",
text: `# currentDate\n${new Date().toISOString()}`
})

Codex

// 项目配置
if let Some(config) = self.load_config().await? {
sections.push(format!("# Project Config\n{}", config));
}

// Git 状态
let git_status = self.get_git_status().await?;
sections.push(format!("# Git Status\n{}", git_status));

// 当前日期
let date = chrono::Local::now().format("%Y-%m-%d");
sections.push(format!("# Current Date\n{}", date));

版本管理

Claude Code

// src/constants/system.ts
export const SYSTEM_PROMPT_VERSION = "2.1.888"

export const identitySection = `
<identity>
You are Kiro, version ${SYSTEM_PROMPT_VERSION}
...
</identity>
`

Codex

// codex-rs/core/src/version.rs
pub const SYSTEM_PROMPT_VERSION: &str = "1.0.0";

pub const IDENTITY_TEMPLATE: &str = r#"
<identity>
You are Codex, version {{version}}
...
</identity>
"#;

// 渲染时替换
template.replace("{{version}}", SYSTEM_PROMPT_VERSION)

多语言支持

Claude Code

// 根据用户语言选择
const language = getUserLanguage()

const sections = [
language === 'zh' ? identitySectionZh : identitySectionEn,
language === 'zh' ? rulesSectionZh : rulesSectionEn,
]

Codex

// 模板文件
// templates/identity.en.txt
// templates/identity.zh.txt

let template_name = format!("identity.{}.txt", language);
let template = load_template(&template_name)?;

可复用模板

TypeScript 分段组装模板

// system-prompt.ts
export interface SystemPromptBuilder {
identity: string
capabilities: string
rules: string
context?: string
gitStatus?: string
}

export function buildSystemPrompt(
builder: SystemPromptBuilder
): SystemPrompt {
const sections: Array<{
type: "text"
text: string
cache_control?: { type: "ephemeral" }
}> = []

// 静态部分(缓存)
sections.push({
type: "text",
text: builder.identity,
cache_control: { type: "ephemeral" }
})

sections.push({
type: "text",
text: builder.capabilities,
cache_control: { type: "ephemeral" }
})

sections.push({
type: "text",
text: builder.rules,
cache_control: { type: "ephemeral" }
})

// 动态部分(不缓存)
if (builder.context) {
sections.push({
type: "text",
text: builder.context,
cache_control: { type: "ephemeral" } // 项目上下文也可以缓存
})
}

if (builder.gitStatus) {
sections.push({
type: "text",
text: builder.gitStatus
})
}

return sections
}

Rust 模板系统模板

// system_prompt.rs
pub struct SystemPromptBuilder {
templates: HashMap<String, String>,
variables: HashMap<String, String>,
}

impl SystemPromptBuilder {
pub fn new() -> Self {
Self {
templates: HashMap::new(),
variables: HashMap::new(),
}
}

pub fn add_template(&mut self, name: &str, template: &str) {
self.templates.insert(name.to_string(), template.to_string());
}

pub fn set_variable(&mut self, key: &str, value: &str) {
self.variables.insert(key.to_string(), value.to_string());
}

pub fn build(&self) -> String {
let mut sections = Vec::new();

for (name, template) in &self.templates {
let rendered = self.render(template);
sections.push(rendered);
}

sections.join("\n\n")
}

fn render(&self, template: &str) -> String {
let mut result = template.to_string();

for (key, value) in &self.variables {
let placeholder = format!("{{{{{}}}}}", key);
result = result.replace(&placeholder, value);
}

result
}
}

最佳实践

1. 分离静态和动态

// 静态部分(缓存)
const staticSections = [
identitySection,
capabilitiesSection,
rulesSection,
]

// 动态部分(不缓存)
const dynamicSections = [
gitStatus,
currentDate,
]

// 组装
const prompt = [
...staticSections.map(s => ({
type: "text",
text: s,
cache_control: { type: "ephemeral" }
})),
...dynamicSections.map(s => ({
type: "text",
text: s
}))
]

2. 版本控制

// 在 System Prompt 中包含版本号
const identitySection = `
<identity>
System Prompt Version: ${VERSION}
Last Updated: ${LAST_UPDATED}
...
</identity>
`

3. 环境适配

// 根据环境调整
const rulesSection = process.env.NODE_ENV === 'production'
? productionRules
: developmentRules

4. 模块化管理

src/system-prompt/
├── identity.ts
├── capabilities.ts
├── rules.ts
├── response-style.ts
└── index.ts // 组装

关键要点

  1. Claude Code:分段组装 + Prompt Cache
  2. Codex:模板系统 + 变量插值
  3. 缓存策略:静态缓存,动态不缓存
  4. 成本优化:缓存命中节省 90%
  5. 可维护性:模块化,易于修改
  6. 性能:Codex 快 1.7 倍,但 Claude Code 有缓存优势
  7. 选择:简单拼接 vs 模板渲染

记住:System Prompt 要模块化管理,静态部分要缓存。


字数:约 3500 字
阅读时间:约 9 分钟