搜索

搜索是 多范式、可插拔 的:输入一个标准 Search Entry,引擎并发地询问多个 搜索提供方(provider),归并去重后返回论文 ID 列表。

内置 Provider

Provider

数据来源

catalog

QuantumAtlas 自有数据库(标题 / 作者 / 标识匹配)

arxiv

arXiv 官方 API

openalex

OpenAlex 学术图谱

语义向量检索不在内置 provider 之列:它由独立的 qatlas-rag 微服务提供, 经 qatlas-search 接入(见下文「Agentic 搜索」一节)。

渠道原理与用量限制

各渠道的接入方式与上游限制如下。引擎层面另有统一约束:每个 provider 调用超时 15 秒,max_results 默认 10、上限 50;单个渠道失败只记入 响应的 errors,不影响其他渠道的结果。

  • catalog:本地 PostgreSQL 论文注册表(需 QATLAS_POSTGRES_DSN)。 DOI / arXiv ID 精确命中(评分 1.0),否则按标题分词 ILIKE 匹配 (评分 0.5,按时间倒序)。纯内部 SQL 查询,无外部配额。

  • arxiv:arXiv 官方 Atom API(export.arxiv.org/api/query),无需 API key。查询优先级:id_list``(arXiv ID 直达)> ``doi:"…" > ti:"…" > 全文 all:。arXiv 对匿名客户端限流激进,qatlasd 以 固定 UA 标识自己;搜索调用单次超时 10 秒、不自动重试(被限流时记为 该渠道失败)。论文抓取(非搜索路径)另有独立的令牌桶限流: arxiv_fetch_rps 默认 0.33(约每 3 秒一次,遵循 arXiv 官方建议)、 burst 2、最多重试 3 次并遵守上游 Retry-After

  • openalex:OpenAlex works API(api.openalex.org/works),无需 API key。DOI 查询走 filter=doi:,其余走 search=,单页至多 25 条。配置 paper_access.openalex_mailto``(``QATLAS_OPENALEX_MAILTO) 后进入 polite pool——每 IP 约 10 req/s,远稳于匿名池,生产环境建议 必配。仅含 arXiv ID 的条目在 OpenAlex 无对应查询方式,直接返回空。

agentic 搜索另有一套服务端计量:按用户统计调用次数与 LLM tokens, 每日限额默认 10000 次,超限返回 429,详见下文「Agentic 搜索」一节。

Search Entry 格式

{
  "text":             "自由文本查询",
  "title":            "论文标题(精确或片段)",
  "doi":              "10.xxxx/xxxxx",
  "arxiv_id":         "quant-ph/0001001 或 2401.12345",
  "max_results":      10,
  "required_phrases": ["必须出现的短语"]
}

text / title / arxiv_id / doi 至少要有一个——全空时 POST /api/search/api/search/agentic 都直接返回 400,不再发出 空查询。仅带 arxiv_id / doi 的条目会把身份透传给 qatlas-search 微服务做精确查询(arXiv id_list、OpenAlex DOI filter、Semantic Scholar paper 端点)。

结果归并

归并优先级:DOI > arXiv ID > 标题

  • 带权威身份(DOI / arXiv ID)的命中进入 results,并触发惰性收录 (见 论文编号体系 与响应中的 created 字段);

  • 仅标题匹配的命中进入 candidates,仅供参考,不入库。

调用示例见 API 参考

Agentic 搜索(独立微服务)

除内置 provider 外,QuantumAtlas 还支持 agentic 搜索:由独立仓库 qatlas-search (私有)提供的 搜索微服务,在服务端做多源检索(arXiv / OpenAlex / Semantic Scholar / Crossref / PubMed / Europe PMC / DBLP / DOAJ / OpenAIRE / catalog,以及需 个人或服务端 API key 的 CORE / NASA ADS / Springer / IEEE Xplore / Scopus 和网页引擎 Wikipedia / SearXNG / Tavily / Exa / Serper / Brave / Kagi), 并可选用 LLM 对结果生成一段学术总结。 其中本地语义检索由另一个独立微服务 qatlas-rag 提供(GPU 上的 bge-m3 稠密 + 稀疏混合检索,RRF 融合后重排):qatlas-search 把它作为 fan-out 的一个 backend 调用,qatlasd 在论文收录或转换完成时向 qatlas-rag 推送 索引构建任务。

  • 网页:搜索页打开「agentic 搜索」开关(微服务未上线时开关禁用); 结果上方显示 agent 总结,右上角显示「今日用量 x/限额」。

  • CLI:安装插件包后 qatlas search "query" 自动可用(entry-point 发现,无需改主仓库配置);--direct 本地自带 key 直跑,survey 规则化综述、multi 逐平台原始结果——详细用法与标志表见 命令行(qatlas CLI) 的「论文搜索(qatlas search)」一节;安装 qatlas-rag 包后 qatlas rag "query" 可直接查询语义检索服务;两个插件未安装时都会 提示安装方法。

  • APIPOST /api/search/agentic,body 为 Search Entry(可选 sources 指定 backend 列表),响应在普通搜索的 results/candidates 之上增加 conclusionusage

