首页 / 文章 / 一种防止智能体图谱中幻觉累积的架构

一种防止智能体图谱中幻觉累积的架构

了解如何运用类型化工具、引用日志与模式校验机制来设计控制平面架构,从而防止多智能体大型语言模型的幻觉现象不断累积。

2832 词

人们的第一反应往往是再添加一个评估模型。但这样只会让欺骗行为更加严重,而非解决根本问题。

如果你曾将单模型RAG聊天机器人投入实际使用,就会意识到其中的问题:模型会给出检索到的文档中从未提及的答案,并以与引用真实信息时相同的笃定语气来呈现这些编造的内容。

在多智能体流程中,同样的故障会被放大,因为此时处理的不再是单个模型的输出,而是一个由多个模型构成的整体网络。规划者会设定一个子目标,研究人员会寻找支持该目标的来源,分析师会从这些来源中提取数据,写作者会将这些数据转化为推荐意见,最后负责调用工具的智能体会根据该推荐在计费系统中执行相应操作。在每一个环节中,都存在将猜测伪装成已验证事实的可能。

那些为法律、金融和运营场景构建 LangGraph 风格多智能体系统的团队总会遇到一个反复出现的问题。问题并不在于底层模型不够智能,而在于工作流程本身缺乏认知契约。图中没有任何机制迫使某个智能体披露诉求的来源、能够推翻该诉求的证据,或是当这些证据不存在时应采取的措施。因此,面对这种空白,系统就会像语言模型一贯做的那样:生成一些看似合理的内容来填补它。

接下来介绍的架构适用于那些输出内容可能涉及资金转移、影响法律文件处理或进入客户邮箱的场景。这并非简短的教程,如果你期望通过一次安装就能让智能体变得可靠,那在这里是找不到这样的方法的。

无人预算的复合问题

每次单独调用大型语言模型时,都会存在一定比例的不可靠陈述——我们将其记为 p。如果将五个智能体节点串联起来,且每个节点都有可能引入或放大不可靠陈述,那么实际错误率就不再只是 p 了。它会变成条件概率的乘积,同时还存在多智能体结构特有的另一个问题:智能体之间的权限传递。

智能体B仅仅因为智能体A的输出以结构化的JSON对象形式呈现,且标签为类似 research_findings 的内容,就将其视为既定事实。虽然该JSON的架构验证通过,字段类型也正确,但实际内容却是编造的。通过架构验证并不等同于内容真实,然而大多数团队只注重前者。

