0Smallcat0/report-workflow
GitHub: 0Smallcat0/report-workflow
一个确定性的证据溯源验证层,在 LLM 起草的报告发布前机械性地拦截所有无法追溯到已注册证据的声明。
Stars: 0 | Forks: 0
# Report Workflow
[](https://github.com/0Smallcat0/report-workflow/actions/workflows/ci.yml)


[](LICENSE)
**一个确定性的验证层,允许 LLM 起草报告,但拒绝发布任何无法追溯到已注册证据的声明。**
LLM 会编写流畅的文本,并且时不时地捏造数字、错误引用来源,或者引用不存在的研究。这对于聊天回复来说没问题,但在实验室报告、客户备忘录或招生文件中是不可接受的。Report Workflow 在*起草*和*发布*之间设置了一个可检查的边界:由模型提出建议,而由确定性的 pipeline 决定什么内容允许发布。
这个 Python 包**不调用 LLM,也不需要 API key。** 它负责源文件解析、证据账本、artifact 契约、验证关卡、DOCX 渲染和可追溯性打包。外部 agent(Codex、Claude Code、Hermes 等)负责判断和起草。每一项可发布的声明都必须链接到能够切实支持它的证据,否则会在进入文档前被硬性拦截。
**明确说明范围。** 这是一个用于基于证据写作的*保真度关卡*,而不是通用的幻觉检测器。由于这些检查是机械性的,它们能够可靠地捕获捏造的数字、虚假的引用、错误的引文和单位混淆——但它们不判断含义,因此一种悄悄颠倒来源(“A 在 B 之前” → “B 在 A 之前”)的流畅复述不在范围内。这个边界并没有被隐藏;它在下文的外部数据中进行了测量(§[out-of-domain](#out-of-domain-halueval-qa-10000-pairs-nobody-here-wrote))。
## 用五行代码验证任何 LLM 的答案
不需要 pipeline、schema 和 API key —— 只需传入答案及其理应依据的源文本:
```
from report_workflow import verify
result = verify(
answer="The error rate fell to 0.2% [1].",
sources={"1": "The error rate fell to 3.5% under the structured workflow."},
)
result["publishable"] # False
result["sentence_results"][0]["checker"] # "FE"
result["sentence_results"][0]["reason"] # "Claim number '0.2'% not found in evidence content (evidence has: 3.5%)..."
```
`verify()` 将答案拆分为句子(支持英文和 CJK),将其 `[id]` 标记引用的每个句子限定在相应的源文本内(与任何源都不匹配的标记即为虚假引用,并会被拦截),针对每一个源测试无标记的句子,只要任何一个源能够完全支撑该句子即视为通过,而对于其他所有情况一律判定为失败。这与完整 pipeline 和 MCP server 使用相同的确定性关卡堆栈:作为 `(answer, sources)` 的纯函数——每次运行结果相同,零 token 消耗,支持离线运行和 CI 环境。
## 30秒看懂它
这个关卡是真实的代码,而不是文字描述。这个 demo 针对一个微型的证据账本运行了 pipeline 所使用的确切事实核查器——没有 LLM,也没有网络:
```
python examples/anti_hallucination_gate.py
```

LLM 静默放行的两种失败模式——一个引用了真实证据的**捏造统计数据**,和一个指向不存在来源的**虚假引用**——都被捕获,并附带了阻止它们的具体关卡和原因。诚实且具有充分依据的声明则原封不动地通过,因此该关卡具有辨别力,而不仅仅是严格。来源:[`examples/anti_hallucination_gate.py`](examples/anti_hallucination_gate.py)。
无需本地安装:
[](https://colab.research.google.com/github/0Smallcat0/report-workflow/blob/master/docs/quickstart_demo.ipynb)
在浏览器中运行该关卡,或者在 GitHub Codespaces 中打开该代码库([dev container](.devcontainer/devcontainer.json) 会安装所有依赖并在创建时运行 demo)。
## 红队证据:拦截率是测量出来的,不是空口无凭
一个只看到诚实草稿的关卡证明不了什么。对抗性基准测试通过确切的关卡堆栈运行了 **58 个手工审计的案例**——包含 13 个攻击家族(虚假引用、捏造统计数据、单位混淆、捏造引文、精度虚高、跨语言洗白、跑题引用、状态洗白、中文文本捏造、过度声明等)中的 20 个诚实对照组和 38 个幻觉声明,并在相同的语料库上对比了两个基线:
| 检查器 | 召回率 (拦截的幻觉) | 误报率 (拦截的诚实声明) | Precision |
| --- | --- | --- | --- |
| 无关卡 (全部发布) | 0.0% | 0.0% | — |
| 引用存在检查 (浅层 RAG 风格) | 10.5% | 0.0% | 100% |
| **完整的确定性关卡堆栈** | **89.5%** (34/38) | **0.0%** (0/20) | **100%** |
所有 13 个针对性攻击家族均以 100% 被拦截,且没有任何诚实声明被错误拦截。2026-07-14 的关卡强化修复了以前记录在案的三个规避手段(容差内的精度篡改、少于10个字符的捏造引文、跨语言引用洗白),并将它们升级为常规攻击家族。剩余的 4 个漏网之鱼是**已记录在案的规避手段**(否定反转、没有单位的纯数字、打擦边球的重新解读、数值归因错误),它们被故意保留在语料库中,作为测量出的剩余风险边界——详见 [`docs/DESIGN.md`](docs/DESIGN.md) 的局限性部分。该语料库兼作回归测试套件:预期判定结果在 CI 中被断言,并且 sha256 判定哈希证明了该堆栈是确定性的且可跨平台复现。
```
python scripts/run_adversarial_benchmark.py --check # re-run from source, diff vs archive
```
完整表格:[`benchmarks/evidence/adversarial_2026-07-14/summary.md`](benchmarks/evidence/adversarial_2026-07-14/summary.md)。
### 域外测试:HaluEval QA,10,000 对非本团队编写的数据
上面的语料库是为本项目编写的。为了测量在不受本团队控制的数据上的表现,`verify()` 在公开的 [HaluEval](https://github.com/RUCAIBox/HaluEval) QA 基准测试(Li et al., EMNLP 2023)上运行:10,000 对基于知识的问答,每对都有一个正确答案和一个幻觉答案——共 20,000 个判定,零 token 消耗。
| 指标 | 值 |
| --- | --- |
| 误报率 (拦截的正确答案) | **0.06%** (6/10,000) |
| 拦截判定的 Precision | **99.7%** |
| 召回率 — 所有幻觉 | 23.2% (2,320/10,000) |
| 召回率 — 包含数字的子集 (带有数字+单位的答案) | 66.7% |
客观地看待它:HaluEval 的幻觉是开放域的*实体替换*,专门设计来复用段落本身拥有的词汇——这一类别在 [`docs/DESIGN.md`](docs/DESIGN.md) 中被明确置于确定性词法检查的范围之外。域外测试的声明在于其**严谨性**,而不是召回率:这些关卡几乎从不误报(所有六个误报案例都在存档中进行了特征分析——即那些将开头数字解析为测量值的电影片名和街道地址),并且它们发出的每一次拦截几乎可以肯定都是真实的幻觉。linter 不能抓住每一个 bug;但它绝对不能对它标记出的 bug 撒谎。
```
python scripts/run_external_benchmark.py --download # fetch + sha256-verify the dataset (6 MB)
python scripts/run_external_benchmark.py --check # recompute all 20,000 verdicts, diff vs archive
```
完整分析:[`benchmarks/evidence/halueval_qa_2026-07-15/summary.md`](benchmarks/evidence/halueval_qa_2026-07-15/summary.md)。
## 它与 LLM-as-judge 工具的关系
这**不是** RAGAS、TruLens、DeepEval 或 Guardrails 的竞争对手——它做的是不同且更狭窄的工作。那些工具询问模型(LLM 或训练过的分类器)*“这个输出是有依据的吗?”*,并获得语义上的观点:它们可以判断复述和含义,但代价是需要 API key 或 GPU、每次调用的延迟,以及不同运行之间可能发生变化的判定结果。这个项目根本不做判断。它机械地检查一件事——**文本中的数字、引用和引文是否确实出现在来源中?**——作为一个纯函数,因此每次运行得到的答案都是相同的,而且你可以清楚地看到句子被拦截的确切原因。
| | LLM-as-judge 工具 | 这个保真度关卡 |
| --- | --- | --- |
| 它回答的问题 | “这是否有依据/忠实?” (语义层面) | “数字/引用/引文是否与来源匹配?” (机械层面) |
| 判定来源 | 模型观点 (通过提示词或训练得到) | (声明, 证据) 的纯函数 |
| 相同输入 → 相同判定 | 不保证 | 保证,在 CI 中由 sha256 证明 |
| 离线 / 无需 API key / 无需 GPU | 通常不行 | 总是可以 |
| 每 10,000 次检查的成本与延迟 | 每次调用按 LLM 定价,耗时数秒 | 零 token,每次仅需毫秒 |
| 捕捉复述 / 实体替换的含义 | 是——这正是它们的作用 | 否——需要它所不具备的语义能力 |
| 捕捉捏造的数字、虚假的引用、错误的引文、单位混淆 | 取决于提示词 | 确定性地捕捉,并给出原因 |
它们是互补的,同时使用两者的诚实做法是先运行这种廉价的确定性检查,然后将判断调用仅花费在通过检查的内容上。它是一个基准底线,而不是语义判断的替代品。
## 适用人群
- **需要 CI 关卡的 RAG / agent pipeline。** 在测试中使用 `verify(answer, sources)` 意味着溯源回归测试会导致构建失败——就像 linter 一样,不需要评估预算,也没有不稳定(flaky)的评判器。MCP server 在输出到达用户之前,在 runtime 为任何 agent 提供相同的关卡。
- **受证据约束的文档。** 完整的 pipeline(这个代码库的初衷)适用于每一项声明都必须追溯到已注册来源的报告——实验室报告、财务备忘录、法规草案——并渲染出可审计的 DOCX,附带 QA 包,能够逐句证明为什么允许它发布。
- **任何日后必须解释发布决定的人。** 判定结果是纯函数:可缓存、可 diff、编辑后可重新测试,并且拦截原因指明了关卡和证据。“模型觉得它是有依据的”不是审计跟踪;这个才是。
**不适用人群:** 幻觉属于流畅的复述并复用来源词汇的开放域聊天——这是语义蕴含的领域(已记录在案的规避手段),在这个领域 NLI 模型或 LLM judge 才能体现其价值。两层都使用;这一层是廉价、诚实的底线。
## 其端到端运行的证据
七个 profile 的基准测试从一个受控的来源为每个内置 profile 准备、起草(使用确定性的合成作者)、验证并渲染报告。存档的运行是可复现且可通过机器检查的:
```
python scripts/run_report_benchmarks.py --check # validate archived evidence
python scripts/run_report_benchmarks.py # regenerate from scratch
```
存档结果 ([`benchmarks/evidence/full_benchmark_2026-05-13/summary.md`](benchmarks/evidence/full_benchmark_2026-05-13/summary.md)):
| 指标 | 结果 |
| --- | --- |
| 端到端通过的 profile 数量 | **7 / 7** |
| 针对证据验证的声明 | **42** (每个 profile 6 个), **0 个被拦截** |
| 未解决的引用审计条目 | **0** |
| 交付 QA 决策 | 每个 profile 均为 `pass` |
| 单元测试 | **351 个通过** |
每份报告都与其 QA 包(`final_qa_summary`、factuality、学术质量、图表视觉、模板样式和渲染布局报告)打包在一起,因此发布决定是事后可审计的,而不仅仅是口头断言的。
由该基准测试生成的已渲染工程实验室报告页面——目录、标题和摘要,以及一张基于源数据得出的图表:

## 工作原理
```
flowchart LR
SRC[Sources
text - csv - pdf - docx] --> PREP subgraph PREP[1 - Prepare - deterministic] EV[Evidence ledger] TB[Agent task briefs] end PREP --> AUTH subgraph AUTH[2 - Author - external LLM agent] CM[claim_matrix] DR[section drafts +
sentence_map] end AUTH --> VAL subgraph VAL[3 - Validate and Render - deterministic gates] G1[Citation linkage] G2[Factuality FA FB FE FD] G3[Profile + QA gates] end VAL -->|qa_decision = pass| PUB[Published DOCX
+ traceability pack] VAL -->|claim not grounded| BLK[Hard block] ``` 1. **Prepare** 解析源文件并写出确定性 artifact (`report_spec.json`, `report_profile.json`, `blueprint.json`, `source_registry.json`, `evidence_ledger.jsonl`, 和 `agent_tasks/*.md`)。 2. **Author** —— 外部 agent 编写 `claim_matrix.json`, `outline.json`, `section_drafts/*.md` (或 `structured_drafts.json`), 和 `sentence_map.jsonl`。 3. **Validate and render** 检查 artifact 完整性、章节契约、 引用链接、事实准确性、profile 策略、图表契约和 QA 关卡, 然后进行渲染。`render` 仅在通过验证的检查点记录了 `qa_decision=pass`、通过的 `qa_summary.json`、干净的 `factuality_report.json`没有未解决的引用审计条目时才会运行。 事实准确性关卡是分层的:**FA** 确认声明/证据/句子的链接并拒绝虚假引用;**FB** 要求为统计声明提供定量证据;**FE**(深度审计)将声明内容与证据内容进行对比,捕捉源文件中不存在的捏造数字和引文短语;**FD** 根据证据等级检查措辞力度。详见 [`src/report_workflow/nodes/factuality_check.py`](src/report_workflow/nodes/factuality_check.py)。 ## 安装 仅验证关卡(`verify()`、事实核查器、MCP server)只需要此包——不需要外部工具: ``` pip install "git+https://github.com/0Smallcat0/report-workflow" # PyPI 版本发布通过 trusted publishing 进行关联(参见 docs/RELEASING.md); # 一旦打上 tag:pip install report-workflow ``` 对于从源文件到 DOCX 的完整 pipeline,请从克隆安装并添加 pandoc: ``` pip install -r requirements.txt pip install -e . ``` 如果 `report-workflow` 命令静默失败(在 Windows 上很常见,因为多个 Python 安装在 PATH 上留下了过时的 `report-workflow.exe`),请使用与 PATH 无关的形式——它始终在您调用的解释器上运行: ``` python -m report_workflow prepare --help ``` 用于实现完全保真渲染所需的外部工具: ``` pandoc --version ``` Pandoc 3.x 是主要的 DOCX 渲染器。如果没有 pandoc,workflow 将回退到功能受限的 `python-docx` 渲染器,输出的表格、列表和布局保真度可能会降低。 可选集成: - `mmdc` (`npm install -g @mermaid-js/mermaid-cli`) 用于绘制 Mermaid 图表。 - `TAVILY_API_KEY`、`SERPER_API_KEY` 或 `SERPAPI_API_KEY` 用于可选的网络研究。 - `notebooklm-py` 用于可选的 NotebookLM 同步。 - `pip install -e .[mcp]` 用于 MCP server (`report-workflow-mcp`)。 ## CLI ``` report-workflow prepare ` --prompt "write an engineering lab report from these sources" ` --source C:\path\to\source.txt ` --output C:\path\to\out ` --profile engineering_lab_report ` --preflight-decisions C:\path\to\preflight_decisions.json ` --template-field course_name="Control Systems" report-workflow validate --job-id
report-workflow render --job-id
report-workflow status --job-id
report-workflow run --job-id
```
`prepare` 需要一条 `--preflight-decisions` JSON 记录,以确认用户的安装、降级渲染和可选功能决策。必需的依赖项必须在启动前真正通过预检;仅凭一个决策字符串并不能覆盖仍然缺失的依赖项。这反映了 agent-skill 的 `preflight_decisions` 契约,而不是从原始 CLI 静默启动。
`--source PATH:ROLE` 可以重复使用。有效角色为 `source_data` 和 `base_document`。仅当尾部的标记完全匹配有效角色时,才会解析该角色后缀,因此像 `C:\path\to.txt` 这样的 Windows 路径是安全的。
CLI 退出代码:
- `0`: 成功
- `1`: 崩溃
- `2`: 硬性拦截的验证失败
- `3`: 等待用户决策或 agent 编写的 artifact
## MCP server
任何具备 MCP 能力的 agent(Claude Code、Codex、Cursor、自定义 harness)都可以作为工具调用相同的确定性关卡——利用自身的判断进行起草,然后通过 `verify_claims` 询问每个声明是否允许发布:
```
pip install "report-workflow[mcp] @ git+https://github.com/0Smallcat0/report-workflow"
claude mcp add report-workflow -- report-workflow-mcp
```
工具:`verify_claims`(带有关卡和原因的每个声明判定结果),`list_report_profiles`,`get_workflow_status`。详细信息和 payload 示例:[`docs/mcp.md`](docs/mcp.md)。
## Report Profile
`report_profile` 是唯一公开的报告结构选择器。内置 profile:`engineering_lab_report`、`academic_paper`、`business_report`、`proposal`、`admissions_report`、`admissions_project_report` 和 `custom`。除非提供了 `--profile` 或 `report_profile`,否则 pipeline 会根据提示词推断出一个 profile。
Profile 的用途和严格程度记录在 `agent_skill/reference/profiles.md` 中;注册表位于 `src/report_workflow/profiles.py`。
## 参考模板
Profile 控制参考模板的行为。默认模式是 `style_reference`(使用 DOCX 作为样式/布局参考);如果用户要求完全保留封面或格式,workflow 将升级为 `fixed_template`。Profile 契约的优先级高于提示词和模板提示。工程类封面的精确处理详见 `agent_skill/reference/engineering-lab.md`。
## 质量关卡
核心硬关卡:必须注册并解析源文件;证据账本不能为空;声明必须引用有效的证据 ID;声明状态不能是 `blocked`、`unverified` 或 `disputed`;有证据支撑的句子必须包含匹配的 `[CITE:]` 占位符;引用审计必须得到解决;占位符文本和假元数据会被拦截;并且渲染操作需要 `qa_decision=pass`。Profile 策略会调整前言、摘要结构、引用样式、参考验证以及图表/表格契约的严格程度。权威关卡列表位于 [AGENTS.md](AGENTS.md)。
## 基准测试
在改进跨 profile 的报告质量时,请使用 `benchmarks/`。运行 `python scripts/run_report_benchmarks.py` 以执行七 profile 的 prepare-author-validate-render 基准测试,或者运行 `python scripts/run_report_benchmarks.py --check` 来验证存档的证据而无需重新运行。`python scripts/run_adversarial_benchmark.py` 会重新生成对抗性拦截率证据(`--check` 从源头验证它)。优先进行基准测试的优化方法和差距分类法记录在 `agent_skill/reference/benchmarking.md` 中。
## 测试
```
python -m compileall -q src tests
python -m unittest discover -s tests -v
```
## 设计理念
Report Workflow 是一个总体理念的具体实例:**基于证据边界的生成。** 只要一项声明必须追溯到某个来源——无论是工程实验室报告、每个数字都引用了财务报表的财务备忘录、法规文件,还是基于真实项目的招生文书——值得信任的部分不是流畅的草稿,而是能够*证明*每一项陈述并拒绝它无法证明的内容的这一层。保持这一层的确定性(检查器中不包含 LLM)使得判定结果是可复现和可审计的,而不是另一种概率性的观点。
该代码库由其作者进行了规范制定、整合和验证,并在实现过程中大量使用了编码 agent。确定性的关卡和基准测试框架的存在,正是为了让人类(而不是模型)掌握最终的“这是否正确?”的决定权——这与该工具在其生成的文档中所强制执行的原则相同。
## 仓库指南
- **为什么这样构建 + 测得的局限性** → [`docs/DESIGN.md`](docs/DESIGN.md)
(威胁模型、架构基本原理、评估、客观的局限性)。
- **操作此 skill 以生成报告** → [`agent_skill/SKILL.md`](agent_skill/SKILL.md)
及其 `reference/` 文件。
- **开发此代码库** → [AGENTS.md](AGENTS.md)(权威契约:
布局、阶段列表、artifact 契约、硬关卡、扩展点)。
- **贡献者切入点** → [AGENT_ONBOARDING.md](AGENT_ONBOARDING.md)。
最终 artifact 打包在 `output/--/published/` 下,
交付 QA 位于 `published/qa/` 中。请参阅 [AGENTS.md](AGENTS.md) 了解规范的阶段列表和完整的 QA artifact 契约。
text - csv - pdf - docx] --> PREP subgraph PREP[1 - Prepare - deterministic] EV[Evidence ledger] TB[Agent task briefs] end PREP --> AUTH subgraph AUTH[2 - Author - external LLM agent] CM[claim_matrix] DR[section drafts +
sentence_map] end AUTH --> VAL subgraph VAL[3 - Validate and Render - deterministic gates] G1[Citation linkage] G2[Factuality FA FB FE FD] G3[Profile + QA gates] end VAL -->|qa_decision = pass| PUB[Published DOCX
+ traceability pack] VAL -->|claim not grounded| BLK[Hard block] ``` 1. **Prepare** 解析源文件并写出确定性 artifact (`report_spec.json`, `report_profile.json`, `blueprint.json`, `source_registry.json`, `evidence_ledger.jsonl`, 和 `agent_tasks/*.md`)。 2. **Author** —— 外部 agent 编写 `claim_matrix.json`, `outline.json`, `section_drafts/*.md` (或 `structured_drafts.json`), 和 `sentence_map.jsonl`。 3. **Validate and render** 检查 artifact 完整性、章节契约、 引用链接、事实准确性、profile 策略、图表契约和 QA 关卡, 然后进行渲染。`render` 仅在通过验证的检查点记录了 `qa_decision=pass`、通过的 `qa_summary.json`、干净的 `factuality_report.json`没有未解决的引用审计条目时才会运行。 事实准确性关卡是分层的:**FA** 确认声明/证据/句子的链接并拒绝虚假引用;**FB** 要求为统计声明提供定量证据;**FE**(深度审计)将声明内容与证据内容进行对比,捕捉源文件中不存在的捏造数字和引文短语;**FD** 根据证据等级检查措辞力度。详见 [`src/report_workflow/nodes/factuality_check.py`](src/report_workflow/nodes/factuality_check.py)。 ## 安装 仅验证关卡(`verify()`、事实核查器、MCP server)只需要此包——不需要外部工具: ``` pip install "git+https://github.com/0Smallcat0/report-workflow" # PyPI 版本发布通过 trusted publishing 进行关联(参见 docs/RELEASING.md); # 一旦打上 tag:pip install report-workflow ``` 对于从源文件到 DOCX 的完整 pipeline,请从克隆安装并添加 pandoc: ``` pip install -r requirements.txt pip install -e . ``` 如果 `report-workflow` 命令静默失败(在 Windows 上很常见,因为多个 Python 安装在 PATH 上留下了过时的 `report-workflow.exe`),请使用与 PATH 无关的形式——它始终在您调用的解释器上运行: ``` python -m report_workflow prepare --help ``` 用于实现完全保真渲染所需的外部工具: ``` pandoc --version ``` Pandoc 3.x 是主要的 DOCX 渲染器。如果没有 pandoc,workflow 将回退到功能受限的 `python-docx` 渲染器,输出的表格、列表和布局保真度可能会降低。 可选集成: - `mmdc` (`npm install -g @mermaid-js/mermaid-cli`) 用于绘制 Mermaid 图表。 - `TAVILY_API_KEY`、`SERPER_API_KEY` 或 `SERPAPI_API_KEY` 用于可选的网络研究。 - `notebooklm-py` 用于可选的 NotebookLM 同步。 - `pip install -e .[mcp]` 用于 MCP server (`report-workflow-mcp`)。 ## CLI ``` report-workflow prepare ` --prompt "write an engineering lab report from these sources" ` --source C:\path\to\source.txt ` --output C:\path\to\out ` --profile engineering_lab_report ` --preflight-decisions C:\path\to\preflight_decisions.json ` --template-field course_name="Control Systems" report-workflow validate --job-id
标签:AI, LLM, Python, Unmanaged PE, 数据溯源, 文档生成, 无后门, 自动化代码审查, 自动化校验, 逆向工具