Grok Bot 多 Bot 并行时上下文互相串味 / 按 Bot 隔离会话再复现

文章导读
某个 Bot 的回答里混进了别的任务内容,通常不是模型随机发挥,而是多个 Bot 复用了同一条会话历史,或者读到了同一份没有按 Bot 隔离的中间结果。想分清是哪一种,可以先把串味那句话在会话记录里定位到首次出现的 Bot 和会话,再按 Bot 拆成独立会话跑同一任务做前后对照。判断和处理都只依赖你手上的日志、配置和页面行为,不需要改动模型本身。
📋 目录
  1. 一 在会话记录里找出串味那句是从哪来的
  2. 二 把每个 Bot 拆成独立会话再跑一次
  3. 三 共享中间结果时的替代做法
  4. 四 用同一任务做一次隔离前后对照
  5. 五 把隔离约定写进任务启动流程
A A

某个 Bot 的回答里混进了别的任务内容,通常不是模型随机发挥,而是多个 Bot 复用了同一条会话历史,或者读到了同一份没有按 Bot 隔离的中间结果。想分清是哪一种,可以先把串味那句话在会话记录里定位到首次出现的 Bot 和会话,再按 Bot 拆成独立会话跑同一任务做前后对照。判断和处理都只依赖你手上的日志、配置和页面行为,不需要改动模型本身。

串味排查的关键不是调模型参数,而是先确认复用边界在哪里:同一会话历史、共享线程,还是共享中间结果。通常做法是按 Bot 标识筛选会话记录,找到重复片段的首次出现位置——出现在本 Bot 历史里,多半是会话复用;出现在别的 Bot 会话或共享结果存储里,就是中间结果污染。隔离会话能消掉大多数同类现象,但结论要用同一任务的隔离前后对照来写,只写观察到的现象,不写消除比例。

在会话记录里找出串味那句是从哪来的

会话日志一般会带上 bot_id、session_id、thread_id、role、content 这几类字段,能不能查清来源,取决于这些字段有没有被完整记录。如果日志里只有一段拼好的 prompt 而没有 Bot 标识,需要先补上标识再排查,否则无法区分来源。

# 按 Bot 标识筛出某个 Bot 的会话记录(日志通常是 JSONL)
jq -c 'select(.bot_id=="bot-a") | {ts, session_id, thread_id, role, content}' sessions.jsonl

拿到可疑片段后,用一句特征词去全量日志里找它第一次出现在哪。特征词要选足够独特的,比如某个任务名、某个专有名词或某个数字组合,避免用“确认”“处理”这类高频词。

# 找到该片段的首次出现位置:按时间排序取最早一条
jq -r 'select(.content | test("库存校准")) | [.ts, .bot_id, .session_id] | @tsv' sessions.jsonl | sort | head -n 5

两种来源的区分方式比较直接:首次出现就在本 Bot 的 user 或 assistant 历史里,说明是本会话历史被复用进来的,常见于 session 没换、memory 或 carry_over 默认开着;首次出现在另一个 Bot 的会话,或出现在共享结果表、缓存键、消息主题里,而本 Bot 历史中从未有过这句,则基本是读到了共享中间结果。如果日志里有 trace_id,可以顺着 trace_id 看这次调用到底拼进了哪些上下文,这比看最终回答更可靠。

把每个 Bot 拆成独立会话再跑一次

隔离要看三类配置项:会话标识(session_id、conversation_id)是不是按 Bot 和任务生成唯一值;线程标识(thread_id、agent 命名空间)是不是所有 Bot 共用了一个默认线程;是否复用历史(history、memory、carry_over 之类的开关)是否被显式关闭。不同框架的字段名不一样,需要结合环境确认,但判断标准一致:两个 Bot 的会话标识不应相同,且不应加载对方的对话历史。

Grok Bot 多 Bot 并行时上下文互相串味 / 按 Bot 隔离会话再复现

改完配置后,重跑的步骤要固定下来,否则对照没有意义:先清理旧的会话缓存(按 task_id 或 bot_id 删除),再用同一份输入重新发起任务,最后记录每个 Bot 实际使用的 session_id 和 thread_id,确认互不相同。如果清理后串味消失,说明来源在会话或缓存复用;如果没有消失,再回去看共享中间结果。

共享中间结果时的替代做法

有些场景确实要让 Bot 之间协作,比如一个 Bot 出结论、另一个 Bot 接着处理。这时不要把原始对话整体传过去,只传结构化结果,并把完整内容放到可寻址的存储里,用引用代替内联。

{
  "task_id": "t-1024",
  "from_bot": "bot-a",
  "to_bot": "bot-b",
  "schema_version": "1",
  "summary": "结论摘要,单段,超长截断",
  "refs": ["result:t-1024:full"],
  "expires_at": "由调用方决定"
}

字段约定上,建议固定 task_id、from_bot、to_bot、schema_version,方便回查和版本兼容;summary 只放结论,控制在一段话以内,超出就截断并写进 refs;refs 只存引用,不内联全文。长度约束可以按“整条 payload 能完整写进一行日志”来定,超过这个量级说明该改成只传引用。需要明确禁止的是把 assistant、user 的原始 message 数组塞进 payload,那等于把对话历史换了个容器继续传播。

Grok Bot 多 Bot 并行时上下文互相串味 / 按 Bot 隔离会话再复现

用同一任务做一次隔离前后对照

对照组的设置尽量只改一个变量:同一任务词表、同一份输入、同一批 Bot,隔离前组使用共享会话,隔离后组使用独立会话,其余参数保持不变。观察点不看回答整体质量,只看回答中是否出现属于其他任务的词。可以先整理一份“无关任务词表”,把这个任务不该出现的词列进去,再用脚本匹配回答内容。

结论要按观察到的现象写,比如“隔离前 bot-a 的回答中出现了 bot-b 任务的词 X,改为独立会话后,同一输入下未再出现”,并注明样本只有这一次、环境是什么。不要写成“彻底解决”“完全杜绝”或任何比例化的效果,单次对照不足以支撑这类说法。如果隔离后仍偶尔出现,说明还有共享通道没切断,需要回到会话记录继续定位。

把隔离约定写进任务启动流程

靠事后排查不如在启动时卡住。每次新任务发起前,把下面几项过一遍:会话标识是否按 Bot 和任务生成且唯一;历史是否清空或显式关闭复用;共享传递内容是否只含结构化字段、不含原始对话;是否记录了 trace_id 便于回查。这几项可以直接写成启动前的断言。

def start_task(bot_id, task_id, payload):
    assert "raw_messages" not in payload   # 只允许结构化字段
    session_id = f"{bot_id}:{task_id}"     # 按 Bot 与任务生成唯一标识
    return run(bot_id, session_id, reuse_history=False, input=payload)

这段骨架是通用写法,具体参数名需要替换成你所用的框架里的对应字段。把它放进任务入口处,一旦有人传了原始对话或复用了旧会话,启动阶段就会失败,比等到回答串味之后再翻日志省事得多。