Agensh 多智能体反复说同一句话 / 从终止条件和轮次上限查起

文章导读
多个智能体来回讨论停不下来,多数时候不是模型“想说”,而是编排层没有可判定的停止信号:终止条件只写在提示词里,程序读不到;轮次上限和超时又恰好没配。排查顺序建议固定为两步:先从输出记录里确认重复从第几轮开始,再检查终止条件是自然语言描述还是程序可读取的字段。这两步能在不改模型的前提下定位大部分循环发言问题。
📋 目录
  1. 一 在输出记录里定位重复从第几轮开始
  2. 二 检查终止条件是不是只写在提示词里
  3. 三 把终止条件改成可判定的完成标志
  4. 四 设置轮次上限和超时阈值
  5. 五 复跑对比轮次、耗时和重复率
A A

多个智能体来回讨论停不下来,多数时候不是模型“想说”,而是编排层没有可判定的停止信号:终止条件只写在提示词里,程序读不到;轮次上限和超时又恰好没配。排查顺序建议固定为两步:先从输出记录里确认重复从第几轮开始,再检查终止条件是自然语言描述还是程序可读取的字段。这两步能在不改模型的前提下定位大部分循环发言问题。

Agensh 多智能体反复说同一句话,先分清是“终止条件不可判定”还是“缺少轮次上限”。适用场景是编排层能拿到每轮发言记录的多智能体讨论。操作动作:按轮次切分输出定位重复起点,把提示词里的“达成一致就结束”换成结构化完成标志,同时配置 max_rounds 与超时。验证方式:复跑后对比轮次、耗时、重复率三项,看是否出现完成标志而非被上限截断。风险边界:完成标志解析失败时容易提前结束,需要保留兜底上限与终止原因日志。

在输出记录里定位重复从第几轮开始

先不要动提示词。把一次完整运行的发言记录拉出来,按轮次和发言者切分,看清楚重复是全程都有,还是后期才出现。全程重复通常说明每个智能体都在复述同一份输入;后期重复更常见,说明讨论已经收敛但没人喊停,后面的发言只是把已有结论换个说法再说一遍。

如果日志里每条发言带 round、agent、content 字段,直接按字段分组;如果只有一段拼接文本,就按轮次分隔符或时间戳切分。下面是一个通用切分骨架,字段名需要按实际日志替换:

import re

# 假设日志行形如:[round=3][agent=reviewer] 内容...
line_re = re.compile(r"\[round=(?P<round>\d+)\]\[agent=(?P<agent>[^\]]+)\]\s*(?P<content>.*)")

def split_by_round(lines):
    rounds = {}
    for line in lines:
        m = line_re.match(line)
        if not m:
            continue
        r = int(m.group("round"))
        rounds.setdefault(r, []).append({
            "agent": m.group("agent"),
            "content": m.group("content").strip(),
        })
    return rounds

切分之后要做的是标记重复段落,而不是凭感觉判断“好像一样”。建议把每段内容先标准化:去空白、去标点、统一大小写,再按句号分句,句级去重后统计哪些句子在相邻两轮里都出现过。被标记的段落要记下三件事:首次出现的轮次、重复出现的轮次区间、涉及的智能体。这三项直接决定后面是改终止条件还是加轮次上限——如果重复从第 4 轮就开始且一直持续到最后,那是终止条件没生效;如果只是最后两三轮的收尾寒暄,加个轮次上限就够了。

检查终止条件是不是只写在提示词里

打开编排配置或提示词模板,找“当你们达成一致时结束讨论”“信息足够就停止”这类描述。这类句子对模型是有效的引导,对程序是无效的:程序只能读它拿得到的东西,也就是返回值里的字段、工具调用结果、日志标记,读不到“是否达成一致”这种语义判断。差距就在这里——提示词写了一个人才能判断的条件,运行时代码却没有任何分支去检测它。

Agensh 多智能体反复说同一句话 / 从终止条件和轮次上限查起

对比方法很直接:把提示词里所有涉及“结束、停止、完成、一致、足够”的表述列出来,逐条问一句“代码里哪一行能读到这个状态”。如果答不上来,这条终止条件实际上不存在。常见的情况是三种:一是完全没有终止逻辑,靠轮次跑完自然结束;二是有终止逻辑但只检测了关键词,模型换个说法就失效;三是终止逻辑挂在某个智能体身上,而那个智能体自己也在重复发言,永远不会输出结束信号。第三种最难发现,需要看日志里终止判断函数的调用记录,确认它每轮都被执行过、返回值是什么。