用量与限额:agentic 搜索按用户计量(次数 + LLM tokens),每日限额默认 10000 次,超限返回 429。限额按 用户自定义上限 → 所属套餐(free/pro/max)→ 服务端默认 解析。管理员可在网页管理后台查看每用户用量(含按单价换算的 cost)、编辑套餐限额、为单个用户指定套餐或自定义上限。日期按 UTC 日界。

微服务由管理员配置,终端用户通过 qatlasd 代理访问并计量; 使用入口见 Web 界面API 参考

逐平台搜索与个人 API keys

关闭「agentic 搜索」时,搜索走 multi 模式:qatlasd 把查询代理给 qatlas-search(POST /api/search/multi),每个被选中的 backend 返回 自己的**原始**命中列表(保持该平台自身排序,不做跨源合并与融合评分), 前端用 Tab 按平台分开展示,失败的平台在该 Tab 内显示错误。

  • 后端选择:搜索页提供按「学术源 / 网页引擎」分组的复选框 (GET /api/search/backends 提供 catalog:静态表 + 微服务实时可用性 + 当前用户已配置的 key)。需要 key 但未配置的后端复选框禁用,并给出 指向 dashboard 的「去配置」链接;选择持久化在浏览器 localStorage。

  • 个人 API keys:dashboard 的「搜索 API keys」面板可为支持个人 key 的 backend(Semantic Scholar / OpenAlex / PubMed 加速 key,以及 CORE / NASA ADS / Springer / IEEE / Scopus / Tavily / Exa / Serper / Brave / Kagi 等必填 key)保存自己的密钥。key 以 AES-256-GCM 加密存储在 PocketBase(加密密钥由服务端 system PAT 派生,无额外配置项),列表只 显示末四位掩码;搜索时代理解密注入,qatlas-search 不持久化任何请求级 key。服务端 YAML 里的同名 key 仍作为兜底(优先级:用户 key > 服务端)。

  • APIPOST /api/search/multi (papers:read scope),请求体 含 text / max_results / sources,响应按 backend 分组返回原始命中 列表;key 的 CRUD 在 GET/PUT/DELETE /api/me/search-keys (仅 浏览器会话)。完整请求/响应格式见 api

Robust Downloader(多范式下载入库)

Robust Downloader 页面(/$lang/downloader,侧边栏入口)把一批论文 标识(DOI / arXiv id / 论文链接,每行一条,单次最多 50 条)提交给服务端的 多范式下载模块(internal/downloader,注册为第三个 builtin 插件 downloader):

POST /api/downloader/fetch        {"items": ["10.1038/...", "arXiv:2401.12345"]}
GET  /api/downloader/jobs         本地进度与持久化待执行请求快照
GET  /api/downloader/remote-jobs  持久化远程任务进度

下载 local-first(本地优先):先尝试服务器自身网络可用的下载策略; 启用 outbound worker fleet 后,本地受挑战阻断或策略耗尽时才委托远程任务。 挑战触发的委托可先于本地 browser / agent 兜底,不是每篇论文都发往远程。 远程等待释放本地下载槽位;不同论文可并行,同一论文按有限尝试次数与 截止时间依次换 worker,不向所有节点无限广播。详见下文「Outbound workers」。

