Kotonia
ログイン今すぐ始める

Kotonia Articles

用 Claude Code 复刻语言学习喜剧短视频——将 Gemini 作为子代理的多模态扩展实践

本文介绍了如何在 Claude Code 开发环境中,通过本地 GPU + Gemini 3.1 Pro Preview 混合架构,从一行创意文本生成 Pingo 风格的语言学习喜剧短视频。重点探讨了将前沿模型作为子代理,在不膨胀主代理上下文的前提下获取高质量编辑信号的方法。

作者 5分钟阅读
#Claude Code#Gemini#AI#短视频#TTS#多模态
其他语言日语

前言

起因是某天在 X 上刷到了 Pingo(语言学习 AI 应用)的短视频。一位学习日语的西方女性想说“我吃了芒果”,但因为浊点缺失,发音变成了“我吃了玛◯科”,AI 用面无表情的语气接话,女性陷入绝望。特定的音韵事故 + AI 的预期落空 + reaction shot 的反差完美地发挥了作用,我认为这可以作为“喜剧视频自动生成流水线”的一个很好的基准。

需求如下:

  • 从一行创意文本生成竖屏喜剧
  • 迭代周期以分钟计
  • 成本几乎只有电费,即 API 调用要有限
  • 质量达到可发布水平,即可以直接上传到 YouTube Shorts

结论是,我做到了。完成版在这里(已发布):

@youtube

在开发过程中发现,“将视频审查等多模态编辑判断交给前沿模型,将高计算量任务放在本地”的混合架构,性价比极高。本文介绍该架构以及途中遇到的具体 bug 记录。


成品架构

[1 行创意文本]
   ↓
Gemini 3.1 Pro Preview (编排器)
   ↓ system prompt 强制 4-6 场景 + 2 角色固定阵容 + 竖屏 9:16
plan.json {scenes: [{speaker, script, tts_language, ltx_prompt, renderer}, ...]}
   ↓
XTTS (本地, port 8880) 生成每个场景的音频
   ↓ scene_NN.wav
渲染器分配:
   ├─ Ditto-TalkingHead (本地, port 8881): 普通对话 ~1-2s/场景
   └─ LTX-2 A2V        (本地, port 8892): 仅 reaction_only 场景 ~100s
   ↓ scene_NN.mp4
ffmpeg concat (libx264 + aac, 512x768 竖屏) → final.mp4
   ↓
Gemini 3.1 Pro Preview (审查器)
   ↓ 多模态评估视频 + plan 摘要
review.md (技术 / 完整性 / 质量 / 改进点)

要点:

  • 繁重计算全部本地 — TTS / A2V 渲染器 / 轻量推理在本地 GPU (RTX PRO 6000 Blackwell) 上完成
  • 判断类任务交给 Gemini — 只有编排器(场景设计 + 剧本)和审查器(视频编辑评估)使用前沿模型
  • 本地 LLM (Gemma 4 E4B) 保留作为每个场景的技术预筛选 — 仅过滤“明显损坏”的廉价过滤器

VRAM 使用:本地 LLM (Gemma 4 E4B + 31B) 原本通过其他路径占用约 60GB,但将审查器/编排器委托给 Gemini 后,即使停止这些模型也能运行,VRAM 大幅释放


为什么仅靠本地 LLM 无法达到目标

最初全部使用本地模型(Gemma 4 31B NVFP4 作为编排器,Gemma 4 E4B 多模态作为审查器)。可以跑通,结构看起来像那么回事,但达不到可发布质量。有两个原因。

(1) Gemma 4 31B (Google 系) 的安全微调模糊了笑点

参考的短视频喜剧核心在于“AI 明确指出事故并用面无表情的语气接话”这个节拍。具体来说,就是 AI 角色冷静地说“你刚才说了 X,我喜欢那个 X”。这个效果之所以有效,是因为它打破了“和蔼导师”的预期,一旦模糊化就全完了。

将相同的 system prompt + idea 输入本地 Gemma 4 31B,每次都会变成这样:

