< BACK 本番環境のコード向けプロンプトエンジニアリング:厳しい教訓 -- ラインアート挿絵

本番コード向けプロンプト・エンジニアリング:厳しい教訓

木曜日の夜11時43分、私はGPT-4が完全な自信を持って生成した340行のReactコードを見つめていた。きれいで、コメントも充実している。本番環境では完全に動作していない。カスタムフックは状態を、エラーを投げずに静かなリレンダリングループを引き起こす方法で管理していた。その種のループはエラーをスローしない。ただ静かにパフォーマンスを破壊し続け、金曜日の朝、クライアントがチェックアウトページが9秒かかる理由をあなたに尋ねるまで続く。

その夜は、YouTubeチュートリアルやTwitterのスレッドではどんなものよりも、プロンプト・エンジニアリングについて教えてくれました。そしてあの夜以来、同じような夜を何度も経験しています。

私はWebで9年間開発してきた。Seahawk Mediaでは12,000以上のサイトをリリースしてきた。WordPress、ヘッドレスビルド、カスタムReactアプリ、深刻なトランザクション量を処理するWooCommerceストア。AIコーディングアシスタントは2023年初頭に私のワークフローに本格的に入ってきた。その時から、それらが驚異的だと考えることと、ノートパソコンをテムズ川に投げ込みたいと思うことの間を揺れ動いてきた。

実際に学んだことはこれです。辛い方法でね。

---

モデルはあなたのコードベースを知りません。あなたが教える必要があります。

これは当たり前に聞こえます。実際にはそうではありません。

開発者が犯す最大の間違い(最初の6ヶ月間は私も含む)は、LLMをあなたのコードをすべて読み終えた経験豊富なエンジニアのように扱うことだ。「ユーザー認証を処理する関数を書いて」と頼むと、それは真空の中で技術的に正しい何かを書く。しかし、あなたのプロジェクトはFirebaseではなくSupabaseを使用している。あなたのトークンはlocalStorageではなくhttpOnlyクッキーに存在する。あなたのエラー形式は{ status, message, data }であり、モデルがデフォルトで設定したものではない。

モデルは間違っていません。単にあなたのことを知らないだけです。

プロジェクトプリアンブルを毎回与える

現在、意味のあるコーディングセッションのたびに、私が「コンテキストブロック」と呼ぶもので開始しています。書くのに約90秒かかります。こんな感じです:

  • スタック:Next.js 14(App Router)、TypeScript、Supabase、Tailwind CSS 3.4
  • ステート:Zustand、Reduxはどこにもなし
  • 認証:ミドルウェア経由のhttpOnly cookieを使用したSupabase Auth
  • エラー形式:{ success: boolean, error?: string, data?: unknown }
  • スタイリング規約:ユーティリティファースト、絶対に必要な場合を除きカスタムCSSファイルなし

それを自明でないリクエストの前に貼り付ける。私はCursorでプロジェクトルートに_context.mdファイルを保持することで、これを行う。2キーストロークで貼り付け可能。アウトプット品質が著しく向上し、推測が減り、削除する必要のあるものが減る。

---

具体性がすべてだ

私がまだAIを本格的に使う前の2022年、クライアントから文字通り2文のブリーフを受け取りました:「予約システムを構築してくれ。質の高いものをお願いします。」スコープについて3週間にわたって議論を重ねました。その経験は私に強く印象付けられ、今の私のプロンプト作成方法に直結しています。

曖昧なプロンプト → 曖昧なコード。毎回です。

「オーダーを取得する関数を書いて」というプロンプトはそれなりの結果をくれます。一方「TypeScriptの非同期関数fetchOrdersByUserを書いて。userId: stringを受け入れ、Supabaseのordersテーブルでuser_idが一致しstatusがcancelledではない行をクエリし、created_atの降順でソートし、Order[]を返すか型付きエラーをスローする」というプロンプトは、実際に本番にリリースできるものをくれます。

違いはモデルの能力ではありません。プロンプトの具体性です。

コードプロンプトに含めるべきもの

  1. 関数名と署名。モデルに命名規則を発明させるな。
  2. 入力型と出力型。関連する場合はTypeScriptの総称型。
  3. データソース。どのテーブルか、どのAPIエンドポイントか、どのキャッシュレイヤーか。
  4. すでに把握している エッジケース。「配列が空の場合を処理する」など。
  5. やってはいけないこと。「useEffect でこれをするな、server action を使え」

