AIエージェントの実装:教科書がない、断片を統合し、最小実装で学ぶ。なんだ、みんなタフマンだ
そもそも:なぜ、AIエージェントの「教科書」はどこにもないのか
「AIエージェントを作りたいが、何から学べばいいのかわからない」 「ReActやRAG、Toolformerといった単語は聞くが、全体像が見えない」
今、我々驚き屋noter や、多くのエンジニアがこの壁に直面しています。思考するだけのLLMと、実際にタスクをこなすAIエージェントのあいだには明確な技術的ギャップがありますが、それを埋めるための「体系的な一冊」は、世界中を探してもまだ存在しません。
技術書やドキュメントが充実しているWeb開発などの分野とは異なり、なぜエージェント技術には「公式の教科書」が存在しないのでしょうか。理由は主に5つあります。
1. 技術そのものが「寄せ木細工」の歴史だから
エージェントという仕組みは、ひとつの計画された研究分野から生まれたものではありません。
ReAct (推論と行動のループ)
Toolformer (ツール利用)
Function Calling (構造化されたAPI呼び出し)
RAG (外部記憶)
Self-Refine (自己修正)
これらはすべて、別々の研究者や企業から断片的に発表された技術です。
それらを後からパズルのように組み合わせ、無理やり統合して「エージェント的に振る舞う」仕組みが形成されました。
部品は豊富でも、最初から全体を説明する設計図が存在しないのはそのためです。
2. 商用ベンダーにとっての「秘伝のタレ」だから
OpenAI、Anthropic、Googleなどは、エージェントを最終製品として提供したいと考えています。そのため、Function Callingの仕様やAPIの形は公開しても、その裏側にある「ループ制御」「計画アルゴリズム」「ツール選択のロジック」といった心臓部分は公開したがりません。こここそが、各社の競争力の源泉だからです。
3. 研究と実装のコミュニティが乖離している
アカデミアは「ReActのような思考プロセス」などの論文を発表しますが、実運用に必要な泥臭い要素(JSONバリデーション、失敗時のリトライ戦略、権限管理、無限ループ防止など)は論文になりにくいため、扱われません。
結果として、理論と現場の実装ノウハウをつなぐ資料が空白地帯になっています。
4. 進化速度が「執筆」を追い越している
2023年にFunction Callingが登場し、2024年にReActが普及し、2025年にはメモリ付きエージェントやOSレベル統合が当たり前になる――。このスピードでは、体系書を書き終える頃には用語が入れ替わってしまいます。
5. 各社で「方言」が強すぎる
「エージェント」という言葉は共通でも、OpenAIはFunction Calling中心、Anthropicは自然言語による計画重視、DeepSeekは自己修正ループ重視など、中身の実装思想はバラバラです。統一された説明が困難な状況にあります。
このように、エージェント技術は「複数の断片的技術の寄せ集めの進化形」であり、その統合方法はあえて公開されてきませんでした。
しかし、このギャップは未知の魔法ではありません。断片化された技術要素を整理し、エンジニアの視点で再統合すれば、我々驚き屋noter でもその仕組みを理解し、実装することができます。
それでは、あえてこの「寄せ集めの断片」を整理して一本化し、読み終えたあとに「最小構成のエージェント(Minimum Viable Agent)」を自分で実装できる一歩手前までメモを取ってみましょう。
うまくやれば、エンジニアたちは、泥をしっかりと纏ったあなたのような驚き屋を仲間と誤認し、年収2,000万円の壁を越え、3,000万円以上も夢ではない青天井の世界に、あなたを誘い入れてくれるかもしれませんよ。

