多角度分析智能体群组:构建LLM专家团队

h100envy 发布于 2026-07-16 阅读 44

本文介绍如何构建一个多智能体分析群组,通过编排器分配角色,让多个具有不同偏见和关注点的专家独立分析同一决策,再通过合并步骤综合各方观点。文章提供完整Python代码,包含编排器、专家独立分析、辩论回合、魔鬼代言人攻击假共识,以及最终合成。该结构旨在利用专家间的分歧而非平均化观点,产生经过压力测试的结论。

图像

这不是关于速度。而是关于让多个具有不同视角的智能体(agent)就一个决策进行争论,并得出比它们任何一个单独得出的更好的结论。包含协调器、专家和合并的完整代码。

当你让一个模型评估一个决策时,它会给出一个视角,通常是平均且谨慎的。它倾向于同意、平滑处理、寻求平衡。这就是问题所在:一个重要的决策不能由一个平均的视角来评估,必须从不同的侧面进行攻击。

一个智能体群体(swarm)从结构上解决了这个问题。你创建几个专家,每个都有硬性设定的角色和偏见:一个只考虑金钱,另一个只考虑技术风险,第三个只考虑用户。他们独立分析同一个决策,得出不同结论,然后你强制对这些结论进行调和。这里的价值不是速度,而是分歧被构建在结构之中。单个智能体容易与自己达成群体思维,而一个有角色的群体则不会。

本文展示了如何用代码构建这样一个群体。我们涵盖三个部分:分配角色的协调器,独立分析的专家,以及将它们调和成一个结论的合并器。

架构:协调器、专家、合并器

用于分析的群体由三个组件组成。

协调器接收任务并决定需要哪些专家角色。对于评估产品发布,这些角色可能是投资者、工程师、产品专家、安全人员。协调器自己不进行分析,它分配角色。

专家们并行且独立地工作。每个专家看到相同的决策,但通过自己的视角。关键的是,他们看不到彼此的结论,否则就会产生趋同。独立性正是产生不同观点的原因。

合并器收集专家的结论并进行调和:他们同意的地方,他们矛盾的地方,以及从所有角度得出的最终裁决。这不是平均,而是一种综合,将分歧作为信号保留。

图像

第一步:基础客户端

从模型的简单客户端开始。我使用OpenAI兼容的消息格式,它适用于大多数提供商和本地Ollama。

import requests
import json
from concurrent.futures import ThreadPoolExecutor

API = "http://localhost:11434/api/chat"   # Ollama,或一个提供商端点
MODEL = "qwen2.5:32b"

def ask(system, user, temperature=0.7):
    resp = requests.post(API, json={
        "model": MODEL,
        "messages": [
            {"role": "system", "content": system},
            {"role": "user", "content": user},
        ],
        "temperature": temperature,
        "stream": False,
    }, timeout=120)
    resp.raise_for_status()
    return resp.json()["message"]["content"]

第二步:协调器分配角色

协调器获取任务并决定需要哪些专家。不要提前硬编码角色,让模型为特定任务选择角色,这使群体具有通用性。要求输出严格的JSON以便解析。

ORCHESTRATOR_SYSTEM = """你是分析群体的协调器。
对于给定的任务,定义3-5个专家角色,这些角色将对决策给出最大程度**不同**
且相互冲突的观点。这些角色必须在利益上冲突,而不是互补。

为每个角色给出:名称、关注点(它专注于什么)、偏见(它偏向于什么,它倾向于高估什么)。

**只**回复一个JSON数组,不要解释:
[{"name": "...", "focus": "...", "bias": "..."}, ...]
"""

def plan_roles(task):
    raw = ask(ORCHESTRATOR_SYSTEM, f"需要分析的任务:\n{task}",
              temperature=0.9)   # 更高的温度以获得角色多样性
    # 剪切出JSON部分,以防模型在周围添加了文本
    start, end = raw.find("["), raw.rfind("]") + 1
    return json.loads(raw[start:end])

我们这里有意保持高温:我们需要多样化的、非显而易见的角色。提示语中的要求“角色必须冲突”是关键,没有这个要求,模型会给出三个几乎相同的角色,整个群体的意义就丧失了。

第三步:专家并行且独立地分析

每个专家获得其角色和相同的决策。关键的是:他们并行运行,并且看不到彼此的结论。这里的并行不仅是为了速度,它保证了独立性——一个专家物理上无法根据另一个专家的意见进行调整。

EXPERT_SYSTEM = """你是一个专家,角色是:{name}。
你的关注点:{focus}。
你的偏见:{bias}。不要抗拒它,它正是你对分析的价值。

严格从你的立场分析决策。不要寻求平衡,不要试图考虑其他观点,其他专家会做那件事。你的工作是把你的角度推到极限。

给出:
- 从你的立场得出的结论(赞成 / 反对 / 有条件)
- 2-3个来自你角度的主要论点
- 1个从你立场最容易看到、而其他人会忽略的风险
简短有力,不要废话。"""

