“context-mode”这个词,乍看像是某个库的配置项或者是编辑器的显示模式,但在大模型应用开发这个圈子里,它代表的是一个远比字面意思更麻烦的问题:到底该给模型塞多少上下文、塞什么上下文、用什么结构去塞。我在过去大半年里,帮三四个团队做过基于大模型的应用改造,几乎每个项目最终都会卡在同一个地方——不是模型能力不够,而是上下文管理稀烂,导致模型“该记住的记不住,不该记的全记住了”。
这篇文章不打算讲那种堆砌概念的长篇大论,而是从我实际踩过的坑出发,把context-mode的底层机制掰开揉碎,再给出一套可以直接照搬的落地策略、完整改造案例和调优经验。无论你是在做一个客服机器人、文档问答工具、代码助手还是Agent类应用,这些东西大概率都适用。
1. Context-Mode到底在解决什么:先看三个真实翻车现场
在讨论任何方案之前,得先搞清楚问题的真实面貌。我接触过的项目里,翻车场景高度集中在这几类。
1.1 场景一:长文档分析时的“失忆”
朋友团队做过一个内部产品手册问答系统,把一份五十多页的产品规格书整本塞给模型,让员工自由提问。前十几页的内容回答得还挺像回事,问到第三十几页以后,模型开始一本正经地编造根本不存在的字段名和参数值。最离谱的一次,它把另一个产品的接口文档内容“移植”到了当前产品上,客户差点拿着这个错误答案去对接开发。
原因其实不复杂。这份中文手册大概六万多个字符,按中文一个汉字约1.5到2个token来估算,整体算下来有九万到十二万token。市面上很多模型的上下文窗口虽然是128K甚至更大,但真把这么多token一次性塞进去,首先成本就很高,其次模型在超长上下文下的注意力分配并不均匀,靠后的内容很容易被“稀释”。更关键的是,如果你的方案是把所有内容一股脑全塞进去,那本质上等于没有上下文管理,只是暴力堆料。
1.2 场景二:上下文爆炸带来的账单飙升
另一个电商客服项目,最初的实现方式是每次请求都把整个对话历史原封不动地发给模型。用户和机器人聊了五十轮之后,单次请求的输入token就已经逼近三万。这个项目用的是按token计费的商业API,我帮他们算过一笔账:假设单日活跃会话三千个,每会话平均一百五十轮,每轮平均五百token,每个月光是输入token的支出就足够再开一台高配服务器。
这个问题的本质是:很多开发者把“对话历史”等同于“上下文窗口里的所有内容”,以为把历史全部传进去,模型就能完美理解一切。可实际上,用户聊到第五十轮的时候,前四十轮里百分之九十的信息早就没有再引用的价值了。无脑全量发送,等于让模型每次都在二三十万字里大海捞针,还顺便把账单撑爆。
1.3 场景三:多轮对话的方向漂移与指令稀释
第三个问题更隐蔽。用户一开始说“帮我写一个针对大学生群体的校园二手交易平台推广方案,预算两万以内”,中间又问了几个不相关的问题,比如“顺便帮我看看怎么注册营业执照”“你们能生成图片吗”,等绕回来继续聊方案时,模型已经把“大学生群体”“两万预算”这些核心约束忘得一干二净,给出的方案成了面向所有人群、预算随意的通用版本。
这种所谓的方向漂移,本质是因为指令和约束被淹没在大量无关对话里。模型没有能力自动判断什么该记住、什么只是随口一问。如果代码层面不提供一套明确的上下文管理模式——比如把核心约束单独拎出来作为不可遗忘的“工作记忆”——那模型就只能被最近几轮的内容牵着鼻子走。
这三个场景加在一起,基本就是context-mode要解决的核心问题:在有限的上下文窗口里,用可控的成本,把最重要的信息以最合理的结构交给模型。
2. 理解上下文链路的三个关键机制
想要设计好context-mode,光知道“要管理上下文”是不够的,还得理解底层模型处理上下文时的几个关键机制。不然你前端策略做得再花哨,后端模型不认你,照样白搭。
2.1 上下文窗口:模型记忆的“物理边界”
先理解token。模型不是按“字”读文本的,而是把文本切成一堆更小的单元,叫token。中英文不太一样,大致感受一下就好:一个汉字通常约等于1到2个token,一个英文单词约等于1到2个token。上下文窗口的大小,决定了模型一次推理能“看到”多少token。超过这个数量的内容,不是“看到了但顾不上”,而是根本没有进入计算流程,相当于你把文件放到了会议室外面的走廊上,会议室里的人永远也不会看到。
打个比方:上下文窗口就像一块固定的白板。写满了,要么擦掉旧内容,要么换一块更大的白板。很多应用层报错“context length exceeded”,其实就是白板不够写了,需要你去决定擦掉什么、保留什么。
需要注意的一点是,“大窗口”和“好效果”之间并不是完全正相关。窗口越大,模型处理时的注意力分散问题就越明显,同时也意味着每一轮请求消耗的算力和费用都在上涨。所以,盲目追大窗口不是一个成熟的工程选择,合理的做法是——让窗口里的每一块空间都值得被模型看到。
2.2 注意力机制:为什么长上下文的“中部”总被忽略
自注意力机制是Transformer架构的核心。简单理解,模型在生成每一个新token时,都会给上下文里已有的token计算一个“相关度权重”,然后根据权重决定参考哪些信息。理论上它能考虑到所有位置的信息,但实际表现中,模型的注意力分布存在明显的偏置。
业界有个被反复验证的现象叫“Lost in the Middle”。如果你在上下文的不同位置放一段关键信息,然后让模型回答基于该信息的问题,你会发现:放在开头的信息命中率最高,放在结尾(离生成位置最近)的信息次之,放在中间的命中率最差。换句话说,模型对“头”和“尾”更敏感,对中部内容的利用效率很低。
这对context-mode设计有非常直接的指导意义:不要把核心指令和关键约束放在提示词的中间。有些团队把所有背景资料一股脑堆在中间,模型效果奇差,还以为是模型能力不行,其实就是信息位置摆错了。
2.3 系统提示词与对话历史的权重差异
标准接口调用里,消息数组通常分成system、user、assistant三个角色。system的角色是全局指令——人设、规则、边界条件;user/assistant交替记录对话过程。实践中你会发现,system部分的内容对模型行为的约束力远高于对话历史里的普通语句。
也就是说,哪怕你在对话中途发现用户一直跑偏,靠“微调”对话内容来纠偏,效果远不如一开始在system里把规则写死。反过来说,如果某个约束是贯穿整个会话都必须生效的,它就应该被放进system里,而不是混入某个历史轮次。
理解了这三个机制,你再看现成的各种context-mode策略,就不会觉得它们是拍脑袋想出来的了,每条策略其实都对应着window、attention、role这些底层约束。
3. 四种主流的Context-Mode管理策略及选型
这一节直接上干货。目前工程界用得最多的上下文管理模式,归纳下来无非四种:滑动窗口、递归摘要、检索增强、结构化分离。没有哪种是银弹,重点看你是什么场景。
3.1 滑动窗口模式:最朴素但最稳定的粗粒度策略
做法很简单:维护一个队列,只保留最近N轮对话,超出N轮的一律丢弃。每次请求只传“system + 最近N轮”。
这是许多早期聊天机器人用的方案,也是我所有项目里最先拿来做止损的方案。它的优点在于实现成本极低、token消耗稳定可控,而且对闲聊场景非常友好——因为闲聊本身对历史信息的依赖很小,最近几轮足够应付。
缺点也明显:一旦用户提到“我开头说的那个需求你还记得吗”,模型只能一脸懵。所以它适合那些对早期信息依赖度低的场景,不适合需要维护长期目标的任务型对话。如果你只是先让系统跑起来,滑动窗口是性价比最高的起点。
3.2 摘要递归模式:用空间换记忆的折中方案
既然全量历史装不下,那就把历史“压缩”之后再装。摘要递归模式的基本思路是:当对话轮数超过某个阈值时,触发一次LLM的摘要操作,让模型把当前对话历史总结成一段精简描述,然后在下一次请求时,把“摘要 + 最近几轮原始对话”一起作为上下文。
打个比方:开会两小时内容太多记不住,你会让秘书写一份会议纪要,等下次需要时先翻纪要,再按纪要里的关键词去找详细材料。摘要就是这份纪要,但它不可能包含所有细节,纪要写得越简洁,细节丢得越多。
实际操作中有几个需要反复调整的点:
- 摘要触发时机:是每超过十轮就摘要一次,还是根据token总量来判断。
- 摘要长度上限:如果摘要本身写得跟原文一样长,那压缩就失去了意义。
- 摘要递归次数:摘要再被摘要,信息损耗会指数级放大。我见过一个真实案例,项目跑了三十多轮,模型把用户最初明确说过的“预算两万”给摘成了“预算两三万”,最后干脆摘成了“预算有要求”。这种在反复压缩中产生的信息坍缩,是最常见的坑。
3.3 检索增强模式:让模型学会“带着资料回答问题”
检索增强生成(RAG)是目前知识库问答场景里当之无愧的主力方案。思路和前面的都不一样:不以“把所有资料都塞进去”为目标,而是等用户提出问题后,先从一个更大的知识库或历史记录库里检索出最相关的几段内容,只把“检索片段 + 用户问题”交给模型。
它的典型流程你可以直接抄:
- 把知识库或历史记录切块。切多大的块很有讲究,我的经验是中文场景下按逻辑段切,而不是按固定字符数硬切,不然容易切断语义。每块大概256到512个token比较常用。
- 用嵌入模型把每个文本块向量化,存入向量数据库。
- 用户提问时,把问题也转成向量,做相似度检索,找出Top-K个最相关的块。
- 按相关度排序,把这些块拼接在用户问题之前,一起发给LLM生成答案。
这个模式的好处是:理论上可以应对无限量的资料,成本只取决于检索结果的数量,而不是整个资料库的大小。但这非常依赖切块和检索的质量,如果召回不准确,模型就会基于错误资料自信地胡说八道。所以RAG项目里,真正让人头大的往往不是LLM部分,而是切块策略和召回排序。
3.4 结构化模式:人设、规则与记忆的分离管理
最后一种是我个人最推荐在任务型Agent里使用的模式。核心思想是:不要把所有东西都揉进一段连续的对话历史里,而是把上下文拆分成几个固定槽位,每个槽位独立管理、独立更新。
典型的结构包含四到五个槽位:
- 系统指令槽:人设、规则、禁止事项,一旦设定轻易不改变。
- 工作记忆槽:当前任务的临时状态,比如“用户正在退货流程中,已确认退款金额128元,等待用户提供开户行”。
- 短期对话槽:最近几轮的原始对话,用于维持对话连贯。
- 长期记忆槽:跨会话的用户画像、历史偏好,比如“该用户常用配送地址是海淀区”“上次投诉过物流”。
- 外部数据槽:从订单系统、CRM里拉取的实时数据。
这样做的好处非常直观:每个槽位各司其职,该稳定的稳定,该更新的更新。工作记忆槽随时可以被新任务覆盖,长期记忆槽则需要更谨慎的写入逻辑。当用户下次再来咨询时,系统可以在新会话里直接注入长期记忆,让模型表现得更像一个“有记忆的接待员”,而不是一个什么都忘了的新客服。
| 策略 | 实现复杂度 | 记忆能力 | 成本水平 | 适用场景 | 主要风险 |
|---|---|---|---|---|---|
| 滑动窗口 | 低 | 弱(仅近期) | 低 | 闲聊、简单问答 | 早期信息丢失 |
| 递归摘要 | 中 | 中(压缩后留存) | 中 | 中长对话 | 摘要失真、信息坍缩 |
| 检索增强 | 高 | 强(理论无限) | 中 | 知识库问答、RAG | 切块与召回质量 |
| 结构化分离 | 中高 | 强(分槽管理) | 中 | 任务型Agent、客服工单 | 槽位设计不合理 |
4. 在真实项目中落地Context-Mode:一个客服问答系统的完整改造记录
理论和策略说再多,不如看一个实际项目的改造过程。下面是我帮一个电商团队重构客服机器人的完整记录,三个阶段,每一步都有明确的决策理由和效果数据。
4.1 改造前的系统架构与问题现象
原系统说白了就是一个裸奔的LLM调用。提示词里只有一句“你是一个电商客服”,然后把最近十轮聊天记录原样拼接进prompt,发去调用模型。上线没几天,运营那边就炸了:
- 用户先咨询退换货政策,再问优惠券,AI回答时经常把两个话题搅在一起,回答完退换货忽然又开始讲“您可以领取一张20元无门槛券”,根本分不清当前正在处理什么。
- 用户连续追问订单状态后,AI开始编造物流信息,比如“您的包裹已到达杭州转运中心”,而订单系统里根本没有这种状态。
- 用户隔天再次来访时,AI完全不认识对方,同样的“订单异常”问题要让用户重新解释一遍前因后果。
表面看是模型问题,实际上是上下文结构的问题。十轮原始对话把系统指令稀释得所剩无几,也没有任务状态的记录,模型当然只能东拼西凑。
4.2 阶段一:引入滑动窗口与指令锚定,先止损
第一步不是上多复杂的技术,而是把prompt结构理清楚。我们把prompt改成了三段式:
[系统指令] 你是一名电商客服。以下是你在本次会话中必须严格遵守的规则: 1. 在任何情况下,都不要编造订单状态、物流信息或退款进度;如果不知道,明确告知用户需要人工核实。 2. 用户当前的核心诉求类型是:{{intent}};你已经确认的信息包括:{{confirmed_facts}}。回答时必须优先基于这两项内容。 3. 当用户话题发生切换时,先回应用户新话题,同时提示“以上问题处理完后,我们会继续为您处理之前的XX问题”。 [最近的历史记录] {{sliding_window_history}} [当前问题] {{user_input}}同时把“最近十轮全量历史”改成“最近五轮全量历史 + 前十五轮的压缩摘要”。这里的压缩摘要不依赖复杂的摘要模型,而是用一个非常简单的规则:每五轮提取一次对话内的关键实体(订单号、金额、地址、诉求类别),存入一个JSON对象,塞进confirmed_facts字段。
这一步上线后,效果立竿见影。单次请求的输入token量平均下降约四成,因为不再把三十几轮历史全部发送。最关键的两个指标:回答串味次数下降了约三分之二,编造订单信息的次数降到了零——不是模型变聪明了,而是我们拿掉了它赖以发挥创造力的那堆混乱历史。
4.3 阶段二:关键词路由与动态检索,拯救“长尾问题”
止损之后,新的问题暴露出来:用户问的知识类问题越来越刁钻。比如“之前买的那个保温杯,杯盖能拆下来放进洗碗机吗”,原系统里完全没有这部分资料,模型只能“凭感觉回答”,经常给出与产品说明书完全相反的答案。
为了解决这个问题,我们把知识库按类目切块并向量化:售后政策、产品规格、物流说明、优惠券规则,每个类目单独建索引。每次用户提问时,先用一个轻量意图识别模型判断属于哪一类(这个模型只需要几百条样本就能做得不错),然后只去对应类目里做向量检索,取Top-3片段拼进prompt。
这一步其实做了个更关键的结构调整:把“指令、历史、检索资料”三个区块彻底分开,中间用清晰的标记符隔开。因为如果检索出来的片段只是一股脑贴在历史里,模型同样会搞混哪些是用户的对话,哪些是外部参考资料。
def build_prompt(user_input: str, history: list[dict], kb_index: dict): intent = classify(user_input) docs = kb_retrieve(kb_index[intent], user_input, top_k=3) prompt = f""" [系统指令] 你是一个基于以下官方资料回答问题的客服。只能使用资料中出现的信息,不要凭空发挥。 当资料中没有答案时,请回复:抱歉,这个问题我需要核实后为您答复。 [参考资料] {docs} [最近对话] {history[-5:]} [当前问题] {user_input} """ return prompt改造后,我们人工抽检了三百条知识类问题,准确率从大约六成提升到接近九成。这个阶段最大的经验是:切块的质量决定了回答的天花板。我们最初按固定三百字硬切,导致很多产品参数被切散,检索回来的片段“缺胳膊少腿”。后来改成按markdown的段落和表格边界切,整体回调率立刻上了一个台阶。
4.4 阶段三:分层记忆设计——短期、工作、长期三层
前两个阶段解决了“单次会话内如何组织上下文”,但跨会话的记忆还没有着落。用户隔天再来,还是得重新报订单号、重新描述问题。这个体验在电商场景里非常糟糕。
于是我们引入了三层记忆结构:
- 短期记忆(Short-term):当前会话最近五轮原始对话,存Redis,设置过期时间二十四小时。
- 工作记忆(Working):当前会话正在处理的任务状态。比如用户正在处理“退款申请”,工作记忆里记录:退款金额、是否上传凭证、等待哪个环节。每次对话更新一次,任务结束就清空。
- 长期记忆(Long-term):跨会话的用户画像和偏好,存在数据库,用户下次到来时先加载。
用JSON举例,工作记忆长这样:
{ "session_id": "sess_20250121_001", "current_task": "refund", "task_step": "pending_user_bank_info", "confirmed_facts": { "order_id": "E20250120002345", "product": "不锈钢保温杯500ml 黑色", "refund_amount": 129.0, "refund_reason": "杯盖密封圈脱落" }, "pending_question": "等待用户提供开户行信息" }长期记忆则存一些相对稳定的画像信息:
{ "user_id": "u_82371", "total_orders": 17, "preferred_address": "北京市海淀区中关村大街xx号", "history_issues": ["2024-11-03 物流延误投诉", "2024-12-18 保温杯杯盖密封圈问题"], "tone_preference": "简洁、直接,不需要寒暄" }每次用户发起新对话时,组装上下文的顺序是:系统指令 + 长期记忆摘要 + 工作记忆当前状态 + 最近五轮短期历史。这样组装之后,模型对整个会话的目标和约束一目了然,不会再出现用户绕了两轮就忘了自己正在办理退款的情况。
改造完成后,人工客服介入率从改造前的百分之三十几降到了百分之十二。这个数字在我接手的所有项目里算是相当拿得出手的成绩了。
5. 配置参数、成本测算与调优经验
策略确定之后,接下来就是工程上的细活。这一节说三个最容易被忽视的点:token预算分配、生成参数与上下文的配合、以及成本测算方法。
5.1 Token预算的分配原则
在每个请求发出前,都应该有一个token预算。它决定了什么东西能进上下文窗口、什么东西不能。我常用的分配比例大致如下,你可以根据自己场景调整:
| 区块 | 占单次请求预算比例 | 说明 |
|---|---|---|
| 系统指令 | 10%-15% | 人设、规则、边界条件,固定开销 |
| 检索/参考片段 | 30%-40% | RAG召回内容、工作记忆、长期记忆摘要 |
| 最近对话历史 | 40%-50% | 原始对话轮次,越近越详细 |
| 模型输出 | 20%-25% | max_tokens,给回答留足空间 |
比如窗口是16K token的模型,系统指令约1600到2400token,检索片段约4800到6400token,最近历史约6400到8000token,输出预留3200到4000token。如果某一轮检索回来的片段特别多,就对历史做进一步的截断——比如从五轮砍到三轮,而不是把窗口撑爆。
这个分配原则的核心逻辑是:系统指令和检索片段决定了回答的“上限”,历史记录只提供连贯性。当你发现回答质量上不去时,优先审视前两者,而不是一味增加历史轮数。
5.2 生成参数与上下文管理的配合
很多人调Large Language Model时只盯着temperature、top_p这些参数,但从我的实践经验看,这些参数必须和你的context-mode策略一起考虑,否则是互相拖后腿。
在客服场景里,我们把temperature从默认的0.7降到了0.2,同时调整了system提示词,明确要求“优先遵循参考资料,而不是历史对话中的推测”。结果稳定性大幅提升,编造类回答明显变少。原因很直观:低温让模型更倾向于按照给定上下文的“高概率路径”走,而不再自己发挥。相比之下,如果你做的是创意写作类应用,低温搭配太死的系统指令反而会让回答变得机械。参数的调优永远要回到“这个应用允许模型有多少自由发挥空间”这个问题上。
另外,如果把上下文做成了结构化检索,那么top_p或者temperature对“检索片段内信息的引用率”其实影响不大,真正影响的是模型在多个矛盾片段之间如何抉择。所以我通常会在提示词里主动写清楚冲突处理规则,而不是指望参数帮我解决。
5.3 成本测算:从按次计费到按Token计费
我还见过不少团队,在方案评审时张口就是“我们的场景一天也就几千次调用”,完全没有token成本概念。这里的核心不是“按次”而是“按token”。一次调用传一万token和一千token,成本完全不是一个量级。
给你一个可以直接套用的公式:
单次请求成本 =(输入token数 + 输出token数)÷ 1000 × 单价拿一个相当常见的商业模型价格举例(不同平台会变,但这个量级可以参考):假设输入每千token约0.002美元,输出每千token约0.006美元。套用之前那个电商客服项目:
- 改造前:平均每次请求输入8000token,输出300token。单次成本约(8000+300)/1000×0.002 + 300/1000×0.006 ≈ 0.0166 + 0.0018 ≈ 0.0184美元。一天十万次调用,一天成本约1840美元。
- 改造后:平均每次输入3500token,输出250token。单次成本约(3500+250)/1000×0.002 + 250/1000×0.006 ≈ 0.0075 + 0.0015 ≈ 0.009美元。同样十万次,一天成本约900美元。
单看一次调用差额不大,但乘以调用量之后,一个月就是几万美元的差距。所以context-mode不只是“让模型更好用”,它本身就是降本的核心手段。省钱的正道不是降低模型档位,而是让每一次请求只携带必要的信息。
6. 踩坑记录:Context-Mode实践中常见的五个坑
最后分享几个日常开发中真正能从你身上扒层皮的坑。有些坑翻车一次就够你记住一辈子。
6.1 上下文“中毒”问题
当模型拿到一段包含错误信息的历史记录时,它极有可能顺着错误继续往下说,而且语气越肯定,越让人信服。比如用户在上一轮说“我的订单显示签收了但我没收到”,模型如果没能正确区分“用户自述”和“系统事实”,就可能在后续回答中直接用了“订单已签收”这个错误前提。
防止中毒的办法主要有两个:一是在系统指令里明确区分信息源的可信度,例如“订单状态以系统数据为准,用户自述仅作为待核实信息”;二是对某些关键字段做独立的规则校验,不允许模型靠上下文里的“记忆”来回答订单状态,必须拉取系统接口实时数据。这类特定领域的规则约束,比任何花哨的prompt技巧都管用。
6.2 摘要失真导致的信息坍缩
前面讲递归摘要时提过信息坍缩,这里再补充一个更隐蔽的情况:摘要不是越短越好。有次我们为了提高压缩率,把摘要上限压得很低,结果用户最初提到的“预算两万”被压缩成了“预算有要求”,后面所有方案都偏离了实际能落地的范围。虽然单次请求token确实降了,但回答的可用性也降了。
后来我们给摘要加了一个保真度检查:摘要完成后,把摘要和原文同时发给模型,让它判断“摘要是否遗漏了原文中所有的具体数值和专有名词”。如果不达标,就重新摘要。这个二次校验会多消耗一些token,但比起整段回答作废,这点成本微不足道。
6.3 检索召回与拼接顺序对回答质量的干扰
RAG检索回来的片段若顺序排得不对,会让模型对信息之间的关系产生错误理解。比如关于“退换货政策”的片段排在“优惠券规则”前面,模型可能会把两者解释成同一个流程。
我的经验是:检索片段拼接时,严格按相似度得分从高到低排,同时在每个片段前加一行标注来源(例如[售后政策-第3条]),并在提示词里明确“如果片段之间信息冲突,以标注时间最新的为准”。这样的微调能让回答质量稳定不少,代码改动量却很小。
6.4 并发场景下的状态隔离
有个项目把整个会话上下文放在一个内存变量里,云服务器并发一高,A用户的订单号就跑到B用户的上下文里去了,客服那边差点把A用户的退款打到B用户的账户上,这是最典型也最要命的坑。
解决思路很简单:会话ID与记忆数据严格绑定,所有状态存Redis或者数据库,不要用进程内单例。每次组装prompt前先根据会话ID拉取对应的记忆对象,用完再写回去,整个过程要保持原子性。并发这块没有捷径,老老实实把状态外置,用分布式锁或者版本号控制写入冲突。
6.5 调试困难:如何重建一条可复现的上下文轨迹
最后这个坑针对开发调试。LLM的输出有随机性,同一个问题在不同的上下文甚至是相同上下文下,表现都可能不同。这导致很多bug你无法稳定复现,排查起来特别痛苦。
我们后期加了一个“上下文快照”日志,每次请求都完整记录:时间戳、会话ID、model版本、temperature、完整prompt拼装结果、模型原始输出。一旦用户报问题,直接从日志里拉出当时的快照,用相同的prompt和参数重新发送,虽然不能保证结果完全一致,但大部分定位都能靠这个追到根因。
不要小看这个动作,很多团队上线后出了质量问题,第一反应是“模型今天抽风了”,但几乎没有考虑过“是不是上下文拼错了一个字段”这类工程bug。
做context-mode这一路下来,我最深的体会是:你以为你在调模型,其实你在设计一套记忆系统。模型就像一个非常聪明但没有自主记忆的临时员工,你给它什么材料,它就基于什么材料工作。材料组织得好,它就是你见过的最靠谱的专家;材料组织得烂,它就是你见过的最自信的骗子。
如果你也正在做类似的大模型应用,建议别一上来就追逐更大的上下文窗口,先把已有代码里prompt的组装逻辑仔细看一遍,看看是不是每个token都在承载真正有价值的信息。很多时候,把“塞进去”变成“选进去”,效果和成本都会同时给你惊喜。