具身智能论文检索工作台:从arXiv数据到FTS5搜索实践
1. 为什么我会给具身智能单独做一个论文检索小网页先说一个很实际的场景。我自己做具身智能方向的研究日常有两类检索需求躲不掉一类是盯 arXiv 上每天的新论文看看有没有人发了新的操作策略、新的世界模型或者新的 sim-to-real 思路另一类是回查某个具体问题比如抓取姿态估计有哪些近三年的工作VLA 模型在真实机器人上的部署效果需要把相关文献快速拉出来对比。用通用搜索引擎去查体验其实挺割裂的。Google Scholar 覆盖面广但排序偏引用量新论文会被老经典压得很死arXiv 原生搜索倒是及时但必须限定在 cs.RO 或者 cs.AI 分类里反复试关键词而且具身智能embodied intelligenceembodied AI这几个说法在论文标题和摘要里的分布非常不均匀漏检率很高。更麻烦的是这个领域本身是交叉的很多工作挂在 CV、NLP、机器人学甚至神经科学分类下面靠一个分类号根本圈不全。我想要的其实是一个轻量的、只服务具身智能这个小方向的工作台打开网页输入一句话或者几个关键词能按时间、按子方向、按会议过滤每天自动把新论文抓进来点开能跳原文、能标记已读、能导出 BibTeX。这个需求用商业通用工具满足不了所以我自己花了一周多做了这个小网页跑了两三个月日常检索效率提升非常明显。如果你也在这个方向里不管是学生刚入坑还是已经在做具体课题这篇就把我踩过的坑和实现思路完整写出来。我不讲特别玄的东西全部是可复现的工程方案你照着搭一个也就一两天的事。2. 数据从哪来论文源的采集、清洗与去重2.1 主力数据源arXiv API 的增量抓取论文数据的主渠道我选了 arXiv 的官方 API没有用爬虫。原因很简单官方 API 有明确的调用规范返回的是结构化 XML字段干净而且支持按时间增量查询对一个小工具来说足够稳定。具体做法是每天凌晨跑一次定时任务用submissionDate字段去拿过去 24 小时内提交的论文。查询参数我会把几个分类都带上cat:cs.RO OR cat:cs.AI OR cat:cs.CV OR cat:cs.LG然后配合关键词过滤。这里有个关键点查询词不能只写embodied intelligence否则漏掉太多。我实际用的关键词字典分了三层第一层是核心词embodied intelligence、embodied AI、embodied agent第二层是技术词manipulation、grasping、locomotion、navigation、world model、vision-language-action第三层是关联词sim-to-real、affordance、dexterous hand、robot foundation model过滤逻辑是第一层出现任意一个或者第二层和第三层各出现任意一个这样能兼顾宽泛和精准。第一版我只用核心词结果一天只能抓到十几篇很多值得看的机器人物体交互工作直接漏了后来加了两层组合量上来不少噪声也还在可接受范围内。2.2 会议论文和中文资源的补充渠道arXiv 只覆盖预印本很多已经正式发表的工作有了期刊或会议版本标题可能改过citation 信息也更全。所以我又加了两类补充源一类是主流会议的程序册像 CoRL、ICRA、IROS、RSS 这些每年出录取列表之后手动整理一次。这部分我没做成全自动化因为会议官方 PDF 格式每年都在变写解析脚本的维护成本比手动整理还高。我现在是半自动把会议标题列表拷到一个表格里脚本去 arXiv API 里按标题近似匹配找预印本把Conference字段补上去。另一类是中文技术社区和公众号的综述文章。这个不是论文主体但我发现一个规律一篇高质量的综述往往会提前把某个子方向的发展脉络梳理清楚对理解一个陌生细分领域非常有用。我单独做了一个综述收藏的标签每周手动添加几篇和论文库分开展示。2.3 去重策略不要相信标题完全一致去重是这项目里第一个让我真正头疼的问题。arXiv 的abs接口返回的标题里有时会带换行、有时包含 LaTeX 的数学标记直接拿字符串比较根本不可靠。我的方案分两级。第一级是把标题做归一化转小写、去掉所有非字母数字符号、把 LaTeX 里的$...$部分整体剥离、连续空格压成一个然后用归一化后的字符串做哈希作为表里的唯一键。第二级是对那些改过名的会议版本标题可能从Learning to Pick变成Pick it Yourself: Learning to Pick with Self-Supervision这时候字符串匹配就失效了。我退而求其次用标题前六个词的 Jaccard 相似度做模糊匹配超过 0.7 就认为是同一篇人工确认后合并。这套规则跑下来的误杀率很低主要误杀场景是同一作者系列工作的标题开头经常撞车但概率不大人工盯一眼就行。2.4 数据表结构设计数据表我一开始设计得特别复杂什么作者拆分表、引用关系表、项目关联表全画进去了后来发现对一个单人维护的检索工具来说完全是过度设计。最终精简下来的表结构就是这样字段类型说明idTEXT唯一标识用 arXiv id 或自增哈希titleTEXT原始标题title_normalizedTEXT归一化后的标题用于去重authorsTEXT作者列表存 JSON 数组abstractTEXT摘要全文categoriesTEXTarXiv 分类列表keywords_flagsTEXT命中的关键词字典层级published_atDATE发布时间updated_atDATE最后更新时间venueTEXT会议/期刊名称可为空tagsTEXT用户自定义标签read_statusINTEGER0 未读 1 已读 2 稍后读作者不拆表是因为检索时几乎不太会按第二作者过滤按字符串包含就够用了。keywords_flags这个字段是我后来加的用处很大它记录这篇论文命中了关键词字典里的哪些词比如[manipulation, sim-to-real]这样前端可以按子方向做聚合筛选不用每次现算。3. 检索核心的实现从暴力搜索到可用的排序3.1 选型对比SQLite FTS5 够用不必上重型检索引擎第一版我想得很简单。数据量也就几万篇全量扫一遍也才几十毫秒直接LIKE %keyword%查不就行了结果第一版上线就发现两个问题一是多关键词组合查询时 SQL 变得非常长维护困难二是没有一个合理的相关度排序搜出来的结果是随机的按时间排又和关键词相关度没关系。后来换了方案。我没有上 Elasticsearch 或者 Meilisearch 这种服务理由很直接这是个单人维护的小网页我犯不上为它再维护一个 Java 或独立服务进程。SQLite 自带的 FTS5 全文索引完全够用支持 BM25 排序算法而且用法简单到令人发指CREATE VIRTUAL TABLE papers_fts USING fts5( title, abstract, categories, contentpapers, content_rowidrowid, tokenize unicode61 remove_diacritics 2 );这个unicode61分词器对英文论文场景是够的。但有个坑中文摘要和中文关键词如果用默认的 unicode61每个汉字会被当成一个独立的 token搜抓取会变成搜抓和取两个 token 的 AND 组合语义上经常出错。我的处理方式是把中文内容单独存一个字段不参与 FTS5 索引搜索时用普通INSTR做次级匹配。3.2 排序权重的调优标题命中比摘要命中值钱得多FTS5 自带的 BM25 排序可以用但默认参数对所有字段一视同仁。实际检索体验里标题里出现关键词和摘要里出现关键词的价值天差地别。我测试了 60 多组不同查询后发现标题命中的论文在用户觉得相关的比例上能高出 30% 以上。所以我自定义了排序公式用 BM25 分数做基础再叠加权重SELECT *, bm25(papers_fts, 8.0, 2.0, 1.0, 1.0) AS rank_score FROM papers_fts WHERE papers_fts MATCH ? ORDER BY rank_score * (1 1.5 * (title_hit_boost recent_boost)) DESC具体调的是标题权重给 8摘要给 2分类给 1。recent_boost是一个时间衰减因子最新 30 天的论文额外加 0.3 分防止旧论文因为引用多而长期霸榜。这个时间衰减很关键对具身智能这种日新月异的领域半年前的工作和最新的工作之间方法已经差了好几代。3.3 中英文混搜的处理方式具身智能这个方向有个特点中文资料和英文论文混着用。用户可能会输入具身智能 机器人操作也可能会输入embodied manipulation。我的做法是先检查查询串里是否包含 CJK 字符如果有先生成一个英文关键词映射表把具身智能映射成embodied intelligence OR embodied AI把抓取映射成grasping OR grasp等等再拿映射后的字符串去跑 FTS5。这个翻译映射表我维护在配置文件里大概一百多个词条覆盖了具身智能领域的常见术语。效果还算可以但坦白说做不到完美。比如灵巧操作这个词不同人翻译成dexterous manipulation或者fine manipulation我映射的时候干脆把两个都写上用 OR 连接宁可召回多一点。4. 前端交互设计的取舍轻量但必须有这三个功能4.1 为什么坚持单页无构建方案这个项目的技术栈我选得比较保守一个index.html一个app.js一个style.css全部手写没有用任何前端框架也没有构建步骤。理由有三层。第一论文检索页的核心是输入关键词 → 看结果列表 → 点进去读摘要这是一个极简的线性流程用 React 或者 Vue 带来的组件化收益非常有限。第二我不想在服务器上维护一个 Node 服务纯静态文件随便扔到任意 Web 服务器上就能跑就是零运维。第三这个页面我要的是快去掉打包压缩和框架运行时之后首屏加载就是几十个 KB输入查询的响应时间基本取决于后端查询速度体感非常好。最终数据交互用的是前后端分离的轻量方案后端是一个 Python 的 FastAPI 服务提供三个接口/api/search、/api/paper/{id}、/api/tags前端直接fetch调用。前端只管展示和交互逻辑全在后面这样后续如果想接 API 给其他脚本用也不费劲。4.2 结果列表的信息密度设计论文列表页的卡片设计我改了三版才满意。第一版照搬了 arXiv 的排版标题、作者、摘要全文信息全但太长一屏只能看两三篇。第二版压缩成一行一条信息太稀扫一眼根本判断不了这篇值不值得点开。最终版用的是中密度卡片每个卡片显示标题、发布时间、命中子方向和一句话摘要。摘要部分用 CSS 做了三行截断但重点是旁边的子方向标签——比如一篇论文的标签是操作 / sim-to-real我不用读摘要就知道这篇大概在做什么方向扫起来非常快。这个标签就是从数据表的keywords_flags字段直接映射出来的。4.3 必做的三个功能筛选、稍后读、BibTeX 导出第一个必做功能是复合筛选。左边一栏放子方向、年份、会议来源三个筛选器和搜索框是叠加关系搜索结果先按关键词匹配再按筛选条件过滤。这个交互模式我觉得比筛选即搜索更容易理解用户不会困惑为什么筛选之后结果少了。第二个必做功能是稍后读列表。具身智能领域有个显著特点好论文扎堆出现尤其 CVPR、CoRL 的接受列表公布那两周一天能冒出来二三十篇值得关注的工作。我那时候根本来不及细读就一键丢进稍后读等周末集中安排时间精读。这个功能做起来很简单一个read_status字段的事但对使用体验的提升是决定性的。第三个必做功能是导出 BibTeX。写论文的人都知道最后整理参考文献是体力活。我的方案是每次点开论文详情除了显示完整摘要、作者、分类还有一个复制 BibTeX按钮后端动态生成格式正确的条目。这个功能让我在写综述的时候省了大量复制粘贴手改的时间算是这个工具带来的最大红利之一。5. 部署方式与自动化维护的最佳实践5.1 Docker 化的整个后端部署我用了一个 Docker Compose 文件包含两个服务API 服务和定时任务。API 服务就是 FastAPI 加 uvicorn定时任务用同一个镜像跑 cron 脚本。你会发现我全程没有引入数据库容器因为 SQLite 就够用数据存在一个挂载的 volume 里备份就是复制一个文件。定时任务的调度逻辑是每天 UTC 凌晨 2 点跑一次增量抓取抓完后重新生成 FTS5 索引然后做一次去重合并。整套流程跑下来大约三到五分钟取决于当天的新论文数量。配置上有一个容易踩的坑arXiv API 对并发请求有限制官方文档要求对每个 IP 的请求间隔不小于 3 秒。我之前用requests并行抓结果被限流返回 403。正确的做法是串行请求加上重试机制重试用指数退避。5.2 核心代码结构三张表管住全部逻辑整个后端就是三个文件没有更多fetch_papers.py负责和 arXiv API 交互解析 XML写库search_api.pyFastAPI 应用实现搜索接口keywords.json关键词字典和翻译映射表# fetch_papers.py 中的核心增量逻辑 def fetch_new_submissions(date_from, date_to): base_query ( (cat:cs.RO OR cat:cs.AI OR cat:cs.CV OR cat:cs.LG) AND (submittedDate:[{from} TO {to}]) ) for start in range(0, total_results, 100): response arxiv_api_query(base_query, startstart, max_results100) for entry in response: paper parse_entry(entry) if should_include(paper, keywords_dict): insert_or_merge(paper) rebuild_fts_index()这段脚本在should_include里实现了第二节说的三层关键词匹配逻辑。这里有个细节我强调一下不是所有命中关键词的论文都值得进库。有些论文只是顺带提了一句我们的方法可以用于机器人操作本质工作是做 CV 的但它的标题和摘要里确实有manipulation。我的策略是记录它命中了第一层还是第二层/第三层如果只是第三层命中则在搜索结果里降权重而不是彻底排除——毕竟这种跨界的思路有时候反而是灵感来源。5.3 实际跑了两三个月后观察到的维护成本这个项目上线到现在真正的日常维护就两件事一是每周看一眼有没有抓取失败的论文主要是 arXiv 偶尔改 XML 格式导致的解析异常二是往关键词文件里加新词。新词这块尤其有意思。具身智能的热词变化很快比如VLA这个缩写我最初就没放在关键词表里导致早期有一批 Vision-Language-Action 模型的论文漏掉了。后来我在浏览论文时注意到这个缩写出现频率暴增才补进去。所以我现在养成了一个习惯每个月花十分钟看一下库里论文的keywords_flags统计出现频率快速上升的组合词就手动加进关键词字典。5.4 实测效果检索效率的量化对比做了一个简单但真实的对比。挑 20 个我熟悉的具体问题比如接触丰富的操作移动抓取机器人基础模型分别用 Google Scholar 和这个小网页搜统计找到目标文献的时间。结果是在已知具体论文标题的场景下两者差不多在按主题探索文献的场景下这个小网页平均能快 40% 以上因为过滤器和子方向标签直接把我导到了想要的位置。还有一个不太好量化的收益是信息节奏——因为每天固定抓取并入新论文我养成了每天早上花十分钟扫一遍新增列表的习惯对整个领域的新动态有了稳定的感知而不是等月末集中补课。这一点我觉得比检索效率更重要。提示如果你是部署在公网服务器上建议至少加一个简单的访问令牌不然任何人都能调你的搜索接口。我用的是 FastAPI 的依赖注入在请求头里校验一个共享密钥成本极低但能挡掉大部分扫描流量。