上下文管理指南
掌握上下文窗口管理技巧,优化Token使用,提升大模型对话质量
Token优化性能提升成本控制
理解上下文窗口
什么是上下文窗口?
上下文窗口是大模型一次能处理的最大Token数量,包括输入和输出的总和。
上下文窗口 = 输入Token + 输出Token
输入
输出
主流模型上下文限制
| GPT-3.5-Turbo | 4,096 tokens |
| GPT-3.5-16k | 16,384 tokens |
| GPT-4 | 8,192 tokens |
| GPT-4-32k | 32,768 tokens |
| Claude-2 | 100,000 tokens |
Token估算参考
1 Token ≈0.75个英文单词
1 Token ≈0.5个中文字符
1000字中文 ≈2000 tokens
1页A4文档 ≈500-800 tokens
上下文管理策略
1. 滑动窗口策略
只保留最近N轮对话,自动丢弃旧的对话历史。
class ConversationManager {
constructor(maxRounds = 5) {
this.maxRounds = maxRounds;
this.messages = [];
}
addMessage(message) {
this.messages.push(message);
// 保留系统消息 + 最近N轮对话
const systemMsg = this.messages.filter(m => m.role === 'system');
const conversation = this.messages.filter(m => m.role !== 'system');
// 每轮包含用户消息和助手回复
const recentRounds = conversation.slice(-this.maxRounds * 2);
this.messages = [...systemMsg, ...recentRounds];
}
getContext() {
return this.messages;
}
}2. 摘要压缩策略
将历史对话压缩成摘要,保留关键信息。
async function compressHistory(messages) {
// 当历史消息超过阈值时压缩
if (calculateTokens(messages) > 2000) {
const historyText = messages
.slice(0, -4) // 保留最近2轮
.map(m => `${m.role}: ${m.content}`)
.join('\n');
// 使用AI生成摘要
const summary = await generateSummary(historyText);
// 返回压缩后的上下文
return [
{ role: 'system', content: `历史对话摘要: ${summary}` },
...messages.slice(-4) // 最近2轮详细对话
];
}
return messages;
}优势:可以保留更长的对话历史,同时控制Token使用。
3. 主题分割策略
识别对话主题变化,只保留当前主题相关的上下文。
class TopicAwareContext {
constructor() {
this.currentTopic = null;
this.topicHistory = new Map();
}
async detectTopicChange(newMessage) {
// 使用嵌入向量检测主题变化
const embedding = await getEmbedding(newMessage);
const similarity = this.currentTopic
? cosineSimilarity(embedding, this.currentTopic.embedding)
: 0;
if (similarity < 0.7) {
// 主题变化,创建新的上下文
this.currentTopic = {
id: generateId(),
embedding: embedding,
messages: []
};
return true;
}
return false;
}
addMessage(message) {
if (this.currentTopic) {
this.currentTopic.messages.push(message);
// 限制单个主题的消息数
if (this.currentTopic.messages.length > 10) {
this.currentTopic.messages =
this.currentTopic.messages.slice(-10);
}
}
}
}长文本处理技巧
文本分块处理
智能分块算法
function smartChunking(text, maxTokens = 2000) {
const chunks = [];
const sentences = text.split(/[。!?.!?]+/);
let currentChunk = '';
let currentTokens = 0;
for (const sentence of sentences) {
const sentenceTokens = estimateTokens(sentence);
if (currentTokens + sentenceTokens > maxTokens) {
// 当前块已满,保存并开始新块
if (currentChunk) {
chunks.push({
content: currentChunk,
tokens: currentTokens,
overlap: chunks.length > 0 ? 100 : 0 // 重叠Token
});
}
// 添加上文重叠
const previousEnd = currentChunk.slice(-200);
currentChunk = previousEnd + sentence;
currentTokens = estimateTokens(currentChunk);
} else {
currentChunk += sentence + '。';
currentTokens += sentenceTokens;
}
}
// 添加最后一块
if (currentChunk) {
chunks.push({
content: currentChunk,
tokens: currentTokens
});
}
return chunks;
}
// 并行处理多个块
async function processLongText(text) {
const chunks = smartChunking(text);
// 并行处理所有块
const results = await Promise.all(
chunks.map(chunk =>
processChunk(chunk.content)
)
);
// 合并结果
return mergeResults(results);
}重叠窗口技术
在分块之间保留重叠部分,确保上下文连续性:
块1
重叠
块2
重叠
块3
优化技巧
Token计数优化
- • 预先计算Token数量
- • 使用tiktoken库精确计算
- • 缓存计算结果
- • 设置Token预算
智能裁剪
- • 移除冗余信息
- • 压缩重复内容
- • 简化系统提示
- • 动态调整详细程度
外部存储
- • 使用向量数据库
- • 实施RAG架构
- • 按需加载上下文
- • 知识库检索
动态压缩
- • 根据重要性排序
- • 保留关键信息
- • 自适应压缩率
- • 渐进式摘要
完整实践示例
import { encode } from 'tiktoken';
class AdvancedContextManager {
constructor(options = {}) {
this.maxTokens = options.maxTokens || 4000;
this.maxOutputTokens = options.maxOutputTokens || 1000;
this.compressionThreshold = options.compressionThreshold || 0.7;
this.messages = [];
this.summaries = [];
}
// 精确计算Token数
countTokens(messages) {
const encoding = encode(JSON.stringify(messages));
return encoding.length;
}
// 添加消息并自动管理上下文
async addMessage(message) {
this.messages.push(message);
const currentTokens = this.countTokens(this.messages);
const availableTokens = this.maxTokens - this.maxOutputTokens;
if (currentTokens > availableTokens * this.compressionThreshold) {
await this.compressContext();
}
}
// 压缩上下文
async compressContext() {
// 分离系统消息和对话
const systemMessages = this.messages.filter(m => m.role === 'system');
const conversation = this.messages.filter(m => m.role !== 'system');
// 压缩策略选择
if (conversation.length > 10) {
// 策略1: 生成摘要
const oldMessages = conversation.slice(0, -6);
const summary = await this.generateSummary(oldMessages);
this.summaries.push({
timestamp: Date.now(),
summary: summary,
messageCount: oldMessages.length
});
// 重构消息列表
this.messages = [
...systemMessages,
{
role: 'system',
content: `Previous conversation summary: ${summary}`
},
...conversation.slice(-6)
];
} else {
// 策略2: 简单截断
this.messages = [
...systemMessages,
...conversation.slice(-6)
];
}
}
// 生成摘要
async generateSummary(messages) {
const prompt = `Summarize the following conversation in 100 words:
${messages.map(m => `${m.role}: ${m.content}`).join('\n')}`;
// 调用AI生成摘要
const response = await callAPI({
messages: [{ role: 'user', content: prompt }],
max_tokens: 200
});
return response.content;
}
// 获取优化后的上下文
getOptimizedContext() {
const tokens = this.countTokens(this.messages);
const budget = this.maxTokens - this.maxOutputTokens;
if (tokens <= budget) {
return this.messages;
}
// 需要进一步裁剪
return this.trimToFit(this.messages, budget);
}
// 裁剪到指定大小
trimToFit(messages, targetTokens) {
let trimmed = [...messages];
// 优先级: system > recent > old
while (this.countTokens(trimmed) > targetTokens && trimmed.length > 2) {
// 移除最老的非系统消息
const nonSystemIndex = trimmed.findIndex(m => m.role !== 'system');
if (nonSystemIndex > -1 && nonSystemIndex < trimmed.length - 2) {
trimmed.splice(nonSystemIndex, 1);
} else {
break;
}
}
return trimmed;
}
}
// 使用示例
const contextManager = new AdvancedContextManager({
maxTokens: 4000,
maxOutputTokens: 1000,
compressionThreshold: 0.7
});
// 处理对话
async function handleConversation(userInput) {
await contextManager.addMessage({ role: 'user', content: userInput });
const optimizedContext = contextManager.getOptimizedContext();
const response = await callAPI({
messages: optimizedContext,
max_tokens: contextManager.maxOutputTokens
});
await contextManager.addMessage(response.message);
return response.content;
}注意事项
- • 过度压缩可能丢失重要信息
- • Token计算会消耗一定性能
- • 不同模型的Token计算方式可能不同
- • 保留必要的上下文对话质量很重要
- • 考虑用户体验,避免突然的上下文切换