基于 NeMo Guardrails 的 RAG 事实核查:以《2023 年 3 月美国就业报告》知识库为例

原创2026-09-28 23:14:461,621 阅读
文章标签:人工智能大模型AI 安全治理模型安全内容安全提示词注入防护RAG

基于 NeMo Guardrails 的 RAG 事实核查:以《2023 年 3 月美国就业报告》知识库为例

本指南以 NeMo Guardrails 仓库中 examples/configs/rag/fact_checking 示例的知识库文档 kb/report.md 为切入点,系统讲解如何为基于 RAG 的对话系统配置事实核查(fact checking)能力:从知识库文档的角色定位、AlignScore 事实核查服务的接入,到 Colang 流中准确率阈值与异常处理策略的落地。读完本文,你将能够把任意一份结构化的领域文档组织成可核查的知识库,并为其配置一套完整的事实核查护栏。

一、为什么 RAG 对话系统需要事实核查

检索增强生成(RAG)系统最常见的失稳点在于:模型基于检索到的上下文作答时,可能输出**与证据不符(not grounded)**的内容,即"幻觉"。NeMo Guardrails 的 fact_checking 示例正是针对这一场景设计的——它演示了如何利用 AlignScore(一种基于信息对齐的文本一致性评估方法)对机器人输出进行事实核查,并在置信度不足时采取降级或告警措施。

整个示例的核心资产就是这份知识库文档 kb/report.md。它是一份真实的美国劳工统计局(BLS)《2023 年 3 月就业形势报告》,被用作检索上下文(evidence)与事实核查的比对基准。示例的 README.md 明确指出目录结构为:

  • kb/:存放知识库,即 kb/report.md(2023 年 3 月美国就业报告);
  • config.yml:承载全部配置选项;
  • general.co:通用 Colang 流程与消息定义;
  • factcheck.co:与事实核查相关的流程定义。

二、知识库文档的内容构成:可作为核查基准的事实清单

kb/report.md 是典型的结构化新闻稿,包含"家庭调查数据(Household Survey Data)"与"机构调查数据(Establishment Survey Data)"两大板块。它之所以适合作为事实核查知识库,是因为其中的每个数据点都是可验证、可引用、可相互交叉验证的硬事实。下面按板块整理核心事实,这些数据既是对文档的完整继承,也是后续设计核查 Prompt 与测试用例的素材。

2.1 总体概况

  • 3 月非农就业总人数增加 236,000,失业率基本持平于 3.5%;
  • 就业继续在休闲与酒店业、政府部门、专业与商业服务业以及医疗保健业呈上升趋势;
  • 报告基于月度家庭调查与机构调查两份数据:家庭调查衡量劳动力状况(含按人口特征划分的失业),机构调查衡量各行业的非农就业、工时与收入。

2.2 家庭调查数据

指标 数值
失业人数 580 万(5.8 million),基本持平
西班牙裔失业率 4.6%(较上月下降)
成年男性 / 成年女性 / 青少年失业率 3.4% / 3.1% / 9.8%
白人 / 黑人 / 亚裔失业率 3.2% / 5.0% / 2.8%
永久性失业者 增加 172,000 至 160 万
重新进入劳动力市场者 减少 182,000 至 170 万
长期失业者(27 周及以上) 110 万,占全部失业者的 18.9%
劳动力参与率 62.6%,继续上升
就业人口比 60.4%,环比微升
因经济原因从事兼职者 410 万,基本持平
不在劳动力市场但想要工作的人数 490 万,基本持平
边缘依附劳动力者(marginally attached) 130 万,基本持平
沮丧工人(discouraged workers) 351,000,基本持平

2.3 机构调查数据

行业 / 指标 3 月变化
非农就业总数 +236,000(前 6 个月平均月增 334,000)
休闲与酒店业 +72,000(其中餐饮服务与酒吧 +50,000;仍低于疫情前水平 368,000)
政府部门 +47,000
专业与商业服务 +39,000(专业、科学和技术服务 +26,000)
医疗保健 +34,000(家庭医疗保健服务 +15,000、医院 +11,000、护理和住宿护理设施 +8,000)
社会救助 +17,000
运输与仓储 +10,000(快递与信使 +7,000、航空运输 +6,000、仓储 -12,000)
零售贸易 -15,000(建材和园艺设备经销商 -9,000、家具家居电器零售商 -9,000、百货商店 +15,000)
平均时薪(私人非农全部雇员) +9 美分(+0.3%)至 $33.18;过去 12 个月 +4.2%
平均时薪(生产与非管理雇员) +9 美分(+0.3%)至 $28.50
平均工作周(私人非农全部雇员) 34.4 小时(环比 -0.1 小时)
制造业平均工作周 / 加班 40.3 小时 / 3.0 小时
1 月非农数据修订 由 +504,000 下修至 +472,000(-32,000)
2 月非农数据修订 由 +311,000 上修至 +326,000(+15,000)

这些数值天然构成了"对 / 错"的判别空间:例如把失业率说成"4.5%"、把休闲酒店业新增岗位说成"95,000",都属于与证据不符的典型幻觉样本。

三、示例配置全景:config.yml 与 Colang 流程

