---
name: literature-search-verify
description: Search academic literature across arXiv, Semantic Scholar, Crossref, OpenAlex, and other connected paper-search MCP tools, and independently verify every candidate citation before it is treated as real. Use this whenever the user asks to find papers, search literature on a topic, build a reading list, compile related-work references, check whether a citation or bibliography entry actually exists, or prepare references to import into Zotero or a .bib file — especially in academic writing contexts where a fabricated citation would be a real problem. Also covers guiding the user to the Zotero Connector browser extension for Chinese-language sources (CNKI/知网, Wanfang/万方, VIP/维普) that have no public API and cannot be reached by search tools.
---

# 文献检索 + 反幻觉引用核查

## 为什么需要这个技能

大语言模型在编造论文引用这件事上非常擅长——生成的标题、作者、期刊名读起来都很像真的,但可能根本不存在,或者张冠李戴(把A论文的结论安在B论文头上)。这在正式学术写作里是不可接受的:一篇论文只要有一条编造的引用被发现,审稿人对全篇的信任都会崩塌。

所以这个技能的核心不是"搜索",而是"搜索之后不轻信"——每一条打算真正拿去引用的文献,都必须经过独立交叉验证,验证不通过的必须明确标出来,而不是悄悄丢弃或者悄悄当作真的用。

## 工作流程

### 第一步:明确检索范围

在开始搜索前,搞清楚(不确定就直接问,一句话就够):
- 核心关键词/研究方向(可以中英文混合,比如"UAV磁补偿 Tolles-Lawson"这类)
- 大致的时间范围(比如"近5年"还是不限)
- 是否需要限定顶会/顶刊,还是什么来源都要

### 第二步:检索——直接调用脚本,不要自己现编API调用

`scripts/` 目录下已经写好了能直接跑的检索脚本,不依赖任何第三方Python包,也不需要装MCP工具:

```bash
# 始终从项目根目录调用(脚本本身不关心cwd,但--bib-out等输出路径按项目根目录约定拼)。
# 一次性搞定:检索 arXiv + Semantic Scholar + Crossref,自动去重、逐条验证,
# 并把通过验证的条目写成BibTeX文件——这是应该默认调用的入口
mkdir -p output/literature-search-verify/uav_aeromagnetic_compensation
python3 .claude/skills/literature-search-verify/scripts/literature_search.py \
    "UAV magnetic compensation Tolles-Lawson" \
    --max-per-source 8 \
    --bib-out output/literature-search-verify/uav_aeromagnetic_compensation/refs.bib
```

草稿路径(检索报告JSON、下载的PDF、中间生成的bib)统一落在项目根目录下的
`output/literature-search-verify/`,不要写回技能自己的目录里(`.claude/skills/`
应该只放技能代码,不放运行时产生的草稿数据)。如果项目里以后还有别的技能也
需要草稿区,各自建 `output/<skill-name>/` 子目录,互不混放。

**同一个技能内部也要按主题分开,不要所有检索会话都堆在同一层**:开始一个新
主题的检索时,先按"和第六步归档时同样的规则"把主题名转成 slug(小写、非
字母数字换成下划线,比如"UAV aeromagnetic compensation" → `uav_aeromagnetic_compensation`),
建 `output/literature-search-verify/<topic-slug>/` 子目录,这一整个主题下
不管跑多少轮检索、多少条不同的query,原始JSON/bib草稿都写进这一个子目录里
(文件名可以随意区分轮次,比如`q1.json`/`q2.json`),不要用不带主题区分的
通用文件名散落在`output/literature-search-verify/`根下。这样同一个主题的
草稿和第六步归档产出的`references/<topic-slug>/`目录能通过同一个slug对上号,
之后回来补充检索同一主题时也知道去哪个子目录续。

