跳转到主内容

Claude Files API 深入:从上传、复用到配额管理的工程化指南

Files API 是 Claude API 的文件持久化层,让 PDF、图片、CSV、源码一次上传、跨请求复用。本文讲清楚生命周期、500MB 单文件 / 100GB 组织配额、与 Batch / MCP / Code Execution 的协同,以及生产环境去重、清理、错误处理的实践方案。

开发指南code executionbatch api预计阅读10分钟
2026.05.23 发表
Claude Files API 深入:从上传、复用到配额管理的工程化指南

Claude Files API 深入:从上传、复用到配额管理的工程化指南

如果你在生产环境用 Claude 处理任何带"文档"的业务——合同问答、发票识别、代码审查、数据分析——很快会撞到一个共同问题:同一份文件被反复 base64 编码塞进请求。一份 5MB 的 PDF 每次调用上传一次,base64 编码膨胀到 6.6MB,10 万次请求就是 660GB 的无效带宽,token 计费上也按全量重新计算。

Files API 就是为这个场景设计的:上传一次拿到 file_id,后续所有请求只引用 ID。听起来简单,但接入时一堆细节会被忽略——beta header 怎么带、配额怎么算、文件能不能跨 API key 复用、删不删除、和 Batch / MCP / Code Execution 怎么配合。本文把这些都讲清楚。

所有代码示例使用 claudeapi.com 的国内接入点 https://gw.claudeapi.com,避免国内直连 api.anthropic.com 的超时问题。Files API 在国内中转和官方 API 上行为完全一致,只是入口换了。


一、Files API 解决的核心问题

把同一份文件反复塞进请求会带来三个具体损失:

损失 表现 Files API 怎么解决
带宽 base64 比原始字节多 33%,每次上传都重传 一次上传,后续只传 file_id(几十字节)
延迟 大文件上传占据请求首段时间 file_id 引用是常数时间
编排复杂度 多用户共享同一文档时各传一份 同 workspace 内 file_id 可被任意 API key 引用

注意:Files API 不能省 token——文件被引用时仍按原文 token 量计费,省的是网络传输和编码开销,以及"重复上传"这种纯浪费。要真正省 token 还得叠加 prompt caching。

现状(截至 2026-05)

Files API 仍处于 beta 阶段,调用必须带 header anthropic-beta: files-api-2025-04-14。Anthropic 在 2026 年的官方路线图里提过会在年内 GA,但接口形态可能微调,生产接入时建议把这个 header 抽成常量集中管理,以便未来一处修改。

支持的平台:Claude API 直接调用、Claude Platform on AWS、Microsoft Foundry。不支持 Amazon Bedrock 和 Vertex AI(来源:Anthropic Files API 官方文档)。


二、生命周期:上传、引用、删除

2.1 上传

import anthropic

client = anthropic.Anthropic(
    api_key="sk-你的ClaudeAPI密钥",
    base_url="https://gw.claudeapi.com",
    default_headers={"anthropic-beta": "files-api-2025-04-14"},
)

with open("annual_report.pdf", "rb") as f:
    uploaded = client.beta.files.upload(
        file=("annual_report.pdf", f, "application/pdf")
    )

print(uploaded)
# File(
#   id='file_011CNha8iCJcU1wXNR6q4V8w',
#   type='file',
#   filename='annual_report.pdf',
#   mime_type='application/pdf',
#   size_bytes=2456789,
#   created_at='2026-05-23T08:12:33Z',
#   downloadable=False
# )
import anthropic

client = anthropic.Anthropic(
    api_key="sk-你的ClaudeAPI密钥",
    base_url="https://gw.claudeapi.com",
    default_headers={"anthropic-beta": "files-api-2025-04-14"},
)

with open("annual_report.pdf", "rb") as f:
    uploaded = client.beta.files.upload(
        file=("annual_report.pdf", f, "application/pdf")
    )

print(uploaded)
# File(
#   id='file_011CNha8iCJcU1wXNR6q4V8w',
#   type='file',
#   filename='annual_report.pdf',
#   mime_type='application/pdf',
#   size_bytes=2456789,
#   created_at='2026-05-23T08:12:33Z',
#   downloadable=False
# )

返回对象里要关注三个字段:

  • id:后续所有引用的句柄
  • size_bytes:累加到组织 100GB 配额
  • downloadable:用户上传的文件 不能下载(恒为 False),只有 skill 或 code-execution 生成的文件可下载

2.2 引用

response = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=4096,
    extra_headers={"anthropic-beta": "files-api-2025-04-14"},
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "document",
                    "source": {"type": "file", "file_id": uploaded.id},
                },
                {"type": "text", "text": "概述本报告的财务关键指标。"},
            ],
        }
    ],
)
response = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=4096,
    extra_headers={"anthropic-beta": "files-api-2025-04-14"},
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "document",
                    "source": {"type": "file", "file_id": uploaded.id},
                },
                {"type": "text", "text": "概述本报告的财务关键指标。"},
            ],
        }
    ],
)

content block 类型按文件类型选择:

文件类型 content block type source.type
PDF document file
图片(PNG/JPEG/GIF/WebP) image file
CSV/Excel(搭配 code execution) container_upload
源码文件(搭配 code execution) container_upload

2.3 列出与删除

# 分页列出
files = client.beta.files.list(limit=100)
for f in files.data:
    print(f.id, f.filename, f.size_bytes, f.created_at)

# 删除单个
client.beta.files.delete("file_011CNha8iCJcU1wXNR6q4V8w")
# 分页列出
files = client.beta.files.list(limit=100)
for f in files.data:
    print(f.id, f.filename, f.size_bytes, f.created_at)

# 删除单个
client.beta.files.delete("file_011CNha8iCJcU1wXNR6q4V8w")

重要:删除是不可逆的,且不会回滚之前用该 file_id 完成的请求记录。但如果有任何进行中的 Batch 任务还在引用这个 file_id,删除会让 Batch 任务报错。删除前用 list 接口或自己的本地索引确认没有引用方。

2.4 cURL 三件套

# 上传
curl https://gw.claudeapi.com/v1/files \
  -H "x-api-key: sk-你的ClaudeAPI密钥" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: files-api-2025-04-14" \
  -F "file=@annual_report.pdf;type=application/pdf"

# 列出
curl https://gw.claudeapi.com/v1/files \
  -H "x-api-key: sk-你的ClaudeAPI密钥" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: files-api-2025-04-14"

# 删除
curl -X DELETE https://gw.claudeapi.com/v1/files/file_xxx \
  -H "x-api-key: sk-你的ClaudeAPI密钥" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: files-api-2025-04-14"
# 上传
curl https://gw.claudeapi.com/v1/files \
  -H "x-api-key: sk-你的ClaudeAPI密钥" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: files-api-2025-04-14" \
  -F "file=@annual_report.pdf;type=application/pdf"

# 列出
curl https://gw.claudeapi.com/v1/files \
  -H "x-api-key: sk-你的ClaudeAPI密钥" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: files-api-2025-04-14"

# 删除
curl -X DELETE https://gw.claudeapi.com/v1/files/file_xxx \
  -H "x-api-key: sk-你的ClaudeAPI密钥" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: files-api-2025-04-14"

三、配额:500MB 单文件、100GB 组织

维度 限制
单文件大小 500 MB
组织(workspace)总存储 100 GB
文件名长度 1-255 字符
文件名禁止字符 路径分隔符 / \、控制字符
Zero Data Retention 不适用——Files API 不在 ZDR 覆盖范围

100GB 看着多,但生产环境很快就能爆——一个客服 SaaS 一天上传 5000 份 1MB 的工单截图,20 天就 100GB。配额管理要做两件事:前置去重定期清理

3.1 前置去重:SHA-256 + 本地索引

每次上传前先算 hash,命中已上传文件直接复用 file_id,不重复上传。

import hashlib
import sqlite3

def get_or_upload(file_path: str, client) -> str:
    with open(file_path, "rb") as f:
        content = f.read()
        digest = hashlib.sha256(content).hexdigest()

    # 查本地 hash → file_id 索引
    db = sqlite3.connect("file_index.db")
    db.execute("CREATE TABLE IF NOT EXISTS files (hash TEXT PRIMARY KEY, file_id TEXT)")
    row = db.execute("SELECT file_id FROM files WHERE hash = ?", (digest,)).fetchone()
    if row:
        return row[0]

    # 未命中,上传并入库
    uploaded = client.beta.files.upload(
        file=(file_path, content, "application/pdf")
    )
    db.execute("INSERT INTO files VALUES (?, ?)", (digest, uploaded.id))
    db.commit()
    return uploaded.id
import hashlib
import sqlite3

def get_or_upload(file_path: str, client) -> str:
    with open(file_path, "rb") as f:
        content = f.read()
        digest = hashlib.sha256(content).hexdigest()

    # 查本地 hash → file_id 索引
    db = sqlite3.connect("file_index.db")
    db.execute("CREATE TABLE IF NOT EXISTS files (hash TEXT PRIMARY KEY, file_id TEXT)")
    row = db.execute("SELECT file_id FROM files WHERE hash = ?", (digest,)).fetchone()
    if row:
        return row[0]

    # 未命中,上传并入库
    uploaded = client.beta.files.upload(
        file=(file_path, content, "application/pdf")
    )
    db.execute("INSERT INTO files VALUES (?, ?)", (digest, uploaded.id))
    db.commit()
    return uploaded.id

