Agent 与数字人建造复盘

单仓不拆,但按“未来可拆”组织

单仓还是多仓,两边都有政治正确:拆微仓显得架构先进,单仓显得务实。我们的数字人 Agent 项目选了第三条路:继续单仓,但按"未来可拆"组织——部署单元和共享包先分清楚,仓库数量以后再说。拆不拆是后来的决定,拆得动是现在的能力。

怎么分:先画部署单元,再画共享包

目录按两类角色组织。apps/ 放未来可能独立部署的单元:用户端、后台端、接口服务、后台任务。packages/ 放共享能力:契约、应用编排、领域、持久化、外部集成、运行时。

这次重组是物理搬迁,不是建新目录摆样子。前端两端的源码完成隔离,共享样式收进独立 UI 包,两端不再通过内部路径互相调用;后端的路由按资源拆成十几个模块文件——世界、来信、任务、创作、账号、记忆、后台管理各归其位,注册器只保留装配和鉴权 helper;领域相关的检索逻辑从遗留大文件里抽出来,测试按单元、契约、E2E 分目录归档,脚本按迁移、备份、评测、发布、维护分层。旧的兼容层和混放目录直接删除,不留"以后再清"的尾巴。

两条硬边界

第一,契约包是源头。以手写 schema 为准,生成 OpenAPI 与客户端;跨模块事件用版本化名称;资产 manifest 在契约里定义版本、URI、哈希和内容类型,主仓用 lock 文件锁定资产仓的提交。契约先行,代码随后。

第二,依赖方向锁死。领域代码不得依赖 Web 框架、前端框架、队列、缓存或具体 SDK;领域之间通过应用层编排或类型化事件通信。光靠约定不够,加了一个架构检查脚本,阻止应用/领域包反向依赖服务端、数据库和队列实现——边界由机器守,不靠自觉。

数据库也一样:PostgreSQL 是正式接口服务和后台任务的唯一业务数据库,SQLite 只保留在迁移、备份和隔离测试工具里。正式启动路径不再加载 SQLite 驱动,一种用途一种数据库,不搞双轨。

搬迁清单:动了哪些东西

这次重组的具体动作值得列一下,因为"模块化"三个字太容易停留在 PPT 里。

路由层:世界、来信、任务、创作主题/项目/版本/审批、后台资源、账号登录登出、记忆/成长,各自独立成模块文件;HTTP 资源覆盖十几个模块后,注册器只做装配和鉴权 helper,不再塞业务逻辑。

数据层:数字人兼容 SQL 按记忆、创作、研究世界、种子拆成四个迁移模块,统一入口按固定顺序调用;研究路径的检索、来源增强和时间窗口评估,从遗留大文件里抽离出来。

应用层:新增 application 包,承载跨域入口——发用户来信、排队手动研究、启动创作项目,都走应用层编排时钟、分诊和持久化。任务立即运行也通过应用层端口接入,不再直连实现。

资产:运行时生成的资产不进入 Git。独立资产仓候选已在本地初始化,主仓用 manifest lock 文件锁定其提交;新增校验命令,对版本、路径、文件存在性、内容类型和哈希做校验,且不依赖运行时。

脚本和测试:脚本按迁移、备份、评测、发布、维护分层;单元测试、契约测试、E2E 分目录归档,测试的依赖方向和源码边界保持一致。

仓库数量:不预先锁定

决策里还有一句容易被忽略的话:最终仓库数量暂不预先锁定。现在按"未来可拆"组织,不等于将来一定要拆成 N 个仓。拆不拆、拆成几个,是到时候看团队规模、发布节奏、权限边界再定的事。

现在要保证的只有一条:想拆的时候,依赖关系已经理清楚了。最糟糕的状态不是单仓也不是多仓,是"单仓拆不动,多仓不敢拆"——前者是意大利面,后者是分布式意大利面。

诚实收尾:没做完的写下来

验证数据:类型检查、lint、293 项测试、构建、OpenAPI 生成、架构检查全部通过;容器开发环境四服务重建后健康检查正常。但 E2E 是 32 通过、4 跳过、4 失败——失败集中在既有 mock 和测试数据的等待问题,没有把它宣称为"本次结构改动已解决"。

没做完的也明确列出来:API 路由还没按全部资源拆完,迁移 SQL 还没按领域物理拆完,独立资产仓还没真正发布。这些保留为后续阶段,不凑进本次结论。重构报告里最可疑的就是"全部完成",我们选择把未完成项写在正文里。

小结

"未来可拆"的本质是:用部署单元的视角组织单仓,用契约和检查脚本锁住依赖方向,用诚实的验证报告代替"重构完成"的宣言。拆不拆以后再说,拆得动现在就要证明。

© 2026 rotor®GitHub 开源CC BY-NC-ND · 转载请注明出处