菜鸟AI - 让提示词生成更简单! 全站导航 全站导航
AI工具安装 新手教程 进阶教程 辅助资源 AI提示词 热点资讯 技术资讯 产业资讯 内容生成 模型技术 AI信息库

已有账号?

首页 > AI教程 > Claude Code API 调用上下文拼接从原理到优化全方位深度对比实战全攻略
进阶教程 综合资讯

Claude Code API 调用上下文拼接从原理到优化全方位深度对比实战全攻略

2026-06-01
阅读 0
热度 0
作者 菜鸟AI编辑部
摘要

摘要

每次调用模型API时,payload由SystemPrompt、Tools和Messages三部分组成。SystemPrompt与Tools作为稳定

Claude Code 每次发起模型 API 请求时,发送的 payload 包含三个组成部分:

  • System Prompt — 定义 Agent 角色定位、行为规范及会话上下文
  • Tools — 工具 schema 清单,告知模型当前可用的能力
  • Messages — 对话消息序列,涵盖用户指令、CLAUDE.md 配置以及工具执行结果

这三部分均在 Agent Loop 调用模型时传入,但来源各不相同:System Prompt 和 Tools 主要在循环开始前准备就绪,循环过程中相对稳定;而 Messages 则随着每轮工具执行持续追加和更新。Agent Loop 的核心运作模式为:模型返回工具调用请求 → 系统执行工具并将结果追加至 Messages → 进入下一轮模型调用,直至任务完成。

// src/query.ts — Agent Loop 中调用模型(简化示意)
for await (const message of deps.callModel({
  systemPrompt: fullSystemPrompt,   // System Prompt
  messages: ...,                    // 对话消息
  tools: ...,                       // 工具 schema 列表
}))

整个设计受一个关键约束制约:System Prompt 和 Tools 构成对缓存敏感的稳定前缀层,而 Messages 才是持续增长的动态层。模型 API 会尽量复用稳定的请求前缀;若 System Prompt 或工具 schema 中途发生变化,前缀缓存将失效。

这一约束直接决定了 Claude Code 的上下文组装架构:稳定前缀置于前,动态内容后移。也就是说,适合缓存的片段尽量保留在前缀中保持稳定,而运行时的变化则尽可能转移到 Messages、attachment 附加上下文或延迟工具加载中处理。

Agent 运行前的上下文组装

会话启动时,Claude Code 首先构建基础 System Prompt 和工具池;后续尽量维持前缀稳定,将动态变化移至 Messages、attachment 附加上下文或延迟工具加载中。

System Prompt 的工程化组装

System Prompt 并非一个庞大的字符串,而是一个由多个独立段落组成的数组。每个段落对应一个语义单元,在发送给 API 前才拼接为最终形式。这样做的好处包括:

  • 每个段落职责单一,便于单独维护和测试
  • 静态段落与动态段落可以分离,静态部分能直接命中模型的前缀缓存
  • 动态段落可按需裁剪,灵活控制注入内容

下面这段代码仅需关注三点:返回值是数组;静态 section 放在前部;动态 section 放在缓存边界之后。

export async function getSystemPrompt(tools, model, ...): Promise<string[]> {
  const dynamicSections = [
    systemPromptSection('session_guidance', () => getSessionSpecificGuidanceSection(...)),
    systemPromptSection('memory', () => loadMemoryPrompt()),
    systemPromptSection('env_info_simple', () => computeSimpleEnvInfo(model, ...)),
    // ...
  ];
  return [
    // --- 静态段落 ---
    getSimpleIntroSection(),                // 身份声明
    getSimpleSystemSection(),              // 系统规则
    getSimpleDoingTasksSection(),          // 任务执行准则
    getActionsSection(),                   // 操作安全
    getUsingYourToolsSection(),            // 工具使用偏好
    getSimpleToneAndStyleSection(),        // 沟通风格
    getOutputEfficiencySection(),          // 输出效率
    // === 缓存边界标记 ===
    ...(shouldUseGlobalCacheScope() ? [SYSTEM_PROMPT_DYNAMIC_BOUNDARY] : []),
    // --- 动态段落 ---
    ...dynamicSections,
  ].filter(s => s !== null);
}