最後のポイントは人々が思っているより重要だ。モデルに何を避けるべきかを教えることで、膨大な時間を節約できる。私は今、プロジェクトごとに小さな「アンチパターン」ノートを保管するようにしている。「ユーザーインタラクションが必要な場合を除き、クライアントコンポーネントを使うな」といったことで、そのプロジェクト用のプロンプトに関連する行を含めている。

---

プロンプトをチェーンさせる。一度にすべてを求めないこと。

Seahawk は 2023 年後半、多段階 KYC フロー を構築していた金融クライアント(社名は明かせないが)を抱えていた。複雑な案件だった。ドキュメントアップロード、本人確認統合、ステータスポーリング。早期の段階で、GPT-4 に「KYC フロー全体のコンポーネントを構築してくれ」と頼むという過ちを犯した。600 行の見栄えだけ良いゴミが出てきた。ロジックがもつれていて、関心が混在していて、UI state とビジネスロジック間に真の分離がなかった。

だから私はそれを破棄して、チェーンで再スタートした。

最初のプロンプト: 「4 ステップの KYC フローの状態マシンを設計してくれ。ステップ: 本人確認、ドキュメントアップロード、ライブネス、レビュー。状態型とトランジションだけくれ、UI は不要。」

2番目のプロンプト:「この状態マシン[貼付]が与えられたとき、Zustandストアを書いてください」

3番目のプロンプト:「このストア[貼付]が与えられたとき、StepIdentityコンポーネントを書いてください。このステップだけです」

チェーンアプローチからの出力は使える代物だった。完璧ではなく、それでも 30% 程度は書き直したが、使える。モノリシックアプローチからは何ももらえなかった。

Anthropic自身のプロンプティングに関するガイダンスは、複雑なタスクをサブタスクに分割することを推奨しており、正直なところ、試行錯誤を通じて私が見つけたものと完全に一致しています。コードベースを壊す前に、問題を細分化してください。

---

自分自身と議論させる

これは完全な偶然で発見したものです。生成されたユーティリティ関数をレビューしていたとき、単に実行するのではなく、フォローアップのプロンプトを追加しました:「あなたが書いたコードの潜在的なバグやエッジケースは何ですか?」

モデルは自分が考慮していなかった 3 つの問題を発見した。うち 1 つは本物の問題で、非同期ループのレースコンディションで、本番環境でデバッグするのは悪夢だったはずだ。

今は定期的にこれをやっている。コードを書く、モデルにコードを批評させる、批評を直させる。モデルに自分の仕事をレビューさせるというのは少し馬鹿馬鹿しく聞こえるが、辛いデバッグセッションの後でしか気づかないようなことを一貫して表面化させてくれる。

これをもっと進めることができます。動作する関数を手に入れたら、次のように試してください:「パフォーマンスに焦点を当てて書き直してください」または「これは高い並行実行下でどのように動作するでしょうか?」答えが常に適用可能とは限りませんが、約40%の場合、実行する価値のあるものが浮かび上がります。

---

「ロール + 制約」フレーム

今は常に使っているプロンプトパターンがあるが、1年目に気づいていれば良かったと思う。それは「あなたは[特定のエンジニアのタイプ]です。制約は[ハードルール]です。では[タスク]を」という形だ。

例:「あなたはデータベースクエリの効率性を深く気にかけるバックエンドエンジニアです。制約は、このレンダーに必要な以上のものを取得できない、オーバーフェッチなしです。管理ダッシュボード用の Supabase クエリを書いてください。注文数、総収益、そして最新の 5 件の注文を返してください。」

そのフレーミングは 2 つのことをする。モデルの「ペルソナ」を、私が実際に必要なものと揃える。そして制約はガードレールとして機能し、モデルが生成する際に明示的にチェックする何かだ。

OpenAIのプロンプト作成ベストプラクティスでは、明示的な指示を伴うペルソナをモデルに与えるという同様の考え方が説明されている。読む価値があるが、正直なところ制約の部分は彼らのドキュメントでは強調が不足していると言える。

そのフレーム付きプロンプトの出力を「管理ダッシュボードのためのSupabaseクエリを書いてください」と比較してみろ。全く違う。本当に。

---

プロンプトをやめて、ただコードを書くべき時

これは誰も声に出して言いたくない部分だ。

AI コーディングツールは以下の点で優れています:ボイラープレート、CRUD操作、ユーティリティ関数、既に書いたコードのテスト作成、フォーマット間の変換(JSON スキーマから TypeScript 型へ、SQL から Supabase クエリへなど)、そして大幅に修正することになるものの初期ドラフト作成。

