| ← 返回 Claude Code 最佳实践 |
当通过 Claude Agent SDK 与 Claude CLI (Claude Code) 发送相同的消息(例如"挪威的首都是什么?")时,伴随这些消息的系统提示(system prompts)有着本质的不同。CLI 使用模块化系统提示架构(约 269 个基础 tokens,根据功能条件加载额外上下文),而 SDK 默认使用最小化提示。即使配置匹配,两者也无法保证输出完全相同,这是由于缺少种子参数以及 Claude 架构固有的非确定性。
Claude CLI 使用模块化系统提示架构,基础提示约 269 tokens,根据功能条件加载额外上下文:
| 组件 | 描述 | 加载时机 |
|---|---|---|
| 基础 System Prompt | 核心指令和行为 | 始终加载(约 269 tokens) |
| 工具指令 | 18+ 内置工具(Write、Read、Edit、Bash、TodoWrite 等) | 始终加载 |
| 编码指南 | 代码风格、格式化规则、安全实践 | 始终加载 |
| 安全规则 | 拒绝规则、注入防御、伤害预防 | 始终加载 |
| 响应风格 | 语气、详细程度、解释深度、emoji 使用 | 始终加载 |
| 环境上下文 | 工作目录、git 状态、平台信息 | 始终加载 |
| 项目上下文 | CLAUDE.md 内容、设置、hooks 配置 | 条件加载 |
| 子代理 Prompts | Plan mode、Explore agent、Task agent | 条件加载 |
| 安全审查 | 扩展安全指令(约 2,610 tokens) | 条件加载 |
关键特性:
- 模块化架构,110+ 系统提示字符串条件加载
- 基础提示适中(约 269 tokens),总量因激活的功能而异
- 包含广泛的安全和注入防御层
- 自动加载工作目录中的 CLAUDE.md 文件
- 交互模式下的会话持久化上下文
Agent SDK 默认使用最小化系统提示,包含:
| 组件 | 描述 | Token 影响 |
|---|---|---|
| 基本工具指令 | 仅显式提供的工具 | 最小化 |
| 基础安全 | 最小化安全指令 | 最小化 |
关键特性:
- 默认无编码指南或风格偏好
- 除非显式配置,否则无项目上下文
- 无广泛的工具描述
- 需要显式配置才能匹配 CLI 行为
System Prompt: [模块化,~269+ 基础 tokens]
├── 基础系统提示(~269 tokens)
├── 工具指令(Write、Read、Edit、Bash、Grep、Glob 等)
├── Git 安全协议
├── 代码引用指南
├── 专业客观性指令
├── 安全和注入防御规则
├── 环境上下文(OS、目录、日期)
├── CLAUDE.md 内容(如果存在)[条件加载]
├── MCP 工具描述(如果已配置)[条件加载]
├── Plan/Explore 模式提示 [条件加载]
└── 会话/对话上下文
User Message: "挪威的首都是什么?"
System Prompt: [最小化]
├── 基本工具指令(如果提供任何工具)
└── 基本操作上下文
User Message: "挪威的首都是什么?"
const response = await query({
prompt: "挪威的首都是什么?",
options: {
systemPrompt: {
type: "preset",
preset: "claude_code"
}
}
});System Prompt: [模块化,匹配 CLI]
├── 完整 Claude Code 系统提示
├── 工具指令
├── 编码指南
└── 安全规则
// 注意:除非配置 settingSources,否则仍不包含 CLAUDE.md
| 方法 | 命令 | 效果 |
|---|---|---|
| 追加到 prompt | claude -p "..." --append-system-prompt "..." |
在保留默认值的同时添加指令 |
| 替换 prompt | claude -p "..." --system-prompt "..." |
完全替换系统提示 |
| 项目上下文 | CLAUDE.md 文件 | 自动加载,持久化 |
| 输出风格 | /output-style [name] |
应用预定义的响应风格 |
| 方法 | 配置 | 效果 |
|---|---|---|
| 自定义 prompt | systemPrompt: "..." |
完全替换默认值(丢失工具) |
| Preset 追加 | systemPrompt: { type: "preset", preset: "claude_code", append: "..." } |
保留 CLI 功能 + 自定义指令 |
| CLAUDE.md 加载 | settingSources: ["project"] |
加载项目级指令 |
| 输出风格 | settingSources: ["user"] 或 settingSources: ["project"] |
加载保存的输出风格 |
| 功能 | CLI 默认 | SDK 默认 | SDK with Preset |
|---|---|---|---|
| 工具指令 | ✅ 完整 | ❌ 最小化 | ✅ 完整 |
| 编码指南 | ✅ 是 | ❌ 否 | ✅ 是 |
| 安全规则 | ✅ 是 | ❌ 基础 | ✅ 是 |
| CLAUDE.md 自动加载 | ✅ 是 | ❌ 否 | ❌ 否* |
| 项目上下文 | ✅ 自动 | ❌ 否 | ❌ 否* |
*需要显式 settingSources: ["project"] 配置
Claude Messages API 不提供用于可复现性的种子参数。 这是一个基本的架构限制。
| 因素 | 描述 | 可控制? |
|---|---|---|
| 不同的系统提示 | CLI vs SDK 有不同的默认值 | ✅ 是(通过配置) |
| 浮点运算 | 并行硬件特性 | ❌ 否 |
| MoE 路由 | Mixture-of-Experts 架构变化 | ❌ 否 |
| 批处理/调度 | 云基础设施差异 | ❌ 否 |
| 数值精度 | 推理引擎变化 | ❌ 否 |
| 模型快照 | 版本更新/变更 | ❌ 否 |
即使使用 temperature=0.0(贪婪解码):
- 完全确定性无法保证
- 由于基础设施因素,仍可能发生微小变化
- 已知 bug:Claude CLI 对相同输入产生非确定性输出
要在 SDK 和 CLI 之间获得最接近的相同输出:
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
// 选项 1:使用 claude_code preset
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
// 尽可能匹配 CLI 系统提示
system: "Your exact system prompt matching CLI",
messages: [
{ role: "user", content: "挪威的首都是什么?" }
],
// 使用贪婪解码以获得最大一致性
temperature: 0
});
// 选项 2:使用 Agent SDK query 函数
import { query } from "@anthropic-ai/agent-sdk";
for await (const message of query({
prompt: "挪威的首都是什么?",
options: {
systemPrompt: {
type: "preset",
preset: "claude_code"
},
temperature: 0,
model: "claude-sonnet-4-20250514",
// 像 CLI 一样加载项目上下文
settingSources: ["project"]
}
})) {
// 处理响应
}# 尽可能匹配 SDK 配置
claude -p "挪威的首都是什么?" \
--model claude-sonnet-4-20250514 \
--temperature 0即使配置完全匹配:
- 输出可能在不同运行之间不同
- 输出可能在 SDK 和 CLI 之间不同
- 不存在强制可复现性的种子参数
| 用例 | 推荐接口 | 原因 |
|---|---|---|
| 交互式开发 | Claude CLI | 完整工具套件、项目上下文 |
| 程序化集成 | Agent SDK | 细粒度控制、嵌入 |
| 一致的 API 响应 | Agent SDK + 自定义 prompt | 对系统提示有更多控制 |
| 批处理 | Agent SDK | 更适合自动化流水线 |
| 一次性任务 | Claude CLI | 设置更快、即时上下文 |
-
不要依赖位级精确的可复现性
- 构建能应对微小输出变化的应用程序
- 使用结构化输出和验证
-
对于需要一致性的生产流水线:
- 尽可能缓存结果
- 使用带 JSON schema 验证的结构化输出
- 结合确定性逻辑和验证
- 考虑多代生成和共识
-
要在 SDK 中匹配 CLI 行为:
systemPrompt: { type: "preset", preset: "claude_code", append: "Your additional instructions" }, settingSources: ["project", "user"]
| 配置 | 架构 | 说明 |
|---|---|---|
| SDK (最小化) | 最小化默认 | 仅基本工具指令 |
| SDK (claude_code preset) | 模块化(~269+ 基础) | 匹配 CLI,因功能而异 |
| CLI (默认) | 模块化(~269+ 基础) | 条件加载额外上下文 |
| CLI (带 MCP 工具) | 模块化 + MCP | MCP 工具描述添加大量 tokens |
注意: Claude Code 使用模块化架构,110+ 系统提示字符串。基础提示约 269 tokens,单个组件根据激活的功能从 18 到 2,610 tokens 不等。
影响: SDK 的最小化默认为你的实际任务留出更多上下文,但代价是失去 Claude Code 的完整功能。
| 方面 | Claude CLI | Agent SDK (默认) | Agent SDK (Preset) |
|---|---|---|---|
| 系统提示 | 模块化(~269+ 基础) | 最小化 | 模块化(匹配 CLI) |
| 包含工具 | 18+ 内置 | 仅如果提供 | 18+ 内置 |
| CLAUDE.md 自动加载 | 是 | 否 | 否(需要配置) |
| 编码指南 | 是 | 否 | 是 |
| 安全规则 | 完整 | 基础 | 完整 |
| Temperature 控制 | 是 | 是 | 是 |
| 确定性保证 | 否 | 否 | 否 |
| 相同输出? | N/A | 否(vs CLI) | 更接近,但否 |
Q:SDK vs CLI 中相同消息伴随什么系统提示?
CLI 使用模块化系统提示架构,约 269 token 基础提示和 110+ 条件加载组件(工具指令、编码指南、安全规则、项目上下文)。SDK 使用最小化默认,仅包含基本工具指令,但可以使用 claude_code preset 配置为匹配 CLI 行为。
Q:是否有相同输出的保证?
否。 即使系统提示匹配、输入相同且 temperature=0,也无法保证相同输出,原因包括:
- Claude API 缺少种子参数
- 浮点运算变化
- 基础设施级非确定性
- 模型架构(Mixture-of-Experts)路由变化
建议: 设计系统时应具备应对输出变化的能力,而不是依赖确定性行为。对于关键一致性的应用,使用结构化输出、缓存和验证层。
- Modifying System Prompts - Agent SDK
- Claude Code CLI Reference
- Claude Code Headless Mode
- Claude Code Best Practices - Anthropic Engineering
- Claude Messages API Reference
- GitHub Issue #3370: Non-deterministic output
- Claude Code System Prompts Repository - 模块化提示架构分析
- Why Deterministic Output from LLMs is Nearly Impossible
本报告由 Claude Code 使用 Opus 4.5 模型于 2026 年 2 月 3 日生成。