news 2026/10/21 23:22:26

Relay 后端 API 服务包 @openjiuwen/relay-api-server:模块化 Provider 架构与接入实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Relay 后端 API 服务包 @openjiuwen/relay-api-server:模块化 Provider 架构与接入实践
  • 人工智能
  • AI Agent
  • 多智能体
  • 后端
  • 前端

【免费下载链接】relay

Relay 是一个多智能体协作平台,通过统一的界面进行协作开发、代码审查、任务管理,将多个 AI Agent 组织成一个真正的团队。

项目地址:https://gitcode.com/openJiuwen/relay
点击查看免费下载

Relay(OfficeClaw)的多智能体协作平台将后端 HTTP API 服务封装为独立的 npm 包@openjiuwen/relay-api-server,它向外导出服务入口与编程式接入接口,并通过"Provider 模块 + 环境变量"的方式按需加载存储、证据、调度、认证、目录等能力实现。本文以 packages/api/README.md 为骨架,结合仓库源码与测试,系统讲解该包的安装方式、导出结构、Provider 模块化机制、SQLite 提供方接入实践以及编程式启动的完整用法,帮助你理解如何基于该包二次集成或定制 Relay 的 API 服务。

一、包定位:Relay 运行时的后端 API 入口

@openjiuwen/relay-api-server是 OfficeClaw 运行时使用的后端 API 服务包(OfficeClaw API server package)。按 packages/api/README.md 的描述,它导出 OfficeClaw 运行时所需的服务器入口点(server entry points),并依赖共享契约包(shared contracts)与核心运行时包(core runtime package)。

在仓库 monorepo 结构中,该包的依赖关系可以在 packages/api/package.json 中得到印证:

  • @openjiuwen/relay-core:核心运行时,提供OfficeClawProviderPlugin、ProviderPluginRegistry等插件契约;
  • @openjiuwen/relay-api-server-contracts:API 服务契约包,定义IMessageStore、IThreadStore、EvidenceProvider、SchedulerProvider等端口接口;
  • @openjiuwen/relay-shared:共享类型与工具(如createRedisClient、SessionStore、Agent 注册表等)。

三者均以workspace:*形式引入,说明该包必须工作在 pnpm workspace 中。包本身还内置了 Fastify、Socket.IO、ioredis、puppeteer、nodemailer、imapflow、sharp 等大量依赖,覆盖了消息、会话、调度、推送、音视频、连接器等后端能力。

二、安装与基本用法

按 README 给出的安装方式,在应用或运行时项目中执行:

pnpm add @openjiuwen/relay-api-server

安装后有两个可用的导出子路径(exports):

  • @openjiuwen/relay-api-server:主入口,对应 src/index.ts 编译产物dist/index.js,导出main()、createApiModule()、createAuthModule、createStorageModule、createCatalogModule等;
  • @openjiuwen/relay-api-server/server:编程式服务器工厂入口,对应 src/server.ts 编译产物dist/server.js,导出createOfficeClawServer()。

此外,packages/api/package.json 中还注册了两个 bin 命令:

  • office-claw-api-server
  • relay-api-server

二者都指向./dist/cli.js,也就是 src/cli.ts 的编译产物。CLI 入口非常轻量,仅仅调用main()并在出错时输出[api] Fatal error后以退出码 1 结束进程:

import { main } from './index.js'; main().catch((err) => { console.error('[api] Fatal error:', err); process.exit(1); });

这意味着安装该包后,你既可以通过pnpm dev/node dist/cli.js直接启动服务,也可以在宿主代码中编程式拉起服务器。

三、Provider 模块化架构:能力按需加载

README 的核心信息在于:存储(storage)、证据(evidence)、调度(scheduler)、认证(auth)、指标(metrics)与目录(catalog)等实现并不内置于 API 包,而是通过 Provider 模块加载。你需要单独安装 Provider 包,并用对应的OFFICE_CLAW_*_PROVIDER_MODULES环境变量告诉运行时去哪里加载它们。

这种"端口 + 适配器"的设计在源码中有清晰的对应实现。每一个领域都有一份独立的module.ts,统一遵循"注册内置 Provider → 按环境变量加载外部模块 → 解析激活 Provider ID → bootstrap → 创建具体能力"的模式:

