Language: 日本語
「型は通るのに品質が狂う」を防ぐ。AI ワークフロー移植で混入する「もっともらしい推測値」の検証法
画像生成、動画生成、テキスト解析、セグメンテーション、字幕、レンダリングまでを連携させるマルチモーダル AI 生成パイプラインを、新しいワークフロー基盤(Mastra)へ移植したときのことです。
画像生成、動画生成、テキスト解析、セグメンテーション、字幕、レンダリングまでを連携させるマルチモーダル AI 生成パイプラインを、新しいワークフロー基盤(Mastra)へ移植したときのことです。
TypeScript でコードを書き直し、型チェックも通り、コンパイルエラーはゼロ。意気揚々とパイプラインを実行したところ……。
「なぜか品質評価ゲートが 2 回連続で不合格になる」「一部のモデル呼び出しで 400 や 404 が多発する」
という原因不明のトラブルに直面しました。
この移植作業で最も時間を奪われたのは、新しいフレームワークのコードを書くことではありませんでした。「コードベースのあちこちに仮置きされていた、もっともらしい推測値の正体を暴く作業」 だったのです。
この記事では、AI ワークフローやデータ処理パイプラインの移植時に潜む 「型システムをすり抜ける推測値」の危険性と、デバッグ時間を劇的に削る 4 つの移植前検証ルール を解説します。
得られること
- 閾値やモデル名など、型(
number/string)では検知できない「もっともらしい値」が引き起こすサイレント品質劣化の正体がわかる reasoning_effortやセグメンテーション API など、実際に踏み抜いた 3 つのリアルな不整合事例が学べる- 移植後の手戻りをゼロにする「一次情報(正本)に基づく 4 つの検証原則」が身につく!
罠 1: 閾値のズレ(単体で見れば誰も怪しまない)
品質評価ゲートが不合格になり続けた直接の原因を調査したところ、移植先の設定ファイルに定義されていた画像処理・セグメンテーションの閾値群が、移植元の正本とほぼすべて食い違っていたこと が判明しました。
| パラメータ | 移植元の正本 | 移植先の設定(推測値) | 影響 |
|---|---|---|---|
artifact_segarea_threshold | 20 | 64 | 評価ゲートが不合格になる直接原因 💥 |
boundary_margin_threshold | 20 | 12 | 境界抽出の精度低下 |
dilate_kernel_size | 20 | 6 | マスク膨張の不足 |
padding_size | 50 | 10 | パディング欠落 |
polygon_outline_width | 50 | 2 | 輪郭描画の欠損 |
popup_weight / spot_weight | 0.4 / 0.6 | 0.6 / 0.4 | 重み付けが真逆に逆転 😱 |
resize_rate | 1.0 | 0.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、メモリ制限など)で踏んだ落とし穴については、『移植先の実行環境で踏んだこと』 で詳しく解説しています!