连续对话上下文设计,真正难的不是“把历史消息塞回模型”,而是判断哪些内容值得继续带着走。很多聊天应用一开始都采用最近 N 轮截断,写起来很快,但一旦用户从“帮我写活动方案”跳到“预算按 3 万重算”,再跳到“把语气改得像给老板汇报”,模型就容易丢掉约束:目标人群、预算、交付格式、语气边界,全混成一锅粥。
大模型的上下文窗口可以理解为一次推理时的“工作台”。工作台越乱,模型越容易抓错重点。OpenAI、Anthropic 等主流接口都采用 messages 结构,本质上是在区分不同来源的信息:system 定规则,user 提需求,assistant 给回应,tool 返回事实。
一个可靠的上下文通常分成四层:
如果把这四类内容全混成一段长文本,短期能跑,复杂任务会慢慢失控。
“保留最近 4 条”是最常见方案,适合客服寒暄、简单问答、个人玩具项目。它的优势是成本可控,缺点也明显:重要信息不一定出现在最近几条。
比如用户第 1 轮说“我是牙科诊所老板”,第 8 轮问“帮我设计复购短信”。如果只传最近 4 轮,模型可能写出通用电商短信,甚至出现“亲爱的会员,您的购物车还没结算”这种离谱文案。问题不在模型笨,而是上下文把行业身份弄丢了。
更稳的做法是:近期对话 + 摘要记忆 + 关键事实槽位。
实际工程里,可以把上下文整理成这样的结构:
摘要不是简单压缩,而是提取可复用约束。比如:
用户正在为牙科诊所设计老客户复购短信,目标是预约洗牙,语气要专业但不推销,避免夸大疗效,预算信息无关。
这类摘要比十几轮原文更干净,也更省 token。以 8K 上下文模型估算,中文一轮长问答很容易占掉 800 到 1500 token;连续塞 20 轮,成本和延迟都会明显上升。
上下文管理最好不要完全交给模型临场判断。系统可以维护结构化状态,例如:
每次请求前,再把这些状态转成简短提示。这样用户说“按刚才那个方案改一下”,模型才知道“刚才那个方案”指的是上下文策略,而不是页面布局。
好的连续对话上下文,用户不会感觉自己在“提醒一个健忘同事”。他改预算、换语气、追加格式要求,系统都能接住;但当他开启新话题,旧约束又不会阴魂不散地冒出来。
说白了,上下文设计不是越长越聪明,而是越会取舍越像人。模型负责生成,应用负责记性;这活儿分清了,聊天体验才不会一边烧 token,一边装糊涂。
参与讨论
这思路不错,上下文得筛选,不能全塞。
之前搞过类似,全丢进去token爆炸,后来也是分层才稳住。
摘要记忆会不会把重要细节也丢掉啊?
道理都懂,但实际写代码的时候还是懒得搞这么细。