用AI分析,你的笑话为什么不可笑
上传一段你的演出片段。引擎会测量观众真正有反应的时刻,请 Gemma 解释每个节拍发生了什么,然后交给你一份好制作人本会给出的笔记——哪里出彩、哪里冷场、为什么,以及下次演出前该改什么。
AI模型价格对比 | AI工具导航 | ONNX模型库 | Vibe Coding教程 | PLC在线仿真器 | Tripo 3D | Meshy AI | ElevenLabs | KlingAI | ArtSpace | Phot.AI | InVideo
每个喜剧演员走下舞台时,对刚才发生的事情都只有一段不完整的故事。你知道第三段包袱很软。你觉得自己把收尾讲得太赶。但你只能凭记忆和肾上腺素拼凑这一切,而唯一的目击者早就回家了。
他们为什么笑?(Why'd They Laugh?)是我们的尝试,试图从房间里唯一留下的信号中找回那段缺失的反馈——笑声本身。
上传一段你的演出片段。引擎会测量观众真正有反应的时刻,请 Gemma 解释每个节拍发生了什么,然后交给你一份好制作人本会给出的笔记——哪里出彩、哪里冷场、为什么,以及下次演出前该改什么。
它也能处理未表演过的素材。粘贴文字,你就能得到同样的结构拆解,只是少了观众数据。但视频路径是这个项目的核心,因为它是幽默唯一有答案对照表的地方。
1、"这好笑吗?"这个问题的毛病
理解幽默很难,原因很具体:没有基准真相(ground truth)。同一句话在俱乐部里炸场,在公司全员大会上却冷掉。问模型"这好笑吗?",你得到的只是一个没人能验证、辩护或反驳的数字。
所以我们不问这个问题。
相反,我们让模型的推理过程变得显式。铺垫(setup)设下了什么预期?笑点(payoff)如何违背这个预期?听众必须具备哪些知识——而这一要求又悄悄排除了哪些观众?
这些问题有可检验的答案。喜剧演员能读懂它们并不同意,而这正是重点。6.2/10 的分数是无法证伪的。"你的铺垫从未设下清晰的预期"则是一句你可以据此行动或拒绝的评语。
而有了视频,一个真正的标签终于存在了。现场观众要么笑了,要么没笑。从音频中检测出笑声并交给 Gemma,就把任务从猜什么好笑转换成了解释已经发生了什么——这是一个措辞好得多的问题,对拿着话筒的人来说也实用得多。
2、一个真实的片段,从头到尾
这是引擎在一个真实的 28 秒单口片段上运行的结果——一个关于"看起来不像战争难民"的段子。
2.1 测量现场
我们用 ffmpeg 提取音频,并把观众反应检测为高于语音基线的、持续的宽带能量爆发。这里完全没有模型参与——是 numpy 在做信号处理。
输出是一条响度曲线,标记出笑声区域,渲染成交互式时间线。Gemma 检测到的喜剧节拍位于下方,是可点击的标记:绿色表示现场有反应,红色表示没有。

2.2 用现实检验模型的理论
这是我们最想捍卫的想法。
Gemma 单独地、完全看不到观众音频地阅读文字稿,仅凭结构预测笑声应该落在哪里。然后我们把这些预测叠加到实测笑声上——不匹配的地方就是诊断结果。
在这个片段上:2 处命中,2 处扑街,1 处惊喜笑点。


这两处扑街都有具体的时间戳。13.5 秒处:"我是个战争难民!"17.5 秒处:"我看上去不像战争难民。"两者在纸面上读起来都很好笑。两者都遇上了沉默。当结构没问题而现场保持安静时,问题就不在写作——而在表演、节奏,或者观众不对。
5.0 秒处的惊喜笑点则是相反的信号:真实的 laughter 出现在没有任何文字可以解释的地方。一定发生了什么身体层面的东西——一段表演动作、一个表情、一次停顿——而这些是文字稿根本看不见的。这正是表演者希望被标记出来的时刻,因为它们在脚本里不可见,改写时又极易被删掉。
2.3 逐节拍修改
对于每个冷场的节拍,Gemma 会指出机制并给出具体指令。

7.0–10.0 秒的直呼式台词——"你们都在笑,你们同意吧!"——没有得到任何反应,评语也很直接:**整个删掉。**16.0–18.0 秒的自嘲节拍得到的是*改写得更直接。*18.0–21.0 秒的夸张部分停留过久,被砍成一个五个词的版本。
这些是能在真正改写中存活下来的评语,因为它们依附于时间戳和机制,而不是感觉。
2.4 幽默基因组
这段片段还会接受完整的结构分析——六个维度,分别打分,渲染成雷达指纹图。

整体好笑程度:**5.0/10。**惊喜感在 8 左右,巧妙感在 6 左右,但具体性很低,共鸣感、锋芒和温度全都停在零。这个轮廓就是诊断本身:一个建立在抽象前提上的巧妙惊喜,观众却没有任何可以抓住的东西。
Gemma 自己的总结也同意。开头是干净的铺垫-笑点结构,揭示部分有扎实的推进,随后是一个越来越离题的说明,完全失去了喜剧节奏。它指出了这个段子所需的文化假设——熟悉老兵梗、接受"氛围"(vibe)这种主观特质——并点名了由此产生的失败模式:无法解析"vibes"的听众直接就懵了,而抽象的东西让人抓不住任何把手。它的节奏点评精确指出了转入解释难民体验时节奏不均的问题。
2.5 给谁看
受众匹配度会按受众群体给出各自的评判,并附带理由。

密友欣赏它对荒诞的投入。普通大众觉得它太抽象,还依赖一些没解释的术语。然后是针对最弱维度的定向修改:用一个更有力、更直接的主张开场,而不是绕来绕去的铺垫;要么把"战争氛围"这个概念充实起来,要么抛弃它,更用力地押注在不合逻辑上。
这就是从 28 秒素材中得出的一套完整评语,全部立足于现场观众的真实反应。
3、Gemma 是如何做这些工作的
Gemma 是全部的推理核心。背后没有悄悄干活的独立分类器或规则引擎。
- 结构化拆解。一个指令微调过的提示词返回严格匹配我们基因组 schema 的 JSON。我们把模型约束在六个固定维度和一套已知的喜剧机制词汇表上,这样结果可以在不同笑话之间比较,而不是自由形式的散文。
- 观众模拟。在同一次调用中,Gemma 扮演每个观众群体,并对评判、分数和理由作出承诺——实际上是在模拟四个不同的房间。
- 多模态片段推理。采样帧与文字稿、实测笑声时间线一起送入多模态 Gemma,所以"成功/冷场"的判断是基于观察到的行为,而不是猜测。
- 定向改写。两个最弱的维度带着目标受众被回喂给模型,Gemma 进行改写——并报告它改了哪个机制、为什么改。理解变成了行动。
我们弃用 Gemma 2,因为它只支持文本,看不了片段。文本路径和画面理解运行在 Gemma 3(4B/12B/27B,文本 + 图像,128K 上下文)上;视频功能使用 Gemma 3n(E2B/E4B),原生支持文本、图像、音频和视频的多模态。模型名放在环境变量里,所以指向 Gemma 4 或更大的尺寸只是一行代码的事。
3.1 架构
Streamlit UI ─┐
CLI ─┼─► HumorGenomeEngine ─► GemmaClient ─► Ollama | HF | mock
Library API ─┘ ├─ prompts.py JSON-schema prompts
├─ genome.py typed schema (axes, audiences, beats)
├─ video.py ffmpeg frames + audio, SRT/VTT parsing
└─ laughter.py numpy audience-reaction detection
三个决定承担了大部分重量。
Schema 优先。UI、CLI 和测试都依赖稳定的 dataclass,与生成报告的后端完全解耦。
稳健的解析。指令微调模型喜欢把 JSON 包在代码围栏里,再配上道歉式散文。我们提取最外层对象、修复尾随逗号、把分数钳制在 [0, 10],并降级为一份最小报告而不是崩溃。
三个后端。统一客户端自动选择 Ollama,然后是 HuggingFace,最后是一个确定性的离线 mock,它在 UI 中明确标注——所以完整体验几秒内就能点开,真正的 Gemma 只差一条命令。反应检测在任何后端上都能运行,因为它是纯音频分析。
3.2 我们学到了什么
让模型点名被违背的预期结果是一个出奇有力的透镜。低分的段子几乎总有一个含糊或缺失的预期,这与关于软弱铺垫的喜剧直觉完美吻合。
观众是一等变量。强制按群体分别预测,暴露了"好笑"在多大程度上其实只是匹配度——而且关于文化假设的推理始终比分数本身更锋利。
在没有基准真相时,可解释性胜过数字。理由比一个孤零零的好笑分数更有价值、更可调试。
但我们最想捍卫的发现,是预测-实测叠加图产生的那一个。一个读起来很好却冷场的笑话,能告诉你脚本永远无法告诉你的东西。一个没有任何文字支撑的笑声也一样。两者只有在你停止问模型什么好笑、转而让它解释一个房间时才会显现。
4、30 秒上手
pip install -r requirements.txt # + ffmpeg for the video tab
HUMOR_GENOME_BACKEND=mock streamlit run app.py
# or, for real Gemma:
ollama run gemma3 && ollama pull gemma3n && streamlit run app.py
原文链接:I Built an App with Gemma to Decode Why Nobody Laughed at Your Joke
汇智网翻译整理,转载请标明出处