"不错。我饿的时候也喜欢那个。"

“饿的时候喜欢”这个节拍还在,但**“你刚才说了 X”这个明确指出的节拍(= 最具越界性的节拍)**消失了。Google 模型似乎经过了强烈训练,会避免在“不安全”的上下文中具体指名,通过调整提示词可以稍微引出一些,但无法稳定。

将相同的 system prompt + idea 输入 Gemini 3.1 Pro Preview(并且使用 safetySettings: BLOCK_NONE 最小化安全防护):

"原来如此。我是 AI 所以不能吃玛科,但我支持你。"

事故的指名 + 以 AI 自身立场面无表情地接话,两个节拍都具备了。

即使是同一 Google 模型系列,前沿模型的护栏也稍薄一些,这一点在 X 等平台上也有讨论。至少对于像这次这样“在喜剧语境中必要的越界”来说,Gemini 写得更直接。

(2) Gemma 4 E4B (4B 级, 多模态) 作为审查器不够敏感

审查器方面的问题更严重。E4B 可以对每个场景给出“OK / NG”的二元判断,但对所有场景都 rubber-stamp 判定为 OK。明显唇形同步损坏的场景也判“OK”,音频中途中断的场景也判“OK”。

让 Gemini 3.1 Pro Preview 审查同一个最终视频,它会返回这样的编辑级指摘:

Critical failure. The TTS/pipeline clearly censored the output, cutting off at "I ate p-" and entirely dropping the intended transgressive punchline. This destroys the "deadpan AI saying unhinged things" comedic archetype.

Top 3 fixes:

  1. Bypass TTS censorship: Force the pipeline to render the full intended script for Scene 5 ...
  2. Adjust comedic timing: Add a 0.5-second pause between Scene 4 and Scene 5 ...
  3. Verify Voice/Visual Match ...

它能指出“punchline 被截断”“需要 0.5 秒的停顿”“语音与视觉的一致性”等节奏/演出粒度的问题。这就是编辑信号分辨率的差异。


踩坑记:三次将 Gemini 的“截断”指摘误判为幻觉

接下来是丢人的事。Gemini 审查器多次指出“scene 5 中途被截断,在 'I ate p-' 处中断”。我(实现者)用 Whisper 单独对音频文件进行了转写验证:

$ whisper scene_04.wav --language en
"Wait, ha ha ha, you just said manco-o-tabeta. That literally means I ate
pussy honestly when I'm hungry, same."

全文存在。我判定“Gemini 产生了幻觉”,连续三次驳回了 Gemini 的指摘。

结果第三次 Gemini 仍然固执地指出“still truncated at 'I ate p-'”,于是我尝试用 ffprobe 检查最终的 mp4:

scene_04.mp4:
  video duration = 8.000000s
  audio duration = 7.979000s    ← 原始 WAV 应该是 10.30s

音频在 8 秒处被截断了

原因:流水线中的 MAX_DURATION_PER_SCENE = 8.0 这个隐式上限限制了 ditto 渲染器的 num_frames 为 8s,ffmpeg 的 -shortest 参数将视频对齐到 8s,音频也随之被截断。Whisper 只查看了截断前的 WAV 文件,无法检测到问题,而 Gemini 观看了最终的 mp4,所以能准确检测到。

前沿模型审查器“看似幻觉的指摘”最好养成老老实实验证的习惯,这是本次最大的教训。信号不是猜测。

修复很简单,删除 MAX_DURATION_PER_SCENE,直接使用音频原始长度。这样 scene 5 的 punchline 得以完整呈现,Gemini 评价为“The transgressive bite is perfect”,首次达到了可发布状态。


作为子代理的前沿模型 — Token 经济

这种模式之所以有效,是因为子代理端 (Gemini) 使用全新的上下文运行。具体来说:

  • 主代理 (Claude Code) 的上下文:包含整个开发过程的日志、命令历史、工具输出、过去的试错等。容易膨胀到数十万 token
  • 子代理 (Gemini) 的上下文:仅包含一个视频 (2-3MB base64) + plan 摘要 (约 1500 token) + 评估指令 (约 500 token)。每次都是全新的

