4、上下文窗口管理:Token计算与预算、滑动窗口策略、关键信息压缩、长文本摘要与检索增强

上下文窗口,说白了就是AI的「短期记忆」。

我刚开始做Agent时,总觉得上下文越大越好。直到有一次,我的Agent在处理一个长达50页的合同审核任务时,直接「失忆」了——它忘了前面讨论过的关键条款,开始胡言乱语。嗯,从那以后,我彻底明白了:上下文窗口不是越大越好,而是要用得巧

4.1 Token计算与预算:你的「内存条」有多粗?

先搞清楚一个概念:Token。它不是字符,也不是单词。中文里,一个Token大约对应1-2个汉字。英文里,一个Token大约对应0.75个单词。

我习惯用一个简单公式来估算:

中文文本:Token数 ≈ 字符数 × 0.6
英文文本:Token数 ≈ 单词数 × 1.3
混合文本:建议直接用工具计算
我的小工具:OpenAI的tiktoken库,或者直接去各大模型官网的Token计算器。我每次写Prompt前,都会先跑一遍Token数,心里有个底。

为什么要做预算?因为Token就是钱啊!

模型 上下文窗口 输入价格(每千Token) 输出价格(每千Token)
GPT-4 Turbo 128K $0.01 $0.03
Claude 3 Opus 200K $0.015 $0.075
本地模型(如Llama 3) 8K-32K 免费(但吃显存) 免费

你看,一个128K的上下文,如果全塞满,一次对话可能就要花掉几块钱。要是你的Agent每天跑几千次……嗯,老板会找你谈话的。

我曾经踩过的坑:有一次我把整个知识库(约50万Token)直接塞进上下文,结果模型不仅回答变慢,还开始胡说八道。后来才发现,模型在长上下文下,中间部分的信息会「衰减」。这叫「迷失在中间」现象。

4.2 滑动窗口策略:让AI保持「新鲜感」

滑动窗口,说白了就是「只保留最近N条对话」。就像你刷朋友圈,只看最近几天的,太旧的就划走了。

我常用的滑动窗口策略有三种:

  1. 固定大小窗口:保留最近K轮对话,旧的直接丢弃。
  2. Token数窗口:保留最近N个Token,超出的部分从最旧开始删。
  3. 语义窗口:保留与当前问题最相关的M条历史。

举个例子,一个客服Agent的滑动窗口实现:

class SlidingWindow:
    def __init__(self, max_tokens=4000):
        self.max_tokens = max_tokens
        self.history = []
        self.current_tokens = 0
    
    def add_message(self, message, token_count):
        self.history.append((message, token_count))
        self.current_tokens += token_count
        
        # 超出预算,从最旧开始删
        while self.current_tokens > self.max_tokens:
            oldest_msg, oldest_tokens = self.history.pop(0)
            self.current_tokens -= oldest_tokens
    
    def get_context(self):
        return [msg for msg, _ in self.history]

你想想看,如果不做滑动窗口,一个对话持续100轮后,光历史记录就能吃掉几万Token。模型哪还有精力去处理你当前的问题?

我的经验:对于大多数对话场景,保留最近10-20轮对话就够了。如果是长文档分析,建议用Token数窗口,控制在上下文窗口的60%-70%,留出空间给输出。

4.3 关键信息压缩:把「废话」扔掉

压缩,不是让你删内容,而是让你提炼精华

我常用的压缩技巧:

  • 摘要压缩:让模型自己把长文本总结成几句话。
  • 结构化压缩:把段落变成列表、表格、JSON。
  • 去冗余压缩:去掉重复的、无关的、过时的信息。

举个例子,原始对话可能是这样的:

用户:你好,我想问一下我的订单什么时候发货?
客服:您好,请问您的订单号是多少?
用户:订单号是123456。
客服:好的,我查一下。您的订单目前显示已发货,预计明天到达。
用户:好的,谢谢。
客服:不客气,祝您生活愉快!

压缩后,变成这样:

{"order_id": "123456", "status": "shipped", "eta": "tomorrow"}

你看,从100多个Token压缩到不到20个Token。信息一点没少,但体积缩小了5倍。

一个小技巧:我习惯在Agent里加一个「压缩器」模块。每次存入历史前,先让模型自己判断:「这段信息对后续对话还有用吗?」如果没用,直接丢弃。如果有用,压缩成结构化格式。

4.4 长文本摘要与检索增强:让AI「翻书」而不是「背书」

长文本处理,是上下文窗口管理的终极挑战。

你想想看,如果让AI直接读一本500页的书,它肯定记不住。怎么办?两个思路:

  1. 先摘要,再处理:把长文本切成块,每块生成摘要,然后把这些摘要拼起来。
  2. 检索增强(RAG):不把全文塞进上下文,而是让AI自己去「翻书」找答案。

RAG的流程,我用一张SVG图来说明:

RAG(检索增强生成)核心流程 用户查询 嵌入模型 向量数据库 检索结果 上下文组装 大语言模型 最终回答 文档分块 向量化存储 索引构建

你看,RAG的核心思想就是:不把所有信息塞进上下文,而是让AI学会「查资料」

我做过一个项目,需要处理1000份技术文档。如果全塞进上下文,一次对话就要花掉几十块钱。用了RAG后,每次只检索最相关的3-5段,成本降到了原来的1/10,而且回答质量反而更高了。

关键点:RAG不是万能的。如果问题需要全局理解(比如「总结整本书的核心思想」),还是得用摘要法。我一般这样选:
  • 需要精确查找某个事实 → RAG
  • 需要整体理解 → 先摘要,再分析
  • 需要多步推理 → 混合使用:先RAG找证据,再摘要整合

4.5 实战:一个完整的上下文管理方案

说了这么多,来一个我实际用过的方案:

class ContextManager:
    def __init__(self, model_max_tokens=128000):
        self.model_max = model_max_tokens
        self.safety_margin = 0.8  # 留20%给输出
        self.max_input = int(self.model_max * self.safety_margin)
        
        # 三个缓冲区
        self.system_prompt = ""  # 系统提示(固定)
        self.short_term = []     # 短期记忆(滑动窗口)
        self.long_term = []      # 长期记忆(压缩后)
    
    def add_to_context(self, message, token_count):
        # 1. 先尝试加入短期记忆
        self.short_term.append((message, token_count))
        
        # 2. 检查总Token数
        total = self._count_total_tokens()
        if total > self.max_input:
            # 3. 超出预算,压缩短期记忆
            self._compress_short_term()
    
    def _compress_short_term(self):
        # 把最旧的一半对话压缩成摘要
        old_half = self.short_term[:len(self.short_term)//2]
        summary = self._summarize(old_half)
        
        # 存入长期记忆
        self.long_term.append(summary)
        
        # 删除旧对话
        self.short_term = self.short_term[len(self.short_term)//2:]
    
    def get_context(self):
        # 组装最终上下文
        context = [self.system_prompt]
        context.extend(self.long_term)  # 长期记忆(压缩后)
        context.extend(self.short_term)  # 短期记忆(原始)
        return context
我的习惯:每次调用模型前,都打印一下当前Token使用情况。这样能及时发现「内存泄漏」——有时候Agent会不知不觉把大量无用信息塞进上下文。

嗯,上下文窗口管理,说白了就是在「记住所有」和「记住关键」之间找平衡。你想想看,人类开会时,不也是记笔记、划重点、扔废纸吗?AI也一样。

最后送你一句话:别让AI的「记忆」成为它的「负担」。管理好上下文,你的Agent才能跑得又快又准。