能力域模块文件激活 ID 环境变量模块列表环境变量默认 Provider
存储src/storage/module.tsOFFICE_CLAW_STORAGE_PROVIDEROFFICE_CLAW_STORAGE_PROVIDER_MODULES有 Redis 用redis,否则MEMORY_STORE=1用memory,否则直接抛错(fail-closed)
证据src/evidence/module.tsOFFICE_CLAW_EVIDENCE_PROVIDEROFFICE_CLAW_EVIDENCE_PROVIDER_MODULESnoop
调度src/scheduler-persistence/module.tsOFFICE_CLAW_SCHEDULER_PROVIDEROFFICE_CLAW_SCHEDULER_PROVIDER_MODULESnoop
认证src/auth/module.tsOFFICE_CLAW_AUTH_PROVIDEROFFICE_CLAW_AUTH_PROVIDER_MODULESno-auth
目录src/catalog/module.tsOFFICE_CLAW_CATALOG_PROVIDEROFFICE_CLAW_CATALOG_PROVIDER_MODULESfile

几个值得注意的源码细节:

  1. 模块列表支持逗号分隔:以存储模块为例,storage/module.ts 中的parseModuleSpecifiers()会把OFFICE_CLAW_STORAGE_PROVIDER_MODULES按逗号切分并过滤空项,因此一个变量可以加载多个 Provider 模块。
  2. 激活 Provider 与模块分离:OFFICE_CLAW_*_PROVIDER决定"用哪一个",OFFICE_CLAW_*_PROVIDER_MODULES决定"从哪些模块注册可用项";如果激活的 ID 未注册,Registry 的get()会抛出形如Storage provider 'xxx' not found. Registered: [...]的明确错误(见 storage/storage-provider-registry.ts)。
  3. 证据与调度默认 noop:未配置时证据与调度 Provider 为noop,此时证据索引与 TaskRunnerV2 调度器不会真正工作。在 src/index.ts 中,调度模块初始化为noop时会被判定为不可用(scheduler provider is noop抛错并被捕获为非致命警告),这说明生产环境必须接入真实的调度 Provider。
  4. README 中提到的 metrics:README 将 metrics 与 storage、evidence 等并列。从当前仓库源码结构看,storage、evidence、scheduler、auth、catalog五个模块均有对应的module.ts与OFFICE_CLAW_*_PROVIDER_MODULES环境变量可查证;metrics 相关的 Provider 模块文件未在packages/api/src下发现,如需启用可参考同族环境变量的命名规律自行接入 Provider 包。

Provider 模块的导出契约

每个外部 Provider 模块被加载后,Registry 会从模块的命名空间中收集候选 Provider。以证据 Registry(src/evidence/provider-registry.ts)为例,它依次检查default、evidenceProvider具名导出以及evidenceProviders数组导出,只要命中的对象满足{ id: string; createEvidenceServices: Function }形状即视为有效 Provider。存储 Registry(src/storage/storage-provider-registry.ts)还支持部分 Provider:只实现部分 store 的 Provider 会被wrapPartialProvider包装,用默认 Provider 补齐缺失的 store。这为"只替换某个存储"的定制场景提供了很大灵活性。

四、实战:接入 SQLite 证据与调度 Provider

README 给出的完整示例是使用@openjiuwen/relay-storage-sqlite包来获得 SQLite 证据(evidence)与调度(scheduler)能力:

pnpm add @openjiuwen/relay-storage-sqlite
OFFICE_CLAW_EVIDENCE_PROVIDER=sqlite OFFICE_CLAW_EVIDENCE_PROVIDER_MODULES=@openjiuwen/relay-storage-sqlite/evidence OFFICE_CLAW_SCHEDULER_PROVIDER=sqlite OFFICE_CLAW_SCHEDULER_PROVIDER_MODULES=@openjiuwen/relay-storage-sqlite/scheduler

4.1 Provider 包的结构

该包对应仓库中的 packages/sqlite-adapter/api 目录,包名为@openjiuwen/relay-storage-sqlite(见 package.json)。它通过exports暴露三个子路径:

  • .:主入口,导出evidenceProvider、schedulerProvider与approvalRecordStorageProvider;
  • ./evidence:映射到dist/evidence/sqlite.js,导出id: 'sqlite'的evidenceProvider;
  • ./scheduler:映射到dist/scheduler/sqlite.js,导出id: 'sqlite'的schedulerProvider;
  • ./authorization:提供createSqliteApprovalRecordStore等审批记录存储能力。

子路径导出正是 README 示例中.../evidence与.../scheduler能作为模块说明符被直接加载的原因——OFFICE_CLAW_EVIDENCE_PROVIDER_MODULES指向的字符串本质上就是一个可被import()的模块说明符。