正常情况下**只需要跑这一条命令**,它内部会依次调用 `search_arxiv.py`、`search_semantic_scholar.py`、`search_crossref.py`、`search_openalex.py` 做检索,再对每条合并后的候选文献跑 `verify_citation.py` 做交叉验证,输出一份JSON报告(每条候选都带`verdict`字段)。如果只是想单独查一个来源,或者针对某一条文献单独复核,再分别调用对应的单个脚本(用法见每个脚本文件开头的docstring)。OpenAlex(`search_openalex.py`)是在 arXiv/Semantic Scholar/Crossref 之外新增的第四个源,免费、无需API key,覆盖面比单独的 Crossref 更广(聚合了包括 IEEE 在内的绝大多数出版商元数据),还能拿到开放获取PDF直链;可以设置`OPENALEX_MAILTO`环境变量为一个邮箱地址进入OpenAlex的"polite pool"换取更稳的限额,不设置也能正常用。

所有脚本的网络请求都经过 `http_utils.py` 统一封装:遇到 429(限流)或 5xx 会按指数退避自动重试几次(优先遵守服务端返回的`Retry-After`),不需要每次手动重试;`verify_citation.py`的跨源标题核查更是同时查 Semantic Scholar 和 OpenAlex 两个独立源、任一命中即算通过,不会再出现"S2一限流,整批候选的跨源核查全部退化成skipped"的情况(这是实际发生过的问题,现在已经用两个源+重试解决)。即便如此,如果这些脚本因为网络原因跑不动(比如内网/代理限制导致连不上这几个学术API域名),`literature_search.py` 会把每个来源的报错单独记在`search_errors`里而不是直接崩溃——这时候老实告诉用户"检索脚本连不上网络,以下是报错信息",不要退回去凭记忆编文献。如果用户这边确实连不上这几个学术API域名,才退回到 web_search 工具,并在结果里明确标注"来自通用网络搜索的补充结果,未经过脚本的交叉验证流程,置信度较低"。

如果用户已经连了 paper-search-mcp / scholar_mcp_server 这类MCP工具,可以补充用来扩大覆盖面(比如它们能覆盖PubMed、能直接下载PDF),但**不能替代**`verify_citation.py`的交叉验证这一步——MCP搜到的候选一样要过一遍验证,不能因为是工具搜出来的就默认可信。

### 第三步:理解验证结果——这是最关键的一步

`literature_search.py`(或单独调用`verify_citation.py`)对每条候选文献做的核查是:

1. **arXiv ID 独立核实**:如果有 arXiv ID,反查一次 arXiv API,确认这个ID真的存在且标题对得上——一个编造的ID在这一步会直接暴露。
2. **DOI 独立核实**:如果有 DOI,反查一次 Crossref,确认这个 DOI 真的能解析出对应文献。
3. **跨源标题复核(双源)**:不管有没有ID,单独拿标题分别去 Semantic Scholar 和 OpenAlex 各搜一次,要求返回的标题跟候选标题高度相似(相似度≥0.9)——这一步专门用来抓"标题作者读起来很像真的,但其实是编出来的"这种情况。两个源里任一个命中相似度达标就算通过;只有当两个源都明确没找到匹配(不是因为网络问题被跳过)时才算这一项核查失败——避免某个源覆盖不全(比如论文太新还没被其中一个索引收录)被误判成"编造"。

每条候选最后会带一个`verdict`:
- **verified**:至少一项独立核查通过,而且没有任何一项核查明确失败
- **suspect**:至少一项核查明确失败(比如DOI查不到、跨源标题对不上)——**这种情况下不要用这条文献,即使标题看起来很合适**
- **unverified**:所有核查项都因为网络等原因被跳过(`skipped`),不代表验证通过,只代表"没能验证"——**同样不能当成已核实的文献直接使用**,要跟用户说清楚原因

呈现给用户时按这三档分组说明,`suspect`和`unverified`都要明确标出来,不要因为报告里有个"看起来还行"的标题就含糊地当真的用。

**原则**:找不到真实存在的相关文献时,直接说"没找到符合条件的文献",不要为了凑数编一条出来。这条原则没有例外。

### 第四步:输出

按 verified / suspect / unverified 分组呈现结果,每条包含标题、作者年份、venue、标识符、一句话相关性说明。

`literature_search.py` 传了 `--bib-out` 参数时,会自动把所有 `verified` 的条目写成BibTeX文件,citation key 用"姓氏+年份"约定,可以直接导入 Zotero(配合 Better BibTeX 插件)。这些 key 也是后续`paper-writing-grounded`技能里`\cite{}`要用到的,两个技能之间通过这些key保持一致,不需要额外对照。

