纲要上下文窗口是什么Token 的本质与计算方式上下文窗口的限制因素Transformer 注意力机制的复杂度硬件显存与响应时间训练数据的短文本倾向注意力衰减与长距离依赖应对上下文窗口限制的策略检索增强生成滑动窗口新架构探索LangChain 中的 Token 追踪usage_metadata与response_metadata流式输出中开启stream_usage实战基于滑动窗口的长文本处理与 Token 监控项目结构使用tiktoken计算 Token 数实现滑动窗口切分结合ChatOpenAI调用并记录用量代码上下文窗口的概念大模型的“上下文窗口”是指模型一次能够处理的最大 Token 数量。可以把它想象成一个固定大小的视野模型只能“看到”窗口内的内容超出窗口的部分会被忽略。这个窗口长度是人为设定的直接决定了模型能处理多长的输入和输出。不同模型的上下文窗口差异很大例如 GPT-4 有 8K、32K 甚至 128K 的版本而某些模型可能只有 4K。窗口越大模型处理长文档、多轮对话的能力越强但对计算资源的要求也越高。Token大模型的“基本语言单位”人类使用字符和单词交流但模型底层处理的并不是原始文本而是 Token。Token 是模型能够理解的最小信息单元它可以是单词的一部分、整个词、标点符号甚至是图片或音频的片段在多模态模型中。以 OpenAI 的分词方式为例英文中大约 1 个 Token 相当于 0.75 个单词或者 4 个英文字符。句子 “LangChain is cool.” 会被切分成[Lang, Chain, is, cool, .]共 5 个 Token而字符数是 18。可见 Token 的信息密度远高于原始字符。因为 Token 并非与字符一一对应所以在开发 AI Agent 时必须精确计算文本的 Token 数避免输入超出上下文窗口导致截断或响应异常。为什么上下文窗口不能无限大上下文窗口的大小受到多方面因素的制约计算复杂度当前主流的大模型均采用 Transformer 架构其核心的自注意力机制计算复杂度为O(n²)n为序列长度。序列长度翻倍计算量和显存需求会增长约四倍。这是限制窗口长度的根本原因。硬件限制GPU 显存大小直接决定了能容纳的序列长度上限。长序列需要更多显存来存储中间状态同时也会使推理延迟显著增加。训练数据分布预训练语料中长文本比例通常较低模型在学习长距离依赖关系时存在天然困难。如果窗口设得过大模型在早期信息和当前信息之间容易“遗忘”或混淆。注意力衰减随着序列增长模型对早期 Token 的关注度会逐渐下降导致生成质量变差尤其是需要引用前文的问答场景。这些因素共同决定了每个模型都必须设置一个权衡后的上下文窗口值而不是任意扩大。突破窗口限制的常见策略当实际需求超出模型上下文窗口时可以采用以下方法检索增强生成将历史对话或文档存储到外部向量数据库中每次请求时根据当前问题检索相关片段只将最相关的内容拼接进 Prompt从而“外挂”记忆。滑动窗口维护一个固定长度的 Token 窗口当新内容加入时移除窗口最左侧的部分即最早的内容。这样可以始终在有限窗口内保留最近、最相关的信息。新架构探索研究者也在尝试用状态空间模型、线性注意力等新结构来替代 Transformer以突破平方复杂度限制但目前尚在演进阶段。这些策略并非互斥在实际 Agent 开发中常常组合使用。接下来我们重点实现一种简单的滑动窗口处理方式并结合 LangChain 的 Token 追踪功能直观展示窗口管理全流程。LangChain 中的 Token 用量追踪LangChain 的大模型组件返回的AIMessage中包含标准化的usage_metadata字段可直接获取输入、输出及总 Token 数。无论底层是 OpenAI、DeepSeek 还是 Anthropic该字段都会被封装部分模型可能为空。此外某些模型如 OpenAI在流式输出时支持开启stream_usageTrue能够在每一个 chunk 中附带累计的 Token 用量方便实时监控成本。下面通过代码具体展示。项目结构本示例将实现一个简单的滑动窗口处理器能够使用tiktoken计算 Token 数将超长文本按照指定窗口大小和重叠步长切分成多个片段逐片段调用大模型并记录每个窗口的 Token 消耗。目录结构如下├── main.py # 滑动窗口处理与 Token 追踪 └── requirements.txt # 依赖列表依赖清单requirements.txtlangchain-openai0.3.0 tiktoken0.7.0完整可运行代码importosfromtypingimportList,Tupleimporttiktokenfromlangchain_openaiimportChatOpenAI# ---------- 滑动窗口切分器 ----------classSlidingWindowSplitter:将文本按 Token 数切分为滑动窗口片段def__init__(self,model_name:strgpt-4,max_tokens:int2000,overlap:int200): :param model_name: 对应 tiktoken 的编码模型名 :param max_tokens: 每个窗口的最大 Token 数 :param overlap: 相邻窗口之间的重叠 Token 数 self.encodingtiktoken.encoding_for_model(model_name)self.max_tokensmax_tokens self.overlapoverlapdeftoken_count(self,text:str)-int:returnlen(self.encoding.encode(text))defsplit(self,text:str)-List[str]:tokensself.encoding.encode(text)totallen(tokens)chunks[]start0whilestarttotal:endmin(startself.max_tokens,total)chunk_tokenstokens[start:end]chunks.append(self.encoding.decode(chunk_tokens))startend-self.overlap# 重叠部分returnchunks# ---------- Token 追踪与调用 ----------defdemo_sliding_window_processing():# 1. 初始化模型使用 GPT-4需设置 OPENAI_API_KEY 环境变量llmChatOpenAI(modelgpt-4,temperature0.3,max_tokens500,# 每次回复的最大长度api_keyos.getenv(OPENAI_API_KEY),)# 2. 模拟一篇很长的对话记录或文档long_text 在人工智能的发展历程中大语言模型的出现是一个重要的里程碑。 它使得机器能够理解和生成自然语言从而在对话系统、内容创作、代码生成等领域展现出巨大的潜力。 然而大模型并不是万能的其固有的上下文窗口限制经常导致长文档处理、多轮对话等场景中的信息丢失。 为了突破这一限制研究者们提出了多种方案包括检索增强生成、滑动窗口、以及探索全新的模型架构。 其中滑动窗口是一种简单而有效的方法它将长文本切分成固定大小的片段每个片段之间保留一定的重叠区域 使得模型可以在窗口内处理局部上下文并通过对多个窗口结果的后处理来获得全局理解。 这种技术在实际的 AI Agent 开发中被广泛采用尤其适用于问答、摘要等需要长上下文的任务。 *50# 构造一个长度超过 5000 Token 的文本splitterSlidingWindowSplitter(model_namegpt-4,max_tokens2000,overlap200)print(f原文总 Token 数:{splitter.token_count(long_text)})windowssplitter.split(long_text)print(f切分成{len(windows)}个窗口\n)# 3. 对每个窗口调用模型并追踪 Token 用量total_input_tokens0total_output_tokens0results[]fori,wininenumerate(windows):print(f--- 处理窗口{i1}(Token 数:{splitter.token_count(win)}) ---)msgllm.invoke(f请用中文总结以下文本的核心要点\n{win})# 记录用量usagemsg.usage_metadataifusage:print(f 输入 Token:{usage.get(input_tokens)}, 输出 Token:{usage.get(output_tokens)}, 总计:{usage.get(total_tokens)})total_input_tokensusage.get(input_tokens,0)total_output_tokensusage.get(output_tokens,0)results.append(msg.content)# 演示流式追踪可选只针对最后一个窗口展示ifilen(windows)-1:print( 流式追踪演示)forchunkinllm.stream(win,stream_usageTrue):# stream_usage 会将累计用量放在 chunk.usage_metadata 中ifchunk.usage_metadata:print(f 当前累计:{chunk.usage_metadata})# 这里只打印用量不打印内容print()print(f\n全部窗口总消耗 - 输入 Token:{total_input_tokens}, 输出 Token:{total_output_tokens}, 合计:{total_input_tokenstotal_output_tokens})returnresultsif__name____main__:demo_sliding_window_processing()代码说明SlidingWindowSplitter使用tiktoken将文本按 Token 数切分并可设置重叠量保证语义连贯。ChatOpenAI调用时通过msg.usage_metadata提取标准化用量对于流式模式开启stream_usageTrue后可在每个 chunk 的usage_metadata中获得累计统计。实际开发中可结合 LangChain 的RunnableLambda将滑动窗口封装为链式步骤方便嵌入 Agent 工作流。关键要点总结上下文窗口是模型一次能处理的 Token 上限受计算复杂度、硬件、训练数据等因素限制。Token是模型理解的最小单元不等同于字符或单词开发前务必用专门工具如tiktoken进行精确计算。突破窗口限制的实用方法包括RAG外挂记忆和滑动窗口局部上下文。LangChain 提供usage_metadata和response_metadata两个标准化属性来追踪 Token 消耗支持流式监控。滑动窗口策略实现简单且效果可靠是 AI Agent 处理长文本时的常用技术。