zcbot/skills/research/SKILL.md

4.6 KiB

name description
research 查 paper_server 文献库(基于 OpenAlex 元数据 + Sci-Hub 下载的内部部署)。用户要查文献、找 DOI、拉 PDF、做文献综述、写带引文的申报书 / 研究方案 / 调研报告时使用。

Research

paper_server 是内部部署的 Django 文献库:元数据来自 OpenAlex,PDF 由 Sci-Hub 异步抓取。本 skill 给你三个 helper(search / get_paper / fetch_pdf),用 run_python 调用,不要自己 httpx 裸调 API。

何时用

  • 用户要查 / 找 / 看 / 推荐文献
  • 要 DOI、要某篇 PDF、要 abstract
  • 写申报书 / 研究方案 / 调研报告的"国内外现状"段需要真实文献支撑
  • 配合 proposal skill 的「立项依据」起草 —— 先 search 拿候选,get_paper 看 abstract 决定要不要引

何时不用

  • 用户只问通识(直接答即可,不需要文献支撑)
  • 用户已经给了具体文献清单(直接用,不要二次校验)
  • paper_server 没覆盖的领域(本库主打中文工程 / 材料 / 土木 / 化学;前沿 AI / 数学 / 纯理论 paper 命中率低 —— 命中 0 条直接告诉用户,不要瞎编)

准备

from skills.research.paper import search, get_paper, fetch_pdf

(import 路径由 run_python 注入的 PYTHONPATH 提供,直接写就行,不必折腾 sys.path)

三个函数

search(keyword="", year=None, doi="", has_pdf=None, limit=10) -> list[dict]

搜文献,返回精简列表(每条只含 id / doi / title / first_author / publication_year / publication_name / has_fulltext_pdf / has_abstract / type)。

  • keyword: paper_server 的 search 字段,匹配 title / first_author / first_author_institution
  • year: 精确年份(目前只支持 exact)
  • doi: 精确 DOI(命中 0 / 1 条)
  • has_pdf=True 仅返已下好 PDF 的;False 仅返没 PDF 的;None 都返
  • limit: 默认 10,上限 50
# 找最近 5 篇关于"水泥水化"且已下好 PDF 的
papers = search(keyword="水泥水化", has_pdf=True, limit=5)
for p in papers:
    print(p["title"], p["doi"], p["publication_year"])

get_paper(id_or_doi) -> dict

取单条完整 metadata + abstract。id_or_doi 既接受 paper_server 内部 id,也接受 DOI(自动解析)。

paper = get_paper("10.1016/j.cemconres.2020.106156")
print(paper["title"])
print(paper["abstract"])  # 没 abstract 时是空串,不会抛

fetch_pdf(id_or_doi, working_dir) -> str

下载 PDF 到 <working_dir>/papers/<safe_doi>.pdf,返回相对路径 papers/<safe_doi>.pdf(safe_doi 把 / 换成 _)。已存在跳过下载直接复用。

rel = fetch_pdf("10.1016/j.cemconres.2020.106156", working_dir=r"D:/projects/zcbot/workspace/users/<uid>/<wd>")
# rel == "papers/10.1016_j.cemconres.2020.106156.pdf"

has_fulltext_pdf=False 时抛 RuntimeError —— 这时该 paper 服务器侧还没下到 PDF,告诉用户不要硬等。

标准工作流

  1. search:按关键词 / 年份缩窄候选(limit=10 起,不够再扩)
  2. 筛选:扫返回列表,挑相关的(看 title + first_author + year),has_fulltext_pdf=True 的优先
  3. get_paper:对每篇候选拿 abstract,确认确实切题再继续
  4. fetch_pdf:确定要全文细读时才下载(用户没说要全文就别下,abstract 已足够覆盖大多数引用场景)
  5. read PDF:fetch_pdf 返回相对路径,用主 agent 的 read 工具读 PDF 提取关键段(zcbot 已内置 PDF 文本提取)

错误处理

  • 网络超时 / paper_server 不可达:httpx.ConnectError / httpx.TimeoutException —— 直接告诉用户"paper_server 暂时连不上",不要重试堆栈刷屏
  • doi 未命中 / doi 命中多条:get_paper / fetch_pdf 内部 _resolve_to_idValueError —— DOI 拼写错或库里真没收录,改 keyword 重搜
  • has_fulltext_pdf=False:fetch_pdfRuntimeError(reason=...) —— 服务器还没下到 PDF;告诉用户"这篇 paper_server 还没下到 PDF,可读 abstract 或换一篇"
  • abstract 字段为空字符串:正常情况,不是错;告诉用户"这篇没收录摘要"即可

反模式

  • httpx / requests 裸调 paper_server API(走 helper,免得 base_url / auth / 字段名漂移时四处改)
  • search(limit=50) 一次拉满后扔给 LLM 全文 dump(只 print 前 5-10 条精简就够,要全部让用户自己 print(papers))
  • 没看 abstract 就 fetch_pdf(80% 场景 abstract 够用,下载 PDF 慢且费带宽)
  • 编造 DOI / title / 作者 —— 不在 paper_server 库里就明确告诉用户"未命中",不要凭训练数据脑补
  • fetch_pdf 返回的相对路径当绝对路径用(它是相对 working_dir 的)