### 第五步:提醒中文文献的检索缺口

MCP 检索工具覆盖的是 arXiv/Semantic Scholar/Crossref 这类有公开 API 的英文为主的库,**知网、万方、维普这类中文数据库没有公开 API,搜不到很正常,不是技能出错**。遇到用户明显需要中文文献的场景,主动提醒:装好 Zotero Connector 浏览器插件,在浏览器里正常登录学校账号搜索、打开文献页面,点一下 Connector 图标就能把元数据和 PDF 存进 Zotero——这部分需要用户手动完成,不要尝试用检索工具"模拟"或"猜测"中文文献的存在。

### 第六步:归档

`<project-root>/output/literature-search-verify/` 只是脚本运行时的草稿区——里面
混着每一轮探索性检索的原始JSON(包括被过滤掉的噪声,比如"Tolles""Lawson"被当成
人名匹配出的无关文献),不适合作为最终交付物,而且随着会话增多会越堆越乱、也不
方便下次会话或用户直接翻阅。

所以每次整理出一份**稳定可信的参考文献列表**(不管是第一轮检索还是后续多轮补充检索合并后的结果)之后,调用归档脚本把它固化到项目级目录,而不是留在草稿区里:

```bash
python3 .claude/skills/literature-search-verify/scripts/archive_references.py \
    "UAV aeromagnetic compensation" \
    --bib output/literature-search-verify/uav_aeromagnetic_compensation/uav_aeromagnetic_compensation_final.bib \
    --project-root . \
    --pdfs-dir output/literature-search-verify/uav_aeromagnetic_compensation/pdfs \
    --suspect "某条可疑文献标题|不建议引用的具体原因" \
    --notes "检索覆盖了哪些方向、哪些方向搜了但没结果、中文文献缺口提醒等"
```

这会在 `<project-root>/references/<按主题自动生成的slug>/` 下生成:
- `references.bib` —— 传入的bib文件原样拷贝过去
- `pdfs/`(如果传了`--pdfs-dir`且里面有PDF)—— 一并拷贝过去
- `README.md` —— 自动从bib里解析出条目列表(标题/年份/venue/DOI/note)生成索引,`--suspect`和`--notes`里的内容会分别整理进"不要引用"和"检索覆盖说明"两个小节

几个要点:
- `--bib` 传的必须是**已经过滤掉无关噪声、只保留verified条目**的干净bib文件,不要把`literature_search.py`直接吐出来的、可能夹杂噪声的原始bib不加甄别地拿去归档。
- 同一个`topic`名字多次调用会往同一个归档目录里覆盖更新(bib和README会被覆盖,pdfs按文件名去重合并),所以后续检索到更多文献后可以直接对同一个topic重新跑一遍归档脚本来更新,不需要手动合并。
- 这一步做完之后可以明确告诉用户归档目录的路径,方便他们后续在`paper-writing-grounded`阶段直接引用。

## 维护者备注:单元测试

`scripts/tests/` 下有针对核心正确性逻辑的单元测试(不发真实网络请求,全部用
mock):`verify_citation.py` 的三档判定和双源标题核查合并逻辑、
`archive_references.py` 的 bib 解析(含嵌套花括号、中文主题名slugify等边界
情况)、`literature_search.py` 的候选去重合并与BibTeX生成、`http_utils.py`
的限流重试。改动这几个脚本后应该跑一遍:

```bash
python3 -m unittest discover -s .claude/skills/literature-search-verify/scripts/tests -t .claude/skills/literature-search-verify/scripts
```

只用标准库`unittest`,不引入pytest等第三方测试框架,和脚本本身"不依赖第三方
包"的原则保持一致。

## 和 paper-writing-grounded 技能的配合

这个技能负责把"真实存在、经过核实的文献"整理好并生成 BibTeX;写作阶段的 paper-writing-grounded 技能会直接消费这里产出的 citation key,正文引用只能来自这里核实过的条目,不会凭空生成新的引用。两个技能配合使用时,建议先跑完这个技能、拿到稳定的参考文献列表,再进入写作。
