学术搜索 API 一览¶
Agentero Host 端(src-tauri/src/features/)在论文识别、入库、引用补全、推荐等流程中,会调用若干外部学术服务。本文档列出所有当前在用的学术搜索/元数据 API,说明其用途、调用入口、请求形态、fallback 链路与并发控制。
范围限定在学术元数据与论文发现相关的外部 HTTP API。翻译 API(Google/Bing/DeepL/OpenAI 等)、版面分析 ONNX、本地 Agent/ACP、PostHog 遥测不在本文讨论范围内。
路径简写:
scholar_api/…与features/paper/import/的映射 / resolver / 路由(scholar_api::identifiers、api_mapper.rs、search_router.rs、search.rs、download.rs、sources/)已随 crate 拆分迁到crates/agentero-core/src/features/paper/…;import/recognize/(PDF 识别)与import/commands.rs仍在src-tauri。其余features/…均指src-tauri/src/features/…。
1. API 总览¶
| 服务 | 主要端点 | 用途 | 核心调用模块 |
|---|---|---|---|
| Semantic Scholar Graph API | GET /graph/v1/paper/search |
标题/关键词搜索 | features/paper/import/search_router.rs |
| Semantic Scholar Graph API | GET /graph/v1/paper/{id}/references |
在线参考文献补全 | features/refs/online.rs |
| Semantic Scholar Graph API | GET /graph/v1/paper/ARXIV:{id} / DOI:{doi} |
venue 回填(publicationVenue.name) |
features/paper/scholar_api/sources/semantic_scholar.rs(fetch_venue_by_*),调用方 features/paper/import/commands.rs |
| Semantic Scholar Graph API | GET /graph/v1/paper/{id}/citations |
"谁引用了我" 候选发现 | features/refs/citing.rs |
| arXiv Atom API | GET https://export.arxiv.org/api/query |
按 ID 取元数据 / 按标题搜索 | features/paper/import/mod.rs, features/paper/import/search_router.rs |
| arXiv 二进制端点 | https://arxiv.org/pdf/{id} / https://arxiv.org/e-print/{id} / https://arxiv.org/src/{id} |
PDF / TeX 源码下载 | features/paper/import/download.rs |
| Crossref REST API | GET https://api.crossref.org/works/{doi} |
DOI → 元数据 / 参考文献 | features/paper/import/recognize/pdf_recognize.rs, features/paper/analyze/refs/online.rs, features/paper/catalog/commands.rs |
| OpenAlex REST API | GET https://api.openalex.org/works |
标题搜索兜底(含 cited_by_count) |
features/paper/scholar_api/search.rs(SourceScope::All 兜底源) |
| Unpaywall | GET https://api.unpaywall.org/v2/{doi} |
DOI → 开放获取 PDF | features/paper/import/download.rs |
| PubMed / NCBI E-utilities | GET https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi / efetch.fcgi |
标题/PMID → 医学/生命科学元数据 | features/paper/scholar_api/sources/pubmed.rs |
| alphaXiv | GET https://api.alphaxiv.org/papers/v3/{id}/preview、GET /v1/search/paper?q= |
arXiv 元数据/标题搜索的末位备份源(未文档化匿名 JSON API) | features/paper/scholar_api/sources/alphaxiv.rs |
| bioRxiv | GET https://api.biorxiv.org/details/biorxiv/{doi} |
DOI → 生命科学预印本元数据 | features/paper/scholar_api/sources/biorxiv.rs |
| medRxiv | GET https://api.biorxiv.org/details/medrxiv/{doi} |
DOI → 医学预印本元数据 | features/paper/scholar_api/sources/biorxiv.rs |
| Zotero Recognizer | POST https://services.zotero.org/recognizer/recognize |
PDF 首页文字几何识别 | features/paper/import/recognize/pdf_recognize.rs |
| Translator Runtime | POST {base}/web, POST {base}/search, POST {base}/import |
通用 URL/标识符/题录解析 | features/import/mod.rs |
| Cool Papers (papers.cool) | GET https://papers.cool/{branch}/search?query=..., GET https://papers.cool/{branch}/kimi?paper={id} |
Kimi 论文解析 / 广场导入 | features/coolpapers/ |
| arXiv RSS | GET https://rss.arxiv.org/rss/{category} |
推荐与订阅流 | features/recommend/mod.rs, features/feeds/ |
2. 调用链路详解¶
2.1 论文识别与魔棒入库¶
入口:features/import/commands.rs::paper_resolve_identifier、features/import/mod.rs::import_by_identifier_with_progress。
当前主路径按以下顺序尝试:
- 标题/关键词搜索(
features/paper/import/search_router.rs::search_papers) - Semantic Scholar
GET /graph/v1/paper/search?query=...&fields=title,authors,year,venue,publicationVenue,journal,externalIds,citationCount,url与 arXiv AtomGET export.arxiv.org/api/query?search_query=ti:"..."并行发起。S2 在 5s 预算(S2_SEARCH_BUDGET)内返回非空则优先(venue 取publicationVenue.name(跳过type=repository),其次journal.name,再次venue),否则取已在途的 arXiv 结果;最坏耗时 ≈ max(预算, 单请求 20s 超时)。 - 仅保留带 DOI 或 arXiv id 的候选;返回结果会按精确标题匹配重新排序。
resolve_search_queries接收前端task_id:关闭搜索卡片取消任务后,剩余查询直接跳过。- Translator Runtime(
features/import/mod.rs::resolve_metadata) - 若用户输入被识别为 arXiv id / DOI / URL,会构造
{base}/web或{base}/search请求。 - arXiv 的各类输入(
2508.05004、arXiv:2508.05004v2、https://arxiv.org/pdf/...、https://arxiv.org/html/...)都会被规范化为https://arxiv.org/abs/{id}再走/web。 - Translator 失败时按标识符类型走直连兜底链(
scholar_api::identifiers::fallback,见下)。 - 直连兜底链(
features/paper/scholar_api/identifiers/fallback.rs) - arXiv →
ARXIV_CHAIN= arXiv Atom → S2ARXIV:{id}→ alphaXiv/papers/v3/{id}/preview。 - DOI →
DOI_CHAIN= Crossrefworks/{doi}→ S2DOI:{doi}→ OpenAlex。 - PMID →
PMID_CHAIN= PubMedefetch。 - 执行模型是错峰投机并发 + 优先级顺序接受(hedged chain):链内所有源同时 spawn,第 i 个源先睡
i×600ms再请求,随后严格按优先级顺序 await——首个非空Ok胜出并 abort 其余在飞请求。健康主源在错峰窗口内完成时请求数与单源直连相同;主源 429/慢时失败前缀时延取max而非sum。整趟全失败且含 429 → 2s 冷却后重试一趟,仍失败按rate_limited上报(#524:不再误报「无结果」)。 - arXiv Atom 解析
<arxiv:journal_ref>作为 publication/venue(链内其余源不提供 venue 回填语义,透明受益于既有 merge 偏好)。
被引数(
citation_count):Crossref 解析is-referenced-by-count、OpenAlex 解析cited_by_count、Semantic Scholar 解析citationCount,三者capabilities()均声明PROVIDE_CITATION_COUNT;Crossref / OpenAlex 的 title search 还必须把该字段列进select白名单,否则 API 根本不返回它。api_paper_to_meta把值带进PaperRecord,merge_api_papers合并两个源时取较大值(各自索引的引用文献子集不同)。arXiv Atom 与 Translator 不产出被引数。注意:入库以 Translator 为主路径,map_zotero_item_to_record不带被引数,因此常规导入写入的仍是 NULL;只有 Translator 失败后降级到 Crossref 直连的 DOI 导入才会落进真实值。完整缺口见 catalog.md。
2.2 PDF 元数据识别¶
入口:features/paper/import/recognize/pdf_recognize.rs::recognize_and_resolve。
流程:
- 本地 liteparse 探测 PDF 前若干页文字几何。
- 将文字几何按 Zotero Worker 形状提交到
https://services.zotero.org/recognizer/recognize,获取可能的 DOI / arXiv / title。 - 若识别出 DOI →
import/mod.rs::resolve_metadata→ Translator → DOI 兜底链(Crossref→S2→OpenAlex)。 - 若识别出 arXiv → arXiv 兜底链(Atom→S2→alphaXiv);
meta_source如实反映实际应答源。 - 仅有 title/authors 时 → 生成本地 PDF 占位元数据(
meta_from_recognize)。
2.3 参考文献在线补全¶
入口:features/refs/online.rs::fetch_references。
- 优先 Semantic Scholar:
GET /graph/v1/paper/{id}/references?fields=title,authors,year,venue,externalIds,url&limit=1000,{id}为arXiv:...或DOI:...。 - 失败或无结果且存在 DOI 时,fallback Crossref:
GET api.crossref.org/works/{doi}?mailto=agentero@users.noreply.github.com,取message.reference[]。
2.4 反向引用发现("谁引用了我")¶
入口:features/refs/citing.rs。
- 仅使用 Semantic Scholar:
GET /graph/v1/paper/{id}/citations?fields=...&offset={offset}&limit={limit}。 - 因为 OpenAlex 的 arXiv 预印件引用边稀疏,所以未采用。
- 内部有 L0/L1/L2 三层过滤与 SPECTER2 相似度排序,分页上限受 S2
offset + limit < 10000限制。
2.5 Venue / Publication 回填¶
入口:features/import/commands.rs::paper_backfill_publication。
用于 Library 的 publication 列批量补全。实测各源准确度:
| 源 | 适合 | 缺陷 |
|---|---|---|
arXiv <arxiv:journal_ref> |
作者已回填的发表信息,最完整(含年/卷) | 大量已发表论文仍为空(如 Attention Is All You Need) |
S2 publicationVenue.name |
会议 + 期刊的规范化全名 | 免费端点限流;venue 字段常为空或缩写 |
Crossref container-title |
期刊(Nature 等)准确 | ACL/NAACL 等会议名会被截断(Proceedings of the 2019 Conference of the North) |
| OpenAlex / DBLP | — | OpenAlex 对 CS arXiv 常无 venue;DBLP 只有缩写(NIPS / NAACL-HLT) |
因此顺序是:
- arXiv id → arXiv Atom
export.arxiv.org/api/query?id_list={id},取<arxiv:journal_ref>;缺失则GET /graph/v1/paper/ARXIV:{id}?fields=venue,publicationVenue,journal(s2_venue_from_paper)。丢弃arXiv/CoRR等仓储名。 - DOI → 取 S2
publicationVenue与 Crossrefcontainer-title中更长的可用名(S2 赢截断的 ACL/NAACL;Crossref 赢完整 proceedings 标题)。跳过10.48550/arXiv.…。 - 仅 title → Semantic Scholar
search_papers(title, 1),同样走publicationVenue。
UI 刷新(paper_resolve_identifier)对 DOI/arXiv/URL 先走标识符解析,再用 S2 补全空缺或 Crossref 截断的 proceedings 标题;自由文本才走 title search。
2.6 arXiv / DOI Venue 回填¶
入口:features/paper/scholar_api/sources/semantic_scholar.rs::SemanticScholarApi::fetch_venue_by_arxiv / fetch_venue_by_doi / fetch_venue_by_ids(取值逻辑 venue_from_paper)。
请求 GET /graph/v1/paper/{ARXIV:id\|DOI:doi}?fields=venue,publicationVenue,journal。取值顺序:
publicationVenue.name(type=repository跳过)journal.name- 遗留
venue字符串
用于:
paper_backfill_publication的 arXiv 分支:Atom 的<arxiv:journal_ref>(scholar_api/sources/arxiv.rs::parse_entries→ApiPaper.venue)缺失时补 venue。- 批量 publication 回填与 Edit Metadata 刷新(
enrich_publication_from_s2)。 - title search 候选的 venue 字段。
2.7 推荐与订阅¶
入口:features/recommend/mod.rs。
- 按用户关注的 arXiv category 拉取
https://rss.arxiv.org/rss/{category}。 - 解析后基于本地 embedding 做相似度排序,产生推荐候选。
2.8 广场 Feed 解析¶
入口:features/feeds/。
- 订阅源同样以
rss.arxiv.org为主。 features/feeds/parse.rs::extract_paper_url会把rss.arxiv.org链接规范化到arxiv.org/abs/{id},并支持 Nature DOI 链接提取。
2.9 Cool Papers (papers.cool)¶
入口:features/coolpapers/mod.rs。
- 解析论文 URL:
https://papers.cool/{arxiv|venue}/{id}。 - 按标题搜索:
GET https://papers.cool/{branch}/search?query=...。 - 获取 Kimi 解析:
GET https://papers.cool/{branch}/kimi?paper={id}。 - 这是一个人工整理的学术站点,不是开放 API;解析结果写入 NOTES.md。FAQ 问题写成
## Qn,保留答案内###小节;丢弃末尾「想要进一步了解论文」FAQ(跳转 Kimi 网页版的推广段)。
2.10 PDF / TeX 资产下载¶
入口:features/paper/import/download.rs。
- arXiv PDF 候选链:
https://arxiv.org/pdf/{id}→https://arxiv.org/pdf/{id}.pdf→https://export.arxiv.org/pdf/{id}。 - arXiv TeX 源码:
https://arxiv.org/e-print/{id}(/src/为别名)。 - DOI 论文 PDF:先查
api.unpaywall.org/v2/{doi},再查 Crossrefmessage.link中的 PDF 链接。
2.11 PubMed / bioRxiv / medRxiv 元数据兜底¶
入口:features/paper/scholar_api/sources/pubmed.rs、features/paper/scholar_api/sources/biorxiv.rs。
- PubMed:实现
AcademicApi,支持标题搜索和 PMID 查询。流程为esearch.fcgi(JSON)拿 PMID 列表 →efetch.fcgi(XML)批量取详情;请求带email与tool参数以符合 NCBI 礼貌使用要求。解析字段包括 title、authors、year、venue、volume、issue、pages、DOI、PMID、abstract;PMC 存在时给出 PDF 候选。 - bioRxiv / medRxiv:共用
biorxiv.rs,实现AcademicApi,仅支持FETCH_BY_DOI(上游 API 无 title 搜索端点)。请求https://api.biorxiv.org/details/{server}/{doi},解析 title、authors、date、abstract,并构造.full.pdf直链。 - PMID 在
scholar_api::identifiers::resolver中已有识别器,现在为其补充 PubMedefetch直连 fallback(scholar_api::identifiers::fallback::fetch_pubmed_metadata);Translator 失败时可直接从 NCBI 拉取。
3. 并发与限流¶
| 能力 | 并发控制 | 说明 |
|---|---|---|
| scholar_api 全部请求 | GLOBAL_CONCURRENCY = 4(scholar_api/client.rs Semaphore) |
6 个标题搜索源并发时尾部排队,排队计入各源 8s FETCH_BUDGET;429→RateLimited、404→NotFound 统一处理 |
| 直连兜底链 | 错峰 600ms/源 + 优先级顺序接受 | 主源健康时零请求放大;链整体限流才 2s 重试一趟 |
| 在线参考文献 | ONLINE_REFERENCE_CONCURRENCY = 2 |
与 title search 独立 |
| 批量入库 | 默认 concurrency = 5 |
LookupImportBatchArgs.concurrency 可覆盖 |
| 反向引用发现 | FETCH_CONCURRENCY = 8 |
实测 8 并发比串行快约 4.6 倍 |
| Cool Papers /kimi | 1 |
避免触发上游 LLM 配额 |
| 通用 HTTP | crate::core::http::client |
共享连接池,单个请求超时 20s,PDF/TeX 下载 180s |
默认所有调用均使用无 API key 的免费端点(Semantic Scholar、arXiv、Crossref、Unpaywall);Semantic Scholar、PubMed 与 OpenAlex 额外支持可选的 BYOK 环境变量(见第 4 节)。Cool Papers 无 auth。Translator Runtime 默认使用项目托管实例 https://translation-server.agentero.app,用户可在设置中替换。
4. 配置与可替换项¶
| 配置项 | 位置 | 默认值 | 说明 |
|---|---|---|---|
translatorBaseUrl |
features/system/settings/mod.rs |
https://translation-server.agentero.app |
可替换为自托管 Translator Runtime |
LookupImportArgs.translator_base_url |
单次请求参数 | 空则使用设置值 | CLI/批量导入可临时覆盖 |
| 后台 PDF 识别(RecognizeMetadata job) | job_runners.rs 直接读设置 translator_base_url |
空则用 DEFAULT_TRANSLATOR_BASE_URL |
不经 IPC 入参传入(ImportLocalPdfArgs 无此字段) |
SEMANTIC_SCHOLAR_API_KEY |
环境变量,scholar_api/client.rs::auth_headers 按请求读取 |
未设置 | 对 api.semanticscholar.org 的请求追加 x-api-key 头;免费 key 可将共享池限速提升至 1 req/s+ |
NCBI_API_KEY |
环境变量,scholar_api/sources/pubmed.rs 按请求读取 |
未设置 | esearch/efetch 追加 api_key= 参数;免费 key 将单 IP 限速从 3 提升到 10 req/s |
institutionProxyType |
设置项 | ezproxy |
网关形态:ezproxy(查询透传 {prefix}{urlencode(target)},裸域名自动补 /login?url=)或 wengine(网瑞达路径式 /https/{AES-128-CTR(host)}/{path},浙大等,见 settings.md) |
institutionProxyPrefix |
设置项(settings.json,camelCase) |
未设置 | 机构网关地址(源站即可),如 https://webvpn.zju.edu.cn(wengine)。设置页提供常见院校快速填充(浙大 / 中科大 / 西交 / 东北大学 / 浙江师范 / 沈阳建筑 / 肇庆学院,均为实测 wengine 网关)。配置后 PDF 下载链在 Unpaywall 未命中时经前缀重写请求,覆盖 #654 一类"浏览器能看、直连 403"的机构订阅场景(预设表为 #677 第一期后的延续项) |
institutionProxyCookie |
设置项 | 空 | 随机构代理请求发送的会话 Cookie(从浏览器 DevTools 粘贴);配套 institution_proxy_probe 命令可测试连通性(取 10.1038/nature12373 校验 %PDF)。桌面与 headless CLI 共用同一份 settings.json:CLI 启动时经 download::load_institution_proxy_from_settings 读取并注入下载链,故 import id / paper download 同样走机构网关(#654 之后补齐的 CLI 侧接线) |
OPENALEX_MAILTO |
环境变量,scholar_api/sources/openalex.rs 按请求读取 |
agentero@users.noreply.github.com |
覆盖 OpenAlex polite pool 联系邮箱;同时补齐 doi: 端点的 mailto 参数 |
Translator Runtime 约定端点:
POST {base}/web:解析 URL(arXiv abstract page、期刊 landing page 等)。POST {base}/search:按标识符或标题搜索。POST {base}/import:解析 BibTeX / RIS 等题录。
5. Fallback 行为速查¶
| 场景 | 第一选择 | Fallback | 最后兜底 |
|---|---|---|---|
| 用户输入 title/关键词 | 6 源并发(S2/Crossref/OpenAlex/arXiv/PubMed/alphaXiv,S2 match 3s 快路径优先) | 单源失败 warn 降级;任一源应答即返回 | 全源失败且含 429 → 报 rate limited(#524 不再误报无结果) |
| 用户输入 arXiv id | Translator /web (canonical abs URL) |
arXiv 链:Atom → S2 → alphaXiv(错峰投机并发) | 链整体限流 → 2s 重试一趟 → rate_limited |
| 用户输入 DOI | Translator /search |
DOI 链:Crossref → S2 → OpenAlex(错峰投机并发) | 同上 |
| 用户输入 PMID | Translator /search |
PubMed 链:efetch |
同上 |
| 用户输入 URL | Translator /web |
- | 无 |
| PDF 识别出 DOI | Translator | DOI 链(Crossref→S2→OpenAlex) | 本地 title fallback |
| PDF 识别出 arXiv | arXiv 链(Atom→S2→alphaXiv) | - | 本地 title fallback;链整体限流 → arxiv_rate_limited 警告 |
| 在线参考文献 | S2 references | Crossref reference[] |
本地 TeX/.bbl |
| 反向引用 | S2 citations | 无 | 无 |
| 补全 publication | arXiv journal_ref / S2 publicationVenue |
S2 DOI:{doi} → Crossref container-title |
S2 title search |
| 下载 PDF | arXiv 直连 | arXiv export / Unpaywall / Crossref link | 无 PDF |
| 下载 TeX | arXiv e-print | - | PDF only |