
1. 为什么上下文模式突然成了LLM应用的必修课我是在一次改版事故里真正意识到这个问题的。当时我们团队给一个内部AI客服机器人做了记忆增强功能用户问完帮我查一下上周的订单之后紧接着又问那笔退款到账了吗机器人直接回了句请问您说的是哪笔退款。那一刻产品经理的脸都绿了——不是模型笨是我们根本没把上下文这件事当工程问题来对待。很多人以为context-mode就是把聊天记录一股脑塞给大模型塞得越多AI记得越牢。这个想法在demo阶段确实成立可一旦进入生产环境它会让你的请求越来越慢、账单越来越贵甚至让模型在无关信息里迷路答非所问。我在过去一年多里做了好几个带对话能力的LLM应用从零开始把context-mode从裸奔搭到可控中间踩过的坑、试过的方案、总结出的取舍原则值得完整写出来。这篇文章会覆盖三件事context-mode到底有哪几种形态、每种形态分别解决什么问题上下文窗口的预算怎么做token就像每月工资得精打细算以及检索增强RAG和上下文模式怎么配合才能让AI既记得住又答得准。适合正在做LLM应用开发、或者准备把聊天机器人从玩具推向工具的工程师阅读。如果你只写过单轮prompt调用这篇文章也能帮你建立一套完整的上下文工程思维。2. context-mode的三种核心形态会话、知识、工程别搞混2.1 会话级上下文让AI记住刚才聊了什么这是最直觉的一种context-mode。用户连续提问AI需要记住前几轮说过的话否则每次回答都是初次见面。会话级上下文的实现看起来简单——把历史消息拼进system prompt就行——但真正的难点在多久的历史和哪些历史值得保留。我在实际项目中常用的做法是给每条历史消息打上几个标签消息类型用户提问/助手回答/系统消息、时间戳、是否包含实体关键词比如订单号、日期、商品名、是否被后续消息引用过。然后按下面的优先级组装上下文当前问题以及往前推2-3轮的直接对话这部分必须有包含实体信息的历史消息订单号、金额、时间这类硬信息丢了没法答用户主动引用过的历史内容你刚才说的那个方案其余历史按时间倒序截断这里有个关键认知上下文不是录音机不需要完整回放。它更像是客服交接班时留下的工单摘要——只记对后续处理有用的信息而不是逐字记录用户骂了多久。2.2 知识库级上下文让AI用上你给的资料第二种context-mode是知识库模式。典型场景是企业内部的AI助手需要回答制度手册里的内容或者电商客服要查询商品规格表。模型本身不知道这些私有知识你必须把相关资料放进上下文里喂给它。知识库级上下文的常见翻车点在于全都要。有次我为了让助手回答得更全面把一份300页的技术手册全部塞进system prompt结果模型每次回答前光读资料就要消耗大量token而且因为资料里充斥着互相矛盾的旧版本信息AI的回答反而比不喂资料时更不稳定。后来我调整了策略知识库上下文走按需加载路线——先根据用户问题做一次关键词匹配和语义检索只把最相关的3-5个片段拼进上下文。这样做之后回答准确率明显提升单次请求的token消耗也降到了原来的四分之一左右。知识库级上下文的核心不是塞得多而是选得准。2.3 工程级上下文让AI读懂你这套代码第三种形态在AI编程场景里最常见但它的思路其实可以迁移到任何AI需要理解系统全局的场景。工程级上下文要解决的是让模型不只看到当前文件的代码还要理解整个项目的结构、调用关系、依赖约定。我最开始做AI代码助手时老办法是把所有源码文件都拼进提示词里不到三天就撑爆了上下文窗口。后来我换了个思路先让模型看项目目录树和核心配置文件比如package.json、路由表、数据库schema再根据用户的问题按需拉取相关文件。这个思路后来被我总结成一句话工程级上下文本质上是地图局部街区图。地图就是项目结构概览局部街区图就是用户正在操作或提问涉及的那几个文件。模型有了地图能理解你在哪个城市工作有了街区图能看清你脚下的细节两者配合才是一个可用的工程上下文。3. 上下文窗口的预算管理token就像工资精打细算才能用到月底3.1 先学会估算一次请求到底花了多少token很多刚开始做context-mode的人对token没有体感直到收到账单才吓一跳。其实token估算有规律可循中文文本大致1个汉字≈1到1.5个token英文一个单词≈1.3个token代码平均一个字符≈0.25到0.4个token。我习惯在使用前先做一个静态估算公式很简单单次请求token 系统提示词token 上下文注入token 用户输入token 模型输出token预留以一个典型的客服助手为例系统提示词常年保持500 token左右注入的历史上下文控制在2000 token用户每次提问平均300 token预留输出600 token。那么一次请求的预算大概是3400 token左右。如果模型的上下文窗口是128K理论上可以支持三十多轮对话才需要做压缩。但理论归理论实际中我通常会预留20%的余量因为上下文会随着对话不断累积而且tiktoken和模型实际计费偶尔会有小出入。把预算留出来能避免对话进行到一半突然越界报错。3.2 历史消息的裁剪策略滑动窗口与重要性衰减上下文窗口再大也有上限所以历史消息必须裁剪。我试过两种路径一种叫滑动窗口一种叫重要性衰减各有各的使用场景。滑动窗口简单粗暴只保留最近N轮对话超过N轮的旧消息直接丢弃。好处是成本可控、计算简单坏处是一旦用户回头问早期提到过的事情AI已经忘光了。我在做短会话应用比如限时答疑、临时代码生成时比较喜欢用这种方式交互干净不会因为陈年旧事干扰当前话题。重要性衰减则更聪明每条消息有一个分数时间越久分数越低但包含关键实体订单号、用户名、具体数字或用户明确引用过的消息分数衰减得更慢。组装上下文时按分数排序高分必进低分淘汰。具体实现时我给每条历史消息维护一个JSON结构{ role: user, content: 那笔订单的退款到账了吗, time: 2024-05-11T10:30:00Z, entities: [order_88921, refund], score: 0.87 }系统定期重算分数对话越长、越需要这个机制兜底。打个比方滑动窗口像最近30天邮件全保留重要性衰减像把老板的邮件标星哪怕是一个月前的也置顶。3.3 上下文压缩当对话太长让AI先做笔记即便是重要性衰减也扛不住几十轮的超长对话。这时就该上上下文压缩了。我给对话系统设计过一个跑题检测摘要合并的流程当历史消息总量即将超过预算阈值比如达到窗口的70%时触发压缩。压缩过程是这样的——先把早期对话交给一个轻量模型让它输出一份300字以内的结构化摘要保留主要议题、涉及的关键实体、未解决事项和用户偏好然后删掉原始消息把摘要作为一个特殊的system消息放回上下文里。这里有个细节值得注意压缩摘要本身也会占token而且摘要可能丢失细节。所以我的策略是原消息保留副本但不进上下文如果后面用户提到一个只在原始消息里出现过、摘要里没有的信息系统能识别出这个意图可能来自被压缩的旧对话进而去查原始缓存。简而言之压缩是从上下文中拿走而不是从系统中删掉。4. 检索增强RAG与上下文模式结合短期记忆与长期记忆分工4.1 为什么不能只靠堆历史来解决上下文有段时间我认为context-mode的终极形态就是把相关内容都塞进上下文窗口里越多越好。这个想法在一次高频问答场景中被彻底推翻。当时处理的是产品FAQ机器人用户每天会问上千个类似问题。如果系统把每个用户的历史对话都完整保留并注入上下文早就爆了。更麻烦的是很多问题之间没有关联性——用户问完怎么退货又立刻问你们有没有实体店这两段历史放在一起不仅没用还会稀释模型对当前问题的注意力。这逼着我接受了另一个思路对话上下文负责短期记忆知识库检索负责长期记忆。短期记忆解决连贯性长期记忆解决覆盖面两者不是替代关系而是分工关系。context-mode要想真正好用得在同一套系统里让这两种记忆协同工作。4.2 结构化分块让按需加载成为可能长期记忆的落地我依赖RAG检索增强生成。RAG的工作流程等于对资料库做了一次反向索引先把知识库内容切成小块chunk为每个块生成向量存入向量数据库用户提问时把问题转成向量搜索最相似的一批块作为上下文注入。分块大小很关键。我以前用固定的512字符分块结果语义经常被从中间截断检索出来的内容牛头不对马嘴。后来改成了按语义边界分块段落天然成为块段落太长时按句子边界二次切分并给每个块附上标题和元信息来源文档、章节路径。检索时先靠向量召回Top 20个块再做一次重排rerank只留最相关的3-5块配合对话历史一起组装进最终提示词。这套组合发挥的作用就是上下文按需加载——模型只有在真正需要时才会看到相关资料没有被检索到的知识平时根本不占token。4.3 混合策略落地实例一个客服助手的完整上下文组装流程拿我目前维护的客服助手举例它一次请求的上下文组装大致是这样系统提示词里写死角色设定、回答规范、敏感词拦截规则固定部分注入最近3轮原始对话保底连贯性从历史消息中按重要性衰减算法提取另外5条关键信息补充实体细节用当前问题和关键实体去向量库检索召回3个最相关的知识块检查触发词判断是否需要引用被压缩过的旧对话摘要所有部件按系统提示词 → 知识块 → 历史摘要 → 近期对话 → 当前问题 → 输出预留的顺序组装。这套流程上线后客服机器人的准确率从61%提到了83%平均单次请求token却只涨了不到15%。核心就在于每一个放进上下文的片段都经过了筛选没有浪费的噪音token。这就是context-mode真正的意义——不是把所有东西塞进去而是知道该放什么、不该放什么以及什么时候放弃什么。5. 实测踩坑记上下文污染、漂移与成本失控5.1 上下文污染AI被多余信息带跑偏的典型case最让我头疼的一个问题是上下文污染。简单说就是把不相关内容塞进上下文后模型开始自作聪明地建立错误关联。有一次我测试一个法律咨询助手在上下文里同时放了一份离婚协议模板和一篇关于劳动仲裁的新闻稿。用户本来只是问工资拖欠多久可以仲裁模型却在回答里主动提了一句如果双方对财产分割有异议建议另行咨询。它把劳动仲裁的事和离婚协议的上下文搅在一起了。这种问题很难靠prompt工程完全规避。更可靠的解法是来源隔离不同的知识库片段在注入时带上明确的来源标签并在系统提示词里要求模型只能依据与当前问题来源一致的资料作答。如果再配合上置信度阈值——检索结果相似度低于某个值就不注入——基本能挡住大部分污染。5.2 上下文漂移多轮对话越聊越偏的根因多轮对话中另一个常见问题是上下文漂移。用户本来在聊A话题中途岔到B话题再绕回A时AI已经被B话题带偏对A的回答质量明显下滑。我做了一个小实验同一套系统不设置漂移检测时10轮对话后的意图识别准确率只有58%加上漂移检测后准确率升到了76%。漂移检测的做法是在每轮对话开始时对当前问题做一次意图聚类如果与前面3轮的话题中心距离超过阈值就触发话题切换标记。系统会把新话题作为独立会话片段对待旧话题的信息降权、但仍保留关键实体。这里有一个教训不要强行把多轮对话放在一个永续增长的上下文里。该切就切该重置就重置上下文不是越长越好而是适错率越低越好。5.3 成本与性能的平衡缓存、批处理与异步化最后聊聊钱的问题。context-mode做得越完善请求携带的信息越多token成本增长得越快。我在这里吃过一次大亏上线了知识库级上下文之后单月API账单涨了3倍后来才发现很多重复知识块每次请求都在重新注入、重新计费。优化分三层来做。第一层是会话级缓存相同的历史摘要如果不涉及新消息更新直接用缓存结果不重复让模型生成。第二层是知识块复用经常被检索到的热门内容比如客服的退换货政策可以做预组装直接作为固定提示词的一部分省掉每次检索和拼装的成本。第三层是异步预取在用户输入结束之前先根据输入的前半部分预检索知识块等用户发完整内容时直接用把响应延迟从800ms降到了450ms左右。成本优化的原则说起来很简单却容易被忽略上下文越精确成本越可控。宁可多花时间做检索和筛选也不要让模型陪着一堆无关内容阅读。写在最后context-mode不是特性而是基本功做了这么多轮迭代我最大的体感是context-mode不是一个加上就完了的功能开关它是一项贯穿整个LLM应用生命周期的工程能力。会话记忆、知识注入、窗口预算、压缩策略、检索增强、污染检测——每一个环节单独拿出来都不复杂难的是把它们拼成一个能经受住真实流量考验的系统。如果你正在设计自己的AI应用我的建议是从最简单的滑动窗口开始跑通全流程然后在真实的对话数据里观察模型忘掉什么、答错什么再用重要性衰减和RAG逐步补位。中间会走弯路但每解决一个问题你对上下文的理解就会深一层。我自己也是踩了无数个坑之后才明白真正优秀的context-mode是让用户感觉不到它存在的那种——它不秀技术只是让AI始终记得该记住的忽略该忽略的。