RAG+LLM构建文本事实核验系统:架构设计与实践
“Aletheias Quest”这个名字听起来很宏大实际做下来更像是一场“带着 AI 去查谎”的实践课。这个项目的目标很直接输入一段陈述系统返回一个可信度分析——它是在复述已知事实还是在逻辑上站不住脚或者在细节上和公共知识冲突。需要先说清楚一个边界标题里写了“谎言检测”但真正落地的不是读心术也不是微表情识别而是基于文本语义、逻辑一致性和知识库检索的事实核验系统。它不能直接告诉用户“这个人正在撒谎”只能给出“这段陈述与已有证据的冲突程度”最终判断仍然需要人来下。项目本身的价值在于把大模型、向量检索、规则校验和人工抽检组合成了一条可用的流水线。数据侧做了清洗和标注推理侧用了 RAG 加 LLM 分析服务侧用 FastAPI 暴露了同步和批量两种调用方式。如果你在做一个类似的文本事实核验、舆情风险筛查、审核助手或知识库一致性检查工具这篇文章可以给你一份能落地的架构参考清单也会说清楚哪些坑我踩过之后不建议再踩。文章会按“能力速览 → 边界与合规 → 架构设计 → 数据准备 → 模型策略 → 部署与接口 → 效果评估 → 性能与资源 → 经验教训 → 排查清单 → 最佳实践”的顺序展开。代码部分以通用示例为主路径、模型名、端口请按实际项目替换。1. 核心能力速览能力项说明项目类型文本可信度分析 / 事实一致性核验系统核心功能单条陈述核验、批量文本核验、溯源证据返回、矛盾点高亮、规则引擎辅助技术栈Python、FastAPI、向量数据库、嵌入模型、LLM本地模型或 API、Celery 或 RQ、PostgreSQL / SQLite 可选模型策略RAG LLM 推理结合关键词规则不单独依赖分类器部署方式本地命令启动支持 HTTP 服务、批量任务 Worker、Web 页面可选是否支持 API支持提供/api/check、/api/batch等接口风格是否支持批量任务支持通过异步任务队列处理长文本和批量样本硬件要求纯 API 模式无强 GPU 要求本地推理需按模型实际占用测试显存占用取决于嵌入模型和 LLM 参数规模需用本机实测确认适合场景新闻线索核查、产品描述一致性检查、资料文档交叉比对、自定义规则审核不适合场景司法层面认定“说谎”、对非自愿对象做潜在画像、独立自动化决策表格里的参数对应的是常见实现方式。实际项目里显存、模型名、接口路径都要根据真实环境调整不建议照抄。2. 项目定位与使用边界2.1 这个项目能解决什么问题Aletheias Quest 解决的是一个大而模糊的问题一段陈述是否与已知证据一致。它能把“这个说法看着不太对”变成可以追踪的流程——先判断候选陈述与知识库中最相关的若干证据再让 LLM 按证据做一致性打分最后输出“支持 / 冲突 / 证据不足”三个等级并附上来源片段。2.2 它不能做什么不要把“可信度分析”包装成“测谎神器”。文本层面的分析存在三个天然盲区项目边界必须写清楚无法判断主观动机说错话不等于撒谎错误记忆和故意欺骗在文本上可能完全同形。无法处理超出知识库范围的陈述知识库里没有对应证据时结论只能是“证据不足”而不是“这句话是假的”。无法应对高质量对抗样本刻意绕过规则的表达、反讽、双关、多义词都可能让模型把冲突识别成一致。2.3 合规与隐私边界这是最容易忽略的部分。构建文本分析系统必须明确数据来源合法、样本授权清晰不能拿用户的私密聊天内容当测试语料。涉及个人姓名、联系方式、住址、证件信息时必须先做脱敏或匿名化。结果只做辅助判断最终的上线、发布、投诉或审核决定必须有人工复核和申诉通道。无论是做新闻报道核验还是产品评论分析都要在用户协议里写清楚数据处理和保留期限。3. 系统架构设计整个系统可以拆成五个模块按数据流方向连接3.1 数据采集与知识库构建先把用于核验的“已知事实”收集成结构化文档比如权威发布的公告、产品官方说明、历史新闻原文、行业白皮书。这些文档经过清洗、去重、分段后写入向量库每段内容作为一条知识单元。知识库质量直接决定核验效果宁可规模小但来源干净不要为了数量塞进大量未经核实的网页内容。3.2 候选证据检索当用户提交一条待核验陈述时系统先用嵌入模型把陈述转成向量再从知识库里检索 top K 最相关的段落。K 通常设置在 3 到 8 之间K 太小容易漏证据K 太大容易带入噪声干扰 LLM 判断。3.3 规则引擎前置过滤在进入大模型之前可以先用规则处理几类简单问题日期、数量、人名等实体冲突直接比对。明显的关键词缺失或格式异常直接提示。长度过短、无实义内容的输入不进入推理。规则引擎不追求覆盖所有情况而是为了减少无效请求、降低调用成本。3.4 LLM 推理与结果生成把原始陈述和检索到的证据片段拼成提示词让 LLM 输出结论等级、冲突原因和证据编号。这一段需要对提示词做版本管理因为后续效果调优主要靠这里。3.5 服务层与应用层最上层是 FastAPI 服务。同步接口适合单条测试批量接口把任务写入队列由独立 Worker 消费。Web 页面用于人工复核和证据对照。4. 数据准备与样本标注4.1 样本收集策略要训练和评估这套系统不能只看正例。建议按四个类别收集样本样本类型含义示例一致陈述与知识库事实一致的表达“该产品支持番茄钟提醒”直接冲突与明确事实矛盾“该产品不支持番茄钟提醒”误导性遗漏省略关键限定条件“安装只需要 10 分钟”无关表述与知识库无关的主观感受“用起来很顺心”四类样本比例可以根据业务场景调整。如果是做广告合规审查重点加“误导性遗漏”如果是做新闻核验重点加“直接冲突”。4.2 标注流程标注需要两个人独立进行遇到分歧由第三人裁决。每个样本要记录证据来源和冲突类型否则后期无法评估模型是漏检还是误判。文本类标注相对便宜但也不能直接把原始标注丢给模型训练需要做一轮清洗和格式统一。4.3 最小标注量如果没有标注团队可以先从公开的事实核查文章、产品说明书和官方公告里抽取 300 到 500 条测试样本。这批数据不足以训练一个好的分类器但足够做 RAG 流程的功能验证和阈值调整。先把流程跑通再逐步放大数据。5. 模型选型与训练策略5.1 我第一轮的错误选择直接微调分类器早期版本用的设计方案是把待核验陈述和检索到的证据拼在一起用有标注样本微调一个文本分类模型输出“一致 / 冲突 / 无关”。这个方案在小样本数据集上指标一度不错但换到真实用户输入后明显崩坏。原因很简单真实陈述的表达方式变化太多训练集无法覆盖“同样的事实不同的说法不同的上下文”分类器很容易把语义相近但事实不同的两句话判成一致。5.2 第二轮调整RAG LLM 推理第二个版本把重心从“训练一个分类模型”改成“构建一条证据链”。先检索候选证据再把证据作为上下文交给 LLM让它根据证据内容做推理。这样做有几个好处可解释性强输出结论同时返回引用证据。新增知识只需更新向量库不用重训模型。对多变表达更鲁棒因为 LLM 参考的是证据原文而不是固化的分类边界。代价是推理成本更高单条请求耗时更长需要设计批量任务队列。5.3 提示词模板的关键设计提示词里必须强制要求 LLM 区分“事实判断”和“推断判断”。下面是一段通用提示词结构实际字段需要按项目调整你是文本可信度分析助手。请根据提供的证据片段判断用户陈述与证据是否一致。 证据片段 {evidence} 用户陈述 {statement} 请按以下格式输出 - 结论支持 / 冲突 / 证据不足 - 理由一句话说明判断依据 - 支持证据编号evidence_1, evidence_2注意这里没有要求 LLM 判断“是否撒谎”因为系统根本做不到。它只能判断“陈述与证据的一致性”。6. 服务部署与接口设计6.1 服务框架选择服务层用 FastAPI 是常见选择原因很直接异步支持好、自动生成 OpenAPI 文档、写代码量小。数据库和向量库分离元数据存 PostgreSQL 或 SQLite向量检索单独用向量数据库。服务整体启动流程大致如下具体命令根据项目结构调整# 安装依赖 pip install -r requirements.txt # 启动 API 服务 python -m app.main --host 0.0.0.0 --port 8000 # 启动批量任务 Worker celery -A app.tasks worker --loglevelinfo批量任务不能和同步接口共用同一套阻塞逻辑否则长文本会把请求线程占满。推荐用 Celery 或 RQ 做异步队列任务状态存 Redis前端轮询任务结果。6.2 同步接口设计同步接口适合单条测试和低并发调用下面给出一个通用请求示例接口路径和字段名需要按实际项目调整import requests url http://127.0.0.1:8000/api/check payload { statement: 该产品支持番茄钟提醒功能, top_k: 5, model_name: your-llm-model } response requests.post(url, jsonpayload, timeout60) print(response.json())返回结果里应该包含三部分结论等级、冲突原因、引用证据列表。如果只用结论而不看证据就失去了 RAG 流程的核心价值所以接口设计上一定要把证据字段返回给调用方。6.3 批量任务接口设计批量任务提交后返回一个 task_idWorker 在后台处理用户通过 task_id 查询进度。典型流程如下import requests submit_url http://127.0.0.1:8000/api/batch payload { items: [ {id: 1, text: 句子A}, {id: 2, text: 句子B} ] } resp requests.post(submit_url, jsonpayload, timeout10) task_id resp.json()[task_id] # 轮询任务结果 query_url fhttp://127.0.0.1:8000/api/task/{task_id} result requests.get(query_url, timeout10).json()批量任务要增加幂等设计。同一个 task_id 重复查询时不能重复触发队列里的任务避免资源浪费。6.4 服务启动后的验证路径服务起来后先做一个冒烟测试curl -X POST http://127.0.0.1:8000/api/health返回正常后再用一条已知冲突的样本测试接口确认证据检索、LLM 推理、结果返回三个环节都通。7. 功能测试与效果评估7.1 单条核验测试测试输入选择一条带有明确事实冲突的句子比如陈述该产品内置容量为 64GB。 证据官方说明写明内置容量为 128GB。 预期结果结论为“冲突”。如果接口返回“支持”要先检查证据是否检索到了正确的官方说明再看 LLM 提示词是否把证据内容完整传给了模型。大部分问题出在证据检索阶段而不是 LLM 推理阶段。7.2 证据不足测试输入一条知识库没有覆盖的陈述预期输出应该是“证据不足”而不是“冲突”。很多用户会把“没找到证据”误当成“找到反证”这个边界必须在产品文案和接口注释里写清楚。7.3 批处理稳定性测试批量任务要重点验证三个问题大量短文本同时提交时任务队列是否堆积。单条长文本是否会超过 LLM 上下文窗口导致失败。Worker 崩溃后任务是丢失还是重试。建议准备 100 条测试样本做小规模压测。如果程序出现内存持续增长优先怀疑向量数据库连接和 LLM 推理线程没有正确释放资源。7.4 评估指标怎么定对这类系统不能只看“准确率”单指标。推荐同时记录指标含义使用场景精确率模型判定“冲突”中真正冲突的比例减少误伤召回率真正冲突样本中被检出的比例减少漏检溯源覆盖率结论引用正确证据的比例衡量可解释性误判率一致陈述被判定为冲突的比例用户信任关键平均响应时间单条请求的处理耗时性能监控阈值选择要结合业务容忍度。新闻核验场景宁可多返回“证据不足”也不要把大量正常内容打成冲突。别追求在离线测试集上刷高分真实输入的长尾表达才是判断系统价值的核心。8. 性能观察与资源占用8.1 观察哪些指标运行过程里重点看四个指标CPU 占用负责向量化、规则引擎和 Web 服务。显存占用由嵌入模型和本地 LLM 决定用 API 模式则只需关注网络延迟。推理耗时单条请求从提交到返回的总时长。队列堆积数批量任务处理不过来时队列长度会持续上涨。推荐用nvidia-smi查看显存用top或htop查看内存用 FastAPI 的访问日志统计接口耗时。显存数字会随模型参数和输入长度变化我没有统一的标准数字可以给出必须用本机实测确认。8.2 降本提速的常用手段有几个通用优化方向嵌入向量做缓存相同或高度相似的句子直接命中缓存。知识库分段做预过滤先用关键词粗筛再走向量精排。LLM 请求走异步并发避免串行等待。控制证据片段长度只保留与陈述最相关的部分。推理用 API 模式时可以适当降低输出 token 上限。8.3 批量任务卡顿排查思路批量任务变慢最常见的原因是每个任务都重新加载了模型参数。解决方法是把模型实例做成进程级单例在初始化阶段加载一次任务循环里复用。如果任务涉及外部知识库更新也要确认更新逻辑不会阻塞主队列。9. 构建过程中的经验与教训9.1 失败案例一把“相关”当成“事实”最开始我用语义相似度作为冲突判据凡是相似度低的句子就标成“冲突”。这个思路有一个致命缺陷相关不等于一致更不等于冲突。“今天天气不错”和“昨天晚饭很丰盛”相似度低但两者完全不冲突。系统要判断的是“陈述是否与证据矛盾”而不是“陈述是否与证据相似”。这个区别决定了后续必须引入 LLM 推理而不是只靠向量距离。9.2 失败案例二忽视知识库的时效性新闻事实核验场景里同一家媒体昨天的报道和今天的报道完全可能相反。系统如果只在建库时导入一次知识面对事实反转就会持续输出过时结论。教训是知识库必须带版本和发布时间做核验时要带上“截至某个时间点”的限定不能让系统跨时间去判断。9.3 失败案例三全自动流程没有兜底早期版本做成了全自动调用接口就直接给出“真 / 假”结论没有人工复核环节也没有置信度阈值。后来发现模型遇到低质量文本时非常容易产生误导性的“假阳性”用户拿到错误的结论直接用于决策风险不可控。改为“系统给出建议 人工落地确认”之后整体可用性反而上来了。9.4 最重要的教训模型并不是系统的全部在埋头调提示词之前先把数据管道、知识库、召回效果、日志链路和人工审核闭环搭好。很多“效果问题”查到最后其实是数据问题比如知识库没有覆盖、检索到了无关片段、源文档解析错误。模型只是整个链条里的一环不能指望它独自解决所有事情。10. 常见问题与排查方法问题现象可能原因排查方式解决方案接口返回结果没有引用证据检索未命中或 top_k 设置过小查看返回的 evidence 字段调大 top_k检查知识库是否有对应内容冲突样本被判为一致证据检索到了无关片段打印检索结果前几项验证优化分段策略和检索权重批量任务卡住Worker 内模型加载阻塞查看 Worker 日志和队列长度模型实例改为单例复用输入过长报错超出 LLM 上下文窗口查看错误信息中的 token 数对长文本做切片或换用更长上下文的模型显存不足本地模型过大运行nvidia-smi观察占用换小模型、开启量化、改用 API 模式端口冲突另一个服务占用了端口netstat -anofindstr :8000结论波动大提示词不稳定或多候选证据冲突多次调用同一输入对比输出固定模型温度参数增加确定性推理知识库更新后结果没变缓存未失效检查缓存 key 是否包含知识库版本号在缓存 key 中带上版本信息11. 最佳实践与合规建议11.1 工程侧建议第一版先做最小可行闭环不要着急上大模型先用 100 条样本跑通“检索 → 拼接 → 规则判断”的流程。配置文件和代码分离模型名、API Key、数据库连接串不要硬编码在代码里。所有接口调用都要记录 request_id方便联调定位问题。批量任务要带日志和失败重试重试次数默认 3 次避免无限重试。模型输出做 schema 校验防止 LLM 返回 JSON 格式错乱。11.2 算法侧建议知识库分段控制在 200 到 500 字太长会稀释检索信号。检索结果的 top_k 设置成动态可配不同业务场景可以自行调整。阈值不要用统一值。新闻核验、广告审查、客服质检的冲突容忍度完全不同需要分别标定。引入人工抽检池每周随机抽取 100 条系统输出交给人工复核把错误样本重新喂回评测集。11.3 合规侧建议明确告知用户这里做的是“事实一致性分析”不是心理学意义上的“测谎”。数据采集和知识库构建必须确认来源合法避免直接抓取未授权网页。涉及个人数据时先脱敏处理后不留存原始数据。系统结论不允许作为司法或人事决策的唯一依据。对外提供服务时在页面和 API 文档中展示“AI 生成结果仅供参考需人工复核”的说明。结语兜兜转转做完 Aletheias Quest最深刻的一点是AI 谎言检测器这个产品名称容易让人误解它真正做得好的部分是“证据矛盾识别”而不是“动机判定”。通过把知识库、向量检索、规则引擎和大模型推理组合在一起项目跑通了从单条核验到批量任务、从接口服务到人工复核的完整闭环。如果你准备复刻一个类似项目建议验证顺序是先确认知识库覆盖是否足够再确认检索能否召回相关证据最后才去调 LLM 的提示词。最容易踩的坑是把精力全放在模型参数上而忽略了上游的数据质量和下游的人工确认。这个项目可以继续扩展的方向包括多语言事实核验、实时知识库增量更新、更细粒度的矛盾类型分类、以及面向特定垂直领域的专用知识库。方向不少但每往前走一步之前先把当前流程的边界和失败案例记录好这些记录会比模型本身更有长期价值。