AI PLAY玩法更新持续收录
← 回到更新流

2026-10-02 · 原文发布日

用本地Ollama给AI输出做事实核查闸门

一个离线可跑的n8n核查流:把任何AI输出POST进来,本地Ollama模型只抽取可核查的事实性声明(人名、数字、日期、事件),先从你的可信事实Data Table、再从维基百科(免费无需key)取证,评判模型给出VERIFIED/UNSUPPORTED/CONTRADICTED并必须附引文;纯代码校验引文逐字存在且能证明该条,否则降级。有矛盾即BLOCK,不支持过多即FLAG,模型宕机则fail closed返回FLAG。每周一邮件发送真实度得分周报。

原文要点

原模板是一个免费n8n工作流:AI输出经POST webhook进入,本地Ollama模型(作者用qwen3:4b-instruct)只抽取人名、数字、日期、事件类可核查声明;证据先查n8n Data Table的truth_facts,再查维基百科(免费无key),搜索主题由代码而非模型提取;评判模型给出VERIFIED/UNSUPPORTED/CONTRADICTED并必须附引文,纯代码校验引文逐字存在;矛盾即BLOCK,不支持比例过高即FLAG,模型宕机fail closed返回FLAG、真实度得分0;结果记录到truth_checks,每周一08:00邮件发周报并删除90天前记录。作者称在n8n 2.41.5实测端到端通过。

这次做成什么

在自己电脑上架一个离线事实核查闸门:任何AI生成的文字POST进来,逐条声明给出PASS/FLAG/BLOCK判定并附证据引文。练习方案:先不装完整模板,用本站给出的抽取提示词、评判提示词、引文校验代码和合成事实表,手工跑通一条假声明被BLOCK的完整链路,再去原模板对照配置。

准备什么

  • 安装Ollama并执行ollama pull qwen3:4b-instruct,或任一OpenAI兼容接口
  • n8n实例且支持Data Tables功能(作者测试版本为2.41.5)
  • 两个Data Table:truth_facts(fact、topic字符串列)与truth_checks(checked_at、request_id、source、decision、text_excerpt、details字符串列和truth_score、claims_total、verified、unsupported、contradicted数字列)
  • 可选:SMTP凭据用于告警与周报邮件,没有就停用两个邮件节点

具体怎么做

  1. 准备本地模型与事实表

    在本机运行ollama pull qwen3:4b-instruct并确认11434端口可访问;在n8n里新建Data Table truth_facts,录入你的可信事实行(先用本站的合成示例数据),再建truth_checks用于落日志。两张表按名称查找,名字不要改。

  2. 配置入口与模型地址

    打开模板的Read Request & Config节点,把LLM_URL设为Ollama的聊天接口;若n8n跑在Docker里,按原文说明用http://host.docker.internal:11434/v1/chat/completions(Linux需启动参数--add-host=host.docker.internal:host-gateway)。同时确认MAX_CLAIMS、FLAG_RATIO、BLOCK_ON_CONTRADICTED、USE_WIKIPEDIA等开关的默认值。

  3. 先用声明抽取提示词手工演练

    把本站artifacts里的抽取提示词粘贴到任意聊天窗口,输入一段含数字和日期的AI文字,确认模型只输出人名/数字/日期/事件类声明的JSON数组、忽略观点句。通过后再回到n8n,理解模板中对应的LLM节点在做什么。

  4. 理解评判与代码校验的双重闸门

    评判模型只能基于给定证据判定VERIFIED/UNSUPPORTED/CONTRADICTED且必须引用原文一句话;之后纯代码逐字检查引文是否真的出现在证据里、且数字吻合,证明不了的判定一律降级为UNSUPPORTED。用本站的校验代码示例在Code节点里跑一遍正反两个用例。

  5. 发布并POST测试

    点Test With Sample跑内置样例,确认无误后发布工作流,向/webhook/truth-gate发送{"text":"AI输出内容","source":"my-bot"},观察返回的decision与truth_score;再故意把Ollama关掉重发一次,应得到FLAG且truth_score为0(fail closed)。

可直接复制的材料

事实声明抽取提示词(本站编写,对应模板第一个LLM节点)

本站按模板职责独立编写;{{$json.text}}为n8n表达式占位,手工演练时替换为实际文字。

你是事实声明抽取器。从下面这段文字中,只抽取可以被外部证据核查的事实性声明:人名、数字与度量、日期与时间、历史或地理事件。严格忽略观点、评价、预测和建议。
对每条声明输出JSON数组的一项:{"claim": "声明原文", "type": "name|number|date|event", "subject": "用于检索证据的主题词"}。
不要改写声明的措辞,不要补充原文没有的信息,不要输出数组以外的任何文字。
待核查文字:
{{$json.text}}

评判提示词(本站编写,对应模板judge节点)

