从刚接触大模型应用那会儿开始,我一直被一个问题反复折磨:聊天机器人聊着聊着就“失忆”,可一旦我把所有历史记录全部塞给模型,它又变得又慢又贵,甚至会翻出早该过期的信息来自作聪明。这个“给多少上下文、怎么给、什么时候给”的分寸感,后来我才知道业内管它叫 context-mode,也就是上下文模式。它不是什么高深算法,而是一套有明确规则的上下文管理策略:什么时候保留、什么时候截断、什么时候压缩成摘要、什么时候去检索外部知识,并以可枚举的运行模式固化下来。这篇文章我想把这些年实现和调优 context-mode 的完整思路、代码结构和踩坑记录整理出来,给正在做对话机器人、AI Agent 和 RAG 应用的朋友一份可以直接上手的参考。
1. 先把问题看清楚:context-mode 到底在解决什么
1.1 一次“客服失忆”事故引发的改造
最早我做了一个客服问答机器人,最初的版本非常天真:每次用户提问,就把这个会话从第一条消息开始的所有内容原封不动拼进 prompt。测试的时候一切正常,因为测试对话就那么三五轮。上线一周之后,用户开始在群里反馈“它怎么连我半小时前说的收货地址都给忘了”,“我之前明明说不要拆包装,它又让我自己包好退回去”。
我去翻了日志,发现真相令人哭笑不得:模型并没有忘,是我把输入框塞满了。当一轮会话累积到七八十条消息时,token 数已经逼近模型上下文窗口上限,我的代码逻辑是“超了就截断最后十轮”,结果用户早先提供的地址、偏好、订单号全部被截掉了。模型表现出的“失忆”,是上下文管理策略的失败,而不是模型本身的问题。
这个事故让我意识到一个关键点:上下文不是“有”或者“没有”的二元问题,而是需要一套分场景、分阶段的管理模式。所谓 context-mode,本质上就是把“如何处理上下文”这件事变成可配置、可切换、可监控的模式集合。
1.2 三个边界条件,决定了你不得不做上下文管理
为什么不能永远走“全量塞进去”的简单路线?因为有三个硬约束,任何做生产级应用的人都绕不开。
第一个是上下文窗口的物理上限。模型能处理的 token 数量存在天花板,今天的主流商用模型窗口虽然从几千扩展到了几十万甚至更多,但窗口再大也不是无限大。更关键的是,即便窗口足够大,你的业务会话也可能比窗口更长。靠窗口硬扛,等于把产品上限绑定在模型参数上。
第二个是成本和延迟。Attention 机制的复杂度随序列长度增长,输入 token 越多,每次请求的延迟越高、费用越贵。我在项目里统计过,一个窗口使用率 80% 的会话,单轮请求耗时比 20% 时翻了一倍不止,而成本几乎是线性上涨。在真实业务里,延迟每增加 500ms,用户流失率就肉眼可见地上升。
第三个是信息生命周期的差异。有些信息是临时的,比如“用户当前正在浏览哪个页面”;有些是这个会话内必须记住的,比如“用户选好了黑色、45码”;有些则是要长期沉淀的,比如“该用户常买某品牌”;还有根本不进上下文的,比如产品知识库里的标准化条款。把所有信息都丢进同一个上下文窗口,本身就是一种信息管理上的偷懒。
这三个边界条件共同决定了:上下文管理模式不是“锦上添花的优化”,而是保证产品可用性的基本门槛。你能把多少信息塞进窗口、能维持多久的记忆、能在什么成本下运行,全都由 context-mode 的规则设计决定。
2. 我常用的五种 context-mode 运行形态
context-mode 落到工程上,通常表现为几种相对固定的运行形态。我在不同项目里轮着用过,这里按“信息保留强度”从强到弱做个拆解。
2.1 全量上下文模式:最省心,也最贵
全量模式就是最朴素的做法:把当前会话的全部原始消息按顺序拼进 prompt。它适合短会话、一次性任务、或者那些每一条信息都不能丢的场景,比如法律咨询、医疗预问诊,这类场景里哪怕漏一条用户陈述都可能出问题。
但全量模式有一个副作用很多人没意识到:上下文里信息越多,模型对每条信息的注意力权重就越平均,关键信息反而容易被淹没。我做过对比测试,同样一个用户需求,塞入 3 条历史消息时模型能正确执行,塞入 30 条之后反而开始犹豫甚至答非所问,因为噪音太多了。所以全量模式从来不该是默认选项,它只适合明确知道自己“会话很短”的场景。
2.2 滑动窗口模式:用最近对话换短期记忆
滑动窗口是最容易理解的折中方案:只保留最近 N 轮对话,更早的全部丢弃。N 可以是固定条数,也可以按 token 阈值计算。这种模式适合“用户当前意图与最近对话强相关”的场景,比如客服对话里用户在描述报错现象,最近三五轮包含了最核心的信息。
滑动窗口的优点是实现极其简单,几乎不需要额外逻辑。但它的致命弱点在于没有“记忆分层”,窗口中所有消息被一视同仁地对待。早期我在技术论坛场景里用滑动窗口,发现用户两周前提过的“我买过某某设备”这种关键背景,一旦被滑出窗口,模型就会给出完全脱离用户情况的建议,体验非常割裂。所以滑动窗口只能作为基础层,不能单独作为完整方案。
2.3 摘要舍入模式:把历史压缩成结构化摘要
摘要舍入是我在生产里最常用的一种模式,它的核心思路是:不保留全部历史原文,而是定期把旧对话压缩成一段结构化摘要,再在每次请求时把“摘要 + 最近原文”一起喂给模型。
举个具体例子:假设一个客服会话进行到 60 轮,我设定每 10 轮做一次摘要。第 1-10 轮会被压缩成类似“用户已提供订单号:XXX,问题:商品破损,诉求:换货,紧急程度:高”这样的结构化文本。之后第 11-20 轮进来,上下文变成“摘要(1-10) + 原文(11-20)”,以此类推。这样窗口里永远只保留一份摘要和最新的少量原文,既保留长期关键信息,又控制 token 量。
摘要模式的难点在于摘要质量。普通摘要很容易丢掉关键数字、否定表述、以及用户语气中隐含的偏好。我后面在踩坑部分会专门讲这个问题,这里先提醒一句:摘要不是让模型自由发挥“总结一下”,而是要设计一套固定字段模板,让它逐字段提取,最大程度减少信息丢失。
2.4 检索增强模式:把长期记忆交还给知识库
检索增强模式,也就是 RAG 思维在上下文管理里的应用:把历史信息和知识库提前切块、向量化存储,每次请求先做语义检索,只把最相关的若干块拼进上下文。
这种模式的适用场景很明确:用户的长期偏好、历史订单、浏览记录,这些信息量太大、又不需要全部进入窗口。比如一个购物助手,用户过去一年的订单可能有几百条,全部塞进窗口既不现实也没必要;但如果用户问“我上次买的那瓶香水叫什么味道”,系统可以检索“香水、上次、购买记录”相关向量,只取出对应订单记录喂给模型,既精准又便宜。
检索增强模式的问题在于,检索结果的质量直接决定回答质量,而语义检索偶尔会把毫不相关但措辞相似的内容召回进来,形成噪声。这个问题我在第 5 节“上下文污染”里会展开讲,它是 RAG 类项目上线后最隐蔽的坑之一。
2.5 分层混合模式:生产环境的常见选择
成熟的 production 系统,几乎不会只用单一模式,而是把上面几种组合成分层结构。我目前的主力架构是:
- 第一层:固定系统提示词 + 当前用户输入,这部分永远保留;
- 第二层:最近 10 轮原文,用滑动窗口控制;
- 第三层:整段会话的结构化摘要,用摘要舍入维护;
- 第四层:按需检索回来的外部知识片段,用检索增强控制。
每一层就像是带存储的不同层级的记忆系统——L1/L2 缓存(最近原始数据)、L3 缓存(压缩摘要)、主存储(向量数据库)。这样设计的好处是,每层的淘汰策略可以独立调优,比如窗口大小改了不影响摘要,摘要频率改了不影响检索。下面用一个表把这五种形态的关键差异列出来,方便你做选型:
| 模式 | 信息保留强度 | 成本与延迟 | 实现复杂度 | 适用场景 |
|---|---|---|---|---|
| 全量上下文 | 最强,无丢失 | 最高 | 最低 | 短会话、信息零容忍场景 |
| 滑动窗口 | 只保留最近 | 较低 | 低 | 强近期意图场景 |
| 摘要舍入 | 中等,经压缩 | 中 | 中 | 中长客服会话、任务型对话 |
| 检索增强 | 按需召回 | 低-中 | 高 | 长期记忆、知识库问答 |
| 分层混合 | 强,按层管理 | 中-高 | 高 | 生产级 Agent、复杂对话 |
3. 把 context-mode 落到代码:处理管线、状态机与存储结构
模式讲清楚了,代码层面怎么落地?我不会直接贴一个框架级的完整代码,因为每个后端语言和模型 SDK 都不一样,我把最核心的三个环节拆开讲,你拿到自己项目里就能对上号。
3.1 一条完整的上下文处理管线
无论用什么技术栈,context-mode 的处理逻辑都可以抽象成一条固定管线,我给它起了个名字叫“五段式管线”:
- 输入接入:收到用户新消息,把它和当前会话 ID 绑定;
- 状态读取:从存储里取出该会话当前的模式状态、消息记录、摘要块、检索索引;
- 策略裁决:根据会话长度、token 用量、时间间隔等信号,决定本次是用滑动窗口、触发摘要、还是执行检索;
- 上下文组装:按决策结果,把系统提示、摘要、窗口内原文、检索片段拼接成最终 prompt;
- 后处理与持久化:拿到模型输出后,更新消息记录、必要时追加摘要、更新索引。
这个管线里最容易出错的是第 3 步的“策略裁决”写成了硬编码的一堆 if else。比如“if 会话超过 20 条消息就做摘要”,这样写短期内没问题,但一旦业务复杂起来,条件之间会互相打架:超长会话既满足摘要条件又满足检索条件,到底先执行哪个?所以我在这一步通常不直接写死逻辑,而是引入一个轻量的规则引擎或者状态机,把“模式切换”当成系统的核心状态来管理。
3.2 用状态机管理模式切换
我把 context-mode 的每种模式定义成状态机中的一个状态,状态之间的迁移由事件触发。这套设计让模式的切换变得非常可控,而且天然支持可视化排查。
class ContextMode(Enum): FULL = auto() # 全量模式 SLIDING = auto() # 滑动窗口模式 SUMMARY = auto() # 摘要舍入模式 RETRIEVAL = auto() # 检索增强模式 MIXED = auto() # 分层混合模式 class ContextStateMachine: def __init__(self): self.mode = ContextMode.FULL def transit(self, event: str, session_metrics: dict) -> ContextMode: # 事件示例:message_arrived, window_full, summary_ready, retrieval_hit if event == "message_arrived": if session_metrics["total_tokens"] > 4000: self.mode = ContextMode.MIXED elif session_metrics["message_count"] > 50: self.mode = ContextMode.SUMMARY elif event == "retrieval_hit" and self.mode in (ContextMode.SLIDING, ContextMode.SUMMARY): self.mode = ContextMode.MIXED return self.mode实际生产里我不会把迁移规则全部埋在代码逻辑里,而是把它们抽成 JSON 配置,这样产品和算法同学也能调整。比如上面 4000 token 和 50 条的阈值,就放在配置中心里动态下发,不用发版就能调参。
3.3 存储结构与关键记录
context-mode 的存储设计直接决定了系统能支撑多复杂的会话。我的存储结构通常分三张表(或三个集合):
第一张是消息表,存储所有原始消息,包含字段:session_id、message_id、role、content、tokens、created_at、summary_round。其中 summary_round 字段表示这条消息属于第几轮摘要周期,方便后续回溯清理。
第二张是摘要表,存储每个会话的分段摘要,包含字段:session_id、round_start、round_end、summary_text、keywords、critical_entities(关键实体,比如订单号、名字)、expired_at。这里我把“关键实体”单独抽出来存,是为了防止摘要压缩时把最关键的实体弄丢。
第三张是向量索引表,如果在用检索增强模式,就需要把消息、摘要、知识库片段都切块 embedding 后写入向量库,每条记录带 metadata——source_type(是用户历史还是知识库)、session_id、created_at 等。检索的时候可以按 metadata 过滤,避免跨会话串数据。
3.4 最小可运行的伪代码
把管线、状态机、存储逻辑合在一起,最小实现大概长这样:
def build_context(session, user_input, knowledge_retriever): # 1. 读取当前会话 mode = state_machine.transit("message_arrived", session.metrics()) # 2. 准备各层上下文 system_prompt = "你是合格的客服助手,回答简洁专业。" recent_messages = session.last_messages(k=10) # 滑动窗口 summary = session.current_summary() # 结构化摘要 # 3. 策略:是否需要检索 retrieval_chunks = [] if mode in (ContextMode.RETRIEVAL, ContextMode.MIXED): retrieval_chunks = knowledge_retriever.search(user_input, top_k=3) # 4. 组装最终 prompt final_prompt = "\n".join([ system_prompt, f"[会话摘要]\n{summary or '无'}", f"[历史消息]\n{recent_messages}", f"[参考知识]\n{retrieval_chunks}", f"[当前问题]\n{user_input}", ]) return final_prompt, mode这段伪代码省略了 token 预算校验和摘要触发逻辑,真实环境中,组装完 prompt 后一定要做一次 token 计数,如果超限,需要按优先级取舍:先丢最老的原文,再丢检索片段,最后才动摘要。
4. 参数选型:context-mode 的核心参数应该怎么定
模式框架搭好以后,真正拉开差距的是参数。context-mode 里高频出现的核心参数没有几个,但每个参数之间的耦合关系,初期很容易被人忽略。我按“先用直觉设初值,再用线上数据回测”的思路来给你拆解。
4.1 五个高频参数及直觉含义
| 参数 | 含义 | 我的常用初值 |
|---|---|---|
| max_window_tokens | 最近原文最大 token 预算 | 2000-4000 |
| summary_interval | 每多少轮触发一次摘要 | 10-15 轮 |
| summary_max_tokens | 摘要块的最大 token 上限 | 500-800 |
| retrieval_top_k | 检索增强召回的片段数量 | 3-5 |
| stale_threshold | 信息过期时间,超过则降权或丢弃 | 30-60 分钟 |
先说 max_window_tokens。这个值不是拍脑袋定的,而是看你的业务在“最近几轮”里到底需要多少信息。我做过一个测试:客服对话中超过 83% 的意图判断,只需要最近六轮对话;超过 95% 的场景,最近十轮已经够了。所以我的窗口预算通常按“十轮平均 token 数 x 1.2”来设置,既能覆盖绝大多数场景,又不会给太多噪声。
再说 summary_interval。这个值取决于两件事:一是模型的摘要能力稳定性的经验阈值,二是 token 成本。摘要太频繁会浪费调用次数,太稀疏又会导致摘要块过大、超预算。我常用的规则是“窗口预算即将耗尽时触发”,而不是固定按轮数。比如 max_window_tokens 设为 3000,当“当前窗口 token 数 + 新消息 token 数”超过 3000 的 85% 时,就把最老的一批未摘要消息压缩进摘要块,同时清空对应的原文。
4.2 成本估算公式,别让模式把你烧穷
估算 context-mode 的成本,要有一个固定的计算思维。每次请求的输入 token 数可以这样估算:
总输入 token = 系统提示词 token + 摘要块 token + 窗口原文 token + 检索片段 token 费用 = (总输入 token / 1000) × 每千 token 单价 + 输出 token 费用以一个真实项目为例:系统提示词约 300 token,摘要约 600 token,最近窗口约 3000 token,每次检索召回约 1000 token,那么每次请求输入约 4900 token。如果日均请求 10 万次,按商用模型每百万输入 token 约 15 元估算,一天的输入成本约 7350 元;如果换成全量模式,会话平均 2 万 token,同样的请求量成本会直接跳到 3 万元一天。
这里容易被忽略的是摘要本身也是一次模型调用,也有成本。每 10 轮触发一次摘要,假设会话平均 50 轮,那就是 5 次摘要调用,这些都要计入单会话总成本。我做成本报表时会把“摘要触发率”单列一个监控指标,防止线上摘要调用过多悄悄烧钱。
4.3 我的一个落地方案参数配置
这里分享一下我在一个电商客服 Agent 上的最终配置,供参考:
{ "mode": "mixed", "system_prompt_tokens_max": 500, "window": { "max_tokens": 3200, "max_rounds": 10, "evict_policy": "oldest_first" }, "summary": { "trigger": "token_budget_percent >= 85", "max_tokens": 700, "fields": ["order_id", "sku", "issue_type", "user_requirement", "pending_action"], "model": "fast_summary_model" }, "retrieval": { "enabled": true, "top_k": 4, "min_score": 0.55, "metadata_filter": {"session_id_only": true} }, "stale": { "threshold_minutes": 45, "action": "dropped_from_window_kept_in_summary" } }这个配置文件里我特别想强调 min_score 这个参数。检索召回结果如果相关度分数太低,宁可不用,也不要硬塞进上下文。很多 RAG 项目效果差,不是因为知识库内容不行,而是把一堆低相关度的片段强行拼进去,模型被无关信息干扰,最后生成了似是而非的答案。min_score 设为 0.55 是我在多个数据集上调出来的折中值,太低容易混入噪声,太高又会漏掉真实相关的信息。
5. 上线后的坑:我在生产环境踩过的五个典型问题
框架和参数都定好了,不代表就能平稳运行。context-mode 的坑大多不是一上来就爆炸的,而是随着对话轮数增长、场景增多慢慢累积出来的。我把自己踩过的最典型的五个问题列出来,每一个都经历了从怀疑人生到定位到修复的过程。
5.1 上下文污染:检索内容把模型结论带偏
这是 RAG 类模式最容易踩的坑。我的知识库里有一条关于退换货政策的文档,里面写了“食品类商品不支持无理由退换”。但用户问的是“我买的保健品能不能退”,语义检索召回的片段里既有“保健品”又有“退换”,于是模型直接判定不能退。实际上用户购买的是保税仓直发的保健品,属于“质量问题可退、无理由不可退”的特殊品类。检索片段里的“食品”被模型过度泛化,造成了错误结论。
排查链路是这样的:先在日志里查看最终 prompt,发现模型确实拿到了检索片段。然后手动计算片段的向量相关度分数,发现“保健品”和“食品”在语义空间确实很近,top 4 里有两段是关于食品政策的。问题不在模型,而在检索召回策略。修复方案是双管齐下:第一,给知识库文档打业务标签,检索时增加品类过滤条件;第二,把 min_score 从 0.5 提高到 0.6,低于阈值的片段直接丢弃。修复后这类误判率下降了大约四成。
这里我总结出一个原则:检索回来的内容必须来源清晰、字段可追溯,不能让模型把“参考知识”当成“用户给的确定事实”。我会在 prompt 里明确标注检索片段的来源和更新时间,并加一句“以上知识仅作参考,如果与用户描述冲突,请以用户最新陈述为准”。这一句看似简单,但对抑制上下文污染非常有效。
5.2 摘要舍入吞掉了关键数字与专有名词
摘要模式上线后,我又遇到一个奇怪现象:用户明明在会话早期报过订单号“PO-20241108-0023”,聊了半小时后模型却回复“请提供您的订单号”。日志显示摘要里根本没有这个订单号。我去看了摘要模型生成的文本,发现它把订单号压缩成了“用户的订单号”,完全丢失了实体本身。
这让我意识到,不能把摘要完全交给模型的“自由意志”。我的修复方案有两层。第一层是在摘要指令中强制要求“必须原样保留并显式列出关键实体字段”,我把订单号、人名、数字、地址、日期、否定词列为强制提取字段,任何情况下不得省略。第二层是在代码层面加兜底:摘要生成后,用正则和实体解析脚本把原文中的关键实体抽出来,如果摘要里缺失,就自动追加到摘要末尾。这套“模型生成摘要 + 规则兜底实体”的方案,后来成了我做 context-mode 的标准做法。
5.3 过期信息未衰减,多轮对话“翻旧账”
第三个坑来自信息的时间特性。某个会话里用户在第 2 轮说过“我想买蓝色”,但聊到第 30 轮时用户明确改口“还是黑色吧”。由于滑动窗口很小,第 2 轮的内容早就进了摘要块,摘要里同时存在“蓝色”和“黑色”两个历史偏好。模型看到两个矛盾信息,有时候会默认采用最早的那条,结果推荐了蓝色。
这个问题的本质是上下文里缺少“信息时效性”的标注。我的修复方案是:在摘要表里给每条关键实体加上 created_at 和 updated_at 字段,组装 prompt 时,同一实体会保留最新一条,并显式标注“用户在 HH:MM 更新了颜色偏好为黑色”。这样模型就非常清楚该信哪条。同时我在 stale_threshold 参数上设了 45 分钟,超过这个时间且未更新的低优先信息,直接从窗口丢弃,只保留在摘要中作为背景。
5.4 模式切换的边界条件没定义好,状态机乱跳
第四个坑是工程层面的。早期我用简单的 if-else 控制模式切换,条件多了以后发现状态经常跳来跳去:一会是全量,一会是滑动窗口,用户发一条消息就可能触发摘要,下一轮又触发了检索,最后 prompt 结构极不稳定,回答质量也跟着忽高忽低。
排查后发现,根因是切换条件之间存在竞争关系,且没有“稳定优先”的设计。比如消息一多,摘要触发条件和检索触发条件同时满足,代码里哪个写在前面就执行哪个,但用户的实际对话意图变化并不需要那么频繁地切换模式。修复方案是在状态机里加了两个约束:一是冷却时间,同一个会话在 10 分钟或 5 轮对话内不允许频繁切换模式;二是切换优先级,摘要 > 检索 > 滑动窗口,摘要一旦触发,本次请求不再触发检索,避免一次请求同时做两件耗时操作。
5.5 上下文模式的调试复现难:必须留痕
最后这个坑,准确说不是功能 bug,而是排障效率问题。context-mode 是高度依赖上下文的系统,同样的用户输入,在不同会话状态下回答可能完全不同。早期我排查线上问题时,只记录了模型最终输出,没有记录它当时的完整上下文,导致“这个回答为什么这么奇怪”完全无法复现。
后来我的日志规范是:每次请求都记录三个东西——session_id 对应的完整 prompt 原文、当时的模式状态(是哪种 context-mode 以及触发原因)、以及关键参数快照。这三个数据存入单独的 debug 日志表,随时可以回放。这个习惯帮助我解决了前面四个坑中的至少三个,因为排查的第一步永远是“看它当时到底看到了什么”。
6. 评估与上线:怎么判断你的 context-mode 合格了
context-mode 调优到什么程度可以上线?这个问题不能靠感觉回答。我给自己定了一套评估维度,每次调整模式或参数,都拿固定的测试集跑一遍对比,用数据说话。
6.1 五个评估维度,缺一不可
第一是准确性,就是模型输出是否正确回应用户意图。这个维度要在固定测试集上跑,测试集里要专门准备“需要回溯早期信息”的题目,比如“我 20 轮前提到的订单号是多少”“我之前说不要拆包装,现在还要遵守吗”。
第二是遗忘率,也就是用户明确提供过的信息,在后续轮次里被模型忽略或反问的比例。这个指标最容易暴露摘要问题和过期信息问题。
第三是延迟,也就是从用户发消息到收到回复的时间。上下文越长,延迟越高。我会监控 P95 延迟,而不是平均值,避免被少数超短请求拉低。
第四是成本,即单会话平均 token 消耗和单日总成本。摘要触发率、检索调用率都要纳入成本看板。
第五是可解释性,也就是当回答出错时,你能否快速定位是检索召回错了、摘要丢了信息、还是窗口截断导致。这个维度看起来偏管理,实际上决定了排障速度。
6.2 拟合测试、对抗测试和回归基线
我用来验证 context-mode 的测试方法有三类。第一类是真实会话回放,把历史线上会话重新用新参数跑一遍,对比新旧输出。这个成本低、见效快,能快速发现参数改崩的情况。
第二类是对抗测试,专门设计一些刁钻场景去“折磨”上下文模式:超长会话(100 轮以上)、用户中途改口、早期信息和最新信息冲突、多个相似订单并存、用户用简称指代前文提到的长名称。这些场景能非常好地暴露问题。
第三类是回归基线。每次改参数或逻辑,我会在同一组测试集上重新跑,把结果和上一次对比,记录哪些问题修复了、哪些新问题引入了。没有基线对比的调优,基本等于盲调。
6.3 我从项目里总结的经验法则
最后分享几条经验法则,每条都是在真实项目里交了学费换来的。
第一,永远把“用户最新意图”的优先级排到最前面。不管摘要里记了什么、检索到了什么,只要用户在当前消息里明确表达了新的意向,你就要让模型学会“听最新的话”。我所有 prompt 组装逻辑里都会加一句“最新用户消息优先于历史摘要和参考知识”。
第二,摘要字段模板比摘要模型更重要。与其花大力气调一个聪明的摘要模型,不如先把强制字段设计好。字段定了,摘要质量的下限就有了保证。
第三,context-mode 的参数不是调一次就完事。会话长度分布是动态变化的,业务旺季用户聊天轮数会变多,摘要触发阈值就要跟着调整。我建议把关键参数放进配置中心,每周看一次指标报表,随时微调。
第四,不要为了“省 token”牺牲关键信息。token 节省的目标应该放在裁剪噪声上,而不是裁剪关键实体。剪错一条订单号导致的客诉和售后成本,远超省下的那几厘钱 token 费。
如果你现在刚开始设计自己的 context-mode,我给你的第一个建议不是急着调参数,而是先认真想清楚:你的应用里,哪些信息必须在短期记忆内、哪些必须长期保留、哪些可以直接忘掉。把这三类信息划出一条清晰的边界,再动手搭模式框架。模式这东西看着是技术题,本质上是信息管理的产品题,想透了边界,技术实现都是水到渠成的事。