現代AIエージェント 実装技術の全体像整理
まず、エージェントを技術的な部品に分解して眺めてみます。細かいフレームワーク名より前に、「何が最低限そろえばエージェントになるのか」を押さえるほうが、実装の筋道が見えやすいです。
現在「エージェント」と呼ばれているものは、おおまかに以下の4つの要素で成り立っています。
Brain (推論エンジンとしてのLLM)
Why(なぜ必要か): 従来プログラムでは記述不可能な「非決定的な判断」や「曖昧な指示の解釈」を行うためです。CPUが計算を担当するように、Brainは「意味の理解と決定」を担当します。
How(どう使うか): プロンプトエンジニアリングにより、単なるテキスト生成ではなく、次のアクションを決定する「意思決定器」として振る舞わせます。
Tools (決定論的な実行環境)
Why: LLMは確率的に単語を繋ぐだけであり、正確な計算やリアルタイムな情報の取得、外部システムへの副作用(書き込み)を起こす能力がないためです。
How: APIや関数として定義し、LLMが生成した引数を受け取って実行する「確実な処理」として実装されます。
Memory (状態管理とコンテキスト)
Why: LLM自体はステートレス(状態を持たない)な関数であり、リクエストごとに記憶がリセットされるためです。文脈を維持するには外部ストレージが必須です。
How: 会話履歴を保持する「短期メモリ」と、Vector DB等を用いて検索する「長期メモリ(RAG)」を組み合わせ、プロンプトに動的にコンテキストを注入します。
Control Loop (再帰的処理フロー)
Why: 複雑なタスクは1回の推論(ワンショット)では解決できません。試行錯誤や多段階の推論を行うには、出力を次の入力に繋ぐループ構造が必要です。
How: PythonやTypeScriptのスクリプトとして記述され、LLMの出力(思考・行動)を解析し、ツールの実行結果を再びLLMにフィードバックするサイクルを回します。
この4要素による分解は、近年のLLMエージェントに関するサーベイ論文でも共通して採用されているスタンダードな見方といえるでしょう。
その他のシステムと異なり、意識を変革しないといけない点として、これら4つが「自然言語」を共通インターフェースとして結びついている特徴的なアーキテクチャがありますので、それをポストイットに描いてPCモニターに貼っておいて下さい。
Brainはテキストで思考し、ToolsはJSONスキーマを通じて呼び出され、MemoryはテキストとEmbedding(ベクトル)の両方で管理されます。そしてControl Loopが、PythonやTypeScriptのコードとしてこれらを接着剤のように繋いでいます。
どの最新フレームワークを選んだとしても、結局は「この4つをどう効率的に組み合わせるか」というアーキテクチャ論に帰着します。
1. LLM本体APIとモデル選定のスタートライン
どんなエージェントも、中心となるLLM(Brain)がなければ始まりません。実装の第一歩は「どのAPIで、どのモデルを呼ぶか」を決めることです。
2025年現在の主流は、OpenAIの Responses API や、各クラウドベンダーが提供する同等の統合APIを利用するものです。
従来の「Chat Completion(単なる会話)」と「Assistants API(自律動作)」の良いとこ取りをしたようなインターフェースで、テキスト生成とツール呼び出しがシームレスに統合されています。
具体的なコードとしては、まずクライアントを初期化し、モデルと入力テキストを指定してレスポンスを受け取るところから始めます。以下は公式Pythonライブラリを用いた最小構成の例です。
from openai import OpenAI
client = OpenAI()
# エージェントの「脳」を呼び出す最小単位
response = client.responses.create(
model="gpt-安いやつ",
input="こんにちは。あなたはタスク実行エージェントの頭脳です。",
)
print(response.output_text)複雑なエージェントを作る際も、最初の一歩はこのレベルです。まずは「LLM単体でエラーなく安定して動く」状態を作り、そこからJSON形式の構造化出力(Structured Outputs)や、後述するツール呼び出しへと、少しずつ機能を足していくのが定石です。
2. ReActパターン:推論と行動の循環プロンプト
「ただ質問に答えるLLM」と「行動できるエージェント」を分けている最大要因は、推論(Reasoning)と行動(Acting)をどう結びつけるかというロジックでしょう。ここでデファクトスタンダードとして使われているのが、かの有名なReActパターンです。
ReActは、モデルに以下の3つのフェーズをループさせる枠組みです。
Why(なぜ必要か): LLMは内部知識だけで回答しようとすると、事実と異なるもっともらしい嘘(ハルシネーション)をつく傾向があります。行動の前に「思考」を挟むことで論理的な整合性を高め、行動の結果を「観察」することで事実に基づいた軌道修正が可能になります。
How(どう機能するか): プロンプト内で「思考(Thought) → 行動(Action) → 観察(Observation)」という厳格なフォーマットを強制します。
Thought: タスクを分解し、次の方針を言語化する。
Action: 具体的なツール名と引数を生成する。
Observation: (システム側が) ツールを実行し、その生データをプロンプトに追記する。 このサイクルを繰り返すことで、ブラックボックスになりがちな推論プロセスを可視化(Traceable)し、デバッグ可能な状態にします。
たとえば、「東京の天気を調べて」と言われた場合、いきなり「晴れです」と答えるのではなく、まずThoughtで「東京の天気を知るには天気APIが必要だ」と考え、ActionでAPIを叩き、Observationで「APIの結果はRainだった」と認識し、再びThoughtで「では雨だと回答しよう」と考える。この泥臭い過程こそがエージェントの正体です(出典:Yaoら 2022)。
実装のイメージとしては、システムプロンプトに以下のような指示(Instruction)を組み込みます。
あなたはツールを使いながら問題を解決するアシスタントです。
思考プロセスを開示するため、次のフォーマットで出力してください。
Thought: 今考えていること、次の一手
Action: ツール名["引数"] の形式でツールを呼び出す
Observation: ツールの実行結果(ここにはツールの出力を挿入する)あとはControl Loop(プログラム側)で、LLMが Action: Search[...] のような文字列を出力したのを検知し、実際に検索APIを叩いて、その結果を Observation としてプロンプト末尾に追加し、再度LLMに投げ返すわけです。
3. Function Calling:ツール実装の具体ステップ
LLMがいかに賢く思考できても、実際にメールを送ったりデータベースを更新したりするには、外部プログラムへの接続が必要です。Function Calling (Tool Use) の出番です。
Why(なぜ必要か): プログラミングにおける関数実行は厳密な型と構造(JSON等)を要求しますが、LLMの出力は曖昧な自然言語です。この「非構造化データ(自然言語)」と「構造化データ(API)」のインピーダンスミスマッチ(不整合)を解消するために開発されました。
How(どう機能するか): LLMは学習段階で「JSONスキーマに従った出力を生成する」ようにファインチューニングされています。 開発者は関数の定義(名前、引数、型、説明)をJSONスキーマとしてAPIに渡します。LLMはこれを読み取り、文脈に合致する場合のみ、通常のテキストではなく、指定されたスキーマに準拠したJSONオブジェクトを生成します。これにより、正規表現等による不安定なパース処理を排除し、プログラムから安全に呼び出し可能なデータを得ることができます。
最新のAPIでは、プロンプトで「こう書いて」と指示する代わりに、tools パラメータとして利用可能な関数のリスト(JSONスキーマ)を渡す手法が一般的です。モデルはこのスキーマを読み解き、「どのツールを、どんな引数で呼ぶべきか」を判断します(出典:OpenAI Toolsガイド 2025)。
イメージしやすい例として、「天気取得ツール」を一つだけ持ったエージェントのコードを見てみましょう。
from openai import OpenAI
import json
client = OpenAI()
# ツールの定義(LLMに「こういう道具があるよ」と教える)
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "都市名から現在の天気を取得する",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}
]
# ユーザーの問いかけとツール定義を渡す
response = client.responses.create(
model="gpt-安いやつ",
input="東京の今の天気を教えて",
tools=tools,
)
# LLMが「ツールを使いたい」と言ってきたか確認
print(response)このコードを実行すると、LLMは「東京の天気ですね。では get_weather を引数 city="Tokyo" で実行してください」という旨の構造化データを返します。
我々驚き屋noter や、開発者の仕事は、このレスポンスを受け取り、実際にPythonの get_weather 関数を実行し、その結果(例: "晴れ, 25度")を再度APIに渡して、「結果はこうでした。ユーザーに回答して」と依頼することです。
4. メモリとRAG:コンテキスト管理と知識統合
エージェントが一問一答のチャットボットを超えて、継続的なタスクをこなすためには「記憶(Memory)」が不可欠です。
短期メモリ (Short-term Memory):
現在進行中の会話やタスクの履歴です。Responses APIなどが持つ conversation_id や thread の機能を使えば、前回までの文脈(Context)を維持したまま次の推論を行えます。ここが欠落すると、エージェントは毎回「初めまして」の状態に戻ってしまいます。長期メモリ (Long-term Memory) / RAG:
コンテキストウィンドウに入りきらない膨大なマニュアルや、過去のプロジェクト履歴などを扱う部分です。一般的には、テキストをEmbedding(ベクトル化)してVector DB(Chroma, Pineconeなど)に保存し、必要なときだけ検索してプロンプトに差し込む RAG の構成を取ります。
最近では file_search のようなAPI組み込みツールもあり、自前でデータベースを構築せずとも、ファイルをアップロードするだけで検索可能な状態を作れるようになっています。
5. LangChainやLangGraph等 オーケストレーションライブラリの活用
ここまでの要素(LLM, Tools, Memory, Loop)はすべて素のPythonで記述可能ですが、エラー処理や分岐が増えるとコードが複雑化します。そこで役立つのがオーケストレーションライブラリです。
LangChain / LangGraph:
LLMアプリ開発のデファクトスタンダード。特にLangGraphは、エージェントの挙動を「グラフ(状態遷移図)」として定義でき、複雑なループや条件分岐を可視化・管理しやすく設計されています。LlamaIndex:
RAGを絡めたエージェントや、大量のドキュメントを参照しながら動くエージェントを作る場合に強力です。AutoGen (Microsoft):
「マルチエージェント」に特化したフレームワーク。複数のエージェント同士を会話させてタスクを解決させたい場合に適しています。
アドバイスとしては、「最初はライブラリを使わずに書いてみる」ことを強くおすすめします。素のAPI呼び出しでReActループを一度でも書いておけば、ライブラリが裏側で何をしているかが手に取るように分かり、ブラックボックス化を防げるからです。

