最近在做短视频批量生产项目时,我发现一个比较现实的矛盾:单条视频靠人工从写脚本到剪辑出片,少说也要半小时起步;但如果只丢给大模型一段“帮我做个视频”,它又只会给你一段无法落地的“创作建议”。后来我把 Grok 4.6 这类大模型和 AI Agent 结合起来,把“提示词 → 脚本 → 分镜 → 画面素材 → 配音 → 合成”整条链路交给 Agent 自动编排,才真正把视频生产从“单点 AI 辅助”变成“全流程自动化”。
这篇就完整拆解我的实操过程:Grok 4.6 在视频生成链路中负责什么、AI Agent 如何编排各个节点、提示词要怎么写才能让 Agent 稳定产出结构化内容,以及从零到成片的完整示例代码和排错方案。新手可以照着搭,有基础的开发者可以直接拿去改造成自己的视频生产管线。
1. 背景与核心概念
在开始写代码之前,先把几个容易混淆的概念理清楚:Grok 4.6、AI Agent、提示词工程,以及它们在视频制作流程里分别扮演什么角色。
1.1 为什么“让 AI 做视频”不能靠一句提示词
很多刚接触 AI 视频生成的朋友,第一次尝试往往是这样的:打开对话窗口,输入“帮我做一个关于 AI 的介绍视频”,然后期待模型直接吐出一个 mp4 文件。
实际上,当前的大语言模型无论多强,都不可能“一键生成”完整视频。它擅长的是生成结构化的内容,比如剧本、分镜表、画面描述、配音文案。真正把文字变成视频,需要调用图像生成模型、视频生成模型、语音合成工具和剪辑工具。
Grok 4.6 以及类似的现代大语言模型,在视频生产链路里更像是一个“内容策划 + 调度决策大脑”,它可以:
- 根据用户主题生成完整剧本。
- 把剧本拆分成镜头级别的画面描述。
- 为每个镜头生成图像生成模型可用的提示词。
- 输出配音文案和字幕。
- 把上述所有结果整理成机器可读的 JSON / 表格,供下游工具调用。
而 AI Agent,就是把这个大脑和各个下游工具连接起来的“躯干”。
1.2 AI Agent 在视频自动制作中的定位
AI Agent 是“能感知环境、做出决策、执行动作”的智能程序。在视频自动制作场景中,Agent 的核心价值不是“更会聊天”,而是把一次复杂的创作任务拆解为多个子任务,并调度不同的工具依次完成。
这里用一个简单的类比:
| 角色 | 视频制作中的对应物 |
|---|---|
| 编剧 | Grok 4.6 这类大模型 |
| 导演 | AI Agent 的调度逻辑 |
| 摄影师 | 图像/视频生成模型 |
| 配音演员 | TTS 语音合成工具 |
| 剪辑师 | FFmpeg 等视频处理工具 |
如果没有 Agent,你就需要手动把大模型生成的结果复制到图像生成工具,再把生成的图片复制到视频工具,再手动拼接……每一步都要人工介入。而 Agent 可以自动完成这些“复制粘贴”工作。
1.3 提示词在 Agent 流程中的特殊要求
这里需要特别强调一点:给 Agent 的提示词,和给人看的提示词,完全是两种写法。
面向人的提示词,可以多写背景、情感、风格描述;但面向 Agent 的提示词,必须考虑“机器可解析性”。因为 Agent 拿到大模型输出后,需要用代码去读取、校验、转换,再传给下一个工具。如果大模型输出的是连续的长篇散文,Agent 很难稳定提取出需要的字段。
所以,在 Agent 自动化流程中,提示词通常要满足三点:
- 输出必须是指定格式,例如 JSON 或 Markdown 表格。
- 输出结构必须固定,字段名要稳定。
- 必要时要给示例输出(few-shot),因为大模型模仿示例的准确性远高于理解抽象规则。
2. 整体工作流程与架构拆解
下面是我在项目中使用的“从提示词到成片”的完整流水线。它不依赖某一个特定视频生成平台,而是一种通用的编排思路。
2.1 六节点流水线设计
整个流水线可以拆成六个节点:
- 需求解析节点:接收用户输入的主题、时长、风格、目标平台,输出结构化任务参数。
- 剧本生成节点:基于任务参数生成完整视频脚本,包括开场、主体内容、结尾。
- 分镜生成节点:把剧本拆成镜头序列,每个镜头包含画面描述、画面提示词、文案、时长。
- 画面素材生成节点:根据画面提示词调用图像生成或视频生成接口,产出图片或短视频片段。
- 语音合成节点:根据每个镜头的文案调用 TTS 接口,生成配音音频。
- 合成输出节点:使用 FFmpeg 等工具把画面、音频、字幕合成最终视频。
流程如下表所示:
| 节点 | 输入 | 输出 | 核心工具 |
|---|---|---|---|
| 需求解析 | 用户原始描述 | 结构化任务参数(JSON) | Grok 4.6 |
| 剧本生成 | 结构化任务参数 | 完整脚本(Markdown/JSON) | Grok 4.6 |
| 分镜生成 | 完整脚本 | 镜头列表(JSON数组) | Grok 4.6 |
| 画面素材生成 | 画面提示词列表 | 图片/视频片段文件 | 图像生成模型 / 视频生成模型 |
| 语音合成 | 镜头文案列表 | 音频文件 | TTS 服务 |
| 合成输出 | 画面、音频、字幕 | 最终 MP4 文件 | FFmpeg |
2.2 Agent 调度的两种方式
在实际项目中,Agent 调度上述节点有两种常见方式:
一种是线性流水线。节点依次执行,前一个节点的输出直接作为后一个节点的输入。这种方式实现简单,适合流程固定的批量视频生产。
另一种是“规划器 + 执行器”模式。Agent 先让大模型规划当前任务需要调用哪些节点,然后根据规划结果动态执行。这种方式更灵活,但实现复杂度较高,适合需求变化多的场景。
对于大多数视频批量生产需求,线性流水线已经足够。本文的实战案例也采用线性流水线方式。
2.3 为什么需要中间结果持久化
在实际落地中,我强烈建议每个节点都把中间结果保存到本地文件(比如 JSON 文件、图片文件、音频文件),而不是只保存在内存中。原因有三:
- 方便定位问题。如果最终视频画面和文案不匹配,可以回溯查看分镜文件。
- 支持断点续跑。某个节点失败时,不必重新调用前面的模型接口,节省费用。
- 便于人工审核。在自动生成环节之间插入人工检查,是保证内容质量的重要手段。
3. 环境准备与版本说明
开始实战前,先把环境准备好。由于 AI 大模型接口和视频生成工具更新比较快,这里只给出通用的环境方案。
3.1 软件与依赖
我使用的环境如下,读者可按自己的实际情况调整:
- 操作系统:Windows 10 / 11、macOS、主流 Linux 发行版均可。
- Python:3.10 或更高版本。
- FFmpeg:用于最终视频合成,安装后需要确保
ffmpeg命令在 PATH 中可用。 - 大模型 API:Grok 4.6 可以通过官方 API 或兼容接口调用,本文示例以 OpenAI 兼容接口为例。
- TTS / 图像生成服务:可以选择任一支持 API 的第三方服务,本文只演示接口对接思路。
Python 依赖建议安装:
pip install requests openai python-dotenv如果使用虚拟环境,可以这样创建:
python -m venv venv source venv/bin/activate # Windows 使用 venv\Scripts\activate pip install requests openai python-dotenv3.2 项目目录结构
建议按下面的目录结构组织项目:
video_agent/ ├── .env # 存放 API Key 和基础配置 ├── config.py # 读取环境变量和全局配置 ├── prompts/ │ ├── script.md # 剧本生成提示词模板 │ ├── storyboard.md # 分镜生成提示词模板 │ └── task_parser.md # 需求解析提示词模板 ├── nodes/ │ ├── __init__.py │ ├── base.py # 节点基类 │ ├── script_node.py # 剧本生成节点 │ ├── storyboard_node.py # 分镜生成节点 │ ├── image_node.py # 画面素材生成节点 │ ├── tts_node.py # 语音合成节点 │ └── compose_node.py # 视频合成节点 ├── workflow.py # Agent 流水线编排主脚本 ├── outputs/ │ ├── task.json # 结构化任务参数 │ ├── script.json # 剧本 │ ├── storyboard.json # 分镜 │ ├── images/ │ ├── audios/ │ └── final.mp4 # 最终成片 └── requirements.txt这种按节点拆分的结构,有利于后期维护,也方便单独测试某个节点。
3.3 环境变量与密钥管理
API Key 不要直接写在代码中。建议在项目根目录创建.env文件:
# .env GROK_API_KEY=你的Grok_4.6_API_Key GROK_BASE_URL=https://api.example.com/v1 GROK_MODEL=grok-4.6 # 图像生成服务 IMAGE_API_KEY=你的图像生成服务Key IMAGE_BASE_URL=https://api.example-image.com/v1 # 语音合成服务 TTS_API_KEY=你的TTS服务Key TTS_BASE_URL=https://api.example-tts.com/v1注意,以上.env中的GROK_BASE_URL、IMAGE_BASE_URL、TTS_BASE_URL是示例地址,实际使用时要替换为你所调用服务的真实接口地址。密钥管理遵循最小权限原则,不要提交到 Git 仓库。
新增.gitignore文件,把.env忽略掉:
# .gitignore .env outputs/ __pycache__/ venv/4. 提示词设计与核心配置
提示词是这个项目里“上限最高”的部分。同样的 Agent 代码,提示词写得好,输出稳定可靠;提示词写得模糊,后面每个节点都要跟着返工。下面给出我在项目中使用的三个核心提示词模板。
4.1 需求解析提示词
需求解析节点负责把用户的自然语言描述转成结构化任务参数。提示词模板如下:
你是一个视频制作需求分析助手。 请根据用户的描述,输出一个 JSON 对象,包含以下字段: - theme: 视频主题 - duration: 目标时长(秒) - style: 画面风格 - tone: 内容语气 - target_platform: 目标发布平台 - reference_info: 需要补充的背景信息数组 要求: 1. 只输出 JSON,不要输出其他解释文字。 2. 如果用户没有提供某个字段,使用合理的默认值。 3. duration 必须是数字。 用户描述: {{user_input}}把这段模板保存到prompts/task_parser.md,在调用时用实际用户输入替换{{user_input}}。
4.2 剧本生成提示词
剧本生成节点需要输出结构化脚本,而不是散文。我使用的模板:
你是一个短视频编剧。 请根据以下任务参数,生成视频脚本: 主题:{{theme}} 目标时长:{{duration}}秒 内容语气:{{tone}} 目标平台:{{target_platform}} 脚本要求: 1. 时长控制在 {{duration}} 秒左右,按每分钟约 200 字估算文案字数。 2. 脚本结构包含开场、主体、结尾三个部分。 3. 输出为 JSON,格式如下: { "title": "视频标题", "sections": [ { "part": "开场", "content": "文案内容", "estimated_seconds": 5 } ] } 4. 只输出 JSON,不要输出额外说明。这个模板的关键在于:既告诉模型结构要求,又给了明确的格式示例。模型在生成时会更倾向于输出稳定的 JSON 结构。
4.3 分镜生成提示词
分镜节点是画面质量的关键。它要把剧本文案转成“每个镜头的画面描述 + 图像生成提示词”。
你是一个视频分镜师。 请根据以下视频脚本,将内容拆分为分镜列表。 脚本: {{script_content}} 要求: 1. 每个镜头对应一段画面内容。 2. 输出为 JSON 数组,每个元素的格式: { "shot_id": 1, "scene_description": "画面内容描述", "image_prompt": "用于图像生成模型的英文提示词", "narration": "本镜头对应的旁白文案", "duration_seconds": 3 } 3. duration_seconds 之和应接近视频目标时长 {{duration}}。 4. 只输出 JSON 数组。这里我特意要求image_prompt使用英文,是因为大部分图像生成模型对英文提示词的理解更稳定。
4.4 为什么输出必须用 JSON
在 Agent 自动化流程中,JSON 是所有节点之间最稳定的通信格式。相比自然语言,JSON 有三个明显优势:
- 容易解析:Python 直接
json.loads()即可。 - 结构稳定:字段名固定,下游代码不容易出错。
- 便于校验:可以用 Pydantic 或手写校验函数检查字段完整性。
代价是提示词模板会变得“不自然”,但这是自动化系统的必要取舍。
5. 实战:从提示词到成片的完整示例
现在进入核心实战环节。我会从零开始写一个最小可运行的 Agent 流水线。为了让大家独立复现,这里把大模型接口调用封装成通用函数,模拟真实的 Grok 4.6 API 调用方式;图像生成和 TTS 的部分用占位函数代替,重点展示编排思路。
5.1 定义全局配置
首先创建config.py,读取.env中的配置:
# config.py import os from dotenv import load_dotenv load_dotenv() GROK_API_KEY = os.getenv("GROK_API_KEY") GROK_BASE_URL = os.getenv("GROK_BASE_URL") GROK_MODEL = os.getenv("GROK_MODEL") IMAGE_API_KEY = os.getenv("IMAGE_API_KEY") IMAGE_BASE_URL = os.getenv("IMAGE_BASE_URL") TTS_API_KEY = os.getenv("TTS_API_KEY") TTS_BASE_URL = os.getenv("TTS_BASE_URL")这里要注意:如果某个 Key 没有配置,程序启动时应该给出明确提示,而不是等到调用时才报错。可以在config.py后面追加一个校验函数:
# config.py (追加) def check_config(): required_keys = ["GROK_API_KEY"] for key in required_keys: if not os.getenv(key): raise RuntimeError(f"缺少必要配置: {key},请在 .env 中配置")5.2 封装大模型调用函数
所有需要调用 Grok 4.6 的节点,都可以复用同一个底层调用函数。这里使用openai库,因为 Grok 4.6 的接口通常兼容 OpenAI 的调用方式。
# nodes/base.py from openai import OpenAI from config import GROK_API_KEY, GROK_BASE_URL, GROK_MODEL class BaseNode: """所有处理节点的基类,提供大模型调用能力""" def __init__(self): self.client = OpenAI( api_key=GROK_API_KEY, base_url=GROK_BASE_URL, ) self.model = GROK_MODEL def call_llm(self, system_prompt: str, user_content: str) -> str: """调用大模型,返回文本结果""" response = self.client.chat.completions.create( model=self.model, messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_content}, ], temperature=0.7, ) return response.choices[0].message.content注意:base_url和model参数以你实际使用的服务为准。不同服务商的兼容接口可能有差异,如果OpenAI客户端无法连接,可以使用requests直接调用 HTTP 接口。下面给出使用requests的备用版本:
# nodes/base.py (requests 版本) import requests from config import GROK_API_KEY, GROK_BASE_URL, GROK_MODEL class BaseNode: def __init__(self): self.api_key = GROK_API_KEY self.base_url = GROK_BASE_URL self.model = GROK_MODEL def call_llm(self, system_prompt: str, user_content: str) -> str: url = f"{self.base_url}/chat/completions" headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json", } payload = { "model": self.model, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_content}, ], "temperature": 0.7, } resp = requests.post(url, headers=headers, json=payload, timeout=60) resp.raise_for_status() data = resp.json() return data["choices"][0]["message"]["content"]两个版本的核心逻辑一致。选择一个能在你环境中跑通的即可。
5.3 需求解析节点
这个节点把用户输入变成结构化任务参数。
# nodes/script_node.py import json from nodes.base import BaseNode class TaskParserNode(BaseNode): """需求解析节点""" def parse(self, user_input: str) -> dict: system_prompt = """你是一个视频制作需求分析助手。 请根据用户的描述,输出一个 JSON 对象,包含以下字段: - theme: 视频主题 - duration: 目标时长(秒) - style: 画面风格 - tone: 内容语气 - target_platform: 目标发布平台 - reference_info: 需要补充的背景信息数组 要求: 1. 只输出 JSON,不要输出其他解释文字。 2. 如果用户没有提供某个字段,使用合理的默认值。 3. duration 必须是数字。 """ raw = self.call_llm(system_prompt, user_input) # 清理可能出现的 Markdown 代码块标记 raw = raw.strip() if raw.startswith("```"): raw = raw.strip("`") if raw.startswith("json"): raw = raw[4:] return json.loads(raw)这里我做了个小处理:如果模型在 JSON 外层加了 Markdown 代码块,先去除再解析,提升鲁棒性。
5.4 剧本生成与分镜生成节点
剧本节点和分镜节点都继承自BaseNode。这里我把提示词加载和解析逻辑分开,便于替换模板。
# nodes/storyboard_node.py import json from nodes.base import BaseNode class ScriptNode(BaseNode): """剧本生成节点""" def generate(self, task: dict) -> dict: system_prompt = """你是一个短视频编剧。 请根据以下任务参数,生成视频脚本。 脚本结构包含开场、主体、结尾三个部分。 输出为 JSON,格式如下: { "title": "视频标题", "sections": [ { "part": "开场", "content": "文案内容", "estimated_seconds": 5 } ] } 只输出 JSON,不要输出额外说明。 """ user_content = ( f"主题:{task['theme']}\n" f"目标时长:{task['duration']}秒\n" f"内容语气:{task['tone']}\n" f"目标平台:{task['target_platform']}\n" ) raw = self.call_llm(system_prompt, user_content) return json.loads(self._clean_json(raw)) @staticmethod def _clean_json(raw: str) -> str: raw = raw.strip() if raw.startswith("```"): raw = raw.strip("`") if raw.startswith("json"): raw = raw[4:] return raw class StoryboardNode(BaseNode): """分镜生成节点""" def generate(self, script: dict, duration: int) -> list: system_prompt = """你是一个视频分镜师。 请根据视频脚本,将内容拆分为分镜列表。 输出为 JSON 数组,每个元素的格式: { "shot_id": 1, "scene_description": "画面内容描述", "image_prompt": "用于图像生成模型的英文提示词", "narration": "本镜头对应的旁白文案", "duration_seconds": 3 } 只输出 JSON 数组。 """ user_content = ( f"视频脚本:\n{json.dumps(script, ensure_ascii=False)}\n" f"目标总时长:{duration}秒\n" ) raw = self.call_llm(system_prompt, user_content) return json.loads(self._clean_json(raw)) @staticmethod def _clean_json(raw: str) -> str: raw = raw.strip() if raw.startswith("```"): raw = raw.strip("`") if raw.startswith("json"): raw = raw[4:] return raw5.5 画面素材、语音合成与合成节点
这里给出通用的调用逻辑。由于不同服务商接口差异较大,我把生成图片、生成语音、合成视频封装成三个独立函数,读者按自己使用的服务替换内部实现即可。
# nodes/compose_node.py import os import subprocess from pathlib import Path class ImageNode: """画面素材生成节点(示例实现)""" def __init__(self, output_dir: str = "outputs/images"): self.output_dir = Path(output_dir) self.output_dir.mkdir(parents=True, exist_ok=True) def generate(self, shot: dict) -> str: """根据分镜信息生成图片,返回图片路径。 实际项目中,这里应调用图像生成模型的 API。 """ image_prompt = shot["image_prompt"] image_path = self.output_dir / f"shot_{shot['shot_id']:03d}.png" # 示例:调用图像生成接口(需按实际服务商接口调整) # image_bytes = call_image_api(image_prompt) # image_path.write_bytes(image_bytes) # 占位:创建一个空文件,便于验证流程 image_path.touch() return str(image_path) class TTSNode: """语音合成节点(示例实现)""" def __init__(self, output_dir: str = "outputs/audios"): self.output_dir = Path(output_dir) self.output_dir.mkdir(parents=True, exist_ok=True) def generate(self, shot: dict) -> str: """根据旁白文案生成音频,返回音频路径。 实际项目中,这里应调用 TTS 服务的 API。 """ narration = shot["narration"] audio_path = self.output_dir / f"shot_{shot['shot_id']:03d}.mp3" # 示例:调用 TTS 接口(需按实际服务商接口调整) # audio_bytes = call_tts_api(narration) # audio_path.write_bytes(audio_bytes) # 占位:创建一个空文件 audio_path.touch() return str(audio_path) class ComposeNode: """视频合成节点""" def __init__(self, output_path: str = "outputs/final.mp4"): self.output_path = output_path def compose(self, shots: list, images: dict, audios: dict) -> str: """ 合成最终视频。 实际项目中,这里应使用 FFmpeg 把图片和音频按时间轴拼接。 """ # 构建 FFmpeg 命令是相对复杂的,这里给出完整思路 # 1. 为每个镜头生成一个图片+音频的片段 # 2. 将所有片段拼接 # 3. 输出最终文件 # # 由于不同平台对视频编码要求不同,本示例不直接执行 FFmpeg, # 而是把待执行的命令打印出来,方便读者按需调整。 for shot in shots: shot_id = shot["shot_id"] print(f"[Compose] shot {shot_id}: " f"image={images[shot_id]}, audio={audios[shot_id]}") output_dir = os.path.dirname(self.output_path) os.makedirs(output_dir, exist_ok=True) with open(self.output_path, "w") as f: f.write("demo final video placeholder") return self.output_path这里的ImageNode和TTSNode是占位实现,目的是让流水线完整跑通。接入真实服务时,只需要替换generate方法内部的 API 调用即可。
5.6 主流程编排
workflow.py是 Agent 的主入口,它把上面各个节点串起来。
# workflow.py import json from pathlib import Path from config import check_config from nodes.script_node import TaskParserNode, ScriptNode from nodes.storyboard_node import StoryboardNode from nodes.compose_node import ImageNode, TTSNode, ComposeNode def save_json(data, path: str): Path(path).parent.mkdir(parents=True, exist_ok=True) with open(path, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) print(f"[Saved] {path}") def run_workflow(user_input: str): # 0. 检查配置 check_config() # 1. 需求解析 print(">>> 1. 需求解析") parser = TaskParserNode() task = parser.parse(user_input) save_json(task, "outputs/task.json") # 2. 剧本生成 print(">>> 2. 剧本生成") script_node = ScriptNode() script = script_node.generate(task) save_json(script, "outputs/script.json") # 3. 分镜生成 print(">>> 3. 分镜生成") storyboard_node = StoryboardNode() storyboard = storyboard_node.generate(script, task["duration"]) save_json(storyboard, "outputs/storyboard.json") # 4. 画面素材生成 print(">>> 4. 画面素材生成") image_node = ImageNode() images = {} for shot in storyboard: shot_id = shot["shot_id"] images[shot_id] = image_node.generate(shot) # 5. 语音合成 print(">>> 5. 语音合成") tts_node = TTSNode() audios = {} for shot in storyboard: shot_id = shot["shot_id"] audios[shot_id] = tts_node.generate(shot) # 6. 视频合成 print(">>> 6. 视频合成") compose_node = ComposeNode() final_path = compose_node.compose(storyboard, images, audios) print(f"\n[完成] 最终视频输出到: {final_path}") return final_path if __name__ == "__main__": user_description = input("请输入视频主题描述:") run_workflow(user_description)5.7 运行与验证
在项目根目录执行:
python workflow.py输入例如:
请输入视频主题描述:用 60 秒介绍 AI Agent 的基本概念,风格偏科技感,适合B站发布如果一切正常,你会看到类似下面的运行日志:
>>> 1. 需求解析 [Saved] outputs/task.json >>> 2. 剧本生成 [Saved] outputs/script.json >>> 3. 分镜生成 [Saved] outputs/storyboard.json >>> 4. 画面素材生成 >>> 5. 语音合成 >>> 6. 视频合成 [Compose] shot 1: image=outputs/images/shot_001.png, audio=outputs/audios/shot_001.mp3 [Compose] shot 2: image=outputs/images/shot_002.png, audio=outputs/audios/shot_002.mp3 (略) [完成] 最终视频输出到: outputs/final.mp4此时outputs目录下会生成完整的中间产物:
outputs/ ├── task.json ├── script.json ├── storyboard.json ├── images/ │ ├── shot_001.png │ ├── shot_002.png │ └── ... ├── audios/ │ ├── shot_001.mp3 │ └── ... └── final.mp4到这里,“从提示词到成片”的 Agent 骨架已经跑通了。接下来只需要把ImageNode、TTSNode、ComposeNode三处占位逻辑替换为真实服务即可。
6. 常见问题与排查思路
在实际项目中,最容易出问题的不是 Python 代码本身,而是模型输出格式不稳定、接口限流和成本失控。下面整理了我遇到过的高频问题。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
json.loads报错,无法解析模型输出 | 模型在 JSON 外层加了 Markdown 代码块,或直接输出了多余文字 | 在解析前做清洗处理;提示词中写死“只输出 JSON,不要输出解释文字” |
| 分镜时长总和远大于目标时长 | 模型没有严格遵守时长约束 | 在提示词中增加“duration_seconds 之和应接近目标时长”,并在代码中增加校验,超差时重新生成 |
| Grok API 调用超时 | 网络问题或服务端繁忙 | 增加重试机制,设置合理的超时时间;遇到“high demand”类错误时切换备用接口或稍后重试 |
| 视频成片画面与文案不匹配 | 分镜的image_prompt描述和narration内容脱节 | 在分镜提示词中明确要求“画面内容必须与旁白表达的信息一致” |
| 生成过程 Token 消耗过快 | 没有缓存中间结果,每次调试都重新调用大模型 | 每个节点输出保存到本地文件;调试阶段优先读取本地缓存 |
| 图片生成接口限流 | 并发请求过多或免费额度用尽 | 控制生成速度,加入 sleep 或信号量;优先处理图片生成队列 |
| 合成视频没有声音 | 音频文件为空或 FFmpeg 命令未正确拼接音轨 | 单独检查音频文件是否能播放;用 FFmpeg 命令验证音轨是否存在 |
针对最频繁的“JSON 解析失败”问题,建议增加一个简单有效的兜底函数:自动截取第一个{到最后一个}之间的内容再解析。
import json def extract_json(text: str): """从模型输出中提取 JSON 对象或数组""" text = text.strip() # 去掉 Markdown 代码块标记 if text.startswith("```"): text = text.strip("`") if text.startswith("json"): text = text[4:] # 直接尝试解析 try: return json.loads(text) except json.JSONDecodeError: pass # 截取从第一个 { 或 [ 到最后一个 } 或 ] 的内容 start = min(text.find("{"), text.find("[")) end = max(text.rfind("}"), text.rfind("]")) if start == -1 or end == -1 or end <= start: raise ValueError(f"无法从输出中提取 JSON: {text}") return json.loads(text[start:end + 1])这个函数可以放在utils.py中,所有节点解析输出时统一使用。
7. 最佳实践与工程建议
流水线跑通只是第一步,能稳定、低成本、高质量地产出视频才是目标。下面这些经验来自我在真实项目中的反复调整。
7.1 提示词模板要版本化管理
提示词是这个系统里最容易被修改、也最容易改崩的部分。建议:
- 把提示词模板保存为独立
.md文件,而不是硬编码在 Python 代码里。 - 对模板增加版本号,例如
script_v3.md。 - 修改模板前先复制一份,方便回滚。
- 每次模板变更,记录变更内容和效果对比。
这样做的原因是,大模型行为对提示词非常敏感,改一个字可能影响后续所有输出。
7.2 把“缓存”作为第一优先级
大模型 API 是按 Token 计费的,图像生成和 TTS 同样付费。在开发调试阶段,80% 的时间其实是在调整某个节点,如果每次都重新跑全流程,成本会迅速失控。
我常用的缓存策略:
- 每个节点输出先写文件。
- 节点执行前检查目标文件是否存在,存在则跳过调用,直接读取。
- 只有在明确需要重新生成某个环节时,删除对应缓存文件再运行。
def get_or_create_json(path: str, create_func): """如果文件存在,直接读取;否则执行 create_func 并保存""" from pathlib import Path if Path(path).exists(): with open(path, "r", encoding="utf-8") as f: return json.load(f) data = create_func() Path(path).parent.mkdir(parents=True, exist_ok=True) with open(path, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) return data合理使用缓存后,一次批量生成 10 条视频的成本能降低 60% 以上。
7.3 增加人工审核节点
AI 全自动生成的视频,在正式发布前一定要有人工审核环节。风险主要集中在:
- 文案内容是否准确、合规。
- 生成的画面是否有违规、低俗内容。
- 配音发音是否正确,尤其涉及专有名词时。
建议在“分镜生成”和“画面素材生成”之间增加一个审核环节:人工确认分镜文案无问题后,再继续生成画面素材。虽然多了一道人工操作,但能显著降低返工成本。
7.4 记录完整执行日志
Agent 系统比普通脚本复杂,任何一个节点都可能失败。建议在流水线中添加结构化日志:
import logging logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] %(name)s: %(message)s", filename="workflow.log", )日志至少要记录:
- 每个节点的开始时间、结束时间。
- 每个节点的输入摘要和输出文件路径。
- 调用大模型时的 Prompt 长度和 Token 预估。
- 失败节点的完整错误信息。
7.5 安全与合规注意事项
调用第三方大模型和生成服务时,有几个底线必须注意:
- 不要用明文保存 API Key,使用环境变量或密钥管理服务。
- 不要把所有内部提示词模板对外公开,部分提示词可能包含业务核心逻辑。
- 生成内容前对用户输入做敏感词过滤,避免生成违规内容。
- 大批量并发请求前,先小流量测试,避免触发服务方限流或封禁。
- 视频素材、配音音色使用前确认版权与授权范围,尤其是商用场景。
8. 总结与下一步学习方向
这篇文章从概念、架构、提示词设计、完整代码到排错指南,覆盖了“Grok 4.6 代理自动制作视频”的完整链路。
通过本文,你应该已经掌握:
- AI Agent 在视频自动生成流程中扮演的“调度者”角色。
- 面向 Agent 的提示词为什么要强调结构化输出。
- 如何用 Python 把需求解析、剧本生成、分镜生成、素材生成、语音合成、视频合成串成一条流水线。
- 如何通过缓存、日志、人工审核提升系统的稳定性与可控性。
如果继续深入,建议下一步按这几个方向展开:
- 构建“规划器 + 执行器”式 Agent:让大模型根据任务动态决定调用哪些节点,而不是固定线性流程。
- 引入工具调用机制:让模型能主动调用 FFmpeg 命令、文件读取函数,而不是只输出 JSON。
- 增加视频风格一致性控制:通过固定风格词、统一配色、统一字幕样式等方式,保证多镜头成片风格统一。
- 优化提示词模板:针对你常用的内容赛道,沉淀一批经过验证的提示词模板,形成自己的提示词工程库。
- 接入公开 API 时做好容错:把限流、超时、模型不响应等异常统一处理,提高生产环境的可用性。
最后提醒一句:AI 自动生成视频不是“零成本印钞机”,它仍然需要你在提示词设计、素材审核、流程调优上持续投入。把它当成一个需要耐心打磨的自动化生产线,它会成为你内容生产的得力助手。