Paper Anchor:把每一句 AI 回答釘回原文的開源論文閱讀器
一個自架的雙欄論文閱讀器:AI 回答裡的每個論斷都是可點擊的引用,點下去就跳回 PDF 上那一塊被高亮的原文。MIT 授權,自帶金鑰,embedding 可以全程不出門。
問題不在摘要不準,在於你查不動
用 LLM 讀論文的體感通常是這樣:貼進去、拿到一段看起來很合理的摘要、然後開始懷疑。想確認某句話是不是真的寫在文獻裡,你得回頭在 PDF 裡搜關鍵字——而這正是你一開始想省掉的事。
所以那段摘要的實際價值是負的:它讓你多花一次力氣,還在你沒力氣查的時候給你一個沒有根據的安心感。無法追溯回原文的回答是負債,不是功能。
Paper Anchor 就是照著這句話做出來的。
它長什麼樣子
左邊是 PDF,右邊是對話,兩邊連動:
- 引用錨點——回答中每個論斷後面帶一個
[C12],點下去左邊直接翻到那一頁,並把來源區塊高亮起來。是 bbox 精度,不是只給你頁碼。 - 選取提問——在 PDF 上圈任何一段,浮動選單給你「解釋/翻譯/質疑/提問」,選取的段落與前後文會強制進入檢索,不用擔心模型跑去別的章節找答案。
- 自動導讀——上傳完成後自動生成結構化導讀:研究問題、方法、發現、貢獻、限制。每一點都能點回原文。
- 文獻沒寫就說沒寫——問到文獻沒涵蓋的東西,它回「文獻中未提及」並附上最接近的段落,而不是幫你編一個。
錨定為什麼要做到 bbox
因為只給頁碼等於沒給。一頁密密麻麻的雙欄排版,「在第 7 頁」跟「你自己找」是同一句話。
實作上,PyMuPDF 吐出來的每個 span 都帶座標,我把座標一路帶進切塊的 metadata、帶進向量庫,檢索回來之後可以直接還原成畫面上的高亮框。這條路徑上沒有任何一層抽象會把座標吃掉——這也是這個專案沒有用 LangChain 的原因:多數檢索框架的抽象邊界畫在「文字」那一層,版面資訊被當成雜訊丟掉。對一般 RAG 應用來說那是對的取捨,對這個產品來說丟掉的正好是全部。
引用會不會壞,有回歸評測守著:backend/scripts/eval_citations.py,3 篇論文 × 5 題,檢查每題都有結構化引用、頁碼有效、錨點確實能高亮。目前 NIM deepseek-v4-flash 15/15,本機 Ollama qwen3.8:27b 搭 bge-m3 也是 15/15。
不綁供應商,而且可以完全不出門
chat 只有一條程式路徑:POST {LLM_BASE_URL}/chat/completions。所以 OpenAI、NVIDIA NIM、OpenRouter、Together、Groq,或本機的 vLLM/Ollama/LM Studio,改兩個環境變數加一個模型名就能換。
embedding 更進一步:不設 EMBED_API_KEY 的話,它用內建的 BAAI/bge-m3 在本機跑(fastembed 的 ONNX runtime,首次使用會下載約 2.2GB 模型檔)。再搭一個本機的 chat 端點,整套可以完全離線——你的 PDF 一步都不會離開你的機器。
跑起來
git clone https://github.com/Grayidea-bit/paper-anchor && cd paper-anchor
cp .env.example .env # 填 LLM_API_KEY,EMBED_API_KEY 可留空
docker compose up -d # web :5173 / api :8000
打開 http://localhost:5173,上傳一篇 PDF 就可以開始。
它現在不適合誰
先講清楚比較好:
- 沒有登入機制。 這是給單人在自己信任的機器上用的,所以 compose 只把埠綁在
127.0.0.1,資料庫的埠根本不對主機公開。要放到區網或公網,前面得自己補一層帶驗證的反向代理。 - 只能跑單一 worker。 備份/還原的互斥鎖與設定快取都是行程內狀態,開多 worker 會安靜地壞掉。
- 掃描版 PDF 不支援。 沒有文字層就沒有座標,目前也不做 OCR,上傳會直接明確報錯,而不是做出半套結果。
- 第一個 token 可能要等 20–40 秒。 預設模型是推理模型,思考階段算在裡面。在意延遲就換非推理模型。
開源
MIT 授權,程式碼在 github.com/Grayidea-bit/paper-anchor。README 中英都有,架構筆記與里程碑記錄放在 docs/。
Issue 跟 PR 都歡迎。最想聽的是:你讀論文的時候到底卡在哪裡——因為這個工具到目前為止,只解掉了我自己卡住的那一個。