陷阱:本地 hash 索引和 Anthropic 服务器的真实状态可能不同步——你删除了 file_id 但本地索引没更新。生产环境每周跑一次"对账",让本地索引和 client.beta.files.list() 的实际结果保持一致。

3.2 清理策略:按用途分类

不是所有文件都该长期保留。按用途打 tag 用不同的清理周期:

文件用途 保留策略
用户主动上传的"我的文档库" 用户删除时同步删除
工单/客服截图 30 天 TTL,自动删除
一次性问答的临时文件 调用完立即删除
全局共享的标准文档(产品手册、SOP) 永久保留,放白名单

Anthropic 服务端没有 TTL 字段——TTL 要靠本地 created_at + 定时任务实现。

3.3 监控配额

files = client.beta.files.list(limit=1000)
total_bytes = sum(f.size_bytes for f in files.data)
print(f"已用: {total_bytes / 1024**3:.2f} GB / 100 GB")
print(f"文件数: {len(files.data)}")
files = client.beta.files.list(limit=1000)
total_bytes = sum(f.size_bytes for f in files.data)
print(f"已用: {total_bytes / 1024**3:.2f} GB / 100 GB")
print(f"文件数: {len(files.data)}")

接到 Grafana / Prometheus 里,设置 80% 配额告警。


四、与其他能力的协同

Files API 真正发挥威力是和其他能力组合用,单独看只是个上传接口。

4.1 + Prompt Caching:长文档反复问答省 90%

文档内容 token 在第一次问答时全价计费,后续 5 分钟内的复用按 1/10 计价。

response = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=4096,
    extra_headers={"anthropic-beta": "files-api-2025-04-14"},
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "document",
                    "source": {"type": "file", "file_id": file_id},
                    "cache_control": {"type": "ephemeral"},
                },
                {"type": "text", "text": "问题 1..."},
            ],
        }
    ],
)
response = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=4096,
    extra_headers={"anthropic-beta": "files-api-2025-04-14"},
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "document",
                    "source": {"type": "file", "file_id": file_id},
                    "cache_control": {"type": "ephemeral"},
                },
                {"type": "text", "text": "问题 1..."},
            ],
        }
    ],
)

cache 5 分钟内反复命中,法务团队连续问 20 个问题,实际计费只有 1 次全价 + 19 次 1/10 价。

4.2 + Batch API:批量处理多份文档

Batch API 用于"我有 1000 份发票,半小时内出结果可以接受异步"这类场景,价格是同步接口的一半。Files API 上传的文件可以被 Batch 任务引用,1000 份发票实际只占 1000 个 file_id,不需要在请求里塞 base64。

import json

batch_requests = [
    {
        "custom_id": f"invoice_{i}",
        "params": {
            "model": "claude-haiku-4-5-20251001",
            "max_tokens": 1024,
            "messages": [{
                "role": "user",
                "content": [
                    {"type": "document", "source": {"type": "file", "file_id": fid}},
                    {"type": "text", "text": "抽取发票号、日期、金额,输出 JSON"},
                ],
            }],
        },
    }
    for i, fid in enumerate(invoice_file_ids)
]

batch = client.messages.batches.create(
    requests=batch_requests,
    extra_headers={"anthropic-beta": "files-api-2025-04-14,message-batches-2024-09-24"},
)
import json

batch_requests = [
    {
        "custom_id": f"invoice_{i}",
        "params": {
            "model": "claude-haiku-4-5-20251001",
            "max_tokens": 1024,
            "messages": [{
                "role": "user",
                "content": [
                    {"type": "document", "source": {"type": "file", "file_id": fid}},
                    {"type": "text", "text": "抽取发票号、日期、金额,输出 JSON"},
                ],
            }],
        },
    }
    for i, fid in enumerate(invoice_file_ids)
]

batch = client.messages.batches.create(
    requests=batch_requests,
    extra_headers={"anthropic-beta": "files-api-2025-04-14,message-batches-2024-09-24"},
)

4.3 + Code Execution Tool:把 CSV 喂进沙箱

Code Execution Tool 允许 Claude 在沙箱里跑 Python,适合分析 CSV / Excel。文件通过 Files API 上传后,用 container_upload 类型挂载到沙箱:

response = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=4096,
    tools=[{"type": "code_execution_20250522", "name": "code_execution"}],
    extra_headers={
        "anthropic-beta": "files-api-2025-04-14,code-execution-2025-05-22"
    },
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "container_upload", "file_id": csv_file_id},
                {"type": "text", "text": "分析销售数据,给出 Top 10 SKU 与同比增速。"},
            ],
        }
    ],
)
response = client.messages.create(
    model="claude-opus-4-7",
    max_tokens=4096,
    tools=[{"type": "code_execution_20250522", "name": "code_execution"}],
    extra_headers={
        "anthropic-beta": "files-api-2025-04-14,code-execution-2025-05-22"
    },
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "container_upload", "file_id": csv_file_id},
                {"type": "text", "text": "分析销售数据,给出 Top 10 SKU 与同比增速。"},
            ],
        }
    ],
)

Claude 会在沙箱里 pd.read_csv() 这份文件,跑分析,输出结论。

4.4 + MCP / Managed Agents:跨会话共享文件

Managed Agents API(2026-04-01 beta)允许在 agent session 里 mount 文件——挂载产生的是"session 内的副本 file_id",不占用户存储配额,且 agent 不能修改原文件。这套机制让多个 agent 共享一份标准文档(比如客服 SOP)成为可能。


五、错误码与排查

HTTP 码 错误类型 常见原因 处理
400 invalid_request_error 漏 beta header anthropic-beta: files-api-2025-04-14
400 file_too_large_for_context 文件比上下文窗口大 切分或换更大上下文模型
400 invalid_filename 文件名非法 限制在 1-255 字符,移除路径分隔符
413 request_too_large 文件 > 500 MB 拆分或压缩
403 storage_limit_exceeded 组织达 100 GB 清理旧文件,或加配额
404 not_found file_id 已删除或拼错 校验 file_id 是否仍存在

六、5 条生产经验

经验 1:beta header 写在 SDK 初始化里,不要散落在每次调用

client = anthropic.Anthropic(
    api_key="...",
    base_url="https://gw.claudeapi.com",
    default_headers={"anthropic-beta": "files-api-2025-04-14"},
)
client = anthropic.Anthropic(
    api_key="...",
    base_url="https://gw.claudeapi.com",
    default_headers={"anthropic-beta": "files-api-2025-04-14"},
)

避免 90% 的 400 错误。

经验 2:file_id 不要直接暴露给前端

file_id 在同 workspace 内全局可引用,前端拿到等于拿到文件指针。前端应该用自己的业务 ID(如 doc_uuid)做映射,后端维护 doc_uuid → file_id 关系。

经验 3:scope 是 workspace,不是 API key

同一个 workspace 下,API key A 上传的文件,API key B 可以引用。这意味着工作流可以一个 key 专门做上传(权限受限),另一个 key 做问答。但也意味着多租户系统必须自己做隔离——不要把多个客户放在同一 workspace。

经验 4:删除是异步可见的,不要"删除后立即引用"做测试

DELETE 返回 200 不代表存储端立刻清理,极短时间内可能仍能引用。生产代码不要写这种边界用例的逻辑。

经验 5:用 created_at 而不是 updated_at

Files API 没有 updated_at——文件一旦上传就不可改,要改就重传。本地索引按 created_at 排序做 LRU 清理即可。


七、模型选型参考

Files API 本身和模型无关,但配合不同模型的常见组合:

场景 推荐模型 原因
大文档深度问答(合同/财报/论文) Opus 4.7 推理深度高,长上下文稳
标准文档问答(产品手册/SOP) Sonnet 4.6 性价比最高,大部分场景够用
批量结构化抽取(发票/简历/订单) Haiku 4.5 极速,适合 Batch + Files 组合
数据分析(CSV/Excel + code execution) Sonnet 4.6 / Opus 4.7 看分析复杂度选

小结

Files API 把"重复上传"这个朴素的浪费消灭掉,真正的工程价值在于和 Prompt Caching、Batch、Code Execution、Managed Agents 的组合——单独看它就是个上传接口,组合起来可以把生产环境的 token 成本和延迟降一个数量级。

接入要点就三句话:SDK 初始化时塞 beta header本地用 SHA-256 做去重索引按用途分类设清理策略。剩下都是细节。

国内开发者直接调用 Anthropic 官方 Files API 会被防火长城拦截,推荐通过 claudeapi.com 接入:base_url 改为 https://gw.claudeapi.com,SDK 一行不动,Files API 配额、上传速度、调用日志都能在 console.claudeapi.com 控制台看到。人民币结算,支持支付宝/微信充值与对公开票。

相关文章