从AI小镇模拟到AI视频生成:Oneiric开源项目实战指南 📅 发布时间:2026/8/31 7:39:39 👁 浏览次数: 最近在做一个 AI 短视频方向的开源实验项目选定的主题是“Oneiric”——一个由 AI 自动生成梦境感视频短片。整个项目跑下来我发现最大的难点并不在“调用大模型生成对话”而是在“如何让 AI 角色真正像人一样有自己的记忆、行为和故事线”以及“如何把这些模拟出来的剧情最终变成一段能看的视频”。网上关于 AI 生成视频的教程很多但大多数要么只讲单个模型调用要么只讲概念真正能把角色模拟、事件导出、分镜生成、视频合成串成一条完整链路的很少。这篇文章会围绕 Oneiric 这个开源项目完整复盘我从 AI 小镇模拟器到 AI 生成视频的全过程并把代码、配置和踩坑点都梳理出来。无论你是想学习 AI Agent 开发还是想自己做 AI 短剧/AI 视频生成工具这篇文章都能给你一条可落地的路线。1. 背景什么是 Oneiric为什么用 AI 小镇来生成视频1.1 Oneiric 是什么Oneiric 这个词根源自希腊语“oneiros”意思是“梦”。在 AI 视频生成这个项目里Oneiric 代表一种带有梦境感、开放式的视觉风格画面不一定写实反而更像记忆碎片、幻觉和想象交织在一起的场景。更重要的是Oneiric 这个项目并不是“拿一段文本直接丢给视频模型”而是先构建一个 AI 小镇让多个 AI 角色在小镇里自由生活、对话、产生事件再把这些事件转成视频分镜。也就是说视频里的故事不是人写的而是 AI 角色在模拟环境中“活”出来的。这和传统 AI 生成视频有本质区别传统方式人写文案 → 文本生成视频。Oneiric 方式人设定角色 → AI 小镇自动运行 → 角色产生对话和事件 → 事件转成分镜 → 分镜生成画面 → 视频合成。这样做最大的好处是视频内容有真正的故事逻辑而不是一堆炫酷但没有叙事的画面。1.2 为什么这个方向值得关注如果你关注过 AI 短剧、AI 虚拟主播、游戏 NPC 开发一定会发现一个共同需求需要一批“有记忆、有个性、能长期维持行为逻辑”的 AI 角色。传统的对话模型每次调用都是独立的角色上一句话说了什么下一句话就可能忘掉。而 AI 小镇类项目通过记忆池、反思机制、规划机制让角色能持续积累经验行为逻辑更接近真实的人。Oneiric 项目把这件事和视频生成结合带来了几个直接的应用场景AI 短剧制作不用请演员AI 角色在小镇里自动演出。游戏 NPC 系统为游戏角色注入持续记忆和行为规划。交互叙事用户参与小镇事件改变故事走向。视频创作工具把文本模拟结果自动转成分镜和画面。1.3 本文适合哪些读者这篇文章适合三类人想入门 AI Agent 开发但对架构还不熟悉的新手。想做 AI 视频/短剧工具但不知道怎么把角色对话转成视频的开发者。已经跑过一些开源项目想在现有项目上扩展记忆、反思、分镜生成能力的进阶玩家。通过这篇文章你会掌握一条完整的链路角色设定 → 模拟运行 → 事件存档 → 分镜脚本 → 视频合成。2. 环境准备与项目结构在开始之前先说明一下版本和环境。Oneiric 项目通常跑在 macOS 或 Linux 环境下Windows 也可以运行但部分依赖需要额外处理。本文示例以 Python 3.10 Node.js 18 的环境为主具体版本请根据你本机实际情况调整。2.1 需要准备的工具工具用途说明Git拉取项目代码版本控制工具Python 3.9运行模拟器核心逻辑建议 3.10 或 3.11Node.js 18运行前端展示界面可选如果只跑命令行模拟可以不装FFmpeg合成视频最后生成视频必须用到大模型 API Key生成角色对话和分镜OpenAI 兼容接口均可2.2 获取项目源码Oneiric 项目基于 AI 小镇开源项目修改而来核心仓库地址为https://github.com/mewamew/my_ai_town克隆项目到本地git clone https://github.com/mewamew/my_ai_town.git cd my_ai_town建议先查看仓库根目录下的 README了解项目启动方式、依赖清单和数据库配置。很多开源项目在不同时间点的目录结构差异较大以仓库当前版本为准最稳妥。2.3 安装 Python 依赖大多数 AI 小镇类项目会有一个requirements.txt文件直接安装即可pip install -r requirements.txt如果项目没有requirements.txt通常也会在 README 中列出openai、flask、sqlalchemy等核心依赖。建议使用虚拟环境安装避免污染系统 Pythonpython -m venv venv source venv/bin/activate # macOS/Linux venv\Scripts\activate # Windows2.4 安装 FFmpegFFmpeg 用于将图片序列合成视频也可以把音频和视频合并。macOS 可以使用 Homebrew 安装brew install ffmpegUbuntu/Debian 使用 aptsudo apt update sudo apt install ffmpegWindows 用户需要从 FFmpeg 官网下载二进制文件并配置环境变量。安装完成后验证ffmpeg -version正常会输出一长串版本信息。3. 核心原理AI 角色如何在小镇里“生活”和“讲故事”Oneiric 项目最核心的部分不是视频生成模型而是 AI 角色的记忆与行为机制。只有角色行为足够真实生成的视频才会有故事感。3.1 生成式 Agent 的四个关键环节AI 小镇模式借鉴了生成式 AgentGenerative Agents的设计思路核心可以拆成四个环节感知Perception角色每次行动前会先感知当前环境自己在哪里身边有哪些角色最近发生了什么。感知信息会作为上下文注入到大模型请求中。记忆Memory角色不会记住所有事情而是把重要事件以自然语言形式存储到记忆库中。例如2025-01-10 09:30 在广场遇到了林晓聊起最近新开的咖啡馆记忆库通常使用向量数据库或简单的 JSON 文件存储。每次对话前会检索与当前场景最相关的记忆帮助角色做出更合理的回应。反思Reflection反思是一个周期性任务每隔一段时间角色会把最近发生的事件拿出来“复盘”提炼出更高层次的认知。例如最近三天林晓多次提到工作压力大应该多关心她的情绪反思结果会被写回记忆库让角色行为越来越有“个人特点”。规划Planning根据角色自身目标和近期记忆生成行动清单。例如1. 上午去咖啡馆写代码 2. 下午约林晓散步 3. 晚上为明天的分享会准备提纲规划结果会影响角色下一步的动作。3.2 对话生成与大模型调用在 Oneiric 项目中角色对话通过大模型接口生成。一个基础的角色对话函数通常包含三部分系统人设定义角色名字、性格、目标。当前场景角色所处位置、时间、周围事件。最近记忆从记忆库中检索出的相关历史。这里给出一个最简示例展示对话函数的核心逻辑# 文件路径simulate_town.py import os from openai import OpenAI client OpenAI(api_keyos.getenv(OPENAI_API_KEY)) def ask_agent(agent, scene, recent_speech): messages [ { role: system, content: ( f你叫{agent[name]} f性格是{agent[personality]} f你的目标是{agent[goal]}。 你生活在一个AI小镇中请用中文自然对话。 ) }, { role: user, content: ( f当前场景{scene}\n f你听到有人说{recent_speech}\n 请用一两句话回复保持你的人设。 ) } ] response client.chat.completions.create( modelgpt-4o-mini, # 按你实际开通的模型调整 messagesmessages, temperature0.8, max_tokens200 ) return response.choices[0].message.content.strip()这里需要特别注意这个示例基于openai库 1.x 版本的写法。如果项目使用的是旧版 0.x接口会有所不同。模型名称gpt-4o-mini只是示例实际使用哪种模型取决于你对接的 API 服务。如果用开源模型或国内大模型平台只要接口兼容 OpenAI 格式代码结构基本不变。temperature0.8控制回复随机性。数值越高回复越有想象力数值越低回复越稳定。梦境感视频场景下可以适度调高到 0.9。3.3 从模拟事件到视频分镜模拟运行一段时间后会产生大量事件记录。这些记录格式大概是{ timestamp: 2025-01-10 10:00:00, agent: 林晓, action: 来到咖啡馆看到李雷正在写代码, dialogue: 李雷你又在加班啊 }要把这些事件变成视频需要先转成分镜脚本。分镜脚本通常包含镜头描述、画面元素、角色状态、台词等内容。Oneiric 项目的常见做法是把事件记录按时间线分组每组生成一个分镜片段。例如时间分镜描述画面元素00:00-00:05小镇全景清晨阳光洒在街道上街道、树木、光线00:05-00:12林晓走进咖啡馆镜头跟随咖啡馆门口、角色背影00:12-00:20林晓和李雷对话特写两人面部表情、咖啡杯分镜生成后可以交给文本生成图像模型、视频生成模型或者用最简单的“文本卡片 配音”方式快速合成验证视频。4. 完整实战从 AI 小镇模拟到 Oneiric 视频生成接下来我带你完整走一遍 Oneiric 项目的核心流程。这里不依赖仓库内部具体代码而是演示一类通用方案你可以把它当作模块嵌入到自己的项目中。4.1 创建项目结构建议把项目拆成四个目录oneiric/ ├── agents/ # 角色配置 ├── simulation/ # 模拟运行代码 ├── story/ # 事件与分镜脚本 └── video/ # 生成的图片和视频创建目录mkdir -p oneiric/{agents,simulation,story,video} cd oneiric4.2 配置角色在agents/agents.yaml中定义两个角色作为小镇的第一批居民agents: - name: 林晓 personality: 温柔细腻有点文艺喜欢植物和诗歌 goal: 今天想在咖啡馆认识一位新朋友 avatar: young_woman_flowers_soft_light - name: 李雷 personality: 理性冷静的程序员喜欢修东西偶尔有点呆 goal: 想找人分享自己刚写完的小游戏 avatar: young_man_laptop_cafe_windowavatar字段表示生成角色画面时使用的图像描述词。在后续生成分镜画面时这个字段会直接拼进正向提示词中。为了方便 Python 读取写一个简单的加载函数# 文件路径simulation/load_agents.py import yaml from pathlib import Path def load_agents(pathagents/agents.yaml): with open(path, r, encodingutf-8) as f: data yaml.safe_load(f) return data[agents] if __name__ __main__: agents load_agents() for agent in agents: print(agent[name], agent[personality])运行python -m simulation.load_agents正常会输出两个角色的基本信息。4.3 编写模拟主循环模拟主循环的职责是让两个角色在某个场景中依次发言记录对话并把事件写入存档文件。# 文件路径simulation/run_simulation.py import json import os from datetime import datetime from openai import OpenAI from simulation.load_agents import load_agents client OpenAI(api_keyos.getenv(OPENAI_API_KEY)) def build_messages(agent, scene, memories, recent_speech): system_prompt ( f你叫{agent[name]}性格{agent[personality]}。 f当前目标是{agent[goal]}。 你生活在一个AI小镇里请用中文自然对话。 ) memory_text \n.join(f- {m} for m in memories[-5:]) user_prompt ( f当前场景{scene}\n f你最近记得的事情\n{memory_text}\n f你听到有人说{recent_speech}\n 请用一两句话回复并保持你的人设。 ) return [ {role: system, content: system_prompt}, {role: user, content: user_prompt}, ] def ask_agent(agent, scene, memories, recent_speech): messages build_messages(agent, scene, memories, recent_speech) response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, temperature0.85, max_tokens200 ) return response.choices[0].message.content.strip() def append_event(log_path, event): events [] if os.path.exists(log_path): with open(log_path, r, encodingutf-8) as f: events json.load(f) events.append(event) with open(log_path, w, encodingutf-8) as f: json.dump(events, f, ensure_asciiFalse, indent2) def main(): agents load_agents() scene 下午三点小镇边缘的一家咖啡馆窗外下着小雨 memories [] log_path story/simulation_log.json for round_idx in range(3): for agent in agents: recent_speech if memories: recent_speech memories[-1][dialogue] reply ask_agent( agentagent, scenescene, memories[m[dialogue] for m in memories], recent_speechrecent_speech ) event { timestamp: datetime.now().strftime(%Y-%m-%d %H:%M:%S), round: round_idx, agent: agent[name], scene: scene, dialogue: reply, action: f{agent[name]}看了看窗外的雨喝了一口咖啡 } memories.append(event) append_event(log_path, event) print(f[{event[timestamp]}] {agent[name]}{reply}) if __name__ __main__: main()运行前先配置 API Keyexport OPENAI_API_KEY你的API Key然后执行python -m simulation.run_simulation预期输出类似[2025-01-10 15:02:11] 林晓窗外的雨声让人很安静平时总在忙坐在这里发呆也挺好的。 [2025-01-10 15:02:20] 李雷啊你也喜欢下雨天吗我写代码的时候特别喜欢这种背景音。每一次对话都会追加写入story/simulation_log.json。这就是 AI 小镇“故事”的原始素材。4.4 把事件转成视频分镜脚本有了模拟事件后下一步是把 JSON 事件数据转换成适合视频生成的分镜脚本。这里提供一个转换函数# 文件路径story/make_storyboard.py import json def load_events(pathstory/simulation_log.json): with open(path, r, encodingutf-8) as f: return json.load(f) def build_storyboard(events): storyboard [] for i, event in enumerate(events): shot { shot_id: i 1, duration: 4, scene: event[scene], character: event[agent], dialogue: event[dialogue], image_prompt: ( f{event[agent]}在{event[scene]}中 f说‘{event[dialogue]}’ ) } storyboard.append(shot) return storyboard if __name__ __main__: events load_events() storyboard build_storyboard(events) with open(story/storyboard.json, w, encodingutf-8) as f: json.dump(storyboard, f, ensure_asciiFalse, indent2) for shot in storyboard: print(shot[shot_id], shot[character], shot[dialogue])运行python -m story.make_storyboard得到story/storyboard.json。这个文件就是你视频的“剧本”。这里要注意分镜脚本越具体后续生成画面时的可控性越强。建议把场景描述细化到“光线、天气、镜头角度、角色动作”而不是只写“两个人在聊天”。4.5 用图像生成画面可选方案如果项目接入的是图像生成模型可以使用以下思路生成每一帧画面。# 文件路径video/generate_frames.py import json import os from openai import OpenAI client OpenAI(api_keyos.getenv(OPENAI_API_KEY)) def load_storyboard(pathstory/storyboard.json): with open(path, r, encodingutf-8) as f: return json.load(f) def generate_frame(storyboard): for shot in storyboard: response client.images.generate( modeldall-e-3, # 以实际可用模型为准 promptshot[image_prompt], size1024x1024, qualitystandard, n1 ) image_url response.data[0].url print(shot[shot_id], image_url) if __name__ __main__: shots load_storyboard() generate_frame(shots)这个代码的核心思路是每一段分镜对应一张提示词图片。实际项目中你也可以采用更先进的方式用同一角色 seed 保持形象一致。4.6 用 FFmpeg 合成视频当图片素材准备好后使用 FFmpeg 把图片序列合成视频是效率最高的方式。假设你的图片命名规范为frame_0001.png、frame_0002.png可以执行ffmpeg -framerate 24 -i frame_%04d.png \ -vf scale1280:720 \ -c:v libx264 -pix_fmt yuv420p \ oneiric_dream.mp4参数说明-framerate 24每秒显示 24 帧看起来更流畅。-i frame_%04d.png读取按四位数编号的 PNG 图片序列。-vf scale1280:720统一输出分辨率。-c:v libx264使用 H.264 编码兼容性好。-pix_fmt yuv420p保证视频在大部分播放器中正常播放。如果只是快速验证剧情不生成图片也可以直接用 FFmpeg 把字幕文件和配音合成简单视频。4.7 给视频加字幕与配音Oneiric 风格的视频如果只有画面没有声音会缺少情绪。给视频加字幕最简单的方式是硬编码字幕ffmpeg -i oneiric_dream.mp4 -vf subtitlessubtitle.srt oneiric_dream_sub.mp4字幕文件subtitle.srt格式如下1 00:00:01,000 -- 00:00:05,000 林晓窗外的雨声让人很安静。配音方面可以使用 TTS文本转语音服务。不同 TTS 服务接口差异较大建议按官方文档接入这里不展开。5. 常见问题与排查思路下面的表格汇总了我在跑 Oneiric 和 AI 小镇类项目时最常见的几个问题以及对应的排查方式。问题现象常见原因解决思路调用大模型接口报超时网络不稳定或 API 配置不正确先确认 API Key 是否有效检查接口地址增加超时时间重试角色回复越来越跑题上下文太长导致重点被稀释做记忆裁剪只检索最相关的 3-5 条记忆内存占用过高记忆库无限增长加载了所有历史记录使用向量数据库或对记忆做分段读取生成视频画面不连贯每次生成图片时角色形象不一致固定角色描述词使用相同 seed 值中文字幕在视频里乱码FFmpeg 缺少中文字体支持安装中文字体或使用图片字幕叠加API Key 泄露代码中硬编码了密钥改用环境变量或密钥管理服务禁止提交到 Git5.1 关于大模型 API Key 的安全提醒无论开发多小的项目都不建议把 API Key 写死在代码里更不要提交到 GitHub。正确做法是export OPENAI_API_KEY你的API Key在 Python 中使用import os api_key os.getenv(OPENAI_API_KEY)如果代码需要部署到公网还应该在服务入口加权限校验避免接口被他人免费调用。5.2 模型选择问题Oneiric 视频生成链路中涉及对话模型、图像生成模型、语音模型三类。它们的选型逻辑不太一样对话模型优先选择上下文窗口大、指令理解能力强的模型。角色对话往往依赖多轮记忆上下文窗口太小的模型表现会差很多。图像生成模型优先关注角色一致性和场景还原能力。语音模型优先关注自然度和情感表现力梦境风格需要有一定语气起伏。版本变化很快这里不推荐写死具体模型而是建议你在实际项目里多做对比测试。6. 最佳实践与工程建议6.1 控制 Token 成本AI 小镇模拟最花钱的地方是角色对话和记忆反思。每轮模拟都要把系统提示词、场景描述、记忆列表一起发给大模型Token 消耗会很快。建议做法记忆只取最近几条避免全部传入。场景描述使用模板减少重复内容。对于非关键角色可以使用更小、更便宜的模型。把模拟结果缓存起来调试时优先读取缓存。6.2 保持角色人设稳定角色人设漂移是 AI 小镇类项目最常见的问题。主要原因是系统提示词太长模型注意力被分散或者温度参数设置过高。工程上可以用两个方法改善把角色核心设定单独写一段并放在系统提示词最前面。在角色回复后增加一道“人设校验”如果回复语气明显偏离设定则重新生成一次。6.3 视频生成时固定角色形象做 Oneiric 这种多镜头视频最大的痛点是同一个角色在不同镜头中长相不一致。解决方法包括在提示词中固定角色外貌描述例如“穿米色毛衣的黑发年轻女性”。使用支持角色一致性的模型。先生成一张角色设定图再基于该图生成不同动作。6.4 数据落盘与可复现性AI 生成具有随机性同样的输入可能得到不同结果。为了保证实验可复现建议每次模拟运行时把以下内容一起保存角色配置文件内容。模型名称和参数。完整事件 JSON。分镜 JSON。最终视频版本号。这样即使后续要回滚到某个版本也能完整还原。6.5 合规与安全边界做 AI 生成内容时有几个底线必须守住不能生成违法违规、色情、暴力等内容。如果视频中出现真人形象、名人声音必须有明确授权。开源项目也需要遵守对应 License商用时尤其要确认。6.6 部署到公网时的防护如果你把 Oneiric 做成了在线服务至少要注意以下几点用 API Key 或 Token 保护服务接口。对用户输入做长度限制防止恶意消耗资源。记录请求日志便于排查问题。部署前在测试环境完整跑通流程再考虑上线。7. 总结与后续学习路线通过 Oneiric 这个项目你已经跑通了一条完整的 AI 生成视频链路从 AI 小镇角色模拟到事件日志生成再到分镜脚本组织和视频合成。需要重点掌握的几个关键点生成式 Agent 的感知、记忆、反思、规划机制。角色人设提示词的设计方法。模拟事件如何结构化保存。分镜脚本如何描述画面才能让生成模型更好理解。FFmpeg 图片序列合成视频的基本命令。如何通过固定提示词和 seed 保持角色一致性。接下来你可以从三个方向继续深入学习 Agent 开发框架例如 LangChain、AutoGen把 AI 小镇的记忆管理做得更健壮。研究视频生成模型和图像生成模型的角色一致性方案把 Oneiric 的画面质量提升到接近电影级别。尝试接入 TTS 和音乐生成模型给视频配上有情绪感的声轨。最有效的学习方式是先在本地把 AI 小镇模拟器跑起来写两个角色让它们聊上几十轮再想办法把这几十轮对话变成一部小短片。等你亲手把第一个完整视频生成出来之后对 AI Agent、分镜、视频合成这条链路会有非常直观的理解。如果你也在做类似的 AI 视频生成项目欢迎收藏这篇文章也欢迎在评论区一起交流思路。