【Claude】Prompt too long 错误:上下文 Token 超出上限的截断与压缩 bug报错已解决
·
【Claude】Prompt too long 错误:上下文 Token 超出上限的截断与压缩 bug报错已解决
关键词: Claude Code、Prompt too long、上下文窗口、Token 超限、context window exceeded、截断、压缩、Token 计算、消息长度、max_tokens、输入长度、模型限制
一、问题描述:当上下文"塞满"了
"Prompt too long" 是 Claude API 最直接的输入长度错误之一。当请求中的消息内容(包括当前消息和历史对话)的总 Token 数超过模型支持的最大上下文窗口时,API 会直接拒绝处理并返回此错误。与 "Error during compaction"(系统尝试压缩但失败)不同,"Prompt too long" 意味着在压缩之前,请求就已经超过了硬性限制——系统甚至不会尝试压缩,直接拒绝。
1.1 典型报错场景与错误信息
场景一:单次消息超长
import anthropic
client = anthropic.Anthropic(api_key="your-key")
long_text = "A" * 500000 # 50 万字符
response = client.messages.create(
model="claude-sonnet-4-20250514",
messages=[{"role": "user", "content": long_text}]
)
# 错误:prompt is too long: 200000 tokens > 200000 limit
场景二:累积历史超限
# 经过多轮对话后,历史消息累积超过 200K tokens
messages = [...] # 包含大量历史对话
response = client.messages.create(
model="claude-sonnet-4-20250514",
messages=messages + [{"role": "user", "content": "new message"}]
)
# 错误:prompt is too long
场景三:图片 Base64 导致超长
import base64
with open("large_image.png", "rb") as f:
image_data = base64.b64encode(f.read()).decode()
response = client.messages.create(
model="claude-sonnet-4-20250514",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "分析图片"},
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": image_data}}
]
}]
)
# 错误:prompt is too long(base64 编码非常长)