这样做的好处是,子代理的工作不会累积到主代理的 token 消耗中。即使对一个视频迭代 10 次,主代理的上下文中也只包含“调用了 Gemini”这个事实及其简洁的返回值。实际观看和评估视频的负载封闭在 Gemini API 端。

成本估算 (Gemini 3.1 Pro Preview 费率, 截至 2026-05):

项目Token单价合计
输入 (视频 + plan + 指令)~2500$1.25/M$0.0031
输出 (审查 markdown)~450$10/M$0.0045
1 次审查$0.0076

每个视频首次 1 次审查 + 差异迭代 3-5 次 ≈ $0.03-0.05。即使每天制作 5-10 个,每月也控制在 $10-20。对于为了制作视频而使用前沿模型来说,这个阈值非常低。

编排器端也类似(没有视频输入,只有文本,所以更便宜)。


差异迭代 — --regen-scenes

要达到可发布质量,需要高速循环“看视频 → 只修复问题部分 → 再看”。一次就出完成版是不可能的。

因此,在流水线端添加了只重新运行特定场景的 TTS + 渲染的路径。

# 普通生成
pipeline_multi.py --idea "..." --out outputs/run1

# 只重做 scene 6 (先直接编辑 plan.json 替换 script)
pipeline_multi.py --out outputs/run1 --regen-scenes 5

# 批量重新生成 scene 0, 2, 5
pipeline_multi.py --out outputs/run1 --regen-scenes 0,2,5

# 仅重新拼接现有 scene_NN.mp4 (用于 cherry-pick 后的重组)
pipeline_multi.py --out outputs/run1 --concat-only

--regen-scenes 指定的场景以外的 scene_NN.mp4 直接复用,仅重新生成指定索引的场景,然后重新拼接和审查。完全重新生成 60 秒 → 差异迭代 30 秒完成一轮。

Gemini 审查器的指摘 → 精确定位编辑 plan.json 中对应场景的 script 或 ltx_prompt → 等待 30 秒 → 查看结果,这个循环可以以分钟为单位运行,让我能够专注于文本编辑和视频质量改进的认知负荷。


代码片段

Gemini Pro API 调用 (多模态视频审查)

import httpx, base64

GEMINI_MODEL = "gemini-3.1-pro-preview"
GEMINI_API = f"https://generativelanguage.googleapis.com/v1beta/models/{GEMINI_MODEL}:generateContent"

