文献检索 本节摘要:假设廉价;知道是否有人已证明它才是贵的部分。在运行器起沙盒前构建回答这个问题的检索层。关键词搜摘要返与查询共享词汇的论文,覆盖了大部分表面,但漏两种情况:奠基论文用不同词汇(查「稀疏注意力」漏了标题「transformer 路由中的块选择」)、相关论文是引已知锚点的后续(找锚点向前走比暴扫摘要池高效)。本节建两遍:仅用 stdlib 数据结构在摘要上建 BM25 索引抓词法命中,引用图遍历从种子集前后扩一两跳。两者按论文 id 去重合并,按小组合分排序。把两个 mock 外部 API 藏在单一客户端后,使上游调用点在真实端点落地时不变。 对应原课程:Phase 19 · Lesson 51 · (原英文 )。本节属「AI Scientist」赛道第二节。
本节摘要:假设廉价;知道是否有人已证明它才是贵的部分。在运行器起沙盒前构建回答这个问题的检索层。关键词搜摘要返与查询共享词汇的论文,覆盖了大部分表面,但漏两种情况:奠基论文用不同词汇(查「稀疏注意力」漏了标题「transformer 路由中的块选择」)、相关论文是引已知锚点的后续(找锚点向前走比暴扫摘要池高效)。本节建两遍:仅用 stdlib 数据结构在摘要上建 BM25 索引抓词法命中,引用图遍历从种子集前后扩一两跳。两者按论文 id 去重合并,按小组合分排序。把两个 mock 外部 API 藏在单一客户端后,使上游调用点在真实端点落地时不变。
对应原课程:Phase 19 · Lesson 51 ·
literature-retrieval(原英文phases/19-capstone-projects/51-literature-retrieval/docs/en.md)。本节属「AI Scientist」赛道第二节。
阅读完本节,你应当能够:
关键词搜摘要返与查询共享词汇的论文,覆盖大部分表面。它漏两种情况。第一,奠基论文用不同词汇——查「稀疏注意力」漏了标题「transformer 路由中的块选择」的论文。第二,相关论文是引已知锚点的后续——找锚点向前走比暴扫摘要池高效。
检索客户端拥有两遍与合并。调用方递查询,得排好序列表,每条带每论文分字段(bm25_score/graph_distance/recency_score/final_score)解释排序。
Paper id : str (稳定标识, mock 语料用 "p001") title : str abstract : str year : int authors : list[str] references : list[str] (此论文引的论文 id) citations : list[str] (引此论文的论文 id) source : str (哪个 mock api 供的, "arxiv" 或 "s2")
references 与 citations 构成有向引用图。两 mock API 返重叠但不同的字段,语料加载器在 id 上并。
实现是标准 Okapi BM25,默认参数 k1=1.5、b=0.75。索引是两个字典:term -> doc_frequency 与 term -> list of (doc_id, term_count)。文档长是摘要 token 数,平均文档长在索引建时算一次。打分查询是查询词项的 idf * tf_norm 之和,tf_norm 是标准 BM25 长度归一项频。分词是 lower 后按非字母数字切,无词干还原(生产换小词干还原器,接口不变)。
idf(t) = log((N - df + 0.5) / (df + 0.5) + 1.0) tf_norm(t) = (f * (k1 + 1)) / (f + k1 * (1 - b + b * dl / avgdl)) score(d, q) = sum over t in q of idf(t) * tf_norm(t)
图从语料建一次。前向边从论文到其 references,后向边从论文到其 citations。遍历是以 BM25 top 命中为种子的广度优先搜索,封顶两跳。两跳是刻意上限:一跳太浅(代理常要直接祖或后裔);三跳在连通图上炸结果规模、易跑题。hop 上限作配置旋钮暴露。
两遍返重叠集。合并按论文 id 键。每论文终分是加权混合:
final_score = w_bm25 * bm25_score_norm + w_graph * graph_score + w_recency * recency_score
bm25_score_norm 是 BM25 分除以合并集最大 BM25 分(使字段落零到一)。graph_score 直接词法命中一、一跳 0.6、两跳 0.3、否则零。recency_score 是从语料最小年到最大年的线性斜坡。默认权重 0.5/0.3/0.2,作配置;陈题调低 recency,快题调高。
语料是 build_corpus() 生成的百篇论文,每篇手写标题与摘要,覆盖五主题:注意力稀疏、检索增强、低秩适配器、数据集蒸馏、评估框架。references 与 citations 接线使每主题成连通子图、带几条跨主题边。两 mock API 客户端(ArxivMockClient、SemanticScholarMockClient)读同语料但暴露不同字段:Arxiv 返 title/abstract/year/authors,Semantic Scholar 加 references/citations。检索客户端在 id 上并。
code/main.py 定义 Paper、ArxivMockClient、SemanticScholarMockClient、BM25Index、CitationGraph、RetrievalClient 与确定性 demo。BM25 实现一类约 60 行,图遍历一方法。code/tests/test_retrieval.py 覆盖词法路径、图路径、合并、去重、空查询。
设计要点:检索客户端返
RetrievalResult含排好序列表与每查询指标(命中数、均分、top 分、总墙时间),运行器日志这些使下游可观测遍能绘质量随时间。第 52 节运行器读paper.id、paper.title与摘要前三句作实验上下文;第 53 节评估器读paper.year与paper.references把基线归到具体论文。检索客户端是四阶段中最廉的,在编排器中最先跑。
真实学术检索用 Semantic Scholar API、arXiv API、Google Scholar(无官方 API,需爬)。BM25 是经典(1994,Elasticsearch/Lucene 默认),生产常配 dense 检索(FAISS + 句嵌入)做混合检索——词法抓精确匹配,dense 抓语义相关。引用图遍历是 Connected Papers、ResearchGate、Inciteful 的核心。本节手写让你看清 BM25 的 idf * tf_norm、图遍历的 BFS hop、混合排序的加权。换真 API 只需 mock 客户端替成 HTTP 调用,接口不变。RAG 系统(第 64~69 节)的检索层用同模式,只是语料是文档而非论文。
code/main.py + code/tests/test_retrieval.py。RetrievalClient.search(query) -> RetrievalResult 是编排器入口,产排好序列表供第 50/51 节消费。BM25Index、CitationGraph 可独立复用——任何「词法 + 图」混合检索场景。换真 API(Semantic Scholar/arXiv HTTP),只需替两 mock 客户端,检索客户端与排序逻辑不动。
ArxivMockClient 换成真 arXiv API(免费、无需 key),对真实查询跑检索。w_recency,对陈题(如 SVM)调低,观察排序变化。idf * tf_norm,纯 stdlib 两字典索引,默认 k1=1.5/b=0.75。bm25_norm/graph/recency 三分,权重作配置。下一节,我们做「实验运行器」——把实验编成类型化 spec,在沙盒子进程里执行,发评估器可信任的 json 指标 blob。