更新于

Anthropic Files API 国内使用完整指南


Anthropic 在 2025 年底推出了 Files API,允许开发者将文档、图片、PDF 等文件先上传到 Anthropic 的服务端,获得一个持久化的 file_id,之后在多轮对话或 Batch 请求中反复引用,而无需每次都重新传输原始数据。

对国内开发者而言,这个功能在节省带宽、提升稳定性方面意义明显——但能否在大陆网络环境中顺利使用,又有哪些坑,是本文要重点解答的。

一、Files API 解决了什么问题

在 Files API 推出之前,将文件发给 Claude 只有两种方式:

  1. Base64 内联:把文件编码后塞进 messagescontent 字段。每次请求都要重传,如果文件是 20MB 的 PDF,每轮对话就多 20MB 的上行流量。
  2. URL 引用:把文件托管到公网,传入 URL。这要求文件服务器对 Anthropic 的爬取友好,且文件必须公开可访问。

Files API 的思路是:先传一次,后续复用

对比维度Base64 内联Files API
每次请求流量原文件大小仅引用(几十字节)
文件生命周期单次请求最长 30 天
多轮对话复用需重复上传一个 file_id 复用
Batch API 联动需在 batch JSON 内嵌直接引用 file_id
国内网络依赖单次上传即可上传一次,访问多次

对于合同分析、财务报表审核、代码库批量审查等场景,Files API 可以大幅降低 API 调用的网络成本和失败率。

二、Files API 的基本概念

2.1 文件存储期限

上传成功后,文件默认保留 30 天,之后自动删除。可以通过 API 手动提前删除。每个 Organization 的存储上限目前约为 100GB,单个文件最大 512MB(PDF 单页超过 100 张时建议分割)。

2.2 支持的文件类型

  • 文档:PDF(application/pdf)、纯文本(text/plain)、Markdown
  • 图片:JPEG、PNG、GIF、WebP(支持 vision 场景)
  • 数据:CSV(当作文本处理,需在 prompt 说明格式)

不支持 Word、Excel 的原始格式(需先转 PDF 或 CSV)。

2.3 计费逻辑

上传和存储本身不额外收费(截至 2026 年中)。费用发生在引用文件时,按实际读取的 token 数计算。如果同一文件在 Batch 中被 100 个请求引用,就计 100 次读取费用——但总费用仍然远低于每次 Base64 重传带来的延迟和重试成本。

三、国内网络环境下的访问现状

Anthropic 的 API 端点(api.anthropic.com)在中国大陆无法直连,Files API 的上传端点同样如此:

https://api.anthropic.com/v1/files

常见的解决方案有两种:

方案 A:自建代理或 VPN 在境外服务器搭建 Nginx 反向代理,将 api.anthropic.com 转发到本地可访问的域名。维护成本高,且 IP 随时可能被封。

方案 B:使用 API 中转服务 选择兼容 Anthropic 原生协议的 API 中转平台(如 YoTradeApi),将 base_url 替换为中转地址。这是大多数国内开发者的首选——无需自建基础设施,只需改一行配置。

本文后续示例均以**方案 B(API 中转)**为前提,但代码结构与直连完全一致,切换只需改 base_url

四、环境准备

pip install anthropic>=0.40.0

设置环境变量:

# 如使用 API 中转
export ANTHROPIC_BASE_URL="https://api.yotradeapi.com"
export ANTHROPIC_API_KEY="your-relay-key"

初始化客户端:

import anthropic
import os

client = anthropic.Anthropic(
    api_key=os.environ["ANTHROPIC_API_KEY"],
    base_url=os.environ.get("ANTHROPIC_BASE_URL", "https://api.anthropic.com"),
)

五、核心操作:上传、引用、删除

5.1 上传文件

def upload_file(client: anthropic.Anthropic, file_path: str) -> str:
    """上传文件并返回 file_id"""
    with open(file_path, "rb") as f:
        response = client.beta.files.upload(
            file=(file_path.split("/")[-1], f, "application/pdf"),
        )
    print(f"上传成功: {response.id}")
    return response.id

返回的 response.id 格式类似 file-abc123xyz,保存好,后续引用都靠它。

5.2 列出已上传文件

def list_files(client: anthropic.Anthropic):
    files = client.beta.files.list()
    for f in files.data:
        print(f"  {f.id}  {f.filename}  created={f.created_at}")

5.3 在对话中引用文件(PDF 示例)

def analyze_pdf(client: anthropic.Anthropic, file_id: str, question: str) -> str:
    response = client.beta.messages.create(
        model="claude-opus-4-8",
        max_tokens=2048,
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "document",
                        "source": {
                            "type": "file",
                            "file_id": file_id,
                        },
                    },
                    {
                        "type": "text",
                        "text": question,
                    },
                ],
            }
        ],
        betas=["files-api-2025-04-14"],
    )
    return response.content[0].text

注意两点:

  • 必须在请求中加 betas=["files-api-2025-04-14"](beta header)
  • source.type"file"file_id 填上传返回的 ID

5.4 在图片分析中引用文件

def analyze_image(client: anthropic.Anthropic, file_id: str, prompt: str) -> str:
    response = client.beta.messages.create(
        model="claude-opus-4-8",
        max_tokens=1024,
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "image",
                        "source": {
                            "type": "file",
                            "file_id": file_id,
                        },
                    },
                    {"type": "text", "text": prompt},
                ],
            }
        ],
        betas=["files-api-2025-04-14"],
    )
    return response.content[0].text

