Claude 返回 Unable to process,这个错误提示看起来像是服务端不稳定,但实际排查中它更多指向两个明确的原因:单次请求的 token 数量超过模型的上下文窗口,或者上传的附件体积、格式超出入口限制。错误本身不区分这两种情况,需要结合请求特征来判断。理解这两个边界,并针对性地削减请求负载,才能稳定完成长文档分析、多轮对话和批量处理任务。

一、错误背后的两个限制:上下文长度与文件大小
上下文长度限制通常以 token 为单位。Claude 模型在接收请求时,会把系统提示词、历史消息、用户输入以及模型即将生成的输出全部计入上下文窗口。如果已经累积的消息接近窗口上限,模型就没有空间生成回复,接口会直接返回错误。不同模型的窗口大小并不完全相同,常见的 Claude 系列模型多为 200K tokens,部分长上下文测试接口可以支持 1M tokens,但可用性取决于账号和模型版本。
文件大小限制则更多出现在网页版或客户端上传附件时。PDF、Word、图片、代码压缩包等文件会经过解析后再进入上下文,如果原始文件体积过大,或者解析后产生的文本量过多,就可能在解析阶段失败。这里要注意,文件大小和解析后的 token 数量是两个概念,一个 20MB 的扫描版 PDF 可能只包含很少的文字,但图片数据仍然会占用上传带宽和解析时间;一个 1MB 的纯文本文件可能解压出几十万 token,足以撑爆上下文。因此排查时必须同时看文件体积和解析后的文本规模。
判断是哪种限制导致的错误,可以先用简化后的请求做对照测试。把历史消息清空,只发送一句“你好”,如果能够正常回复,说明服务本身没有故障;再把出错的文档按段落截取一半重新请求,如果请求成功,大概率是上下文长度问题;如果同一文件在新建会话中依然失败,就优先检查文件大小和格式。
二、先处理上下文长度:估算 token 与截断历史消息
在无法直接查看模型返回的 token 用量时,可以用一个保守的估算公式。英文文本大约每 4 个字符对应 1 个 token,中文文本因为字符密度更高,通常 1 个汉字对应 1 到 2 个 token。下面这段代码把中文和其他字符分开计算,得到一个近似值,足以用来判断是否接近上限。
def estimate_tokens(text: str) -> int:
# 中文按每字约 1.2 个 token 估算,英文按每 4 个字符约 1 个 token 估算
chinese_chars = sum(1 for ch in text if '\u4e00' <= ch <= '\u9fff')
other_chars = len(text) - chinese_chars
return int(chinese_chars * 1.2 + other_chars / 4)
def within_limit(text: str, limit: int = 180000) -> bool:
return estimate_tokens(text) < limit
多轮对话是最容易累积 token 的场景。用户可能连续粘贴多段文档,再加上助手之前的回复,几十轮之后输入内容就非常庞大。处理这个问题的关键是只保留最近的一部分消息,旧消息要么直接丢弃,要么压缩成摘要。下面的 trim_history 函数从消息列表末尾向前遍历,尽量保留最新的消息,一旦累计 token 超过阈值就停止。
def trim_history(messages, max_tokens: int = 100000) -> list:
total = 0
kept = []
for msg in reversed(messages):
msg_tokens = estimate_tokens(msg.get("content", ""))
if total + msg_tokens > max_tokens:
break
kept.insert(0, msg)
total += msg_tokens
return kept
如果旧消息中还有必须保留的信息,例如用户前面提出的约束条件或关键结论,直接丢弃会影响回答质量。这时可以先把旧消息交给 Claude 生成一段简短摘要,再把摘要作为新的上下文头部,后面拼接最近几条完整消息。这样既保留了上下文主线,又大幅降低了 token 数量。摘要的长度控制在 300 到 500 个 token 左右通常足够。
def summarize_old_messages(messages, keep_recent: int = 6) -> list:
old = messages[:-keep_recent]
recent = messages[-keep_recent:]
old_text = "\n".join(msg.get("content", "") for msg in old)
# 下面 summary 需要调用 Claude 生成,具体 client 代码省略
summary = call_claude_summary(old_text, max_tokens=500)
return [{"role": "assistant", "content": "历史摘要:" + summary}] + recent
估算公式只能作为参考,真实 token 数量还会受到特殊字符、代码片段和 Markdown 结构的影响。如果使用 API,响应对象中通常会返回 input_tokens 和 output_tokens,应该优先使用这些精确数据来做截断判断。网页版则可以在用量提示或控制台里查看当前会话的 token 消耗。
三、处理文件大小限制:提取文本、压缩图片与分块上传
对于 PDF 和 Office 文档,最直接的办法是提取纯文本后再提交。很多 PDF 文件体积大是因为嵌入了图片、字体和排版信息,而 Claude 真正需要处理的通常是文字内容。下面这段代码使用 pypdf 读取 PDF,只提取前若干页的文本,避免一次性解析所有页面。
from pypdf import PdfReader
def extract_pdf_text(path: str, max_pages: int = 50) -> str:
reader = PdfReader(path)
text_parts = []
for i, page in enumerate(reader.pages):
if i >= max_pages:
break
text_parts.append(page.extract_text() or "")
return "\n".join(text_parts)
扫描版 PDF 或者截图类图片需要先做 OCR。图片分辨率过高会增加处理时间,把图片缩放后再识别通常不会明显降低文字准确率,却能显著减少数据量。下面的示例用 Pillow 和 Tesseract 将图片转成文本,适合发票、合同扫描件等场景。
from PIL import Image
import pytesseract
def image_to_text(image_path: str) -> str:
img = Image.open(image_path).convert("L")
# 缩小到原尺寸一半,降低识别压力
img = img.resize((img.width // 2, img.height // 2))
return pytesseract.image_to_string(img, lang="chi_sim+eng")
如果提取后的文本仍然超过上下文窗口,就需要把文本分块发送。分块时尽量按段落或章节边界切分,而不是机械地按字符数切,因为后者可能把一段完整逻辑拆到两个请求里。下面这个函数按行累加 token,超过阈值就另起一块,适合处理长报告和长文档。
def split_text(text: str, chunk_tokens: int = 8000) -> list:
chunks = []
current = ""
for line in text.splitlines(keepends=True):
if estimate_tokens(current + line) > chunk_tokens:
chunks.append(current)
current = line
else:
current += line
if current:
chunks.append(current)
return chunks
分块之后可以逐块发送给 Claude 进行分析,再把每块的分析结果汇总。对于需要整体理解的文本,例如合同条款或小说情节,建议先对所有块生成摘要,再基于摘要做全局判断,否则模型只看片段可能会丢失上下文关联。压缩图片、提取文字、分块处理这三步组合使用,能够覆盖大多数因文件大小导致的请求失败。
四、降低后续失败概率的请求设计建议
除了出问题时再处理,更稳妥的方式是在设计请求时就给 token 和附件做预算。把 Claude 的上下文窗口预留出 15% 到 20% 给模型输出,不要把输入塞得刚好到上限。例如模型窗口是 200K tokens,输入内容最好控制在 160K 到 170K 以内。系统提示词中也应删除重复说明和无效示例,这些内容每次请求都会重新占用 token。
使用 API 时可以利用异常重试机制,在请求失败后自动缩短消息列表并重新提交。下面这段代码在捕获到 BadRequestError 后判断错误信息是否与上下文长度有关,如果确实超出限制,就调用 trim_history 精简历史消息后重试。
import anthropic
client = anthropic.Anthropic()
def call_claude_with_retry(messages, max_retries: int = 3):
model = "claude-sonnet" # 请替换为当前可用的 Claude 模型 ID
for attempt in range(max_retries):
try:
resp = client.messages.create(
model=model,
max_tokens=4096,
messages=messages,
)
return resp.content[0].text
except anthropic.BadRequestError as e:
err_text = str(e)
if "prompt is too long" in err_text or "Unable to process" in err_text:
messages = trim_history(messages, max_tokens=100000)
continue
raise
return ""
如果任务需要读取多个大文件,不要一次全部上传。可以先把文件清单和结构发给模型,让它判断优先分析哪些部分,再按优先级分批提交。对于网页版用户,建议新建会话来处理不同主题的文档,避免历史消息和附件不断累积。对于固定团队内部的重复任务,可以维护一个精简后的知识库或索引,每次只把相关片段注入上下文,而不是每次重新读取完整文档。
这些方法的核心思路是一致的:把上下文窗口和上传通道当成有限资源来管理。只要持续监控 token 消耗、压缩文件体积、控制历史消息长度,并预留输出空间,就能显著降低 Claude 返回 Unable to process 的概率,长文档处理也会更加顺畅。
Claude Unable to process上下文长度文件大小限制修改时间:2026-09-28 13:31:19