Skip to content

三端架构与 Monorepo

要点

  • 在大多数场景下,Agent 项目至少需要三个入口:用户工作台、管理后台和 API/Agent 服务。
  • 三端拆分先看用户角色、权限范围和发布节奏,再看框架和部署平台。
  • Monorepo 的价值在于让任务状态、API 契约、Agent 输出 schema、Prompt 版本和共享 UI 保持一致。

1. 从技术选型到工程组织

前面的文章已经讨论了边缘 API、Hono.js、FastAPI 的边界,也拆过 LangGraph、RAG、Prompt、流式输出和可观测性。到了工程组织阶段,问题会从「某个能力怎么做」转向「这些能力分别由哪些应用承接」。

Agent 项目通常有三类参与者:

  1. 最终用户:提交任务、选择资料范围、查看产物、处理审稿意见。
  2. 管理者或维护者:管理资料库、Prompt 版本、质量规则、模型配置和发布门禁。
  3. 系统运行侧:承接 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/webpackage.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 放到同一个仓库里管理。这样可以保留安全边界,也能减少跨端同步成本。

参考资料

基于 MIT 协议开源