AI TOOLS

EP08. "Prompt Caching 加速省钱 + Code Execution 沙盒跑代码"

首页 › AI 工具 › Claude · Developer and Platform · Claude API · EP08
约 14 分钟· #EP08#Claude#Claude API
🔒 登录后可标记已读
  • Prompt Caching 能省下「重复处理同一段内容」的运算成本——Claude 处理 prompt 要经过分词、embedding、语境化好几个预处理步骤,没有 caching 时,这些工作每次请求都要重跑一遍,纯属浪费
  • Caching 不是自动的——要自己在指定的 message block 上手动加 cache breakpoint(cache_control: {"type": "ephemeral"}),断点之前的内容才会被缓存,断点之后照常处理
  • 缓存默认只活 5 分钟,想延长到 1 小时要多付 cache-write 的费用;内容只要有一丝改动(哪怕加一个字),缓存就直接失效
  • Code Execution Tool 让 Claude 在隔离的 Docker 容器里真的跑 Python 代码,但容器没有网络连接,配合 Files API 上传数据文件,才能把外部数据"喂"进这个完全隔离的沙盒
  • 前置知识:读过 [EP04](./EP04_工具调用基础.md) 理解工具调用(tool schema)基本概念;这篇笔记涉及的两个功能(Caching、Code Execution)都是叠加在标准 messages.create() 之上的进阶选项

重点内容


Prompt Caching 解决什么问题

Claude 处理一次请求,一般要经过这几步预处理:

  • 把 prompt 切成一个个 token
  • 给每个 token 生成 embedding
  • 根据上下文调整每个 token 的含义
  • 才轮到真正生成输出

没有 caching 时,这些预处理的运算成果,每次请求完就被丢掉了。开启 caching 后,Claude 会把预处理结果存进一张查找表,同样的内容再次出现时,直接复用,不用重算。

好处:

  • 命中缓存的部分响应更快
  • 命中缓存的部分成本更低
  • 不用手动区分"这次该写缓存还是该读缓存"——第一次请求自动写入,后续请求自动读取

限制:

  • 缓存默认5 分钟过期;想延长到 1 小时,要多付更高的 cache-write 费用
  • 只有「重复出现相同内容」的场景才有意义,不是随便加上去就有用
  • 越频繁复用同一段内容,收益越大

最适合的场景:文档分析工作流(同一份长文档反复被问不同问题)、迭代式编辑任务(基础内容不变,只是反复微调某个局部)。


Cache Breakpoint 怎么运作

📌 Caching 不是自动发生的——要手动在特定的 message block 上加缓存断点(cache breakpoint)。

规则:

  • 断点之前(含断点本身)的内容会被缓存,断点之后的内容照常正常处理,不进缓存
  • 要用"展开格式"(expanded format),把 cache_control 字段设成 {"type": "ephemeral"}——简写格式(shorthand)没有地方能加这个字段,不支持缓存
  • 后续请求只有在"直到断点为止的内容完全一致"时才会命中缓存——哪怕只是多加了一个「please」这种小改动,缓存也会直接失效

⚠️ Cache breakpoint 可以跨越多条 message、多种类型。如果断点放在比较靠后的 message 上,它前面所有的 message(不管是 user 还是 assistant)都会被算进缓存内容里。

可以加断点的内容类型:system prompt、tool 定义、图片 block、tool use/result block——其中 system prompt 和 tool 定义是最值得优先加缓存的对象(因为它们通常是整个应用里最稳定不变的部分)。

处理顺序与上限:

  • Claude 处理的顺序固定是:tools → system prompt → messages
  • 一次请求最多允许 4 个缓存断点
  • 缓存生效有最低门槛:累计至少 1024 token(跨所有 message/block 加总)才会触发缓存

实际怎么写:给 Tools 和 System Prompt 加缓存

Tool Schema 加缓存(只在最后一个 tool 上加断点,前面的 tools 也会一起被缓存进去,因为处理顺序是整批一起算):

