← 新しい形の研究 C-1 / AIエージェントで1から作る

AIエージェントで1から作る — 1分AIニュース(YouTube Shorts)

1本のShortsが、
できるまでの全部

ずんだもんがAIニュースを5本読み上げるShortsシリーズを、AIエージェントと立ち上げました。 ニュース集めから投稿までを6工程に分けた記録です。1本あたり約40分、費用はほぼゼロ。

2026-09-12 / 1分AIニュース #01・#02 の制作から / 読了 約8分

00

できあがるもの

動画冒頭。赤い背景に「Claude Code / Cursor 使ってる人へ」と大きく表示されている
0秒。タイトルは出さず、当事者を名指しする。
ニュース1件の画面。当事者タグ・結論・数字カード・図解・あなたはどうする、が縦に並ぶ
各ニュースは「誰に → 結論 → 数字 → 図 → どうする」の順。
サムネイル。緑背景に「AIが攻撃側に」の文字と、右上に赤いリボン
サムネイルも同じデータから自動生成(横16:9・縦9:16)。
01

6工程を、上から下へ流す

1本のShortsができるまで
1
ニュースを5本に絞る人間
その日のAIニュースを集め、一次ソースまで辿って数字を確認する。
出力
ニュース5本
+ 出典URL
2
台本をデータで書くエージェント
見出し・数字・読み上げ文・字幕・出典を、1件ずつ構造化データで宣言する。
出力
script.json
3
声と口パクを作るエージェント
VOICEVOXで合成し、音量から口の開きを決める。BGMを重ねて音量を揃える。
出力
mix.wav
timing.json
4
画面を描いて動画にするエージェント
画面はHTML/CSS。「この時刻の画面」を返す関数を用意し、1,700枚撮ってつなぐ。
出力
mp4
5
出せるかを機械が判定エージェント
尺・音圧・止まり具合・重なり・実機UIを数値で測る。数字は出典と突き合わせる。
出力
合格 / 不合格
6
投稿して告知するエージェント
YouTubeへ投稿し、サムネイルを設定、再生リストに追加、Xへ動画付きで流す。
出力
公開URL
人間 判断が要るところ エージェント 任せられるところ

人間がやるのは工程1だけです。どのニュースを選ぶか、その数字は信用できるか。 ここは任せていません。

2本目に打ったプロンプト

以下は、AIエージェント(Claude Code)のチャット欄に実際に入力した文です。 コマンドではなく、この日本語をそのまま渡しています。

入力 — Claude Code に送ったプロンプト
02の制作に進んでほしい。説明文にサイトとXの紹介も入れて、Xにも動画付きで投稿してください。
出力 — エージェントが実行したこと
ニュース収集 → 5本選定 → 台本生成 → 音声7本 → 口パク → ミックス → 1,763枚レンダリング → 品質ゲート8項目 → 事実確認(誤り1件を修正して再レンダリング) → サムネ2種 → YouTube公開 → 縦サムネ設定 → 再生リスト追加 → X投稿

この1つで最後まで走りました。途中で止めたのはXの投稿先アカウントを聞かれた1回だけです。

02

1本目は8回、2本目は1回

1回で走るようになったのは2本目からです。1本目は作りながら直しました。 下は、AIエージェント(Claude Code)に送ったプロンプトの全部です。 赤い番号が修正の指示にあたります。

#
Claude Code に送ったプロンプト→ エージェントがやったこと
1
エンジニア向けに、1分で最新のAIニュースがわかるShortsシリーズを作りたい。
→ 方向性を決めて、パイプライン一式を新規作成。1本目を書き出し
2
サムネイルが弱い。字幕とキャラクターが重なっている。
→ サムネに警告リボンを追加。字幕とキャラの座標を調整
3
まだ重なっている。
→ マージンを広げたが、解決していなかった
4
Playwrightで実機の画面と比べてテストしてほしい。構造がわかる図も添えて。
→ 転機。座標を機械判定する仕組みを作ったところ、動画内部は重なっていないが、 YouTube実機UIとほぼ全編重なっていることが判明。レイアウトを再設計
5
ニュースの背景がわかる図を作って、説明の余白に入れてほしい。
→ 内容を1枚で示す図解を5種類実装
6
最初の5秒で離脱されない構成に見直してほしい。コマンドログの演出はわかりにくい。
→ 構成を作り直し。0秒から当事者名指し、各ニュースに「あなたはどうする」を追加
7
最後のセリフが途中で切れている。尺は無理に縮めなくていい。
→ 原因(尺を音声の終端ちょうどに合わせていた)を特定。以後は余韻0.7秒を確保
8
再生リストを作って公開してよい。
→ 投稿、再生リスト作成、縦サムネ設定まで実行