本地策略阶梯(逐层尝试,全部候选先过统一验证管线——%PDF- 魔数、 %%EOF 尾部、大小上下限、bot 墙/付费墙/错误页分类):

  1. arxiv — arXiv 直下(版本固定、全局限速);

  2. twin-resolve — OpenAlex 把 DOI 解析到 arXiv 孪生预印本后走 1;

  3. oa-apis — Europe PMC(含绕过 PMC PoW 的 ?pdf=render)、 Unpaywall、OpenAlex、Semantic Scholar 的 OA PDF 直链;仓库**落地页** (HAL、高校机构库等)会被继续挖掘出真实 PDF 链接(绿色 OA);

  4. pattern — 出版社 URL 构造表(Springer/Wiley/T&F/Sage/ACS/ACM/ Frontiers/PLOS/eLife/bioRxiv,按 DOI 前缀);

  5. landing — doi.org 落地页 citation_pdf_url 挖掘(IEEE 文档页 额外解析 stamp.jsp 中间页);

  6. agent(兜底,默认关)——LLM 阅读落地页 HTML 提取候选链接。配置 项 downloader.agent.backend 设为 openai (OpenAI 兼容端点) 或 claude (本机 headless claude CLI)。

成功的 PDF 带溯源元数据(downloader:<策略>、来源 URL、sha256)写入 对象存储并登记资产;MinerU 转换属于后续处理,PDF 已归档不等于转换已完成。 本地策略轨迹记录在任务快照与 paper_acquisition_events 审计表, 远程任务另有持久化进度。抓取带 cookie jar、浏览器式请求头、按主机限速; downloader.respect_robots 默认关闭,运维人员仍须确认下载权限及站点条款。

诊断工具qatlasd downloader probe 支持位置参数(DOI/arXiv)、 --random N`(OpenAlex 随机抽样)、:code:--search`(领域过滤), 输出本地下载阶梯的逐篇结果与失败分类,任一失败退出码为 1。 它 不测试新的 outbound fleet--proxy 仅测试 LEGACY 代理。 新 fleet 应通过服务器 Web 界面 / API 参考 提交并观察持久化进度, 管理员同时检查节点状态(见 管理后台)。失败可能来自网络、权限、 超时或服务故障,不能一概视为权限终态;有权获取但自动下载失败的论文 可人工下载后经 /api/papers/{id}/upload-pdf 上传。配置 downloader.s2_api_key 可改善 Semantic Scholar OA 候选查询的稳定性。

本地 agentic 后端(claude CLI)

除远程微服务外,agentic 搜索还可以切换为 本地后端:qatlasd 进程内调用 本机已登录的 claude CLI(headless claude -p)对引擎 fan-out 的原始命中做精炼/去重/排序,并产出学术总结。 两种后端走同一端点、同一响应形状(results/candidates/conclusion/ usage/errors),由配置切换:

search:
  agentic:
    backend: local        # 默认 remote(qatlas-search 微服务)
    local:
      claude_bin: claude  # 需在本机完成 OAuth 登录
      model: ""           # 空 = claude 默认模型
      sandbox_dir: ""     # 空 = <paths.data_dir>/agentic
      timeout: 5m         # 单次 claude 调用超时
      retention: 24h      # 沙箱审计保留时长
      max_budget_usd: 0   # 0 = 不传 --max-budget-usd
      prompt_template: "" # 空 = 内嵌模板

沙箱机制:每个请求在 sandbox_dir 下建一个独立目录 (<时间戳>-<随机后缀>/),写入 query.json``(规范化后的查询)、 ``results.json``(fan-out 原始命中)、``prompt.txt``(渲染后的 prompt)、 ``run/``(claude 的工作目录,唯一可写区)、``response.json``(标准化输出) ``meta.json``(耗时/exit code/token 用量/错误)。后台 janitor 每分钟 清扫超过 ``retention 的沙箱,启动时先兜底清扫一次崩溃残留。沙箱是 文件系统级隔离(cwd + 工具白名单 Read/Write/Glob/Grep),不是容器级隔离。

agent: false 的请求同样可用:本地后端只做引擎 fan-out,不调 claude, conclusion 为 null、errors 携带各 provider 失败表,响应形状与 agent: true 完全一致。

Outbound workers(主动连接的下载节点)

协调器内置于 qatlasd。管理员可批准多台 downloaderworker,每台使用 自己的网络出口与浏览器环境 获取其有权访问的论文;worker 使用共享 下载策略,但不递归委托其他 worker / proxy,也不启用 agent 执行。 worker 主动通过 HTTPS 注册、发心跳、领取租约、上传 PDF 并查询收据; 服务器 不拨入 worker,无需开放 worker 或 CDP 入站端口。

