审核 AI 生成文章中的可验证事实,通过 web search 逐条校验,输出差异报告并支持用户审批替换。当用户需要事实核查、验证文章准确性、检查数据日期金额是否正确、去除 AI 幻觉内容、或 fact-check 一篇文章时使用。触发于"事实核查"、"验一下这些数据"、"检查事实"、"去幻觉"、"fact ch...
---
name: true-seeing
description: 审核 AI 生成文章中的可验证事实,通过 web search 逐条校验,输出差异报告并支持用户审批替换。当用户需要事实核查、验证文章准确性、检查数据日期金额是否正确、去除 AI 幻觉内容、或 fact-check 一篇文章时使用。触发于"事实核查"、"验一下这些数据"、"检查事实"、"去幻觉"、"fact check"、"核实文章"、"核实这段话"、"帮我对一下数据"、"这篇文章里的数字对不对"。不适用于语法纠错、翻译校对、纯观点验证、文风调整。
---
# True Seeing — AI 文章去幻觉校验
## 目的
识别文章中的可验证事实性陈述,通过 web search 逐条校验,输出差异报告供用户审批后替换。适用于 AI 生成内容的去幻觉化处理。
## Pipeline 架构
```
[article] → Stage 1: extract → fact_list → Stage 2: verify → report → 🛑 用户审批 → Stage 3: replace → corrected article
```
三个阶段支持独立调用(`stage` 参数)或全流程顺序执行(默认)。
**`stage=full` 模式的执行流程:**
1. 执行 Stage 1 → 输出 fact_list
2. 执行 Stage 2 → 输出 verification_report
3. **暂停。向用户呈现差异报告,等待用户回复 user_selections。**
4. 收到 user_selections 后执行 Stage 3 → 输出修正文章
Stage 2 完成后必须暂停等待用户审批,不得自动进入 Stage 3。
## 输入参数
| 参数 | 类型 | 必需 | 说明 |
|------|------|------|------|
| article | string | 是 | 待核查的文章全文或文件路径 |
| stage | enum | 否 | `extract` / `verify` / `replace` / `full`(默认 `full`) |
| fact_list | JSON | 条件必需 | `stage=verify` 时必需;Stage 1 的输出 |
| verification_report | JSON | 条件必需 | `stage=replace` 时必需;Stage 2 的输出 |
| user_selections | list[int] | 条件必需 | `stage=replace` 时必需;用户选择替换的有分歧事实编号 |
## 数据契约
### fact_list(Stage 1 输出 → Stage 2 输入)
```json
{
"article_summary": "文章主题一句话概括",
"total_facts": 5,
"facts": [
{
"id": 1,
"category": "funding",
"original_text": "XXX公司于2025年3月完成B轮融资5亿元",
"position": "第2段第3句",
"search_query": "XXX公司 B轮融资 2025年3月 金额"
}
]
}
```
### verification_report(Stage 2 输出 → Stage 3 输入)
```json
{
"summary": { "total": 5, "verified": 3, "corrected": 1, "remain": 1 },
"verified": [
{
"id": 1,
"original_text": "原文描述",
"source_url": "https://...",
"source_snippet": "网页上的对应描述"
}
],
"corrected": [
{
"id": 2,
"original_text": "原文描述",
"actual_fact": "实际查找到的信息",
"source_url": "https://...",
"source_snippet": "网页上的对应描述",
"divergence_type": "number_mismatch | date_mismatch | event_nonexistent | entity_mismatch"
}
],
"remain": [
{
"id": 3,
"original_text": "原文描述",
"search_queries_tried": ["query1", "query2"],
"note": "未找到可验证的搜索结果"
}
]
}
```
---
## Stage 1: Extract(事实抽取)
### 输入
- `article`:文章全文
### 执行步骤
1. **通读全文**,逐段扫描。
2. **按 `references/fact-extraction-rules.md` 中的分类规则**,标记每一条可验证的事实性陈述。
- 跳过:观点、推测、评价、定性描述(如"市场前景广阔")。
- 标记:包含具体数字、日期、金额、事件名称、人物+动作的陈述。
3. **对每条标记事实**,记录:
- `id`:自增编号,从 1 开始
- `category`:分类标签(funding / pricing / date / event / statistic / personnel / product / other)
- `original_text`:原文中的完整句子或分句
- `position`:段落+句子位置描述
- `search_query`:转化为适合 web search 的关键词查询(去掉虚词,保留实体+关键信息)
4. **批量上限检查**:如果标记事实数量超过 30 条,仅保留前 30 条,在输出中附注"发现 N 条事实,已截取前 30 条。如需继续,请将剩余部分作为新输入。"。
5. **输出 `fact_list` JSON**。
6. **质量自检**:
- 每条事实都有 id、category、original_text、position、search_query。
- search_query 不包含虚词和上下文依赖词。
- 总数 ≤ 30。
### 停止条件
- 文章为空或不含可验证事实 → 输出空 fact_list,附注"未发现可验证事实"。
- 事实数量超过 30 条 → 截取前 30 条,附注截取说明。
### search_query 构造规则
- 提取核心实体(公司名、人名、产品名)
- 保留关键数值和日期
- 去掉修饰词和上下文依赖词
- 如有歧义,生成 2 个备选查询(用 `|` 分隔)
---
## Stage 2: Verify(事实校验)
### 输入
- `fact_list`:Stage 1 输出的 JSON
### 事实状态机
每条事实在处理过程中有以下状态:
| 状态 | 含义 |
|------|------|
| `Unverified` | 初始状态,待处理 |
| `keywords-generated` | 已生成检索词,待搜索 |
| `fact-fetch` | 已获取搜索结果,待比对 |
| `Verified` | 终态:内容无误 |
| `Corrected` | 终态:内容已修正 |
| `Remain` | 终态:保持不变(无法验证或用户选择保留) |
状态转换规则:
```
Unverified ──(生成检索词成功)──→ keywords-generated
Unverified ──(生成检索词失败)──→ 留在 Unverified,回到大池子
keywords-generated ──(搜索成功)──→ fact-fetch
keywords-generated ──(搜索失败)──→ 留在 keywords-generated,等当前批次步骤 5 重试
fact-fetch ──(比对:内容无误)──→ Verified
fact-fetch ──(比对:内容有差异)──→ Corrected
fact-fetch ──(比对:结果模糊/无法判定)──→ Remain
```
### 执行步骤
1. **前置检查**:执行一次 `web_search`,查询 `"test"`,确认 Brave Search 可用。
- 成功 → 继续。
- 失败 → **abort**,向用户输出错误信息:"web_search (Brave) 当前不可用,无法执行事实校验。建议过一段时间再试。",流程终止。
2. **初始化**:将 fact_list 中所有事实放入 `unverified_pool`(大池子),创建空的 `done_pool`(已完成池)。
3. **进入循环**(最多 5 轮):
**3a.** 从 `unverified_pool` 中捞出最多 5 条 Unverified 事实,形成当前批次的 `batch_pool`(小池子)。如果 `unverified_pool` 为空,跳到步骤 4。
**3b.** 对 `batch_pool` 中的每条事实,按 `references/search-query-templates.md` 生成检索词:
- 成功 → 状态变为 `keywords-generated`。
- 失败 → 状态保持 `Unverified`,移出 `batch_pool`,放回 `unverified_pool`(大池子)。
**3c.** 对 `batch_pool` 中所有 `keywords-generated` 的事实,使用 `sessions_spawn` 启动 sub-agent 并行搜索:
- 每个 sub-agent 执行 `web_search`,取前 3 条结果用 `web_fetch` 抓取内容。
- 搜索返回 ≥1 条包含原文实体的结果 → 状态变为 `fact-fetch`。
- 搜索返回 0 条包含原文实体的结果,或工具返回错误 → 状态保持 `keywords-generated`,留在 `batch_pool`。
**3d.** 对 `batch_pool` 中所有 `fact-fetch` 的事实,按 `references/verification-criteria.md` 逐要素比对:
- 所有要素一致 → 状态变为 `Verified`。
- 有关键要素不一致 → 状态变为 `Corrected`,记录 actual_fact + source_url + divergence_type。
- 搜索结果与原文的实体/数值/日期无直接对应关系 → 状态变为 `Remain`,附注原因。
**3e.** 对 `batch_pool` 中仍然停留在 `keywords-generated` 的事实(搜索失败的),换策略重搜一次:
- 换策略规则:换用英文查询 / 去掉数值只搜实体+事件 / 扩大时间范围(按 `references/search-query-templates.md` 重试策略)。
- 成功 → 回到步骤 3d 处理。
- 失败 → 状态变为 `Remain`,附注"搜索重试失败"。
**3f.** 当前批次处理完毕:
- `batch_pool` 中已达终态(Verified / Corrected / Remain)的事实 → 移入 `done_pool`。
- `batch_pool` 中仍有未达终态的事实 → 放回 `unverified_pool`。
**3g.** 检查 `unverified_pool` 是否为空。空 → 跳到步骤 4。非空 → 回到 3a 开始下一轮。
4. **循环结束**:
- 循环 5 轮后 `unverified_pool` 中仍有 Unverified 事实 → 全部标记为 `Remain`,附注"超过最大轮次(5轮)仍未验证",移入 `done_pool`。
- 合并 `done_pool` 中所有事实,输出 `verification_report` JSON。
5. **质量自检**:
- Verified 事实都有 source_url。
- Corrected 事实都有 actual_fact + source_url + divergence_type。
- Remain 事实都有 search_queries_tried + note。
- 无事实停留在中间状态(Unverified / keywords-generated / fact-fetch)。
### 并行处理规则
- 步骤 3c 中,当前批次内所有 `keywords-generated` 的事实同时启动 sub-agent 搜索,不逐条等待。
- 每个 sub-agent 内部保持搜索节流(间隔 ≥ 2 秒)。
- 单个 sub-agent 最多使用 2 个搜索查询 + 3 次 web_fetch。
- 如果 sub-agent 执行失败,该条事实状态保持 `keywords-generated`,等步骤 3e 重试。
### 停止条件
- 前置检查 web_search 不可用 → abort,向用户报错。
- 搜索结果全部为 429 → 当前批次暂停,已完成的批次结果保留,未完成的标记为 Remain 附注"因 rate limit 中断"。
- 循环 5 轮结束 → 兜底,剩余 Unverified 标记 Remain。
---
## Stage 3: Replace(审批 + 替换)
### 输入
- `article`:原文
- `verification_report`:Stage 2 输出的 JSON
- `user_selections`:用户选择替换的有分歧事实编号列表
### 执行步骤
1. **呈现差异报告**,格式如下:
```markdown
# 事实核查报告
## 有分歧的事实(Corrected)
| 编号 | 原文事实 | 实际查找到的事实 | 出处 |
|------|---------|----------------|------|
| {id} | "{original_text}" | "{actual_fact}" | [来源]({source_url}) |
## 无分歧的事实(Verified)
| 编号 | 原文事实 | 佐证出处 |
|------|---------|----------|
| {id} | "{original_text}" | [来源]({source_url}) |
## 未能验证的事实(Remain)
| 编号 | 原文事实 | 备注 |
|------|---------|------|
| {id} | "{original_text}" | {note} |
```
2. **等待用户回复**,格式为:用户给出「有分歧的事实」表格中的编号(如 `2, 5`)。空回复或不修改 → 输出原文不变,流程结束。
3. **根据 user_selections 执行替换**:
- 在原文中定位对应编号的 `original_text`
- 替换为 `actual_fact`
- 在替换处追加 citation 标记 `[^fc-{id}]`(如 `[^fc-2]`),使用 `fc-` 前缀避免与原文已有脚注编号冲突
- 在文末追加参考来源列表
4. **输出修正后的文章**,文末附:
```markdown
---
## 参考来源
- [^fc-1] {source_url} — {source_snippet 摘要}
- [^fc-2] {source_url} — {source_snippet 摘要}
...
```
5. **质量自检**:
- 替换后的文章保持原文结构,仅修改事实部分。
- citation 编号 `[^fc-{id}]` 与参考来源一一对应。
- 用户未选择的事实保持原样未修改。
### 替换规则
- 替换时保持原文句式结构,只替换有差异的事实部分,不重写整句。
- 如果用户选择的编号包含 Remain 状态的事实,提示用户该事实无法验证,确认是否仍要保留原文。
---
## 故障处理
| 故障场景 | 行为 |
|---------|------|
| 文章为空 | 输出错误信息:"文章内容为空,无法执行事实核查" |
| fact_list 为空 | 输出:"未发现可验证事实",流程结束 |
| web_search 不可用 | abort,输出错误信息:“web_search (Brave) 当前不可用,无法执行事实校验。建议过一段时间再试。” |
| 搜索结果全部 429 | 输出已完成部分,标记中断位置 |
| 原文找不到对应位置 | 跳过该条替换,在输出中标注"原文未找到匹配位置" |
| 用户选择的编号不存在 | 提示"编号 X 不在差异列表中",忽略无效编号 |
## 质量门槛
执行完成后自检:
- [ ] 每条事实都有明确的分类和编号
- [ ] Verified 事实都有 source_url
- [ ] Corrected 事实都有 actual_fact + source_url + divergence_type
- [ ] Remain 事实都有 search_queries_tried + note
- [ ] 替换后的文章保持原文结构,仅修改事实部分
- [ ] citation 编号与参考来源一一对应
- [ ] 用户未选择的事实保持原样未修改
## 范围边界
**做:** 校验文章中的可验证事实性陈述(数据、日期、金额、事件等)。
**不做:** 语法纠错、观点验证、逻辑推理验证、翻译质量检查。
**移交:** 如果文章需要专业领域事实核查(法律条文、医学数据),提示用户建议由领域专家复核。
don't have the plugin yet? install it then click "run inline in claude" again.