修正は6回。うち3回は同じ指摘でした。解決したのは、目で見るのをやめて 測る仕組みを作ったときです。

そしてこの6回が、そのまま検証スクリプトになりました。2本目以降、同じ指摘は出ていません。

03

目視をやめる

エージェントは自分が作った動画を見られません。mp4は再生できず、1,700枚のフレームを 全部は確認できず、音は聞けない。だから「間延びしている」の判断ができません。

そして人間の目も当てになりませんでした。重なりを直したつもりで、実機ではまだ重なっていた。 重なっていた相手は動画の中ではなく、YouTubeのUIだったからです。

ニュース画面に、YouTube Shorts実機UIのセーフゾーンを赤く重ねた検証画像
赤い部分が、実機でボタンやタイトルに覆われる場所。ここを自分で定義して、 要素がはみ出していないかを機械に測らせます。

そこで、目で見ていた項目を数値に置き換えました。

品質ゲート — 1つでも外れたら投稿しない
長すぎないか尺 ≤ 60秒
音が小さい / 割れていないか-14±1.5 LUFS / ≤ -1.0dBTP
冒頭が暗すぎないか輝度 ≥ 20/255
画面が止まっていないか最長の静止 < 3秒
間延びしていないか静止フレーム比率 < 1/3
文字が重なっていないか矩形が交差しない
実機UIに隠れないか右220px・下310px を侵さない
数字は出典どおりか別エージェントが照合

測ってみると、見えていなかったものが出てきました。

測ったら原因
画面の91%が静止していた背景の動きを、手前の不透明なパネルが隠していた(→14%)
実機UIとほぼ全編重なっていたキャラクターを画面の右下に置いていた
最後の声が0.02秒切れていた尺を音声の終端ちょうどに合わせていた
キャラクターが消えていた画像が404。それでもレンダリングは成功扱いで終わる

数値になれば、エージェントは自分で回して自分で直せます。 「91%」と出れば原因を探し、もう一度測って「14%」を確認する。人間を待ちません。

閾値に根拠は要りません。過去の動画を見比べて「これ以上止まると飽きる」と感じた線を、 そのまま数字にしただけです。
大事なのは、線が引かれていて、機械が毎回同じ厳しさで測れることです。

形式は測れる。中身は測れない

「中国の7ラボがClaudeを蒸留、1.5億回」と書いたことがあります。出典を確認すると、 1.51億回はそのうち1社の数値でした。嘘ではないが、合計だと誤読される。

これは画面をどれだけ測っても出てきません。別のエージェントに出典URLを渡し、 「この数字は出典のどこに書いてあるか」を1件ずつ答えさせています。

04

1本あたり40分

工程時間
1. ニュース収集・選定 ← 人間15〜20分
2. 台本作成10分
3. 音声合成〜ミックス3分
4. レンダリング2分
5. 検証 + 事実確認4分
6. 投稿・再生リスト・SNS5分
合計約40分

VOICEVOXもレンダリングも無料なので、費用は実質ゼロです。 X投稿のAPI利用料が1回$0.200かかる程度でした。

できたもの

この構成で作ったシリーズです。上の事故はすべて投稿前に止まりました。

1分AIニュース →
05

自分の題材でやるなら

動画でなくても、スライドでも記事でもアプリ画面でも同じです。

  1. 不合格の条件を、先に数値で書く。「良いもの」は定義できなくても「出せないもの」の線は引ける。3つで十分
  2. データと表現を分ける。明日、内容だけ差し替えて2本目が作れるか
  3. 表現から時間を追い出す。時刻を引数で受ければ、何度実行しても同じ絵になる
  4. 検証はコマンド1つ。最後に合否の1行だけ出す。判断を挟ませない
  5. 事実は他人に検証させる。「誇張はないか」ではなく「出典のどこにあるか」を聞く

残るのは、何を作るかどこに線を引くかだけです。

付録 A

各工程の中身

台本をデータで書く

1本のニュースが持つ情報を全部宣言します。誰に関係あるか、結論、数字、読者がすべきこと、 出典とその種別、そして読み上げ用と表示用の2つの文

最後の分離は必須です。音声合成には「ペーパーカット」と渡さないと読みを間違えますが、 画面には「PaperCut」と出したい。1つの文では両立しません。

dict(
  audience="社内にサーバーがある人へ",           # 誰に関係あるか
  summary="AIエージェントが395組織を突破",       # 3秒で読める結論
  figs=[{"n":"395組織","l":"侵害された組織(48カ国)"},
        {"n":"7分","l":"侵入から管理者権限まで"}],
  impact="PaperCutは今すぐパッチ適用を",         # 読者がすべきこと
  text="ペーパーカットの脆弱性を突く攻撃で…",     # 読み上げ用(カタカナ)
  caption="PaperCutの脆弱性を突くAI主導の攻撃で…", # 字幕用(正表記)
  source_url="https://…", sourceType="調査",
)