def run_expert(role, task):
    system = EXPERT_SYSTEM.format(**role)
    opinion = ask(system, f"需要分析的决策:\n{task}", temperature=0.7)
    return {"role": role["name"], "opinion": opinion}

def run_swarm(roles, task):
    # 并行启动:独立性与速度兼得
    with ThreadPoolExecutor(max_workers=len(roles)) as pool:
        futures = [pool.submit(run_expert, role, task) for role in roles]
        return [f.result() for f in futures]

注意专家的提示语:我们明确禁止它寻求平衡。这反直觉,但正是关键所在。如果每个专家都试图考虑所有方面,你会得到五个相同的谨慎意见。通过强制每个专家将其角度推到极限,你得到了一个真正的光谱,然后由合并器进行调和。

第四步:合并器调和结论

现在我们有了几个尖锐的、片面的意见。合并器将它们收集成一个裁决,但不是通过平均。它寻找专家们一致的地方(一个强信号),他们矛盾的地方(需要决策的风险区域),以及什么比重更大。

MERGE_SYSTEM = """你是分析群体的综合器。你被给予了几位具有不同偏见的
专家对同一个决策的意见。

你的工作**不是**对它们取平均。你的工作是:
1. 共识:尽管立场不同,专家们在哪些方面达成了一致。
   这是最可靠的信号,高亮显示它。
2. 冲突:专家们直接矛盾的地方。不要平滑处理,明确指出冲突,
   并说明每一方的代价。
3. 盲点:只有一个专家提到的风险,但它很重要。
4. 综合所有因素的最终裁决:赞成 / 反对 / 有条件,以及在什么条件下会改变。

写密集一些。将分歧作为信息保留,不要隐藏它。"""

def merge_opinions(task, opinions):
    block = "\n\n".join(
        f"### 专家:{o['role']}\n{o['opinion']}" for o in opinions
    )
    user = f"决策:\n{task}\n\n专家意见:\n{block}"
    return ask(MERGE_SYSTEM, user, temperature=0.4)   # 综合时用较低温度,以求冷静一致

我们在合并时降低温度:如果专家应该多样化(高 T),那么综合器应该冷静且一致(低 T)。这里的关键指令是“不要平均,将分歧作为信息保留”。一个普通的合并会把一切变成稀粥——“一方面,另一方面”。一个好的合并会直截了当地说:这里所有人都同意,而这里有一个冲突,代价是这么多。

第 4.5 步:针对虚假共识的魔鬼代言人

有一个潜在的危险:有时专家们达成一致不是因为决策好,而是因为每个人出于惯性都在朝同一个方向看。这是虚假共识,比公开冲突更危险,因为它看起来像是信心。

针对这一点,我们添加一个特殊的智能体:魔鬼代言人。它的唯一工作就是攻击共识。它看到所有专家的意见,并有责任找出为什么他们可能同时全部错误。如果群体一致投了“赞成”,代言人就会寻找一个可能灾难性的场景。

DEVIL_SYSTEM = """你是一个分析群体中的魔鬼代言人。你被给予专家的意见。
你唯一的工作:攻击他们的共识。

如果专家们在某件事上汇聚了,找出为什么他们可能**同时全部**错误。
寻找一个共同的盲点:每个人都未经检查就接受的假设,一个因为不方便而
没有人考虑的场景。

不要客气。你的价值在于你说出群体不想听的话。给出:
- 专家们最危险的共同假设是什么
- 一个场景,在该场景下群体的统一意见被证明是致命的错误
- 群体小心回避的一个问题
如果没有任何共识,专家们真正有分歧,就直说,并指出最尖锐的未解决冲突。"""

def run_devil(task, opinions):
    block = "\n\n".join(
        f"### {o['role']}\n{o['opinion']}" for o in opinions
    )
    user = f"决策:\n{task}\n\n群体意见:\n{block}"
    return ask(DEVIL_SYSTEM, user, temperature=0.8)

代言人在专家之后、合并之抢跑,它的攻击与意见一起进入综合。关键在于,即使是一个统一的群体,也至少有一个智能体有义务去找到裂缝。这是廉价的(一次调用),并且在结构上打破了群体思维:共识现在必须经受攻击,而不仅仅是发生。

第 4.6 步:一轮辩论以激化冲突

第一轮专家是独立的,这对多样性来说是正确做法。但在收集意见之后,你可以给出一轮辩论:向每个专家展示其他专家意见的摘要,并允许它反驳。这激化了冲突,薄弱的论点会消失,有力的论点会巩固。

