Blogへ戻る

Language: 日本語

「型は通るのに品質が狂う」を防ぐ。AI ワークフロー移植で混入する「もっともらしい推測値」の検証法

画像生成、動画生成、テキスト解析、セグメンテーション、字幕、レンダリングまでを連携させるマルチモーダル AI 生成パイプラインを、新しいワークフロー基盤(Mastra)へ移植したときのことです。

画像生成、動画生成、テキスト解析、セグメンテーション、字幕、レンダリングまでを連携させるマルチモーダル AI 生成パイプラインを、新しいワークフロー基盤(Mastra)へ移植したときのことです。

TypeScript でコードを書き直し、型チェックも通り、コンパイルエラーはゼロ。意気揚々とパイプラインを実行したところ……。

「なぜか品質評価ゲートが 2 回連続で不合格になる」「一部のモデル呼び出しで 400 や 404 が多発する」

という原因不明のトラブルに直面しました。

この移植作業で最も時間を奪われたのは、新しいフレームワークのコードを書くことではありませんでした。「コードベースのあちこちに仮置きされていた、もっともらしい推測値の正体を暴く作業」 だったのです。

この記事では、AI ワークフローやデータ処理パイプラインの移植時に潜む 「型システムをすり抜ける推測値」の危険性と、デバッグ時間を劇的に削る 4 つの移植前検証ルール を解説します。

得られること

  • 閾値やモデル名など、型(number / string)では検知できない「もっともらしい値」が引き起こすサイレント品質劣化の正体がわかる
  • reasoning_effort やセグメンテーション API など、実際に踏み抜いた 3 つのリアルな不整合事例が学べる
  • 移植後の手戻りをゼロにする「一次情報(正本)に基づく 4 つの検証原則」が身につく!

罠 1: 閾値のズレ(単体で見れば誰も怪しまない)

品質評価ゲートが不合格になり続けた直接の原因を調査したところ、移植先の設定ファイルに定義されていた画像処理・セグメンテーションの閾値群が、移植元の正本とほぼすべて食い違っていたこと が判明しました。

パラメータ移植元の正本移植先の設定(推測値)影響
artifact_segarea_threshold2064評価ゲートが不合格になる直接原因 💥
boundary_margin_threshold2012境界抽出の精度低下
dilate_kernel_size206マスク膨張の不足
padding_size5010パディング欠落
polygon_outline_width502輪郭描画の欠損
popup_weight / spot_weight0.4 / 0.60.6 / 0.4重み付けが真逆に逆転 😱
resize_rate1.00.5解像度が半分に劣化

なぜこの不整合が混入し、見逃されたのか?

これらはすべて number 型として完全に合法です。 コードレビューで popup_weight: 0.6 という行を見ても、レビュアーは「まあ重み付けの係数だし、妥当な値だな」と思って approve してしまいます。

初期の実装者が「とりあえず動かすための妥当そうな値」として推測で仮置きした数値が、そのまま本番相当の設定として生き残ってしまっていたのです。

移植元の設定を export して実値を 1 つずつ突き合わせるまで、この誤りに気づく手段はどこにもありませんでした。

罠 2: モデル名の推測とパラメータの不整合(400 / 404 エラー)

同じ問題は、LLM モデルの指定でも発生しました。

ある評価ゲートが provider_rejected でクラッシュしたため、実際の API リクエストを再現してみると、以下のようなエラーが返ってきました。

{
  "error": {
    "code": 400,
    "type": "invalid_request_error",
    "message": "Unrecognized request argument supplied: reasoning_effort"
  }
}

呼び出し側のコードは全ゲートで reasoning_effort: "low" を送信していましたが、設定されていたモデルはその引数に対応していませんでした。

「コード側の引数が間違っているのか?」と疑いましたが、移植元の本番ログと設定を確認すると、実際に使われていたのは別の推論モデルであり、そちらは正常に reasoning_effort を受け取っていた のです。 つまり、「コード側が正しく、モデル名のほうが推測で書かれたダミー値だった」というオチでした。

別のモデルで起きた 404(アカウント権限の差異)

さらに別のゲートでは、移植元で動いていたモデル名(例: models/gemini-2.5-pro)をそのまま持ってきたところ、今度は 404 エラーになりました。

"This model models/gemini-2.5-pro is no longer available to new users"

移植元の GCP プロジェクトは既存ユーザー扱いで使えていたものの、移植先の新規プロジェクト・API キーでは利用不可になっていたのです。リテラル文字列をそのまま信じて移植してはならず、「移植先のアカウントで実際に叩いて 200 が返るか」 を検証しなければならない好例でした。

罠 3: コメントを信じて踏んだ 404 と 403(エンドポイントの実体)

テキストのセグメンテーション処理を実行した際にも 404 エラーが発生しました。

コード内のコメントには「サービス A が検出とセグメンテーションの両方を提供している」と書かれていました。 しかし、サービス A の /openapi.json を直接取得して確認すると、公開されているパスは検出(Detection)のみ でした。セグメンテーション機能は別リージョンにあるサービス B に置かれていたのです。

さらに、エンドポイントをサービス B に修正すると、今度は 403 Forbidden が発生しました。 セグメンテーションサービスは検出サービスとは異なる専用のサービスアカウントで稼働しており、成果物保存用 Cloud Storage バケットへの閲覧権限が付与されていなかったのです。

コメントも設定も、書かれた当初は正しかったのかもしれません。しかし、「信じてよいのは、実際の OpenAPI スキーマと IAM 権限の事実だけ」 です。

デバッグ時間を 8 割削る「移植前の 4 大原則」

これらのトラブルを振り返ると、原因はすべて共通していました。 「移植元の正本を確認せず、それらしい推測値や古いコメントで埋めてしまったこと」 です。

閾値やモデル名の誤りは、プログラムのクラッシュではなく「生成結果がなんとなくおかしい」「精度が出ない」という形で現れるため、原因の特定に膨大な時間が溶けていきます。

この手戻りをゼロにするために、以下の 4 つの移植前検証ルール を確立しました。

【 移植前の 4 つの検証原則 】
1. 移植元の設定を export して「正本(Single Source of Truth)」を確定する

2. 移植先に対応する処理がないパラメータは、推測で埋めず「未対応」とコメントで明記する

3. 外部サービスの API パスは、コメントではなく /openapi.json や実リクエストで確認する

4. モデル名は、移植先の API キーを使って実際にリクエストを送り 200 応答を担保する

この 4 つをコーディング開始前に済ませておくだけで、移植後に発生する不可解なデバッグの大半は未然に消滅します。

まとめ: 推測を捨て、一次情報の事実から入る

AI パイプラインや複雑なデータ基盤の移植において、「型が通ること(Compiles)」と「正しく動くこと(Behaves correctly)」はまったくの別物 です。

特に AI ワークフローには、直感では正誤が判定できないハイパーパラメータや閾値が無数に存在します。だからこそ、自分の推測や誰かが残した曖昧なコメントに頼るのをやめ、「一次情報(正本の設定・OpenAPI スキーマ・実 API のレスポンス)」 から始めることが、最も速く最も堅牢な移植への最短ルートです。

※ なお、移植元の設定とは無関係に、コンテナの実行環境(Cloud Run や WIF、メモリ制限など)で踏んだ落とし穴については、『移植先の実行環境で踏んだこと』 で詳しく解説しています!

参考リンク