论文标题相似度去重 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 能力,提供基础试用额度,具体以账号权限为准。

前往控制台