本站独立编写的练习提示词;{{claim}}与{{evidence}}为占位。模板还靠后续代码校验quote逐字存在,提示词只是第一层。

你是事实核查评判员。只能用下面提供的证据判断声明,禁止使用你自己的知识。
判决只能是三种之一:VERIFIED(证据明确支持)、UNSUPPORTED(证据不足或没有提到)、CONTRADICTED(证据明确矛盾,包括数字不一致)。
输出JSON:{"verdict": "...", "quote": "从证据中逐字复制的、能证明判决的一句话", "reason": "一句话说明"}。
quote必须逐字摘自证据,不得改写、不得拼接。没有可用证据时必须判UNSUPPORTED。
声明:{{claim}}
证据:{{evidence}}

truth_facts合成示例数据(CSV)

本站虚构的练习用可信事实,导入Data Table的truth_facts后配合下方示例输入使用。

fact,topic
埃菲尔铁塔高330米,埃菲尔铁塔
埃菲尔铁塔1889年建成于巴黎,埃菲尔铁塔
长江全长约6300千米,长江
水星是离太阳最近的行星,水星
2024年夏季奥运会在巴黎举行,奥运会

引文逐字校验代码(n8n Code节点,本站示例方案)

本站独立编写的简化版,只实现逐字存在校验;原模板还校验数字吻合和引文是否真正支撑该条声明,完整逻辑以原模板Code节点为准。

// 输入:judge输出 {verdict, quote} 与证据文本 evidence
// 规则:quote必须逐字出现在evidence中,否则降级为UNSUPPORTED
const judge = $json.judge;
const evidence = $json.evidence || "";
const quote = (judge.quote || "").trim();
const quoteFound = quote.length > 0 && evidence.includes(quote);
let finalVerdict = judge.verdict;
if (judge.verdict !== "UNSUPPORTED" && !quoteFound) {
  finalVerdict = "UNSUPPORTED";
}
return [{ json: { claim: $json.claim, verdict: finalVerdict, quote, quoteFound, reason: judge.reason || "" } }];

Read Request & Config关键字段示例

字段名以原模板节点为准;Docker部署时LLM_URL按原文改为http://host.docker.internal:11434/v1/chat/completions。本站未逐项核对节点内全部字段。

{"LLM_URL": "http://localhost:11434/v1/chat/completions", "MAX_CLAIMS": 10, "FLAG_RATIO": 0.5, "BLOCK_ON_CONTRADICTED": true, "USE_WIKIPEDIA": true, "WIKI_LANG": "zh"}

输入与输出示例

本站虚构演示:truth_facts中记的是330米,450米与之矛盾故CONTRADICTED触发BLOCK;非实际运行结果,truth_score计算方式以原模板为准。

输入

POST /webhook/truth-gate,正文:{"text": "埃菲尔铁塔高约450米,建成于1889年,是巴黎最高的建筑。", "source": "demo-bot"}

对应输出

{"decision": "BLOCK", "truth_score": 0.5, "claims_total": 2, "verified": 1, "unsupported": 0, "contradicted": 1, "details": [{"claim": "埃菲尔铁塔高约450米", "verdict": "CONTRADICTED", "quote": "埃菲尔铁塔高330米"}, {"claim": "建成于1889年", "verdict": "VERIFIED", "quote": "埃菲尔铁塔1889年建成于巴黎"}]}

做完检查这些

  • Ollama关闭时POST请求返回decision为FLAG且truth_score为0,证明fail closed生效
  • 评判输出中quote无法在证据文本里逐字找到时,Code节点把该条降级为UNSUPPORTED
  • truth_checks表在每次核查后新增一行,含decision、truth_score和各计数
  • 含矛盾声明的输入返回BLOCK,纯无证据声明的输入返回FLAG而非BLOCK

容易卡住的地方

  • n8n跑在Docker里却填localhost会连不上Ollama,需按原文用host.docker.internal并在Linux加--add-host参数
  • 没有SMTP账号却不停用两个邮件节点,告警流程会以错误状态结束,原文明确提示这一点
  • 模型可能编造不存在的引文,所以代码逐字校验不可省略,只信模型输出会失去闸门意义
  • USE_WIKIPEDIA设为true时需要外网访问维基百科;完全离线环境应设为false只查自有事实表
  • Data Table按名称查找,改名会导致找不到表

原文与作者资料 ↗

本站借助AI整理来源事实,独立编写中文操作指南与示例。示例不代表实际运行结果;来源效果尚未由本站独立复现。付费模板与模型、服务费用分别计算。

原文标题
Gate and score AI outputs with Ollama, Wikipedia, and data tables
原作者
SPIRIDON TSAKONAS
原始发布日期
2026-10-02T08:12:20.904Z
来源
https://n8n.io/workflows/20327