木曜の夜11時43分、GPT-4が完全な自信を持って生成した340行のReactコードを眺めていました。クリーンでした。コメントも充実していました。本番環境では完全に動作しませんでした。カスタムフックが状態を管理していたのですが、それがサイレント再レンダリングループを引き起こしていて、エラーは投げないけれど、ただ静かにパフォーマンスを殺すタイプで、金曜の朝にクライアントから「なぜチェックアウトページが9秒もかかるのか」と電話がかかってくるまで誰にも気づかれません。
その夜は、YouTubeチュートリアルやTwitterのスレッドではどんなものよりも、プロンプト・エンジニアリングについて教えてくれました。そしてあの夜以来、同じような夜を何度も経験しています。
私はウェブ開発を9年間行ってきました。Seahawk Mediaでは12,000以上のサイトをデプロイしてきました。WordPress、ヘッドレスビルド、カスタムReactアプリ、真剣な取引量を扱うWooCommerceストア。AIコーディングアシスタントは2023年初頭ぐらいに本格的に私のワークフローに入り込みました。それ以来、それらが奇跡的だと思ったり、ノートパソコンをテムズ川に投げ込みたくなったり、の間を揺れ動いています。Seahawk Media we've shipped well over 12,000 sites — WordPress, headless builds, bespoke React apps, WooCommerce stores handling serious transaction volume. AI coding assistants entered my workflow properly around early 2023, and I've swung between thinking they're miraculous and wanting to throw my laptop into the Thames.
実際に学んだことはこれです。辛い方法でね。
---
モデルはあなたのコードベースを知りません。あなたが教える必要があります。
これは当たり前に聞こえます。実際にはそうではありません。
開発者が犯す最大の過ちは — 最初の6ヶ月の私を含めて — LLMを既にあなたのコードをすべて読んだシニアエンジニアのように扱うことです。「ユーザー認証を処理する関数を書いて」と聞くと、モデルは真空状態で技術的に正しいものを書きます。しかしあなたのプロジェクトはFirebaseではなくSupabaseを使っています。あなたのトークンはlocalStorageではなくhttpOnly cookieに格納されています。あなたのエラー形式は{ status, message, data }で、モデルがデフォルトで採用したものではありません。{ status, message, data }, not whatever the model defaulted to.
モデルは間違っていません。単にあなたのことを知らないだけです。
プロジェクトプリアンブルを毎回与える
現在、意味のあるコーディングセッションのたびに、私が「コンテキストブロック」と呼ぶもので開始しています。書くのに約90秒かかります。こんな感じです:
- スタック:Next.js 14(App Router)、TypeScript、Supabase、Tailwind CSS 3.4
- ステート:Zustand、Reduxはどこにもなし
- 認証:ミドルウェア経由のhttpOnly cookieを使用したSupabase Auth
- エラー形式:{ success: boolean, error?: string, data?: unknown }
{ success: boolean, error?: string, data?: unknown } - スタイリング規約:ユーティリティファースト、絶対に必要な場合を除きカスタムCSSファイルなし
些細でないリクエストの前にそれを貼り付けます。Cursorではプロジェクトルートに _context.md ファイルを保管しておき、2キーストロークで貼り付けます。出力品質は目に見えて向上します—仮定が減り、削除し直す必要のあるものが減ります。Cursor by keeping a _context.md file in the project root. Two keystrokes to paste. The output quality jumps noticeably — fewer assumptions, fewer things I have to rip out.
---
具体性がすべてだ
私がまだAIを本格的に使う前の2022年、クライアントから文字通り2文のブリーフを受け取りました:「予約システムを構築してくれ。質の高いものをお願いします。」スコープについて3週間にわたって議論を重ねました。その経験は私に強く印象付けられ、今の私のプロンプト作成方法に直結しています。
曖昧なプロンプト → 曖昧なコード。毎回です。
「オーダーを取得する関数を書いて」というプロンプトはそれなりの結果をくれます。一方「TypeScriptの非同期関数fetchOrdersByUserを書いて。userId: stringを受け入れ、Supabaseのordersテーブルでuser_idが一致しstatusがcancelledではない行をクエリし、created_atの降順でソートし、Order[]を返すか型付きエラーをスローする」というプロンプトは、実際に本番にリリースできるものをくれます。fetchOrdersByUser that accepts a userId: string, queries the orders table in Supabase where user_id matches and status is not cancelled, orders results by created_at descending, and returns Order[] or throws a typed error" will get you something you can actually ship.
違いはモデルの能力ではありません。プロンプトの具体性です。
コードプロンプトに含めるべきもの
- 関数名とシグネチャ—モデルに命名規約を勝手に作らせない — don't let the model invent naming conventions
- 入力型と出力型 — TypeScript ジェネリクスが関連する場合 — TypeScript generics if relevant
- データソース — どのテーブル、どの API エンドポイント、どのキャッシュレイヤーか — which table, which API endpoint, which cache layer
- すでに認識しているエッジケース — 「配列が空の場合を処理する」など — "handle the case where the array is empty"
- やってはいけないこと — 「このために useEffect を使わない、サーバーアクションを使う」 — "don't use useEffect for this, use a server action"
この最後の点は人々が気付いているより遙かに重要だ。モデルに避けるべきことを指示することで、莫大な時間を節約できる。私はプロジェクトごとに小さな「アンチパターン」ノートを保持し始めた — 「ユーザー操作が必要でない限りクライアントコンポーネントを使わない」のようなもの — そのプロジェクト向けのプロンプトに関連行を含める。
---
プロンプトをチェーンさせる。一度にすべてを求めないこと。
Seahawk は 2023 年後半にフィンテック系クライアントがいた — 誰とは言わないが — マルチステップの KYC フローを構築していた。複雑な内容だ。ドキュメントアップロード、ライブネスチェック統合、ステータスポーリング。早い段階で私は GPT-4 に「フルの KYC フローコンポーネントを構築してくれ」と求める間違いを犯した。600 行の見栄えのいい駄作が出てきた。ロジックが絡み合い、懸念が混在し、UI ステート とビジネスロジック間に真の分離がない。
だから私はそれを破棄して、チェーンで再スタートした。
最初のプロンプト: 「4 ステップの KYC フローの状態マシンを設計してくれ。ステップ: 本人確認、ドキュメントアップロード、ライブネス、レビュー。状態型とトランジションだけくれ、UI は不要。」"Design the state machine for a 4-step KYC flow. Steps: identity, document upload, liveness, review. Give me the state type and transitions only, no UI."
2番目のプロンプト:「この状態マシン[貼付]が与えられたとき、Zustandストアを書いてください」"Given this state machine [paste], write the Zustand store."
3番目のプロンプト:「このストア[貼付]が与えられたとき、StepIdentityコンポーネントを書いてください。このステップだけです」"Given this store [paste], write the StepIdentity component. Just this step."
チェーン方式の出力は使える品質でした。完璧ではなく、30%程度は自分で書き直しましたが、使える状態でした。モノリシック方式ではなにも得られませんでした。
Anthropic自身のプロンプティングに関するガイダンスは、複雑なタスクをサブタスクに分割することを推奨しており、正直なところ、試行錯誤を通じて私が見つけたものと完全に一致しています。コードベースを壊す前に、問題を細分化してください。 talks about breaking complex tasks into subtasks, and honestly, this aligns exactly with what I found through trial and error. Break the problem down before you break your codebase.
---
自分自身と議論させる
これは完全な偶然で発見したものです。生成されたユーティリティ関数をレビューしていたとき、単に実行するのではなく、フォローアップのプロンプトを追加しました:「あなたが書いたコードの潜在的なバグやエッジケースは何ですか?」"What are the potential bugs or edge cases in the code you just wrote?"
モデルは3つの見落としていた問題を見つけました。そのうち1つは本当の問題でした。非同期ループの競合状態で、本番環境でデバッグするのは悪夢になっていたはずです。
今では定期的にこれをやっています。コードを書いて、それをモデルに批評させる。その批評を修正させる。モデルに自分の仕事をレビューさせるのはやや不格好に感じますが、辛いデバッグセッションの後でしか気づかないようなことを、一貫して見つけ出します。
これをもっと進めることができます。動作する関数を手に入れたら、次のように試してください:「パフォーマンスに焦点を当てて書き直してください」または「これは高い並行実行下でどのように動作するでしょうか?」答えが常に適用可能とは限りませんが、約40%の場合、実行する価値のあるものが浮かび上がります。"Rewrite this with a focus on performance" or "How would this behave under high concurrency?" The answers aren't always applicable, but about 40% of the time they surface something worth acting on.
---
「ロール + 制約」フレーム
今は常に使っているプロンプトパターンがあるが、1年目に気づいていれば良かったと思う。それは「あなたは[特定のエンジニアのタイプ]です。制約は[ハードルール]です。では[タスク]を」という形だ。"You are a [specific type of engineer]. Your constraint is [hard rule]. Now [task]."
例:「あなたはデータベースクエリの効率を深く考えるバックエンドエンジニアです。制約は、このレンダリングに必要な以上のデータを取得することはできないということです — オーバーフェッチは禁止です。管理ダッシュボードの注文数、総収益、最新5件の注文を返すSupabaseクエリを書いてください。」"You are a backend engineer who cares deeply about database query efficiency. Your constraint is that you cannot fetch more than what's needed for this render — no over-fetching. Write a Supabase query for the admin dashboard that returns order count, total revenue, and the five most recent orders."
このフレーミングは2つのことをする。モデルの「ペルソナ」を、私が実際に必要とするものと一致させる。そして制約はガードレール機能し — モデルが生成する際に明示的に自分自身に対して確認するものになる。
OpenAIのプロンプト作成ベストプラクティスでは、明示的な指示を伴うペルソナをモデルに与えるという同様の考え方が説明されている。読む価値があるが、正直なところ制約の部分は彼らのドキュメントでは強調が不足していると言える。 describe a similar idea around giving the model a persona with explicit instructions. Worth reading if you haven't, though I'd say the constraint piece is underemphasised in their docs.
そのフレーム付きプロンプトの出力を「管理ダッシュボードのためのSupabaseクエリを書いてください」と比較してみろ。全く違う。本当に。
---
プロンプトをやめて、ただコードを書くべき時
これは誰も声に出して言いたくない部分だ。
AI コーディングツールは以下の点で優れています:ボイラープレート、CRUD操作、ユーティリティ関数、既に書いたコードのテスト作成、フォーマット間の変換(JSON スキーマから TypeScript 型へ、SQL から Supabase クエリへなど)、そして大幅に修正することになるものの初期ドラフト作成。
一方、以下の点で著しく不得意です:アプリの実際のアーキテクチャを理解すること、あなたの特定のスケールにとってどのトレードオフが重要かを知ること、複雑なステートフルなインタラクションに関わるものを大幅なガイダンスなしで書くこと、そして仕様が本質的に曖昧な場合のすべてのもの。
私は今、個人的なルールを持っています:コードを正しく書き直すために4回以上のフォローアッププロンプトを送った場合、チャットを閉じて自分で書きます。プロンプトデバッグの時間コストは、特に約50行以下のものについて、単に書いてしまう時間コストを超える可能性があります。
Stack Overflow Developer Survey 2024 によると、開発者の76% が AI ツールを使用しているか、使用する予定ですが、同じデータは精度への信頼が比較的低いことを示していました。使用と信頼のこのギャップこそが、優れたプロンプトエンジニアリングが存在する場所です。Stack Overflow Developer Survey 2024 found that 76% of developers are using or planning to use AI tools — but the same data showed relatively low trust in accuracy. That gap between usage and trust is exactly where good prompt engineering lives.
---
コードをバージョン管理するのと同じようにプロンプトをバージョン管理する
昨年から、AI アシスタンスが重要なプロジェクトに prompts/ フォルダを保持し始めました。Markdown ファイル。主要な機能領域ごとに1つ。プロンプトが特に良い出力を生成するとき、保存します。より良いバージョンを見つけたら、ファイルを更新します。prompts/ folder in projects where AI assistance is significant. Markdown files. One per major feature area. When a prompt produces particularly good output, I save it. When I find a better version, I update the file.
強迫観念的に聞こえます。最後の大きなプロジェクトだけで、おそらく6時間節約されました。ショッピファイから移行する小売業者向けのヘッドレス WooCommerce ビルドです。4つの異なるコンポーネント全体にわたって商品クエリプロンプト(軽微な編集付き)を再利用し、ゼロからコンテキストを再度エンジニアリングする代わりになりました。
Git で追跡してください。本当に。プロンプト品質は、プロンプトを一時的な入力ではなくアーティファクトとして扱えば再現可能です。LangChain のプロンプトテンプレートはフレームワークコンテキストでこのアイデアを形式化しますが、フレームワークは必要ありません。ほとんどのエージェンシーワークフローでは Markdown ファイルのフォルダで十分です。LangChain's prompt templates formalise this idea in a framework context, but you don't need any framework — a folder of Markdown files is enough for most agency workflows.
---
よくある質問
プロンプトエンジニアリングは本当に応用可能なスキルなのか、それとも単にモデル固有のものなのか?
ほぼ応用可能だ。コア原理——具体性、文脈設定、チェーニング、批評ループ——はGPT-4、Claude 3.5 Sonnet、Gemini、その先に来るものにも当てはまる。構文は多少異なり、あるモデルは特定のフレーミングにより良く応答するが、根本的なロジックは変わらない。Claudeは明示的な制約に応答しやすい傾向にあり、GPT-4は例に応答しやすいと気付いている。わずかな違い、同じ基本原理だ。syntax varies a bit and some models respond better to certain framing, but the underlying logic holds. I've found Claude tends to respond well to explicit constraints; GPT-4 responds well to examples. Minor differences, same fundamentals.
コードレビューではAI生成コードをどのように扱うか?
他のコードと同じように扱う。本番環境に入るなら、レビューされる。以上だ。Seahawk での PR では「これはAI生成である」というフラグを立てるのをやめた。というのも、それがミスリードになってしまい——レビュアーがそれを異なる方法で精査するようになり、時には不公正に、時には十分でない方法でレビューするようになったからだ。コードはその本質的価値で評価されるか、されないかのいずれかだ。私がフラグを立てるもの:ロジックが自明でなく、推論を説明するインラインコメントを追加していない箇所である。
システムプロンプトを使うのか、それともチャットプロンプトだけなのか?
両方だ。Cursor ではプロジェクトレベルの永続的な指示——そうでなければ毎回貼り付けるようなもの——に .cursorrules ファイルを活用している。ChatGPT や Claude の web UI でのワンオフタスクの場合、すべてチャット内だ。.cursorrules アプローチは反復を大幅に減らし、長いセッションを通じてモデルの一貫性が保たれている。.cursorrules file for persistent project-level instructions — things I'd otherwise paste every time. For one-off tasks in the ChatGPT or Claude web UI, it's all in the chat. The .cursorrules approach has meaningfully reduced repetition and the model stays more consistent across a long session.
AI が開発者に取って代わるというあなたの本当の見方は?
特定のタスクに取って代わっている、開発者そのものではない。判断呼び出し——何を構築するか、どのようにアーキテクチャするか、このクライアントの実際の状況に合う取引はどれか——それらは自動化にはほど遠い。むしろ、実行志向だけだった開発者が圧迫されている、設計やアーキテクチャ志向ではない。判断層を磨け。それが守れる部分だ。tasks, not developers. The judgment calls — what to build, how to architect it, which trade-off fits this client's actual situation — those are nowhere near automated. If anything, the developers getting squeezed are the ones who were purely execution-oriented, not design or architecture-oriented. Sharpen the judgment layer. That's the defensible bit.
---
ウェブ上でものを作り続けて9年間、同じ教訓が何度も繰り返されている。出力の質は入力の質で決まる。それはクライアントのブリーフだった時代も真実だった。プロンプトの今でも真実だ。the quality of your output is determined by the quality of your inputs. That was true when it was client briefs. It's true now with prompts.
そのモデルは高速で、時々素晴らしく、頻繁に自信過剰なジュニア開発者だ。それに応じて管理する必要がある。
