这是一个面向真实落地场景的多 Agent 技术尽调与可行性分析后端项目。系统输入一个创业项目想法后,由多个专业 Agent 协作完成市场判断、MVP 范围裁剪、技术评估、财务建模、跨 artifact 一致性审查,并最终输出技术可行性分析和落地评估 brief。
项目不是普通 RAG 聊天机器人,也不是多个 prompt 串联的 demo。它重点展示 AI 应用开发中的结构化输出、Agent 编排、Skill/Tool/MCP 分层、错误分类、人工介入、恢复执行,以及后端工程化中的 API contract、异步任务、状态机、Postgres 持久化、Redis 队列、Docker Compose 部署、可观测性和告警。
flowchart LR
client["Client / 前端 / 调用方"] --> api["FastAPI API"]
api --> pg["Postgres\n运行状态事实源"]
api --> redis["Redis\n队列 / 延迟重试 / run lock"]
redis --> worker["worker\n执行 startup / recovery job"]
worker --> runtime["Agent Runtime\nscheduler / retry / errors / status"]
runtime --> agents["Market / Product / Tech / Finance / Critic / Decision Agents"]
agents --> skills["Skill Layer"]
skills --> tools["Tool Layer"]
tools --> mcp["MCP Adapter Layer"]
agents --> deepseek["DeepSeek API"]
worker --> pg
sweeper["sweeper\n扫描 stale heartbeat"] --> pg
sweeper --> redis
api --> prometheus["Prometheus"]
prometheus --> grafana["Grafana"]
核心模块:
main.py:FastAPI 应用入口,注册 API 路由、中间件和启动校验。api/routes.py:创建 run、查询 run、resume、recover、heartbeat、metrics 等接口。worker.py:从 Redis 队列消费任务,拿 run lock,执行工作流,处理 worker-level retry。sweeper.py:扫描运行中的任务,发现 heartbeat 过期后重新入队或标记失败。runtime/:Agent 调度、状态更新、错误分类、重试、恢复计划、心跳、生命周期事件、metrics。agents/:市场、产品、技术、财务、审查、最终决策 Agent。skills/:Agent 可组合业务能力,例如市场研究、MVP 裁剪、架构评估、财务分析、一致性审查、投资决策。tools/:确定性工具,例如市场规模估算、功能优先级、技术风险、unit economics、一致性检查、技术可行性 brief。mcp_layer/:把内部 Tool 包装成 MCP 风格 tool definition 和 call result。storage/:JSON 本地仓库和 Postgres 仓库,包含轻量 migration runner。queues/:Redis 队列和 Redis run lock。monitoring/:Prometheus、Grafana dashboard 和 alert rules。
复制环境变量文件:
copy .env.example .env.env.example 只用于本地开发和演示。公网 SaaS 部署前请参考 .env.production.example、.env.staging.example 和 docs/production_config.md,真实密钥不要提交到仓库,应由 Secret Manager、CI/CD secret 或部署平台环境变量注入。
本地开发可以使用 JSON repository:
APP_ENV=local
REPOSITORY_BACKEND=json
DEEPSEEK_API_KEY=你的_deepseek_key
安装依赖:
pip install -r requirements.txt启动 API:
uvicorn main:app --reload如果要测试异步队列模式,需要启动 Redis,并分别启动 worker 和 sweeper:
python worker.py
python sweeper.py运行测试:
python -m pytest -q部署前预检查:
python scripts/preflight.py公网 SaaS 上线配置审计:
set -a; . ./.env.production; set +a; python scripts/production_audit.py生产发布顺序建议固定为:
migration -> production_audit -> compose_config -> start_services -> smoke -> smoke_staging -> smoke_prod -> smoke_tenant_control -> smoke_rejection -> rollback_ready
也就是先执行数据库 migration:
python scripts/migrate.py再执行 set -a; . ./.env.production; set +a; python scripts/production_audit.py,然后启动 API、worker、sweeper,最后运行 python scripts/smoke_test.py。如果使用生产 Docker Compose,可以在启动服务前运行:
make public-compose-config
docker compose --env-file .env.production -f docker-compose.yml -f docker-compose.prod.yml -f docker-compose.public.yml run --rm api python scripts/migrate.py发布清单已经固化在 docs/release_checklist.md,上线前可以执行静态门禁,确认 migration、生产审计、compose 配置、服务启动、smoke、生产 smoke、单租户 run 创建止损、429 拒绝链路和 rollback 准备都没有漏项:
make release-check预发环境可以使用 staging release gate 把本地静态门禁和黑盒 smoke gate 串成固定顺序。默认命令只打印 dry-run 计划,不执行任何操作:
make staging-release-plan
python scripts/staging_release_gate.py确认 .env.production 中的生产静态审计配置已就绪,.env.staging.example 已复制为 .env.staging 并由 Secret Manager 注入真实 staging smoke 值,且 SMOKE_EXPECT_TENANT_CONTROL_GATE=1、SMOKE_PLATFORM_OPERATOR_API_KEY、SMOKE_API_KEY 指向专用 smoke tenant 后,再执行:
make staging-release-gate
python scripts/staging_release_gate.py --execute这个 gate 会按顺序执行 release-plan -> production_audit -> preflight -> release-check -> smoke-staging。其中 production_audit 显式读取 .env.production,smoke-staging 显式读取 .env.staging;执行结果会对 smoke/API/operator 相关密钥做脱敏,失败时停在第一个失败步骤,避免后续 smoke 继续制造额外流量。
依赖版本固定是生产部署门禁之一。requirements.txt 中的直接依赖必须使用 == 固定版本,production_audit.py 会检查该要求,避免每次镜像构建时解析到不可预期的新版本。
GitHub Actions 已配置 CI 门禁:每次 push 或 pull request 会安装固定依赖、运行 python -m pytest -q、执行 python scripts/production_audit.py,最后执行 python scripts/preflight.py。这保证安全配置、依赖固定、Docker Compose 配置和测试不会只依赖本地手工检查。
生产审计还包含 repository tenant guard:PostgresWorkflowRepository 的关键查询方法必须提供 tenant-aware 查询或显式 tenant filter,例如 load_run_for_tenant、list_runs(tenant_id=...)、list_usage_ledger(tenant_id=...)、list_api_keys(tenant_id=...)。这一步不能替代 Postgres RLS,但可以防止后续开发时把跨租户查询能力误暴露给 API 层。
真实 Postgres 生产环境可以继续按 docs/postgres_rls.md 启用数据库层行级安全,SQL 模板见 db/postgres_rls.sql。RLS 与 repository tenant guard 是两层防线:前者在数据库层隔离数据,后者在应用层阻止危险查询路径进入 API。
创建数据库模式 API key。该命令只会在终端输出一次明文 key,数据库只保存 hash:
python scripts/create_api_key.py `
--tenant-id demo-tenant `
--scope admin `
--key-id demo-admin-key `
--note "initial admin key"生成 Postgres 备份或恢复命令。脚本只输出命令计划,不直接执行生产备份/恢复:
python scripts/postgres_backup.py --mode backup --file backups/agent.dump
python scripts/postgres_backup.py --mode restore --file backups/agent.dump如果本地安装了 make,也可以使用:
make verify服务启动后的 smoke test:
python scripts/smoke_test.py如果 API 启用了 API_KEY,需要设置:
$env:SMOKE_API_KEY="your_api_key"生产模式下 smoke test 还应该验证 Prometheus metrics token、平台队列接口和 docs 关闭策略:
$env:SMOKE_BASE_URL="https://api.acme-corp.com"
$env:SMOKE_METRICS_API_KEY="your_metrics_key"
$env:SMOKE_PLATFORM_OPERATOR_API_KEY="your_platform_operator_key"
$env:SMOKE_EXPECT_PRODUCTION_DOCS_CLOSED="1"
python scripts/smoke_test.py生产模式 smoke 要求 SMOKE_BASE_URL 是真实 https:// 公网 DNS 地址,不能使用 localhost、IP 地址或 example.com 模板域名。脚本会检查 /api/metrics/prometheus 带 metrics token 时是否包含 agent_queue_ready_jobs、agent_worker_jobs_total、agent_sweeper_dispatch_failures_total 和 agent_sweeper_version_conflicts_total,并验证无 token 访问会返回 401/403;同时检查 /api/admin/queues 是否返回 ready、processing、delayed,并在创建 run 时携带 Idempotency-Key,避免 smoke test 重试造成重复任务。
发布窗口或预发环境还可以打开维护模式 smoke gate,用来验证平台可以暂停新 run、暴露维护指标、记录审计事件,并在关闭维护后恢复创建:
$env:SMOKE_PLATFORM_OPERATOR_API_KEY="your_platform_operator_key"
$env:SMOKE_EXPECT_MAINTENANCE_GATE="1"
$env:SMOKE_MAINTENANCE_TENANT_ID="tenant_maintenance_smoke"
python scripts/smoke_test.py该 gate 会调用 /api/admin/maintenance 开启维护模式,确认 POST /api/startup/runs 返回 maintenance_mode_enabled,检查 /api/metrics/prometheus 中的 agent_maintenance_mode_enabled 和 agent_maintenance_run_rejections_total,再通过 /api/admin/audit-events 确认 maintenance.run_rejected,最后关闭维护模式并创建一个正常 run。
预发环境还可以执行单租户 run 创建止损 smoke gate,用来验证平台 operator 可以暂停某个专用 smoke tenant 创建新 run,并在验证后恢复:
$env:SMOKE_PLATFORM_OPERATOR_API_KEY="your_platform_operator_key"
$env:SMOKE_EXPECT_TENANT_CONTROL_GATE="1"
$env:SMOKE_TENANT_CONTROL_TENANT_ID="tenant_control_smoke"
python scripts/smoke_test.py该 gate 会调用 /api/admin/tenants/{tenant_id}/run-creation-control 开启暂停,确认 POST /api/startup/runs 返回 tenant_run_creation_suspended,检查 /api/metrics/prometheus 中的 agent_tenant_run_creation_suspended 和 agent_tenant_run_creation_rejections_total,再通过 /api/admin/audit-events 确认 tenant.run_creation_rejected。最后脚本会关闭暂停并创建一个正常 run,避免预发租户被长期锁住。正式生产环境不要对真实客户 tenant 执行这个 gate,只能使用专用 smoke tenant。
也可以使用:
make smoke生产化演示建议使用 Docker Compose,因为它会同时启动 API、worker、sweeper、Postgres、Redis、Prometheus 和 Grafana。
准备 .env:
copy .env.example .envDocker 环境至少需要配置:
DEEPSEEK_API_KEY=你的_deepseek_key
API_KEY_AUTH_BACKEND=database
METRICS_API_KEY=你的_metrics_key
PLATFORM_OPERATOR_API_KEY=你的_platform_operator_key
CORS_ALLOWED_ORIGINS=https://app.example.com,https://admin.example.com
TRUSTED_HOSTS=api.example.com
GRAFANA_ADMIN_PASSWORD=你的_grafana_强密码
DEEPSEEK_BASE_URL=https://api.deepseek.com
DEEPSEEK_MODEL=deepseek-chat
DEEPSEEK_INPUT_TOKEN_PRICE_PER_1K=0
DEEPSEEK_OUTPUT_TOKEN_PRICE_PER_1K=0
DEEPSEEK_TIMEOUT_SECONDS=60
DEEPSEEK_MAX_CONCURRENCY=4
DEEPSEEK_CIRCUIT_BREAKER_FAILURE_THRESHOLD=5
DEEPSEEK_CIRCUIT_BREAKER_RECOVERY_SECONDS=60
POSTGRES_POOL_SIZE=5
POSTGRES_MAX_OVERFLOW=10
POSTGRES_POOL_RECYCLE_SECONDS=1800
REDIS_SOCKET_TIMEOUT_SECONDS=5
REDIS_HEALTH_CHECK_INTERVAL_SECONDS=30
API_PROCESS_MODEL=gunicorn
API_BIND=0.0.0.0:8000
API_WORKERS=2
API_TIMEOUT_SECONDS=120
API_GRACEFUL_TIMEOUT_SECONDS=30
API_KEEP_ALIVE_SECONDS=5
API_MAX_REQUEST_BODY_BYTES=1048576
公网 .env.production 不要加入 localhost、127.0.0.1、通配符或 URL origin 到 TRUSTED_HOSTS;本地调试域名只应留在本地 .env.example。
按需开启高并发控制:
WORKER_CONCURRENCY=2
WORKER_TENANT_INFLIGHT_LIMIT=2
API_RATE_LIMIT_PER_MINUTE=120
TENANT_RUN_QUOTA_PER_DAY=50
TENANT_MONTHLY_RUN_QUOTA=1000
TENANT_MONTHLY_TOKEN_QUOTA=5000000
TENANT_MONTHLY_COST_QUOTA_USD=50
如果只是本地演示,可以继续使用 API_KEY_AUTH_BACKEND=env、API_KEY 和 API_KEY_TENANT_MAP;公网 SaaS 上线前应使用 database-backed API key,并通过 python scripts/create_api_key.py 创建初始 admin key。
启动完整服务:
docker compose up --build公网 SaaS 部署不要直接使用本地 demo 配置。生产环境应叠加 docker-compose.prod.yml,它会把服务切到 APP_ENV=production、强制使用 database-backed API key、要求 Secret Manager 注入关键密钥,并清除 Postgres、Redis、Prometheus、Grafana 的本地端口暴露:
docker compose --env-file .env.production -f docker-compose.yml -f docker-compose.prod.yml -f docker-compose.public.yml config --quiet
docker compose --env-file .env.production -f docker-compose.yml -f docker-compose.prod.yml -f docker-compose.public.yml up --build生产 override 同时配置 restart: unless-stopped 和 API/worker/sweeper 的 stop_grace_period,让异常退出可以自动拉起,滚动发布时也能给 readiness draining、worker 当前 batch 和 sweeper 当前扫描留下退出时间。它还为公网容器配置 security_opt: no-new-privileges:true、cap_drop: ALL、pids_limit 和 mem_limit,降低小服务器上进程逃逸、fork 炸弹和单容器内存打满的风险。生产 compose 校验使用 config --quiet,只验证配置可渲染,不把注入后的密钥打印到 CI 或发布日志。
服务地址:
- API:
http://localhost:8000 - API Docs:
http://localhost:8000/docs - Prometheus:
http://localhost:9090 - Grafana:
http://localhost:3000 - Postgres:
localhost:5432 - Redis:
localhost:6379
创建异步技术可行性分析任务:
curl -X POST http://localhost:8000/api/startup/runs `
-H "Content-Type: application/json" `
-H "X-API-Key: your_api_key" `
-H "Idempotency-Key: tenant_a_create_run_001" `
-d "{\"user_input\":\"给独立开发者做一个 AI 技术可行性分析工具\",\"user_id\":\"demo-user\"}"公网客户端创建 run 时建议总是传 Idempotency-Key。如果客户端超时后用同一个 key 重试,API 会返回已经创建过的 run,不会重复创建工作流、重复入队,也不会重复扣减月度 run 配额。
异步创建链路会先把 queued run 持久化到 Postgres,持久化成功后才写入 Redis 队列。这样 worker 不会拿到数据库里还不存在的 run;如果数据库保存失败,请求会直接失败且不会产生孤儿队列任务。
查询 run:
curl http://localhost:8000/api/runs/{run_id} -H "X-API-Key: your_api_key"恢复执行:
curl -X POST http://localhost:8000/api/runs/{run_id}/resume `
-H "Content-Type: application/json" `
-H "X-API-Key: your_api_key" `
-d "{\"from_agent\":\"tech\"}"触发恢复任务:
curl -X POST http://localhost:8000/api/runs/{run_id}/recover -H "X-API-Key: your_api_key"Prometheus 指标:
curl http://localhost:8000/api/metrics/prometheus `
-H "X-Metrics-API-Key: your_metrics_key"队列运维状态,只允许 platform operator token 调用:
curl http://localhost:8000/api/admin/queues `
-H "X-Platform-API-Key: your_platform_operator_api_key"暂停或恢复单个租户创建新 run,只允许 platform operator token 调用:
curl -X POST http://localhost:8000/api/admin/tenants/{tenant_id}/run-creation-control `
-H "X-Platform-API-Key: your_platform_operator_api_key" `
-H "Content-Type: application/json" `
-d "{\"run_creation_suspended\":true,\"reason\":\"cost anomaly investigation\"}"查询当前租户 API key 元数据,不返回明文或 hash:
curl http://localhost:8000/api/admin/api-keys `
-H "X-API-Key: your_admin_api_key"创建新的 database-backed API key。响应里的 api_key 只出现一次:
curl -X POST http://localhost:8000/api/admin/api-keys `
-H "Content-Type: application/json" `
-H "X-API-Key: your_admin_api_key" `
-d "{\"key_id\":\"tenant-member-key\",\"scope\":\"member\",\"note\":\"member service key\"}"禁用或轮换 API key:
curl -X POST http://localhost:8000/api/admin/api-keys/{key_id}/disable `
-H "Content-Type: application/json" `
-H "X-API-Key: your_admin_api_key" `
-d "{\"reason\":\"leaked key response\",\"confirm_key_id\":\"{key_id}\"}"
curl -X POST http://localhost:8000/api/admin/api-keys/{key_id}/rotate `
-H "Content-Type: application/json" `
-H "X-API-Key: your_admin_api_key" `
-d "{\"new_key_id\":\"tenant-member-key-v2\",\"scope\":\"member\",\"note\":\"rotated service key\",\"reason\":\"scheduled key rotation\",\"confirm_key_id\":\"{key_id}\"}"当前租户用量统计:
curl http://localhost:8000/api/tenant/usage `
-H "X-API-Key: your_api_key"当前租户用量账本:
curl http://localhost:8000/api/tenant/usage-ledger `
-H "X-API-Key: your_api_key"当前租户配额状态:
curl http://localhost:8000/api/tenant/quota `
-H "X-API-Key: your_api_key"系统包含 agent-level retry、worker retry、Redis run lock、heartbeat、stale job sweeper、recovery plan、resume workflow、human review request、结构化日志和 Prometheus 指标。
租户隔离第一版:
- 创建 run 时写入
tenant_id。 - 生产推荐使用
API_KEY_TENANT_MAP把 API key 绑定到 tenant,认证中间件会把租户写入request.state.tenant_id。 API_KEY_TENANT_MAP兼容旧格式{"key":"tenant"},也支持结构化格式{"key":{"tenant_id":"tenant","scope":"admin","key_id":"key_admin"}}。- API key scope 第一版支持
admin、member、read_only;创建 run、同步 run、resume、recover 需要写权限,read_only只能查询。 - API key 认证支持
API_KEY_AUTH_BACKEND=env和API_KEY_AUTH_BACKEND=database两种模式;env保留本地和演示兼容,database会从 Postgresapi_keys表读取 hash 后的 key,不在数据库保存明文 API key。 api_keys表包含key_id、key_hash、tenant_id、scope、enabled、expires_at、note、created_at和last_used_at;认证成功后只把key_id写入审计日志,便于禁用、过期、轮换和追踪 key 使用。- 使用 database 认证模式时,可以通过
python scripts/create_api_key.py --tenant-id <tenant> --scope admin --key-id <key_id>创建初始 key;终端输出的api_key只出现一次,需要由运维保存到调用方密钥管理系统。 - 管理 API 提供
/api/admin/api-keys、/api/admin/api-keys/{key_id}/disable和/api/admin/api-keys/{key_id}/rotate,支持列出 key 元数据、创建 key、禁用 key、轮换 key;这些接口只允许adminscope 调用,并且不会返回key_hash。 - 禁用和轮换 API key 必须在请求体中提供
reason和confirm_key_id,该原因会进入audit_events.details;confirm_key_id必须等于路径中的 key_id,系统也会拒绝禁用或轮换当前请求正在使用的 key,避免管理员把当前会话锁死后无法继续恢复。 - 查询 run 列表时按认证后的 tenant 过滤;未启用 API key 时,本地开发仍可用
X-Tenant-ID兼容调试。 - 查询、resume、recover 单个 run 时校验 run 所属租户,不匹配返回 404。
- 创建 run 时优先使用认证后的 tenant,防止客户端通过 body 里的
tenant_id伪造租户;未启用认证时才使用请求里的租户字段兼容本地开发。 - repository 提供 tenant-aware load 方法,API 查询单个 run 时优先在 repository 层按
run_id + tenant_id读取,减少业务层漏校验风险。 - Postgres repository 会在已知 tenant 的业务操作前调用
_set_tenant_context,通过set_config('app.current_tenant_id', tenant_id, true)设置事务级 RLS 上下文;SQLite 本地测试会自动跳过。 - API key 认证发生在识别 tenant 之前,PostgreSQL 生产路径会通过
db/postgres_auth_lookup.sql中的resolve_api_key_principalSECURITY DEFINER函数解析最小 principal,避免普通 RLS tenant context 无法用于认证入口的问题。 - Postgres repository 已把
tenant_id提升为runs.tenant_id明确列,并创建(tenant_id, updated_at)索引,列表查询可以在数据库层按租户过滤。 - 未传租户信息时使用
default租户,兼容本地开发和旧测试数据。 - 生产环境会收紧公开路径,
/docs、/openapi.json和/api/metrics/prometheus不再作为默认公开路径。 /api/metrics/prometheus支持独立METRICS_API_KEY,生产环境必须配置;调用方需要通过X-Metrics-API-Key或Authorization: Bearer <token>传入,避免运行指标在公网裸露。/api/metrics是 tenant-scoped JSON metrics,只聚合当前租户 runs;/api/metrics/prometheus是全局运维采集入口,必须使用独立 metrics token,不复用普通租户 API key。- 启用 Postgres RLS 后,普通
/api/metrics使用app.current_tenant_id的租户上下文;Prometheus 全局指标使用显式list_ops_metric_runs/load_ops_metric_run和_set_platform_ops_context设置app.platform_ops,配合platform_ops_read_runs只读 policy,避免普通租户接口复用全局读取路径。 /api/admin/queues是平台级运维接口,只允许PLATFORM_OPERATOR_API_KEY通过X-Platform-API-Key或Authorization: Bearer <token>调用,不复用普通租户adminscope;它会返回 Redis ready、processing、delayed 队列数量,用于判断 worker 是否积压、是否有任务卡在 processing、是否有大量延迟重试。/api/admin/tenants/{tenant_id}/run-creation-control是租户级止损接口,只允许 platform operator 调用。开启后该租户创建 run 会返回tenant_run_creation_suspended,不会保存 run、不会写 Redis 队列、不会预扣月度 run quota;每次切换写入platform.tenant_control.updated,拒绝创建写入tenant.run_creation_rejected。- Redis ready queue 支持轻量 tenant fairness:worker 记录
last_dequeued_tenant,如果队首还是同一租户,会向后扫描一小段 ready jobs,优先取另一个租户的任务,避免单个租户短时间提交大量任务时压住其他租户。 - Redis dequeue 还支持
WORKER_TENANT_INFLIGHT_LIMIT:生产环境要求显式设置正数;当某个 tenant 的 processing job 数量达到阈值时,worker 会跳过该 tenant 的 ready job,优先领取其他 tenant 的任务,避免单租户占满全部 worker in-flight 容量。 - malformed/poison Redis job 会进入 dead-letter queue,不会反复回到 ready queue 占用 worker;Prometheus 暴露
agent_queue_dead_letter_jobs和agent_queue_dead_letter_latest_reason_info,告警为AgentQueueDeadLetterDetected。 /api/admin/audit-events只允许adminscope 调用,会返回当前租户的audit_events持久化审计事件,用于追踪 API key 创建、禁用、轮换、配额拒绝和 metrics 未授权访问;limit会在 API 层限制到 1 到 500,避免一次查询拉取过多审计数据。audit_events表会记录tenant_id、api_key_id、权限 scope、事件类型、资源 ID、request_id、客户端 IP 和脱敏后的 details;不会保存 API key 明文、Authorization、Cookie、DeepSeek key 等敏感字段。- API 结构化日志会记录
tenant_id、auth_scope、api_key_id、path、status_code、run_id 和 request_id,便于审计谁在什么租户下访问了什么资源;日志只记录 key_id,不记录 API key 明文。 - API 错误响应和结构化日志会递归脱敏
Authorization、X-API-Key、cookie、token、secret、password 等敏感字段。 - API 支持
CORS_ALLOWED_ORIGINS和TRUSTED_HOSTS两个公网边界配置;生产环境必须显式配置允许的前端域名和 API Host,避免任意 Origin 或异常 Host 访问。 - 创建 run 的
user_input和metadata有长度和类型限制,避免超大请求打爆 prompt、日志和数据库。
高并发控制第一版:
- API 支持按
X-Tenant-ID做 Redis 计数限流,API_RATE_LIMIT_PER_MINUTE控制每个租户每分钟最多请求数。 - API 容器通过
python scripts/start_api.py启动,Docker Compose 默认使用gunicorn + uvicorn worker生产进程模型,不再直接用单进程uvicorn作为容器主进程。 API_PROCESS_MODEL支持uvicorn和gunicorn;本地开发默认uvicorn,production 启动校验要求必须使用gunicorn。API_WORKERS控制 API worker 进程数,API_TIMEOUT_SECONDS控制单个请求最长执行时间,API_GRACEFUL_TIMEOUT_SECONDS控制优雅退出等待时间,API_KEEP_ALIVE_SECONDS控制连接 keep-alive。API_MAX_REQUEST_BODY_BYTES控制 API 请求体最大字节数;超过上限的请求会在中间件层返回 413。该限制同时覆盖带Content-Length和无Content-Length的流式请求,避免超大 body 进入 Pydantic、prompt 拼接、日志和数据库写入链路。- Postgres engine 配置了连接池参数,
POSTGRES_POOL_SIZE、POSTGRES_MAX_OVERFLOW和POSTGRES_POOL_RECYCLE_SECONDS用于控制连接数量、溢出连接和连接回收。 - Redis client 配置了 socket timeout 和 health check interval,
REDIS_SOCKET_TIMEOUT_SECONDS和REDIS_HEALTH_CHECK_INTERVAL_SECONDS用于避免 Redis 异常时请求长期挂起。 - 创建分析任务接口支持每日 run 配额,
TENANT_RUN_QUOTA_PER_DAY控制每个租户每天最多创建多少个 run。 - 创建 run 前会做月度租户配额校验,
TENANT_MONTHLY_RUN_QUOTA控制每月最多 run 数,TENANT_MONTHLY_TOKEN_QUOTA控制每月最多 token 数,TENANT_MONTHLY_COST_QUOTA_USD控制每月最多估算成本。 - 月度配额命中后 API 会返回
429 tenant_quota_exceeded,并且不会创建 run、不会保存初始状态、不会写入 Redis 队列,避免超额任务进入 worker。 - worker 支持本地并发消费,
WORKER_CONCURRENCY控制单个 worker 进程同时处理多少个 Redis job。 WORKER_TENANT_INFLIGHT_LIMIT控制单个 tenant 同时处于 Redis processing set 的 worker job 数;本地默认0表示不启用,production 启动校验要求必须设置为正数。- 默认值都是保守配置:限流、配额和 tenant in-flight 限制默认为
0,表示本地开发不启用;worker 默认并发为1,保持旧行为。 - Redis job 会携带
tenant_id,延迟重试会保留该租户信息。 - Redis run lock 使用
agent:tenant:{tenant_id}:lock:run:{run_id}命名空间,即使多个 worker 或高并发 batch 拿到同一个 run,也只有对应租户下的一个执行者能真正处理该 run。 - worker 运行期间会随着 heartbeat 刷新 Redis run lock TTL,避免长任务超过锁 TTL 后被其他 worker 重复执行。
- 当前队列入口仍是全局 worker queue,便于 worker 统一消费所有租户任务;后续如果要做租户优先级或独立 worker pool,可以再拆成 tenant queue。
/api/tenant/usage会按当前租户聚合 run 数、Agent 调用次数、失败次数、重试次数、人工介入次数和估算成本。- DeepSeek provider 会记录
prompt_tokens、completion_tokens和total_tokens,Agent 输出会把这些信息写入_provider_usage,最终进入 trace。 - DeepSeek 调用配置了显式 timeout,
DEEPSEEK_TIMEOUT_SECONDS控制单次请求最长等待时间;worker 内部通过DEEPSEEK_MAX_CONCURRENCY限制同时调用大模型的数量,避免高并发下外部 provider 拖垮 worker。 - DeepSeek provider 增加 circuit breaker;
DEEPSEEK_CIRCUIT_BREAKER_FAILURE_THRESHOLD控制连续 provider 请求失败多少次后打开熔断,DEEPSEEK_CIRCUIT_BREAKER_RECOVERY_SECONDS控制恢复窗口。熔断打开后会快速失败,避免 worker 继续堆积外部模型请求。 /api/tenant/usage如果发现 trace 中有 provider token usage,会优先按真实 token 聚合,并使用DEEPSEEK_INPUT_TOKEN_PRICE_PER_1K和DEEPSEEK_OUTPUT_TOKEN_PRICE_PER_1K分别计算输入/输出成本。- scheduler 会把每次带
_provider_usage的 Agent 调用追加到_usage_ledger,Postgres repository 保存 run 时会同步到独立usage_ledger表。 /api/tenant/usage-ledger会按当前租户返回每次 Agent 调用的 token 和成本账本明细,可用于账单对账、配额扣减和成本审计。/api/tenant/quota会返回当前租户的月度 run、token、成本配额状态,包括已用量、上限、剩余额度和是否允许继续创建任务。- 当前只支持单个大模型 provider:DeepSeek。成本金额按本地配置单价换算,不等同于 DeepSeek 官方账单;如果要做真实商业账单,下一步需要做价格同步和账单对账。
这仍然不是完整企业级租户体系。生产 SaaS 还需要用户/组织表、权限角色、Postgres RLS 行级安全、租户独立队列或优先级队列、跨实例 worker autoscaling、请求排队优先级和租户级成本账单。
重试逻辑分层:
- Agent 内部失败:scheduler 根据错误分类原地重试当前 Agent。
- Worker 失败:worker 根据 run retry 配置延迟重新入队。
- Worker 异常退出:sweeper 根据 heartbeat 判断 stale job 并重新入队。
- 结果不可信:quality eval 或 critic 可触发 human review。
- 需要回滚:resume workflow 会清理下游 artifact、trace、错误和 retry 状态。
这个项目可以重点讲四件事:
- 自研多 Agent runtime,不依赖 LangGraph,能解释调度、join rule、retry、resume 和 recovery。
- Agent 不是纯 prompt,而是
Agent -> Skill -> Tool -> MCP分层,工具证据会进入_skill_outputs和_tool_evidence。 - 后端不是 demo:API、worker、Redis、Postgres、run lock、heartbeat、sweeper、metrics、Grafana、CI 和 Docker Compose 都完整。
- 项目定位是技术尽调与可行性分析,最终输出
_technical_feasibility_brief,更适合展示 AI 应用工程化能力。
详细上线 runbook 见 docs/runbook.md,备份与恢复策略见 docs/backup_recovery.md。
常见问题:
- API 无法启动:检查
.env、DEEPSEEK_API_KEY、REPOSITORY_BACKEND、DATABASE_URL。 - worker 不消费:检查 Redis 是否启动、
REDIS_URL是否正确、队列是否有任务。 - run 卡在 running:检查 heartbeat、sweeper 日志和
/api/runs/{run_id}/recovery-plan。 - 结构化输出失败:查看
_agent_retries、errors和_traces。 - Docker Compose 失败:生产排障先运行
docker compose --env-file .env.production -f docker-compose.yml -f docker-compose.prod.yml -f docker-compose.public.yml config --quiet和python scripts/preflight.py。quiet 模式只校验配置,不把环境变量渲染结果打印到日志。
推荐上线前执行:
set -a; . ./.env.production; set +a; python scripts/production_audit.py
python scripts/preflight.py
python -m pytest -q
docker compose --env-file .env.production -f docker-compose.yml -f docker-compose.prod.yml -f docker-compose.public.yml config --quiet生产默认 smoke test 不会主动制造 429,因为这会依赖线上套餐/配额配置,并可能创建额外任务。预发或 staging 环境可以显式打开 tenant rejection smoke gate:
$env:SMOKE_EXPECT_TENANT_REJECTION="1"
$env:SMOKE_REJECTION_TENANT_ID="tenant_smoke_rejection"
python scripts/smoke_test.py打开后,scripts/smoke_test.py 会使用 Idempotency-Key 创建一次允许的 run,再创建第二次并期待 429。它会验证 agent_tenant_quota_rejections_total 或 agent_tenant_rate_limit_rejections_total 出现在 /api/metrics/prometheus,并通过 /api/admin/audit-events 确认存在 quota.rejected 或 rate_limit.rejected 审计事件。
这个 gate 建议只在专用租户和低日级 run quota 的预发环境使用,例如把该租户所在环境的 TENANT_RUN_QUOTA_PER_DAY 配成 1。生产正式租户不要用这个 gate 制造拒绝流量。
仓库提供 .env.staging.example 作为预发环境模板,已经包含 TENANT_RUN_QUOTA_PER_DAY=1、SMOKE_EXPECT_TENANT_REJECTION=1 和 SMOKE_REJECTION_TENANT_ID。实际部署时仍然要从 Secret Manager 注入真实 SMOKE_API_KEY、SMOKE_METRICS_API_KEY 和 SMOKE_PLATFORM_OPERATOR_API_KEY。
常用 smoke 命令已经收敛到 Makefile:
make smoke
make smoke-prod
make prepare-smoke-env
make smoke-prod-env
make smoke-rejection
make smoke-maintenance
make smoke-tenant-control
make smoke-staging
make production-init-check
make public-launch-check
make public-compose-config
make public-migrate
make public-up
make release-check
make release-plan
make staging-release-plan
make staging-release-gatemake smoke:普通服务启动烟测。make smoke-prod:带SMOKE_EXPECT_PRODUCTION_DOCS_CLOSED=1,用于生产模式验证/docs和/openapi.json默认关闭;需要先设置真实 HTTPSSMOKE_BASE_URL。make prepare-smoke-env:从.env.production和首个 tenant API key 生成.env.smoke.production,供公网生产 smoke 使用。make smoke-prod-env:加载.env.smoke.production后执行生产公网 smoke,避免在命令行手写 metrics/operator 密钥。make smoke-rejection:带SMOKE_EXPECT_TENANT_REJECTION=1,用于预发环境验证 429、Prometheus tenant rejection 指标和审计事件。make smoke-maintenance:带SMOKE_EXPECT_MAINTENANCE_GATE=1,用于发布窗口或预发环境验证维护模式开关、503 拒绝、Prometheus maintenance 指标、审计事件和恢复创建。make smoke-tenant-control:带SMOKE_EXPECT_TENANT_CONTROL_GATE=1,用于预发环境验证单租户 run 创建止损、Prometheus tenant control 指标、审计事件和恢复创建。make smoke-staging:预发环境一键黑盒门禁,顺序执行生产 docs/metrics gate、维护模式 gate、tenant control gate 和 tenant rejection gate,减少发布前漏跑某个 smoke 步骤的风险。make production-init-check:离线检查.env.production,拒绝占位符、默认密码、过短密钥、非生产模式和不一致的公网域名边界。make public-launch-check:检查单机公网部署 contract,确认docker-compose.public.yml、Nginx TLS 反代模板、部署文档和 Makefile 命令一致。make public-compose-config:使用.env.production静默校验docker-compose.yml、docker-compose.prod.yml和docker-compose.public.yml三层叠加,确认公网只暴露 Nginx 80/443。make public-migrate:使用.env.production在公网部署 compose 组合下执行数据库 migration。make public-up:使用.env.production用公网部署 compose 组合启动 API、worker、sweeper、Postgres、Redis、Prometheus、Grafana 和 Nginx。make release-check:静态校验docs/release_checklist.md是否覆盖上线前必须执行的发布门禁。make release-plan:输出python scripts/release_orchestrator.py的 dry-run 发布编排计划,确认maintenance_on、queue_drain_check、smoke_staging、smoke_maintenance和maintenance_off等 gate 没有漏项。make staging-release-plan:输出python scripts/staging_release_gate.py的 dry-run 计划,不执行命令。make staging-release-gate:执行python scripts/staging_release_gate.py --execute,用于预发环境串联 production audit、preflight、release checklist 和make smoke-staging;静态生产审计读取.env.production,预发 smoke 读取.env.staging。
如果你还没有服务器,先按 docs/public_server_deploy.md 准备域名、DNS、TLS 证书和 .env.production。正式单机公网部署使用:
make public-launch-check
make generate-production-env
make production-init-check
make public-compose-config
make public-migrate
SMOKE_API_KEY="${SMOKE_API_KEY}" make prepare-smoke-env
make public-up
make smoke-prod-envmake generate-production-env now requires PUBLIC_API_HOST, CORS_ALLOWED_ORIGINS, PLATFORM_OPERATOR_ALLOWED_CIDRS, TRUSTED_PROXY_CIDRS, NGINX_GRAFANA_ALLOWED_CIDR, DEEPSEEK_API_KEY, and ALERTMANAGER_WEBHOOK_URL to be set in the shell before running it.
这一路径通过 Nginx 暴露 80/443,不直接暴露 API 8000、Postgres 5432、Redis 6379、Prometheus 9090 或 Grafana 3000。
Production smoke also checks the public Grafana subpath. When SMOKE_EXPECT_PRODUCTION_DOCS_CLOSED=1, python scripts/smoke_test.py first requires SMOKE_BASE_URL to be a real https:// public DNS URL, then requests /grafana/ and accepts 200 or 302, proving Nginx can reach Grafana without exposing port 3000.