FactLens 事实透镜:团队展示、选题报告与需求分析
| 项目 | 内容 |
|---|---|
| 作业所属课程 | 广东工业大学计算机学院 · 计科 24 级 56 班 |
| 作业要求 | 团队项目第一次作业:团队展示、选题报告与需求分析 |
| 作业目标 | 从真实使用场景中确定选题,把智能体嵌入可以访问的软件,并用可重复的测试说明系统做到了什么。 |
| 团队名称 | FactLens |
| 团队成员学号-姓名 | 3224004156-刘心怡、3224004158-杨添媛、3224004157-吴纯瑶、3224004155-李晨昀、3124004111-依木拉木·阿不都苏力、3124004121-艾力夏提·艾海买提、3124004146-杨宗林 |
一、团队展示
1.1 团队名称与项目名称
团队名称:FactLens
项目名称:FactLens —— AI 多领域虚假信息鉴别智能体
队名取自 Fact(事实)+ Lens(透镜)。我们想表达的意思很朴素:一条说法究竟是真是假,往往不是"看一眼就知道",而是要放到透镜下面,看清它由哪几个部分组成、每一部分有没有人证实、有没有人反驳、还有哪些说不准。FactLens 做的就是这副透镜。
FactLens 是一个中文信息核查网站。把一段拿不准的消息粘贴进去,读者能看到系统怎样判断、判断时参考了什么,以及哪些地方仍需要核实。
| 端 | 地址 | 说明 |
|---|---|---|
| 前端(用户界面) | https://factlens-dn7.pages.dev | 在这里输入文字、阅读报告。网页使用 Vue 3 和 Vite,由 Cloudflare Pages 从 GitHub 仓库构建。 |
| 后端(智能体服务) | https://factlens.pythonanywhere.com | 核查服务的基础地址。网页向 POST /api/check 提交原文;PythonAnywhere 上的 WSGI 入口接收请求。 |
| 健康检查 | https://factlens.pythonanywhere.com/api/health | 打开可查看服务状态和配置的模型名称。这个接口不执行文字核查。 |

我们用放大镜表示查看证据,用镜中的对勾表示完成了一次核查。对勾不代表原话属实:核查完成后,系统也可以给出“暂无法核实”。
1.2 项目规划
| 阶段 | 时间 | 目标 | 交付物 |
|---|---|---|---|
| 阶段一:立项 | 10 月下旬 | 组队、确定选题,约定前端怎样提交原文、后端返回哪些字段。 | 团队分工、POST /api/check 接口约定 |
| 阶段二:最小可用版本 | 11 月 1 日-11 月 2 日 | 打通“断言拆解 → 证据检索 → 结论判定 → 报告输出”,部署到公网。 | 可访问的前端页面、可调用的后端接口 |
| 阶段三:联调与缺陷修复 | 11 月 3 日-11 月 4 日 | 排查检索结果不相关、刷新后没有历史记录、记录时间相差八小时的问题。 | 检索调整、历史记录与时区修复、复测记录 |
| 阶段四:文档与答辩 | 11 月 5 日-11 月 9 日 | 整理团队展示、选题报告和需求分析;准备 4 分钟陈述和 3 分钟讨论。 | 团队博客、答辩幻灯片、讲稿 |
| 阶段五:迭代二 | 11 月中下旬-12 月 | 修复报告原文和线上长度校验;扩展证据来源,用同一组例句比较检索结果和结论。 | 计划交付:迭代版本、核查质量测试报告 |
| 阶段六:期末交付 | 期末 | 按验收标准逐项复测,整理部署、使用和维护说明。 | 计划交付:可运行的最终版本、使用文档、项目总结 |
1.3 队员风采与分工
| 姓名 | 项目角色 | 性格或特点 | 技术特长或本项目实践方向 | 兴趣爱好 |
|---|---|---|---|---|
| 刘心怡 | 智能体与后端 | 细心耐心 | 智能体编排、提示词设计、后端接口联调 | 运动、听歌 |
| 杨添媛 | 前端开发与测试 | 善于学习 | Vue 页面交互、输入与提交测试 | 看小说、旅游 |
| 吴纯瑶 | 产品设计与需求分析 | 细致认真 | 梳理用户需求、产品设计 | 看小说、运动 |
| 李晨昀 | 智能体与后端 | 细心仔细 | 检索结果整理、核查接口返回字段核对 | 听歌 |
| 依木拉木·阿不都苏力 | 智能体与后端 | 有耐心 | 熟悉基础智能体 | 打篮球、听音乐 |
| 艾力夏提·艾海买提 | 前端开发与测试 | 耐心沉稳 | 页面基础布局、交互调试 | 打球、听音乐 |
| 杨宗林 | 前端开发与测试 | 冷静平和 | 历史记录页面测试、缺陷复现与回归验证 | 看电影 |
产品组负责选题、使用场景与验收标准。智能体与后端组负责从原文中找出要核实的问题,为每个问题检索资料,再把判断和出处一起返回给网页。前端开发与测试组负责输入、等待、报告和历史记录页面,也负责用实际操作检查这些功能。
1.4 团队首次合照

