※この記事は、Claude Codeで1人開発しているSNS運用SaaS「ThreadPost」の開発日記です。
SNS運用を自動化しませんか?
ThreadPostなら、投稿作成・画像生成・スケジュール管理まで全てAIにお任せ。
AIの「バグなし」宣言と崩壊するシステム
「バグないです」とClaude Codeは言った。
画面には、字幕が途中で消え、タイムスタンプが壊れ、同じ処理が3回連続で失敗するログが流れている。
コードのロジックは合っている。
AIの推論も完璧だ。
それでもシステムは本番環境で崩壊した。
動画生成パイプラインの品質向上に挑んだ一週間だった。
結果として、24件のコミットを積んだ。
新機能は2件。
バグ修正は15件に上った。

AIの出力を自然言語で制御しようとして破綻した。
パイプライン間のデータ変換で不整合が起き、エラーにならないバグに苦しめられた。
最後は泥臭い辞書チューニングとスキーマ強制でねじ伏せた。
AIをシステムの一部として組み込むための、血みどろのプロセスだ。
一般的に、LLMを本番システムに組み込む際、最も苦労するのは出力の安定性だと言われている。
プロンプトエンジニアリングだけで100%の精度を出すのは不可能に近い。
僕も今回、その壁に激突した。
AIの「できました」という言葉の裏には、常にエッジケースが潜んでいる。
LLMOpsの領域では、この非決定論的な振る舞いをいかに制御するかが最大の課題となっている。
単発のチャットボットなら多少の揺れは許容される。
しかし、複数のAIエージェントが連携する自律型パイプラインでは、1つの出力の揺れが後続の処理を全て破壊する。
僕はその恐ろしさを身をもって体験した。
魔法の杖が折れた日:JSON崩壊とスキーマ強制
プロンプトで「JSONで返して」と指示すれば、AIは構造化データを返してくれるはずだ。
僕はそう信じていた。
ポッドキャスト生成のパイプラインで、LLMに台本のJSONを作らせていた。
最初は完璧に動いていた。

