LESSON 40分

ストーリー

佐藤CTO
RAGのアーキテクチャとベクトルDBは固まった。次はLLMへの指示の質、つまりプロンプトだ
佐藤CTO
同じモデル、同じコンテキストでも、プロンプト次第でこれだけ品質が変わる。左は曖昧で冗長。右は簡潔で正確。プロンプトエンジニアリングは”お願いの仕方”ではない。精密な指示設計だ
あなた
体系的なアプローチがあるのですか?
佐藤CTO
もちろんだ。Zero-shot、Few-shot、Chain of Thought。テクニックは多いが、原則は少ない。今日はその原則を叩き込む

プロンプトの基本構造

システムプロンプト vs ユーザープロンプト

interface ChatMessage {
  role: 'system' | 'user' | 'assistant';
  content: string;
}

// 本番プロンプトの基本構造
const messages: ChatMessage[] = [
  {
    role: 'system',
    content: `あなたは社内技術ナレッジベースのアシスタントです。

## 役割
- 技術的な質問に対して、提供されたコンテキストに基づいて正確に回答する
- 不明な点は正直に「分かりません」と回答する

## 制約
- コンテキストに含まれない情報で回答しない
- 推測や一般知識での補完は行わない
- 回答には必ず出典を含める

## 出力形式
- 簡潔かつ構造化された回答(箇条書き推奨)
- コード例を含む場合はTypeScriptで記述
- 出典は [出典N] の形式で引用`,
  },
  {
    role: 'user',
    content: `## コンテキスト
${retrievedContext}

## 質問
${userQuery}`,
  },
];

Zero-shot / Few-shot / Chain of Thought

Zero-shot

事前の例示なしで直接タスクを指示するパターンです。

// Zero-shot: シンプルな分類タスク
const zeroShotPrompt = `以下のユーザー質問のカテゴリを判定してください。

カテゴリ: ["技術質問", "手続き質問", "障害報告", "その他"]

質問: ${userQuery}

カテゴリ:`;

Few-shot

具体例を提示してタスクの期待出力を示すパターンです。

// Few-shot: 入出力の例を提示
const fewShotPrompt = `ユーザーの質問からメタデータを抽出してください。

## 例

質問: "先月のPostgreSQLデッドロック障害の原因を教えて"
抽出結果:
\`\`\`json
{
  "category": "incident",
  "technology": ["PostgreSQL"],
  "timeRange": "先月",
  "intent": "cause_analysis"
}
\`\`\`

質問: "Kubernetes上でのBlue-Greenデプロイの手順"
抽出結果:
\`\`\`json
{
  "category": "tech-doc",
  "technology": ["Kubernetes"],
  "timeRange": null,
  "intent": "how_to"
}
\`\`\`

## タスク

質問: "${userQuery}"
抽出結果:`;

Chain of Thought (CoT)

段階的に推論させることで、複雑な問題の精度を向上させるパターンです。

// Chain of Thought
const cotPrompt = `以下の技術的な質問に対して、ステップバイステップで考えてから回答してください。

## コンテキスト
${context}

## 質問
${userQuery}

## 回答プロセス
1. まず、質問の意図を分析します
2. 次に、コンテキストから関連する情報を特定します
3. 関連情報を組み合わせて回答を構成します
4. 最後に、回答の正確性を検証します

では、上記のプロセスに従って回答します:`;

プロンプト設計の7原則

1. 明確な役割の定義

// 悪い例
const bad = "質問に答えてください";

// 良い例
const good = `あなたはシニアソフトウェアエンジニアとして、
チームメンバーからの技術的な質問に対して、
正確で実用的なアドバイスを提供します。`;

2. 構造化された指示

// 悪い例
const bad = "コンテキストを見て質問に答えて、出典も書いて、分からないときは分からないと言って";

// 良い例
const good = `## 指示
1. コンテキストを注意深く読む
2. 質問に対する回答を構成する
3. 各主張に [出典N] を付与する
4. コンテキストに情報がない場合は「該当する情報が見つかりませんでした」と回答する

## 出力形式
- Markdown形式
- 箇条書きまたは番号付きリスト
- コード例がある場合はコードブロックで囲む`;

3. 具体的な制約の設定

const constrainedPrompt = `## 制約
- 回答は300文字以内
- 日本語で回答
- 技術用語は正確に使用(略称は初出時にフルスペル)
- 個人的な意見や推測は含めない
- "おそらく"、"たぶん" などの曖昧な表現は使わない`;

