dsh-paper-reader
DSH 插件:论文解读模式。精读单篇论文并生成证据可追溯的中文解读报告,按图注自动裁出图表,并基于同一份解析产物回答关于这篇论文的问题。速览 / 解读 / 深读三档可选,以 agent preset 隔离,只在选中该模式时可见。
- Stars
- 0
- Language
- JavaScript
- Created
- Sep 29, 2026
- Updated
- Oct 2, 2026
Introduction
dsh-paper-reader
DSH 插件:论文解读模式。精读一篇具体论文并生成解读报告,同时基于同一份解析产物回答关于这篇论文的问题。
这个插件解决什么
三件事,都放在一个只在需要时出现的模式里:
- 解读报告 —— 给定一篇论文,产出结构固定、证据可追溯的中文报告。解读深度分 速览 / 解读 / 深读
三档,由输入框旁的档位控件选定(不是让模型自己猜);图表自动裁好,嵌在第一次提到它的位置;
报告头写清原文路径与
docId,读者把报告交给自己的 agent 提问时能直接定位同一份解析产物。 - 论文问答 —— 针对同一篇论文提问,答案带页/章节锚点,并分清作者主张与推断;默认一次检索 就带约两段上下文,多数问题不必再读整页。
- 输出风格 —— 术语首现给中英对照加白话解释、缩写首现展开、同一概念只用一个名字、指标首现 说清「它在算什么」、公式写成 LaTeX、不写空转句。
档位控件
进入「论文解读」模式的会话后,输入框工具行左侧会出现一个三档段控件:
| 档位 | 篇幅(参考,不设上限) | 读到什么程度 | 交付文件名 |
|---|---|---|---|
| 速览 | 通常 800–1500 字 | 主智能体自己顺序读 3–5 页(摘要、引言、方法开头、主结果),不起并行编排 | <简称>-速览.md |
| 解读(默认) | 通常 3000–6000 字 | 并行分节读正文,附录只读与主张相关处 | <简称>-解读报告.md |
| 深读 | 参考 8000 字以上 | 并行读全文 + 附录的超参 / 梯度 / 算力 / 数据配比 | <简称>-深读报告.md |
篇幅只用来校准基调,不是硬指标:该讲清楚的(指标在算什么、公式的符号、证据边界)不因为怕超字数而省, 内容紧凑时也不硬凑;写长了先检查是不是把更深档位的内容写了进来。
档位是每个会话独立的(同一工作目录里可以一个会话写速览、另一个写深读)。模型只看到自己这一档的 流程:技能正文按档位装配,系统提示里也只有当前档位那一段——没有另外两档的冗余。控件只在论文解读 模式出现,其他模式的会话里既不显示控件、也看不到这些技能。
档位不是模型判断的:模型只被要求照当前档写。用户的措辞看起来像另一档时,模型按当前档交付并在导读 里说明可以换档,不会自行改档。
为什么是 agent preset,而不是全局 skill
DSH 的 skill 目录只在上下文里放「名字 + 描述」,正文按需加载——但目录行、persona、工具仍然是每个 session 都要背的成本。本插件把这部分整个放进一个 agent preset:在 Web 的新任务模式选择器里选 「论文解读」才生效,其他模式(standard / ptc / …)的会话里看不到这些 skill、persona 和工具。
这不是约定,是 DSH 的原生隔离:ctx.skills.registerProvider 的注册落到调用上下文的 scope 层。
取舍与实测细节见 设计与取舍。
一处例外,值得明说:档位控件必须由 profile 根层的 bundle 提供——DSH 组装浏览器插件图时只扫描 根层 bundle 行,preset 的子行拿不到 UI(代码层面无解)。所以本包被挂两次:根层那一行 (
role: control)只负责让控件进页面并注册档位端点,preset 里那一行(role: agent)注册技能、 五个工具与档位提示词段。模型可见面仍然全部落在 preset 的 scope 上,隔离是 DSH 原生的——包括 工具在内,别的模式一件都看不到。两行都由本包自己的 patch 提供,不需要手工改配置;取舍与实测 见 设计与取舍。
安装
本包自带运行时依赖(mupdf、yaml),且 node_modules/ 不入库,所以在装进 profile 之前必须先在
本包目录里装一次依赖:
cd <本包目录>
pnpm install
dsh plugin --profile web add <本包目录>
装完重启 dsh web:preset 与根层 bundle 都属启动期组装。本包同时出现在两处——
cordis.patch.yml 插根层 bundle 行(role: control,让控件进页面),presets/paper.patch.yml
插 preset 行(role: agent,提供模式身份与模型可见面)。dsh plugin add 会自动带上这两层,
不需要手工改 profile 配置,也不要删掉其中任何一行:少了根层那行没有控件,少了 preset 那行则论文
模式没有技能和工具。
别用 scp 风格的 URL 让 pnpm 去装(
git@github.com:...)——pnpm 会把它误解析成「包名git+ 版本」,插件不会生效。本插件目前只验证过本地路径安装;远端安装的写法与注意事项见 开发文档。
Windows 与 Linux 都能用:preset 里 bash / pwsh 两行按平台互相 disabled,与官方 preset-standard
的写法一致。
五个工具
| 工具 | 做什么 | 关键参数 |
|---|---|---|
paper_import | 把 PDF 导入本地缓存,返回 docId 与论文地图(章节树 + 图表清单) | source(绝对路径) |
paper_search | 检索词句,返回命中片段与 [p.7 §3.2] 锚点 | docId query limit(默认 6,≤30) context(默认 window) |
paper_read | 按页读正文,超出字符预算就如实报告截断 | docId pages(如 3,7,9-11) maxChars(默认 24000) |
paper_figure | 渲染整页,或按 bbox 只裁一块区域 | docId pages(单次≤8 页) dpi(默认 120) bbox outputDir |
paper_figures | 按图注自动裁出全部图与表,一张一个 PNG | docId pages dpi(默认 200) max(默认 24) outputDir |
paper_search 的 context 有三档:snippet(命中处前后各 70 字,最省)、block(命中所在块)、
window(默认,命中块连同前后各最多两块,约 700 字符)。默认档就是照着「一次检索够回答、
不必再读整页」选的。
设计上值得说明的四点:
- 一次导入,多处复用。 报告与问答共用同一份解析产物,所以锚点在同一篇论文里始终一致。
docId是 PDF 字节的 sha256 前 12 位,同一份文件换路径导入仍然命中同一份缓存。 - 检索优先于通读。
paper_search先按短语匹配,一个都不中才退化成「所有词都出现」的宽松匹配, 并在结果里标明是哪种模式——避免模型把宽松命中当成精确依据。 - 锚点是算出来的。 每个文本块带 bbox 与「是否标题」判定,命中项因此能给出
[p.7 §3.2]这种 可核查的位置。判定同时看文本形态与排版特征(加粗,或字号大于全篇正文基准字号),宁可漏判 让锚点变粗,也不误判让锚点指错章节。算法与失败模式见 设计与取舍。 - 图是按图注找出来的。
paper_figures走一遍页面的 display list 收集矢量图元与位图的 bbox, 按「图注所在栏 + 正确一侧」认领,再用墨迹分布收紧。因此裁出来的是图本身,不是整页截图; 并排的两张图各自成图。裁切框不与图注文字相交:渲染前按图注块的 bbox 再削一遍,图注原文 单独返回,报告把它写在图片下方。启发式会失败,失败项如实列出并可用bbox手动裁,取舍见 设计与取舍。
数据放在哪
缓存默认落在 $DSH_HOME/paper-reader/:
paper-reader/
├── levels.json 档位:{ "version": 1, "levels": { "<sessionId>": "brief|standard|deep" } }
└── <docId>/
├── meta.json 页数、源路径、导入时间、PDF 内嵌标题/作者(常常没有)
├── source.pdf 源文件副本——缓存因此自包含,原文件被移走也能继续渲染
├── pages/001.txt 分页正文
├── pages/001.json 结构化块(bbox / 行数 / text / heading),锚点由图注分侧都由它算出来
├── figures.json 图形区域检测结果(图注 → 裁切矩形),首次检测时写入
└── figures/p002@120.png
meta.json 最后写,所以它存在就意味着这次导入完整;中断的导入不会留下「看起来能用」的半份
缓存。缓存根可以在代理面那一行(presets/paper.patch.yml 的 paper-reader-agent)加
config.cacheRoot 覆盖;档位文件也在同一个根下,控制面那一行必须给同一个值(控制面默认值与
代理面一致,所以只在两边都改时才需要动):
- id: paper-reader-agent
name: 'dsh-paper-reader'
config:
role: agent
cacheRoot: /path/to/paper-cache
它里面的 format 是缓存格式版本:抽取逻辑改进后旧缓存里的页码与块结构就不再可信,版本对不上会
重新解析并覆盖。因此改了抽取逻辑必须抬 CACHE_FORMAT,见
维护纪律。
档位写的是文件而不是会话事件:DSH 的持久化读到未知事件类型会拒绝整条会话日志,而仓库外插件
无法给事件打 ignorable 标记。取舍与替代做法见
设计与取舍。
技能
skills/<name>/SKILL.md 三个技能包,随模式一起生效:
| 技能 | 什么时候用 | 按档位装配 |
|---|---|---|
paper-report | 要求解读、精读、写阅读报告 | 是(工作流与各节重心来自 levels/<档位>.md) |
paper-qa | 针对某一篇论文提问 | 否(问答与档位无关) |
paper-verify | 成稿自审(报告或较长答案交付前) | 是(第 10 项按档位核对,来自 levels/verify.md) |
技能名刻意保持稳定(不按档位拆成三个技能):/paper-report 这类手势与「用户自己的同名技能覆盖
本插件版本」都依赖名字稳定,而技能目录的每一行都是每个会话的固定成本。代价是目录行看不出档位差异,
所以系统提示里的档位段会明说「以 paper-report 正文为准」。
技能名的来源、frontmatter 约定与「改正文不需要重载」的机制见 开发文档。
验证
node --test # 132 条:provider / preset / client 契约 + levels 装配 + pdf 行为 + tools 行为
不改任何 profile、验证 bundle 与 preset 组装的方法见 开发文档。
已知限制
首次导入会把每页解析两遍(实测 17 页约 127ms、31 页约 247ms,之后命中缓存);图形区域检测是启发式 的,会漏也会多框(唯一硬保证是裁切框不含图注文字),自动裁不出来的项会如实列出;公式的上下标在 纯文本抽取里会丢,本包不做公式 OCR,改为要求写成 LaTeX 并回原页核对;章节锚点的粒度取决于论文模板。 逐条说明与实测记录见 已知限制。
许可证
MIT,见 LICENSE。仓库:https://github.com/s11phere/dsh-paper-reader(私有)。