给Cellium Agent做了一个组件市场

作者:xiaojinao | 分类:tech

组件市场上线了:https://components.cellium.top

从"我打算做一个"到"它真的能用",中间隔的不是代码,是我思维的转变。

我本来想写一个后端

这站自带登录,所以想做组件市场的时候,第一反应很自然:写个后端的提交流程和审核流程,存储再挂个对象存储桶。

用户登录、上传 zip、填名称描述、进审核队列、审核通过落库、再给个下载接口。数据库、对象存储、审核后台、权限控制,一样都不能少。方案在脑子里越画越沉。

而且我自己也心虚:组件本来就该放在作者的 GitHub 仓库里,我这边说到底只是个"目录",凭什么替人托管代码?审核还得单独做一套——用 Agent 审核吗?

但当时我确实没想到别的路。

Mr.Lee:"你用静态网站不就能做吗?"

在群里跟 Mr.Lee 聊起这个后端方案,他听完先反问了一句:你要的不就是一个列表加详情页?静态网站不就能做吗?

我还没消化,他又补了一句:提交也不用你做,发个 PR 就行。

我当时的反应是:一头雾水。

PR 不是改代码用的吗?组件提交是"业务",这俩怎么接得上?

他给我捋了一遍:你要的到底是什么?账号、审核、版本记录、自动校验、变更历史——GitHub 全都有。作者 Fork 注册表仓库,在 components/<slug>/ 下加一个 meta.json,发 PR,你 review,CI 校验,合并。这就是完整的提交流程。

