输入一个研究主题 → 收获论文调研、阅读以及综述撰写的全周期信息
Paper-Agent 3.0 是相对旧版@GreatZack项目的一次全新重写。它保留了旧版「检索 → 阅读 → 分析 → 写作」的相关思路,但在Agent化实现上做了全面升级:
- 前端改为 Vue 3 + TypeScript + Vite,交互更现代、响应更快;
- 包管理统一使用
uv,一条命令即可完成 Python 依赖安装; - 论文来源 扩展到 arXiv、OpenAlex、Semantic Scholar 三源检索;
- 会话持久化改用 SQLite + 文件系统,浏览器刷新后历史线程不丢失;
- 实时进度基于 SSE 推送到工作台,从检索到写作每一步都可观察。


输入研究主题,实时追踪检索论文、精读论文、生成综述等各环节进度(综述内部的分析、大纲、逐节写作以同一张卡片的实时状态文字呈现)
在浏览器中可视化配置模型 Provider 与 Agent 档位,一键测试连通性
做学术调研时,你一定经历过这些:
| 场景 | 传统方式 | Paper-Agent |
|---|---|---|
| 初步了解陌生研究方向 | 手动搜索多个来源,逐个打开论文判断相关度,耗时费力 | 从 arXiv / OpenAlex / Semantic Scholar 自动检索,按主题和约束去重、筛选、整理 |
| 论文阅读与资料积累 | 读完一篇记一篇笔记,资料散落在各处,容易丢失和重复 | 先读摘要判断相关性,再按条件下载全文、解析、切分,逐块精读并把全文与笔记留在本地 |
| 撰写领域综述 | 边读边写,反复调整结构,常常写到一半推倒重来 | 先从论文整体分析、再做全局综合,据此生成结构化大纲,然后逐节按证据写作 |
| 管理长流程任务 | 每跑一步都担心进度、状态和重启后丢失,不敢中途停下 | 会话、运行状态、阶段产物和实时进度都在工作台可见;刷新后历史与实时流可接回,进程中断的任务会被标记为「已中断」,可基于工作区已保存的产物继续下一轮调研 |
| 控制模型成本 | 全程用一个模型档位,不清楚每个环节花了多少 token | 精读、追问、综述等子 Agent 的 token 用量会累加到对应工具卡片;主对话按轮次上报,多轮对话下看到的是最近一轮的用量 |
Paper-Agent 是一个完整的 AI 研究助理——它找得到论文、读得懂全文、理得清脉络、写得出综述。
| 特性 | 一句话说明 | |
|---|---|---|
| 🔍 | 多来源论文检索 | 内置 arXiv、OpenAlex、Semantic Scholar 连接器,统一为 PaperDocument,按年份、来源、数量和排除词筛选并去重;按研究主题用概念组检索,用户给出一篇已知论文的完整标题时由助手自动改走标题检索,不必拆成布尔关键词。多源结果用 RRF(排名融合)排序——每篇论文按它在各源里给出的名次累计得分,被多个源同时命中、且名次靠前的排在前面 |
| 📖 | 从摘要到全文的渐进式阅读 | 先读摘要判断相关性,满足条件的论文走下载 → 用 Nougat 把每一页写成 Markdown → 插图仍按页面截图并配上图注 → 按块装箱 → 逐块精读并汇总成报告。用户只要 Markdown、不要精读报告时,可以单独把全文转成 Markdown 并写入本地缓存。需要再精读一遍时,只清掉旧报告、复用已经切好的正文片段重新阅读,不必从工作区删文再检索。全文下载或转换失败时自动降级为「基于摘要的精读」,并把失败原因告知用户 |
| 🧩 | 本机论文长期记忆 | 一篇论文完成全文分片和精读后,报告和分片留在本机;论文身份、别名和各会话引用记在会话库同一个 SQLite 里。之后任意会话再检索到同一篇(按 DOI / arXiv / 标题认),会自动召回已有报告和分片,不必重新精读;只有摘要的降级报告不进入这份记忆。工作区删除只退出当前会话;清除本地全文或手工删掉缓存目录时,卡片保留,已精读改回可精读 |
| 🧠 | 上下文预算与自动压缩 | 对话历史不再按固定轮数截断,而是按「模型窗口 × 0.8」的 token 预算管理:超预算先免费归档旧工具结果(附 get_history 取回工具),仍不够再把最老的整轮经一次 LLM 调用压成要点摘要(带缓存、不落库);问答子 Agent 同样改为「全文目录 + read_sections 按需取原文」,长论文中间内容不再被截断弄丢 |
| 🔬 | 分层研究分析 | 综述先按字数把论文分成几批做子主题分析,再做全局综合。每篇论文的卡片留在综述状态里,后面各步只把有字数上限的摘录发给模型,形成研究现状、共识、争议、空白、时间演化与展望等结构化内容 |
| ✍️ | 证据约束下的综述写作 | 先生成大纲与证据映射,再逐节写作;证据不足时检索补充,写完后审查并限次修改。完成后可在对话卡片里打开全文,并下载 Markdown |
| 📡 | 实时会话工作台 | SSE 实时推送检索、阅读、分析、大纲与逐节写作进度,SQLite + 文件系统持久化,刷新后历史可恢复;长对话打开时先显示最近几轮,避免一次画出全部历史 |
| 🎛️ | 可视化模型配置 | 在浏览器中管理 Provider 协议、API 地址、密钥与各 Agent 档位,一键测试连通性,保存即生效 |
flowchart TB
subgraph Main["主对话 Agent (researchAgent)"]
direction TB
U[用户输入] --> LLM[LLM 工具循环]
LLM --> T1[search_papers]
LLM --> T2[evaluate_papers]
LLM --> T3[deep_read_paper]
LLM --> T4[ask_paper]
LLM --> T5[generate_review]
LLM --> T6[expand_by_citations]
LLM --> T7[list_papers]
LLM --> T8[get_paper_details]
LLM --> T9[remove_papers]
LLM --> T10[download_paper]
LLM --> T11[get_history]
LLM --> T12[convert_paper_to_markdown]
end
subgraph SubAgents["子 Agent(agent-as-tool)"]
direction TB
DR[DeepReadAgent\n全文精读 map-reduce]
PQ[PaperQAAgent\n目录 + read_sections 按需取原文追问]
RV[ReviewPipeline\nStateGraph 编排综述流程]
end
T3 --> DR
T4 --> PQ
T5 --> RV
subgraph Sources["外部数据源"]
direction LR
AX[arXiv]
OA[OpenAlex]
SS[Semantic Scholar]
end
T1 --> Sources
T6 --> OA
T6 --> SS
主对话共注册 12 个工具(上图全部列出)。
convert_paper_to_markdown把论文全文转成 Markdown 并写入本地缓存,不生成精读报告。引文扩展(expand_by_citations)由 OpenAlex 与 Semantic Scholar 承担:arXiv 的接口本身不提供引文数据,所以它不参与回答,但 arXiv 来源的论文只要带编号(arXiv 编号或 DOI)一样可以扩展。
项目里有两种编排方式,分工是明确的:
| 流程长什么样 | 用什么 | 为什么 |
|---|---|---|
| 阶段能提前枚举出来(综述:分析 → 大纲 → 逐节写作 → 摘要 → 参考文献 → 终稿) | LangGraph StateGraph |
控制流一眼看得全,而且阶段之间天然就是"这一步做完了"的边界,正好用来存检查点 |
| 需要模型每轮自由决定下一步(主对话:想检索就检索、想精读就精读、够了就直接回答) | ReAct 循环 |
循环里要插三件框架不让你顺手插的事:每轮开头的取消检查、推理模型 thinking 块的协议回传、同一轮多个工具的并发控制 |
所以"主对话"和"综述"看起来风格不一样,不是没统一,是两件事的形状本来就不一样。
flowchart TB
S([收到综述请求]) --> P["准备<br/>收集工作区论文、整理分析输入"]
P --> A1["子主题分析"]
A1 --> A2["全局综合分析"]
A2 --> O["组装分析报告 + 生成写作大纲"]
O --> W["写一个小节"]
W -.->|"还有小节没写"| W
W -->|"小节都写完了"| AB["生成摘要"]
AB --> C["整理参考文献、把正文里的编号换成序号、拼出终稿"]
C --> F["保存产物 + 推综述卡片"]
F --> E([完成])
步骤级断点续跑:每做完一个阶段,图的状态会写进会话目录下的 checkpoints.db(随会话一起删除)。所以综述跑到一半进程挂了、或者用户中途点了停止,可以从最后一个做完的阶段接着写——已经写好的小节不用重写,只有崩溃时正在写的那一节要重做。也可以在失败或已停止的卡片上点"继续"。
两个实现细节:
- 小节内部是普通循环,不另存检查点。 写一节时先看证据够不够,不够就补资料(最多 5 次),写完再审查,不通过最多改 2 轮。这些中间状态没有恢复价值:外层已经是写完一节才记一笔,续跑只会从这一节开头重来。分析、大纲、写作是这条流水线里的函数,不再各算一个子 Agent。
- 检查点库的大小随综述规模增长:每完成一节就落一次快照,快照里含当时已写的全部小节。一份 12 节、单篇论文的综述实测约 2 MB。
说明:这是流程级的恢复,粒度是"一节一个检查点",只有综述流水线支持。主对话的恢复是另一套:消息落库 + 刷新页面接回实时流,粒度是整轮。
| 层级 | 技术选型 |
|---|---|
| 运行时 | Python 3.12+、uv、Uvicorn |
| 后端 API | FastAPI、REST、Server-Sent Events(SSE) |
| 编排模式 | 主对话:Orchestrator-workers(主 Agent + 子 Agent 以 tool 形式注册,多轮ReAct工具循环);综述流水线:LangGraph StateGraph |
| 执行持久化 | LangGraph SQLite checkpointer;检查点库在会话目录内(checkpoints.db,随会话一起删除)。只覆盖综述流水线,粒度是"一节一个检查点" |
| Agent | 主对话 Agent(researchAgent)+ 精读 / 追问 / 综述三个子 Agent |
| LLM 适配 | OpenAI 兼容协议、Anthropic Messages 协议 |
| 论文来源 | arXiv、OpenAlex、Semantic Scholar |
| 全文处理 | Nougat 按页把 PDF 写成 Markdown;插图仍用 PyMuPDF 截图并配图注;分片按这些块装箱,不从一块中间切开 |
| 会话存储 | SQLite + 本地 JSON/Markdown 文件 |
| 前端 | Vue 3、TypeScript、Vite、Vue Router、Lucide |
Paper-Agent/
├── main.py # FastAPI 本地启动入口
├── pyproject.toml # Python 项目元数据与依赖
├── package.json # 根目录前端快捷命令
├── config/
│ ├── model.json # 本地模型配置,不提交
│ ├── model.example.json # 模型配置示例
│ └── system.yaml # 系统默认参数
├── front/ # Vue 3 + TypeScript 前端
│ ├── src/api/ # 会话与设置 API 客户端
│ ├── src/components/ # 工作台、状态和会话组件
│ ├── src/views/ # 会话工作台、系统配置页
│ └── vite.config.ts # 开发服务器、代理和端口配置
├── src/
│ ├── agents/ # 智能体,按职责再分成四个包
│ │ ├── common/ # 共用骨架:基类、工具登记、提示词、技能文档
│ │ ├── research/ # 主对话
│ │ ├── reading/ # 摘要相关性、全文精读、追问
│ │ └── review/ # 综述流水线
│ ├── api/ # FastAPI 应用与路由
│ ├── runtime/ # 一次运行的取消、进度上报和共用的网络资源
│ ├── llm/ # Provider 适配、配置解析和统一响应
│ ├── models/ # 会话、阅读与工作区领域模型
│ ├── paper_retrieval/ # 论文模型、编号规则、检索服务和来源连接器
│ ├── repositories/ # SQLite、JSON 与阶段产物持久化
│ ├── services/ # 会话、运行、设置、论文长期记忆和工作流服务
│ └── utils/ # 日志、编号等小工具;全文处理在 fulltext/
│ └── fulltext/ # PDF 转写、分块、缓存和插图
├── data/ # 本地会话库、论文缓存与会话数据
├── logs/ # 运行日志
└── test/ # unittest 测试与联调辅助代码
在项目根目录执行:
uv venv --python 3.12
uv sync
npm run front:install如果你已经有可用的 Python 3.12 虚拟环境,也可以直接执行 uv sync 和 npm run front:install。
全文阅读还要一个单独的 Nougat 环境(不要装进上面这个主环境)。双击 start.bat 时会自动装上依赖,并下载大约 1GB 的模型权重。已经有的会跳过。
想手动准备的话,在项目根目录执行:
uv venv --python 3.12 tools/nougat_trial/.venv
uv pip install --python tools/nougat_trial/.venv/Scripts/python.exe --index-url https://mirrors.aliyun.com/pypi/simple/ nougat-ocr==0.1.17 transformers==4.38.2 albumentations==1.4.24 pypdfium2==4.30.0 requests
uv pip install --python tools/nougat_trial/.venv/Scripts/python.exe --index-url https://mirrors.aliyun.com/pypi/simple/ "https://mirrors.aliyun.com/pytorch-wheels/cu128/torch-2.11.0%2Bcu128-cp312-cp312-win_amd64.whl" "https://mirrors.aliyun.com/pytorch-wheels/cu128/torchvision-0.26.0%2Bcu128-cp312-cp312-win_amd64.whl"最后一条里的 PyTorch 大约 2.6GB。不要改成 uv sync --project tools/nougat_trial,那个目录里的 CUDA 地址不是 uv 能解析的软件源。
推荐通过 Web 工作台的「系统配置」页面修改和测试配置。也可以手动拷贝 config/model.example.json 为 config/model.json,至少确认:
providers中存在一个可用 Provider,并填写api_base;api_key或api_key_env能提供有效密钥;agents.default_agent已配置;
uv run python main.py后端默认监听 127.0.0.1:8000,开发模式自动重载。API 文档:http://127.0.0.1:8000/docs
npm run front:dev打开 http://127.0.0.1:5173/,先进入「系统配置」测试模型,再进入会话工作台创建研究任务。
前端默认只监听本机,并代理 /api、/webui 请求到 127.0.0.1:8000。如需局域网其他设备访问:
npm run front:dev:network上面第 4 步的双服务模式是给开发用的。如果只是想把整个应用跑起来自己用,可以先构建一次前端, 之后由后端直接托管界面,不需要 Node,也不需要 5173 端口:
npm run front:build
uv run python main.py注意 main.py 是带 reload=True 启动的(开发时改代码自动重启,会额外拉一个监视进程)。
想要真正的单进程运行,用分发用的那个启动器,它显式关掉了 reload:
uv run python scripts/launch.py然后访问 http://127.0.0.1:8000/ 即可(不是 5173)。后端会挂载 front/dist 并接管前端路由,
/api 与页面同源,因此不需要任何代理配置。
npm run front:build 会先清空 front/dist 再写入。启动器还会核对产物里的构建记录和当前源码:对不上就先删掉旧产物再构建;构建失败则拒绝启动,避免继续打开旧页面。首页响应带 Cache-Control: no-cache,浏览器不会一直拿着旧首页去加载旧脚本。
注意:
front/dist只在构建后存在。缺了它后端会打一条 warning 并跳过界面挂载, 此时只有/docs和/api/*可用。发给同事的压缩包里只有这一次的构建结果,没有前端源码,同事看到的界面就是打包当时的页面。要更新界面,在有源码的机器上重新执行打包。
想把这个形态做成「解压双击即用」的分发包,用内置的打包与启动脚本:
uv run python scripts/package.py # 生成 Paper-Agent-<日期>.zip包内自带 start.bat 和 uv.exe,解压后双击即可,不用装 Python 或 Node。如果目录里没有 tools/uv.exe、电脑上也没装 uv,start.bat 会先把它下载到 tools/uv.exe。
面向使用者的说明见 使用说明.md。
系统支持配置多个 Provider。内置档位只有 default_agent 一个;主对话另有可选档位 research_agent(未配置时回退 default_agent)。精读、追问和综述不单独配档位,直接复用主对话这次用的模型。
- 配置主文件:
config/model.json(含密钥,不入库),示例见config/model.example.json,系统参数见config/system.yaml
| Agent | 运行时实际使用的档位 | 主要职责 |
|---|---|---|
researchAgent(主对话) |
research_agent,未配置时回退 default_agent |
多轮对话、工具调用与任务分派 |
deepReadAgent / paperQaAgent |
复用主对话的档位快照 | 全文精读、基于全文的追问 |
| 综述流水线 | 复用主对话的档位快照 | 分析论文、生成大纲、逐节写作并审查修改 |
ReadAgent |
复用主对话的档位快照 | 阅读摘要,判断相关性并整理笔记 |
default_agent 是唯一必需的档位,缺失时配置无法工作。
说明:配了
research_agent时,精读、追问、综述和摘要相关性评价跑的都是这一档的模型。ReadAgent的AgentSpec里虽然写了llm_profile,对话里并不按它另装一份。综述里的分析、大纲、写作也不再单独声明档位。
支持 backend 类型:openai、openai_compat、anthropic、anthropic_compat、opencode_go。示例:
{
"providers": {
"my_provider": {
"backend": "openai_compat",
"api_key_env": "OPENAI_API_KEY",
"api_base": "https://api.openai.com/v1",
"extra_headers": {},
"extra_body": {}
}
}
}opencode_go 对应 OpenCode 的 Go 订阅端点(https://opencode.ai/zen/go/v1,OpenAI 兼容),
它强制要求每个请求都带上 x-opencode-session 请求头,这个头由代码自动补齐、不需要手工配置;
可用的模型名以 GET https://opencode.ai/zen/go/v1/models 返回的清单为准。
api_key 与 api_key_env 二选一即可。使用兼容网关时通常需要同时填写 backend、api_base 和模型名称。
config/system.yaml 存放系统级默认值和阅读参数:defaults.llm 是所有 Agent 档位未声明字段时的兜底生成参数,paper_retrieval 是检索数据源密钥,read 是阅读与下载参数(缓存目录、连接/下载超时、最大文件大小、PDF 解析器)。
其中 defaults.llm.context_window_tokens 默认按 1M token 计(DeepSeek 等长窗口模型的量级),主 Agent 用它给对话历史算预算:窗口 × 0.8 = 历史可占用上限,超出会自动「归档旧工具结果 → 整轮 LLM 压缩」。想快速验证压缩效果,可临时把它调小(如 8000)。
PDF 正文由本机的 Nougat 按页写成 Markdown。它读的是整页,公式会写成 LaTeX。写进 paper.md 之前,把 Nougat 的 \[...\] 换成 $$、\(...\) 换成 $...$,这样后面的分块仍能把公式认成一整块。
paper.md 和 chunk.json 仍从同一份文字来。精读、追问、综述写作读到的仍是每段里的文字,不另存一份块文件。
一块仍是这几种:标题、段落、独立公式、夹在句子里的公式、表格、图。公式和表格以 Nougat 写出来的样子为准,不再截图交给精读模型重排。
插图不交给 Nougat。仍用原来的办法在页面上找图、配图注、截到 assets/,再把  接到对应页的末尾。精读时的插图解读也不变。
Nougat 装在 tools/nougat_trial 这个单独环境里。start.bat 启动时如果还没有这份环境,会从阿里云装上 PyTorch,并把大约 1GB 的模型权重下到 tools/nougat_trial/weights(只留在本机,不提交)。主程序用子进程调用。环境或权重不在时,这次转换直接失败,不再退回按字形抽正文。
分片顺着这些块的阅读顺序装箱,片段之间不重叠:
- 装到 1200 字就换下一段,不把一块从中间劈开。
- 新的一级标题到来、而且当前段里已经有正文时,从标题另起一段。字母小节(如
A.)不算一级标题。 - 单块超过 4000 字才单独成段。大表仍按行切开,每一段补上表头。
这两个数字写在 PageChunker 里,不通过配置文件调整。一整块不到 4000 字时可以比 1200 字长,所以不能把 1200 理解成每段的硬上限。精读读某一段时,会附带上一段末尾、下一段开头各一两句作为衔接,切片文件本身仍不重叠。
插图清单来自「图」这种块。网页全文没有这些块,才退回正文里的图片链接。
转换器和分片各自有版本号(现在是 9 和 10)。旧的 paper.md / chunk.json 对不上就重做。没有现成的块时,分片按空行从 Markdown 认块。
The-never-lemon
欢迎提交 Issue 和 Pull Request。建议贡献前先完成:
- 在
test/中补充或更新对应行为的测试; - 运行
uv run python -m unittest discover -s test -v; - 运行
npm run front:build,确保前端类型检查和构建通过; - 在 PR 描述中说明改动范围、配置影响和复现步骤。
项目地址:https://github.com/The-never-lemon/PaperAgentMain
让论文检索更快,让研究脉络更清楚。

