连续对话上下文怎么设计?

4 人参与

连续对话上下文设计,真正难的不是“把历史消息塞回模型”,而是判断哪些内容值得继续带着走。很多聊天应用一开始都采用最近 N 轮截断,写起来很快,但一旦用户从“帮我写活动方案”跳到“预算按 3 万重算”,再跳到“把语气改得像给老板汇报”,模型就容易丢掉约束:目标人群、预算、交付格式、语气边界,全混成一锅粥。

上下文不是聊天记录,而是决策材料

大模型的上下文窗口可以理解为一次推理时的“工作台”。工作台越乱,模型越容易抓错重点。OpenAI、Anthropic 等主流接口都采用 messages 结构,本质上是在区分不同来源的信息:system 定规则,user 提需求,assistant 给回应,tool 返回事实。

一个可靠的上下文通常分成四层:

  • 系统层:角色、禁止事项、输出格式、安全边界。
  • 任务层:当前用户到底要完成什么。
  • 记忆层:长期偏好,例如“用户偏好中文、喜欢表格、代码用 Vue3”。
  • 会话层:最近几轮对话中的临时约束,例如“预算 3 万”“面向 B 端客户”。

如果把这四类内容全混成一段长文本,短期能跑,复杂任务会慢慢失控。

最近 N 轮截断,只适合轻量场景

“保留最近 4 条”是最常见方案,适合客服寒暄、简单问答、个人玩具项目。它的优势是成本可控,缺点也明显:重要信息不一定出现在最近几条。

比如用户第 1 轮说“我是牙科诊所老板”,第 8 轮问“帮我设计复购短信”。如果只传最近 4 轮,模型可能写出通用电商短信,甚至出现“亲爱的会员,您的购物车还没结算”这种离谱文案。问题不在模型笨,而是上下文把行业身份弄丢了。

更稳的做法是:近期对话 + 摘要记忆 + 关键事实槽位

推荐的三段式上下文结构

实际工程里,可以把上下文整理成这样的结构:

  • Profile:用户稳定信息,如行业、技术栈、语言偏好。
  • Session Summary:当前会话摘要,控制在 200 到 500 字。
  • Recent Messages:最近 3 到 6 轮原始对话,保留语气和细节。

摘要不是简单压缩,而是提取可复用约束。比如:

用户正在为牙科诊所设计老客户复购短信,目标是预约洗牙,语气要专业但不推销,避免夸大疗效,预算信息无关。

这类摘要比十几轮原文更干净,也更省 token。以 8K 上下文模型估算,中文一轮长问答很容易占掉 800 到 1500 token;连续塞 20 轮,成本和延迟都会明显上升。

关键细节:别让模型自己猜“什么重要”

上下文管理最好不要完全交给模型临场判断。系统可以维护结构化状态,例如:

  • 用户身份:前端开发者
  • 当前项目:Vue 聊天应用
  • 当前目标:优化连续对话
  • 约束:不暴露 API Key、控制 token 成本、支持 Markdown

每次请求前,再把这些状态转成简短提示。这样用户说“按刚才那个方案改一下”,模型才知道“刚才那个方案”指的是上下文策略,而不是页面布局。

一个成熟设计的判断标准

好的连续对话上下文,用户不会感觉自己在“提醒一个健忘同事”。他改预算、换语气、追加格式要求,系统都能接住;但当他开启新话题,旧约束又不会阴魂不散地冒出来。

说白了,上下文设计不是越长越聪明,而是越会取舍越像人。模型负责生成,应用负责记性;这活儿分清了,聊天体验才不会一边烧 token,一边装糊涂。

参与讨论

4 条评论
  • 月影术士

    这思路不错,上下文得筛选,不能全塞。

  • 寂默

    之前搞过类似,全丢进去token爆炸,后来也是分层才稳住。

  • 冷面笑匠

    摘要记忆会不会把重要细节也丢掉啊?

  • 霓裳贵嫔

    道理都懂,但实际写代码的时候还是懒得搞这么细。