静态段落定义了 Agent 的“行为规范”。它们的共同特点是:通常不依赖当前用户、项目目录、MCP 连接状态或本轮输入,可跨用户缓存,因此适合放在最前面作为稳定前缀:

  • 身份声明 + 安全指令:"You are an interactive agent that helps users with software engineering tasks",同时包含网络安全和 URL 生成限制
  • 系统规则:工具权限、system-reminder 标签说明、外部数据 prompt injection 警告
  • 任务准则:先读取文件再修改、不添加多余功能、不写冗余注释、安全意识(OWASP Top 10)
  • 操作安全:关注操作的可逆性和影响范围,破坏性操作需经用户确认
  • 工具偏好:优先使用专用工具(Read/Edit/Write/Grep/Glob)而非 Bash
  • 沟通风格:简洁、无 emoji、代码引用需附带文件路径和行号

动态段落包含当前会话相关的上下文,会因用户环境、配置、记忆、语言偏好等因素变化。但在单个会话内部,大多数动态段落会被 memoized(首次计算后缓存在内存中,后续直接复用结果):会话开始时计算一次,后续请求直接复用。真正需要运行时变动的部分,通常会后移到 Messages、增量 attachment 附加上下文(仅发送变化部分)或延迟工具加载中,避免直接改动可缓存前缀。典型的动态段落包括:

  • session_guidance — 当前可用的工具和技能列表,包括 Agent 工具(允许模型启动子 Agent 并行处理子任务)、Skill 工具(将用户定义的 slash command 如 /review 封装为模型可调用的工具)的使用指导
  • memory — 自动记忆系统的行为指令,指导模型如何保存和检索记忆
  • env_info_simple — 当前工作目录、操作系统、Shell 类型、模型名称
  • language / output_style — 用户配置的语言偏好和输出风格
  • mcp_instructions — MCP 服务器的连接状态和使用说明;它并非普通 memoized 段落,MCP 连接的变化更多通过 uncached / delta 机制、Tool Search / defer_loading,或下一次顶层上下文构建来体现,而非在同一个 Agent Loop 的每次工具 follow-up 中重算 System Prompt

两者对比:

静态段落动态段落
跨会话设计为尽量稳定,适合作为更稳定的缓存前缀因用户环境、配置而变化
会话内基本保持不变大部分 memoized;需要变化时通常后移至 Messages / delta / deferred tools
内容占比~60%+剩余部分

静态段落与动态段落之间使用 SYSTEM_PROMPT_DYNAMIC_BOUNDARY 标记分隔。该标记的工程意义在于:为 Prompt Cache 提供一个确定性的切分锚点。可以理解为:边界前的段落尽量保持 byte-level 稳定,边界后的段落允许按会话变化,这样缓存策略就能明确复用哪一段。

Tools

Tools 部分并非简单“会话开始后永远不变”。Claude Code 会维护当前可用的候选工具池,再决定哪些工具直接进入本轮模型请求,哪些通过 Tool Search 延迟加载。

可以用三层模型来理解:

  1. 候选工具池 — 当前会话可能使用的工具全集,来源于内置工具、MCP、Skill 等。
  2. 本轮直接传入的工具 — 直接放入模型 payload 的工具 schema,属于缓存敏感前缀的一部分,通常是高频、基础、需要立即可见的工具。
  3. deferred tools — 不直接进入前缀的长尾或动态工具,通过 Tool Search / defer_loading 在需要时暴露,避免工具 schema 撑大稳定前缀或频繁破坏缓存。

延迟加载的触发方式:当模型表达需要某类工具的意图时,系统通过 Tool Search 从候选池中提取对应 schema 补入上下文,而非每次请求都将所有工具 schema 塞入前缀。

Claude Code 的工具来源包括:

  • 内置工具 — Read、Write、Bash、Grep、Glob 等文件操作和搜索工具,约 40+ 个
  • MCP 工具 — 通过 MCP(Model Context Protocol)服务器动态注册的外部工具
  • Skill 工具 — 用户定义的 slash command 转换为可调用的工具

工具池的核心装配路径之一是 assembleToolPool()(接收当前会话的工具来源配置,返回过滤后的候选工具池):它负责将内置工具和 MCP 工具按权限过滤、排序、去重;但工具的来源及后续合并并非全部在该函数中完成。是否直接进入本轮请求,还需由后续的工具选择及延迟加载策略决定。

Messages 的初始组装