团队线上合照(微信群成员头像)
1.5 团队愿景
我们希望做的不是一个"判定对错"的机器,而是一副让人看得见证据的透镜。希望每一个普通人在转发一条消息之前,都能花十秒钟看清它从哪里来、有没有人反驳、还有哪些说不准。让"先查一下"成为一种习惯,让事实核查不再是少数人的技能,而是每个人打开网页就能用的常识工具。
二、选题报告
2.1 选题背景
第一,造假的成本正在快速下降。 生成式模型让一段文字、一张图片、一段音频都可以批量生产,一条看起来"有图有真相"的消息,可能只花了几分钟。过去我们靠"这张图看着怪""这段话不像官方口吻"来判断真假,这些经验正在迅速失效。
第二,传播机制奖励的是情绪,而不是准确。 一条让人愤怒或恐慌的说法,传播速度远快于一条冷静的更正。辟谣往往在谣言已经完成传播之后才出现,而且辟谣内容本身枯燥、缺少"证据感",很难被继续转发。
第三,普通人手上的核查工具其实很难用。 现有的核查产品大致有三类问题:
- 面向专业核查员:界面是给记者和研究员用的,术语多、入口深,普通用户打开就关掉;
- 只给二元结论:真或假。但现实里大量说法是"部分对""数字被夸大""时间地点错了",二元结论会把这些信息全部抹掉;
- 对中文口语不友好:用户输入的是"我妈说西柚和 85 种药相冲,是真的吗",而不是"葡萄柚 药物相互作用 CYP3A4"。直接拿整句去检索,命中率极低。
我们小组在家庭群里就真实遇到过这类问题:长辈转发一条关于“西柚与几十种药物相冲”的养生提醒,家里没人能判断,最后是"宁可信其有"。转发这条提醒只需点一下,家人想核实却要回答两个问题:哪些药物可能受影响?消息里提到的数量又出自哪里?
我们后来把测试句具体写成“西柚与85种药物相冲”。即使查到一篇谈西柚和某种药物的文章,“85种”这个数字仍要单独找出处。
| 实际使用中的疑问 | 形成的产品需求 |
|---|---|
| 一段消息里有好几句话,究竟先查哪句? | 找出每个可以单独核实的问题,分别检索资料。 |
| 文章提到了同一个词,它真的能证明原句吗? | 保留原句、判断理由和不确定之处,让人可以对照。 |
| 想把依据发回群里,原文在哪里? | 展示来源标题、网站域名与链接,可以直接打开。 |
2.2 问题定义
最初定下的设计目标是:
给定一条自然语言说法,在 15 秒内回答:这句话可以拆成哪几条可核查的判断?每条判断有哪些支持证据、哪些反驳证据、还有哪些暂时无法确定的地方?
这句话里有三个关键约束,也正是我们产品的设计出发点:
- "拆成哪几条"——真实说法往往是复合句("某地明天要地震,政府已经通知撤离了"),整体判真假没有意义,必须拆开逐条核查;
- "支持 + 反驳"——只给支持证据是背书,只给反驳证据是抬杠,两边都摆出来才叫核查;
- "哪些说不准"——承认证据不足,比硬给一个结论更负责任。
报告使用“确认属实”“确认不实”“部分属实”“暂无法核实”四种标签。一次测试中,我们提交一条未署名的学校停课通知。由于没有具体学校和官方出处,系统给出“暂无法核实”,理由说明了还缺哪些信息。准备转发的人看了这份报告,可以先去找学校的正式通知。
我们把支持和反驳分成两栏,方便读者检查有没有资料提出了相反的意见。两栏也可以留空。11 月 4 日 17:34 的一份报告把“地球是太阳系中的一颗行星”标为“确认属实”,支持和反驳栏却都是空的。“不确定因素”里写着“缺乏具体网页证据支持”。读者一眼就能看出,这次系统给了判断,能用来复核的网页依据还缺着。
15 秒是设计时的期望。3.8 将普通单次核查的端到端验收目标定为 20 秒。11 月 7 日的一次浏览器测试中,第 15.81 秒检查时,报告和四条来源已经显示。
2.3 产品定位与目标用户
一句话定位: 一个中文、免注册、打开即用的"说法体检器"——输入一句话,拿到结论、证据链和不确定性。
| 用户群 | 典型场景 | 我们提供的价值 |
|---|---|---|
| 大学生与年轻网民(第一优先) | 群聊、社交平台上看到可疑说法,想转发前先确认 | 看清结论和依据,可以把截图或来源发回群里一起核对 |
| 家庭群里的"辟谣者" | 长辈转发的养生、健康、政策类说法 | 给出可读的证据链,而不是一句"这是假的" |
| 内容创作者 / 校园媒体 | 引用二手信息前需要核实 | 一次核查多条断言,附来源链接 |
| 班级、社团、社区管理者 | 群内出现争议信息需要回应 | 结论四值化,避免"误伤"部分属实的说法 |
产品的输入范围是可以用公开资料核对的中文文字。图片、音视频和个人诊断问题超出这一版的范围。健康提醒、科学常识和校园消息都可以用同一套流程。换一个主题能查到什么,要看有没有针对原句的可靠出处。
2.4 核心功能
| 编号 | 功能 | 说明 |
|---|---|---|
| F01 | 说法输入与校验 | 支持整段粘贴,网页拦截空输入,输入框上限 2000 字。直接请求公网接口的超长输入结果见 3.8。 |
| F02 | 断言自动拆解 | 把复合说法拆成 1~3 条独立、具体、可检索的断言 |
| F03 | 证据检索 | 对每条断言检索,长句自动切分为短关键词提升命中率,结果合并去重 |
| F04 | 结论判定 | 输出四值结论:确认属实 / 确认不实 / 部分属实 / 暂无法核实 |
| F05 | 证据链报告 | 并列给出支持证据、反驳证据、不确定因素、判定理由 |
| F06 | 来源可追溯 | 接口返回标题、摘要、链接和域名,网页列出标题和域名,点击可跳转原文 |
| F07 | 历史记录 | 浏览器本地保存最近核查记录,刷新后仍在,可点击原句重新核查 |
| F08 | 时间与状态可见 | 报告标注核查时间(北京时间)。本地诊断版分别记录拆解和判定是否成功调用模型,线上健康检查展示模型配置。 |
看一份真实报告
用户在首页粘贴文字后,系统提取可以分别查证的说法,检索资料,再生成报告。读者可以打开来源、复制报告,或从浏览器的历史记录中找到原句重新核查。下面用一次实际输入展示这条流程。各项功能的前后端分工见 3.3,详细需求见 3.5。
11 月 7 日,我们在公网首页输入“地球是太阳系的一颗行星”。当日 03:04 的报告给出“确认属实”,还列出理由和四个可以打开的来源。