4.2 证据 Provider 的底层实现

evidence/sqlite.ts 中的evidenceProvider调用createMemoryServices()创建一套 SQLite 支撑的证据服务,包括:

  • SqliteEvidenceStore:证据文档与关系(edges)的存储;
  • IndexBuilder:对docsRoot下的文档建索引;
  • VectorStore与EmbeddingService:基于sqlite-vec的向量检索;
  • stats()能力:直接查询evidence_docs与edges表统计文档数、边数以及最近更新时间。

从 src/index.ts 可以看到,API 服务在启动时会调用证据模块的indexBuilder.rebuild()重建证据索引(失败仅告警不阻断启动),随后通过markThreadDirty/accumulateSummaryDelta/flushDirtyThreads每 30 秒把脏线程摘要增量刷入索引。

4.3 调度 Provider 的底层实现

scheduler/sqlite.ts 中的schedulerProvider用better-sqlite3打开数据库文件,并设置三项 pragma:

db.pragma('journal_mode = WAL'); db.pragma('foreign_keys = ON'); db.pragma('busy_timeout = 5000');

随后返回一组 SQLite 持久化对象,供 API 服务的TaskRunnerV2调度器使用:

  • RunLedger:任务运行台账;
  • GlobalControlStore:全局治理开关;
  • EmissionStore:发射(投递)记录;
  • PackTemplateStore:打包模板;
  • DynamicTaskStore:动态任务持久化。

需要留意的是,SQLite 证据与调度默认使用同一个数据库文件路径:API 服务在 src/index.ts 中通过env.EVIDENCE_DB ?? <monorepoRoot>/data/evidence.sqlite同时注入给证据模块与调度模块,即两套能力共享一个evidence.sqlite数据库(调度侧的建表依赖applyMigrations完成)。

4.4 环境变量默认值如何被铺开

仓库的启动脚本已经把这些默认值内置。例如:

  • scripts/start-dev.sh 默认OFFICE_CLAW_STORAGE_PROVIDER_MODULES=@openjiuwen/relay-storage-sqlite、OFFICE_CLAW_APPROVAL_RECORD_PROVIDER=sqlite-approval-records;
  • scripts/start-windows.ps1 为 Windows 运行时设置了OFFICE_CLAW_EVIDENCE_PROVIDER=sqlite、OFFICE_CLAW_EVIDENCE_PROVIDER_MODULES=@openjiuwen/relay-storage-sqlite/evidence、OFFICE_CLAW_SCHEDULER_PROVIDER=sqlite及对应的_MODULES变量。

这解释了 README 示例的完整落地路径:安装 Provider 包 → 设置环境变量 → 启动 API 服务即自动加载 SQLite 证据与调度能力。

五、模块加载器:workspace 内如何解析 Provider 模块

