首页
/ AutoGPT Platform 工程指南:Monorepo 结构、环境配置机制与开发规范

AutoGPT Platform 工程指南:Monorepo 结构、环境配置机制与开发规范

2026-09-06 10:21:26作者:邵娇湘

本文以 AutoGPT 仓库中 autogpt_platform 目录下的开发者指南(CLAUDE.md 仅包含一行 @AGENTS.md 引用,其实际内容即 autogpt_platform/AGENTS.md,并向下引用 backend/AGENTS.mdfrontend/AGENTS.md)为骨架,系统梳理 AutoGPT Platform 的 Monorepo 组成、环境变量分层机制、Docker Compose 服务编排,以及分支策略、PR 规范、TDD 流程与前后端代码风格约定。读完本文,你可以在不逐行翻找文档的情况下,独立完成 Platform 的本地环境初始化、配置覆盖和服务启动。

仓库结构:三部分组成的 Monorepo

autogpt_platform/AGENTS.md 开篇将 AutoGPT Platform 定义为一个 Monorepo,包含三个主要部分:

  • Backendbackend/):Python FastAPI 服务端,支持异步;
  • Frontendfrontend/):Next.js + React 应用;
  • Shared Librariesautogpt_libs/):通用 Python 工具库(如 autogpt_libs/autogpt_libs/api_key/keysmith.py 密钥工具、auth 鉴权模块、logging 日志组件等)。

除三大主目录外,autogpt_platform/ 下还有若干支撑目录,可直接在仓库中查看:

五个核心概念

指南用五个术语概括了 Platform 的业务模型,这是理解后文所有配置项的钥匙:

  1. Agent Graphs(代理图):以 JSON 存储的工作流定义,由后端执行;仓库中 backend/agents/ 目录下保存了大量 agent_*.json 示例(如 calculator-agent.json)。
  2. Blocks(块):位于 backend/blocks/ 的可复用组件,每个块完成特定任务;
  3. Integrations(集成):按用户存储的 OAuth 与 API 连接;
  4. Store(商店):用于共享代理模板的市场;
  5. Virus Scanning(病毒扫描):通过 ClamAV 集成保障文件上传安全——这一点在 docker-compose.yml 中有对应的 clamav 服务(见下文)。

环境配置机制:三层文件与四级加载顺序

配置文件层级

指南规定了三层环境配置文件,每一层都是"默认值文件 + 用户覆盖文件"的成对结构:

作用域 默认值文件(纳入 git 跟踪) 用户覆盖文件(gitignore)
Backend backend/.env.default backend/.env
Frontend frontend/.env.default frontend/.env
Platform 根 .env.default .env

仓库中的 Makefile 提供了 init-env 目标,正是这一层级的落地命令:

init-env:
	cp -n .env.default .env || true
	cd backend && cp -n .env.default .env || true
	cd frontend && cp -n .env.default .env || true

cp -n 表示仅在目标不存在时拷贝,因此首次执行会把三套默认值复制为 .env,之后用户的本地改动不会被覆盖——这就是"默认值随仓库走、覆盖值留在本地"的实现方式。

Docker 环境加载顺序

指南明确了 Docker 环境下配置的生效优先级(从高到低应结合第 3、4 条理解):

  1. .env.default 文件提供基础配置(跟踪在 git 中);
  2. .env 文件提供用户级覆盖(gitignore);
  3. Docker Compose 的 environment: 段提供服务级覆盖;
  4. Shell 环境变量拥有最高优先级。

文档同时给出三条关键实现要点,均可在 docker-compose.yml 中验证:

  • 所有服务在 docker-compose 文件中都使用硬编码默认值,不使用 ${VARIABLE} 插值。例如 db 服务直接写死 POSTGRES_USER: postgresPOSTGRES_PASSWORD: your-super-secret-and-long-postgres-password
  • env_file 指令在运行时把变量加载进容器,因此容器内实际生效的是文件变量与 environment: 段的组合结果;
  • Backend/Frontend 服务通过 YAML 锚点(YAML anchors)获得一致配置,Supabase 数据库服务(db/docker/docker-compose.yml)也遵循同一模式。

根级 .env.default:数据库凭据的单一事实来源