四个条目都来自中文维基百科。《地球》直接对应被核查对象,《地球科学》提供背景,《流浪地球2》和《Google地球》虽然包含相同字词,却无法证明原句。这次测试同时验证了来源列表可以展示,也找到了筛选相关资料时的一个具体缺陷。
我们把输入改成“地球是太阳系的一颗行星,月球是一颗恒星”。系统拆出两条断言并返回八条来源,理由能解释哪部分对、哪部分错,总标签却给了“确认不实”。对于这条真假各一的复合句,我们把“返回部分属实并解释两项判断”写成了一项可重复的验收标准。
2.5 创新点与杀手级功能
一、四值结论,保留“部分属实”和“暂无法核实”。 一段转发里,前半句有根据,不代表后半句的数字也对;一则通知查不到出处,也不等于已经证实它是假的。除“确认属实”和“确认不实”外,我们给这两种情况各留了一个标签。上一节的地球与月球用例,也给了我们检验“部分属实”能否判准的办法。
二、证据链四段式:把反驳原句的资料也摆出来。 这是我们最想保留的功能。一份报告要交代四件事:哪些资料支持原句、哪些资料反驳它、哪些细节还说不准、系统为什么给出这个判断。读者可以先读持相反意见的材料,再顺着来源链接看原文。找不到反驳材料时,这一栏可以留空;没有网页证据时,应在“不确定因素”里明说。空栏本身不能用来证明原句。
三、复合句里的几项说法,分别找依据。 例如“地球是行星,月球是恒星”,前后半句说的是两个天体。系统会先提取最多三条能单独核实的断言,再分别检索。接口保留每条断言与来源的对应关系;目前网页把来源合并展示,下一版计划让读者点选一句话就看到它引用的资料。
四、用关键词检索中文长句。 联调时,把“西柚与85种药物相冲”整句拿去搜,结果里竟有一部漫画。团队在部署版本里按“与”“和”等词提取关键词,分开查找,合并结果时去掉重复链接。这样能找到谈西柚的网页,但“网页提到西柚”和“网页证实有85种药”仍是两件事,后者还得查原始出处。
五、让同学既能在线体验,也能在本地复现。 前端托管在 Cloudflare Pages,后端使用 PythonAnywhere 的免费档。打开网站不需要安装软件,也不用填写自己的模型密钥。想研究某份报告如何生成,可以从仓库分别启动前后端;想在本地测试真实的模型调用,则需要在后端配置自己的 API 密钥。
2.6 技术方案与可行性
总体架构(四层)
用户浏览器
│ HTTPS
▼
[前端] Vue 3 + Vite ── Cloudflare Pages(Git 自动构建)
│ POST /api/check JSON: {"text": "..."}
▼
[接口层] 本地:FastAPI / 线上:PythonAnywhere 的纯 WSGI 入口
│
▼
[编排层] agent.check()
│ [外部服务]
├─ ① 断言拆解 → 智谱 GLM(失败则按句切分)
├─ ② 逐条检索 → searcher 访问检索服务,按链接去重
└─ ③ 综合判定 → 智谱 GLM(失败则用启发式规则)
│
▼
[输出] 四值结论 + 支持 / 反驳 / 不确定 / 理由 + 来源列表 + 北京时间
技术选型理由
| 环节 | 选型 | 为什么 |
|---|---|---|
| 前端 | Vue 3 + Vite | 输入、报告和历史记录共用一个单页应用。静态文件可独立构建和更新。 |
| 后端 | FastAPI(本地),纯 WSGI 入口(线上) | 本地用请求模型校验原文,可查阅自动生成的接口文档。线上 Web 进程找不到原计划使用的适配库,因此 WSGI 入口直接接收请求并调用同一套核查逻辑。 |
| 大模型 | 智谱 GLM-4-Flash(OpenAI 兼容接口) | 拆解和判定共用模型调用模块,密钥、地址和模型名在服务端配置。调用失败时编排层可以改用规则。 |
| 检索 | 独立的检索模块 | 逐条查找断言,合并重复来源。部署时可按服务器能访问的来源调整检索入口。公开仓库使用必应,线上样例返回中文维基百科条目。 |
| 部署 | Cloudflare Pages + PythonAnywhere | 页面和核查服务分别部署。前端从 GitHub 构建,后端可以单独更新,核查路由和请求格式保持一致。 |
可行性。 从 10 月下旬立项到 11 月初上线,团队已经用浏览器走通了“提交原文 → 收到报告 → 打开来源”的流程。前端和后端托管使用课程演示所需的免费档。本地复现真实模型调用需要配置服务端密钥。下一步要评估的是证据覆盖率,以及返回的网页能否支持给出的结论。
2.7 风险与对策
| 风险 | 具体表现 | 已采取的办法或下一步安排 |
|---|---|---|
| 检索源被反爬或不可达 | 部署时试过 13 个搜索入口,多数在服务器上返回空结果或超时。 | 在部署环境逐个测试,保留能访问的入口。下一轮用同一批例句比较各来源的覆盖情况。 |
| 检索相关性差 | 整句检索西柚时搜到了漫画。《流浪地球2》出现在天文学报告里,《健康码》出现在睡眠报告里。 | 部署时增加关键词切分、按链接去重,并保留原文链接供核对。后续评测逐条标记来源是否直接回答原句。 |
| 模型判断超出证据 | 模型可能凭常识下结论,或把“没有支持材料”写成“确认不实”。 | 判定只允许四个标签,并要求交代证据和不确定因素。复测时同时检查标签、理由和实际引用。 |
| 模型限流或超时 | 模型服务可能因配额或网络问题中断。 | 判定失败时保留规则降级路径。本地诊断版记录逐次调用的成败和原因,线上健康检查只展示服务与配置状态。 |
| 服务器时区影响记录 | 历史记录曾比北京时间早 8 小时。 | 生成时间时显式指定 UTC+8,并拿新生成的记录与北京时间对照。 |
| 部署平台和环境差异 | PythonAnywhere 的 Web 进程找不到适配库,后端曾返回 500。 | 改用纯 WSGI 入口,重载后分别验证健康检查和文字核查两个接口。 |
2.8 同类产品对比
| 核查方式 | 什么时候适合用 | 读者怎样核对依据 |
|---|---|---|
| 阅读专业事实核查网站 | 已有编辑或记者调查过这条说法,想了解调查经过。 | 阅读核查文章,查看作者引用的原始材料。 |
| 向通用 AI 助手提问 | 想弄清一个概念,或通过追问梳理思路。 | 有引用时逐一打开;没有引用时,还需另外查找出处。 |
| 使用 FactLens | 手头有一条具体转发,希望把原句、判断和正反依据放在一起看。 | 在同一份报告里查看支持、反驳和不确定因素,再打开来源。没有找到直接依据的地方仍要继续核实。 |
| 维度 | 专业事实核查网站 | 通用 AI 聊天助手 | FactLens |
|---|---|---|---|
| 面向人群 | 查阅已有调查的读者、记者和研究者 | 通过问答了解问题的用户 | 想核对一条具体转发的读者 |
| 结论形式 | 编辑撰写的核查文章 | 随提问和工具而变化的文字回答 | 四值结论和分栏报告 |
| 证据是否可点开 | 查看文章所引材料 | 有可用引用时可打开原文 | 来源标题、域名和可打开的链接汇总展示 |
| 对“部分属实”的处理 | 作者可以在文中说明成立的条件 | 可以追问哪一部分有依据 | 独立保留“部分属实”标签,混合用例仍需改进 |
| 怎样表达“说不准” | 在报道中交代调查限制 | 可追问缺少哪些条件或证据 | 报告保留“不确定因素”一栏 |
| 使用入口 | 检索已经发表的核查文章 | 提问并通过追问细化问题 | 粘贴一段中文文字即可发起核查 |
我们的定位是帮读者核对手里的这句话。一篇扎实的调查报道,仍然值得沿着报告里的链接读完。
三、需求分析
以下需求按使用场景、外部接口、运行条件、功能与验收办法组织,参考了两项软件文档国家标准。GB/T 9385—2008《计算机软件需求规格说明规范》 · GB/T 8567—2006《计算机软件文档编制规范》
3.1 迭代记录表
| 版本 | 日期 | 迭代内容 | 主要变更 | 负责人 |
|---|---|---|---|---|
| v0.1 | 2026-10-28 | 需求梳理与接口约定 | 确定 POST /api/check 请求和响应结构,确定四值结论 |
全体 |
| v0.2 | 2026-11-01 | 后端最小可用版本 | 完成“拆解 → 检索 → 判定 → 报告”链路,在本地跑通 | 智能体与后端组 |
| v0.3 | 2026-11-02 | 后端上线 | 在 PythonAnywhere 部署,因 Web 进程找不到 ASGI 适配库,改用手写 WSGI 入口。/api/health、/api/check 上线实测通过 |
智能体与后端组 |
| v0.4 | 2026-11-03 | 检索可用性修复 | 部署版检索接口改为通过环境变量配置,新增中文长句关键词切分,修复阈值导致的“切分不生效”缺陷 | 智能体与后端组 |
| v0.5 | 2026-11-04 | 前端与时间缺陷修复 | 修复按钮事件被误作参数导致的历史记录漏存。显式使用 UTC+8,修复记录时间相差 8 小时的问题 |
前端开发与测试组、智能体与后端组 |
| v1.0 | 2026-11-05 | 文档基线 | 团队展示、选题报告、需求分析成文,确定需求编号与验收标准 | 文档模块(原记录署名) |
后续复测记录
| 日期 | 工作 | 产出或观察 |
|---|---|---|
| 11 月 5—6 日 | 复测输入边界,补充本地模型调用诊断 | 公网接口接受了 2001 字输入。本地诊断版增加了各次模型调用的结果、失败原因和请求编号。 |
| 11 月 7 日 | 在公网复测普通、混合及信息不足的说法,并核对原文与历史记录 | 保存了输入、完整响应和浏览器截图,定位到证据相关性、混合标签和报告原文绑定问题。 |
公开仓库保留了网页原型、前后端接入和历史记录修复的代码。10 月 30 日的网页已能接收输入并显示等待状态。11 月 2 日前后端接入后,页面开始显示接口返回的报告。前端变更 · 前后端接入记录 · 历史记录修复
上线时有四个问题花了我们不少时间。后端最初一访问就报 500,日志里反复出现模块导入失败。Web 进程找不到适配库 a2wsgi,我们就把入口改成直接处理两个路由的 WSGI 程序。重载后,分别请求健康检查和文字核查,都拿到了响应。
另一次,拿西柚和药物的整句话去搜,结果里竟然有一部漫画。团队当时在服务器上试过 13 个搜索入口,只保留能稳定访问的来源,再从长句里提取关键词分段搜索,最后按链接去重。后来的睡眠案例里仍然出现了《健康码》,说明关键词能帮我们找到更多网页,筛选时还要检查网页究竟回答了什么。
剩下两处都出现在历史记录里。一次是核查结束后记录一直为零,原因是按钮把点击事件传给了核查函数,程序跳过了保存。改为显式调用 checkInfo() 后,再做一次核查,刷新页面还能找到刚才的记录。另一次是记录比北京时间早八小时,后来我们在生成时间时明确指定了 UTC+8。
3.2 项目标志
标志以深色为底,用青绿色线条画出透镜。镜圈、镜柄和中央的对勾构成了图标。