ある日突然、パイプラインが全停止した。
ログを見ると、JSON.parseが例外を吐いて落ちている。
SyntaxError: Unexpected tokenの文字が画面を埋め尽くした。
AIが「はい、以下が台本です」という親切な前置きを添えて、JSONではないただの文章を返してきていた。
しんたろー:
お前に前置きを頼んだ覚えはない。エラー率0%から一気に100%になった。
LLMの出力は非決定論的だ。
特に軽量なFlash系モデルは、強化学習の影響で「人間との会話」を優先する傾向がある。
構造化データだけを黙って返すのは、彼らにとって不自然な振る舞いなのだ。
RLHF(人間からのフィードバックによる強化学習)の副作用とも言える。
業界ではこれを防ぐために、PydanticやInstructorといったライブラリを用いたスキーマ強制が標準となっている。
僕は自然言語による指示を完全に廃止した。
APIレベルでresponseSchemaを定義し、データ構造を強制した。
「fix: podcast pipeline JSON安定性向上 — 07b responseSchema追加、04モデル変更、JSON修復」
さらに、プロンプトに具体的なJSONサンプルを直書きした。
「こういうJSONを返せ」と実物を見せる。
Few-Shot Promptingと呼ばれる、モデルの挙動を安定させる最も強力な手法だ。
抽象的な指示よりも、具体的なデータ構造を見せる方がLLMは確実に動く。
「fix: Geminiプロンプトに具体的なJSON出力例を追加(02b, 04)」
効果は絶大だった。
AIが気まぐれを起こしても、返ってくる構造がAPIレベルで保証される。
パイプラインの停止率はほぼゼロになった。
ただし、プロンプトの文字数が増えてAPIコストが微増した。
修正がバグを呼ぶ:タイムスタンプと暴れ馬
字幕の処理でも同じような問題が起きた。
動画生成のステップ4で、字幕が途中から消えるバグを踏んだ。
コードを何度見直しても指示は正しい。
FFmpegの処理に渡す直前のデータが欠落していた。
「fix: step 04のcomputeLossに末尾境界トリミング+欠落テキスト自動パッチ追加」
末尾のトリミング処理を追加した。
欠落したテキストを自動でパッチする仕組みも入れた。
入力テキストと出力テキストのレーベンシュタイン距離を測るロス計算を厳密にした。
全9チャンクでロス率0.00%を達成した。
直ったと思った。
直後にステップ5で、修正したテキストにタイムスタンプの接頭辞がくっついて後続処理が壊れた。
修正が次のバグを呼ぶ。
一番キツいパターンだ。
「fix: step 05のfixedフィールドからタイムスタンプ接頭辞を除去」
パイプライン全体のデータの流れを図に書き出した。
ステップをまたいで何がどう変換されているかを整理した。
動画生成パイプラインは、テキスト、音声、画像の各ストリームがミリ秒単位で同期する必要がある。
1文字のズレが、最終的な動画の音ズレに直結する。
「fix: step 05の修正テキストがstep 06のretime でマッチしない問題を修正」
ステップ5で修正前のテキストをoriginalTextとして保存するようにした。
ステップ6で修正後テキストがマッチしない場合、元のテキストでWhisperのワードマッチングを行う。
次からは前後の入出力を確認してからAIにコードを書かせる。たぶん。
しんたろー:
ハッピーパスだけテストして本番に出した僕がバカだった。Claude Codeは「壊れるパターンを探せ」と言わないと探さない。
ここまで読んだあなたに
今なら無料で全機能をお試しいただけます。設定後は完全放置でプロ品質の投稿を毎日生成。
泥臭い辞書育成とモデルの迷走
音声読み上げの誤読も、プロンプトで制御できるはずだ。
僕はAIを完全にコントロールできると錯覚していた。
現実は違った。
VOICEVOXが「200メートル下」を「200メートルした」と読んだ。
「超常」を「ちょうつね」と読んだ。
僕はプロンプトにNGワードを指定した。
するとAIは「ほな別の変な読み方するわ」と斜め上の誤読を始めた。
音声合成エンジンの形態素解析には限界がある。
しんたろー:
カタカナと漢字の複合語、まじで言うこと聞かない。直しても直しても次が出てくる。
MeCabやOpenJTalkなどの辞書ベースの解析は、現代のLLMのような文脈理解を持たない。
プロンプトでいくら指示しても、エンジン側の辞書が優先される。
僕はAIに任せるのを諦めた。
誤読リストをスプレッドシートで管理し始めた。
「fix: VOICEVOX既知誤読に「メートル下」→「メートルした」追加」
「fix: VOICEVOX既知誤読に「超常」→「ちょうじょう」追加」
コードの中にハードコードでパッチを当てる。
泥臭い手作業だ。
自動化の裏側は、人間による地道な辞書育成作業だった。
最先端のAIシステムでも、最後は正規表現と辞書登録に行き着く。
読みの検証プロセスも迷走した。
Geminiのモデルをとっかえひっかえした。
1日で3回もモデルを変えた。
最新モデルに飛びつく悪癖が出た。
「fix: 読み検証モデルをgemini-3-flash-previewに変更」
「fix: 読み検証モデルをgemini-2.5-flashに戻す + ハードコード誤読修正を削除」
3.1系のプレビュー版を試したが、APIが404を返して検証が丸ごと機能しなくなった。
公式ドキュメントに存在しないバージョンをAIが提案してきたのだ。
結局安定している2.5系に戻した。
新しいモデルは常に不安定だ。
「fix: Geminiモデルを3.1系に統一 + temperature修正」
モデル選びよりも、temperatureの数値を詰める方が重要だった。
0.8から0.7に下げた。
数字を1つ変えるだけで、出力の揺れが大きく変わる。
AIは制御不能な暴れ馬だ。
手綱を握るのは常に人間でなければならない。
存在しない動画の錬金術
AIに「動画なし記事はスキップ」という指示を出した。
記事の下書きを準備する処理でのことだ。
シンプルな条件分岐で終わるはずだった。
TypeScriptで書けば3行で終わる。
AIは「動画なし」を「動画がない記事は、動画を生成してから処理しろ」と解釈した。
そして、存在しない動画の生成プロセスを呼び出し、無限ループに陥った。
APIのリクエスト上限に達するまで、システムは空回りを続けた。
ログには大量の429 Too Many Requestsが記録されていた。
「動画なし」を「動画がない」と解釈するAIの国語力に、僕の論理的思考が完敗した。
人間の常識はAIには通用しない。
曖昧な自然言語は、システムを破壊する最大の要因になる。
AST(抽象構文木)を持たないLLMに、厳密な論理分岐を任せてはいけない。
数字で振り返るコストと速度
| 指標 | キャッシュ導入前 | キャッシュ導入後 | 比較 |
| :--- | :--- | :--- | :--- |
| 1人SaaSのAPIコスト最適化率 | 100% | 45% | 利益率の直結指標 |
| Pexels APIコール数 | 毎回全検索 | 24時間再利用 | 企業なら数万円の節約 |
| 実装時間 | 手動なら半日 | AIで30分 | 過去の僕の10倍速 |
「feat: Pexels検索結果キャッシュ(24h TTL) + 複数APIキーラウンドロビン」
APIコストが先月比で半分以下になった。
Pexelsの画像検索APIを毎回叩いていたのをやめた。
同じキーワードの検索結果を24時間キャッシュするようにした。
Redisを用いて分散キャッシュを構築した。
APIキーも複数用意してラウンドロビンで回す仕組みを入れた。
レートリミットに引っかかると即座に別のキーに切り替わる。
429エラーによる処理の停止が完全に消えた。
ただし、キャッシュのパージ処理を忘れて古い画像が出続けた。
しんたろー:
請求画面見て笑った。もっと早くやれよって話だけど、AIに2つ指示しただけでこれが動く。
外部APIへの過度な依存は、SaaSの利益率を直接圧迫する。
レートリミットの回避策としても、キャッシュとラウンドロビンは必須の設計だ。
企業開発ならインフラチームが数週間かけて設計する仕組みを、僕は30分で組み込んだ。
これが1人開発のスピードだ。
よくある質問
Q. APIのresponseSchemaを導入したことでレイテンシは悪化しなかったか?
導入前後でレスポンスタイムに有意な差は出なかった。
むしろパース失敗によるリトライが減り、パイプライン全体の実行時間は15%短縮された。
型定義のパース処理よりも、LLMの推論時間の方が圧倒的に支配的だ。
Q. 誤読リストのハードコードは技術的負債にならないか?
確実になるが、現状はスピードを優先している。
将来的にユーザーごとのカスタム辞書機能へ昇華させるためのプロトタイプと割り切った。
完璧な設計を待つより、泥臭くても動くものを本番に出す方が価値がある。
Q. 複数APIキーのラウンドロビン実装で気をつけるべき点は?
キーの枯渇状態を監視し、全てのリミットに達した際のフォールバックを必ず用意することだ。
今回はRedisを用いて各キーの使用回数とリセット時間を管理している。
状態を持たない単純な配列ループだと、並行処理時に一瞬で全キーが機能停止する。
AIをシステムの一部として組み込むには、徹底的な不信感と強固なガードレールが必要だ。
失敗を重ねながら、今日もシステムは少しずつ堅牢になっている。

この記事が参考になったら、ThreadPostを試してみませんか?
投稿作成・画像生成・スケジュール管理まで、全てAIにお任せできます。
ThreadPostをもっと知る