DEBATE_SYSTEM = """你是第二轮分析中的专家 {name}。
你原来的立场:
{own_opinion}

现在你看到了其他专家的意见。不要迫于压力屈服,但也不要忽视强有力的论点。给出:
- 在哪些地方别人的论点真正击中了你的立场,诚实地承认
- 在哪些地方你坚持自己的立场,以及为什么他们的反对意见薄弱
- 辩论后你是否改变了你的结论,如果是,如何改变的
简短。这不是重复第一轮意见,而是对对手的回应。"""

def debate_round(roles, task, opinions):
    others_map = {}
    for o in opinions:
        others = "\n\n".join(
            f"### {x['role']}\n{x['opinion']}" for x in opinions if x is not o
        )
        others_map[o["role"]] = others

    def rebut(o):
        system = DEBATE_SYSTEM.format(name=o["role"], own_opinion=o["opinion"])
        user = (f"决策:\n{task}\n\n"
                f"对手的意见:\n{others_map[o['role']]}")
        return {"role": o["role"], "opinion": ask(system, user, temperature=0.6)}

    with ThreadPoolExecutor(max_workers=len(opinions)) as pool:
        return list(pool.map(rebut, opinions))

辩论轮也是并行的:每个专家同时回应所有其他人,同样不会产生实时趋同。辩论后,意见通常更加尖锐:你可以看到哪些立场在压力下站住了脚,哪些崩溃了。正是这些经过锤炼的意见进入最终的合并。

第五步:整合所有代码

def analyze(task, debate=True):
    print("协调器正在挑选角色...")
    roles = plan_roles(task)
    for r in roles:
        print(f"  - {r['name']}: {r['focus']}")

    print(f"\n并行启动 {len(roles)} 个专家...")
    opinions = run_swarm(roles, task)
    for o in opinions:
        print(f"\n[{o['role']}]\n{o['opinion']}")

    # 可选的辩论轮:专家之间互相反驳
    if debate:
        print("\n辩论轮,专家们互相反驳...")
        opinions = debate_round(roles, task, opinions)

    # 魔鬼代言人攻击群体的共识
    print("\n魔鬼代言人在寻找共识中的裂缝...")
    devil = run_devil(task, opinions)
    print(f"\n[魔鬼代言人]\n{devil}")

    # 合并器调和结论以及代言人的攻击
    print("\n合并器正在调和结论...")
    opinions_plus = opinions + [{"role": "魔鬼代言人", "opinion": devil}]
    verdict = merge_opinions(task, opinions_plus)
    print(f"\n=== 最终裁决 ===\n{verdict}")
    return verdict

if __name__ == "__main__":
analyze(
"我们想取消免费层级,使产品完全付费并提供14天试用。我们应该这样做吗?"
)

运行这段代码,你会看到完整的流程:协调器挑选角色,专家们从各自角度剖析真相,在辩论轮中互相争论,代言人攻击他们的共识,而合并器给出涵盖所有方面(包括攻击)的裁决。一个单独的智能体对同一个问题会给出模糊的“这取决于你的受众”,而群体给出了一个结构化的分解,其中冲突是明确的,共识经过了压力测试。

是什么让这个群体有效

三件事将有用的群体与由智能体组成的戏剧区分开来。

角色必须冲突,而不是互补。 如果你的专家是“一个营销人员、一个社交媒体专员、一个内容经理”,他们会给出几乎相同的答案,因为他们的利益一致。真正的价值在于利益冲突时:增长 vs 可持续性,速度 vs 质量,眼前的钱 vs 未来的信任。利益冲突才能把决策撬开。

专家不得互相看到。 一旦一个专家看到另一个专家的意见,趋同就开始了,它会调整。独立性不是一个实现细节,而是一个工作条件。并行启动免费提供了这一点。

合并器不取平均,它保留冲突。 一个糟糕的综合会把五个尖锐的意见变成一个无力的总结。一个好的综合会让冲突可见,因为冲突是最有价值的信息:它显示了决策真正存在风险的地方,而不是每个人都点头同意的地方。

可以扩展的地方

这个骨架可以在明显的方向上扩展。你可以添加一个辩论轮:在第一次合并后,向专家展示摘要,允许他们提出反对意见,这会使冲突更尖锐。你可以用一个比专家更强的模型作为法官来权衡论点。你可以为重复类型的决策固定角色,这样就不必每次都生成它们。

但基本原则保持不变:不同的镜头、独立分析、尊重分歧的综合。一个群体对分析有用不是因为有很多智能体,而是因为它们以不同方式看待,并且不让彼此滑向一个共同的底线。现在就拿一个你独自在脑中反复思考的决策,通过这样的群体运行一遍。你会看到你未曾注意到的角度。

  • 原文链接: x.com/h100envy/status/20...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~

相关文章

0 条评论