论文标题相似度去重 Demo
Agent元数据进阶
论文标题相似度去重 Demo
基于标题相似度将重复文献分组,选择最权威版本作为主记录(不保证能完整聚合 preprint 与正式版)
用户场景
科研 Agent 在检索时常遇到同一篇论文的 preprint(arXiv)、正式发表版(Nature/Science)、以及 PDF/Web 多来源副本。需要将它们聚合为一条 canonical 记录,避免重复引用。
预估调用量
~10–20 次 API 调用 / 一次去重任务
适用工具
agentic-searchmeta-searchcontent调用链路
agentic-search→ 候选文献列表→ meta-search 按 DOI/标题聚合→ 去重合并→ canonical pack
输入示例
Agent 检索“Attention Is All You Need”相关文献,返回了 arXiv 预印本、NeurIPS 正式版、以及多个 PDF 镜像。 需要合并为一条记录,保留最权威版本的元数据。
输出示例
{
"canonical": {
"title": "Attention Is All You Need",
"doi": "10.5555/3295222.3295349",
"venue": "NeurIPS 2017",
"versions": [
{"source": "arxiv", "doc_id": "arxiv_1706.03762"},
{"source": "neurips", "doc_id": "nips_2017_xxx"},
{"source": "pdf_mirror", "doc_id": "pdf_att_yyy"}
],
"primary_doc_id": "nips_2017_xxx"
}
}Agent Prompt 示例
你是一个论文去重 Agent。当收到一组检索结果时:
1. 按标题相似度和 DOI 分组
2. 对每组调用 meta-search 确认正式发表版本
3. 选择最权威版本作为 primary_doc_id
4. 输出 canonical evidence pack分步实现
Step 1: 环境准备
安装依赖并配置 API Token
!pip install httpx
import os
os.environ["SCIVERSE_API_TOKEN"] = "sv-your-token-here" # 替换为你的真实值
Step 2: 语义检索候选文献
用 agentic-search 获取与某主题相关的所有片段
import os
import asyncio
import httpx
from collections import defaultdict
BASE = "https://api.sciverse.space"
TOKEN = os.environ["SCIVERSE_API_TOKEN"]
HEADERS = {"Authorization": f"Bearer {TOKEN}"}
async def search_candidates(query: str, top_k: int = 50):
async with httpx.AsyncClient(timeout=30) as client:
resp = await client.post(
f"{BASE}/agentic-search", headers=HEADERS,
json={"query": query, "top_k": top_k}
)
resp.raise_for_status()
return (resp.json().get("hits") or [])
hits = await search_candidates("Attention Is All You Need transformer")
print(f"Raw hits: {len(hits)}")
Step 3: 按标题相似度聚合
将同一篇论文的不同版本分组
from difflib import SequenceMatcher
def title_similarity(a: str, b: str) -> float:
return SequenceMatcher(None, a.lower(), b.lower()).ratio()
def cluster_by_title(hits, threshold=0.85):
clusters = []
used = set()
for i, h in enumerate(hits):
if i in used:
continue
group = [h]
used.add(i)
for j in range(i + 1, len(hits)):
if j in used:
continue
if title_similarity(h["title"], hits[j]["title"]) >= threshold:
group.append(hits[j])
used.add(j)
clusters.append(group)
return clusters
clusters = cluster_by_title(hits)
print(f"Clustered into {len(clusters)} unique papers")
for c in clusters[:3]:
print(f" [{len(c)} versions] {c[0]['title'][:60]}")
Step 4: 确认正式版本并生成 canonical pack
用 meta-search 查询 DOI 信息,选择最权威版本
async def find_primary(cluster):
"""\u4ece\u4e00\u7ec4\u7248\u672c\u4e2d\u627e\u5230\u6700\u6743\u5a01\u7684\u6b63\u5f0f\u53d1\u8868\u7248"""
# \u4f18\u5148\u7ea7: \u6709 DOI > \u6709 venue > arXiv
best = cluster[0]
for item in cluster:
# \u7528 meta-search \u67e5\u8be2\u66f4\u591a\u5143\u6570\u636e
async with httpx.AsyncClient(timeout=30) as client:
resp = await client.post(
f"{BASE}/meta-search", headers=HEADERS,
json={
"query": item["title"],
"filters": [],
"page": 1, "page_size": 1
}
)
if resp.status_code == 200:
results = resp.json().get("results", [])
if results and results[0].get("doi"):
best = item
break
return {
"title": best["title"],
"primary_doc_id": best["doc_id"],
"versions": [{"doc_id": v["doc_id"], "title": v["title"]} for v in cluster]
}
async def build_canonical_pack(clusters):
pack = []
for cluster in clusters[:10]:
canonical = await find_primary(cluster)
pack.append(canonical)
return pack
pack = await build_canonical_pack(clusters)
print(f"Canonical pack: {len(pack)} unique papers")
注意事项
- 标题相似度阈值 0.85 适合大多数场景,可根据领域调整
- 对于有 DOI 的论文,可直接用 DOI 做精确去重
- 建议保留所有版本的 doc_id,以便后续读取不同版本的全文
- canonical pack 可作为下游 RAG/Agent 的标准输入
FAQ
为什么需要论文去重?
同一论文可能存在预印本、正式发表版或重复元数据,需要聚合后再引用。
主记录如何选择?
优先 DOI、正式期刊版本、年份、引用数和元数据完整度。
去重会影响引用吗?
会,建议引用主记录,同时保留其他版本作为关联记录。
如何处理标题相似但不是同一篇?
需要结合 DOI、作者、年份、摘要和 venue 判断,不能只靠标题相似度。
下一步
还没有 API Key?
登录控制台「密钥」即可创建。同一套 API Key 可用于已开通的 Sciverse、点石与 Skills 能力,提供基础试用额度,具体以账号权限为准。