连续几轮交互后画面越来越不像最初要的东西,先不要急着改提示词。X2.0 这类连续交互场景里,跑偏通常有两个来源:一是提示在轮次之间被改写、截断,或者本轮新增的约束没有累积进下一轮(提示漂移);二是上一轮的画面状态——参考图、种子、画幅、掩码、历史摘要——在第 N 轮没有被正确带下去(状态丢失)。两者在结果上很像,改法却完全不同:一个要改提示的拼接和压缩方式,一个要改状态透传和会话存储。比较快的做法是按轮次记录、核对下发日志、跑两组对照,把两个因素拆开验证。
先用一条固定提示连跑多轮,看偏离是否随轮次累积:逐轮加重更像提示漂移,第 2、3 轮就崩更像状态没接上。再在每轮请求里打印提示全文和状态字段,确认参考图标识、种子、历史摘要有没有缺项或被长度限制截断。最后做两组对照——每轮重发完整提示、每轮只发本轮增量——看差异落在主体结构变形还是风格颜色渐变。这套判断只适用于能拿到请求日志或接入配置的情况;拿不到日志时只能粗略推测,需要结合环境确认。
固定提示只改轮次,确认跑偏是否随轮次累积
第一步只回答一个问题:偏离跟轮次有没有关系。把提示固定成一句完整的画面约束,例如“同一人物、同一构图、正面半身、白色背景、无文字”,中间不插入“再亮一点”“稍微换个角度”这类增量词,其它参数尽量不动,连续跑 5 到 8 轮,每轮只改轮次编号。每轮结束后记一行,用自己的话描述画面和目标差在哪,不要写“变差了”这种无法对比的描述。
| 轮次 | 实际下发提示是否改动 | 是否带上一轮参考图/种子 | 画面与目标偏离表现 | 偏离类型 |
|---|---|---|---|---|
| 1 | 否 | 是 | 记录首轮基准,作为对照起点 | — |
| 2 | 否 | 是 | 如“构图保持、背景开始变灰” | 风格渐变 / 结构变形 |
| 3 | 否 | 是 | 如“主体轮廓仍在,色调继续偏离” | 同上 |
| 4 | 否 | 是 | 如“人物姿态改变,背景接近原目标” | 结构变形 |
| 5 | 否 | 是 | 记录是否继续恶化或趋于稳定 | — |
读这张表时看三条:偏离在第 2、3 轮就明显出现、之后基本不再加重,优先怀疑状态传递,多半是首轮状态没接上或第 2 轮断链;偏离逐轮累积、越往后越不像,优先怀疑提示或历史摘要的累积方式;偏离每轮无规律波动,先排除采样随机性和画幅尺寸变化,再谈漂移。
在每轮请求里记录实际下发的提示和状态字段
“我以为发出去的”和“实际发出去的”经常不是一回事。在构造请求的地方加一段打印,把每轮提示全文和状态字段一起落日志。下面是一段通用接入骨架,字段名是占位,按你们实际接口改名;放在客户端构造 payload 的位置或服务端入口都能用。
def build_turn_payload(turn_index, user_input, state):
payload = {
'model': 'x2.0', # 占位,按实际接入改
'turn_index': turn_index,
'prompt': user_input,
'state': {
'ref_image_id': state.get('ref_image_id'), # 上一轮输出或参考图标识
'seed': state.get('seed'),
'size': state.get('size'),
'mask_id': state.get('mask_id'),
'history_digest': state.get('history_digest'), # 历史摘要或完整历史
},
}
log = {
'turn': turn_index,
'prompt_len': len(payload['prompt']),
'prompt_full': payload['prompt'],
'state_keys': sorted(payload['state'].keys()),
'state_missing': [k for k, v in payload['state'].items() if v in (None, '', [])],
}
print(json.dumps(log, ensure_ascii=False))
return payload
核对时看四项:每轮日志的 state_keys 是否齐全,state_missing 是否从某一轮开始变多;prompt_full 的长度是否和上游拼出来的原文一致,有没有被“…”“已省略”截断;history_digest 是否随轮次变短,压缩后是否丢掉了关键约束(比如画幅、风格词);parent_request_id 这类链路字段是否每轮都能指回上一轮。如果 prompt_full 本身是完整的、但 state_missing 在递增,问题基本不在提示。
做对照:每轮重发完整提示与只发增量各跑一组
这一步把“提示有没有累积”和“状态有没有传下去”分开。同一个会话、同一组初始参数,开两条线,其它条件保持一致。
- A 组:每轮重发完整提示。把初始风格约束和本轮需求一起写进去,例如“同一人物、正面半身、白色背景;本轮把背景改为浅灰”。状态字段照常带。
- B 组:每轮只发本轮增量。只写“把背景改为浅灰”,不回写历史约束。状态字段同样照常带。
- 两组各跑 5 轮,按第 1 节的表格式记录;如果需要再拆一层,可临时加一组“只发增量且不带状态”,用来交叉确认。
观察点只看这几项:第几轮开始偏离;偏离形态是主体结构变形还是色调、风格缓慢渐变;A 组画面稳定而 B 组逐轮偏离,说明提示累积丢失,模型对句子里缺失的约束不会再自行补回;两组都在同一轮偏离,说明和提示写法关系不大,重点查状态字段。对照组不要中途改画幅和种子,否则观测结果没法归因。
按对照结果判定是提示漂移还是状态丢失
| 日志与对照特征 | 判断 | 下一步动作 |
|---|---|---|
| A 组稳定,B 组逐轮偏离;prompt_len 逐轮递减;history_digest 越压越短 | 提示漂移 | 每轮拼装固定的约束模板再叠加本轮增量;历史摘要换成结构化约束列表,不用自由文本压缩 |
| 两组都在第 2、3 轮偏离;state_missing 含 ref_image_id 或 seed;链路字段断在某一轮 | 状态丢失 | 状态在服务端按会话存储,客户端只传会话标识和本轮增量;参考图标识、种子显式透传并做非空校验 |
| 两组均随机波动,日志字段完整无缺 | 不属于上述两类 | 固定采样参数与画幅,复跑确认是否只是随机性 |
| 提示在某一轮被截断,之后画面丢掉早期约束 | 提示漂移的特例 | 拆分子提示分批下发,或把不常变的约束移到状态字段而非提示正文 |
判定为提示漂移时,改法集中在提示侧:维护一份每轮都会重发的约束模板,增量只往模板尾部追加,不要让模型从历史摘要里回忆早期设定。判定为状态丢失时,改法集中在透传侧:把参考图标识、种子、画幅、会话标识做成必传字段并加非空断言,缺字段时直接报错,不要静默降级成“重新生成一张”。
如果日志显示提示完整、状态也齐全,但画面仍逐轮偏离,通常是两者叠加:状态带的是上一轮已经跑偏的输出,等于每轮都以偏离样本为基准继续放大。这种情况下建议在一处分界点回退到首轮参考图重跑,确认偏离是否会重新累积,再决定是修模板还是修状态链路。