6. 実運用で「死なない」エージェントを作るインフラ設計
個人PCで動くデモと、本番環境で動くエージェントは全く違います。我々驚き屋noter は前者で満足してしまいがちですが、実際に対価が払われるのは後者です。
そこの駆け出しプログラマーのあなた、AIバブルに乗っかったPoC攻勢が永遠に続くと誤解して、前者でも稼ぐことができるんだぞ、と死亡フラグを立てるのはお勧めできません。
SES派遣業界のオジサンたちは、そういう実装力ゼロ枠が定期的に大量死するのを手ぐすねを引いて待っています。ドナドナされていく荷馬車からの叫び声は世の中には出回りません。
我々驚き屋noter は、その都度、大袈裟に驚いて「世界が変わった!」と言うだけなので気楽なものです。
そして、ベンダーからゆるふわな提案と接待を受けている、そこのあなた。この観点からの質問に答えられないベンダーは、実はベンダーを装った芸人です。あなたの上司が、ショートコントにおひねりを投げる趣味をお持ちかお伺いを立ててから、購入の稟議書を書くことをお勧めします。
閑話休題
本番環境に耐えるAI Agentとは、すなわち「失敗への耐性」と「可観測性」です。実運用では、モデルの賢さ以前に、インフラ起因のエラーでエージェントが停止してしまうケースが頻発します。
インフラ起因の失敗と「429エラー」の壁
検証環境では快調だったスクリプトが、本番リリース直後に停止する最大の要因は、レート制限(Rate Limits)です。
LLM APIには「1分あたりのトークン数 (TPM)」や「リクエスト数 (RPM)」の上限があり、これを超えると 429 Too Many Requests エラーが返されます。また、ネットワーク越しである以上、DNS解決失敗やタイムアウトといった5xx系エラーも避けられません。単純な同期処理(1回のリクエストで全て終わらせる実装)では、こうした一時的なエラーひとつでタスク全体が失敗とみなされてしまいます(出典:OpenAI Cookbook Rate Limits 2025)。
信頼性の3本柱:リトライ、キュー、状態管理
こうした「不安定な足場」の上で安定して動くために、アプリケーション側で追加の工事が必要になります。これらは伝統芸能ですので、比較的ナレッジ自体は流通していますが、具体的に何がOpenAIのAPIに最適かは口伝でしか伝わっていないのが現状です。
指数バックオフ付きリトライ:
エラー時に即座にリトライするのではなく、1秒、2秒、4秒…と待機時間を指数関数的に伸ばしながら再試行するアルゴリズムです。OpenAI Cookbookでも推奨されている標準的な実装です。
具体的には、コードのあちこちに try-catch を書くのではなく、LLM呼び出し用の小さなラッパー関数を作り、そこに tenacity 等を使った指数バックオフ(Exponential Backoff)を閉じ込めてください。非同期キュー(Job Queue):
Why: LLMの推論は数秒〜数十秒かかるロングランプロセスであり、HTTPリクエストのタイムアウト制限(通常30-60秒)を超えやすいためです。
How: ユーザーからのリクエストを即座に受け付け(202 Accepted)、処理の実体をバックグラウンドワーカーに委譲することで、フロントエンドのブロッキングを防ぎます。
WebサーバーのHTTPリクエスト内で、エージェントのループを完結させようとしないでください。タイムアウトで死ぬのがオチです。
リクエストを受け取ったら、即座に「ジョブID」だけをユーザーに返し、処理自体は Redis (BullMQ) などのキューに積んでください。裏側のワーカー(Worker)がキューからジョブを取り出し、自分のペースでAPIを呼び出す非同期アーキテクチャが、スパイクアクセスからシステムを守る定番のお作法です。
状態の永続化(State Persistence):
Why: プロセスがクラッシュした場合やデプロイによる再起動時、メモリ上の変数は消失します。長時間稼働するエージェントにおいて、最初からやり直しになるコストを避けるためです。
How: 各ステップ(思考・行動)が完了するたびに、会話履歴や変数のスナップショットを外部DB(Postgres等)にシリアライズして保存します。これにより、障害発生時も直前のチェックポイントからステートフルに復帰(Resume)可能にします。
エージェントの会話履歴や現在のステップ(思考の途中経過)を、メモリではなくデータベースに保存します。こうすることで、プロセスが再起動しても、あるいはAPIエラーで中断しても、続きから処理を再開(Resume)できるようになります。LangGraphなどは、この永続化を前提としたアーキテクチャを採用しています。
ただし、すべてを保存する必要はありません。「会話履歴」「直前のツール実行結果」「現在のステップ番号」。この3つさえあれば、プロセスが落ちても途中から再開(Resume)できます。「入力と出力とステップ番号さえあれば戦える」と割り切り、DBに書き込むデータを絞るのがパフォーマンス問題も考えたなら現実解でしょう。
え?四つ目?権限管理とHuman-in-the-loop:
エージェントに「削除」や「購入」といった不可逆な操作(書き込み系ツール)を許可する場合は、必ず人間の承認(Human-in-the-loop)を挟むように設計します。
ツールを「読み取り専用(Safe)」と「書き込み(Unsafe)」に分類し、Unsafeなツールを呼ぼうとした時だけループを一時停止し、人間に確認を求める。この最低限の防御線があるだけで、ガバナンス要件をクリアしやすくなりますし、Dドライブ全削除を避けられたのです。
これらは、公開情報が少なく、実装ノウハウは現場で手渡しされることが多いエリアです。
“暗黙知”として散らばるというよりも、分かっている人にとっては常識過ぎて明文化されないものも多く、我々驚き屋noter には見えにくいのが辛いところです。
可観測性とトレーシング:Langfuse等の活用
LLMエージェントは「同じ入力でも出力が変わる」非決定的なシステムです。そのため、「なぜか失敗した」ときの調査が非常に困難です。
ログファイルを目視する代わりに、Langfuse のようなLLM専用のトレーシングツールを導入、これは憲法26条で認められた権利です。これでやっと、「どのプロンプトで、どのツールを呼び出し、何秒かかって、いくらかかったか」という基本的人権をようやく1つのトレースとして可視化できます。
逆にこれがない場合、本番運用のデバッグは「当て推量」になってしまいます(出典:Langfuse Observability & Tracing 2025)。
推論基盤の選択:APIからNVIDIA NIMまで
コストやセキュリティ要件が厳しくなると、API利用から自社環境での推論へ移行するケースも選択肢に入ってきます。
例えば、NVIDIA NIM のようなマイクロサービス型の推論基盤を利用すると、OpenAI互換のAPIを維持したまま、AWSや自社データセンターのGPU上で高速にモデルを動かせます。Kubernetes (EKS) 上でオートスケーリングさせる構成も一般的になっており、アプリケーションコードを変えずにバックエンドだけを差し替えることが可能です。

