Token 与上下文窗口
Token 是 LLM 的计费单位,上下文窗口是能力边界。理解这两个概念是成本控制和架构设计的基础。
Token 基础
什么算一个 Token?
| 内容 | 约等于 Token 数 |
|---|
| 1 个英文字符 | 0.25 |
| 1 个中文字符 | 1-2 |
| 1 个英文单词 | 1.5 |
| 1 个代码 Token | ~4 字符 |
| 一个中文字(中文) | 1-2 |
粗略估算:中文 1 Token ≈ 1 个汉字;英文 1 Token ≈ 0.75 个单词。
Token 计数的实际影响
1 2 3 4 5 6 7 8
| GPT-4o 定价(2025年参考): - 输入:$2.5 / 1M Token - 输出:$10 / 1M Token
实际例子: 一篇 2000 字的中文文章 ≈ 2000 Token 输入 一次回复 500 字 ≈ 500 Token 输出 每次 API 调用成本 ≈ $2.5/1M × 2500 ≈ $0.00625 ≈ 0.6分钱
|
代码 Token 效率
代码重复率高,同样的 Token 数能容纳更多代码:
1 2
| Python 代码:1 Token ≈ 4 字符(高度重复,压缩率高) 自然语言:1 Token ≈ 0.75 词
|
上下文窗口(Context Window)
什么是上下文窗口?
上下文窗口 = 输入 + 输出能容纳的最大 Token 数(不含模型参数)。
| 模型 | 上下文窗口 | 说明 |
|---|
| GPT-4o | 128K | 最大众 |
| GPT-4o-mini | 128K | 性价比 |
| Claude 3.5 Sonnet | 200K | 最大之一 |
| Claude 3 Opus | 200K | 旗舰 |
| Claude 3 Haiku | 200K | 便宜 |
| Llama 3.1 8B | 128K | 开源 |
| Qwen2.5-7B | 32K(可扩展) | 国产 |
| DeepSeek-V3 | 64K | 国产 |
上下文耗尽时会发生什么?
1 2 3 4 5 6 7 8 9
| 问题:上下文窗口满了 LLM 会怎么做?
答案:取决于具体实现
1. 截断(Truncation,最常见)
2. 滑动窗口
3. 主动摘要(部分系统支持)
|
上下文管理策略
策略 1:简单截断
1 2 3 4 5 6 7 8 9 10
| messages = [] MAX_TOKENS = 16000
def add_message(messages, role, content): messages.append({"role": role, "content": content}) while count_tokens(messages) > MAX_TOKENS: messages.pop(0) return messages
|
策略 2:摘要压缩(Summarize)
1 2 3 4 5
| def compress_history(messages): summary_prompt = "将以下对话压缩为50字摘要:\n" + str(messages) summary = llm.invoke(summary_prompt) return [{"role": "system", "content": f"对话摘要:{summary}"}]
|
策略 3:选择性保留(Semantic)
1 2 3 4 5 6 7 8 9 10
| def filter_relevant_history(messages, current_query): query_emb = embedding.embed(current_query) scored = [] for msg in messages: msg_emb = embedding.embed(msg["content"]) score = cosine_similarity(query_emb, msg_emb) scored.append((score, msg)) return [msg for score, msg in scored if score > 0.7]
|
Token 计数工具
1 2 3 4 5 6 7 8 9 10 11
| import tiktoken
enc = tiktoken.get_encoding("cl100k_base") tokens = enc.encode("你好,世界") print(len(tokens))
prompt_tokens = len(tokens) cost = prompt_tokens / 1_000_000 * 2.5 print(f"成本: ${cost:.4f}")
|
1 2 3 4
| def count_chinese_tokens(text: str) -> int: """中文字符粗略估算""" return len(text) * 1.5
|
生产环境 Token 管理
分级降级策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| def answer_with_budget(question: str, budget: float): """ 根据预算自动选择方案 budget: 允许的最大成本(美元) """ estimated_tokens = estimate_tokens(question)
if budget < 0.001: return vector_db.similarity_search(question)
if budget < 0.01: return llm_mini.invoke(question)
if budget < 0.1: return rag_pipeline(question)
return claude_long_context(question)
|
上下文窗口的架构影响
| 问题 | 影响 | 解决方案 |
|---|
| 对话越来越长,成本增加 | 每次调用都带入全部历史 | 定期摘要 / 滑动窗口 |
| 长文档 RAG 超限 | 无法同时处理全文 | 分块检索 + 二次排序 |
| Agent 记忆过长 | 关键信息被稀释 | 重要记忆存入外部存储 |
最佳实践
- 对话系统:设置 Token 上限,用摘要或截断管理
- 长文档 RAG:先分块,检索 Top-K 后再让 LLM 读
- 代码生成:用代码专用模型(如 Cursor 用 GPT-4o-mini),Token 成本更低
- 成本控制:API 调用前先估算 Token 数