この形にすると、2本目はデータを差し替えるだけです。HTMLには触っていません。

声は、変わった行だけ作り直す

本文のハッシュをファイル名に使い、同じものがあれば再利用します。

th = hashlib.sha1((ln["text"] + str(sid)).encode()).hexdigest()[:10]
f = AUD / f"l_{ln['idx']:03d}_{sp}_{th}.wav"
if f.exists():
    sec = dur(f)            # 本文が同じなら再利用
else:
    vv(ln["text"], sid, f)  # 変わった行だけ合成

事実確認で1行直したとき、再合成されたのは7本中1本でした。

画面から時間を追い出す

CSSアニメーションは使いません。「この時刻の画面」を返す関数を1つ置き、 外から時刻を進めます。

window.__setTime = function(t){
  $("pbar").style.width = (Math.min(t/TOTAL,1)*100) + "%";
  $("bgfx").style.transform =
    "translate("+(Math.sin(t*0.42)*230)+"px,"+(Math.cos(t*0.31)*300)+"px)";
};
for i in range(N):
    pg.evaluate(f"window.__setTime({i/FPS:.4f})")
    pg.screenshot(path=str(FR/f"f_{i:05d}.jpg"), type="jpeg", quality=88)

実時間に依存しないのでコマ落ちせず、何度実行しても同じ絵になります。 そして検証側が好きな時刻の画面を再現できます

画面の構造図。各要素に色付きの枠とラベルが重なり、右と下に赤いセーフゾーンが示されている
この構造図もスクリプトが自動で描いています。手で線は引いていません。

重なりは座標で判定する

def rects_overlap(a, b):
    ox = min(a["right"], b["right"]) - max(a["left"], b["left"])
    oy = min(a["bottom"], b["bottom"]) - max(a["top"], b["top"])
    if ox > 0 and oy > 0:
        return {"w": round(ox, 1), "h": round(oy, 1)}
    return None

0.1秒刻みで全編に回します。500〜600回の判定が数十秒で終わり、出力は1行です。

ep02: 重なりなし(0.1秒刻み, 全587フレーム走査)

動画ではなくHTMLに対して走るので、mp4を作る前に判定できます。

実機UIの領域を定義する

# YouTube Shorts 実機UIの目安(1080x1920基準)
SAFE_RIGHT_W, SAFE_RIGHT_Y0, SAFE_RIGHT_Y1 = 220, 760, 1780  # 右のボタン列
SAFE_BOTTOM_H = 310                                          # 下のキャプション欄

止まり具合を測る

diffs = [float(np.abs(arrs[i]-arrs[i-1]).mean()/255*100)
         for i in range(1, len(arrs))]
still_ratio = sum(1 for d in diffs if d < 0.5) / len(diffs)

404を取りこぼさない

requestfailed はネットワークエラーでしか発火しません。404は正常応答なので拾えない。

pg.on("response", lambda r: fails.append(r.url) if r.status >= 400 else None)

末尾に余韻を足す

フレーム数は整数に丸められます。48.117秒は1,443フレーム=48.10秒。 音声の終端48.12秒に0.02秒足りず、-shortest が短い方に合わせていました。

TAIL = 0.7   # 最後の声にぴったり合わせると末尾が切れる
total += TAIL

判定の出力

$ python qc_video.py ep02

=== 品質ゲート(必須項目)===
  尺                     58.00s        OK (Shorts上限60s)
  音圧 LUFS              -15.13        OK (-14±1.5)
  冒頭0.5秒の輝度        61.0/255      OK
  最長の静止             1.0s          OK (3秒未満)
  静止フレーム比率       6%            OK (1/3未満)

判定: 全項目通過 — 投稿可

エージェントが読むのは、最後の1行だけです。

付録 B

パイプライン一式について

ここまでで同じ構造を組み直すことはできます。ただ、実際に動かすには、 VOICEVOXの読み間違いの潰し方、口パクの閾値、BGMのダッキング、API認証まわりなど、 書ききれない部分が残ります。それを含めた実行可能な一式を別途配布する予定です。

含まれるもの中身
パイプライン本体台本生成・音声合成・口パク・ミックス・レンダリング(13スクリプト)
画面テンプレート本編と図解5種、横/縦サムネ
検証スクリプト品質ゲート・重なり判定・セーフゾーン判定・構造図の生成
配信スクリプトYouTube投稿・再生リスト・縦サムネ設定・X投稿
Claude Code スキルこの手順をエージェントに実行させる SKILL.md
セットアップ手順VOICEVOX / Playwright / ffmpeg / API認証

配布方法と価格は準備中です。決まりしだい、このページに追記します。