一方、以下の点で著しく不得意です:アプリの実際のアーキテクチャを理解すること、あなたの特定のスケールにとってどのトレードオフが重要かを知ること、複雑なステートフルなインタラクションに関わるものを大幅なガイダンスなしで書くこと、そして仕様が本質的に曖昧な場合のすべてのもの。

私は今、個人的なルールを持っています:コードを正しく書き直すために4回以上のフォローアッププロンプトを送った場合、チャットを閉じて自分で書きます。プロンプトデバッグの時間コストは、特に約50行以下のものについて、単に書いてしまう時間コストを超える可能性があります。

Stack Overflow Developer Survey 2024 は、開発者の 76% が AI ツールを使用しているか使用予定だと判明させたが、同じデータは精度への信頼が比較的低いことを示した。使用と信頼の間のそのギャップは、まさに優れたプロンプトエンジニアリングが生きる場所だ。

---

コードをバージョン管理するのと同じようにプロンプトをバージョン管理する

昨年から、AI アシスタンスが重要なプロジェクトに prompts/ フォルダを保持し始めました。Markdown ファイル。主要な機能領域ごとに1つ。プロンプトが特に良い出力を生成するとき、保存します。より良いバージョンを見つけたら、ファイルを更新します。

執着的に聞こえるかもしれない。先ほどの大きなプロジェクト(Shopify から移行する小売業者向けのヘッドレス WooCommerce ビルド)だけでおそらく 6 時間節約してくれた。4 つの異なるコンポーネント全体でプロダクトクエリプロンプト(小編集を加えたもの)を再利用して、ゼロからコンテキストを再エンジニアリングする代わりにした。

Gitで管理してください。本気でそう考えています。プロンプトの品質は、プロンプトを使い捨ての入力ではなく、成果物として扱えば再現可能です。LangChainのプロンプトテンプレートはこの考え方をフレームワークコンテキストで形式化していますが、フレームワークは不要です。ほとんどのエージェンシーワークフローではMarkdownファイルのフォルダで十分です。

---

よくある質問

プロンプトエンジニアリングは本当に応用可能なスキルなのか、それとも単にモデル固有のものなのか?

ほぼ応用可能です。中核となる原則—詳細性、コンテキスト設定、チェーニング、批判的なループ—はGPT-4、Claude 3.5 Sonnet、Geminiなど、次に来るものまで、すべてに適用されます。構文は若干異なり、一部のモデルは特定のフレーミングに反応しやすいですが、根底にある論理は変わりません。私の経験では、Claudeは明示的な制約に応じやすく、GPT-4は例に応じやすいです。軽微な違い、同じ基本原則です。

コードレビューではAI生成コードをどのように扱うか?

他のコードと同じです。本番運用に投入される場合は、レビューされます。それだけです。Seahawkのプルリクエストで「これはAIが生成した」とフラグを立てるのはやめました。フラグを立てるとレビュアーが異なる方法で精査するようになったからです。時には不公平に、時には不十分に。コードはそれ自体の価値で成立するか失敗するかが決まります。私がフラグを立てるのは、ロジックが明らかでなく、推論を説明するインラインコメントを追加していない箇所です。

システムプロンプトを使うのか、それともチャットプロンプトだけなのか?

どちらも。Cursorでは.cursorrules ファイルを永続的なプロジェクトレベルの指示に使用します。そうでなければ毎回貼り付けるような内容です。ChatGPTやClaude Webウェブ UIでの一度きりのタスクは、すべてチャット内にあります。.cursorrules アプローチは反復を大幅に減らし、長いセッションを通じてモデルの一貫性を保つようになりました。

AI が開発者に取って代わるというあなたの本当の見方は?

これは特定のタスクを置き換えています。開発者を置き換えるのではなく。判断の呼び出し、何を構築するか、どのようにアーキテクチャするか、このクライアントの実際の状況にどのトレードオフが適合するか—これらは全く自動化されていません。むしろ、開発者が圧迫されているのは、純粋に実行指向で、設計やアーキテクチャ指向ではない開発者です。判断層を磨いてください。それが守ることができる部分です。

---

ウェブ上でものを作り続けて9年間、同じ教訓が何度も繰り返されている。出力の質は入力の質で決まる。それはクライアントのブリーフだった時代も真実だった。プロンプトの今でも真実だ。

そのモデルは高速で、時々素晴らしく、頻繁に自信過剰なジュニア開発者だ。それに応じて管理する必要がある。

関連記事:Next.js & Supabaseでリアルタイムオークションサイトを構築する、2026年のカスタムソフトウェアコスト算出方法:実践的な見積ツール、およびカスタムウェブ開発。

< BACK