共计 3017 个字符,预计需要花费 8 分钟才能阅读完成。
Token 在 LLM 中的核心作用
Token 是大语言模型处理文本的基本单位。与传统的字符或单词计数不同,Token 化过程会将文本拆分为模型可理解的子词片段。例如英文单词 ”unhappiness” 可能被拆分为 ”un”, “happi”, “ness” 三个 Token,而中文通常以字或词为单位进行 Token 化。

不同模型的 Token 计算方式存在显著差异:
- GPT 系列:使用 BPE(Byte Pair Encoding)算法,英文平均 1 个 Token≈0.75 单词
- Claude 系列:采用更高效的 Token 化方案,相同文本通常比 GPT 少用 15-20% 的 Token
- 多语言模型:非拉丁语系文字(如中文)通常需要更多 Token 表示
Claude Pro 的 Token 限制机制
Claude Pro 对单次请求设置了严格的 Token 上限(当前为 100K Tokens),这直接影响:
- 对话历史长度:累计 Token 数超过限制会导致最早的消息被自动截断
- API 调用成本:计费基于输入 + 输出的总 Token 数,长文本处理成本呈指数增长
- 响应质量:关键上下文被截断可能导致回答偏离预期
Token 优化实战方案
精准计数工具
使用官方 anthropic 库的 count_tokens 方法,这里给出增强版的计数工具类:
from anthropic import Anthropic, HUMAN_PROMPT, AI_PROMPT
class TokenOptimizer:
def __init__(self, api_key):
self.client = Anthropic(api_key=api_key)
def count_tokens(self, text):
"""实时计算文本 Token 数,支持包含对话标记"""
return self.client.count_tokens(f"{HUMAN_PROMPT} {text} {AI_PROMPT}"
)
def estimate_cost(self, input_txt, output_tokens=500):
"""预测 API 调用成本(基于 2023.12 定价)"""
input_tokens = self.count_tokens(input_txt)
return (input_tokens + output_tokens) * 0.00002 # $0.02/1K tokens
对话历史压缩算法
实现基于重要性的对话记忆管理:
def compress_history(messages, max_tokens=80000):
"""
优化对话历史的核心算法:1. 保留最近的系统指令
2. 按时间衰减系数加权关键信息
3. 去除重复内容
"""
compressed = []
token_count = 0
# 逆序处理以优先保留最新消息
for msg in reversed(messages):
current_tokens = TokenOptimizer.count_tokens(msg["content"])
if token_count + current_tokens > max_tokens:
# 实施内容摘要处理
summarized = summarize_content(msg["content"])
summarized_tokens = TokenOptimizer.count_tokens(summarized)
if token_count + summarized_tokens <= max_tokens:
compressed.append({"role": msg["role"], "content": summarized})
token_count += summarized_tokens
break
compressed.append(msg)
token_count += current_tokens
return list(reversed(compressed))
长文本分块处理策略
对于超长文档(如 PDF、网页),建议采用以下处理流程:
- 预处理阶段
- 移除 HTML/PDF 格式标签
-
标准化换行符和空格
-
语义分块原则
- 按段落 / 章节自然分割
- 每块保持 200-500 个 Token
-
保留上下文关联的标题
-
分块实现代码
import re
from typing import List
def semantic_chunking(text: str,
max_chunk_size: int = 500) -> List[str]:
"""基于语义的智能分块算法"""
# 第一阶段:按自然段落分割
paragraphs = re.split(r'\n\s*\n', text.strip())
chunks = []
current_chunk = ""
for para in paragraphs:
para_tokens = TokenOptimizer.count_tokens(para)
if para_tokens > max_chunk_size:
# 对超大段落进行句子级拆分
sentences = re.split(r'(?<=[.!?])\s+', para)
for sent in sentences:
sent_tokens = TokenOptimizer.count_tokens(sent)
if TokenOptimizer.count_tokens(current_chunk) + sent_tokens > max_chunk_size:
chunks.append(current_chunk.strip())
current_chunk = sent
else:
current_chunk += " " + sent
elif TokenOptimizer.count_tokens(current_chunk) + para_tokens > max_chunk_size:
chunks.append(current_chunk.strip())
current_chunk = para
else:
current_chunk += "\n\n" + para
if current_chunk:
chunks.append(current_chunk.strip())
return chunks
性能优化对照表
| 优化策略 | Token 节省率 | 延迟影响 | 实现复杂度 |
|---|---|---|---|
| 基础计数监控 | 5-10% | 无 | 低 |
| 对话历史压缩 | 30-50% | +5-15ms | 中 |
| 语义分块 | 20-40% | 无 | 高 |
| 预处理净化 | 1-3% | 无 | 低 |
常见误区与解决方案
- 误区:认为 Token 与单词 1:1 对应
- 现象:英文复合词、中文长句的 Token 消耗被低估
-
方案:始终使用 API 计数工具验证
-
误区:忽视系统提示词的 Token 占用
- 现象:
HUMAN_PROMPT等标记占用固定 Token -
方案:将系统消息计入总预算
-
误区:过度截断导致上下文丢失
- 现象:关键信息被意外移除
-
方案:实施重要性加权保留机制
-
误区:并行请求导致配额耗尽
- 现象:突发流量触发速率限制
-
方案:实现 Token 预算的分布式计数
-
误区:缓存未考虑 Token 差异
- 现象:相同内容在不同模型 Token 数不同
- 方案:建立模型专属的缓存键
动手实践建议
- 使用
TokenOptimizer类分析你最近 10 次 API 调用的 Token 分布 - 对历史对话日志实施
compress_history压缩,比较效果差异 - 用
sematic_chunking处理一个技术文档,观察分块质量 - 根据性能对照表,制定适合你业务场景的优化组合方案
通过结合精准计数、智能压缩和语义分块三大策略,开发者可平均降低 30-60% 的 Token 消耗。建议每月审计 Token 使用模式,持续优化提示工程和上下文管理策略。
正文完
发表至: 未分类
近三天内
