
视觉AI当下最大的瓶颈不是生成能力而是连贯创作能力。单张图片生成已经非常成熟输入一段提示词就能得到一张精致图像但用户真正需要的往往是一个完整的视觉作品比如一套海报、一段分镜脚本、一个产品主图和配套详情图甚至是带叙事逻辑的短视频画面。这里的差距正是视觉AI从「会生成」走向「能创作」要解决的问题。RabbitVis 这个探索性项目把大模型生成、多模态理解、工具调用和流程编排放在同一个应用框架里用一套可复现的工程方案演示视觉AI应用的新范式。本文以 RabbitVis 为例梳理这种新范式的核心机制、整体设计、关键实现、验证方法以及生产化改造思路适合正在做 AI 应用产品、视觉工具链或 Agent 工程的开发者参考。1. 先理解视觉AI从「会生成」到「能创作」到底变了什么1.1 「生成」和「创作」在工程上不是同一个问题单次文生图任务输入是一段提示词输出是一张图片整个链路是「理解提示词 - 扩散采样 - 解码图像」。这个链路已经有大量现成模型和开源工具可以覆盖比如 Stable Diffusion、Flux、Midjourney 类接口。工程上关心的是采样步数、CFG Scale、负提示词、LoRA 加载这类参数。但「创作」不同。以一张电商主图为例用户真正要的不是随便生成一张图而是「品牌调性统一、产品角度正确、背景干净、带营销文案、尺寸符合平台要求、和详情页风格一致」的一组图。这要求 AI 不只完成一次生成而是完成一整套策划和制作流程理解需求从自然语言描述中抽取主体、风格、场景、用途。拆解任务把一个复杂目标拆成多个可执行子任务比如主体设计、背景生成、局部重绘、文案排版。调用工具不同子任务可能需要不同模型或不同参数比如外观一致性用 IP-Adapter精细修改用局部重绘。迭代修正生成结果不理想时要能自动或半自动地回到前置步骤修改而不是重新随机生成。组装输出多张图片按模板或版式合成最终作品并对应到不同尺寸和文件格式。这就是视觉AI从「单点生成」走向「多步创作」的差别创作是带状态、带目标、带校验的流程而生成只是其中一个原子动作。1.2 RabbitVis 选择的技术路线不是又一个大模型而是一个 Agent 编排层RabbitVis 的定位不是训练一个新模型而是把已有视觉模型、大语言模型和图像处理能力封装成可编排的 Agent 任务。它要解决的问题是当用户提出一个模糊的创作目标时系统如何把它变成一组可落地、可回溯、可修正的视觉任务。这里有两个关键判断第一视觉创作需要语言模型作为「宏观调度器」。大语言模型擅长任务理解、目标拆解、参数格式化和结果评价。图像生成模型擅长像素空间的具体输出。前者负责想清楚做什么后者负责把它画出来。第二多步创作不能靠「一次提示词搞定」必须保存中间状态。每一步生成结果要能被后续步骤引用失败时还要能定位到具体环节。所以 RabbitVis 的架构里引入了一个工作流引擎而不是简单把多个 API 串起来。1.3 以「创作」为目标的视觉 AI 应用通常包含哪些核心能力参考 RabbitVis 的设计一个能「创作」的视觉 AI 应用至少需要具备五类能力能力模块作用典型依赖意图理解把用户需求转成结构化创作方案LLM、多模态大模型方案拆解把创作方案拆成有序的生成步骤LLM 工作流模板视觉生成完成具体图像/视频内容生成Diffusion 模型、GAN资产管理管理参考图、生成图、LoRA、风格模板对象存储、向量数据库校验反馈判断结果是否符合目标决定是否重试多模态评分模型、规则引擎这五类能力不是独立的工具集而是需要通过一个统一的任务模型串联起来。RabbitVis 在这一点上选择用一个「创意蓝图Creation Blueprint」数据结构来承载整个创作任务。它既保存了用户原始需求也保存了拆分后的步骤、每个步骤的入参出参、生成结果的状态以及失败时的重试记录。这样整个创作过程才是可解释、可调试、可复用的。2. RabbitVis 的总体设计一个可复现的视觉创作应用骨架2.1 整体模块划分和核心概念RabbitVis 参考实现可以分为四个层次。第一层是接入层负责接收用户请求比如文本描述、参考图上传、创作类型选择。第二层是编排层核心是 Agent 调度和任务流程管理它决定创作者意图如何被拆解和执行。第三层是执行层封装各类生成工具、图像处理工具和校验工具。第四层是资产层负责统一保存和索引所有输入输出文件以及中间状态。这种分层的核心意图是解耦。编排层不直接依赖具体模型厂商执行层的模型可以替换资产层独立演进。否则一旦换一个图像模型整个流程都要跟着改很难持续迭代。RabbitVis 里最核心的概念是「创作任务CreationTask」。一个任务包含任务 ID、用户需求、拆解后的步骤列表、每个步骤的执行状态、全局上下文、最终产物地址。结构上接近一个带状态机的 DAG 图但为了保持简单第一版可以先支持顺序执行和条件分支。2.2 项目目录结构建议实际开发时目录结构直接影响后续维护成本。RabbitVis 第一版可以采用这样的结构rabbitvis/ ├── app/ │ ├── api/ # API 路由 │ │ ├── tasks.py # 创作任务接口 │ │ └── assets.py # 素材上传与查询接口 │ ├── core/ # 配置与基础设施 │ │ ├── config.py # 环境变量与配置 │ │ ├── storage.py # 文件与对象存储封装 │ │ └── logging.py # 日志初始化 │ ├── orchestration/ # 编排层 │ │ ├── planner.py # 用 LLM 拆解任务 │ │ ├── executor.py # 执行步骤并维护状态 │ │ └── workflow.py # 工作流定义与分支逻辑 │ ├── tools/ # 执行层工具 │ │ ├── text_to_image.py # 文生图工具 │ │ ├── img2img.py # 图生图工具 │ │ ├── inpaint.py # 局部重绘工具 │ │ └── evaluator.py # 质量评分工具 │ ├── schemas/ # 数据模型 │ │ ├── task.py │ │ └── blueprint.py │ └── main.py # FastAPI 入口 ├── tests/ # 单元测试与集成测试 ├── examples/ # 示例请求与配置 ├── requirements.txt └── .env.example这个结构不是必须照搬但有一个原则不要违背编排层、执行层和 API 层之间不要互相 import 具体实现。例如planner.py只负责返回步骤列表不直接调用某个图像模型的 SDK真正调用发生在executor.py通过工具注册表找到对应工具并执行。2.3 依赖选型和环境准备RabbitVis 面向的是 Python 技术栈因为视觉模型和 Agent 框架的生态都在 Python 侧更成熟。核心依赖可以分成三组Web 框架、AI 推理和图像处理、Agent 编排。依赖分组建议选型用途说明Web 框架FastAPI Uvicorn提供 REST API 和异步支持图像生成diffusers transformers加载 Diffusion 模型图像处理Pillow opencv-python图像缩放、合成、遮罩处理Agent 编排LangGraph 或自研状态机管理多步任务状态和重试LLM 调用openai SDK 或 langchain 兼容层调用语言模型做任务拆解存储本地文件目录 SQLite学习和演示阶段最低成本方案学习环境快速跑通时不需要引入 Redis 和 Postgre。SQLite 加本地文件目录已经能承载整个任务状态和素材管理。生产环境再替换为对象存储和关系数据库。要注意依赖版本必须根据实际安装环境固定。下面是一个参考的requirements.txt片段fastapi0.110,1.0 uvicorn[standard]0.29,1.0 diffusers0.27,1.0 transformers4.40,5.0 sentencepiece0.1.99 opencv-python4.9 pillow10.0 pydantic2.6 python-dotenv1.0 sqlalchemy2.0这里没有把特定视觉模型的版本写死因为模型文件通常单独管理不同机器使用不同硬件需要单独下载。推荐把模型下载脚本放到scripts/目录而不要放在应用代码里。3. 核心实现从文本创意到可分镜视觉作品的完整链路3.1 用创意蓝图管理创作任务的输入和中间状态RabbitVis 的核心数据结构是创意蓝图。它描述了一个视觉创作任务的完整过程。下面是一个简化版 Pydantic 模型from pydantic import BaseModel, Field from typing import List, Optional from enum import Enum class StepStatus(str, Enum): PENDING pending RUNNING running SUCCEEDED succeeded FAILED failed RETRYING retrying class ToolCall(BaseModel): tool_name: str params: dict Field(default_factorydict) result_ref: Optional[str] None class CreationStep(BaseModel): step_id: str description: str tool_calls: List[ToolCall] Field(default_factorylist) status: StepStatus StepStatus.PENDING retry_count: int 0 error_message: Optional[str] None output_ref: Optional[str] None class CreationBlueprint(BaseModel): task_id: str user_request: str creative_goal: str style_tags: List[str] Field(default_factorylist) steps: List[CreationStep] Field(default_factorylist) global_context: dict Field(default_factorydict) created_at: str 这个模型看起来简单但它解决了创作类应用最关键的问题系统知道每一步在做什么、是否成功、输出在哪里。很多只接大模型 API 的 Demo 失败后整个任务就丢了就是因为没有保存中间状态。创意蓝图的global_context字段非常重要。它用来存放各步骤之间需要共享的信息比如生成的主视觉图路径、提炼出的色彩主题、统一的产品描述等。后续步骤可以直接读取避免重复计算或出现前后风格不一致。3.2 让 LLM 把用户需求拆解成可执行的视觉步骤「创作」的第一步不是画图而是计划。RabbitVis 用一个planner模块调用语言模型将用户需求转换为结构化步骤。这里不直接让用户写步骤是因为普通用户不会用「先生成主体再局部重绘背景」这类语言表达需求。一个关键技巧是给 LLM 提供工具清单和输出格式约束。比如在 prompt 中列出可以调用的工具、每个工具的参数要求并要求只输出 JSON。下面是一个简化实现import json from openai import OpenAI client OpenAI() tool_declaration 可用工具 1. text_to_image: 文生图参数 {prompt, width, height, style} 2. img2img: 图生图参数 {prompt, input_image, denoise_strength} 3. inpaint: 局部重绘参数 {input_image, mask, prompt} 4. assemble: 图像合成参数 {background, foreground, position} 请把用户需求拆解为最多5个步骤每个步骤只调用一个工具。 输出 JSON 格式 { creative_goal: 这里写创作目标总结, steps: [ {description: 步骤说明, tool: 工具名, params: {...}} ] } def plan_creation(user_request: str) - dict: response client.chat.completions.create( modelgpt-4o-mini, response_format{type: json_object}, messages[ {role: system, content: 你是视觉创意流程规划器。 tool_declaration}, {role: user, content: user_request}, ], ) return json.loads(response.choices[0].message.content)这里要强调一个容易忽略的坑大模型输出的 JSON 不一定是有效 JSON尤其是复杂 prompt 时容易多出注释或代码块标记。生产环境一定要对输出做二次解析和字段校验不能直接json.loads并假设成功。推荐的做法是使用response_format指定 JSON同时在后端用 Pydantic 校验并抛出可读错误。3.3 执行器按步骤调用图像工具并维护任务状态步骤拆解完成后executor负责依序执行。RabbitVis 里每个工具都是一个普通 Python 函数通过工具注册表按名称查找。这样编排层不需要写大量 if-else。class ToolRegistry: def __init__(self): self._tools {} def register(self, name: str, func): self._tools[name] func def get(self, name: str): if name not in self._tools: raise ValueError(fTool {name} not found) return self._tools[name] registry ToolRegistry() def run_blueprint(blueprint: CreationBlueprint, registry: ToolRegistry) - CreationBlueprint: for step in blueprint.steps: step.status StepStatus.RUNNING try: for tool_call in step.tool_calls: func registry.get(tool_call.tool_name) result func( **tool_call.params, contextblueprint.global_context ) tool_call.result_ref result.get(ref) if context_update in result: blueprint.global_context.update(result[context_update]) step.status StepStatus.SUCCEEDED except Exception as exc: step.status StepStatus.FAILED step.error_message str(exc) # 在这里决定重试或终止 raise return blueprint这里的run_blueprint是顺序执行的简化版。实际 RabbitVis 可以引入状态机或 LangGraph 来做更复杂的控制流但顺序执行已经把核心逻辑表达清楚了每步执行、记录状态、更新全局上下文。在上述代码中工具函数的参数里注入了context这样工具可以读取之前步骤的输出。例如局部重绘工具需要主图路径主图路径就是前一个文生图步骤写入 global_context 的字段。3.4 工具层示例把生成、重绘和合成封装成统一接口工具层必须保持统一的输入输出协议。RabbitVis 约定每个工具返回一个 dict包含ref和可选的context_update。ref指向存储在资产目录中的文件路径。下面是一个文生图工具示例from diffusers import StableDiffusionPipeline import torch class TextToImageTool: def __init__(self, model_id: str, device: str cuda): self.pipe StableDiffusionPipeline.from_pretrained( model_id, torch_dtypetorch.float16 ).to(device) def __call__(self, prompt: str, width: int 768, height: int 768, style: str default, context: dict | None None, **kwargs): # 这里可以从 context 读取统一风格描述 if context and global_style in context: prompt f{context[global_style]}, {prompt} image self.pipe( promptprompt, widthwidth, heightheight, num_inference_steps25, ).images[0] asset_path fassets/generated/{uuid4().hex}.png image.save(asset_path) return { ref: asset_path, context_update: {latest_image: asset_path} }这个实现里有一个值得学习的点工具函数可以通过context感知全局风格从而保证多次生成结果风格一致。它没有把风格参数写死在 prompt 里而是从上下文读取。这是保持一致性的一个有效手段也避免用户每次重复描述风格。局部重绘工具的接口类似差别在于需要输入遮罩 mask。RabbitVis 里 mask 可以由用户上传也可以由前置步骤根据目标区域生成。因为输入输出统一后面的合成步骤不需要关心上一张图是生成的还是重绘的。4. 验证、评估与排查如何判断 AI 是在「创作」而不是「随机生成」4.1 创作类应用要验证四个层面不能只看最终图片好不好看很多视觉 AI 项目上线后的最大问题是「演示效果很好用户一用就崩」。原因在于只验证了生成结果的美观度没有验证流程的确定性、资产的完整性和步骤的可恢复性。RabbitVis 把验证拆成四个层面验证层面验证内容通过标准输入解析用户需求能否被正确拆解为步骤步骤数在预期范围参数合法流程执行每个步骤能否按顺序完成无未处理异常状态流转正确产物一致性多次生成风格、尺寸、内容是否稳定同一需求两次结果相似度可接受失败恢复步骤失败后能否定位并重试错误信息可读任务可恢复单张图片的美观度属于第三层里面的内容相似性但不能替代整个过程验证。尤其要注意用户第一次使用时流程可能完全正常第二次调整了提示词LLM 拆解出步骤数可能变了工具参数可能超出预期。所以必须对 LLM 输出做持续性校验。4.2 建立「创作过程日志」定位问题到底出在哪一环传统生成应用出问题只需要看生成日志。创作类应用的问题可能出在规划、执行、工具、资产引用四个环节。RabbitVis 要求在每一步开始和结束时都记录结构化日志。{ event: step_started, task_id: task_001, step_id: step_2, tool: img2img, params: { prompt: 把背景换成办公室场景, input_image: assets/generated/xxx.png, denoise_strength: 0.6 }, timestamp: 2025-01-01T12:00:00Z }日志里必须包含task_id、step_id、tool_name和完整 params。这样当最终图片异常时可以回放「每一步用了什么参数、输入了哪张图」。很多问题比如背景没有变化、主体被改变、生成结果僵硬通过对步骤日志逐层检查很快就能定位到是工具参数设置错误还是模型问题。一个典型排查链路如下用户反馈「最终图片和第一张图风格完全不一样」。检查任务日志中的每一步context_update确认global_style是否被后续步骤覆盖。检查img2img的denoise_strength参数太大会导致原图被破坏太小导致修改不生效。检查assemble工具读取的前背景路径是否正确是否存在文件覆盖。根据日志判断需要调整哪一步而不是盲目重跑整个任务。4.3 至少要注意这三个典型坑第一个坑认为 LLM 的 JSON 输出可以直接使用。真实项目中 LLM 可能输出非法 JSON、字段缺失、工具名拼写错误、参数超出枚举范围。解决办法是让 LLM 返回一个结构化推理结果同时在后端做 schema 校验校验失败时重新请求一次或抛出明确错误。第二个坑把global_context当成公共垃圾桶。所有步骤都往里塞字段很快会出现 key 覆盖和隐式依赖。例如文生图步骤把result_image写入 context局部重绘步骤又写入result_image最终引用时不知道是哪一个。推荐做法是每个步骤的输出使用step_id作为命名空间读取时明确指定step_1.output_ref避免全局字段互相污染。第三个坑忽略硬件和模型版本差异。Diffusion 模型在不同设备上可能得到不同结果同一模型不同版本的效果也可能变化。RabbitVis 在资产元数据中必须记录模型名称、版本、采样器、种子等参数。否则同一个任务在 A 机器上成功在 B 机器上失败排查时没有足够信息几乎无法定位问题。建议生成结果旁边保存一张 JSON 元数据内容至少包括{ asset_path: assets/generated/xxx.png, tool_name: text_to_image, model_id: stabilityai/sdxl-turbo, prompt: ..., seed: 20250101, width: 768, height: 768, steps: 4, created_at: 2025-01-01T12:00:00Z }4.4 在开发环境加入「半自动修正」而非全部自动创作类 AI 的第一步可以先做成半自动。用户确认每一个关键步骤的结果再进入下一步。例如用户需要一张产品图系统生成产品主体后用户确认外观满意再让系统生成背景。这个模式的工程代价更低同时能收集用户在每个环节的反馈为以后训练自动决策模型积累数据。如果直接做成全自动一旦生成结果不符合预期用户只能重新开始体验很差。半自动模式下用户可以在任意步骤回退或修改参数。RabbitVis 实现半自动时只需要在CreationStep上增加一个requires_confirmation字段执行器在遇到该字段时暂停并等待用户确认。5. 最佳实践从 RabbitVis Demo 到生产级视觉 AI 应用要做什么5.1 学习环境怎么快速跑通生产环境需要补足哪些能力学习环境下核心目标是把链路跑通。可以把所有资产存在本地目录使用 SQLite 保存任务和元数据图像模型加载到单张 GPU 或 CPU。示例任务建议从「一套 3 张风格统一的社交媒体配图」开始不要一开始就做复杂分镜视频因为流程越复杂排查成本越高。生产环境则需要在五个方向上补强维度学习环境生产环境配置管理项目内.env配置中心或环境变量敏感信息加密存储本地文件目录对象存储 CDN 备份策略队列同步执行消息队列 异步 worker监控print 日志结构化日志 指标采集 告警权限无鉴权API Key、用户体系、配额管理生产环境最容易被忽略的是资源隔离。多个用户同时提交创作任务时如果每个任务都加载一个独立的 Diffusion 模型显存会直接溢出。正确的做法是模型常驻内存用并发队列控制同时生成的请求数不同模型可以部署到不同推理服务中。5.2 推荐一个可复用的「创作任务上线前检查清单」在发布 RabbitVis 类应用之前建议至少过一遍这个清单。不要只检查功能是否可用还要检查异常路径和运维保障。[ ] 用户输入为空、过长、含敏感词时接口是否返回明确错误。[ ] LLM 拆解结果非法时是否触发重试或降级方案。[ ] 每个步骤超时是否有限制超时后任务状态是否正确。[ ] 步骤失败后用户能否根据任务 ID 看到具体失败原因。[ ] 全局上下文是否有命名空间是否会被无意覆盖。[ ] 生成资产的元数据是否完整是否能追溯到模型、参数和 seed。[ ] 多个步骤并发执行时资产路径是否冲突。[ ] 模型加载失败或显存不足时是否有健康检查和自动恢复。[ ] 生产环境是否开启鉴权和限流。[ ] 是否有清理老旧临时资产的定时任务。这条清单不是一次性的每次增加新工具或新模型时都要重新跑一遍尤其是「模型是否可替换」这一项。RabbitVis 的核心价值在于编排层模型无关新接入一个文生图模型时不要修改 planner 和 executor只替换工具实现和配置。5.3 下一步扩展方向从单图创作走向多模态叙事RabbitVis 第一个可落地的版本可以先处理静态图像创作。再往后走不外乎三个方向。第一个方向是视频分镜。把创作蓝图扩展为「镜头列表」每个镜头包含场景描述、构图、时长和运镜方式。每一步生成的图片作为关键帧再用视频生成模型或插帧工具生成短镜头。这个过程中当前实现里的分步执行和状态管理可以直接复用难点在于镜头之间保持角色一致性。第二个方向是品牌一致性。建立一个品牌视觉库里面存储颜色、字体、参考图、LoRA 和禁止元素。在 planner 拆解任务时将品牌视觉库注入 global_context所有工具在生成时都受品牌约束。这比在 prompt 里重复描述品牌风格更稳定。第三个方向是有人参与的人机协同。把 RabbitVis 从「AI 自动完成任务」变成「AI 完成初稿人类在关键节点反馈」。实践中会发现创意类任务中人类反馈比任何自动评分模型都有效。因此在工具链中预留人工修订接口比强行追求全自动更有产品价值。5.4 给开发者的实践建议如果现在要开始做一个视觉 AI 创作类应用建议不要直接去写大量 Agent 编排代码。先用最简单的方式把一个真实创作场景打通比如用 Python 脚本串起文生图、抠图、合成三个步骤把每步的输入输出记录成 JSON。跑通一次后再考虑引入 FastAPI、LangGraph、消息队列等架构组件。RabbitVis 这个例子想说明的不是某个框架或某个模型最好而是视觉 AI 应用的设计重心已经从「生成一张图」转移到「管理一次创作过程」。谁能把模型能力、任务编排和用户反馈揉进一个可维护的系统里谁才真正把 AI 能力变成了产品能力。对于视觉 AI 应用开发者来说多花时间在任务状态设计、结果验证和失败恢复上比不断换更大的模型更有价值。