聊到第五六轮时模型不再提第一轮给过的条件,先别急着换模型或把提示写得越来越长。要分清是两类问题:一类在会话侧——历史消息根本没被拼进这一轮请求;另一类在提示侧——历史带上了,但关键条件被后面几轮内容淹没,或者「它」「上面那段」这类指代让模型挑错了对象。这两类在会话记录里的表现不一样,判断顺序建议是先按轮次定位第一处不再引用前文条件的回合,再决定往会话侧还是提示侧查。
多轮对话丢前文通常不是单一原因。先用带轮次编号的记录,找出第一处不再引用前文关键条件的回合:如果某轮起携带的历史条数不再递增或会话标识变了,偏向会话没续上;如果历史一直在、只是模型不再引用,偏向提示没约束住。把关键条件在当前轮原样复述一遍再重跑,条件被重新引用就按提示侧处理,仍不引用再回头核会话标识。这些只是定位手段,结论要结合你所在环境的请求日志确认。
在会话记录里找出第一处答非所问的回合
凭感觉说「聊到第五轮它就忘了」不太可靠,因为记忆衰减和指代误解在感受上很像。可行的做法是给每一轮编号,并记下这一轮回答里有没有引用到前面某一轮给过的具体条件。字段不用多:轮次、本轮你发出的条件、模型回答是否引用该条件、本次请求携带的历史条数、备注。跑一次完整对话,把表填满,第一处「否」就是丢失的实际发生点。
轮次 | 本轮条件 | 回答是否引用该条件 | 携带历史条数 | 备注
1 | 预算上限 5000 | — | 0 | 首轮
2 | 沿用第 1 轮条件 | 是 | 1 |
3 | 沿用第 1 轮条件 | 是 | 2 |
4 | 沿用第 1 轮条件 | 否(首次) | 3 | 从这里起不再提 5000
5 | 沿用第 1 轮条件 | 否 | 4 |
判读时看两列的关系:如果首次未引用出现在历史条数明显偏小的那一轮,先怀疑会话侧;如果历史条数一路正常递增、回答却从某轮开始不再提关键条件,先怀疑提示侧。这个表本身不是结论,只是把「第几轮开始丢」从体感变成可核对的行。
把关键条件在每轮提示里原样复述再测
这一步是为了区分「模型没拿到前文」和「拿到了但没被约束住」。做法是同一段对话跑两遍,只改一个变量:第二遍在当前轮末尾把第一轮的条件原文粘回来。其余措辞、轮次顺序尽量保持一致,否则对照不成立。
(当前轮)
问题:把方案改成按季度排期。
约束:本题仍按第 1 轮给出的条件执行——
「预算上限 5000,交付周期不超过两周,不含硬件采购」。
观察指标只有一个:回答里有没有重新出现并遵守这条条件。复述后重新引用,说明历史很可能在,只是没被约束住,处理方向是每轮把关键条件显式带上;复述后依然不提,甚至回答里出现与条件冲突的内容,那更可能是历史没进请求,接着去看会话标识那一步。
把指代词替换成具体名称后重问
很多「丢前文」其实是指代不明造成的误解:模型不是忘了,而是把「它」「上面那段」指到了别的对象上。改写时把代词换成具体名称,其余不变,然后对照两次回答的差异。
改写前:它能不能再便宜点?
改写后:方案里的服务器采购部分,能不能压到 3000 以内?
记录方式:
改写前回答要点 → 指向了哪个对象、给了什么结论
改写后回答要点 → 指向了哪个对象、给了什么结论
如果改写后回答立刻回到你要的那条线上,说明问题出在指代,不需要动会话配置;如果改写后还是答非所问,再回到前一步核对会话侧。
核对每轮请求里的会话标识是否连续
这一步用来排除会话被拆成多段、导致前文对新请求不可见。核对方法很简单:逐轮比较请求里携带的会话标识是否一致,以及历史消息条数是否随轮次递增。字段名各客户端不一样,含义是固定的,按你自己的接入替换即可。
通用请求骨架(字段名按你的客户端替换)
{
"会话标识": "同一段对话内每轮应保持一致",
"历史消息": [
{"角色": "用户", "内容": "第 1 轮的内容"},
{"角色": "模型", "内容": "第 1 轮的回答"},
{"角色": "用户", "内容": "第 5 轮的内容"}
]
}
判断方式:若某轮起会话标识变了,说明中途另起了会话,前文本来就不该可见;若标识没变但历史条数停止增长,说明拼接环节没把上一轮追加进去。两种情况都属于会话侧问题,改提示解决不了。
定一份长对话的上下文携带约定
零星修好一次,下次同类场景还会再丢。建议在项目里定一份约定,写清楚三条:关键条件每隔若干轮原样复述一次,轮数按你的任务长度定;所有指代在发出前替换成具体名称,避免「它」「上面那段」直接进入请求;历史超过一定长度时,先做一次摘要再带入,把长列表压缩成结论性的几条,并在摘要里保留关键条件原文。约定落在哪一层(客户端拼接、还是业务代码统一封装)按你的环境定,但要有地方能查,否则下次排查又从零开始。