在实际应用中,有三种特定的故障模式出现的频率远高于多数文献的描述:

  1. 伪造的工具调用。模型会生成看似语法正确的函数调用语句——类似search_matters(client_id=…)——但其实际指向的却是并不存在的工具,或者提供的参数在遵循该工具的实际规范时会导致错误。那些默许不匹配类型或允许模型用稍作修改的参数重新尝试的协调层,实际上是在训练系统掩盖数据中的缺陷而非将其暴露出来。
  2. 在不同处理节点间掩饰事实。研究人员会以“根据相关文件”作为借口,而后续的处理人员实际上从未打开过那个文件。随后撰写者又会以该处理人员为信息来源。等到有人审核最终总结时,最初的限定条件早已完全消失。正是通过这种方式,原本不确定的“也许”会变成可以收费的、被明确陈述的事实。
  • 验证器机制。团队通常会通过添加“评论员”或“验证器”角色来应对,这类角色的唯一职责就是识别幻觉。问题在于,这个验证器本身也是一个大语言模型,它基于相同的上下文——往往来自同一模型系列——并且通过提示词的设计,会因表现出顺从与乐于助人而被隐性奖励。那些被优化为乐于助人的验证器往往会选择确认而非质疑。一个真正独立的验证器需要独立的信息来源、不同的目标函数,以及一种比简单同意成本更低的拒绝机制。实际上很少有架构能够提供这样的功能。
  • 检索增强生成也无法解决这个问题。检索仅能提供先验信息。如果规划智能体从未构建出正确的查询,或者分块处理将本可推翻该主张的整段文本拆分为两个独立的嵌入向量,那么研究智能体仍然会检索到一些听起来通顺且主题相关的内容。与正确答案相关并不等同于在逻辑上能够被其推导出来。

    “有依据”的真正含义,否则它就毫无意义

    “有依据”不应只是用来描述氛围或语气的模糊词汇。在多智能体系统中,只有满足以下所有条件时,某个主张才能被视为有依据:

    1. 该声明具有明确的类型,会被标记为AssertionConjectureQuoteActionIntent。将这些类别混同在一个无类型文本字段中,正是审计轨迹出现混乱的原因。
    2. 每个Assertion都会关联到一条来源记录——可能是检索到的文本片段、工具的输出结果,或是人类直接提供的事实。这种关联是通过内容哈希实现的,绝非模型自行编造的URL。
    3. 通过一种确定性的、非大语言模型的验证方法,已确认所引用的来源记录确实存在于该运行过程的账本中。确认记录存在成本较低,而确认其推论关系则成本较高。这两种验证都是必要的,且必须按此顺序进行。
  • 当检查失败时,系统会选择不回应要求进一步说明,而不会擅自修改表述直到其听起来足够有说服力从而通过检查。
  • 无法拒绝回答的架构就无法保证真实性。默认情况下,生成内容是最省力的方式;因此必须将“不回应”作为一种明确的、一级状态嵌入到系统中——并且其实现成本应低于仅通过不同提示重新尝试。

    这就是整个前提。其余的一切都是为了解决在引入LangGraph、实际工具调用以及要求演示始终给出答案的产品经理需求后,如何让这四条规则得以遵循而需要的工程解决方案。

    是控制平面,而非提示词

    应将你的智能体视为不可信任的运行环境,并将其置于控制平面之中。该控制平面由六个组件构成,缺少任何一个都会导致其余组件的功能逐渐下降。

    1. 类型化工具总线

    每个工具都有针对输入和输出的带版本号的 JSON Schema,这些 Schema 存储在模型无权修改的注册表中。模型可以提出调用请求,但必须先有确定性的验证器对其予以接受或拒绝,才能产生任何实际结果。不允许类型强制转换,也不允许枚举值与模型输出内容之间采用“差不多就行”的映射方式。如果调用无效,会以结构化错误的形式返回给规划器,而绝不会以对话式的责备形式出现。

    这看似是个显而易见的要求,但实际上大多数 CrewAI 或 AutoGen 的演示都会忽略它,因为演示中从来不会出现真正会向永久性账本写入数据的工具。

    对于任何会产生不可逆后果的工具——发送数据、写入文件、部署系统或更新记录系统——总线系统应要求双重控制:既要有已通过验证的ClaimSet,也要有人工干预的审批或明确的策略授权。在这种设计下,操作代理永远无法直接使用这些工具。

    2. 只能追加数据的引用账本

    每一个检索结果、每一项工具输出以及人类提供的每一条事实都会被写入一个只能追加数据的存储中,并通过run_id和内容哈希值进行索引。代理不得在自己的临时存储中“记住”信息来源,而必须使用引用账本编号

    如果某个写作代理生成的句子没有附带账本编号,那么这个句子根本算不上一种断言。它只是无标签的文本,绝不应被允许通过架构验证关卡。这可以说是针对现有代理图所能采取的最有效的解决方案:阻止自由形式的文字以数据的形式离开系统。

    哈希值在这里也很重要。模型可以引用doc:matter-4421#p3,但仍可能错误引用第3页的实际内容。账本需要存储完整的文本片段——或者至少是一个指向不可变对象存储的指针——这样验证器就能根据这些确切的字节进行核对,而非依据模型对内容的记忆。

    3. 架构验证关卡(非大语言模型)

    在任何成果向下传递给下一个代理之前——无论是研究总结、计算出的数据还是建议采取的行动——都必须先通过包含以下内容的架构验证:

    • 一个claims[]数组,其中每个元素包含typetextledger_ids[]以及一个confidence值,该值需后续进行校准,而不能由模型直接判定为“高”
    • 一个open_questions[]数组,规划器必须解决这些问题或将其明确上报
    • 一个action_intents[]数组,其中应指定具体的工具名称,而非类似“我们或许应该……”这样的模糊表述

    这一环节必须使用普通代码实现——可以是Pydantic、JSON Schema,或是CEL或Rego策略等,任选其一。绝不能使用大语言模型。如果在这里加入语言模型,就相当于在更低层级重新实现了批评者-代理机制。

    4. 具有不同信息来源的声明验证器

    真正的成本就体现在这里。将每个Assertion拆解为最小的可核查单元,确保每个单元对应一个主体、一种关系或属性,以及某个时间点或时间段。对于这些单元中的每一个,都只能从账本中获取支持证据,绝不能通过实时网络搜索或模型的参数来获取。

    接着进行蕴含关系检查:所获取的文本片段是支持该命题、与之矛盾,还是完全无关?你可以使用小型自然语言理解模型、仅能从该片段中复制内容的受限解码器,或是人工审核员来实现这一检查。但绝不能将这项工作交给同一个大型聊天模型,让其运行相同的系统提示语,然后询问它该主张“是否合理”。

    当某个申请被拒绝时,没人会悄悄修改表述以便在下一次尝试时通过审核。系统会返回Unsupported{proposition, missing_evidence}的结果,此时规划人员的工作应是寻找更多证据,而非重新措辞来规避问题。

    这一步骤还能发现更隐蔽的错误:用看似严谨但实际上模糊且无法验证的表述来替代原句。仅仅说某张发票金额过高并不足以构成可核查的主张。只有明确具体数值——指出对应的费用项、超出合同规定的上限、超出的金额以及支撑这三点的账目记录——才能让核查人员真正确认或拒绝该申请。若采用那种接受模糊表述的架构,最终验证的将只是语气而非事实。

    5. 在真实数据上评估,而非凭感觉

    你需要一套冻结的基准数据集:输入数据、账本快照、预期出现的声明以及预期出现的弃权情况。对图表所做的任何更改——无论是提示词修改、模型更换、分块器调整还是新工具的使用——都会根据以下标准进行评分:

    • 准确性:生成的声明中有多少实际上被账本所蕴含
    • 覆盖度:图表实际生成的声明占预期声明的比例,因为保持沉默本身也可能被视为一种失败
    • 弃权精确度:当系统拒绝回答时,这种拒绝是否确实有依据
    • 副作用控制:在没有有效授权的情况下不得执行任何不可逆的工具调用

    如果准确性下降两点都无法阻止系统部署,那就说明你并没有真正的控制机制——只不过有一个看起来令人安心的仪表板罢了。

    无论采取何种方法,都不要用模型自身的历史输出来构建这个评估集。那样做只会将当前的幻觉模式当作真实结果。黄金标准数据应来自原始文档和实际的系统记录,然后让图表独立地与这些数据进行比对。虽然这种方式效率较低,但却是唯一有实际意义的指标版本。

    6. 不可逆场景下的HITL

    人工审核员的存在并非为了让智能体变得更聪明。他们的职责是在系统即将发送邮件、上传文档或写入记录的临界时刻进行干预。审核界面应展示相关主张集、对应的账本范围以及待处理的工具调用信息,而非一大堆聊天记录。如果需要反推智能体为何会相信某个事实,那就说明该设计已经未能完成其任务。

    对于高处理量的流程——发票审核就是一个很好的例子——应当仅对异常情况进行人工审核,而非对所有内容都进行审查。当所有条件均得到充分满足且财务差异处于可接受范围内时,系统应自动批准。其他所有内容都会被标记出来,仅显示那些没有依据的特定项,而非整份文档。

    合同概要,而非实现细节

    这大致就是各个组件之间传递的数据应具备的样子。编排逻辑、NLI验证栈、账本存储层以及负责发放授权的组件都被刻意省略了——这些都属于实现层面的具体内容,应放在实际代码中,而非博客文章里。

    {
      "run_id": "run_7f3c",
      "from_agent": "analyst",
      "claims": [
        {
          "id": "c_19",
          "type": "Assertion",
          "text": "Line item 14 exceeds the engagement-letter hourly cap.",
          "propositions": [
            {
              "id": "p_19a",
              "pred": "exceeds_cap",
              "args": {"line_id": "14", "cap_source": "engagement_letter"},
              "ledger_ids": ["led_aa12", "led_bb90"],
              "entailment": null
            }
          ]
        }
      ],
      "open_questions": [],
      "action_intents": [
        {
          "tool": "flag_invoice_line",
          "args": {"invoice_id": "INV-4421", "line_id": "14"},
          "requires_grant": true,
          "depends_on": ["c_19"]
        }
      ]
    }
    

    注意缺少了什么:没有可供下一个处理节点直接引用的summary字段。摘要正是各种限定条件与模糊表述容易丢失的地方。如果下游节点需要文字描述,就必须完全基于已验证的信息来构建内容;在得到人工确认可作为面向客户的文本之前,这类内容会被标记为Conjecture

    另外请注意,entailment的值被设置为null。提出该声明的节点本身无权填写此字段,只有验证者才有权限。允许处理节点自行评估自己的声明,就如同让企业自行进行合规审计却称其为独立监督一样。

    为何“只需添加引用”仍然行不通

    最常见的虚假保障手段是仅表面上看似有引用的输出。模型会加上[1][2]之类的标记,有时甚至指向实际检索到的内容片段。但当你打开那个片段后却发现它实际上并不能支持相关主张。

    单凭引用本身无法证明任何事情。真正的证据应该是:特定的文本片段、精确的字节组合,与某个具体的命题相对应,并带有蕴含关系标签,同时还有明确的规则规定当该标签为neutral时应如何处理。缺少这一整套要素,“引用”只不过是伪装成证据的格式化手段而已。

    第二种虚假保障手段是将温度参数设置为0。这并不会让输出更真实——只是让错误答案保持一致而已。稳定的幻觉内容每次都能通过快照测试,但却无法在经过妥善维护的记录系统中存活下来。

    说实话,这需要多少成本

    在 LangGraph 这类平台上搭建一个演示流程只需几天时间。但要构建其背后的实际控制层——包括工具注册表、引用记录系统、模式校验机制、基于自然语言理解的验证器、黄金标准评估流程、对所有可写入路径的人工审核,以及详细到能让律师理解的日志——这些才是将一个能运行的原型与可用于实际业务决策的可靠系统区分开来的关键。

    并不存在一个适用于所有情况的统一标准数值。实际成本取决于你的工具中有多少会引发副作用、你的数据源是否已经具备结构化且可查询的特性,以及在你所处的特定领域中,那些不受支持的声明究竟需要付出多高的代价。法律账单处理和财务报告属于成本高昂、风险极高的范畴;而由大量智能体构成的头脑风暴工具则处于另一端,强制为其配备如此复杂的基础设施实属过度。

    首先应该思考的问题不是该基于哪种框架来构建,而是明确你自己的工作流程处于这个范围中的哪个位置。

    如果这正是你所面临的问题

    对于那些无法容忍看似有把握实则错误的答案的团队来说,这种控制平面尤为重要:通常包括法律工作、金融领域以及需要处理大量文档的业务。这意味着需要使用 LangGraph 等工具构建智能体图谱,采用实际经过验证而非仅凭假设就能正常运行的检索流程,以及能够在审计中经得起检验的提取系统。

    如果您的图谱在演示时表现良好,但上线后却开始产生错误结论,那么问题几乎总可以追溯到此处提到的六个组成部分之一——找出是哪一个,以及是否值得投入工程资源进行修复,才是确定工作范围的真正起点。

    相关阅读