autogpt_platform/.env.default 全文只描述数据库凭据,其注释明确说明:这些值就是 db 服务在 docker-compose.yml 中硬编码的凭据,"如果改动,请同步更新 docker-compose.platform.ymlDATABASE_URL / DIRECT_URLbackend/.env(.default)frontend/.env(.default)"。内容如下:

POSTGRES_HOST=db
POSTGRES_DB=postgres
POSTGRES_PORT=5432
# default user is postgres
POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password

文件头部还有一条醒目警告:上生产环境前必须更换该密码

backend/.env.default:关键变量逐项解读

backend/.env.default 是 Platform 本地开发的核心配置清单,按指南标注"在 settings.py 中有可用默认值的变量不在此列出"。以下摘录并解读关键分组(原文含外部网址的注释行已省略):

数据库连接(必填)

DB_USER=postgres
DB_PASS=your-super-secret-and-long-postgres-password
DB_NAME=postgres
DB_PORT=5432
DB_HOST=localhost
DB_CONNECTION_LIMIT=12
DB_CONNECT_TIMEOUT=60
DB_POOL_TIMEOUT=300
DB_SCHEMA=platform
DATABASE_URL="postgresql://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}?schema=${DB_SCHEMA}&connect_timeout=${DB_CONNECT_TIMEOUT}"
DIRECT_URL="postgresql://${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}?schema=${DB_SCHEMA}&connect_timeout=${DB_CONNECT_TIMEOUT}"
PRISMA_SCHEMA="postgres/schema.prisma"

注意 DB_SCHEMA=platform00-init.sql 注释的对应关系:docker-compose.ymldb/init/00-init.sql 挂载到 /docker-entrypoint-initdb.d/,在新卷上创建 platform schema 及兼容历史 Prisma 迁移的 auth.users 兼容表;DATABASE_URLDIRECT_URL 的区分是 Prisma 的经典做法——前者给连接池(如 PgBouncer)使用,后者给 Prisma 迁移工具直连使用。

中间件凭据(必填)

REDIS_HOST=localhost
REDIS_PORT=17000
RABBITMQ_DEFAULT_USER=rabbitmq_user_default
RABBITMQ_DEFAULT_PASS=k0VMxyIJF9S35f3x2uaw5IWAl6Y536O7

Redis 集群三节点(compose 中的 redis-0/1/2)通过 17000 端口暴露给宿主机;RabbitMQ 是异步任务处理的队列(见 backend/AGENTS.md 的 Architecture 一节)。

鉴权(JWT)

JWT_JWKS_URL=http://localhost:3000/api/auth/jwks
# JWKS_ALLOW_INSECURE_TRANSPORT=false
JWT_VERIFY_KEY=your-super-secret-jwt-token-with-at-least-32-characters-long