5.5 删除文件

client.beta.files.delete(file_id)
print(f"已删除: {file_id}")

删除是立即生效的,之后引用该 file_id 会返回 404 错误。

六、与 Batch API 联动:批量处理的最优解

Files API 和 Batch API 组合是处理大规模文档的利器。典型场景:对 500 份合同逐一做合规审查。

传统做法:500 个同步请求,每个都内嵌 PDF,网络稳定性是噩梦。

Files API + Batch 做法

import json

def build_batch_requests(client, pdf_paths: list[str], question: str) -> list[dict]:
    requests = []
    for i, path in enumerate(pdf_paths):
        file_id = upload_file(client, path)
        requests.append({
            "custom_id": f"contract-{i}",
            "params": {
                "model": "claude-haiku-4-5-20251001",
                "max_tokens": 1024,
                "messages": [
                    {
                        "role": "user",
                        "content": [
                            {
                                "type": "document",
                                "source": {"type": "file", "file_id": file_id},
                            },
                            {"type": "text", "text": question},
                        ],
                    }
                ],
            },
        })
    return requests

# 提交 batch
requests = build_batch_requests(client, pdf_paths, "请列出合同中的主要违约条款")
batch = client.beta.messages.batches.create(
    requests=requests,
    betas=["files-api-2025-04-14"],
)
print(f"Batch ID: {batch.id}")

Batch API 的费用是标准价的 50%,加上 Files API 避免了重复传输,合规批处理的总成本可以下降 60–70%。

七、多轮对话场景:同一文件贯穿整个会话

适合「先上传文件,然后用户不断追问」的场景,比如合同问答机器人:

def contract_qa_bot(client, file_id: str):
    history = []
    
    # 第一轮:初始化文件上下文
    history.append({
        "role": "user",
        "content": [
            {
                "type": "document",
                "source": {"type": "file", "file_id": file_id},
            },
            {"type": "text", "text": "请先概括这份合同的主要条款。"},
        ],
    })
    
    while True:
        resp = client.beta.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=2048,
            messages=history,
            betas=["files-api-2025-04-14"],
        )
        assistant_msg = resp.content[0].text
        history.append({"role": "assistant", "content": assistant_msg})
        
        print(f"Claude: {assistant_msg}\n")
        user_input = input("你: ").strip()
        if user_input.lower() in ("exit", "quit", "退出"):
            break
        
        # 后续轮次只需传文本,文件通过 file_id 已在上下文中
        history.append({"role": "user", "content": user_input})

关键设计:文件只在第一轮传入一次,后续轮次的 messages 里不需要重复引用 file_id,Claude 会在整个会话中记住文件内容。

八、错误处理与重试策略

国内网络环境下,API 调用可能因网络抖动中断。以下是推荐的重试结构:

import time
from anthropic import APIStatusError, APIConnectionError

def robust_upload(client, file_path: str, max_retries=3) -> str:
    for attempt in range(max_retries):
        try:
            return upload_file(client, file_path)
        except APIConnectionError as e:
            if attempt < max_retries - 1:
                wait = 2 ** attempt  # 2s, 4s
                print(f"连接失败,{wait}s 后重试 ({attempt+1}/{max_retries})")
                time.sleep(wait)
            else:
                raise
        except APIStatusError as e:
            if e.status_code == 413:
                raise ValueError(f"文件过大(最大 512MB): {file_path}")
            elif e.status_code == 415:
                raise ValueError(f"不支持的文件类型: {file_path}")
            raise

常见错误码:

错误码含义处理建议
400请求格式错误(缺 beta header)检查 betas 参数
404file_id 不存在或已过期重新上传
413文件超过 512MB分割文件
415不支持的 MIME 类型转换为 PDF/PNG/TXT
429速率限制指数退避重试

完整的速率限制处理可参考 LLM 速率限制处理实战

九、文件管理最佳实践

本地维护 file_id 映射表:上传后立即写入本地数据库或 JSON 文件,避免重复上传同一文件。

import json
from pathlib import Path

MAPPING_FILE = Path("file_id_cache.json")

def load_cache() -> dict:
    return json.loads(MAPPING_FILE.read_text()) if MAPPING_FILE.exists() else {}

def save_cache(cache: dict):
    MAPPING_FILE.write_text(json.dumps(cache, indent=2, ensure_ascii=False))

def get_or_upload(client, file_path: str) -> str:
    cache = load_cache()
    if file_path in cache:
        print(f"缓存命中: {cache[file_path]}")
        return cache[file_path]
    
    file_id = upload_file(client, file_path)
    cache[file_path] = file_id
    save_cache(cache)
    return file_id

主动清理过期文件:30 天期限到期前,如果文件不再使用,主动删除可以保持存储空间整洁(虽然目前不收存储费,但良好习惯有助于未来配额管理)。

十、与 PDF API 的区别

如果你用过 Claude PDF API,会有一个疑问:两者有什么区别?

  • Claude PDF API 是更早期的实现,通过 Base64 在每次请求中内联 PDF,仅支持 PDF 格式。
  • Files API 是更通用的文件管理层,支持多种格式,且文件持久化存储,适合复用场景。

对于新项目,优先选择 Files API;对于已有 PDF API 集成,可以在性能瓶颈出现时迁移。

十一、相关阅读

如果你在国内使用 Files API 遇到连接问题,YoTradeApi 提供稳定的 Anthropic 原生协议中转,支持 Files API 全部端点,无需修改业务代码。