事实核查能力由配置与流程共同驱动。核心配置在 config.yml 中:

models:
  - type: main
    engine: openai
    model: gpt-3.5-turbo-instruct

rails:
  config:
    fact_checking:
      parameters:
        endpoint: "http://localhost:5123/alignscore_base"

  output:
    flows:
      - alignscore check facts
  • models.main:主对话模型,示例使用 OpenAI 的 gpt-3.5-turbo-instruct;
  • rails.config.fact_checking.parameters.endpoint:AlignScore HTTP 服务的地址(示例为本地 5123 端口);
  • rails.output.flows:声明在输出方向启用的护栏流——alignscore check facts,即对每条机器人回复执行 AlignScore 事实核查。

配套的 Colang 流程定义在 factcheck.co 中,其设计逻辑值得逐段拆解。

3.1 用户意图:ask about report

define user ask about report
  "What was last month's unemployment rate?"
  "Which industry added the most jobs?"
  "How many jobs were added in the transportation industry?"

通过示例问句(失业率、最多岗位行业、运输业新增岗位)限定知识库问答范围,同时这些问句都能在上文知识库中找到精确答案。

3.2 回答流程:激活事实核查开关

define flow answer report question
  user ask about report

  # For report questions, we activate the fact checking.
  $check_facts = True
  bot provide report answer

当用户问到报告相关问题时,将上下文变量 $check_facts 置为 True,随后交由下游输出护栏对机器人生成的回复做事实核查。

3.3 核查子流程:0.4 / 0.6 两级阈值策略

define subflow check facts
  """Add the ability to flag potentially inaccurate responses.

  Flag potentially inaccurate responses when the confidence is between 0.4 and 0.6.

  NOTE: This overrides the default `check facts`.
  """
  # Check the facts when explicitly needed.
  if $check_facts == True
    $check_facts = False

    $accuracy = execute check_facts
    if $accuracy < 0.4
      if $config.enable_rails_exceptions
        create event FactCheckLowAccuracyRailException(message="Fact check triggered. The accuracy of the response is below 0.4.")
      else
        bot inform answer unknown
      stop

    if $accuracy < 0.6
      # We need to provide a warning in this case
      # TODO: Add a warning message
      $bot_message_potentially_inaccurate = True