与 System Prompt 和 Tools 不同,Messages 在会话过程中持续增长。首次对话时,messages 数组包含三个组成部分:

  1. CLAUDE.md — 通过 prependUserContext()(将 CLAUDE.md 内容包装为 user message 后插入 messages 数组最前方)作为首条 user 消息注入。注意,该操作在每轮调用模型前都会执行,因此 CLAUDE.md 在每一轮对话中都位于 messages 最前面。
  2. 用户输入 — 用户实际输入的消息(createUserMessage
  3. attachment 附加上下文(AttachmentMessage)— @提及的文件内容、IDE 选中的代码片段、hook 注入的额外上下文等

组装过程如下:

CLAUDE.md 注入

Messages 部分最核心的注入内容是 CLAUDE.md——用户通过 Markdown 文件定义 Agent 行为规范。文件按优先级从低到高加载:

  1. Managed — /etc/claude-code/CLAUDE.md,管理员全局策略
  2. User — ~/.claude/CLAUDE.md,用户私有全局偏好
  3. Project — 项目根目录或上级目录中的 CLAUDE.md.claude/CLAUDE.md.claude/rules/*.md,入库管理
  4. Local — 项目根目录的 CLAUDE.local.md,本地私有覆盖

Claude Code 从当前目录向上遍历至根目录,每个层级都可能存在上述文件。优先级的具体行为:高优先级文件的内容排在低优先级之后。由于 Claude 模型从上到下阅读 messages,后出现的指令通常会被优先遵循——所以若 User 级写“用中文回复”,Project 级写“用英文回复”,模型会倾向于遵循 Project 级指令。该排序仅描述同为 CLAUDE.md 上下文时的工程策略,不代表 Project 级内容可以覆盖 System Prompt 或安全边界。

简而言之:System Prompt 管控“模型如何被约束”,CLAUDE.md 管控“这个项目希望模型知道什么”。

CLAUDE.md 通过 标签作为首条 user 消息注入。注意:这里的 是 user message 内容中的 XML-like 标签,不等同于 API 的 system role:

<system-reminder>
As you answer the user's questions, you can use the following context:

# claudeMdCodebase and user instructions are shown below. Be sure to adhere to these
instructions. IMPORTANT: These instructions OVERRIDE any default beha vior
and you MUST follow them exactly as written.

Contents of ~/.claude/CLAUDE.md (user's private global instructions for all projects):
# 全局偏好
- 默认使用中文回复
- commit message 使用英文
- 代码风格偏好:优先函数式写法,避免 class

Contents of CLAUDE.md (project instructions, checked into the codebase):
# 项目规范
- 所有接口必须返回统一的 `{ code, data, message }` 结构
- 错误处理使用 AppError 类,不要直接 throw Error
- 参数校验使用 zod schema

# currentDate
Today's date is 2026-05-17.

IMPORTANT: this context may or may not be relevant to your tasks.
system-reminder>

用户输入

用户输入会先被拆分为两部分:原始输入本身包装为 UserMessage,同轮需要补充的上下文包装为 AttachmentMessage

  • 纯文本输入:直接作为 content 传入
  • 粘贴图片:文本与图片组合进 UserMessage.content,图片经过必要处理以满足 API 限制
  • @文件 / @目录 / @图片文件 / MCP 资源 / @agent:不修改用户原文,而是解析为独立的 AttachmentMessage(attachment 附加上下文),跟在 UserMessage 之后

attachment 附加上下文

这里的 attachment 不限于 @ 语法。用户输入预处理阶段会先调用统一的 attachment 上下文收集逻辑,结果与 UserMessage 一同进入 messages。简化来看,模型看到的消息序列类似:

[CLAUDE.md user message, 用户原始输入, attachment:file, attachment:diagnostics, ...]

不应将 attachment 理解为固定、全量、每轮必现的接口表。源码中可见的 attachment 类型众多,其中一部分依赖特定功能、模式或 feature gate。为把握主线,可按用途分组:

分组典型类型作用
用户显式输入filedirectorypdf_referencemcp_resource将 @ 文件、目录、PDF 或 MCP 资源补充到用户消息旁
已读与文件变化already_read_fileedited_text_fileedited_image_file避免重复注入,或仅补充文件读入后的变化
IDE 与诊断selected_lines_in_ideopened_file_in_idediagnostics将用户当前查看的代码、选区、LSP 诊断交给模型
Skill / Agent / Tool 发现skill_discoverydynamic_skillskill_listingagent_mentionagent_listing_deltadeferred_tools_delta让模型了解可用技能、Agent 类型及延迟工具变化
Hook 与异步事件hook_additional_contexthook_successasync_hook_responsequeued_commandtask_status将 hook 输出、后台任务、异步通知补入下一轮上下文
运行模式与提醒plan_modeplan_mode_exitauto_modeauto_mode_exittodo_remindertask_reminderverify_plan_remindercritical_system_remindercontext_efficiencydate_change以轻量提醒同步当前运行状态和约束
预算与输出控制token_usagebudget_usdoutput_token_usage帮助模型感知上下文、预算和输出长度
特定功能路径nested_memorymcp_instructions_deltateammate_mailboxteam_contextultrathink_effortcompanion_intro仅在对应功能、团队模式或实验路径下出现

Agent 运行过程中的动态上下文

前三节描述的是 Agent Loop 启动前的基础组装。进入循环后,Claude Code 会保持 System Prompt 和工具稳定;主要变化集中在 Messages 数组上,而 MCP 这类动态工具则优先通过 Tool Search / defer_loading 处理。

Agent Loop

主循环位于 query() 中,核心逻辑如下:

// query.ts — Agent Loop 核心结构(已简化,保留关键调用)
while (true) {
  // 1. 准备本轮要发送给模型的 messages(提取本轮需要发送的消息,可能包含历史截断逻辑)
  messagesForQuery = getMessagesForCurrentTurn(state.messages);

  // 2. 调用模型
  for await (const message of deps.callModel({
    messages: prependUserContext(messagesForQuery, userContext), // 每轮调用前把 CLAUDE.md / userContext 放回 messages 前部
    systemPrompt: fullSystemPrompt,
    tools: toolUseContext.options.tools,
  })) {
    /* 收集 assistant 消息和 tool_use 块 */
  }

  // 3. 没有工具调用 → 结束
  if (!needsFollowUp) {
    return { reason: 'completed' };
  }

  // 4. 执行工具(异步执行工具调用,返回 tool result 消息流)
  const toolUpdates = runTools(toolUseBlocks, assistantMessages, canUseTool, toolUseContext);
  for await (const update of toolUpdates) {
    yield update.message;
    toolResults.push(update.message);
  }

  // 5. 注入运行时附加上下文
  // ...(见下文)

  // 6. 更新 messages,进入下一轮
  state = {
    messages: [...messagesForQuery, ...assistantMessages, ...toolResults],
    transition: { reason: 'next_turn' },
  };
}