- 外圈透镜围出一小块留白,表示把注意力放在眼前这一条说法上。
- 内部对勾表示“已核查”。即使这一次得到“暂无法核实”,也完成了一次查找依据的过程。以后发现新的来源,还能重新核查。
- 深墨蓝与青绿是项目标志的两种主色。深色背景从
#0F1C2B过渡到#14313F,镜圈和对勾用#2EC4B6,让两处线条清楚可辨。 - 字标使用无衬线的 FactLens 字样。答辩材料把字标与透镜并排展示,方便认出同一项目。
3.3 系统功能结构(思维导图)

功能分为用户入口、核查主流程、结果呈现和支撑能力四部分。主流程依次经过输入校验、断言拆解、证据检索和结论判定。历史记录帮助读者查找原句,本地诊断记录则帮助团队定位哪一次模型调用出了问题。
| 编号 | 用户侧行为 | 后端或浏览器如何处理 |
|---|---|---|
| F01 输入与校验 | 粘贴文字时可见 2000 字上限,提交后显示等待状态。 | 网页拦截空输入并避免连续提交。后端应再次校验首尾空白和长度。 |
| F02 断言拆解 | 一次可以输入含多项判断的说法。 | 编排模块让模型拆出至多三条可以分别检索的断言。拆解不可用时按句切分。 |
| F03 证据检索 | 报告给出检索到的公开资料。 | 后端按断言检索,保留网页标题、链接、摘要和域名,并按 URL 合并重复项。 |
| F04 综合判定 | 查看整体结论与判断理由。 | 模型综合原文和各条资料作四值判定。模型不可用时,后端可以用规则生成报告。 |
| F05 报告展示与复制 | 阅读结论、摘要、理由、支持、反驳和不确定因素,复制报告文字。 | 前端渲染一次响应的字段。报告原文应和本次提交绑定,不能随下一次编辑改变。 |
| F06 来源复核 | 按标题打开参考网页,并看到域名。 | 后端保留断言与来源之间的对应关系,当前网页显示汇总列表。逐条展示断言、摘要与对应来源列入后续迭代。 |
| F07 历史记录 | 在当前设备上搜索、选择、删除或清空历史项。 | 浏览器保存输入、结论与时间。打开记录会用原文重新发起核查,新的判断可能随资料更新。 |
| F08 时间与调用状态 | 报告标记核查时间,故障时应说明判定依据。 | 按北京时间生成时间戳。本地诊断版分别记录拆解和判定的执行状态。线上服务仍使用旧状态字段。 |
3.4 核心类图

