上下文管理指南

掌握上下文窗口管理技巧,优化Token使用,提升大模型对话质量

Token优化性能提升成本控制

理解上下文窗口

什么是上下文窗口?

上下文窗口是大模型一次能处理的最大Token数量,包括输入和输出的总和。

上下文窗口 = 输入Token + 输出Token
输入
输出

主流模型上下文限制

GPT-3.5-Turbo4,096 tokens
GPT-3.5-16k16,384 tokens
GPT-48,192 tokens
GPT-4-32k32,768 tokens
Claude-2100,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计算方式可能不同
  • • 保留必要的上下文对话质量很重要
  • • 考虑用户体验,避免突然的上下文切换