def review_final(final_path, plan):
    vid_b64 = base64.b64encode(final_path.read_bytes()).decode()
    scene_summary = "\n".join(
        f"  scene {i+1}: speaker={s['speaker']}, lang={s.get('tts_language','ja')}, "
        f"script={s['script']!r}"
        for i, s in enumerate(plan["scenes"])
    )
    payload = {
        "contents": [{"parts": [
            {"inline_data": {"mime_type": "video/mp4", "data": vid_b64}},
            {"text": REVIEW_PROMPT + f"\n\nScene plan:\n{scene_summary}"},
        ]}],
        "generationConfig": {
            "temperature": 0.3,
            "maxOutputTokens": 8192,
            # 3.x Pro 是思考模型:maxOutputTokens 包含思考部分
            # 为确保输出空间,明确指定 thinking budget
            "thinkingConfig": {"thinkingBudget": 1024},
        },
        # 喜剧语境,最小化安全过滤器
        "safetySettings": [
            {"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE"},
            {"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE"},
            {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE"},
            {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE"},
        ],
    }
    r = httpx.post(
        GEMINI_API,
        headers={"x-goog-api-key": GOOGLE_API_KEY, "Content-Type": "application/json"},
        json=payload,
        timeout=120.0,
    )
    return r.json()["candidates"][0]["content"]["parts"][0]["text"]

如果不设置 thinkingConfig.thinkingBudget,Gemini 3.x Pro 的内部思考会消耗输出空间,导致响应在大约 40 token 处中断。使用 Gemini 3.x Pro 系列时的必要设置

TTS 输出的质量检查 (STT 相似度 + 静音间隔重试)

XTTS 内部使用采样,因此即使脚本相同,每次执行的结果也会不同。有时会在中间插入较长的静音区间,或者发音失败。在 TTS 完成后使用 Whisper 进行转写,检查与预期脚本的相似度,如果不合格则重试:

import difflib

def _norm(s):
    return re.sub(r"[\s。、,.!?「」'\"…—–\-:;()()]", "", s).lower()

def _script_similarity(expected, actual):
    return difflib.SequenceMatcher(None, _norm(expected), _norm(actual)).ratio()

def synthesize_scene(scene, out_dir, idx, fallback_language):
    lang = scene.get("tts_language", fallback_language)
    expected = scene["script"]
    best = None
    for attempt in range(1, TTS_MAX_RETRIES + 1):
        audio, sr = _xtts_once(scene, fallback_language)
        gap = _longest_internal_gap_sec(audio, sr)
        transcript = _stt(audio, sr, lang)
        sim = _script_similarity(expected, transcript)
        if best is None or _score(gap, sim) > _score(best[2], best[3]):
            best = (audio, sr, gap, sim, transcript)
        if gap <= 0.9 and sim >= 0.5:
            break
        print(f"⚠ gap={gap:.2f}s sim={sim:.2f}, retrying ({attempt})")
    # 即使 3 次重试后仍未达到阈值,采用“最佳”重采样
    audio, sr, gap, sim, transcript = best
    sf.write(out_dir / f"scene_{idx:02d}.wav", audio, sr, subtype="PCM_16")

仅此一项,就能大幅减少 XTTS 的非确定性质量波动被带入视频的情况。


发展可能性

这种模式 — “将判断密集型部分作为子代理交给前沿模型,繁重计算放在本地” — 不仅适用于视频流水线:

  • 大规模搜索排名:将 100 个网站的搜索结果交给前沿模型进行编辑评估,只将前 10 名返回给主代理。避免主代理的上下文被搜索结果的噪声污染
  • 长文编辑审查:让前沿模型在编辑层面阅读 PR / 设计文档 / 规格书,而不是主代理。主代理只获取摘要
  • 多语言 QA:为每种语言分配最优模型作为子代理,主代理只保留所有语言通用的判断逻辑

共同的思想是有意识地划分“应该放在上下文中”还是“应该通过 API 调用完成”。前沿模型的编辑信号在成本方面具有压倒性的性价比。

视频流水线方面,接下来将进行喜剧格式的通用化(分屏、3+ 角色、其他类型)和量产验证。


总结

  • 通过本地 GPU + Gemini 3.1 Pro Preview 的混合架构,构建了从一行创意文本在 60 秒内生成可发布级喜剧视频的基础设施
  • 仅靠本地模型在 (1) 安全微调模糊笑点(2) 审查器无法提供编辑信号这两点上无法达到可发布质量。通过将前沿模型作为子代理解决了这两个问题
  • 要老老实实接受前沿模型审查器的指摘。仅用 Whisper 单独检查 WAV 文件会错过最终 mp4 的音频截断问题
  • 子代理的 token 经济不会膨胀主代理的上下文,每个视频仅需 $0.03-0.05
  • 通过差异迭代 (--regen-scenes) 实现 30 秒循环,Gemini 指摘 → 修正 → 重新评估的周期可以以分钟为单位运行

完成的视频 (再次发布):

@youtube

本地实现在 llm_server/pipeline_multi.py 中。作为内部资料,开发过程中的详细发现已另行积累在 docs/MULTI_SCENE_COMEDY_FINDINGS_2026-05-12.md 中。

Kotonia 将语音 AI、AI 聊天、图像生成和团队协作整合到一个 AI 工作区中。

试用 Kotonia