D-academic-agent — 學術證據核驗工作區
- TypeScript
- Electron
- MCP
- ONNX / HuggingFace Transformers
- DeBERTa-NLI
- SQLite / better-sqlite3
- React
- AI SDK
- Vitest
- scite / Consensus APIs
- OAuth 2.1 PKCE
- Zod
一個本地優先的學術證據核驗工作區,用確定性 NLI judge 對照來源證據審查論點與引用。它提供 Electron 桌面 app 與 MCP-capable core,外部 scite / Consensus 證據檢索則保持明確 opt-in。
一眼看懂
角色 獨立開發者 — 架構、核心管線、Electron app、MCP server、評測框架
問題
大規模文獻審查容易出錯:LLM 虛構 supports 關係;詞彙 judge 無法識別矛盾,所謂 'supports' 毫無意義。每條 claim 需要可溯源的定位器,而非模型猜測。
解法
我做了一條本地優先流程:導入論文、檢索證據、用確定性 NLI 判斷論點,並把裁定、片段與定位器一起呈現。外部證據檢索保持 opt-in,私有草稿與文獻庫預設不外發。
成果
317 個離線測試 · 42 條人工標注 gold set · 最新打包版本覆蓋 macOS arm64 / x64 / universal
我的工作
- Draft Citation Audit — 逐句審查:每條引用解析到來源、判定(supports / weakly_supports / unsupported / contradicts / unclear),附原文片段、字符跨度定位器、置信度與建議改寫;語料庫反例自動浮現
- Thesis Review — 論文拆解 → 檢索 → 逐條判斷 → 共識裁定(supported / contested / refuted / insufficient),附比例、決定性指數與支持/矛盾證據圖
- 混合檢索 — BM25 + 稠密向量(本地 ONNX:all-MiniLM / bge-small / nomic,角色感知)+ reciprocal-rank fusion;定位器從頁面追蹤到字符跨度
- 離線優先 judge — 確定性 DeBERTa-NLI(零外呼)為預設;OpenAI-compatible 與 Ollama 一鍵預設支持雲端/本地 LLM judge
- 持久化文獻庫 — PDF 拖入(GROBID 章節感知 + unpdf fallback);本地 SQLite(Source / Chunk / vectors);切換 embedder 自動重索引
- 迭代 agent-loop checker — 頂層證據不確定時,審查次級候選並追蹤步驟;failure mode 量化後作為診斷指標暴露
- 三軸評測:準確率(macro-F1 + 分類 + 混淆矩陣)、忠實度(answer_groundedness)、治理(policy_compliance:grounded-locator 率 + snippet-only 率 + 外發字符數)
- Provider ablation runner — 橫向對比 hash+mock / all-MiniLM+NLI / agentic 在三軸的表現;本地 vs 雲端、單輪 vs agentic 的取捨,有數字為證
- 寫作台(Writing Desk)— 貼入一個段落:拆分並分類每條 claim(因果 / 比較 / 方法⋯),對照文獻庫標記 needs_citation / overclaimed / contradicted,並給出更穩妥的改寫;可針對每條論點,用一段可編輯、已告知的查詢詞查找外部證據
- 外部研究與引用健康(可選)— 在 app 內檢索 scite / Consensus 以獲取候選外部證據;並把 scite 的引文分析呈現為風險徽章(無明顯問題 / 存在一些反駁 / 值得注意的問題 / 已撤稿或嚴重通告),附支持 / 反駁 / 提及計數與撤稿通告,覆蓋三處:檢索結果、已導入的文獻庫論文(在引用前就抓出被撤稿的文獻),以及一篇論文經 GROBID 解析出的參考文獻
- 可複用的 MCP OAuth — 基於 MCP SDK 的 OAuth 2.1 PKCE + 動態客戶端註冊(DCR)瀏覽器登入,用於需 OAuth 的 MCP server:127.0.0.1 回環流程,token 僅存於鑰匙串,worker 除一個 bearer access token 外什麼都拿不到
- 桌面發布管線 — 最新公開 release 已打包 macOS arm64 / x64 / universal,讓審查者可直接以真實 app 方式檢視,而不只依賴 source checkout
技術證據
- 共享核心,兩個接口:純 TS 引擎在 src/(ingest · retrieve · check · plan · eval · trace);MCP server 與 Electron app 是薄適配層——src/ 不 import Electron
- 確定性來自離線 mock(HashEmbedder / MockJudge / MockPlanner);模型加載測試加 env gate,CI 全程離線
- Gold set:42 條人工標注 claims,附 integrity-gated sources.lock.json;gold 必須人工標注,絕不讓被測模型自評
- 可選的出站,且邊界嚴格 — 外部呼叫僅在明確動作下觸發,且只送出查詢詞或公開 DOI,絕不送出語料庫或草稿(唯一例外:寫作台的證據檢索,送出一段可編輯、已告知的查詢詞);OAuth token 留在鑰匙串,僅以一個 bearer 標量抵達 worker,並在每個邊界被脫敏
- 密鑰存 OS keychain(Electron safeStorage)——不進 config/git/trace/日誌;317 測試覆蓋 retrieval / check / eval / trace 與外部研究層,全程離線(live 網絡冒煙測試以 env gate 隔離)
- Electron 打包覆蓋最新 packaged release 的 macOS arm64 / x64 / universal 產物,同時保留非 macOS 目標的 source-run fallback
管線:計劃 → 檢索 → 判斷 → 報告
核心循環是計劃 → 檢索 → 判斷 → 報告,透過版本化 trace event 端到端可觀測。論文被拆成子查詢;混合檢索在語料庫中收集證據;judge 一次只依據檢索到的片段對一條 claim 判定;報告則是一張帶裁定的 grounded 證據圖。
三個入口共享引擎:逐句的 Draft Citation Audit 把每條引用解析到來源並判斷被引片段;Thesis Review 拆解論文,在支持/矛盾證據圖上給出共識裁定;而 Writing Desk 把段落拆成 claim,對照文獻庫標記未引用與過度宣稱之處,並能為其中任一條拉取外部證據。
為何用確定性 NLI judge
裁定的強度取決於 judge。詞彙 judge 無法識別矛盾——一切看起來都『supported』。確定性 DeBERTa-NLI judge 揭示支持與反駁之間真實的分裂,且完全離線。這一點是用 gold set 量測出來的,不是假設的。
共享核心,兩個接口
一個純 TypeScript 引擎(ingest · retrieve · check · plan · eval · trace)被兩個薄適配層包裹——MCP server 與 Electron 桌面 app。鐵律是 src/ 絕不 import Electron,核心因而保持無頭可測。確定性來自離線 mock(HashEmbedder / MockJudge / MockPlanner),模型加載測試加 env gate,CI 全程離線。
外部研究:可選且受控
在設定中綁定 scite 或 Consensus,agent 便能在本地文獻庫之外檢索候選證據,但僅在你明確觸發時。每次外部呼叫都需明確動作觸發,且只送出已提交的查詢詞或公開 DOI;語料庫絕不離開本機,而在寫作台(Writing Desk)中,那條由 claim 衍生而來的查詢詞是可編輯、且在送出前被告知的。scite 的引文分析以「引用健康」的形式返回:一個風險徽章,加上支持 / 反駁 / 提及計數與撤稿通告,呈現在檢索結果上、在你已導入的論文上(讓你在引用前就抓出已被撤稿的文獻),以及在一篇論文經 GROBID 解析出的參考文獻上。Consensus 負責候選證據檢索,不參與引用健康。
連接需 OAuth 的 MCP server 沿用同一套紀律:標準的 OAuth 2.1 PKCE + 動態客戶端註冊瀏覽器流程(基於 MCP SDK),以 127.0.0.1 回環捕獲回調,token 只存於系統鑰匙串,worker 只會收到一個 bearer access token。外部結果始終被定位為候選——而非 app 自己的裁定。
評測,以及一個誠實的失敗模式
一個凍結的 gold set(42 條人工標注 claim,對 sources lock 文件做完整性驗證)驅動三軸報告:準確率(macro-F1 加混淆矩陣)、忠實度(answer groundedness)、治理(grounded-locator 率、snippet-only 率、外發字符總數)。一個 provider-ablation runner 量化本地 vs 雲端、單輪 vs agentic 的取捨。
agent-loop checker 有一個被量測到的失敗模式:在 noisy judge 下會過度提交。該失敗模式未被隱藏,而是作為診斷指標呈現——全程誠實口徑:這是 seed set,不是權威 benchmark。
界面截圖