在本地代码中,CheckRequest 定义请求体,Source 保存一条检索结果。接口把原文交给 agent.check(),编排模块先调用 llm 拆解原文,再用 searcher 为各项断言取证,最后组织判断和报告。agent、llm、searcher 是 Python 模块。图中的 LLMResult 和 CallStatus 属于本地诊断版,用于关联一次调用的返回值和状态。
| 类 / 模块 | 职责 | 关键成员 |
|---|---|---|
CheckRequest |
接口入参模型 | text: str |
agent(编排) |
串联拆解、检索和判定,组装最终报告 | check()、TYPE_MAP、_now()、_clean_claims()、_judge_no_llm()、_dedup_sources() |
llm(模型层) |
封装兼容 OpenAI 的模型接口 | available()、decompose_claims()、judge() |
searcher(检索层) |
为每条断言查找来源 | search()、search_assertion() |
Source |
保存一条网页来源 | title、url、snippet、domain、to_dict() |
config |
从服务端读取配置 | LLM_API_KEY、LLM_BASE_URL、LLM_MODEL、SEARCH_RESULTS_PER_CLAIM |
LLMResult、CallStatus(本地诊断版) |
把一次模型输出关联到对应阶段和状态 | value、stage、attempted、duration_ms、error_code |
| 前端历史记录对象 | 在当前浏览器保存输入、结论与时间 | id、content、conclusion、time |
3.5 功能描述
P0 项构成一次完整核查,P1 项用于复核来源、查找记录,P2 项补充时间和服务状态。各表列的是需求,线上和本地的实测结果见 3.8。
F01 说法输入与校验(优先级 P0)
| 项 | 内容 |
|---|---|
| 输入 | 用户在文本框粘贴的一段自然语言,长度 1~2000 字 |
| 处理 | 去除首尾空白,拦截空输入和超长输入。在编辑框中显示字数,提交后显示等待状态并避免连续提交 |
| 输出 | 输入合法时发起核查请求。无效输入应在原处提示原因 |
| 异常 | 网络或后端出错时提示用户重试,保留已输入的文字。直接调用接口时也应校验长度 |
F02 断言自动拆解(P0)
| 项 | 内容 |
|---|---|
| 输入 | 待核查原文 |
| 处理 | 优先调用大模型,要求输出 {"claims": [...]} 的 1~3 条独立可核查断言。模型不可用或解析失败时,按中文句读切句,取 6~60 字的句子,最多 3 条 |
| 输出 | 断言列表(每条为一句话) |
| 约束 | 每条断言应能检索验证,保留具体对象及要核实的事实 |
F03 证据检索(P0)
| 项 | 内容 |
|---|---|
| 输入 | 单条断言 |
| 处理 | 部署版的长句策略按连接词切出 2~8 字的候选关键词,过滤纯数字,最多取 3 个。逐段检索后按 URL 合并去重。没有合适关键词时用原句检索,达到目标条数即可结束。公开仓库中的必应检索模块按断言全文查询 |
| 输出 | 来源列表,每条含标题、链接、摘要、域名 |
| 约束 | 部署版要求可替换检索入口,并为单次请求设置超时。原定为 15 秒,公开仓库中的必应请求设置为 20 秒 |
F04 结论判定(P0)
| 项 | 内容 |
|---|---|
| 输入 | 原文 + 每条断言的来源集合 |
| 处理 | 优先由大模型综合判定,输出结论、摘要、理由、支持、反驳和不确定因素。结论只允许四个值。模型判定不可用时,规则根据来源相关性、域名和表示支持或反驳的词给出判断 |
| 输出 | 四值结论之一 + 判定理由 |
| 约束 | 证据不足时应输出“暂无法核实”。混合说法还应交代哪一部分成立,哪一部分有误 |
F05 证据链报告(P0)
| 项 | 内容 |
|---|---|
| 输入 | 判定结果 + 来源集合 |
| 处理 | 按“支持 / 反驳 / 不确定 / 理由”四块组装报告。后端按断言关联来源,当前网页展示汇总列表 |
| 输出 | 可直接阅读和复制的结构化报告。报告原文应固定为提交时的文字 |
| 约束 | 支持、反驳两栏均可为空。缺少依据时应在不确定因素中说明,便于读者继续核查 |
F06 来源可追溯(P1)
| 项 | 内容 |
|---|---|
| 输入 | 来源列表 |
| 处理 | 接口保留标题、摘要、域名和链接。当前网页列出标题与域名,点击后在新标签页打开,按断言展示摘要列入后续迭代 |
| 输出 | 可点击的来源卡片 |
| 约束 | 不隐藏来源域名,让用户能自行判断来源可信度 |
F07 历史记录(P1)
| 项 | 内容 |
|---|---|
| 输入 | 一次成功的核查结果 |
| 处理 | 成功后写入浏览器本地存储(键名 factlens-history),列表变化时同步保存。用户可搜索、删除或清空记录,点开某条记录会用原文重新核查 |
| 输出 | 历史列表,刷新后仍在 |
| 约束 | 历史列表保存在当前浏览器。重新核查时会把原文发往后端,且不应重复新增历史项 |
F08 时间与服务状态(P2)
| 项 | 内容 |
|---|---|
| 输入 | 核查完成事件 |
| 处理 | 以北京时间(UTC+8)生成 checked_at。/api/health 提供服务状态与模型配置 |
| 输出 | 报告显示核查时间。本地诊断版另显示拆解和判定的实际调用状态 |
| 约束 | 时间不依赖服务器默认时区。要判断一次模型调用成败,需要该请求的记录 |
接口需求
| 接口 | 方法 | 请求 | 响应 |
|---|---|---|---|
/api/health |
GET | 无请求体 | 公网返回 status、model 和旧字段 used_llm。 |
/api/check |
POST | {"text":"待核查内容"} |
conclusion、conclusion_type、summary、reason、support、against、uncertainties、claims、sources、checked_at、used_llm。 |
前端使用 Vue 3 和 Vite,由 Cloudflare Pages 提供静态页面。提交后,浏览器通过 HTTPS 向 PythonAnywhere 发送原文。公开仓库的后端入口是 FastAPI,线上部署手册记录的是 WSGI 入口。仓库检索模块使用必应,线上测试样例实际返回的是中文维基百科条目。线上行为以具体请求和报告为准。线上网站 · 前端代码 · 后端代码
| 接口 | 输入及用途 | 返回约定 |
|---|---|---|
POST /api/check |
JSON 对象,形如 {"text":"地球是太阳系的一颗行星。"} |
成功时返回结论及类型、摘要、理由、支持与反驳信息、不确定因素、断言、来源和时间。空输入和超长输入应返回 HTTP 400。 |
GET /api/health |
检查服务当时是否响应及使用的配置 | 11 月 7 日 23:11 公网一度返回 502,23:13 复查恢复为 200,返回的模型名为 glm-4-flash-250414。每次实际模型调用的结果还需单独记录。健康检查 |
3.6 非功能需求
| 类别 | 要求 |
|---|---|
| 性能 | 页面首屏目标为 3 秒内。正常网络下,单次核查从提交到报告可读以 20 秒为目标。 |
| 并发 | 课程现场可能有多位同学同时使用,应分别记录单次和并发请求的耗时。 |
| 可用性 | 后端不可用时,页面提供错误提示并允许重试。模型判定失败时,后端应能用规则返回报告并说明原因。 |
| 安全 | 模型密钥只由服务端读取。仓库、前端代码和诊断日志均应避免泄露密钥。 |
| 隐私 | 历史记录保存在当前浏览器。提交核查时,原文会传给后端并进入相应的检索、模型处理环节。设计要求后端不持久保存原文,网站不要求注册账号。 |
| 可维护性 | 将编排、模型、检索和配置分开。更换模型时修改服务端配置,调整检索方式时修改检索模块。 |
| 兼容性 | 用桌面 Chrome、Edge 和移动端浏览器检查输入框、长报告、来源链接和历史列表。 |
| 可部署性 | 前后端应可独立部署,接口格式保持一致。更换托管平台后,先验证健康检查,再验证实际核查。 |
3.7 运行环境
| 项 | 要求 |
|---|---|
| 客户端 | 电脑或手机上的现代浏览器,能通过 HTTPS 访问前端和后端。 |
| 前端 | Vue 3、Vite。构建后的静态文件由 Cloudflare Pages 提供。 |
| 后端 | 部署手册选用 Python 3.13,线上通过 WSGI 接收请求。本地后端要求 Python 3.10 或更新版本,通过 FastAPI 和 Uvicorn 启动,依赖包括 requests 和 Pydantic。 |
| 外部依赖 | 能够访问公开网页检索服务。使用真实模型时,在服务端配置兼容 OpenAI 的模型服务、模型名和密钥。 |
| 网络 | 服务端需能访问检索与模型接口。部署后要在服务器上验证连通性。 |
3.8 验收标准与实测结果
v1.0 需求文档约定的十二项标准
| 编号 | 验收项 | 通过标准(可测量) |
|---|---|---|
| 标准 A01 | 服务可用 | GET /api/health 返回 200 且 status=ok |
| 标准 A02 | 核查可用 | 输入一条常识性说法,POST /api/check 返回 200,正文和证据字段齐全,包含结论与类型、摘要、理由、支持、反驳、不确定因素、断言、来源和时间 |
| 标准 A03 | 断言拆解 | 复合句输入返回 1~3 条断言,且每条长度 ≥ 4 字 |
| 标准 A04 | 检索相关性 | 输入"西柚与 85 种药物相冲",返回来源标题中含"葡萄柚 / 柚皮苷"等实质相关词,而非无关词条 |
| 标准 A05 | 四值合法 | 任意输入下 conclusion_type ∈ {true, false, partial, unknown},无越界值 |
| 标准 A06 | 证据链完整 | support / against / uncertainties 三个字段均存在(可为空数组),reason 非空 |
| 标准 A07 | 来源可追溯 | sources 中每条均含 title 与 url,url 可正常打开 |
| 标准 A08 | 边界拦截 | 空输入和超过 2000 字的输入均返回 400,并给出中文错误提示 |
| 标准 A09 | 历史持久化 | 核查成功 1 次 → 历史页显示 1 条 → 刷新页面后仍显示 1 条 |
| 标准 A10 | 时间正确 | checked_at 与北京时间偏差 ≤ 1 分钟 |
| 标准 A11 | 异常降级 | 大模型不可用时仍能返回合法四值结论与完整字段,不返回 5xx |
| 标准 A12 | 端到端时限 | 正常网络下,从点击核查到报告渲染完成 ≤ 20 秒 |
11 月公网与本地实测
下表沿用测试记录中的编号。比如原定的长度标准为“标准 A08”,对应的空白和超长两次实测分别记为“实测 A02”和“实测 A03”。
11 月 7 日 23:18 的另一个案例是“成年人每天要睡饱10小时”。下图中的“确认不实”是当次页面显示的结果。报告列出了摘要、理由和不确定因素,但八个来源来自同一网站,《健康码》等条目与睡眠时长无关。报告的理由只说明没有检索到直接支持。缺少支持本身不足以得出反驳原句的结论。


