tsmith-surgexi/verified-rag

GitHub: tsmith-surgexi/verified-rag

一个通过验证门机制确保检索增强生成中每条引文都真实可溯源、无法被捏造的参考实现。

Stars: 0 | Forks: 0

# 🔒 verified-rag [![ci](https://static.pigsec.cn/wp-content/uploads/repos/cas/99/993938d8ce5e902ccfb9d6747725c320d855dea3235ed9a304cedf0d94c9321f.svg)](https://github.com/tsmith-surgexi/verified-rag/actions/workflows/ci.yml) [![license: source-available](https://img.shields.io/badge/license-source--available-blue.svg)](LICENSE) [![python](https://img.shields.io/badge/python-3.12-blue.svg)](requirements.txt) 这是我在生产环境中使用的“绝不捏造”模式的净室参考实现。 它运行在一个微小的**公有领域**玩具语料库上,且**无需任何 API 密钥**,因此您可以一口气通读该技术始末。 ## 观察其运行 — 真实输出,零密钥 `python -m verified_rag.demo` 针对一个小型公有领域语料库运行,无需 API 密钥: ``` (2) Un-groundable query -> HONEST abstention, no invented cite Q: What is the airspeed velocity of an unladen swallow? A: Not supported by the corpus. [ABSTAINED - nothing verifiable] (3) Adversarial synthesizer -> it TRIES to emit an invented key and a one-character-tampered quote. The gate drops both: VERIFIED [policy-returns#c1] - quote is verbatim (sha256=a3ccde9d...) DROPPED [supreme-court-9000#c1] - unknown citation key, not in corpus DROPPED [policy-returns#c1] - quoted text is not a verbatim substring (altered/invented) ``` 捏造的引文和被篡改的引用在**发布前**就会被丢弃——不存在任何会输出未验证引文的代码路径。 ## 问题所在:LLM 会自信地捏造引文 在 *Mata v. Avianca* (2023) 一案中,一名律师提交了一份引用了**根本不存在**的司法意见的案情摘要——LLM 捏造了案件名称、引言和判例汇编引证,并且它们看起来完全真实。法院对此实施了制裁。 这种失败模式并非法律行业的特例;这是要求语言模型基于来源给出答案时的默认行为: - 它会引用一个**不在您的语料库中**的文档,并且 - 它会“引用”**真实文档中从未包含过的**文本。 检索(RAG)会有所帮助,但仅靠检索**并不能**解决这个问题。您可以把正确的段落交给模型,但它*仍然*会引用一个您从未提供过的凭证,或者巧妙地篡改引言。通常的缓解措施——更好的 prompt、更大的模型、“请只使用提供的来源”——虽然降低了发生率,但**无法提供任何保证**。 **本仓库通过将信任机制完全移出模型来提供这种保证。** ## 核心理念:验证,而非说服 将合成器(LLM 或模板——无关紧要)视为**不可信的**。 无论它提出什么建议,在允许任何引文输出之前,都必须通过**验证门**: 1. **Key 解析** — 被引用的 key 必须能解析为一个*真实存储的 chunk*。捏造的 key 会解析不到任何内容 → 被丢弃。 2. **逐字范围** — 任何引用的文本都必须是该 chunk 精确文本的*逐字子字符串*(并根据该 chunk 的 `sha256` 重新核对)。改动一个字符 → 被丢弃。 未通过任一检查的引文将被丢弃,且其支持的观点会**弃权**(“未被语料库支持”),而不是未经核实就输出。 ## 架构 ``` flowchart LR subgraph Ingest D[Public-domain docs] --> CH[Chunk
+ stable key
+ char offsets
+ sha256] CH --> ST[(CorpusStore
authoritative index)] end subgraph Answer Q[User query] --> RT[Retrieve
TF-IDF top-k] ST --> RT RT --> SY[Synthesize
template · or · LLM
UNTRUSTED] SY -->|claimed citations| GATE{{Verification gate}} ST --> GATE GATE -->|key resolves
+ quote verbatim| OUT[✔ Answer
+ verified cite
+ provenance] GATE -->|invented key
or altered quote| DROP[✗ Drop citation] DROP --> AB[Abstain:
"not supported
by the corpus"] end ``` 合成器处于*提议*的信任边界内;它**处于** *发布* 的信任边界**之外**。只有验证门才能发布引文。 ## 常见错误 → 本项目的替代做法 | 常见错误 | verified-rag 的替代做法 | |--------------------|-------------------------------| | “通过 prompt 要求模型只使用提供的来源”并心存侥幸 | 将模型输出视为不可信;在发布前**验证**每一条引文 | | 盲目相信模型返回的引文 key | 对照权威存储**解析**该 key;捏造的 key 会解析不到任何内容并被丢弃 | | 盲目相信引用的段落是真实的 | 要求引用必须是所存储 chunk 的**逐字子字符串**;并重新核对其 `sha256` | | 用听起来貌似合理的答案来掩盖信息缺口 | 选择**弃权** —— “未被语料库支持” —— 而不是输出无根据的声明 | | 先上线,然后再衡量幻觉率 | 在接缝处就让捏造**在结构上变得不可能**,从而无需再追踪发生率 | | 隐藏出处信息 | 每一条发布的引文都包含 key、文档、**字符范围**以及内容哈希值 | ## 演示内容说明 `python -m verified_rag.demo` 针对玩具语料库运行三个案例: 1. **可落地查询** → 包含**逐字引用**和完整出处(key、文档、字符偏移量、sha256)的带引文答案。 2. **不可落地查询**(“一只无载荷燕子的空速”) → **诚实地弃权**,且**不会捏造引文**来填补空白。 3. **对抗性合成器** → 一个故意不诚实的合成器试图夹带输出 (a) 一个**捏造的 key** 和 (b) 一段**被篡改了一个字符的引用**。验证门会**将两者全部丢弃**;只有一条合法且逐字一致的引文能够保留。 ## 快速开始 ``` git clone https://github.com/tsmith-surgexi/verified-rag.git cd verified-rag pip install -r requirements.txt # stdlib-only engine; this installs pytest python -m verified_rag.demo # zero API keys required pytest -q # proves the never-fabricate guarantee ``` 预期结果:演示程序会打印出一个有根据且带引文的答案、一个诚实的弃权结果,以及对抗性案例中丢弃捏造 key 和篡改引用的过程。`pytest` 测试通过。 ## 在代码中使用 ``` from verified_rag import AnswerEngine, CorpusStore store = CorpusStore.from_directory("verified_rag/corpus") engine = AnswerEngine(store) # deterministic, no API key result = engine.answer("What does the preamble establish?") if result.is_grounded: for c in result.citations: # every one is verified print(c.key, c.title, f"chars {c.start}-{c.end}", c.sha256[:12]) else: print(result.answer) # honest abstention ``` `result.citations` 中的每个元素都已经通过了验证门。合成器提出但未通过验证的任何内容都会进入 `result.dropped` 供审计之用,绝对不会出现在 `result.citations` 中。 ## 可插拔、可选的 LLM 合成器是一个可替换的组件。默认情况下,它是一个**确定性、零依赖**的模板合成器,因此本仓库无需密钥即可离线运行。 设置 `VERIFIED_RAG_LLM=1`(并配置一个兼容 OpenAI 的端点——参见 [`.env.example`](.env.example))即可替换为真实模型。**无论哪种方式,保证都是一样的**——验证门对 LLM 输出的验证方式与其对模板输出的验证方式完全相同。模型可以尽情发挥创造力;但它绝对无法将捏造的引文混过验证门。 ## 配置 `verified-rag` **无需任何配置**即可运行。唯一的设置是针对可选的 LLM 模式的,相关说明见 [`.env.example`](.env.example)。不需要存储任何密钥。 ## 局限性(坦诚的范围界定) - **这保证了引文的*完整性*,而不是答案的*正确性*。** 它能证明每一条引文都是真实的,且每一处引用都是逐字的。但它不能证明所引用的段落确实回答了问题,也不能证明合成器生成的周边文字是对该段落的忠实解读。忠实度/蕴含评分是一个互补的层面(参见路线图)。 - **此处的检索是有意设计为玩具级别的** —— 纯 Python TF-IDF,选择它是为了让本仓库在干净的克隆状态下即可运行,无需下载模型。您可以在不影响保证机制的前提下替换为 embeddings/BM25/向量存储;检索只是*提议*候选内容,它永远不会*授权*引文。 - **语料库是一个公有领域的玩具集**(美国宪法序言、一则伊索寓言、两份虚构的“政策”文档),纯粹是为了演示该技术。不包含任何真实的权威资料、产品数据或专有语料库。 - **逐字匹配是精确子字符串匹配。** 针对更模糊但同样安全的匹配而进行的空白字符/引号规范化,是一个深思熟虑的、可审计的扩展点——它绝对不能扩大化为“差不多就行”。 ## 路线图 - [ ] 在验证过的引文之上增加蕴含/忠实度评分 - [ ] 在同一验证门之后提供可插拔的 embedding + BM25 检索器 - [ ] 返回范围级别(而不仅仅是 chunk 级别)的偏移量以用于行内高亮 - [ ] 提供可选的逐字匹配规范化配置(经审计的允许列表) ## 架构与决策记录 如需完整的详细说明——包括问题界定、信任边界、时序图,以及包含权衡取舍的设计决策记录 (ADR)——请参阅 **[ARCHITECTURE.md](ARCHITECTURE.md)** 和 [ADR 文档](docs/adr/)。 ## 许可证 © 2026 SurgeXi Business Intelligence,一家 Teamsmith Enterprises LLC 公司。保留所有权利。 源代码可见,仅供评估 —— 请参阅 LICENSE。
标签:DLL 劫持, Python, RAG, 人工智能, 信息检索, 大语言模型, 无后门, 用户模式Hook绕过, 逆向工具, 防幻觉