
在刷短视频的时候经常能看到类似“我的男朋友好惨啊不过话又说回来....”这样一句话再配上#童年和#AI很容易让人好奇点进去。第一眼你会觉得这只是一个情感吐槽但仔细拆解这类内容其实非常适合作为 AI 内容创作的样本它有情绪反差、有时间背景、有画面感而且完全可以用提示词工程、文生图、图生视频、短视频合成、情感分析这一套 AI 工程流程做出来。本文就把这句话当作一个输入案例带大家从零搭建一条“一句话 → 完整视频 → 内容分析”的 AI 内容生产流水线适合想入门 AI 应用开发、AI 短视频创作或者准备参加类似#AI浪潮创作计划活动的读者阅读。文章会覆盖环境准备、提示词模板、LLM 调用、文生图接口、FFmpeg 合成、情感分析以及常见的排查问题和工程建议。代码以通用接口为主你可以替换成任意大模型或图像生成服务。全程不依赖特定厂商的私有 SDK核心逻辑都可以复用。1. 背景与核心概念1.1 AI 浪潮下为什么“一句话”能变成创作素材传统内容创作的流程通常是选题 → 写稿 → 拍摄/制图 → 剪辑 → 发布。这个过程对设备、人力、审美都有一定要求。而生成式 AI 出现之后最短的创作链路变成了文案 → 脚本 → 画面 → 视频。只要你有一个足够有画面感的“输入”剩下的很多环节都可以通过模型自动完成。“我的男朋友好惨啊不过话又说回来....”这句话之所以适合做 AI 内容实验是因为它天然包含一种“情绪转折”。前半句是吐槽后半句用“话又说回来”把情绪拉回温情再配上#童年这个标签读者会自然脑补出小时候的相处画面。这种“反差 留白”的结构恰恰是短视频脚本里非常经典的开场方式。从技术角度看我们不需要真的去关心这条内容里的人物关系。我们要做的是把这句话当作一个输入样本让大模型扩展出剧情再让文生图模型生成画面最后合成视频。这套流程才是本文真正要讲清楚的东西。1.2 AI 内容创作计划是什么像#AI浪潮创作计划这样的标签通常是一些内容平台或社区为了鼓励用户使用 AI 创作而发起的活动。参与者的做法各不相同有人用大模型写短篇小说有人用文生图模型做漫画也有人用 AI 生成短视频。这类活动的本质是“任务型创作”平台给出一个主题或标签创作者利用 AI 工具完成作品并发布。从工程角度来看一个能稳定复现的 AI 内容创作流程通常包括下面几个环节输入理解把用户提供的短文本转换成结构化脚本。多模态生成根据脚本生成图片、音频或视频素材。内容合成把素材用工程手段合并成最终作品。数据分析对文案或用户反馈做情感分析辅助优化。本文不会去评论具体平台的活动规则而是把这套通用流程完整跑一遍。你可以把它当作一次 AI 应用开发实战也可以把它当作参加创作活动的技术准备。1.3 读完这篇文章你能获得什么这篇文章会围绕一条真实可用的示例文案展开逐步完成下面这些事情使用大模型把“一句话”扩展成带分镜的短视频脚本。使用文生图接口生成关键帧画面。使用 Python 和 FFmpeg 把图片序列合成视频。使用大模型或规则方法对文案做情感分析。整理一套可以复用的提示词模板和项目目录结构。梳理常见报错、合规边界和工程落地建议。换句话说这篇文章不是只讲某个模型的 API 用法而是一个偏“工程实践”的轻量级 AI 应用开发案例。2. 环境准备与技术选型2.1 运行环境为了尽量降低上手门槛本文的代码基于 Python 编写核心依赖只有requests、python-dotenv和Pillow。视频合成部分依赖系统安装的 FFmpeg。建议环境如下操作系统Windows 10/11、macOS、Linux 均可。Python 版本3.9 或更高。FFmpeg建议 4.4 以上版本。GPU不是必须的。如果只是调用云端接口CPU 环境就能运行。如果你打算在本地跑 Stable Diffusion 这类模型那么建议准备 N 卡显存 8G 以上会舒服一些。但本文示例以云端 API 为主没有 GPU 也能完成。2.2 项目依赖安装先创建虚拟环境并安装 Python 包python -m venv .venv source .venv/bin/activate # Windows 使用 .venv\Scripts\activate然后创建requirements.txtrequests2.31.0 python-dotenv1.0.0 Pillow10.0.0安装依赖pip install -r requirements.txt接着需要确认 FFmpeg 可用ffmpeg -version如果提示找不到命令需要先安装 FFmpeg。macOS 可以使用 Homebrew 安装Windows 可以在 FFmpeg 官网下载可执行文件并配置环境变量Linux 可以用系统包管理器安装。不同系统安装命令差异较大请按实际环境操作。2.3 项目目录结构推荐先把项目目录规划好后续代码不会乱。ai-short-video/ ├── .env ├── requirements.txt ├── utils/ │ ├── __init__.py │ ├── llm.py │ └── image_gen.py ├── scripts/ │ ├── generate_story.py │ ├── generate_images.py │ ├── compose_video.py │ └── analyze_sentiment.py ├── prompts/ │ └── story_prompt_template.txt └── outputs/ ├── story.json ├── frames/ └── final.mp4在这个结构中utils放通用方法scripts放入口脚本outputs放中间产物和最终视频。密钥放在.env文件里避免提交到代码仓库。.env文件写法如下LLM_API_KEYyour-llm-api-key LLM_BASE_URLhttps://your-llm-endpoint/v1/chat/completions LLM_MODELyour-model-name IMAGE_API_KEYyour-image-api-key IMAGE_API_URLhttps://your-image-endpoint/v1/images/generations IMAGE_MODELyour-image-model-name这里只是示例实际需要替换成你选择的模型服务地址和密钥。3. 提示词工程把一句话扩展成完整脚本3.1 理解原始输入与目标原始输入是我的男朋友好惨啊不过话又说回来.... #童年 #AI #AI浪潮创作计划要在 AI 生成时不偏题我们得先拆解关键要素情绪前半句吐槽后半句转折。时间背景童年。人物男朋友或者说“小时候的他”。风格口语化、有画面感、适合短视频。因为原文只有一句话画面信息严重不足所以需要大模型来脑补细节。我们要给 LLM 一个非常明确的任务输出结构化的 JSON而不是自由文本。3.2 编写通用 LLM 调用工具为了避免重复写 HTTP 请求我们先写一个通用的 LLM 调用模块。文件路径utils/llm.py# utils/llm.py import os import requests from dotenv import load_dotenv load_dotenv() def chat_completion(prompt: str, system: str , temperature: float 0.8): api_key os.getenv(LLM_API_KEY, ) base_url os.getenv(LLM_BASE_URL, ) model os.getenv(LLM_MODEL, ) if not api_key or not base_url or not model: raise RuntimeError(请在 .env 文件中配置 LLM_API_KEY、LLM_BASE_URL、LLM_MODEL) headers { Authorization: fBearer {api_key}, Content-Type: application/json, } payload { model: model, messages: [ {role: system, content: system}, {role: user, content: prompt}, ], temperature: temperature, } resp requests.post(base_url, headersheaders, jsonpayload, timeout120) resp.raise_for_status() data resp.json() return data[choices][0][message][content]这段代码使用了绝大多数大模型服务通用的 “OpenAI 兼容接口” 格式。很多国内外的模型服务平台都支持这种调用方式所以你可以把LLM_BASE_URL换成自己的服务地址而不用修改核心逻辑。3.3 生成剧情脚本接下来我们编写脚本生成逻辑。文件路径scripts/generate_story.py# scripts/generate_story.py import json from utils.llm import chat_completion STORY_PROMPT 你是一个短视频编剧擅长把平淡的一句话扩展成有画面感的童年回忆故事。 请根据下面的用户输入生成一个适合 AI 绘画和短视频配音的脚本。 用户输入 {raw_text} 要求 1. 保留原句“吐槽 话又说回来”的反差结构 2. 围绕“童年”主题给出 4~6 个场景 3. 每个场景包含scene_id、narration、image_prompt、duration 4. narration 要口语化适合配音 5. image_prompt 要写清楚主体、环境、风格、色调 6. 输出必须是 JSON不要输出任何解释文字。 def parse_json_response(text: str): text text.strip() if text.startswith(): text text.strip() if text.startswith(json): text text[4:] return json.loads(text) def main(): raw_text 我的男朋友好惨啊不过话又说回来.... #童年 #AI #AI浪潮创作计划 prompt STORY_PROMPT.format(raw_textraw_text) result chat_completion(prompt) story parse_json_response(result) with open(outputs/story.json, w, encodingutf-8) as f: json.dump(story, f, ensure_asciiFalse, indent2) print(生成成功outputs/story.json) print(json.dumps(story, ensure_asciiFalse, indent2)) if __name__ __main__: main()这里有一个容易被忽略的细节大模型有时会输出带 markdown 代码块包裹的 JSON例如json {...}所以 parse_json_response 需要先把反引号和 json 标记去掉再交给 json.loads 解析。真实项目中建议再加一层异常兜底比如截取第一个 { 到最后一个 } 之间的内容。 ### 3.4 示例输出结构 运行脚本后你会得到类似下面的 JSON 结构 json { title: 那个永远有点惨的小男孩, tone: 温暖、怀旧、带一点点好笑, scenes: [ { scene_id: 1, narration: 我的男朋友小时候真的很惨放学路上总要摔一跤。, image_prompt: 童年乡村放学土路小男孩背着书包摔倒在泥坑旁夕阳暖色调手绘动画风格, duration: 6 }, { scene_id: 2, narration: 话又说回来那时候他总会从口袋里掏出一颗糖给我。, image_prompt: 小女孩和小男孩坐在老槐树下男孩递出一颗水果糖阳光透过树叶柔和怀旧风格, duration: 6 } ] }注意不同模型生成的结果差异会很大。如果你发现画面风格不统一可以在提示词中固定风格关键词比如“手绘动画、暖色调、景深虚化”。这部分我们放到后面“最佳实践”里再展开。4. 多模态生成AI 绘画与 AI 视频4.1 编写通用文生图工具有了脚本之后下一步是把每个narration对应的image_prompt转成图片。文件路径utils/image_gen.py# utils/image_gen.py import base64 import os import requests from dotenv import load_dotenv load_dotenv() def generate_image(prompt: str, output_path: str, size: str 1024x1024): api_key os.getenv(IMAGE_API_KEY, ) api_url os.getenv(IMAGE_API_URL, ) model os.getenv(IMAGE_MODEL, ) if not api_key or not api_url or not model: raise RuntimeError(请在 .env 文件中配置图片生成服务) headers { Authorization: fBearer {api_key}, Content-Type: application/json, } payload { model: model, prompt: prompt, n: 1, size: size, response_format: b64_json, } resp requests.post(api_url, headersheaders, jsonpayload, timeout180) resp.raise_for_status() data resp.json() image_data data[data][0][b64_json] image_bytes base64.b64decode(image_data) os.makedirs(os.path.dirname(output_path), exist_okTrue) with open(output_path, wb) as f: f.write(image_bytes) print(f图片已保存: {output_path})这个工具假设图片生成接口返回的是b64_json。如果服务返回的是图片 URL那么代码需要改成requests.get(data[data][0][url])下载图片。不同厂商差异很大建议以实际文档为准。4.2 批量生成关键帧接下来读取上一步生成的story.json批量生成图片。文件路径scripts/generate_images.py# scripts/generate_images.py import json from utils.image_gen import generate_image STYLE_SUFFIX , 高清细节手绘动画风格暖色调统一角色设定 def main(): with open(outputs/story.json, r, encodingutf-8) as f: story json.load(f) for scene in story[scenes]: scene_id scene[scene_id] prompt scene[image_prompt] STYLE_SUFFIX output_path foutputs/frames/scene_{scene_id:02d}.png generate_image(prompt, output_path) if __name__ __main__: main()这里加上STYLE_SUFFIX的目的是尽量统一多张图片的画风。不过我们也要诚实地说仅靠提示词很难做到真正意义上的“同一角色”尤其是人物脸部和服装。如果对一致性要求高需要采用 LoRA、ControlNet 或角色参考图等进阶方案。本文先不展开但你要有这个意识。4.3 图生视频可选进阶环节如果不想做静态幻灯片式短视频可以在关键帧之间做“图生视频”。目前很多视频生成服务都支持输入一张图片和一段运动描述输出几秒钟动态片段。代码思路大致如下# utils/video_gen.py 伪代码示例需按实际服务调整 def generate_video_from_image(image_path: str, prompt: str, output_path: str): # 1. 读取图片并转换为服务要求的格式 # 2. 拼接多模态请求参数 # 3. 调用视频生成接口轮询任务状态 # 4. 下载生成的 MP4 文件 pass因为视频生成接口普遍没有统一标准有的服务是同步返回有的服务需要提交任务后轮询有的还涉及排队时间所以这里不写出伪代码的具体实现。建议你在接入具体服务时先阅读该平台的接口文档用脚本先做一次最小调用确认返回格式后再接进主流程。4.4 生成结果校验无论使用哪种图片生成服务都不要把“生成了图片”等同于“生成成功”。至少要做下面几项校验检查文件是否存在且文件大小不为 0。用 Pillow 打开图片确认宽高是否符合后续合成需求。人工浏览一遍关键帧看画面是否严重偏离文案。如果使用 Pillow 检查可以写一个小工具from PIL import Image img Image.open(outputs/frames/scene_01.png) print(img.size, img.mode)如果发现图片比例不统一后期合成时会出现黑边或裁切问题建议在生成阶段就固定size参数比如统一使用1024x576这样的横屏比例。5. 合成与后处理用 Python FFmpeg 制作短视频5.1 准备音频素材短视频不能没有声音。最理想的方案是调用 TTS 服务把每个场景的narration合成为配音。不同 TTS 服务差异较大这里给出一个通用思路。# scripts/generate_tts.py 示例思路 def synthesize_tts(text: str, output_path: str): # 调用 TTS 服务将返回的音频二进制写入本地文件 # 以实际服务文档为准 pass如果你暂时不想接 TTS也可以先生成一个无音频的视频文件后续再手动配音。文章示例里会把音频当作可选参数这样代码跑起来更快。5.2 图片序列转视频文件路径scripts/compose_video.py# scripts/compose_video.py import subprocess def compose_video( frames_dir: str, output_path: str, audio_path: str None, fps: int 24, ): cmd [ ffmpeg, -y, -framerate, str(fps), -pattern_type, glob, -i, f{frames_dir}/*.png, ] if audio_path: cmd [-i, audio_path] cmd [ -c:v, libx264, -pix_fmt, yuv420p, ] if audio_path: cmd [-c:a, aac, -shortest] cmd [output_path] print( .join(cmd)) subprocess.run(cmd, checkTrue) if __name__ __main__: compose_video( frames_diroutputs/frames, output_pathoutputs/final.mp4, audio_pathNone, fps24, )这段代码使用 FFmpeg 把outputs/frames下的 PNG 图片合成视频。-pattern_type glob可以一次匹配多张图片但它在 Windows 命令行的兼容性不一定好。如果你是 Windows 环境建议改成ffmpeg -framerate 24 -i outputs/frames/scene_%02d.png -c:v libx264 -pix_fmt yuv420p outputs/final.mp4这里%02d表示文件名必须是scene_01.png、scene_02.png这种两位数字格式。5.3 添加字幕与简单转场短视频加上字幕阅读体验会好很多。先生成一份.srt字幕文件再用 FFmpeg 的subtitles滤镜嵌入画面。ffmpeg -i outputs/final.mp4 -vf subtitlessubtitle.srt:force_styleFontSize18 -c:a copy outputs/final_with_sub.mp4这个命令在 macOS 和 Linux 上比较稳定。Windows 下需要注意字幕文件路径里的盘符冒号示例-vf subtitlesC\\:/subtitle.srt如果暂时不需要自动转场可以跳过这一步。真正的转场效果可以用xfade滤镜但需要精确计算每段素材的时间点代码复杂度会明显上升。对于本文这种“关键帧图片”模式静态切换加淡入淡出就足够流畅了。6. 情感分析与内容理解6.1 用 LLM 做单条文本情感分析内容发布之后我们需要知道这条文案给人的情绪感受是什么。使用大模型做情感分析最大的好处是不需要标注数据开箱即用。文件路径scripts/analyze_sentiment.py# scripts/analyze_sentiment.py import json from utils.llm import chat_completion SENTIMENT_PROMPT 请对下面的文本进行情感分析只输出 JSON不要输出解释。 要求 JSON 字段 - label: 正面/负面/中性 - score: 0 到 100 的整数表示正面程度 - keywords: 数组列出文本中的情感关键词 - reason: 一句话解释判断依据 文本 {text} def analyze_text(text: str) - dict: result chat_completion( SENTIMENT_PROMPT.format(texttext), system你是一个情感分析专家, temperature0.2, ) result result.strip() if result.startswith(): result result.strip() if result.startswith(json): result result[4:] return json.loads(result) if __name__ __main__: content 我的男朋友好惨啊不过话又说回来他小时候每次摔倒都会笑着站起来。 print(analyze_text(content))输出可能是{ label: 正面, score: 72, keywords: [好惨, 话又说回来, 笑着], reason: 虽然前半句在吐槽但后半句用回忆和笑容带出温馨感整体偏正面 }这里把temperature设置为 0.2是为了让模型输出更稳定避免同一条文本每次分析结果相差太大。6.2 批量分析评论区文本真实场景中你可能要分析很多条评论而不是一条。下面这段代码演示如何把结果写入 CSV 文件。import csv from analyze_sentiment import analyze_text comments [ 小时候真是太好玩了, 只有我觉得这句话很心酸吗, AI 生成的画面太有感觉了, ] with open(outputs/sentiment.csv, w, encodingutf-8, newline) as f: writer csv.writer(f) writer.writerow([comment, label, score, keywords, reason]) for c in comments: r analyze_text(c) writer.writerow([c, r[label], r[score], |.join(r[keywords]), r[reason]]) print(分析完成)这种批量脚本适合在活动结束后复盘内容反馈也适合用来评估不同文案方向的数据表现。不过要注意调用大模型接口都是有成本的如果评论量很大建议先用简单的关键词规则做初筛再把少量不确定的文本交给大模型判断。6.3 情感分析怎么反哺内容生产情感分析不是终点而是后续内容迭代的依据。比如我们对比两条标题标题 A“我的男朋友好惨啊不过话又说回来....”标题 B“童年回忆那个总在摔跤的男孩”通过情感分析我们可以量化两条文案的正面情绪分数和关键词分布再结合实际点击率判断哪一类文案更能引起共鸣。这就是“数据闭环”的思路也是 AI 内容创作区别于单纯手工创作的重要一点。7. 常见问题与排查7.1 常见问题汇总下面整理了一份高频问题清单基本覆盖了从环境配置到视频合成的常见坑。问题现象常见原因解决思路调用 LLM 接口报 401API Key 配置错误或已过期检查.env中的密钥确认没有多余空格调用 LLM 接口报 404LLM_BASE_URL不是/v1/chat/completions格式查看服务文档换成完整请求地址返回内容不是 JSON模型没有按照提示词输出调低 temperature增加“只输出 JSON”约束图片生成速度太慢服务排队或尺寸过大降低图片分辨率或改用异步任务图片比例不统一不同请求使用了不同 size统一设置生成接口的 size 参数FFmpeg 找不到文件glob 匹配不到图片先确认outputs/frames目录下存在 PNG 文件Windows 下 FFmpeg 命令报错路径分隔符或通配符兼容问题改用scene_%02d.png方式中文字幕乱码字体缺失或字幕编码不对指定中文字体路径字幕文件保存为 UTF-8内容被平台拦截生成内容涉及隐私或版权问题提前做内容审核避免使用未授权人脸和品牌7.2 一个通用的排查顺序遇到问题时不要直接怀疑模型能力先按下面顺序排查检查配置密钥、接口地址、模型名是否正确。检查输入原始文本是否有特殊字符JSON 是否被 markdown 包裹。检查权限服务商是否开通了对应模型权限账号是否欠费。检查数据流每一步的中间产物是否生成成功文件大小是否为 0。检查环境FFmpeg 版本是否符合要求Python 包是否安装完整。检查合规内容是否包含敏感信息是否需要打上“AI 生成”标识。这套排查思路不仅适用于本文项目也适用于大多数 AI 应用开发场景。7.3 如何避免问题再次发生最有效的方法是把“校验”纳入流程而不是等出错后再排查。比如在调用 LLM 后先用正则或 JSON 解析校验结果结构。在生成图片后检查文件大小和尺寸。在调用 FFmpeg 前先确认输入文件是否存在。在发布前用内容审核服务对文案和图片做一次合规检查。只有把校验和人工审核放进自动化流程里整个 pipeline 才真正具备上线条件。8. 最佳实践与工程建议8.1 提示词模板化与版本管理不要把提示词散落在代码里。推荐把所有提示词集中放在prompts目录下并在开发阶段记录每次修改。例如story_prompt_template.txt你是短视频编剧。 用户输入{raw_text} 要求 1. 输出 JSON 2. 保留情绪转折 3. 场景控制在 {scene_count} 个以内。代码里通过读取模板文件并格式化参数便于后续改动和维护。这样做的好处是你可以对多个不同主题的文案复用同一套提示词模板只需要替换raw_text和scene_count。8.2 内容合规与安全边界使用生成式 AI 做内容创作绝对不能忽略安全边界。这里给出几条最基本的建议不要使用未经授权的真实人脸、品牌 Logo、目标角色形象。不要生成暴力、色情、歧视等违规内容。不要把他的私人聊天内容直接作为输入至少要完成脱敏处理。关注平台对 AI 生成内容标识的要求必要时要标注“AI 生成”。涉及用户评论数据时要获得合法授权并最小化采集范围。合法授权、测试环境验证、最小权限原则这几条在任何 AI 应用工程里都适用。8.3 成本控制与异步任务大模型、文生图、视频生成服务的成本都不低尤其是视频生成接口。建议在工程上做好下面的事情对同一批提示词的生成结果做缓存避免重复调用。图片生成改成队列任务失败后支持有限次重试。大批量文本分类先用规则或轻量模型只有低置信度才调用大模型。视频生成结果用对象存储保存不放在本地临时目录。如果项目后续要部署成 Web 服务推荐使用消息队列把耗时任务异步化。用户提交创作请求后后端先返回“任务已接收”再由 Worker 消费任务最终通过轮询或 WebSocket 通知用户结果。8.4 模型部署与生产环境注意事项如果只是自己玩脚本式方案完全够用。但如果要做成产品就要考虑更多工程细节密钥管理不要把密钥写在前端代码或公开仓库里。配置隔离开发、测试、生产环境使用不同的.env或配置中心。日志记录记录每次调用的模型、参数、耗时、错误信息方便追踪。限流与降级当第三方 API 不稳定时要有熔断机制和备用供应商。灰度发布新提示词模板先在小流量场景验证效果再全量推广。备份回滚涉及配置修改时先保存上一版本便于快速回退。这些原则和传统后端系统没有本质区别唯一不同的是 AI 模型的输出具有不确定性所以更依赖日志和评估体系。8.5 数据隐私与用户授权最后再说一遍数据问题。“我的男朋友好惨啊”这类文本大概率是用户原创内容。如果你是在做个人实验使用自己的文案没问题如果你要爬取并分析别人的公开评论请务必遵守平台规则并确保数据使用方式符合相关法律法规。在工程上建议对输入文本做脱敏处理例如移除手机号、微信号、地理位置等个人信息再传给第三方 API。这样既能降低数据泄露风险也更符合隐私保护要求。9. 总结与学习路线这次我们用一句话作为输入完整跑通了一条 AI 内容创作流水线。我们从提示词工程开始把“我的男朋友好惨啊不过话又说回来.... #童年 #AI #AI浪潮创作计划”扩展成结构化脚本然后通过文生图接口批量生成关键帧再用 Python 调用 FFmpeg 把图片合成短视频最后用大模型做情感分析把内容创作从“凭感觉”变成一个可以量化、可以迭代的工程过程。如果你第一次接触 AI 应用开发下一步可以继续学习这些方向Stable Diffusion 部署与 LoRA 微调解决角色一致性问题。ComfyUI 或类似的可视化工作流工具降低多节点流程搭建难度。视频生成模型的基本使用顺序了解运动幅度、种子和噪声控制参数。提示词评测方法建立自己的“提示词效果评估集”。内容审核、水印和 AI 生成标识了解合规发布要求。实际项目里最先要关注的不是“模型够不够聪明”而是数据、成本和回流。建议你准备一个虚拟环境把这条 pipeline 跑通再用自己的童年故事替换输入文本观察每一步的生成结果差异。如果碰到具体报错欢迎在评论区留言也可以把这里的思路当成 debug 起点。