| 编号 | 操作及验收标准 | 本次结果 |
|---|---|---|
| 实测 A01 公网核查 | 从网页提交一条说法,检查结论、理由和证据各栏。 | 流程通过。 天文学示例在公网返回报告,23:18 的睡眠案例也展示了报告各栏。证据是否足以支持结论另见实测 A05。 |
| 实测 A02 空输入 | 尝试提交空文本。网页应提示,直接请求接口应返回 HTTP 400。 | 通过。 11 月 7 日晚网页拦截空输入,公网接口返回 400。 |
| 实测 A03 长度上限 | 直接提交 2001 个字,接口应在核查前返回 400。 | 本地通过,公网未通过。 11 月 5 日和 7 日公网都返回 200,并生成报告。 |
| 实测 A04 拆解复合句 | 提交地球与月球的复合句,检查是否分别检索两项判断。 | 该例通过。 两条断言分别获得检索结果,共八条来源。 |
| 实测 A05 来源质量 | 检查来源是否直接支持断言,过滤只命中相同词的资料。 | 未达到目标。 天文学报告包含电影和软件词条,睡眠报告包含《健康码》。11 月 7 日晚另一次测试可从报告打开《月球》原文。 |
| 实测 A06 报告原文 | 查完 A 后在输入框编辑 B,不提交。显示和复制的报告应继续保留 A。 | 页面未通过。 23:12 查完“月球是地球的天然卫星”后改填“月球是一颗恒星”,旧结论“确认属实”出现在新原文旁。本次验证的是页面显示。 |
| 实测 A07 历史持久化 | 核查后刷新,旧项应保留,打开时应重新核查且不重复新增。 | 该例通过。 03:04 的记录刷新后保留,点开会显示“正在核查”,重查前后相同输入的记录数一致。 |
| 实测 A08 模型故障 | 模拟无密钥、超时和无效输出,应标明哪一步未执行或失败,说明规则是否参与判定。 | 本地诊断版通过了相应用例。 16 项后端测试与 7 项前端状态测试使用模拟响应。公网旧字段 used_llm 只反映密钥配置,不能确认一次真实调用成功。 |
| 实测 A09 响应时间 | 记录从点击到可读报告的时间,单次正常用例以 20 秒为目标。 | 一次浏览器样例达到目标。 第 15.81 秒检查时,报告及四条来源已经可见。晚间三个并发接口请求各耗时约 46~51 秒,仍需检验多人使用时的表现。 |
| 实测 A10 真假混合 | 对已知一真一假的两条独立断言,期望总标签“部分属实”并说明两项判断。 | 未通过。 凌晨和夜间两次测试均在理由里分清真假,总标签均为“确认不实”。 |
| 实测 A11 信息不足 | 提交没有学校名称和官方来源的停课消息,应给出“暂无法核实”并指出缺少什么。 | 该例通过。 公网报告明确指出缺少具体学校或官方通知。 |
四、小结
FactLens 已能接收一段中文文字,返回结论、理由和可以打开的来源。上线后的几次核查也让我们找到两个具体问题。报告有时会把仅仅提到了关键词的网页列为依据。对于真假混合的复合句,报告的总标签也可能和它写出的理由对不上。
下一次迭代先让报告始终显示提交时的原文,再给线上接口补上 2000 字的长度校验。修完后,用实测 A06 和 A03 的原输入重测。
核查质量也要有一套能反复使用的题目。我们计划保留天文、家庭群提醒和校园通知三类样例,事先写下预期结论及理由,并说明哪些题本来就缺少定论。每换一次检索来源,分别记录“总标签与预期一致的题数”和“列出的网页中直接回答原句的条数”。这样就能分清,是找到了更好的资料,还是仅仅多找到了几个链接。
接下来我们想用同一组例句比较多个检索来源,优先展示原始出处,让读者可以按网站筛选。报告会把每一项判断与它引用的资料放在一起,让读者能单看有争议的部分。历史记录已有关键词搜索,下一步增加导出。手机上较长的分析理由和来源列表则计划改成按需展开,先让人看清结论,再决定要读哪条依据。
感谢阅读。
浙公网安备 33010602011771号