把终止条件改成可判定的完成标志

完成标志的核心是:程序能解析、有明确的真值、解析失败时有兜底。几种通用写法,按接入难度从低到高排列,可任选一种或组合使用。

  • 结构化字段型:要求智能体在回复末尾输出一段固定格式的 JSON,例如 {"status": "done", "reason": "..."},编排层解析 status 字段,等于 done 就结束。适合大多数讨论型流程。
  • 工具调用型:给智能体一个 finish_discussion 之类的工具,调用即视为结束。这种方式比解析文本可靠,因为调用本身是结构化事件;前提是编排层能拿到工具调用记录。
  • 标记行型:约定独立一行输出 ###DISCUSSION_DONE###,代码按行精确匹配。实现最简单,但模型可能把标记写在解释性句子里,需要严格到行首行尾匹配。
  • 外部检查型:每轮结束后跑一个检查函数,比如必填项是否齐全、待办是否清空,全部满足才结束。适合有明确交付物的流程。

通用骨架大致是这样,判定逻辑放在每轮循环末尾:

def should_stop(round_messages, state):
    last = round_messages[-1]["content"]
    # 1) 结构化完成标志
    flag = parse_json_block(last)
    if flag and flag.get("status") == "done":
        return True, "agent_declared_done"
    # 2) 工具调用记录
    if state.get("last_tool_call") == "finish_discussion":
        return True, "tool_finish"
    # 3) 外部检查
    if state.get("checklist_passed"):
        return True, "checklist_passed"
    return False, None

注意两点:解析失败要当作“未完成”处理,不能因为格式错就中断正常讨论;同时要记录终止原因到日志,否则复跑时无法区分“完成标志触发”和“被上限截断”。

Agensh 多智能体反复说同一句话 / 从终止条件和轮次上限查起

设置轮次上限和超时阈值

完成标志解决“应该停的时候能停”,轮次上限和超时解决“不该继续的时候必须停”。两者是互补关系,不能只配一个。配置项通常包括总轮次、单个智能体连续发言次数、单轮超时、整体超时和连续无进展轮数,字段名各编排层不同,下面只是可替换的骨架:

discussion:
  max_rounds: 8                 # 总轮次硬上限
  max_consecutive_same_agent: 2 # 同一智能体连续发言上限
  no_progress_rounds: 2         # 连续 N 轮无新内容即停
  round_timeout_seconds: 120    # 单轮超时
  total_timeout_seconds: 600    # 整场超时
  max_tokens_per_round: 800     # 单轮输出长度上限,抑制越说越长
  on_limit_reached: return_partial  # 超限后的行为

超限后的预期行为要在配置里写清楚,不要靠默认值猜。建议的行为是:写入终止原因(max_rounds、timeout、no_progress),保留最后一条有效结论,返回状态标记为截断而非成功,并把已产生的发言完整落盘。这样后续排查时能直接看出是“讨论没收敛”还是“配置太紧”。max_tokens_per_round 值得单独配,因为输出越写越长往往和循环发言同时出现,压住单轮长度能让重复段落更容易被识别。

复跑对比轮次、耗时和重复率

改完配置要用同一份输入复跑至少两次,对比三项指标,缺一项都不足以判断改动是否有效。

  1. 轮次:记录实际轮数、终止原因、触发终止的轮次位置。关注的是终止原因是否为 agent_declared_done 或 tool_finish,而不是 max_rounds。
  2. 耗时:记录从开始到结束的总时长和单轮平均耗时。如果轮次下降而总耗时没降,通常是单轮输出变长了,需要回头看单轮长度配置。
  3. 重复率:用第 1 节标记出的重复段落字数除以总输出字数,或重复句数除以总句数,两种口径选一种并在两次复跑中保持一致。口径不一致的对比没有意义。

对比结论按这个顺序读:如果终止原因是完成标志,且轮次落在上限之内,说明改动生效;如果仍是被 max_rounds 截断,说明完成标志没有被触发,需要回第 2 节检查解析逻辑或改换完成标志的写法;如果轮次明显下降但重复率没变化,说明重复发生在更早的位置,问题不在收尾而在讨论结构本身,需要调整的是智能体分工而不是终止条件。重复率的变化只用于判断趋势,不要当成固定指标对外宣传,样本量小的时候波动很大。