外部 Provider 模块说明符(如@openjiuwen/relay-storage-sqlite/evidence)是通过moduleLoader动态import()的。默认的加载器定义在 src/utils/workspace-module-loader.ts:它先尝试标准import(specifier),如果抛出ERR_MODULE_NOT_FOUND,则扫描当前项目根下packages目录中的全部package.json,把@openjiuwen/*包名映射到实际目录,再通过pathToFileURL()定位exports中对应的子路径实现文件。

这正是本仓库 monorepo 部署形态的支撑点:当 Provider 包尚未发布到 npm registry 时,@openjiuwen/relay-storage-sqlite/evidence也能通过 workspace 扫描被正确解析并加载。createStorageModule、createEvidenceModule、createAuthModule等都接收可选的moduleLoader参数,测试与下游宿主可以注入自定义加载器。

六、编程式接入:createOfficeClawServer 与启动选项

6.1 服务器工厂

@openjiuwen/relay-api-server/server子路径导出的createOfficeClawServer()(见 src/server.ts)是最常用的编程式接入点,返回{ start, close }:

import { createOfficeClawServer } from '@openjiuwen/relay-api-server/server'; const server = await createOfficeClawServer({ port: 3004, host: '127.0.0.1', redisUrl: 'redis://127.0.0.1:6379', memoryStore: false, }); const url = await server.start(); // 例如 http://127.0.0.1:3004 // ... 退出前调用 await server.close();

OfficeClawServerOptions支持以下字段,工厂会把它们写入对应环境变量后再启动(见 src/server.ts):

选项写入的环境变量说明
portAPI_SERVER_PORT监听端口,默认3004
hostAPI_SERVER_HOST监听地址,默认127.0.0.1
redisUrlREDIS_URLRedis 连接串,提供后自动启用 Redis 存储与租约
memoryStoreMEMORY_STORE=1开启内存存储模式(无 Redis 时)
projectRootOFFICE_CLAW_CONFIG_ROOT项目根目录,用于解析 Agent 配置
pluginsglobalThis.__clowder_extra_plugins注入额外的OfficeClawProviderPlugin,可注册自定义 Agent 提供方
runtimeEnvStore—运行时环境存储,供启动时 bootstrap 解析

启动完成后返回的 URL 由 src/server-lifecycle.ts 依据API_SERVER_PORT/API_SERVER_HOST拼接,close()则通过_stopForProgrammatic()触发优雅关停。

6.2 更细粒度的 ApiStartOptions

若你不需要server.ts的封装,可以直接调用主入口的main(options)(即createApiModule(options)),它支持更细粒度的扩展点(见 src/index.ts):

  • storageModule/catalogModule:注入自定义模块以替换存储后端或 Agent 配置加载;
  • hooks.afterAppCreated:在全局认证钩子注册前挂载自定义认证中间件;
  • hooks.afterInit:拿到完整的ApiInitContext(env、cwd、Fastify 实例、stores、services、modules);
  • hooks.afterAuthMiddleware:注册 JWTrequest.auth注入;
  • hooks.afterSocketManagerCreated:为 WebSocket 附加认证逻辑;
  • skipFeatures:跳过指定功能组的路由注册。FeatureName的可选值为terminal、ppt、connector、scheduler、memory、session、push、uploads、tts。

6.3 启动阶段的内建行为

main()会依次完成大量初始化,理解这些行为有助于排障与定制:

  • Fastify 实例:bodyLimit为 100MB,注册 Cookie、CORS、WebSocket 插件;日志序列化器会脱敏token、apiKey、secret等查询参数;
  • 全局安全:注册全局认证钩子、安全响应头、统一错误处理器与GET /health健康检查(返回{ status: 'ok', timestamp });
  • 存储层:按OFFICE_CLAW_STORAGE_PROVIDER创建messageStore、threadStore、taskStore、backlogStore、memoryStore等(消息/线程/任务/积压均支持*_TTL_SECONDS过期);
  • Agent 编排:从 catalog 读取 Agent 配置,通过ProviderPluginRegistry按config.provider创建对应的AgentService(内置插件见 src/config/plugins/builtin-providers.ts,涵盖 anthropic、openai、google、dare、opencode、antigravity、relayclaw、acp、a2a),并维护AgentRouter用于消息路由;
  • 多实例保护:配置了 Redis 时通过ApiInstanceLease获取 API 命名空间租约,若租约被抢占或监听失败,进程会拒绝启动并退出,防止同一 Redis 命名空间出现多个活实例;
  • 收尾任务:启动时清理孤儿 invocation(StartupReconciler)、全局会话 reaper 定时扫描卡在sealing状态的会话、预热 provider profiles、检测可用 CLI 客户端、启动 GitHub 评审 watcher 与 CI/CD 轮询器、启动连接器网关;
  • 优雅关停:收到 SIGTERM/SIGINT 后依次记录审计日志、触发 Redis BGSAVE、关闭存储 Provider、停止 watcher、关闭 SocketManager 与 Fastify,最后释放租约。

七、验证与测试

仓库为该包的接入方式提供了直接可读的测试证据:

  • test/server-entrypoint.test.js 验证createOfficeClawServer({ port, host, memoryStore })暴露start/close方法,并验证注入的runtimeEnvStore会被注册到 bootstrap 解析器;
  • test/auth-module.test.js 覆盖OFFICE_CLAW_AUTH_PROVIDER+OFFICE_CLAW_AUTH_PROVIDER_MODULES的 Provider 注册、缺失 Provider 报错与 bootstrap 行为;
  • test/auth-external-provider-e2e.test.js 以OFFICE_CLAW_AUTH_PROVIDER=demo-static、OFFICE_CLAW_AUTH_PROVIDER_MODULES=@examples/demo-auth-provider演示了外部认证 Provider 的端到端接入。

这些测试同时佐证了 README 的 Provider 加载方式:_PROVIDER指定激活 ID,_PROVIDER_MODULES指向模块说明符,二者缺一不可。

八、总结

@openjiuwen/relay-api-server作为 Relay 的官方后端 API 服务包,把"服务入口"与"能力实现"解耦:服务骨架内置在包中(Fastify、认证、路由、Agent 编排、优雅关停等),而存储、证据、调度、认证、目录等具体能力全部由 Provider 模块按需接入。接入时只需两条规则:

  1. 安装对应的 Provider 包(如@openjiuwen/relay-storage-sqlite),并通过其exports子路径指向具体的 Provider 实现;
  2. 设置OFFICE_CLAW_<能力域>_PROVIDER指定激活项,设置OFFICE_CLAW_<能力域>_PROVIDER_MODULES指定模块加载说明符。

需要更深入的实现细节时,建议按以下路径阅读源码:包契约与启动流程看 src/index.ts,编程式接入看 src/server.ts,各能力域模块看 src/storage/module.ts、src/evidence/module.ts、src/scheduler-persistence/module.ts、src/auth/module.ts、src/catalog/module.ts,Provider 实现参考 packages/sqlite-adapter/api/src/evidence/sqlite.ts 与 packages/sqlite-adapter/api/src/scheduler/sqlite.ts。

  • 人工智能
  • AI Agent
  • 多智能体
  • 后端
  • 前端

【免费下载链接】relay

Relay 是一个多智能体协作平台,通过统一的界面进行协作开发、代码审查、任务管理,将多个 AI Agent 组织成一个真正的团队。

项目地址:https://gitcode.com/openJiuwen/relay
点击查看免费下载

相关推荐

上一篇:itch 桌面应用完整指南:下载、安装、更新,一次管明白你的 itch.io 游戏库
下一篇:ZCF 工作流体系详解:六阶段工作流、Feat、BMad、Spec 与 Git 智能命令的使用与实现原理

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 19:05:57

OpenPose核心解读:PAF如何解决多人姿态估计的关键点关联难题

姿态估计这两年其实已经进入“柴米油盐”阶段了&#xff0c;大部分做视觉的工程师手里都有现成的人体关键点方案&#xff0c;但回到那篇让多人实时2D姿态估计真正落地的工作&#xff0c;几乎所有人绕不开同一个名字&#xff1a;OpenPose。我最早接触它的时候&#xff0c;脑子里…

作者头像 李华
网站建设 2026/10/22 7:02:14

C++引用深入解析:本质、与指针的区别及避坑实践

1. 引用的本质&#xff1a;它不是指针的语法糖&#xff0c;而是对象的第二个名字很多从C语言转过来学C的朋友&#xff0c;在第一次接触引用时&#xff0c;都会产生一种感觉&#xff1a;这不就是带解引用的指针吗&#xff1f;我的看法是——理解可以这样起步&#xff0c;但如果停…

作者头像 李华
网站建设 2026/10/20 9:01:23

Abaqus自动网格划分插件:Python二次开发实战

简介&#xff1a;当前CAE前处理中&#xff0c;复杂几何模型的网格划分往往依赖手动反复操作&#xff0c;工作量大且结果受经验影响。这套基于Python开发的ABAQUS网格自动划分插件&#xff0c;正是面向这类批量前处理与自动化建模需求&#xff0c;适用于具备Python基础的仿真工程…

作者头像 李华
网站建设 2026/10/19 8:09:26

散度的物理本质与EMC工程应用:从数学定义到干扰源定位

1. 为什么散度不是“发散程度”的直觉翻译——从电磁场物理图像出发很多人第一次看到“散度”这个词&#xff0c;下意识就把它和“发散”“扩散”“向外跑”画上等号。我带过几届某高校电磁场课程的实验助教&#xff0c;每次讲到∇E这个算符&#xff0c;总有学生在课后追问&…

作者头像 李华
网站建设 2026/10/21 13:13:54

Zabbix Linux客户端监控实战:自定义key编写与调试避坑指南

1. 为什么客户端监控是绕不开的一道坎搞运维的都知道&#xff0c;服务器监控这件事&#xff0c;装个服务端只是万里长征第一步。真正让人头疼的&#xff0c;是后面怎么把几十上百台机器的数据准确、稳定地收上来。Zabbix 作为老牌监控方案&#xff0c;服务端和 Web 界面搭起来不…

作者头像 李华
网站建设 2026/10/18 22:04:54

医疗医药AI+BI小范围试点落地路径分享

导语 医疗医药行业数智化转型持续推进&#xff0c;AIBI成为企业优化经营决策、提升业务效率的核心抓手&#xff0c;但不少企业在落地时容易陷入“盲目铺摊子却无法验证价值”的困境&#xff0c;小范围试点是控制项目风险、验证业务价值的关键起步阶段。医疗医药行业有合规要求高…

作者头像 李华