二、根因分析:Token 限制与超限原因
2.1 Token 限制的硬性边界
| 模型 | 最大上下文 | 描述 |
|---|---|---|
| Claude 4 Sonnet | 200,000 tokens | 输入 + 输出总和 |
| Claude 4 Opus | 200,000 tokens | 同上 |
| Claude 3 Haiku | 200,000 tokens | 同上 |
关键公式:
总 Token 数 = 系统提示 + 历史消息 + 当前消息 + max_tokens(输出预留)
必须满足:总 Token 数 <= 200,000
2.2 常见超限原因
| 原因 | 描述 | 占比 |
|---|---|---|
| 大量历史对话 | 多轮对话累积 | 40% |
| 长文本粘贴 | 粘贴整本书/长文档 | 30% |
| 代码文件过多 | 粘贴多个代码文件 | 20% |
| 图片 Base64 | 图片编码非常长 | 10% |
三、实际操练:截断与压缩策略
3.1 策略一:精确计算 Token 数
#!/usr/bin/env python3
# token_calculation.py
import tiktoken
def estimate_tokens(text):
"""估算 Token 数"""
enc = tiktoken.get_encoding("cl100k_base")
return len(enc.encode(text))
def check_message_length(messages, max_tokens=200000, output_reserve=4096):
"""
检查消息是否超过限制
"""
total = 0
for msg in messages:
content = msg.get("content", "")
if isinstance(content, list):
for item in content:
if item.get("type") == "text":
total += estimate_tokens(item.get("text", ""))
elif item.get("type") == "image":
data = item.get("source", {}).get("data", "")
total += int(len(data) * 0.75)
else:
total += estimate_tokens(str(content))
total += 4 # 消息格式开销
available = max_tokens - total - output_reserve
return {
"total_input": total,
"available_output": available,
"is_over_limit": available < 0,
"usage_percent": (total / max_tokens) * 100
}
# 使用
messages = [{"role": "user", "content": "Hello " * 10000}]
result = check_message_length(messages)
print(f"Token usage: {result['usage_percent']:.1f}%")
print(f"Over limit: {result['is_over_limit']}")
3.2 策略二:截断历史对话
def truncate_messages(messages, max_tokens=180000):
"""
截断消息列表,保留最新的消息
"""
enc = tiktoken.get_encoding("cl100k_base")
total = 0
truncated = []
# 从最新消息开始倒序处理
for msg in reversed(messages):
tokens = estimate_tokens(str(msg.get("content", ""))) + 4
if total + tokens > max_tokens:
break
total += tokens
truncated.insert(0, msg)
return truncated
# 使用:保留最新的 180K tokens
messages = truncate_messages(long_messages, max_tokens=180000)
3.3 策略三:摘要压缩历史
#!/usr/bin/env python3
# conversation_summarizer.py
import anthropic
client = anthropic.Anthropic(api_key="your-key")
def summarize_conversation(messages, max_summary_tokens=5000):
"""
将长对话压缩为摘要
"""
# 将对话转为文本
conversation_text = "\n\n".join([
f"{msg['role']}: {msg['content']}"
for msg in messages
])
# 让 Claude 生成摘要
summary_response = client.messages.create(
model="claude-haiku-3-20250307",
max_tokens=max_summary_tokens,
messages=[{
"role": "user",
"content": f"请用 2000 字以内总结以下对话的关键信息:\n\n{conversation_text[:50000]}"
}]
)
summary = summary_response.content[0].text
# 返回摘要 + 最近 2 轮对话
return [
{"role": "user", "content": f"之前的对话摘要:{summary}"},
] + messages[-4:] # 保留最近 2 轮(user + assistant)
# 使用
compressed = summarize_conversation(long_messages)
response = client.messages.create(
model="claude-sonnet-4-20250514",
messages=compressed + [{"role": "user", "content": "继续讨论"}]
)
3.4 策略四:分块处理长文本
def chunk_text(text, max_chunk_tokens=10000):
"""
将长文本分块,每块不超过指定 Token 数
"""
enc = tiktoken.get_encoding("cl100k_base")
tokens = enc.encode(text)
chunks = []
for i in range(0, len(tokens), max_chunk_tokens):
chunk_tokens = tokens[i:i + max_chunk_tokens]
chunks.append(enc.decode(chunk_tokens))
return chunks
# 使用:逐块处理
chunks = chunk_text(long_document, max_chunk_tokens=15000)
for i, chunk in enumerate(chunks):
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1000,
messages=[{
"role": "user",
"content": f"分析以下文档片段(第 {i+1}/{len(chunks)} 部分):\n\n{chunk}"
}]
)
print(f"Chunk {i+1} result: {response.content[0].text[:100]}")
3.5 策略五:压缩图片
from PIL import Image
import io, base64
def compress_image_for_claude(image_path, max_size=(800, 800), quality=80):
"""
压缩图片以减少 Token 占用
"""
with Image.open(image_path) as img:
img.thumbnail(max_size)
if img.mode in ('RGBA', 'LA'):
img = img.convert('RGB')
buffer = io.BytesIO()
img.save(buffer, format='JPEG', quality=quality)
base64_str = base64.b64encode(buffer.getvalue()).decode()
print(f"Compressed base64 length: {len(base64_str)}")
print(f"Estimated tokens: {int(len(base64_str) * 0.75)}")
return base64_str
# 使用
base64_image = compress_image_for_claude("photo.png", max_size=(600, 600))
四、验证与回归测试
#!/usr/bin/env python3
# prompt_length_test.py
import anthropic
from anthropic import BadRequestError
client = anthropic.Anthropic(api_key="your-key")
def test_length_limit():
"""测试长度限制"""
lengths = [10000, 50000, 100000, 150000, 190000, 200000]
for length in lengths:
text = "A" * length
try:
response = client.messages.create(
model="claude-haiku-3-20250307",
max_tokens=10,
messages=[{"role": "user", "content": text}]
)
print(f"✅ {length} chars: OK")
except BadRequestError as e:
if "too long" in str(e):
print(f"❌ {length} chars: TOO LONG")
else:
print(f"⚠️ {length} chars: {e}")
test_length_limit()
五、总结与最佳实践
5.1 核心要点
- 200K 是硬性限制:输入 + 输出 <= 200,000 tokens
- 预防优于截断:发送前计算 Token 数
- 压缩图片:减少图片的 base64 长度
- 分块处理:长文档分块处理
- 摘要历史:用摘要替代完整对话历史
5.2 最佳实践
| 场景 | 推荐做法 |
|---|---|
| 长文档 > 100K 字符 | 分块处理 |
| 多轮对话 > 50 轮 | 摘要历史 + 保留最近 2 轮 |
| 图片 > 1MB | 压缩到 800x800 以下 |
| 不确定长度 | 先计算 Token 数再发送 |
| 代码库分析 | 逐文件分析,而非全部粘贴 |
更多推荐





所有评论(0)