该子流程定义了完整的分级处置策略:

  • 准确率 < 0.4:判定回复严重偏离证据。若 $config.enable_rails_exceptions 开启,则创建 FactCheckLowAccuracyRailException 事件交由异常处理;否则让机器人告知"无法回答"(bot inform answer unknown)并 stop,阻断该回复;
  • 准确率在 0.4~0.6 之间:视为"可能不准确",设置 $bot_message_potentially_inaccurate = True,触发后续告警流(源码中以 # TODO: Add a warning message 标记了可扩展点);
  • 准确率 ≥ 0.6:认为回复与证据足够一致,放行。

3.4 告警流程:可能不准确的响应

define flow flag potentially inaccurate response
  """Tell the user that the previous answer is potentially inaccurate."""
  bot ...

  if $bot_message_potentially_inaccurate
    $bot_message_potentially_inaccurate = False
    if $config.enable_rails_exceptions
      create event PotentiallyInaccurateResponseRailException(message="Potentially inaccurate response detected. The bot's response may be inaccurate.")
    else
      bot inform answer potentially inaccurate
    stop

define bot inform answer potentially inaccurate
  "Attention: the answer above is potentially inaccurate."

当输出被标记为"可能不准确"时,机器人会追加提示语:"Attention: the answer above is potentially inaccurate.",提醒用户谨慎采信。同样支持通过 enable_rails_exceptions 切换为异常事件模式。

3.5 通用对话流程

general.co 定义了问候、能力介绍、知识库介绍、通用问题兜底等常规流程,其中 bot inform capabilities 明确说明了该示例的设计意图——"问我知识库中的文档可以测试事实核查能力,问其他主题则可以测试幻觉检测能力"。

四、AlignScore 事实核查的源码级原理

alignscore check facts 流背后是库内置的 align_score 模块,其核心动作 alignscore_check_facts 定义在 actions.py 中,关键实现逻辑为:

@action()
async def alignscore_check_facts(
    llm_task_manager: LLMTaskManager,
    context: Optional[dict] = None,
    llm: Optional[LLMModel] = None,
    config: Optional[RailsConfig] = None,
    relevant_chunks: Optional[list] = None,
    bot_message: Optional[str] = None,
    http_client: Optional[HTTPClient] = None,
    **kwargs,
) -> RailOutcome:
    """Checks the facts for the bot response using an information alignment score."""
    fact_checking_config = llm_task_manager.config.rails.config.fact_checking
    fallback_to_self_check = fact_checking_config.fallback_to_self_check

    alignscore_api_url = fact_checking_config.parameters.get("endpoint")

    context = context or {}
    evidence = relevant_chunks if relevant_chunks is not None else context.get("relevant_chunks", [])
    response = bot_message if bot_message is not None else context.get("bot_message")

    alignscore = await alignscore_request(
        alignscore_api_url,
        evidence,
        response,
        http_client=http_client,
    )
    if alignscore is None:
        log.warning("AlignScore endpoint not set up properly. Falling back to the ask_llm approach for fact-checking.")
        if fallback_to_self_check:
            return await self_check_facts(...)
        else:
            return _fact_check_outcome(1.0)
    else:
        return _fact_check_outcome(alignscore)

从中可以提炼出几个重要事实:

  1. 输入信号:动作从上下文获取 relevant_chunks(检索到的证据片段,来自知识库)与 bot_message(机器人生成的回复),两者正是 kb/report.md 这类知识库文档发挥作用的位置;
  2. 端点配置:AlignScore 服务地址从 rails.config.fact_checking.parameters["endpoint"] 读取,与 config.yml 中的配置一一对应;
  3. 降级策略:若 AlignScore 端点不可用(返回 None),默认回退到 self_check_facts(基于 LLM 的自检),或在关闭回退时直接放行(_fact_check_outcome(1.0)),确保护栏失败时系统仍可用;
  4. 返回类型:最终以 RailOutcome 形式返回准确率分数,供 Colang 流中的 $accuracy < 0.4 / $accuracy < 0.6 判断使用。

此外,rail.py 以 RailManifest 声明了该护栏的元信息:方向为 output,能力涵盖 allow、block、fact_check,上下文绑定 relevant_chunks 与 bot_message,并要求存在 AlignScore HTTP 服务 这一外部依赖。这解释了为什么 config.yml 必须配置 endpoint 才能正常工作。

五、启动 AlignScore 服务与运行示例

AlignScore 模块提供了自托管服务的完整工程文件:Dockerfile、requirements.txt、server.py。示例配置中 endpoint: "http://localhost:5123/alignscore_base" 对应的即是本地启动的 AlignScore 服务。

典型运行路径是:

  1. 按 Dockerfile 构建并启动 AlignScore 服务,使其监听 5123 端口并暴露 /alignscore_base 接口;
  2. 使用 config.yml 所在目录作为 Rails 配置目录加载 NeMo Guardrails(如通过 LLMRails.from_path(...) 或 CLI 对话);
  3. 向机器人提问 kb/report.md 覆盖范围内的问题(如"What was last month's unemployment rate?"),观察输出是否经过 alignscore check facts 流核查;
  4. 故意提出与知识库相悖的诱导性问题,验证 0.4 阈值下的拦截与 0.4~0.6 区间的告警行为。

仓库测试目录中的 test_fact_checking.py 也围绕事实核查场景提供了可参考的断言方式,可用于校验流触发与分数判断逻辑。

六、用评估框架量化事实核查效果

仅配置护栏还不够,NeMo Guardrails 提供了配套的离线评估框架 evaluate_factcheck.py,用于量化事实核查的准确率。其核心设计如下:

  • 正负样本:正向样本是"证据 + 正确回答"(应判定为 yes);负向样本由 LLM 扮演对抗者,把正确回答改写为"看似正确但实则错误"的答案(应判定为 no);
  • 评分方式:使用 SELF_CHECK_FACTS 任务 Prompt,将 evidence 与 response 送入 LLM 做蕴含判定,最终输出 Positive Accuracy(正向蕴含准确率)、Negative Accuracy(负向准确率) 与 Overall Accuracy(综合准确率);
  • 命令行入口:通过 config 指定配置目录,dataset_path 指定数据集,num_samples 控制采样数,output_dir 指定预测结果 JSON 的输出位置。

对于以 kb/report.md 为知识库的示例,你可以基于上文的"事实清单"构造正负样本集:正样本直接引用文档数值,负样本把数值替换为邻近但错误的数字(例如把失业率 3.5% 改成 4.5%),即可系统检验 AlignScore 或自检策略的判别能力。

七、把示例迁移到自己的知识库

kb/report.md 只是演示载体,整套机制对任意结构化知识库通用。迁移时只需三步:

  1. 替换知识库文档:将 kb/ 下的文档换成你自己的领域文档(如产品手册、法规文本、财报),保持结构化、数值精确、段落可检索;
  2. 更新用户意图与流程:在 factcheck.co 中把 ask about report 的示例问句替换为与你的文档强相关的问题,并确保 answer report question 流程能触发 $check_facts = True;
  3. 校准阈值:0.4 与 0.6 是示例默认值。对于对准确性要求极高的场景(如金融、医疗),建议结合 evaluate_factcheck.py 的评估结果调高阈值;对宽容场景则可适当降低,避免误拦截。

同时注意,rail.py 的隐私声明表明该护栏会把 bot_message 与检索到的文本块发送到 AlignScore 远程服务,在接入生产环境时需评估数据出境与合规要求。

八、小结

通过 kb/report.md 这份真实就业报告,本示例完整展示了 NeMo Guardrails 事实核查能力的落地路径:以结构化知识库作为证据源,以 AlignScore 服务提供一致性评分,以 Colang 流中的分级阈值实现"拦截 + 告警 + 放行"的精细化处置,并以离线评估框架量化效果。掌握了这套模式,你就拥有了为任意 RAG 对话系统加装事实核查护栏的完整工具箱。

登录后查看全文
Guardrails