多轮对话长上下文截断技巧示例

张开发
2026/4/17 12:20:00 15 分钟阅读

分享文章

多轮对话长上下文截断技巧示例
在处理多轮对话的上下文管理时理论往往很美但工程落地全是坑。不要追求完美的方案能解决问题的均衡策略往往是最有效的。这里尝试基于网络资料尝试示例多伦对话长上下文截断技巧。1 截断技巧对于中等长度(4k-32k)的上下文滑动窗口截断 关键信息锁定是成本最低、速度最快的方法。1.1 关键信息锁定最常用的截断方法是单纯截取倒数N条消息其实这不是一种有效的方法。正确的做法是锁定第一轮对话(System Prompt和User 初始任务)和最后一轮(当前提问)。然后截断中间的N-3条具体为[System] [Turn 1] ... [截取中间的 N-3 条] [Turn Last 2]。这样做是为了保证模型永不忘记初衷且能听懂当下的指令。对于闲聊、角色扮演 场景滑动窗口截断是有效方案。保留最后5-10轮即可重点保留人物设定一般情况下在第一行。1.2 非对称截断策略User 的输入和 Assistant 的输出不要等权对待。这是因为用户的历史输入往往是意图锚点而LLM的历史输出通常是冗长的生成内容。所以优先保留100%用户历史问题对LLM的历史回答进行强力压缩或丢弃。另外一个原因是LLM看到自己的废话容易产生幻觉或重复看到用户的指令才不会跑偏。1.3 Token计数误差截断不要用len(full_seq)/4估算最好调用模型Tokenizer统计比如tiktoken。预留 20% 缓冲空间。如果模型限制 8k代码逻辑设为 6.4k 触发截断。因为流式输出和特殊 Token 会额外消耗配额。2 代码示例2.1 场景说明这是一个客服对话场景示例如何通过截断技巧管理上下文具体为滑动窗口和关键信息锁定。此场景演示客服对话中如何保持用户初始请求始终可见同时只保留最近的N轮完整对话。2.2 代码示例代码示例如下1模型配置由于涉及到向量模型需要从hf下载这里配置hf-mirror国内站点。同时配置openai格式的api key和base url示例代码如下所示。import os os.environ[HF_ENDPOINT] https://hf-mirror.com model_name gpt_model_name # LLM名称,比如deepseek-r1, qwen3.5-8b os.environ[OPENAI_API_KEY] gpt_api_key # LLM供应商提供的api key os.environ[OPENAI_BASE_URL] gpt_api_url # LLM供应商提供llm访问api的url2滑动窗口关键信息锁定这是滑动窗口和关键信息锁定的具体实现具体为客服对话场景 - 滑动窗口 关键信息锁定演示- System Prompt客服角色始终锁定- 用户第一轮问题初始请求始终锁定- 当前轮问题始终锁定- 中间历史按滑动窗口截断保留最近 K 轮完整对话代码示例如下import os import tiktoken from openai import OpenAI class CustomerServiceAgent: def __init__(self, model: str gpt-4o-mini): self.client OpenAI( api_keyos.environ.get(OPENAI_API_KEY), base_urlos.environ.get(OPENAI_BASE_URL) ) self.model model self.encoder tiktoken.encoding_for_model(gpt-4o-mini) # 对话历史每项为 {role: ..., content: ...} self.messages [] # 系统提示词始终锁定 self.system_prompt { role: system, content: 你是一位专业的客服人员态度亲切、耐心。请根据对话历史帮助用户解决问题。 } def _count_tokens(self, text: str) - int: 计算文本的 token 数量 return len(self.encoder.encode(text)) def _build_context_with_sliding_window( self, current_user_input: str, window_size: int 6, # 保留最近 N 条消息userassistant 成对保留 max_tokens: int 4000, # 模型上下文上限的 80%gpt-4o-mini 为 16384取安全值 ) - list: 构建带滑动窗口的上下文同时锁定系统提示词、第一轮用户请求和当前问题 # 添加当前用户输入 self.messages.append({role: user, content: current_user_input}) # 1. 锁定元素 locked_messages [self.system_prompt] if len(self.messages) 1: # 锁定第一轮用户请求始终保留 locked_messages.append(self.messages[0]) # 2. 提取当前轮最后一条 user 消息 current_turn self.messages[-1:] # 当前用户问题 # 3. 中间历史除了锁定的和当前轮之外的所有消息 middle_messages self.messages[1:-1] if len(self.messages) 2 else [] # 4. 滑动窗口只保留最近 N 条中间消息 if len(middle_messages) window_size: middle_messages middle_messages[-window_size:] # 5. 组装 context locked_messages middle_messages current_turn # 6. Token 检查与硬截断防御性编程 total_tokens sum(self._count_tokens(m[content]) for m in context) while total_tokens max_tokens and len(middle_messages) 0: # 逐步丢弃更早的中间消息 middle_messages middle_messages[1:] context locked_messages middle_messages current_turn total_tokens sum(self._count_tokens(m[content]) for m in context) return context def chat(self, user_input: str) - str: 处理用户输入并返回 AI 回复 context self._build_context_with_sliding_window(user_input) print(f\n[调试] 当前上下文消息数: {len(context)}) print(f[调试] 上下文结构: {[m[role] for m in context]}) response self.client.chat.completions.create( modelself.model, messagescontext, temperature0.7, ) ai_response response.choices[0].message.content # 将 AI 回复存入历史 self.messages.append({role: assistant, content: ai_response}) return ai_response3运行测试以下是运行测试的示例# 测试运行 if __name__ __main__: agent CustomerServiceAgent(modelmodel_name) print( 客服对话测试 (滑动窗口) ) print(提示: 输入 exit 退出对话\n) # 模拟长对话场景 test_inputs [ 我想退货订单号是 ORD-2024-00123, 产品是三天前收到的已经拆封了, 包装盒还在但里面的说明书找不到了, 可以退货吗, 退货流程是怎样的, 运费谁承担, 大概多久能退款, 我可以用顺丰寄回吗, 如果卖家拒收怎么办, 好的我明白了谢谢 ] for user_msg in test_inputs: print(f\n 用户: {user_msg}) response agent.chat(user_msg) print(f 客服: {response})输出如下所示 客服对话测试 (滑动窗口) 提示: 输入 exit 退出对话 用户: 我想退货订单号是 ORD-2024-00123[调试] 当前上下文消息数: 3[调试] 上下文结构: [system, user, user] 客服: 您好很高兴为您服务。已经收到您提供的订单号 **ORD-2024-00123** 了。非常抱歉这次购物没能让您满意我们完全理解您想要退货的心情请放心我会全力协助您办理退货手续。为了帮您更快地完成流程麻烦您告诉我一下1. **退货原因**是什么呢例如商品质量问题、尺寸不合适、拍错多拍、或是七天无理由退货等2. 商品目前是否**完好未使用**且包装和配件齐全呢一旦确认这些信息我会立刻为您提交退货申请并告知您后续的寄回地址和注意事项。您看方便简单描述一下吗有任何其他疑问也随时可以问我哦 用户: 产品是三天前收到的已经拆封了[调试] 当前上下文消息数: 4[调试] 上下文结构: [system, user, assistant, user] 客服: 您好收到您的补充信息了。首先请您放心**三天前签收**是在我们的退换货有效期内的。关于**商品已拆封**这一点通常是为了检查商品状况只要商品本身完好、不影响二次销售非质量问题前提下一般是可以正常办理退货的您不必过于担心。为了帮您准确判断退货流程比如运费由谁承担、是否需要提供照片等还需要麻烦您告知一下**具体的退货原因**1. **商品质量问题**比如破损、瑕疵、功能故障等。这种情况即使拆封使用过我们也会负责到底并承担运费2. **非质量问题**比如尺寸不合适、颜色不喜欢、拍错等。这种情况需要商品及配件完好不影响二次销售您看是属于哪一种情况呢如果有商品问题的照片也可以随时发给我我帮您备注加急处理期待您的回复我会一直在线协助您 用户: 包装盒还在但里面的说明书找不到了[调试] 当前上下文消息数: 6[调试] 上下文结构: [system, user, assistant, user, assistant, user] 客服: 您好非常感谢您的反馈这种情况其实挺常见的请您先别着急。关于**说明书找不到**这一点我先给您吃颗定心丸通常情况下只要商品主体完好、功能正常且包装盒还在**是不会直接导致无法退货的**。不过为了保障您的权益特别是关于运费承担和退货审核通过率我还是需要跟您确认一下**具体的退货原因**因为这两种情况的处理方式稍有不同1. **如果是商品质量问题**比如坏了、瑕疵* 说明书缺失完全不影响退货我们会承担所有运费并为您优先处理。️2. **如果是七天无理由退货**比如不喜欢、拍错* 原则上需要配件齐全但鉴于您刚收到 3 天我可以帮您向仓库**特殊申请备注**一下。大多数情况下是可以通过的但可能需要您确保商品本身没有任何使用痕迹。所以麻烦您再跟我确认一下主要是出于什么原因想要退货呢确认好后我马上为您生成退货地址和流程争取让您最省心地把这件事解决好有任何顾虑都可以随时跟我说哦~ 用户: 可以退货吗[调试] 当前上下文消息数: 8[调试] 上下文结构: [system, user, assistant, user, assistant, user, assistant, user] 客服: 可以的请您放心~ ✅**您的订单是可以办理退货的。**虽然说明书找不到了但鉴于您签收才**3 天**且**包装盒还在**只要商品本身没有人为损坏通常是不会影响退货审核的。关于说明书缺失的情况我会帮您在后台做个特殊备注争取让您顺利退回。为了帮您安排最合适的退货方式比如是否有运费险、谁来承担运费等还是需要麻烦您简单告诉我一下**退货原因*** 如果是**质量问题**运费由我们承担说明书缺失完全没关系。* 如果是**七天无理由不喜欢/拍错等**运费可能需要您承担但我会帮您备注说明情况尽量简化流程。您看方便告诉我一下原因吗确认后我**马上把退货地址和流程发给您**争取今天就把这事帮您办好随时期待您的回复我一直在线哦 用户: 退货流程是怎样的[调试] 当前上下文消息数: 9[调试] 上下文结构: [system, user, user, assistant, user, assistant, user, assistant, user] 客服: 您好没问题我这就为您详细介绍一下退货流程非常简单清晰的您跟着步骤操作就行~ 针对您的订单 **ORD-2024-00123**具体的退货流程如下### 退货四步走1. **提交退货申请** * 您可以直接在订单页面点击“申请售后”或者**告诉我您确定的退货原因**我这边帮您后台登记生成退货单。2. **寄回商品** * 审核通过后我会为您提供**退货地址和联系人**。* 您将商品连同现有的包装盒打包好交给快递员寄回。* * 小贴士建议您寄出前拍一张商品照片留底以防物流途中出现意外。*3. **仓库验收** * 仓库收到货后会进行检查。* *✅ 关于说明书请您放心我之前已经帮您在备注里特别说明过“说明书缺失”的情况只要商品主体完好仓库那边会知悉的不会因此拒收。*4. **退款到账** * 验收无误后我们会立即发起退款钱款会原路返回到您的支付账户通常 1-3 个工作日内到账。---### ⚠️ 两个重要小提示1. **关于运费*** 如果是**质量问题**运费由我们承担您可以先垫付退款时一起退给您或者我们提供运费险。* 如果是**七天无理由不喜欢/拍错**运费可能需要您承担哦。* *所以还是麻烦您稍微透露一下退货原因这样我能准确告诉您运费怎么处理避免后续产生误会~ *2. **关于包装*** 您提到包装盒还在这点非常好寄回时请尽量把商品裹好防止运输损坏。**您看现在方便告诉我退货原因吗** 确认后我**马上把退货地址和具体的操作链接发给您**争取让您今天就能把东西寄出去有任何不清楚的地方随时问我我一直都在 用户: 运费谁承担[调试] 当前上下文消息数: 9[调试] 上下文结构: [system, user, user, assistant, user, assistant, user, assistant, user] 客服: 您好这是一个非常重要的问题请您放心我来给您详细说明一下运费的承担规则这样您心里就有底啦~ 运费由谁承担主要取决于**退货的具体原因**分为以下两种情况1. **️ 如果是商品质量问题*** 例如商品损坏、功能故障、发错货等* **运费由我们承担** 您可以先垫付运费退货成功后我们会将运费连同货款一起退给您或者我们直接提供运费险赔付。* *注这种情况完全不用担心说明书缺失的问题。*2. **❤️ 如果是七天无理由退货*** 例如不喜欢、拍错型号、多拍等个人原因* **运费通常需要您承担哦。** 不过如果您下单时购买了**运费险**保险公司会理赔首重运费您基本不需要花钱或只需花很少的钱。* *注即使是这种情况说明书缺失只要备注好一般也不会影响退货只是运费规则按无理由处理。*---** 为了给您最准确的答复能麻烦您稍微透露一下退货原因吗*** 如果是**质量问题**我马上帮您登记运费您不用担心* 如果是**不喜欢**我帮您查一下这个订单是否有**运费险**看看能帮您省多少运费~您告诉我原因后我这边立刻就能帮您确认最终的运费方案并马上发给您退货地址一直在线等您哦~ 用户: 大概多久能退款[调试] 当前上下文消息数: 9[调试] 上下文结构: [system, user, user, assistant, user, assistant, user, assistant, user] 客服: 您好非常理解您关心退款到账的时间毕竟涉及到咱们的钱袋子嘛请您放心我来给您详细说明一下~ ⏰针对您的订单 **ORD-2024-00123**退款时效一般分为两个阶段### 1️⃣ 仓库验货阶段约 1-2 天* 当您寄出的包裹被仓库签收后我们会尽快进行验收。* ** 请放心**之前帮您备注的“说明书缺失”情况仓库那边已经知悉了**不会因为这个问题卡住验货流程**只要商品主体完好验货会很快通过。### 2️⃣ 退款到账阶段约 1-3 天* 验货通过后系统会立即发起退款。* **支付宝/微信余额**通常 **1-3 个工作日** 内到账很多时候甚至是秒到。* **银行卡/信用卡**可能需要 **3-7 个工作日**具体取决于银行的处理速度。---### 总结来说从仓库**收到您的退货包裹算起**大概 **3-5 天** 左右钱款就能回到您的账户了。**我会帮您全程跟进这个订单** 一旦仓库签收我会立刻提醒财务优先处理争取让您早点收到退款。您看要是关于时效没其他疑问了**咱们确认一下退货原因吗** 确认后我马上把退货地址发给您您早点寄出咱们就能早点进入退款流程啦~ 随时期待您的回复我一直在线为您服务 用户: 我可以用顺丰寄回吗[调试] 当前上下文消息数: 9[调试] 上下文结构: [system, user, user, assistant, user, assistant, user, assistant, user] 客服: 您好当然可以呀~ 我们**非常推荐您使用顺丰寄回**因为顺丰的速度快、服务好能更好地保障商品在运输过程中的安全也能让仓库更快收到货从而加快您的退款进度哦不过为了确保您的退货顺利有**两个小细节**需要特别提醒您注意一下1. **❌ 请勿选择“运费到付”*** 除非我们事先特殊约定否则仓库**无法签收“到付”的包裹**可能会被退回。* 请您先**垫付运费**寄出。* * 如果是质量问题*后续我们会把运费退给您。* * 如果是七天无理由*运费险会理赔一部分超出的部分可能需要您自理。2. ** 关于运费差价*** 顺丰的费用可能会比普通快递稍高一些。* 如果是**质量问题**我们会全额承担您不用担心。* 如果是**七天无理由**运费险通常只赔付首重约 10-12 元超出的部分可能需要您自理哦。---** 接下来**您决定好用顺丰后**麻烦还是跟我说一下退货原因**是质量问题还是不喜欢呀我确认后**马上把具体的退货地址和收件人信息发给您**这样您联系顺丰小哥的时候直接就有地址可以填啦~ 一直在线等您哦 用户: 如果卖家拒收怎么办[调试] 当前上下文消息数: 9[调试] 上下文结构: [system, user, user, assistant, user, assistant, user, assistant, user] 客服: 您好非常理解您的担忧毕竟寄出去之后要是被拒收既耽误时间又麻烦换做是我也会担心的。请您放心我来给您吃颗“定心丸”️在我们这里**只要您按照正常的流程操作卖家拒收的概率是非常非常低的**。为了让您更安心我给您列一下**极少数会被拒收的情况**您避开这些就完全没问题啦### ❌ 容易导致拒收的 3 种情况请避免1. **擅自选择“运费到付”** * 这是最常见的拒收原因。仓库无法处理到付件所以**请务必先垫付运费**就像我们刚才聊到的用顺丰寄现付就好。2. **商品人为损坏严重** * 如果是退货商品需要保持完好。如果是质量问题保持原样寄回即可如果是无理由退货不要影响二次销售。3. **寄回的商品不对版** * 确保寄回的就是订单里的商品不要寄错东西哦。### ✅ 关于您担心的其他问题比如之前提到的说明书* **像之前我们沟通好的“说明书缺失”等小配件问题**只要您提前跟我说过我已经帮您备注在系统里啦✅仓库知情后**绝对不会因此拒收**的这点您把心放在肚子里~* 只要商品主体完好包装尽量扎实一点就不会有问题。### 我的承诺1. **全程跟进**您寄出后把**顺丰单号**发给我我会盯着物流信息。2. **提前沟通**我会提前通知仓库查收您的包裹确保顺利入库。3. **异常处理**万一虽然可能性极小仓库有任何异议我会第一时间联系您站在您的角度去协调解决不会让您独自承担损失。---** 咱们下一步**为了让您早点寄出早点安心**您看方便告诉我一下具体的退货原因吗*** 是**质量问题*** 还是**七天无理由**确认后我**立刻**把准确的**退货地址、收件人和电话**发给您您直接填单寄出就好啦我一直在线守着您呢~ 用户: 好的我明白了谢谢[调试] 当前上下文消息数: 9[调试] 上下文结构: [system, user, user, assistant, user, assistant, user, assistant, user] 客服: 不客气哒能帮您把疑问都解开我也很开心呢~ 那您先忙**等您准备好寄出的时候随时回复我一下退货原因**是质量问题还是七天无理由呀我立马把具体的**退货地址和收件信息**发给您绝不耽误您的时间后续有任何问题比如填单号、查物流随时找我我一直都在哦祝您生活愉快心情美美哒对于客服对话场景这里采用滑动窗口关键信息锁定。具体为System Prompt、首轮问题、当前轮永不丢弃Token 安全检查。虽然这里理论上不是一种完美的方案但大部分情况下能抓住重要信息是一种有效方案。reference---智能体上下文窗口告急8种策略破解AI记忆困局https://cloud.tencent.com/developer/article/2550071LLM上下文管理探索-滑动窗口摘要压缩优先级丢弃https://blog.csdn.net/liliang199/article/details/159986000DeepSeek 如果对话过长如何处理上下文长度限制问题https://bbs.itying.com/topic/67a6875f55a429007d7d3b26

更多文章