
Omi Semantic Scholar 插件应用基于无认证 Chat Tools 的学术论文检索服务构建指南【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend本文以开源仓库 Friend 中的独立插件服务 omi-semantic-scholar-app 为主体系统讲解如何为 Omi 构建一个零认证、开箱即用的学术论文检索聊天工具包括三个核心工具关键词搜索、论文详情、作者论文列表的端到端实现、Semantic Scholar Graph API 的对接细节、标识符归一化、本地运行、Manifest 注册与部署方式。读完本文你将掌握 Omi 独立插件服务omi-*-app的标准工程形态并能够照此模式快速扩展新的聊天工具。应用定位Omi 生态中的独立无认证插件在 Friend 仓库中plugins 目录下存在 28 个omi-*-app/独立部署的插件服务见 plugins/README.md。与依赖 OAuth 的集成应用不同omi-semantic-scholar-app是一个standalone no-auth独立无认证集成应用它不需要用户授权流程直接通过公开的 Semantic Scholar Graph APIhttps://api.semanticscholar.org/graph/v1提供服务因此部署成本极低非常适合作为演示 Omi Chat Tools 机制的样板工程。其工程结构非常精简仅 6 个文件见 plugins/omi-semantic-scholar-app文件职责main.pyFastAPI 应用、三个工具端点、Semantic Scholar API 对接与结果格式化models.pyPydantic 请求/响应模型与参数校验requirements.txt依赖锁定fastapi / uvicorn / httpx / pydantictest_main.py无网络依赖的回归测试套件Procfile/railway.toml部署描述文件README.md应用说明与本地运行指引从源码结构看该应用属于独立部署形态拥有自己的main.py、依赖文件和部署描述符与 monolithplugins/main.py解耦可直接独立构建和上线。三个核心 Chat Tools参数契约与返回格式应用通过 Omi 的标准 Chat Tools 机制暴露三个工具定义见 main.py工具名用途必填参数可选参数search_semantic_scholar_papers按关键词搜索论文querymax_results1-10默认 5、min_year可选最小发表年份get_semantic_scholar_paper按 Semantic Scholar 论文 ID 或 DOI 获取论文详情paper_id_or_doi无get_semantic_scholar_author_papers按作者 ID 获取该作者的近期论文author_idmax_results1-10默认 5这三个工具均以POST方式暴露在/tools/*路径下统一返回ChatToolResponse结构result为成功文本、error为失败信息Omi 端只需按 Manifest 中声明的契约调用即可。工具一关键词论文搜索对应请求模型SearchPapersRequest见 models.pyclass SearchPapersRequest(BaseModel): query: str Field(..., min_length2, max_length200) max_results: int Field(default5, ge1, le10) min_year: Optional[int] Field(defaultNone, ge1800, le2100)query长度限制在 2-200 字符max_results被ge1, le10约束在 1-10 之间默认 5防止一次请求返回过多结果撑爆聊天上下文min_year仅接受 1800-2100 之间的年份。实现上该工具调用 Graph API 的/paper/search端点见 main.py请求参数构造如下params: Dict[str, Any] { query: req.query, limit: req.max_results, fields: title,year,authors,citationCount,url,venue, } if req.min_year: params[year] f{req.min_year}-fields参数只拉取渲染所需的六个字段避免不必要的数据传输min_year会被翻译为 Semantic Scholar 支持的区间语法{min_year}-表示从该年份至今。返回结果按序号 标题 作者 年份/期刊/引用数 URL的纯文本格式逐条拼装方便 LLM 直接阅读和引用。工具二论文详情查询get_semantic_scholar_paper接受paper_id_or_doi论文 ID 或 DOI内部先经过标识符归一化再请求/paper/{identifier}端点见 main.pyidentifier quote(normalize_identifier(req.paper_id_or_doi), safe:) data await api_get( f/paper/{identifier}, {fields: title,abstract,year,authors,citationCount,referenceCount,url,venue}, )与搜索工具相比详情工具额外拉取abstract摘要与referenceCount参考文献数并按Title / Authors / Year / Venue / Citations / References / Abstract / URL的结构输出完整信息。当 Graph API 返回 404 时会转换为清晰的Paper not found.错误提示。工具三作者近期论文列表get_semantic_scholar_author_papers请求/author/{author_id}端点见 main.py并通过fields的嵌套语法papers.title,papers.year,papers.citationCount,papers.url一次性取回该作者的论文列表data await api_get( f/author/{author_id}, {fields: name,papers.title,papers.year,papers.citationCount,papers.url}, )获取到的论文先按(year, citationCount)归一化排序见_paper_sort_keymain.py再截取前max_results条输出为Recent papers by {author}:引导的编号列表从而保证近期且高被引的论文优先展示。标识符归一化DOI、arXiv 链接与命名空间识别这是该插件最具工程价值的设计之一。normalize_identifiermain.py负责把用户或 Agent 提供的五花八门的标识符统一转换为 Graph API 认可的NAMESPACE:id形式具体规则识别 URL 型标识符包含doi.org/、arxiv.org/abs/、arxiv.org/pdf/的链接会被提取路径中的标识符arXiv 的.pdf后缀会被自动剥除如https://arxiv.org/pdf/1706.03762.pdf→ARXIV:1706.03762识别命名空间前缀doi:、arxiv:、pmid:、pmcid:、corpusid:、mag:、acl:、dblp:、url:等前缀大小写不敏感会被规范化为标准大小写例如pmid:19872477→PMID:19872477、corpusid:215416146→CorpusId:215416146裸 DOI 自动补前缀形如10.\d{4,9}/...的裸 DOI正则_BARE_DOI_RE见 main.py会自动补成DOI:...否则 Graph API 无法解析其余原样透传裸的 Semantic Scholar 论文 ID40 位十六进制哈希不做任何转换。该逻辑在 test_main.py 中有系统化的测试覆盖包括大小写混合前缀Doi: 10.1/x→DOI:10.1/x、带尾部斜杠的 DOI URL、以及裸 ID 透传等场景。测试还验证了归一化结果会以 URL 编码形式进入请求路径如10.1038/nature12373最终请求/paper/DOI:10.1038%2Fnature12373见 test_main.py。响应模型与错误处理契约所有工具端点统一返回ChatToolResponse见 models.pyclass ChatToolResponse(BaseModel): result: Optional[str] None error: Optional[str] None model_validator(modeafter) def validate_result_or_error(self): if self.result is None and self.error is None: raise ValueError(Either result or error must be provided.) return self该模型的model_validator强制约束result与error至少提供一个从契约层面杜绝空响应。错误处理按三层分类见各工具端点末尾的except块HTTP 状态错误返回Semantic Scholar API error: {status_code}其中 404 会进一步语义化为Paper not found./Author not found.传输层错误连接失败、超时等返回Semantic Scholar request failed: {exc}兜底异常返回Unexpected error: {exc}保证任何异常都能以结构化error字段返回而不会产生 500。此外结果格式化对 Graph API 的脏数据做了充分防御format_authorsmain.py会跳过非 dict 的作者条目并截取前 6 位作者无有效作者时输出Unknownformat_year通过_to_intmain.py把 int、float、数字字符串统一转成整数无法解析时输出Unknown。本地运行与 Manifest 注册本地启动按 README.md 的指引本地运行只需两条命令pip install -r requirements.txt uvicorn main:app --reload --host 0.0.0.0 --port 8080依赖锁定于requirements.txtfastapi0.104.1、uvicorn0.24.0、httpx0.25.2、pydantic2.5.2。启动后访问http://localhost:8080/会返回{message: Semantic Scholar Omi integration is running.}作为健康检查响应见 main.py。Manifest 工具清单Omi 端通过/.well-known/omi-tools.json发现该应用暴露的工具见 main.py。Manifest 为每个工具声明了名称、描述、端点、HTTP 方法以及 JSON Schema 风格的参数定义含required列表。例如搜索工具声明{ name: search_semantic_scholar_papers, description: Search Semantic Scholar papers by keyword., endpoint: /tools/search_semantic_scholar_papers, method: POST, parameters: { type: object, properties: { query: {type: string, description: Search query}, max_results: {type: integer, description: Max results (1-10, default 5)}, min_year: {type: integer, description: Optional minimum publication year} }, required: [query] } }这种/.well-known/路径约定在该仓库的多个独立插件中通用如omi-arxiv-app、omi-coingecko-crypto-app、omi-hacker-news-app等均提供同类 Manifest属于 Omi Chat Tools 生态的既定规范。部署Railway 与 Procfile应用提供两套部署描述均可直接使用ProcfileProcfileweb: uvicorn main:app --host 0.0.0.0 --port $PORT适配 Heroku 风格平台端口取自环境变量railway.tomlrailway.toml面向 Railway 平台指定 Nixpacks 构建器、启动命令uvicorn main:app --host 0.0.0.0 --port $PORT、健康检查路径/超时 100 秒以及失败重启策略最多重试 10 次。从部署描述看该服务无任何外部环境变量依赖API Base 与超时均为代码内常量见 main.py因此可以一键部署到任何支持 Python/FastAPI 的平台。测试保障无网络依赖的回归测试test_main.py 是一个值得借鉴的hermetic密封测试套件在导入被测模块前用标准库 stubs 替换掉httpx、fastapi、pydantic三个第三方依赖见 test_main.py再通过mock.patch将main.api_get替换为返回固定 Graph API payload 的 AsyncMock从而在完全不联网、不安装 site-packages的环境下运行完整回归测试。测试覆盖对应 BasedHardware/omi#13925 历史缺陷包括空/异常 payloaddata、papers为null或非列表时返回No papers found.而非崩溃混合类型排序键year/citationCount同时出现 int、字符串、None 时仍能稳定降序排序见 test_main.py作者字段防御authors为None、非列表或含非 dict 条目时正确渲染Unknown错误语义429 返回状态码、连接失败/超时返回清晰错误信息、404 语义化为Paper not found./Author not found.参数边界max_results截断生效8 篇论文取 3 篇时只渲染最新 3 篇见 test_main.py。运行方式为标准库unittestpython test_main.py不依赖 pytest进一步降低测试执行门槛。与 Omi 插件生态的关联该应用位于 plugins 生态的独立部署插件服务类别中。整个生态包含三个组成部分见 plugins/README.md共享 SDK omi-plugin-sdk持有Conversation、TranscriptSegment、ActionItem等 webhook 载荷模型见 src/omi_plugin_sdk/models.py、28 个独立部署的omi-*-app/服务、以及仅保留历史路由的 legacy monolith。与依赖 webhook 推送的对话类插件不同本应用走的是Chat Tools通道Omi 端按 Manifest 契约调用工具端点并消费result/error文本属于轻量、同步、即调即得的能力集成方式。如果想要把类似能力如任意公开 API 的查询接入 Omi本应用是可直接复刻的最小可运行模板。小结omi-semantic-scholar-app以约 300 行代码演示了 Omi 独立插件服务的完整生命周期工具契约定义Manifest→ 请求校验Pydantic→ 上游 API 对接httpx→ 防御式格式化 → 结构化错误返回 → 密封测试 → 一键部署。其标识符归一化与混合类型排序的处理细节对任何对接外部学术/知识类 API 的集成开发都具有直接的参考价值而/.well-known/omi-tools.json的 Manifest 模式则是接入 Omi Chat Tools 生态的通用入口规范。【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考