4. 出力形式の明示

const outputFormatPrompt = `以下のJSON形式で回答してください:

\`\`\`json
{
  "answer": "回答テキスト",
  "confidence": "high" | "medium" | "low",
  "sources": ["出典1", "出典2"],
  "relatedTopics": ["関連トピック1", "関連トピック2"]
}
\`\`\``;

5. ネガティブプロンプト(やってはいけないことの明示)

const negativePrompt = `## やってはいけないこと
- コンテキストにない情報で回答を補完しない
- ユーザーの質問を勝手に解釈して別の質問に答えない
- 「AIとして」「大規模言語モデルとして」などの自己言及をしない
- 過度に丁寧な前置きや謝罪を含めない
- 同じ情報を繰り返さない`;

6. 段階的な指示(複雑なタスク)

const stepByStepPrompt = `以下のタスクを順番に実行してください。

### Step 1: 質問の分類
質問を以下のいずれかに分類してください:
- factual: 事実を問う質問
- procedural: 手順を問う質問
- analytical: 分析を求める質問

### Step 2: コンテキストの関連度評価
各コンテキストが質問にどの程度関連しているか、1-5で評価してください。

### Step 3: 回答の生成
関連度3以上のコンテキストのみを使って回答を生成してください。

### Step 4: 出典の付与
回答の各主張に出典番号を付けてください。`;

7. デリミターの活用

// 入力の境界を明確にする
const delimitedPrompt = `以下のコンテキストとクエリを使って回答してください。

<context>
${contexts.map((c, i) => `<source id="${i + 1}">\n${c}\n</source>`).join('\n')}
</context>

<query>
${userQuery}
</query>

<rules>
- sourceタグ内の情報のみを使用すること
- 回答にはsource idを引用すること
</rules>`;

アンチパターン

アンチパターン問題改善策
曖昧な指示出力が不安定具体的な出力形式と制約を明示
過剰な指示モデルが混乱優先順位を付けて重要な指示を絞る
矛盾する制約出力が不整合制約間の整合性を事前にチェック
暗黙の期待意図しない出力期待する出力を例示する
長すぎるプロンプトトークンの無駄不要な前置きを削除、簡潔に
本番プロンプトのテンプレート例
function buildProductionPrompt(
  query: string,
  contexts: RetrievedContext[],
  config: {
    systemRole: string;
    outputFormat: 'markdown' | 'json';
    maxLength?: number;
    language: 'ja' | 'en';
  },
): ChatMessage[] {
  const contextSection = contexts
    .map((c, i) => `<source id="${i + 1}" title="${c.chunk.metadata.documentTitle}">\n${c.chunk.content}\n</source>`)
    .join('\n\n');

  const formatInstruction = config.outputFormat === 'json'
    ? `JSON形式で回答してください: {"answer": "...", "sources": [1, 2], "confidence": "high|medium|low"}`
    : `Markdown形式で回答してください。見出しや箇条書きを活用してください。`;

  return [
    {
      role: 'system',
      content: `${config.systemRole}

## 制約
- 提供されたsourceタグ内の情報のみを根拠にして回答する
- 情報が不足している場合は正直にその旨を伝える
- 回答には出典番号を [出典N] 形式で含める
${config.maxLength ? `- 回答は${config.maxLength}文字以内` : ''}

## 出力形式
${formatInstruction}`,
    },
    {
      role: 'user',
      content: `<context>\n${contextSection}\n</context>\n\n質問: ${query}`,
    },
  ];
}

まとめ

ポイント内容
3つのテクニックZero-shot、Few-shot、Chain of Thought を使い分ける
7つの原則役割定義、構造化、制約、出力形式、ネガティブ指示、段階的指示、デリミター
アンチパターン曖昧な指示、過剰な指示、矛盾する制約は品質低下の原因
実践システムプロンプトとユーザープロンプトの役割分担を明確にする

チェックリスト

  • Zero-shot / Few-shot / CoT の使い分けを理解した
  • プロンプト設計の7原則を理解した
  • アンチパターンとその回避方法を理解した
  • 本番向けプロンプトの構造を理解した

次のステップへ

プロンプトの原則を学びました。次のセクションでは、LLMからの出力を構造化データとして確実に取得する方法を学びます。

プロンプトは”お願い”ではなく”仕様書”。曖昧さを排除し、再現性のある出力を目指す。


推定読了時間: 40分