if tools:
    tools_clone = tools.copy()
    last_tool = tools_clone[-1].copy()
    last_tool["cache_control"] = {"type": "ephemeral"}
    tools_clone[-1] = last_tool
    params["tools"] = tools_clone

📌 这里特地先 .copy() 出一份副本再改,不要直接改原始的 tools 列表——避免后续代码里工具顺序变动时,不小心把缓存断点标记也一起带歪了。

System Prompt 加缓存:

if system:
    params["system"] = [
        {
            "type": "text",
            "text": system,
            "cache_control": {"type": "ephemeral"}
        }
    ]

缓存命中的表现:

  • 第一次请求(写入缓存):回应里会带 cache_creation_input_tokens=1772 这类字段,代表这次帮你写了多少 token 进缓存
  • 后续请求(命中缓存):改成看到 cache_read_input_tokens=1772,代表这次直接读缓存,省了重新处理这批 token 的运算
  • ⚠️ 缓存内容只要有任何一个字符不同,就会失效,退回正常处理

💡 如果一次请求里只有部分组件改变了(比如 tools 没变、system prompt 变了),会出现"部分命中缓存"的情况——处理顺序(tools → system prompt → messages)决定了改动出现在哪一层,前面没变的部分照样能命中缓存。


Code Execution + Files API:让 Claude 真的跑代码

Files API:允许把文件单独上传,拿到一个文件 ID,之后用这个 ID 引用文件,不用再把整份文件编码成 base64 塞进消息本体。适合需要反复引用同一份文件、或者文件本身比较大的场景。

Code Execution Tool:服务端功能,让 Claude 能在隔离的 Docker 容器里执行 Python 代码。特点:

  • 容器没有网络访问权限
  • 同一段对话里可以多次执行代码

📌 因为容器完全没有对外连接,Files API 就成了把外部数据"喂"进这个沙盒的主要方式——这两个功能组合起来才是真正的威力所在,单独用 Code Execution 没办法碰到你自己的数据。

典型工作流:

  1. 用 Files API 上传数据文件(CSV 等)
  2. Message 里加一个 container upload block,带上文件 ID
  3. 请 Claude 做分析
  4. Claude 自己写代码、执行,处理这份文件
  5. 生成可下载的产出(比如一张图表)

上传文件:

file_metadata = upload('streaming.csv')

组装带文件引用的消息,并开启 Code Execution 工具:

messages = []
add_user_message(
    messages,
    [
        {
            "type": "text",
            "text": """Run a detailed analysis to determine major drivers of churn.
            Your final output should include at least one detailed plot summarizing your findings."""
        },
        {"type": "container_upload", "file_id": file_metadata.id},
    ],
)

chat(
    messages,
    tools=[{"type": "code_execution_20250522", "name": "code_execution"}]
)

回应里会出现的内容:说明性文字、记录了实际执行代码的 server tool use block、以及包含执行输出的 code execution result block。

拿生成的文件:在回应里找 type: "code_execution_output" 的 block,里面带着产出文件的 file ID,凭这个 ID 下载。

应用场景:数据分析画图之外,还能用在图片处理、文档格式转换、数学计算、自动生成报告等任何"需要真的跑代码才能算出来/做出来"的任务。

常见错误

  • ❌ 以为缓存是全自动的——不手动加 cache_control: {"type": "ephemeral"} 断点,内容不会被缓存
  • ❌ 用简写格式(shorthand)传 system/tools,却想加缓存——简写格式没地方放 cache_control 字段,必须改用展开格式
  • ❌ 内容小改动了还期待命中缓存——哪怕只多了一个字,断点前的内容就必须完全一致才会命中,改了就等于重新写一次缓存
  • ❌ 直接在原始 tools 列表上改 cache_control,不先 .copy()——容易在后续逻辑改动工具顺序时,让缓存标记跟着跑位
  • ❌ 以为开了 Code Execution Tool 就能让 Claude 直接读到你服务器上的文件——容器没有网络,必须先用 Files API 上传、再用 container_upload block 引用

Sources

官方文档:

  1. Building with the Claude API(Claude Academy 课程)— https://academy.claude.com/courses/building-with-the-claude-api