主题
三端架构与 Monorepo
要点
- 在大多数场景下,Agent 项目至少需要三个入口:用户工作台、管理后台和 API/Agent 服务。
- 三端拆分先看用户角色、权限范围和发布节奏,再看框架和部署平台。
- Monorepo 的价值在于让任务状态、API 契约、Agent 输出 schema、Prompt 版本和共享 UI 保持一致。
1. 从技术选型到工程组织
前面的文章已经讨论了边缘 API、Hono.js、FastAPI 的边界,也拆过 LangGraph、RAG、Prompt、流式输出和可观测性。到了工程组织阶段,问题会从「某个能力怎么做」转向「这些能力分别由哪些应用承接」。
Agent 项目通常有三类参与者:
- 最终用户:提交任务、选择资料范围、查看产物、处理审稿意见。
- 管理者或维护者:管理资料库、Prompt 版本、质量规则、模型配置和发布门禁。
- 系统运行侧:承接 API、Agent 编排、工具调用、后台任务、trace 和指标。
这三类使用者对应三个子系统:
| 子系统 | 使用者 | 核心职责 |
|---|---|---|
| Web 用户工作台 | 最终用户 | 任务创建、资料选择、产物预览、审稿处理 |
| Admin 管理后台 | 管理者、开发者 | Prompt 版本、资料库、质量规则、指标和灰度配置 |
| API / Agent 服务 | 系统 | 鉴权、任务状态、编排、工具代理、流式输出、后台任务 |
这个拆分方式把安全边界和迭代节奏分开。用户工作台强调低门槛和任务进度反馈,管理后台强调权限和治理,API / Agent 服务强调稳定契约、可恢复任务和可观测性。
2. Web 用户工作台
用户工作台面向日常使用者。它需要让用户完成一条完整任务:
txt
新建任务
-> 选择对象、场景、范围和风格
-> 查看资料召回结果
-> 确认结构
-> 接收流式产物
-> 处理审稿意见
-> 交付前检查这个入口不宜暴露过多底层配置。用户更关心产物是否可用、哪一步需要人工确认、哪些审稿问题会阻塞交付。Prompt 版本、检索策略、模型灰度和规则阈值可以由后台管理。
从界面边界看,Web 更适合保存这些状态:
- 当前任务所处阶段:资料召回、结构、产物、审稿、改写、交付检查。
- 用户可操作的确认点:是否接受结构、是否允许继续生成、是否处理某条审稿意见。
- 面向产物的结果:资料卡片、产物版本、审稿问题、交付检查结果。
这些状态需要和 API 契约保持一致。只要任务阶段或审稿结构发生变化,Web 的展示、按钮状态和恢复逻辑都会受到影响。
3. Admin 管理后台
管理后台负责治理系统,不直接承担任务执行流程。常见能力包括:
- 资料库管理:上传文档、查看来源、设置可信度、触发重建索引。
- Prompt 版本管理:维护规划、资料、执行、审稿、改写等 Agent 的模板。
- 审稿规则管理:维护禁用表达、事实核查规则、项目风格和交付门禁。
- 任务审计:查看某次任务的资料、结构、产物版本、审稿问题、工具调用和 trace。
- 灰度配置:控制新检索策略、新 Prompt 或新模型的放量范围。
后台系统的安全等级更高。它可以看到资料来源、内部规则、Prompt 版本、线上质量数据和失败样本,所以需要独立权限、独立路由和更严格的审计记录。
它和 Web 的主要差异在于操作对象。Web 面向单个产物的推进,Admin 面向系统规则的维护。比如同样是「审稿问题」,Web 关注某条问题是否已经处理,Admin 关注同类问题在哪些场景、哪些 Prompt 版本、哪些资料来源下更容易出现。
4. API / Agent 服务
API / Agent 服务是三端里的业务中枢。它接收 Web 和 Admin 的请求,维护任务状态,调用 Agent 图,代理外部工具,并把结果写回可追溯的数据结构。
推荐的职责边界是:
- 路由层:HTTP、鉴权、参数校验、响应包装。
- 任务模块:任务状态、版本、恢复和交付检查。
- Agent 模块:规划、资料、执行、审稿、改写、交付检查节点。
- 工具模块:搜索、文件读取、事实核查、格式检查、外部系统写入。
- 观测模块:trace、span、metrics、失败分类、Prompt 版本记录。
一条任务在三端之间可以这样流动:
txt
Web 新建任务
-> API 创建任务状态
-> Agent 服务执行资料召回、结构、产物和审稿
-> Web 接收流式输出和人工确认点
-> API 写入审稿结果与交付检查
-> Admin 查看质量数据、Prompt 版本和失败 trace这个流动关系要求 API 层有稳定契约。Web 和 Admin 都通过同一套 API 访问系统,但权限、页面和使用路径不同。
5. 为什么适合 Monorepo
Agent 项目的共享面很大:
- 任务状态类型。
- Agent 输出 schema。
- API 请求和响应类型。
- 资料卡片、审稿问题、交付检查结果。
- Prompt 版本号和灰度配置。
- 通用 UI 组件。
- TypeScript、lint、测试和构建配置。
如果 Web、Admin、API 分成多个仓库,这些契约容易漂移。比如审稿问题新增 blockingReason 字段,API 写入了新字段,Web 没有更新展示逻辑,后台还按旧字段统计,运行时就会出现不一致。
Monorepo 可以把这些共享契约放到 packages/ 中,让三个应用依赖同一份定义:
txt
apps/
web/ # 用户工作台
admin/ # 管理后台
api/ # API / Agent 服务
packages/
contracts/ # API 与 Agent 输出契约
prompts/ # Prompt 模板与版本
ui/ # 共享 UI 组件
config/ # 共享工程配置这种 apps/ 放可部署应用、packages/ 放共享代码的分层,是 Turborepo 和 pnpm 工作区中的常见约定。Turborepo 官方建议 apps/ 只存放部署入口,packages/ 存放共享库;如果代码需要跨应用复用,就应该从 apps/ 提取到 packages/,而不是让应用之间互相引用。这样可以避免应用之间的循环依赖,也让共享契约的边界更清晰。
在 pnpm 工作区里,内部包通常用 workspace:* 协议引用。例如 apps/web 的 package.json 里写 "@repo/contracts": "workspace:*",pnpm 会把本地包链接到 node_modules,而不是去 npm 拉取同名包。源码改动后,所有依赖它的应用都能即时看到变化,不需要先发布到 npm。如果共享 UI 包用 TypeScript/JSX 直接写源码,Next.js 的 transpilePackages 配置可以让应用直接编译它,省去每个包单独构建 dist/ 的步骤。
在这种结构里,API 契约变更、任务状态变更和 Prompt 元信息变更可以放在同一个 Pull Request 里审查。TypeScript 类型检查也能在开发阶段暴露跨端遗漏。
Monorepo 的主要收益,是减少跨端契约同步成本。它不能替代模块边界设计,也不能把所有业务逻辑都抽成共享包。共享包应该优先保存稳定契约,具体页面流程、Agent 节点内部逻辑和后台筛选交互仍然留在各自应用里。
6. 什么时候不该 Monorepo
Monorepo 也会带来代价。下面几种情况需要谨慎:
- 团队和权限边界完全不同。
- 后端由独立团队维护,发布节奏和前端长期分离。
- 仓库体积过大,构建缓存和依赖管理已经成为主要成本。
- 多语言服务非常多,统一工具链反而增加维护成本。
- 合规要求要求某些 Prompt、客户资料或评估数据与前端代码隔离管理。
如果之后真的需要拆分,可以参考 Turborepo 社区强调的「无向上导入」原则:packages 不应从 apps 导入,UI 等基础包不应从业务包导入,依赖图应该尽量保持有向无环。这能降低拆分时的耦合风险,也避免把某个应用的私有逻辑泄漏到共享包中。
Agent 项目早期通常还没到这个复杂度。更稳妥的做法是先用 Monorepo 保持契约一致,等后台服务、模型服务或数据治理能力独立到一定规模,再按边界拆出去。
拆分也不需要一次完成。可以先把 Python 文档处理、批量评估、模型服务这类后台能力拆成独立服务,同时保留 TypeScript 契约、Web、Admin 和 API 入口在同一个仓库里。
7. 小结
三端架构回答的是「谁使用什么能力」,Monorepo 回答的是「共享契约如何保持一致」。
对 Agent 项目来说,更推荐的起步方式是:Web 用户工作台、Admin 管理后台、API / Agent 服务分应用;任务状态、Agent 输出 schema、Prompt 模板元信息和共享 UI 放到同一个仓库里管理。这样可以保留安全边界,也能减少跨端同步成本。