はじめに
最近、開発チームでAIエージェントを活用したソフトウェア開発へのシフトを本格推進しています。
単なる「プロンプトエンジニアリング」や「AIの使い方」レベルにとどまらず、SE同士が技術的な裏側(内部構造・プロトコル・アーキテクチャ)を正しく理解し、システム設計やチーム開発プロセスのアップデートに活かすことを目的に、本記事を作成しました。
1. LLMはどのように回答を生成しているのか?
単なる「確率による次単語予測」の裏で、Transformerアーキテクチャが具体的にどのような計算を行っているのかを技術的に整理します。(技術的メカニズムの深掘り)
数学的な部分なので、こんな事やってるんだなぁ程度で
トークナイズと埋め込み(Embedding)
入力テキストは数値列へと変換され、多次元ベクトル空間にマッピングされます。
- Tokenization (BPE / WordPiece)
- テキストをバイト対符号化(BPE: Byte Pair Encoding)などでサブワード(トークン)に分割し、語彙辞書(例: 語彙数10万個)のインデックスID(整数)に変換
- Token Embedding & Positional Encoding
- 各トークンIDを多次元ベクトル(例: 4096次元や12288次元)の密ベクトル(Embedding)に変換
- Positional Encoding (RoPE: Rotary Position Embedding 等): TransformerはRNNと異なり全トークンを並列処理するため、単語の順序情報を持ちません。そのため、複素数平面上の回転行列を用いたRoPEなどの手法で、トークンの絶対位置・相対位置情報をベクトルに直接加算・演算します
[入力テキスト: "AI開発"]
↓ Tokenizer (BPE)
[トークンID: 1542, 8920, 301]
↓ Embedding Lookup + RoPE (Positional Encoding)
[多次元ベクトル (d_model=4096)]
Self-Attention(自己注意機構)と Multi-Head Attention
Transformerの核心部である Scaled Dot-Product Attention です。
$$
\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
$$
- Query ($Q$): 「何を探しているか」を表すベクトル($Q = X \cdot W_Q$)
- Key ($K$): 「どのような情報を持っているか」を表すベクトル($K = X \cdot W_K$)
- Value ($V$): 「実際の情報コンテンツ」を表すベクトル($V = X \cdot W_V$)
KV Cache と コンテキストウィンドウ(Needle in a Haystack)
LLMがテキストを1トークンずつ順番に生成(Auto-regressive Generation)する際、過去のトークンの $K$ と $V$ の計算結果をメモリ上に保持する仕組みを KV Cache と呼びます。
- 課題: 長文コンテキストになればなるほど、KV CacheがVRAM(GPUメモリ)を大量に消費します($O(N)$ のメモリ増加)
- 長文理解の限界(Needle in a Haystack): コンテキスト長が128kや1Mに拡大しても、入力の「中央付近」にある情報を見落としやすい現象(Lost in the Middle)が存在するため、単に文脈ウィンドウを広げるだけでなく、後述するRAGなどの構造化検索が引き続き重要となります
デコーディングとサンプリングパラメータ
最終層のロジット(Logits: 語彙数分の未正規化スコア)に Softmax を適用して全語彙の確率分布を出し、次の1トークンをサンプリングします。
2. AIエージェントを利用した開発
開発支援ツールが単なる「コード補完(Autocomplete)」から「目的達成のための自律実行(Agent)」へ変化した技術背景と設計パターンです。(Agentic Workflow)
Tool Calling (Function Calling) のメカニズム
エージェントがTerminal操作、ファイル検索、Git操作などを行えるのは、LLMが「ツールを呼ぶための構造化データ(JSON)」を出力する機能を持っているからです。
[User] ────> [Agent / Runner] ────(1. プロンプト + ツール定義JSON)────> [LLM]
│ │
│ <────(2. "read_file" 関数を引数付きで呼べという指示)─────┘
│
├────> [ファイルシステム実行 (read_file)]
│
[User] <──── [Agent / Runner] ────(3. 実行結果を含めて再度送信)────────> [LLM]
LLMに渡すツール定義(JSON Schema例)
{
"name": "execute_command",
"description": "TerminalでShellコマンドを実行する",
"parameters": {
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "実行するbashコマンド (例: npm test)"
}
},
"required": ["command"]
}
}
MCP (Model Context Protocol) の標準化アーキテクチャ
Anthropicがオープンソースとして提唱した MCP (Model Context Protocol) は、LLMアプリケーション(Host/Client)と外部データソース・ツール(Server)を結ぶ共通プロトコル(JSON-RPC 2.0ベース)です。
従来はツールやサービス(GitHub, Jira, DB, Notion)ごとに個別実装(Custom Integration)が必要でしたが、MCPによりクライアントとサーバーが疎結合に分離されました。
┌────────────────────────────────────────────────────────┐
│ Host App (Cursor, Claude Desktop, Roo Code, Custom) │
│ └─ MCP Client │
└───────────────────────────┬────────────────────────────┘
│ JSON-RPC (stdio / SSE)
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ MCP Server │ │ MCP Server │ │ MCP Server │
│ (GitHub) │ │ (PostgreSQL) │ │ (Sentry) │
└──────────────┘ └──────────────┘ └──────────────┘
MCPの3つのコア要素
- Resources: ファイル、DBレコード、ログ等の「参照専用データ」を提供
- Prompts: サーバー側で定義された再利用可能なプロンプトテンプレート
- Tools: 外部作用(書き込み、API呼出し、コマンド実行)を伴う実行可能な関数
Agentic Design Patterns & ループ構造
エージェントは1回の生成で完結せず、ReActパターン (Reasoning + Acting) などの自律ループを回します。
// エージェントループの概念実装(TypeScript例)
async function runAgentLoop(userGoal: string, tools: Tool[]) {
const messages: Message[] = [{ role: 'user', content: userGoal }];
while (true) {
// 1. LLMに現在の文脈と利用可能なツール群を渡して推論
const response = await llm.generate({ messages, tools });
// 2. 終了条件判定(LLMが最終回答を出した場合)
if (response.stopReason === 'end_turn') {
return response.text;
}
// 3. ツール呼出し(Function Calling)の指示があった場合
if (response.stopReason === 'tool_use') {
for (const toolCall of response.toolCalls) {
// ツールの安全実行(Approval / Sandboxing)
const toolResult = await executeToolSafely(toolCall);
// 実行結果を会話履歴にフィードバック
messages.push({
role: 'tool_result',
toolCallId: toolCall.id,
content: toolResult
});
}
}
}
}
主要な設計パターン
- Reflection(自己修復・批評): 生成したコードをリンターやテスト(
npm test)に通し、エラー結果を再度LLMに読み込ませて自動修正させる - Multi-Agent Collaboration: 役割分離(例: Architect Agent, Coder Agent, Reviewer Agent)を施し、エージェント同士に相互レビューループを行わせる
- Human-in-the-Loop (HITL): 破壊的な変更(DBマイグレーション、外部API実行、
git push等)の前に人間の明示的な承認ステップを挟むインターセプター構造
3. AIをシステムに導入する
自社プロダクトやエンタープライズシステムにLLM/Agent機能を組み込む際の、本番耐えうる技術構成です。(本番運用のアーキテクチャと実践)
高度なRAG(Advanced RAG)の比較とパイプライン設計
単純な「ベクトル化 + 類似度検索(Naive RAG)」では、社内表記ゆれや複雑なビジネスロジックに対応できません。本番構築で採用される先進パターンを比較します。
| RAGパターン | 概要・アプローチ | メリット | デメリット・課題 |
|---|---|---|---|
| Naive RAG | 文書を固定長分割(Chunking)し、Vector DBでCosine類似度検索 | 構成が非常にシンプルで高速 | キーワード完全一致や構造化データに弱い |
| Hybrid Search + Rerank | Vector検索 + BM25(全文検索)を統合し、Cross-Encoderで再スコアリング | 型番・固有名詞の検索漏れを防ぎ精度大幅向上 | 検索レイテンシが若干増大(Reranker計算コスト) |
| Parent-Document RAG | 小さなチャンクで検索を行い、LLMに渡す際は親文書(大きな文脈)を渡す | 検索精度と文脈保持の両立 | DB側のインデックス設計が複雑化 |
| GraphRAG | ナレッジグラフ(Entity-Relation)を構築し、コミュニティ検出と組み合わせて検索 | 組織横断の全体像把握や概念関係の回答に非常に強い | グラフ構築コスト(LLM呼び出しコスト)が高い |
Advanced RAG パイプライン構成図
[User Query]
│
▼
[Query Transformation] ─── (HyDE: 仮説回答生成 / Multi-Query 展開)
│
▼
[Hybrid Search] ────────── (Dense: Vector Search + Sparse: BM25/FTS)
│ └─ RRF (Reciprocal Rank Fusion) でスコア統合
▼
[Reranking] ────────────── (Cohere Rerank / Cross-Encoder による再計算)
│
▼
[Context Compression] ──── (不要な文脈の削減、トークン節約)
│
▼
[LLM Generation]
セキュリティ多重防御
LLMを組み込んだシステムでは、従来のSQLインジェクション等とは異なる新しい攻撃面(Attack Surface)に対応する必要があります。
- Prompt Injection / Jailbreak 対策:
- System/User プロンプトの分離: 入力プロンプトの厳密な区切り(XMLタグ
<user_input>等の活用) - 前処理フィルター: 入力層に検知モデル(Llama Guard や NeMo Guardrails など)を挟み、不適切なプロンプトや命令上書き(System Prompt Override)を検知・遮断
- System/User プロンプトの分離: 入力プロンプトの厳密な区切り(XMLタグ
- Output Validation & Structured Output:
- LLMの出力形式を保証するために Pydantic, Zod, TypeChat を用いたスキーマバリデーションを実施
- パース失敗時はエラーログとともにリトライループを実行
-
データプライバシー・オプトアウト:
- Enterprise API(Azure OpenAI, AWS Bedrock, Anthropic API 等)を利用し、入力データがモデル学習に再利用されない規約・構成を担保
LLMOps(可視化・評価・コスト管理)
LLMアプリは出力が非決定論的であるため、従来型監視(Datadog等)に加え、LLMOpsプラットフォーム(LangSmith, Phoenix, Langfuse等)が必要です。
[Client] ───> [API Gateway] ───> [LLM Application]
│
├── (Trace / Latency / Token) ──> [LLMOps (LangSmith/Langfuse)]
│
└── (Async Evaluation) ─────────> [LLM-as-a-Judge (GPT-4o)]
コスト・レイテンシ最適化プラクティス
- Prompt Caching: Claude API 等のプロンプトキャッシュ機能を活用。固定のシステムプロンプトやRAGのコンテキスト部分の読み込みコストを最大80%削減、レイテンシを大幅低減
- Model Routing: 軽い処理(分類や要約)は小型モデル(Claude Haiku, GPT-4o-mini)、高度な推論・コード生成はフラグシップモデル(Claude Sonnet, O3)へ動的にルーティング
- Speculative Decoding: 小さいモデルで高速にトークンを事前生成し、大きいモデルで検証・一括採択することで生成速度を向上
LLM-as-a-Judge による評価指標(Ragasフレームワーク等)
- Faithfulness(誠実性): 生成された回答が、渡されたコンテキストに基づいているか(Hallucinationの検知)
- Answer Relevance(回答関連性): ユーザーの質問に対して的確に答えているか
- Context Precision / Recall(文脈の精度/再現率): RAGで引き当てた検索結果が適切か
おわりに
プログラミングの単なる手作業部分はAIエージェントに委ねる時代が来ていますが、全体構造の設計・セキュリティの担保・ビジネス要件を正確な制約条件へ落とし込むエンジニアリングの価値はこれまで以上に高まっていると思います。
今回のまとめてみて、下記の3つのポイントからチームでのAI開発を考えてみたいと思います。
- 開発プロセスの再設計として、「AIにコードを書かせる」だけでなく、AIが動作しやすいようにリポジトリを構造化(
README.md,ARCHITECTURE.md, 型定義の厳密化)し、MCP等のインターフェースを整える - 安全性の担保として、RAGパイプライン、Guardrails、コスト(トークン数/キャッシュ)、レイテンシ(SSEストリーミング)のトレードオフを具体的な数値を出して設計する
- 品質管理の変革として、従来通りのテスト(Unit/Integration Test)と、LLMアプリケーションの評価(LLM-as-a-Judge / CIラインでの精度監視)を組み合わせたハイブリッドな評価体制を構築する
参考(感謝)