実践にあたり:さて、段取りをしてみようか
最後に、多くの現場で「勝ちパターン」として採用されているスタックを並べてみます。
2025年12月現在、世界中の現場エンジニアが、血反吐を吐きながら辿り着いた「これしかない」という結論であり、来年には恐らく役立たずになっている悲しい知識でもあります。
Phase 1: ロジック構築(手書きで動かす)
インフラを組む前に、まずは「脳と手足」の挙動をPythonスクリプト単体で掌握します。とにかくブラックボックスを排除し、仕組みを肌で理解することが重要です。怠けるな、頭を使え、頭を。
Environment (Hello World):
OpenAI公式ライブラリ (openai-python) を入れ、client.responses.create でテキストが返ってくることを確認します。Simple Tool (Function Calling):
「計算する」といった単純な関数を定義し、LLMに自発的にツールを呼ばせます。Manual Loop (ReAct体験):
ここが個人的に最大のポイントです。ライブラリを使わず、while 文と正規表現だけでReActループを書いてみてください。
たった150行程度のコードですが、この車輪の再発明が「裏側で何が起きているか」を理解する唯一の方法です。黒魔術のようなフレームワークに頼る前に、生のAPIと正規表現で動く感覚を2時間かけて掴む。その経験が、後のトラブルシューティングで絶対に活きてきます。
Phase 2: インフラ強化(死なない仕組みへ)
ロジックが動いたら、それを「実運用に耐えるシステム」へと昇華させます。ここがホビーとお仕事の分水嶺です。
Orchestration (LangGraph):
手書きのループをLangGraphに移行し、状態(State)をグラフとして定義します。複雑な分岐やループを可視化し、制御します。Queue & Persistence (非同期と永続化):
HTTPリクエストを直接LLMに繋ぐのをやめ、Redis (BullMQ) でキューイングし、Postgres で状態を永続化(Checkpointing)します。
「プロセスの再起動に耐えられるか」が2025年の本番環境の基本的人権です。メモリ上の変数に頼るのをやめ、Postgresへのチェックポイント保存を実装してください。これでエージェントは再起動しても死ななくなります。Observability (Langfuse):
Langfuse を導入し、実行トレースを記録します。トレーシングツールのない運用は、目隠しでデバッグするのと同じです。導入した瞬間に無限ループのバグが見つかることも珍しくありません。「推測」ではなく「計測」でエージェントを制御しましょう。Production Ready (堅牢化):
tenacity ライブラリなどで指数バックオフリトライを仕込みます。ブラックフライデー級のトラフィックを捌き切るには、この「粘り強さ」の実装が不可欠です。
教科書がないなら、自分で作ればいい。さあ、手を叩いて「LangGraph + OpenAI + Redis + Postgres + Langfuse」。
この魔法のない、しかし堅実なプリミティブの組み合わせが、残念ながら現時点では最も信頼できる「教科書」の代わりで、来月には違う組み合わせが出てくることでしょう。
ここまで読み進めた方はお気づきでしょうが、AIエージェント開発とは、上昇商材屋から仕入れた怪しいプロンプトを唱えることではなく、「確率的に振る舞う不安定なコンポーネント(LLM)を、いかに堅牢なシステムアーキテクチャの中に封じ込めるか」という設計論に尽きます。
え?ぼくのかんがえたさいきょうの構成が他にあるって?ならそれはそれで。でも、サ終の可能性の低いやつを選ぶ視点は持っていますか?驚き屋をやっていると忘れがちですが、継続的に更新され、利用者が多い技術を選ぶのが社会人の常識です。
驚き屋noter 同輩の皆さん、このスタックの賞味期限が切れる前に、ぜひ今日から、あなただけの「実用的な最小エージェント」の実装を始めてみてください。