配置文件的注释交代了完整的安全语义:JWT_JWKS_URL 指向内嵌在前端的 Better Auth 服务的 JWKS 端点,后端用 ES256 非对称签名校验 JWT;由于"后端信任该 URL 返回的一切签名密钥",注释专门警告——本机与单主机容器间流量用 http 没问题(如默认的 http://frontend:3000),但跨机器的不可信网络上必须用 https,否则网络攻击者可替换密钥伪造令牌。为此提供 JWKS_ALLOW_INSECURE_TRANSPORT=false 开关:当 JWT_JWKS_URL 为指向非本地主机的明文 http 时,后端默认拒绝启动。JWT_VERIFY_KEY 是 HS256 共享密钥校验的遗留通道,仅用于旧 Supabase GoTrue 会话仍在流通的过渡期,之后可移除。

加密与推送(必填安全密钥)

ENCRYPTION_KEY=dvziYgz0KSK8FENhju0ZYi8-fRTfAdlz6YLhdB_jhNw=
UNSUBSCRIBE_SECRET_KEY=HlP8ivStJjmbf6NKi78m_3FnOogut0t5ckzjsIqeaio=
VAPID_PRIVATE_KEY=17hBPdSdn6TR_yAgQxA0TjTcvRj3Lf6znHnASZ4HQQNLUeiEfzD42zWSlrvY1PR12bs
VAPID_CLAIM_EMAIL=mailto:dev@example.com

注释给出了 Fernet 密钥的生成命令:from cryptography.fernet import Fernet; Fernet.generate_key().decode();VAPID 密钥对(Web Push 用)附有一段 Python 生成脚本,并明确标注"以下为仅开发用密钥,任何非本地部署前必须自行重新生成",VAPID_CLAIM_EMAIL 按 RFC 8292 在推送服务的 410 Gone 报告中被引用,生产环境应设置为真实邮箱。

AutoPilot 本地 LLM 路由(CHAT_*)

CHAT_API_KEY=
CHAT_BASE_URL=
CHAT_USE_LOCAL=false

这段注释是仓库内关于本地模型接入最完整的说明:设置 CHAT_USE_LOCAL=true 后,AutoPilot 会改走 OpenAI 兼容端点(如宿主机上 Ollama 的 http://host.docker.internal:11434/v1),CHAT_API_KEY 可为任意非空字符串;CHAT_*_MODEL 必须填本地后端提供的裸模型名(如 llama3.2:3b),OpenRouter 风格的 provider/model 前缀无法解析;扩展思考模式在该传输下会自动降级为 fast。另有一个重要的分层规则:在托管云平台(BEHAVE_AS=cloud)下,CHAT_*_MODEL 是 AutoPilot 模型解析的最底层——backend/data/llm_registry/catalog.py 中的 LLM 目录路由表与每用户 LaunchDarkly 标志优先;而在自托管安装中目录路由表被跳过,这些环境变量保持权威地位。

其余分组(backend/.env.default 全文可查)包括:Graphiti/FalkorDB 时序知识图谱内存(GRAPHITI_*)、Langfuse 提示词管理、OAuth 凭据(GitHub/Notion/Google/Twitter/Linear/Todoist/Discord/Reddit,回调统一为 <frontend_url>/auth/integrations/oauth_callback)、Stripe 支付、Postmark 邮件、Sentry、LaunchDarkly 特性开关、各媒体/搜索服务 API Key、CoPilot 聊天桥接(Discord/Slack/Telegram)以及 PostHog 分析等——全部为"按需填写、可留空"的可选项。

Docker Compose 服务拓扑:锚点复用与启动门控

docker-compose.yml 的结构本身就在演示指南所说的"YAML 锚点获得一致配置":

x-agpt-services:
  &agpt-services
  networks:
    - app-network
    - shared-network

services:
  rest_server:
    <<: *agpt-services
    extends:
      file: ./docker-compose.platform.yml
      service: rest_server

每个服务先合并 &agpt-services 锚点(统一挂载到 app-networkshared-network 两个网络),再通过 extendsdocker-compose.platform.yml 继承镜像、端口与依赖等细节。当前编排的完整服务清单为:

  • 基础设施migrate(Prisma 迁移)、redis-0/1/2 + redis-init(Redis 集群)、falkordb(Graphiti 图数据库)、rabbitmqclamavdb(Postgres + pgvector);
  • 后端进程rest_serverexecutorcopilot_executorwebsocket_serverdatabase_managerscheduler_servernotification_serverplatform_linking_manager(仅 bot profile);
  • 前端frontend
  • 本地编排辅助depsdeps_backend——仅 local profile 下生效的 busybox 服务,command: /bin/true,纯粹用 depends_on 形成依赖树,便于一次性拉起整栈并等待就绪。

两个值得注意的实现细节:

  1. db 服务的启动门控。注释说明 db 等待 rabbitmq:service_healthy 才启动,原因是 E2B 环境中并发创建容器会与 RabbitMQ 写 .erlang.cookie 竞争,导致 broker 启动时报 eacces;由于 migrate 与所有后端服务都 depends_on db:service_healthy,只门控 db 一个点就能级联到整栈。db 镜像固定为 pgvector/pgvector:pg15,注释解释:"与生产和开发所跑的托管 Postgres 大版本保持一致;测试比生产更新的版本是我们不想要的偏差"。
  2. ClamAV 服务(对应 AGENTS.md 中"Virus Scanning"概念)使用 clamav/clamav-debian:latest,暴露 3310 端口,关键限制参数为 CLAMD_CONF_StreamMaxLength=50MMaxFileSize=100MMaxScanSize=100MMaxThreads=12ReadTimeout=300,健康检查执行 clamdscan --version,扫描数据持久化到 clamav-data 卷。

常用 Make 目标

Makefile 为日常操作提供了快捷入口:

目标 作用
make start-core docker compose up -d deps,仅后台启动核心服务(Postgres/Redis/RabbitMQ 等依赖树)
make stop-core docker compose stop
make reset-db 停止 db、删除 data/db/data 卷,然后依次执行 prisma migrate deployprisma generategen-prisma-stub
make logs-core 跟踪核心服务日志
make format 后端 poetry run format + 前端 pnpm format / pnpm lint
make init-env 三层 .env.default.env 初始化(见上节)
make migrate 后端数据库迁移与 Prisma 类型生成
make run-backend cd backend && poetry run app
make run-frontend cd frontend && pnpm dev
make test-data 运行测试数据创建脚本
make load-store-agents agents/ 目录中的商店代理加载进测试库

分支策略与 Pull Request 规范

分支策略

指南将分支角色规定为两条主分支加一条例外通道:

  • dev 是主开发分支,所有 PR 都应指向 dev
  • master 是生产分支,仅用于生产发布;
  • 例外:LLM 目录的纯目录差异(仅改动 backend/data/llm_registry/catalog.py)可以走 hotfix/* 分支直接指向 master,用于事故级变更(模型下线、路由切换),合并即触发 CD 部署。完整参考文档是 docs/platform/contributing/managing-llm-models.md

PR 的 Why / What / How 结构

创建 PR 时指南要求:

  1. 按关注点拆分 PR——每个 PR 只解决一个明确问题。例如"用量跟踪"和"积分扣费"即使相关也应拆成两个 PR,混合关注点会让评审者难以判断各改动归属;
  2. 分支名要有描述性(如 feature/add-new-block);
  3. 提交信息遵循 Conventional Commits(见下节);
  4. PR 描述必须按 Why / What / How 组织——Why:动机(解决什么问题、缺了它会坏什么);What:变更的高层摘要;How:方案、关键实现细节或架构决策。评审者需要三者齐备才能判断方案是否匹配问题;
  5. 使用 --body-file 传递 PR 正文,避免 shell 对反引号与特殊字符的解释:
PR_BODY=$(mktemp)
cat > "$PR_BODY" << 'PREOF'
## Summary
- use `backticks` freely here
PREOF
gh pr create --title "..." --body-file "$PR_BODY" --base dev
rm "$PR_BODY"
  1. 运行 GitHub pre-commit hooks 保证代码质量;PR 正文使用仓库内 .github/PULL_REQUEST_TEMPLATE.md 模板。

Conventional Commits 规范

提交信息与 PR 标题统一使用以下类型:

类型 含义
feat 引入新功能
fix 修复缺陷
refactor 既非修 bug 也非加功能的重构;移除功能也归此类
ci CI 配置变更
docs 纯文档变更
dx 开发者体验改进

推荐的基础 scope 有 platform(同时影响前后端)、frontendbackendinfrablocks(单个块的增改),并可进一步使用子 scope,如 backend/executorbackend/dbfrontend/builder(含块 UI 组件变更)、infra/prod

测试驱动开发与测试约定

三步 TDD 流程

指南(autogpt_platform/AGENTS.mdbackend/AGENTS.md)对修 bug 或加功能规定了统一的 test-first 流程:

  1. 先写一个失败的测试——复现 bug 或验证新行为,后端标记 @pytest.mark.xfail、前端(Playwright)标记 .fixme,并运行确认它"因正确的原因"失败;
  2. 实现最小修复/功能让测试通过;
  3. 移除 xfail 标记,跑完整测试套件确认没有破坏其他内容。

backend/AGENTS.md 给出了具体示例:

# 1. 写一个标记 xfail 的失败测试
@pytest.mark.xfail(reason="Bug #1234: widget crashes on empty input")
def test_widget_handles_empty_input():
    result = widget.process("")
    assert result == Widget.EMPTY_RESULT

# 2. 运行它——确认失败(XFAIL)
# poetry run pytest path/to/test.py::test_widget_handles_empty_input -xvs

# 3. 实现修复
# 4. 移除 xfail 再跑——确认通过

原则是"每个 bug 修复都应附带一个本可以抓住该 bug 的测试"。

后端测试要点

  • 使用 pytest + 快照测试(API 响应),测试文件与源码同目录(*_test.py),快照存放于 backend/snapshots/
  • 首次写测试或预期输出变化时用 poetry run pytest path/to/test.py --snapshot-update 更新快照,提交前务必 git diff 复核;
  • 在"使用处"而非"定义处"打 mock,重构后同步更新 mock 目标模块路径,异步函数用 AsyncMock
  • 块(Block)有专门的验证测试:poetry run pytest backend/blocks/test/test_block.py -xvs 验证所有块正常工作,也可单独跑 test_available_blocks[GetCurrentTimeBlock] 这样的参数化用例。

前端"完工前检查"(强制)

frontend/AGENTS.md 规定:前端任何代码改动后,报告完成、提交或开 PR 之前必须按顺序执行:

  1. pnpm format —— 自动修复格式问题;
  2. pnpm lint —— 修复出现的 lint 错误;
  3. pnpm types —— 修复类型错误;
  4. pnpm test:unit —— 运行集成测试并修复失败。

任何一条报错都必须修到干净为止;若类型检查持续失败,指南要求"停下来向用户求助"而不是硬改。

架构与代码风格约定

后端架构

backend/AGENTS.md 将后端架构概括为六条:

  • API 层:FastAPI,同时提供 REST 与 WebSocket 端点;
  • 数据库:PostgreSQL + Prisma ORM,含 pgvector 向量扩展——数据模型定义在 backend/schema.prisma,关键模型包括 User(认证与档案)、AgentGraph(带版本控制的工作流定义)、AgentGraphExecution(执行历史与结果)、AgentNode(工作流中的单个节点)、StoreListing(商店上架);迁移脚本位于 backend/migrations/(百余个时间戳目录,如 20241212141024_agent_store_v2);
  • 队列系统:RabbitMQ 处理异步任务;
  • 执行引擎:独立的 executor 服务进程处理代理工作流(对应 compose 中的 executorcopilot_executor 两个服务);
  • 认证:基于 JWT,配合前端内嵌的认证服务;
  • 安全:缓存保护中间件防止敏感数据被浏览器/代理缓存——位于 backend/api/middleware/security.py,默认对所有端点下发 Cache-Control: no-store, no-cache, must-revalidate, private,采用白名单方式(CACHEABLE_PATHS)显式放行可缓存路径(静态资源、健康检查、公开商店页、文档),同时应用于主 API 与外部 API 应用。

后端代码风格

后端规范中信息密度最高的几条:

  • 仅顶层导入,禁止函数内局部导入(重型可选依赖如 openpyxl 除外);跨包用绝对导入 from backend.module import ...,同包兄弟模块允许单点相对导入,禁用双点相对导入;
  • 禁止鸭子类型——不用 hasattr/getattr/isinstance 做类型分发,改用类型化接口/联合类型/Protocol;
  • 用 Pydantic 模型而非 dataclass/namedtuple/dict 承载结构化数据;
  • 禁止 linter 抑制符——不写 # type: ignore# noqa# pyright: ignore,直接修类型/代码;
  • 日志插值分场景——debug 语句用 %s 延迟插值(logger.debug("Processing %s items", count)),其余场景用 f-string;
  • 错误信息清洗路径——用 os.path.basename() 避免泄露目录结构;
  • TOCTOU 意识——文件访问与积分扣费避免 check-then-act 模式;
  • 认证依赖用 Security() 而非 Depends(),以获得正确的 OpenAPI 安全声明;
  • Redis 管道多步操作用 transaction=True 保证原子性;
  • SSE 协议——data: 行承载前端解析的事件(须匹配 Zod schema),: comment 行承载心跳/状态;
  • 规模约束——文件控制在约 300 行内,函数约 40 行内,超限按职责拆分;主函数/类置顶,辅助函数放其下(自顶向下阅读顺序)。

前端架构与风格

frontend/AGENTS.md 描述的架构:

  • 框架:Next.js 15 App Router(client-first);
  • 数据获取:Orval + React Query 生成的类型安全 API hooks(由 pnpm generate:api 从 OpenAPI 规格生成,hook 命名模式 use{Method}{Version}{OperationName});
  • 状态管理:服务端状态交给 React Query,UI 状态就近放在组件/hooks;
  • 组件结构:渲染逻辑(.tsx)与业务逻辑(use*.ts hooks)分离;
  • 工作流编辑器:基于 @xyflow/react 的可视化图编辑器;
  • UI:shadcn/ui(Radix 原语)+ Tailwind CSS;图标仅用 Hugeicons(stroke-rounded),且必须经过 Icon 原子渲染——直接渲染 HugeiconsIcon 是禁止的,原子负责应用 2px 设计系统线宽;
  • 特性开关:LaunchDarkly 集成;
  • 错误处理分工:渲染错误用 ErrorCard,mutation 用 toast,异常上报 Sentry;
  • 测试矩阵:Vitest + React Testing Library + MSW 的集成测试为主(约 90%),Playwright 负责 E2E,Storybook 负责设计系统组件的可视化。

前端代码风格要点:符号中缩写词全大写(graphIDuseBackendAPI);组件/处理器用函数声明而非箭头函数;禁用 dark: Tailwind 类(深色模式由设计系统处理);站内跳转必须用 Next.js <Link> 而非裸 <a>;文件控制在约 200 行、渲染函数与 hook 约 50 行内;除非确实要求优化,不用 useCallback/useMemo;hook 返回值交给 TypeScript 推断而不显式标注;避免索引文件与 barrel 文件。

常见开发任务速查

指南还内嵌了三个高频任务的操作路径,均指向仓库内真实文件:

1. 新增/编辑/下线 LLM 模型 模型定义、成本与 AutoPilot 路由以"目录即代码"形式存放在 backend/data/llm_registry/catalog.py——改文件、开 PR;目录是单一事实来源,元数据与计费字典在 import 时从它派生。块可选模型还须在 backend/data/llm_registry/llm_models.py 加一行 LLMModel 名称(import 时检查强制配对);仅 copilot 用的模型只需目录条目。下线模型 = 目录 PR(is_enabled: False)+ 运行 python -m backend.data.llm_registry.retire <slug> --replacement <slug> --yes 迁移既有图节点(默认 dry-run、可回滚)。全文参考 docs/platform/contributing/managing-llm-models.md

2. 新增 Blockdocs/platform/block-sdk-guide.md 的完整流程:在 backend/blocks/ 建新文件 → 在 _config.pyProviderBuilder 配置 provider → 继承 Block 基类 → 用 BlockSchema 定义输入输出 → 实现异步 run 方法 → 用 uuid.uuid4() 生成唯一块 ID → 跑 poetry run pytest backend/blocks/test/test_block.py 验证。指南特别提醒:批量新增块时先审视各块接口在图编辑器里能否"连得起来"(输入输出是否咬合)。涉及文件处理的块应使用 store_media_file()backend.util.file),其 return_format"for_local_processing"(返回本地路径,供 ffmpeg/PIL 处理)、"for_external_api"(返回 data URI 供外部 API)、"for_block_output"(智能适配:CoPilot 下返回 workspace://,图中返回 data URI)——块输出应默认使用 for_block_output,不要手写 workspace 判断。

3. 修改 API 更新 backend/api/features/ 中的路由 → 同目录更新 Pydantic 模型 → 路由旁写测试 → poetry run test 验证。

4. 涉及工作区与媒体文件时 先读 docs/platform/workspace-media-architecture.md,它覆盖 WorkspaceManager(会话级持久化存储)、store_media_file()(媒体归一化管线)以及病毒扫描与持久化的职责边界——这与 backend/AGENTS.md 中 ClamAV 扫描、platform_linking 等服务职责互相印证。

小结

autogpt_platform 目录的开发者文档体系呈清晰的三层引用结构:CLAUDE.mdAGENTS.md(Monorepo 总览、环境配置机制、分支与 PR 规范、TDD、Conventional Commits)→ backend/AGENTS.mdfrontend/AGENTS.md(各侧命令、架构、代码风格与强制检查流程)。配合 Makefiledocker-compose.yml.env.default / backend/.env.default 等真实文件,开发者可以获得从"复制默认环境"到"跑测试、开 PR"的完整闭环;而配置加载顺序、硬编码默认值与 YAML 锚点这几条设计约定,是理解整个 Platform 自托管部署行为的关键钥匙。

登录后查看全文
热门项目推荐
相关项目推荐