整个循环的流程可概括为:准备消息、调用模型、检查工具调用、执行工具、注入增量上下文、更新状态继续循环。

每轮循环刷新了什么

前面列出的 attachment 附加上下文的收集逻辑并非只在第一轮运行。工具执行完成后,Claude Code 会在下一次模型调用前重新注入 attachment 上下文,但并非将已注入的内容全量重放。多数 attachment 都有自己的触发条件或去重状态:没有新事件、新变化或到期提醒时,便不会产生新的 attachment。去重依据分散在各类型自己的状态中,例如已发送过的 skill name、已读文件记录、队列消费状态、文件 diff 基线等。

后续轮次中最常补充的是这些“增量变化”:

  • 排队消息:后台任务完成、外部通知、子 Agent 消息等异步事件,消费后从队列移除。
  • 文件变更:已读入上下文的文件若被工具修改,仅注入新的文本 diff 或图片内容。
  • 预取记忆:记忆检索在模型返回工具调用时异步启动;结果只消费一次,并会过滤模型已读/已写/已编辑的记忆文件。
  • 技能发现:基于本轮消息和工具写入信号预取;技能列表本身也记录已发送过的 skill name,只补充新增项。
  • 诊断信息:编辑文件后 IDE/LSP 产生新的错误或警告,再以诊断类 attachment 附加上下文补给模型。

更准确地说,循环中的 attachment 机制是在每轮工具执行后执行一次增量检查:仅在发现新的队列消息、文件差异、检索结果或技能变化时,才将对应信息补充进下一轮 Messages。下图仅抽取四类最典型的增量变化。

总结

Claude Code 的上下文并非一次性拼接成一个静态大 prompt,而是分层组装、分阶段更新:

  • System Prompt 承载稳定规则和动态段落边界,尽量让可缓存的前缀保持稳定。
  • Tools 根据内置工具、MCP、Agent、Skill 等来源组装,并在必要时通过延迟加载降低上下文负担。
  • Messages 是 Agent Loop 中持续变化的主体:用户输入、模型回复、工具调用结果和 attachment 附加上下文都按顺序进入消息流。
  • attachment 附加上下文是运行时补充上下文的关键机制:第一轮侧重用户输入和初始环境,后续轮次侧重工具执行后的增量变化。

因此,理解 Claude Code 的上下文组装,核心不在于记住某个固定的 prompt 模板,而在于看透三件事:哪些内容稳定不变、哪些内容按需装配、哪些内容会随着工具执行继续增量补入下一轮 Messages。

来源:互联网

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

同类文章推荐

相关文章推荐

更多