実用的なAIエージェントを構築する: 実践用語集
AIエージェントの実際の機能、チャットボットとの違い、および機能するエージェントを構築するために必要なコンポーネントについてです。
AIエージェントは、目標を受け取り、一連のアクションを決定し、目標が達成されるか諦めるまでツールを使用してそれらのアクションを実行するプログラムです。これはメッセージに応答するだけのチャットボットとは異なります。エージェントは計画し、関数を呼び出し、結果をチェックし、調整します。ブラウザを通じてChatGPTを使用したことがあるだけなら、最初のエージェントを構築することで、モデルがテキストジェネレータであることをやめ、より大きなシステムのコンポーネントになります。
コアループ
どのようにマーケティングされていても、すべてのエージェントは同じループの何らかのバージョンを実行します: 観察、思考、行動、繰り返し。具体的には:
- エージェントはタスク(「来月リスボンへの最安フライトを見つけてメール要約を作成する」)を受け取ります。
- 利用可能なツールの説明とともにタスクをLLMに渡します。
- モデルは最終的な回答またはツール呼び出し(例:
search_flights(destination="Lisbon", month="2025-06"))を返します。 - コードはその関数を実行し、実際の結果を取得し、モデルのコンテキストに戻します。
- モデルは次に何をするかを決定します: 別のツールを呼び出す、説明を求める、または終了する。
このパターンはReActループ(推論と行動)と呼ばれることが多く、LangChainのエージェント実行器、LlamaIndexエージェント、OpenAIの関数呼び出しAPIなどのフレームワークの骨組みです。LLM APIとwhileループだけを使用してPythonで100行以下でこれ全体を実装できます。フレームワークは利便性を追加するだけで、魔法ではありません。
ツールがエージェントにする要素
ツールがないモデルは話すだけです。関数を与えると、行動できるようになります。ツールは通常、名前、パラメータ、目的を説明するスキーマでラップされたプレーンなPython関数です。そのため、モデルはいつ、どのように呼び出すかを知っています。例:
def get_weather(city: str) -> str:
"""Return current weather for a given city."""
resp = requests.get(f"https://api.weather.example/v1/{city}")
return resp.json()["summary"]
OpenAIの関数呼び出しを使用すると、この関数と一緒にJSONスキーマを渡し、モデルはフリーフォームテキストの代わりに{"name": "get_weather", "arguments": {"city": "Lisbon"}}のような構造化呼び出しを出力します。コードはそれを解析し、実際の関数を実行し、結果を会話の新しいメッセージとして返します。モデルが回答するのに十分な情報を得るまで繰り返します。
メモリと状態
1回のAPI呼び出しはコンテキストウィンドウ以上のメモリを持ちません。エージェントには明示的な状態が必要です: メッセージの実行リスト(会話履歴)、および長期的な事実の別のストアが必要な場合があります。短いタスクの場合、会話を表すPythonリストの辞書で十分です。セッション間で物事を覚えておく必要があるエージェントの場合、ベクトルデータベース(Chroma、Pinecone、Qdrant)を使用して埋め込みを通じて関連する過去の情報を保存および取得します。
早い段階でこれを過度に設計しないでください。「エージェント」プロジェクトの意外と多くが失敗する理由は、LLMが弱いからではなく、状態管理がずさんだからです: 重複したメッセージ、無制限のコンテキスト増加、またはどのツール呼び出しがどの結果に属するかを追跡できません。
最小限の動作例
ここでは、フレームワークなしでOpenAI APIを使用したベアボーンエージェントの形状です:
messages = [{"role": "user", "content": "What's the weather in Lisbon?"}]
while True:
response = client.chat.completions.create(
model="gpt-4o",
messages=messages,
tools=[weather_tool_schema],
)
msg = response.choices[0].message
if msg.tool_calls:
for call in msg.tool_calls:
result = get_weather(**json.loads(call.function.arguments))
messages.append(msg)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": result,
})
else:
print(msg.content)
break
これは実在の機能するエージェントです。その他すべて(計画戦略、マルチエージェント調整、検索パイプライン)はこのループの上に構築されます。
失敗する場所
エージェントは予測可能な方法で失敗します: モデルが成功を判断できない場合の無限ツール呼び出しループ、ハルシネーション関数引数、および高価なツールの再呼び出しによる暴走コスト。ハード反復キャップ(例: 10ステップ)でループをガードし、開発中にすべてのツール呼び出しをログに記録します。実際のシステムに触れるものを実行する前に引数を検証します。メール送信やシェルコマンド実行ができるエージェントには、ユーザー向けコードに適用するのと同じ入力サニタイゼーションが必要です。LLMは実質的に、その入力を生成する信頼できないユーザーだからです。
次のステップ
ループが機能したら、興味深い問題が始まります: シングルエージェントとマルチエージェント設計の選択、付与する自律性の決定、出力が決定的でない場合のエージェントの確実なテストです。Korra Studioのショップの関数呼び出しパターンの深さについてカバーしています。検索拡張生成、プロンプト設計、ツール呼び出しパターンについてさらに詳しく知りたい場合は、ここから構築を続けることができます。
この記事は AI の支援を受けて執筆し、Korra Studio の Michal Pilch(CISSP)が確認のうえ公開しました。
これは Korra Studio ナレッジベースの 1 つのノートです。プラットフォームはすべてのトピックと 1 対 1 メンタリングをペアで提供します。
無料で始めるarrow_forward