他还顺手甩了两个例子:NoneBot 的插件就是这么收的,提交就是往 nonebot2 仓库发 PR(https://github.com/nonebot/nonebot2/pull/4239),https://nonebot.dev/store/plugins 展示的就是这些 PR 里的插件。轴中在旁边补了一句更精炼的总结:"添加靠 PR,合并时顺便审了。"

我才反应过来——我一直在想"我要做一个系统",却没想过"我要的这几样能力,早就有人做好了"。npm 这么发包,Homebrew 这么收 formula,NoneBot 这么收插件,凭什么轮到我发明一个上传表单?

安装包也不用我管:作者把 zip 发到自己仓库的 Release,meta.json 里填下载直链。注册表仓库只放 JSON,一行源码都没有。

后端?一行没写。

后来我复盘过:为什么没想到?大概是"做登录"这个动作太熟悉了,熟悉到成了本能。跳出来看一眼需求本身,才发现一半的复杂度是我自己吓自己加上去的。

然后是漫长的"第一次"

方向有了,剩下的全是细节,而细节最耗人。

Mr.Lee 不只是给了方向。市场里第一个组件——cellium-vision,视觉看图,把图片喂给 OpenAI 兼容的多模态模型——不是他手敲的。他有只 bot,叫 Tlipoca,也是拿 Cellium Agent 框架做的;他跟 Tlipoca 说了一嘴,bot 把组件包写好了,他自己 Fork、改 meta.json、提 PR。

也就是说:我做的 Agent 组件市场,第一个组件是另一只 Agent 写出来的。我盯着那个 PR 页面时心情挺复杂,但更多是踏实——流程真能走通,连"写组件"本身都已经不是瓶颈了。

第一次嘛,坑照踩。

中间有一回 CI 红了。那个 PR 把 meta.json 放在 components/cellium-vision/,里面 slug 却写着 vision,构建脚本直接报错,Pages 部署也跟着挂。这个错是 Mr.Lee 陪我看的。读 CI 日志其实没那么难,但第一次红的时候人是懵的,旁边有人说一句"就这,改个名",性质完全不一样。

还有一次,是他提 PR 时的连续吐槽,直接把我文案问题掀了:

"source.commit 听起来像哈希值,安装包直链听起来像链接,这到底要填链接还是哈希值?"
"npm run validate 本地通过——这是啥?"

问得太好了。答案其实很简单:两种登记方式二选一——要么把 zip 发到自己 Release、填下载链接;要么告诉构建机去哪个仓库的哪次提交编号打包。但我把这两个字段并排列在模板里又不解释,谁看谁懵。

npm run validate 也是。当时构建脚本还是 Node 写的,它就是提 PR 前在本地先跑一遍校验:调 node scripts/build.mjs --check,按 CI 同一套规则检查所有 meta.json(目录名和 slug 是否一致、版本号是不是 1.2.3 三段式、日期格式、字段长度),并且会真的访问一次你的直链确认能打开;断网就用 npm run validate:offline,跳过网络检查。我却把它当成人人都懂的黑话写进了清单。

于是 PR 模板里多了一节"术语速查",用人话解释直链、提交编号和该填哪个。这条改进不是我想到的,是被问出来的。

还有些细节是我后来一个个抠的:

顺手把 Agent 那头也接上了

市场这头通了,Agent 怎么"知道"市场上有什么、怎么装?这部分改动在 component_builder.py,Agent 内置的组件管理工具。

改之前它只管本地:生成组件、列组件、从本地 zip 或文件夹安装。改之后加了三个命令,串成一条链路:

没有引入任何新的安装逻辑。审查那一套是现成的,市场安装只是把"包从哪来"从本地路径换成了网络下载。

用户的感受就是:去市场逛一圈,Agent 搜一下、装一下,完事。中间那些 JSON、zip、校验,他完全不用知道。

市场地址还能用环境变量 CELLIUM_COMPONENTS_BASE 换,域名出问题可以指到镜像上。

后来我把构建脚本换成了 Python

市场跑起来之后,我又回头收拾了一次构建链。注册表这边的构建其实只干四件事:读文件、校验、发个 HTTP 探活、按提交打 zip。这些事 Python 标准库全包了,根本不需要 Node 那一套依赖。

于是:

前端打包仍然要用 Node(Vite),但那是我这边一次性的事,跟提交组件的作者没关系。

最后长这样

两个仓库 + 一台服务器:

账号是 GitHub 的,审核是 PR review,版本是 commit 历史,分发是 Release 直链。我要维护的,就一个定时脚本。

我原来准备写的 后来借用的
用户登录 GitHub 账号
上传表单 meta.json
审核后台 PR review
表单校验 CI
版本历史 commit
文件托管 作者自己的 Release

还有个人

轴中 Axlewire,技术上的事他没怎么插手,但他在群里负责点赞、接话、活跃气氛。

气氛担当真的有用。做东西的人都懂,中间有一段纯粹的枯燥期——改 CI、修文案、调手机样式,没有新功能,全是补丁。那段时间每次我扔个截图,轴中就在那丢个 QQ 小表情点赞。没人看的时候是真容易头大;有人在旁边看着,就还能再写两小时。

Mr.Lee 是把我从歪路上拽回来的人。一句"你用静态网站不就能做吗",省掉的不是一个后端,是一整套我本不该维护的东西。而且他不是讲完就走:第一个组件是他让 Tlipoca 帮写、自己亲手提的 PR;PR 模板的歧义是他用提问抓出来的;CI 报错是他陪我看的。

这个市场是群友抬出来的,一点不夸张。

最后

如果你也想做类似的东西,建议就一条:先别想"我要写什么",先想"我要的到底是什么"。

把需求拆成账号、审核、版本、校验、分发这几个词,然后挨个问:这世界上,有没有人已经做得比我好了?

这个问题在我这里的答案是 GitHub,而且它做得好得不止一点。NoneBot 早就这么干了,我只是终于被人拽到了这条路上。

还有一条附赠:别怕把模板写得啰嗦。你觉得理所当然的名词,第一次来的人会一句句问出来。与其等他们问,不如自己先当一次小白——Mr.Lee 那两句吐槽,比我自己检查三遍都管用。