管理员启用 downloader.remote.enabled,并配置 PostgreSQL 与对象存储后, 已接收请求和远程任务进入持久化队列。全局容量、单节点容量、尝试次数与 任务 / worker 截止时间共同限制并发和故障转移。单篇失败可换尚未尝试的 worker,直到成功或预算耗尽;无效标识、取消等终态不会无限重试。 每台 worker 需要独立持久化卷,保存身份、临时 PDF 与恢复状态;不要复制 身份给并行节点。注册与人工审批步骤见 管理后台

归档与删除顺序:

  1. worker 下载、校验并持久化本地 PDF,再主动上传;

  2. qatlasd 将上传流写入有配额的暂存区,独立校验大小、SHA-256、PDF 头尾;

  3. 对象存储写入与 registry 资产登记都成功 后,生成持久化 done 收据;

  4. worker 核对收据的 task ID、attempt ID、SHA-256 与大小后删除已确认副本。

HTTP 成功或 staged (归档中)本身都不是归档确认。上传响应丢失时, worker 可重复查询非破坏性收据或重试传输,不因不确定响应立即删除文件。 临时结果仍有保留期限(worker 默认从 ready 起 24 小时),到期可清理并报告 失败;不能保证服务器长期不可用时仍完成归档。磁盘 / 配额不足会暂停新任务, 不以驱逐未过期结果腾空间。

MinerU 与索引通过归档后的持久化 outbox 重试,不阻塞 done 收据; PDF 归档完成不表示 Markdown 已完成,转换进度需另外查看。 GET /api/downloader/remote-jobs 提供重启后仍可查询的远程任务, GET /api/downloader/jobs 在本地进度之外合并最多 512 条持久化待执行请求, 包含等待本地槽位的请求。远程快照最多 500 条;两者都不是完整分页历史。 具体权限和状态见 API 参考

浏览器不是完整的网络安全沙箱。每台 worker / browser 应隔离运行并限制 出站访问,阻止访问宿主机服务、内部敏感网络和云元数据;勿用 host networking、 挂载宿主服务 socket 或公开 CDP。节点审批并不赋予额外的出版社访问权。

LEGACY Downloader Proxy

downloaderproxyLEGACY:qatlasd 主动访问代理的 POST /v1/jobsGET /v1/jobs/{id}GET /v1/files/{token}, 以共享 Bearer token 认证。旧配置 downloader.proxy.url / token / timeout命令行(qatlas CLI)--proxy / --proxy-token 只属于该协议, 不是 outbound worker 的注册方式,也没有新协议的持久化 done 收据保证。 downloader.remote.enabled: true 与非空旧 downloader.proxy.url 不能同时配置;实现拒绝混用,不会自动迁移现有部署。

浏览器 lane(真实 Chromium 兜底)

当出版社的 bot 墙(Cloudflare / IEEE AWS WAF)挡住所有 plain-HTTP 策略时,downloader 会通过 CDP 驱动一个真实 Chromium 浏览器——事件驱 动挖掘落地页链接(citation_pdf_url / 内联 JSON pdfUrl / IEEE stamp 中间页),被动捕获 PDF 响应,并以人类节奏(1.5–3s 随机间隔)运行。

本地启用 (qatlasd 所在机器跑一个 Chromium):

downloader:
  browser:
    cdp_url: http://127.0.0.1:9222   # Chromium --remote-debugging-port
    timeout: 45s

outbound downloaderworker 容器由自身 runner 管理 Chromium,使用该 worker 的网络环境;外部 CDP 仅限受信任且隔离的私有端点。 LEGACY downloaderproxy 容器也自带 Chromium,但使用旧代理协议。

人工补救通道

所有自动下载失败的论文在管理后台的「下载失败列表」中列出, 提供两个操作:

  1. DOI 链接:点击直达出版社页面人工下载 PDF;

  2. 上传 PDF:选本地文件 → 自动配对 DOI → 走贡献通道入库 (OpenAlex 元数据校验 + resolve-or-mint + 触发 MinerU 转换)。

对应的 CLI 命令为 qatlas contrib pdf <id> --pdf file.pdf

Admin 资产浏览

管理员可在 /zh/admin/assets 搜索、预览、下载论文的 PDF 与 Markdown,并生成预签名 S3 URL。详见 管理后台