AI 3D 短剧 Agent 工作台技术复盘:Next.js 全栈、Agent 状态机与多模型编排
项目地址:https://devflow.aiyly.com/。
它的业务目标很简单:输入小说章节或短剧文本,系统拆解角色、空间、道具、场次和分镜,再生成资产图、3D 运镜预览和图生视频任务。功能层面可以概括成“文本 -> 世界资产 -> 分镜 -> 3D 运镜 -> 视频片段”。
系统实现重点包括:Next.js 全栈架构、Route Handlers 后端接口、Prisma + MySQL 数据模型、AgentRun / AgentStep 状态机、AI Provider 抽象、Three.js 预览、任务恢复,以及 Docker + GitLab CI/CD 部署。
整体技术架构
项目是一个 Next.js 全栈应用,前端页面、服务端 API、Agent 编排、数据库访问、OAuth 登录和部署配置都在同一个工程里。
核心技术栈:
- Next.js 16 App Router
- React 19
- TypeScript
- Tailwind CSS
- Three.js
- Prisma 7
- MySQL
- Google OAuth
- Qwen 文本模型
- Doubao Seedream 图片模型
- Doubao Seedance 图生视频任务
- Docker
- GitLab CI/CD
- Nginx
整体链路如下:
1 | React 页面 |
系统按职责拆成几层:
- UI 层:负责工作台交互、任务进度展示、资产编辑和 3D 预览。
- API 层:使用 Next Route Handlers 承接登录、剧本解析、生成任务、Agent 执行和资产管理。
- Agent 层:负责任务计划、步骤执行、状态流转、人工确认和失败重试。
- Provider 层:屏蔽不同 AI 模型的请求参数、返回结构和错误处理。
- Data 层:用 Prisma + MySQL 持久化用户、任务、资产、分镜和 Agent 状态。
- Deploy 层:使用 Docker 镜像、migrator 镜像、GitLab CI/CD 和 Nginx 发布到生产环境。
前端:App Router 下的工作台式页面组织
这个项目不是营销页,而是偏工具型的工作台,所以前端信息架构按“主流程 + 可插入工具”组织。
主要页面包括:
/:产品入口和主流程说明。/agent:Agent 导演台,创建和执行 AgentRun。/scripts:剧本解析工作台。/scripts/[id]/world:世界资产编辑页面。/storyboard-3d:3D 运镜预览器。/generate:图片和视频生成工作台。/login:Google OAuth 登录入口。/about:项目架构介绍。
前端比较关键的不是 UI 本身,而是状态展示方式。Agent 任务不是一次请求立即返回结果,而是分步骤执行,所以页面需要展示:
- 当前 AgentRun 状态。
- 每个 AgentStep 的状态。
- 正在执行的步骤。
- 等待用户确认的步骤。
- 失败步骤和错误信息。
- 可重试入口。
- 已生成的中间产物。
这类页面不能只靠一个简单 loading。它更像任务控制台,需要把后端状态机完整映射到前端。
后端:Route Handlers 作为 BFF 和任务入口
项目后端没有单独起 Express 或 Nest 服务,而是使用 Next.js Route Handlers。
这种选择的好处是:
- 页面和 API 可以共享 TypeScript 类型。
- 服务端代码可以直接访问 Prisma、Cookie、环境变量和 Provider。
- 部署时可以走 Next standalone 镜像。
- 对个人项目来说工程复杂度更低。
典型 API 包括:
POST /api/agent/runs:创建 AgentRun 和 AgentStep。POST /api/agent/runs/[id]/start:启动 Agent 执行。POST /api/agent/steps/[id]/confirm:确认等待中的步骤。POST /api/agent/steps/[id]/retry:重试失败步骤。POST /api/scripts/analyze:解析剧本。POST /api/scripts/novel/condense:精简小说。POST /api/scripts/novel/to-script:小说转短剧剧本。POST /api/world/assets/[id]/generate-image:生成世界资产图。POST /api/world/storyboards/[id]/generate-image:生成分镜图。POST /api/world/storyboards/[id]/sync-video:同步视频结果。GET /api/auth/me:读取当前登录用户。
Route Handler 里会做几件事:
- 读取并校验请求参数。
- 通过 Cookie Session 获取当前用户。
- 调用 Prisma 查询或写入数据库。
- 调用 Agent executor 或 AI Provider。
- 返回结构化 JSON 给前端。
API Key、模型调用、文件转存都只在服务端发生,前端不直接接触模型密钥。
数据建模:把 AI 过程拆成可恢复的业务对象
AIGC 项目如果只保存最终图片或视频,很快会遇到两个问题:
- 中间过程不可追踪。
- 失败后只能重来。
所以这个项目的数据库设计重点不是“保存结果”,而是“保存生成过程”。
核心模型包括:
| 模型 | 作用 |
|---|---|
User |
用户、登录身份和额度余额 |
GenerationJob |
图片生成、图片编辑等生成任务 |
GenerationCandidate |
一次生成返回的候选结果 |
Asset |
图片、视频等统一资产 |
AssetVersion |
图生图或二次编辑的版本关系 |
CreditTransaction |
成本记录和额度流水 |
ScriptAnalysis |
剧本解析结果 |
WorldAsset |
角色、空间、道具 |
WorldAssetImage |
世界资产和图片资产的关联 |
WorldScene |
场次 |
SceneStoryboard |
分镜、图片提示词、视频提示词和镜头信息 |
AgentRun |
一次 Agent 任务 |
AgentStep |
Agent 任务中的一个执行步骤 |
这里最关键的是 AgentRun 和 AgentStep。
AgentRun 记录一次完整目标,比如“把这段小说转成视频预视觉”。AgentStep 则记录每一个可执行节点,比如“精简小说”“生成资产图”“等待用户确认”“生成分镜图”。
这种设计让系统具备几个能力:
- 可以看到任务执行进度。
- 可以保存每一步输入和输出。
- 可以从失败步骤重试。
- 可以保留已成功的中间产物。
- 可以让用户在关键节点确认后再继续。
- 可以把长任务拆成多个短事务。
Agent 设计:模板计划 + 状态机,而不是黑盒自由 Agent
这个项目没有一开始引入复杂 Agent 框架,而是先实现了一个轻量可控的工作流 Agent。
原因很直接:短剧生成链路强依赖业务数据、资产关系、用户确认和成本控制。如果完全交给模型自由规划,很容易出现不可控的工具调用和难以恢复的状态。
所以当前 Agent 采用:
1 | AgentRunType |
当前支持的 AgentRunType:
novel_to_video_previewscript_to_video_previewasset_generationstoryboard_generationvideo_generation
当前支持的 AgentStepType:
condense_novelconvert_novel_to_scriptanalyze_scriptconfirm_world_assetsgenerate_world_asset_imagesgenerate_scene_storyboardsbuild_scene_director_plangenerate_video_clipsgenerate_final_report
AgentStep 状态:
1 | pending |
AgentRun 状态:
1 | draft |
最重要的设计点是 waiting_user_confirm。当系统解析出角色、空间和道具后,不会立刻消耗模型资源继续生成图片,而是暂停等待用户确认。
这一步让 Agent 从“全自动黑盒”变成“可控半自动工作流”。对生产工具来说,这比单纯追求自动化更实用。
Executor:长任务拆步执行与失败恢复
Agent executor 的职责是找到当前待执行步骤,执行对应工具,然后把结果写回数据库。
执行过程可以抽象成:
1 | 读取 AgentRun + AgentStep |
ExecutionContext 会把前面步骤的输出合并起来,让后续步骤可以复用:
- 精简后的小说。
- 转换后的剧本。
scriptAnalysisId。- 已生成资产数量。
- 分镜数量。
- 视频任务数量。
失败恢复也基于这个模型。重试失败步骤时,只需要把当前步骤及后续未完成步骤重置为 pending,已成功步骤保持不变。这样用户不会因为某一步模型失败而丢掉所有产物。
AI Provider 抽象:把模型差异隔离到服务端
项目目前主要接了三类模型能力:
- Qwen:文本理解、小说精简、小说转剧本、剧本结构化解析、分镜生成。
- Doubao Seedream:文生图、图生图、角色/空间/道具主图、分镜主视觉图。
- Doubao Seedance:图生视频任务。
Provider 层解决的问题是:业务代码不应该关心不同模型的具体请求格式、字段名、错误结构和 URL 处理。
因此页面和 Agent executor 只关心标准化后的能力:
1 | analyzeScript() |
模型层内部再处理:
- 模型名称归一化。
- Prompt 安全规则。
- 请求参数拼装。
- 响应结构解析。
- 错误信息转换。
- 图片或视频 URL 本地化。
- 额度耗尽、配置缺失等异常提示。
这样后续如果要增加新模型,只需要扩展 Provider,不需要改 Agent 主流程。
Prompt 与结构化输出
这个项目里 Prompt 不是随手拼字符串,而是围绕“结构化结果可入库”设计。
文本模型输出需要服务于数据库结构:
- 剧本解析要产出角色、空间、道具和场次。
- 世界资产要有名称、类型、描述、关键词、提示词和负面提示词。
- 场次要有地点、情绪、关键动作、空间关系和视觉重点。
- 分镜要有镜号、原文、图片提示词、视频提示词、镜头运动和对白。
也就是说,Prompt 的目标不是“生成一段好看的文字”,而是生成后端可以继续处理的数据。
这种设计有两个好处:
- 前端能稳定渲染编辑表单。
- 后续步骤能稳定引用前一步结果。
Three.js:把分镜信息转成可视化运镜草案
Three.js 在这个项目里不是做炫技 3D 场景,而是承担“运镜预览”的角色。
它消费的数据来自后端:
- 场次地点。
- 角色列表。
- 道具列表。
- 空间关系。
- 分镜信息。
- 镜头运动。
- 视觉焦点。
前端再把这些信息转成基础站位、摄像机位置、注视点和路径预览。这样用户可以更直观看到“这场戏大概怎么拍”。
这个模块的价值在于:后续视频模型不只拿到一句自然语言描述,还可以拿到结构化的镜头关系。即使当前 3D 预览还不是完整制作工具,它也为后续更精细的视频生成预留了数据接口。
资产存储:外部 URL 本地化与缩略图
AI 图片和视频模型返回的 URL 往往有有效期,不能直接当长期资产使用。
所以项目做了本地化存储:
- 生成图片后保存原图。
- 生成 WebP 缩略图。
- 列表和卡片优先读取
thumbnailUrl。 - 详情页和下载再读取原图。
- 下载通过服务端代理,减少浏览器 CORS 问题。
/uploads/在生产环境中用 volume 挂载。- Nginx 可以直接服务静态资源,避免所有图片流量都打到 Next 容器。
这部分虽然不如 Agent 听起来亮眼,但对 AIGC 项目很关键。否则图片链接过期后,历史记录就会失效。
登录、额度与安全
登录使用 Google OAuth。用户登录后自动创建账户,并通过 Cookie Session 识别当前用户。
额度系统目前主要用于管理 AI 生成成本和任务使用边界:
- 图片生成、图片编辑、资产主图、分镜图和视频任务都有独立成本记录。
- 生成失败、配置错误或额度耗尽时不会记录为成功消耗。
- 当前项目还没有开放付费购买额度,后续会接入订单和支付模块。
安全上主要做了几个约束:
- API Key 只放在服务端环境变量。
- 前端不直接请求模型 API。
- 所有模型调用都通过 Route Handlers。
- 生产环境变量通过 GitLab CI/CD File 类型变量注入。
- OAuth 回调地址通过环境变量区分本地和生产环境。
Docker 与 GitLab CI/CD
项目已经部署到生产环境,线上地址是:https://devflow.aiyly.com/。
部署方案不是直接在服务器上拉代码构建,而是走 Docker 镜像:
1 | GitLab CI |
Dockerfile 分为几个阶段:
deps:安装依赖。migrator:只保留 Prisma 迁移需要的内容。builder:生成 Next standalone 产物。runner:运行生产服务。
Docker Compose 里有两个服务:
aigc-video-studio:主应用。aigc-video-studio-migrate:数据库迁移服务。
这种拆法的好处是生产镜像不会携带完整开发环境,迁移也不会和应用启动强耦合。
这个项目里比较有价值的技术点
从技术角度看,这个项目最值得总结的是下面几件事:
1. Agent 不一定要一开始就上复杂框架
对于业务步骤明确、状态要求强、需要用户确认的系统,模板计划 + 状态机 + 工具函数,比自由 Agent 更稳定。
后续如果分支、循环、并行工具调用变复杂,再引入 LangGraph.js 这类状态图框架会更自然。
2. AI 应用要优先设计“中间态”
很多 AI Demo 只保存最终结果,但真实工具更需要中间态:
- 用户输入。
- 模型增强后的 Prompt。
- 结构化解析结果。
- 候选图。
- 资产版本。
- 分镜。
- 视频任务。
- 错误信息。
- 每一步执行状态。
这些中间态决定了系统是否能恢复、复用和迭代。
3. 生成任务要从第一天考虑失败
AIGC 调用不稳定是常态。网络、额度、内容安全、模型输出格式、图片地址有效期,都可能导致失败。
所以任务系统应该默认支持:
- 失败记录。
- 单步重试。
- 状态回滚。
- 已成功结果保留。
- 用户确认后继续执行。
4. Provider 抽象能降低后续换模型成本
模型变化很快,业务代码如果直接绑定某个厂商的字段,很快会变得难维护。
把模型能力封装成 Provider 后,Agent 和页面只依赖内部统一接口,后续替换模型会轻很多。
后续技术规划
后续优先补齐这些技术能力:
- 额度购买、订单支付和套餐系统。
- 更完整的视频任务队列。
- 视频状态轮询和回调同步。
- 角色语音包、配音和字幕。
- 多视频片段排序和成片导出。
- 更强的角色一致性策略。
- 更细粒度的镜头参数控制。
- 引入对象存储,替换本地 uploads。
- 当 Agent 流程复杂后,引入 LangGraph.js 或自研更完整的 state graph。
最终目标不是做一个“点按钮生成视频”的页面,而是做一个可持续扩展的 AI 短剧制作系统:前端能承载复杂工作流,后端能管理长任务和资产,Agent 能稳定编排多模型,数据层能保存完整创作过程。