AI: AI エージェント
最終更新:2026-08-26
1. 学べること
| No. | 内容 |
|---|---|
| ❶ | エージェントと通常のチャットボットの違い |
| ❷ | ReAct モード(推論 + 行動) |
| ❸ | 関数呼び出し(Function Calling) |
| ❹ | エージェントの計画とメモリ |
| ❺ | Python で簡単なエージェントを実装する |
2. ストーリー
Bob は AI に「Apple の最新株価を調べて、投資する価値があるか分析して」と頼みたかった。標準の ChatGPT は「インターネットに接続できません。私の学習データのカットオフ時点では…」とだけ答え、情報は古くまったく役に立ちません。
Alice はエージェントフレームワークを使って AI エージェントを作りました。同じ質問をされると、エージェントは自ら決定します。
- 検索ツールを開く → AAPL の現在株価が $195.27、PER が 31.2 であると判明
- 計算ツールを開く → 想定年率リターンを約 6.8% と計算
- 以上の結果に基づき → 投資提言を生成
Bob は叫びました。「これって要するに AI が自分で考えて働いてるんじゃないか!」
重要な違い:チャットボットは「話す」だけだが、エージェントは「行動する」。
3. AI エージェントとは?
(1) エージェントの定義
AI エージェント = LLM + ツール + メモリ + 計画
| 構成要素 | 機能 | 比喩 |
|---|---|---|
| LLM(大規模言語モデル) | 理解、推論、意思決定 | 脳 |
| ツール(Tools) | 行動を実行(検索、計算、コード実行など) | 両手 |
| メモリ(Memory) | 会話履歴と長期知識を保存 | ノート |
| 計画(Planning) | タスクを分解し手順を立てる | スケジュール |
典型的なチャットボットは LLM のみに依存し、「口は達者だが行動できない」アドバイザーのようなものです。一方エージェントはツール・メモリ・計画能力を備え、自らウェブを検索して情報を集め、計算し、レポートを書くアシスタントのようです。
(2) チャットボット vs エージェント vs ワークフロー
| 次元 | チャットボット | エージェント | ワークフロー |
|---|---|---|---|
| 意思決定方法 | 決定なし、直接答える | LLM が次のステップを自ら決定 | 事前定義の人間が決めたプロセス |
| ツール使用 | なし | 動的選択と呼び出し | 固定ノード呼び出し |
| 柔軟性 | 低 | 高 | 中 |
| 制御可能性 | 高 | 中 | 高 |
| 典型的シナリオ | Q&A、雑談 | 調査、分析、自律的探索 | ワークフロー、承認プロセス |
4. ReAct モデル——推論 + 行動
(1) ReAct のコア概念
ReAct(Reasoning + Acting、推論と行動)は、エージェントの最も古典的な意思決定モデルです。
- 観察(Observation):ユーザー入力またはツールが返した結果を受け取る
- 思考(Thought):LLM が現状を分析し、次のステップを決定する
- 行動(Action):ツールを呼び出して操作を実行する
- 最終回答に至るまでこのプロセスを繰り返す
(2) ReAct の各ステップの説明
| ステップ | 説明 | 例 |
|---|---|---|
| 観察 | 入力/ツール結果を受け取る | 「ユーザー質問:Apple の最新株価は?」 |
| 思考 | LLM 推論:今何をすべきか? | 「株価を調べるには検索ツールを使う必要がある」 |
| 行動 | ツール呼び出しを実行 | search_stock("AAPL") |
| 観察 | ツール結果 | 「AAPL = $195.27」 |
| 思考 | 推論を継続 | 「株価が分かったので PER を計算できる」 |
| 行動 | 次のツールを呼ぶ | calculate_pe(195.27, 6.26) |
| ... | 最終回答に至るまで繰り返す | ... |
| 最終回答 | 最終応答を出力 | 「AAPL は現在 $195.27、PER 31.2…」 |
(3) ReAct フロー図
graph TB
A[ユーザー入力] --> B[観察]
B --> C[思考]
C --> D{行動が必要?}
D -- はい --> E[行動 / ツール呼び出し]
E --> F[ツール結果]
F --> B
D -- いいえ --> G[最終回答]
G --> H[ユーザー]
5. 関数呼び出し(Function Calling)
(1) 関数呼び出しとは?
関数呼び出しは OpenAI などのモデルが提供する機能です。「どのツールが使えるか」をモデルに教えると、応答時にテキスト回答を直接出すのではなく、特定のツールを呼び出すことを選べます。
重要な違い:モデルがコードを直接実行するのではなく、構造化されたツール呼び出しリクエスト(関数名 + 引数)を出力し、その実行はあなたのコードが担当します。
(2) ツール種別の比較
| ツール種別 | 目的 | 典型的 API | 例 |
|---|---|---|---|
| 検索 | リアルタイム情報を取得 | SerpAPI / Tavily | get_stock_price("AAPL") |
| 計算機 | 数式演算 | Python eval / Wolfram | calculate("31.2 / 6.26") |
| コード実行 | プログラムを実行 | Python REPL / Docker | run_code("print(2**10)") |
| API 呼び出し | 外部サービスと連携 | HTTP / SDK | send_email(to, subject) |
▶ サンプル: ユーティリティ関数の定義(難易度:⭐)
import json
def get_weather(city: str) -> str:
"""都市の現在の天気を取得する。"""
weather_data = {
"Beijing": '{"temp": 22, "condition": "晴れ"}',
"Tokyo": '{"temp": 18, "condition": "曇り"}',
"New York": '{"temp": 15, "condition": "雨"}',
}
return weather_data.get(city, '{"temp": null, "condition": "不明"}')
tool_definition = {
"type": "function",
"function": {
"name": "get_weather",
"description": "指定した都市の現在の天気を取得する",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "都市名(例:Beijing、Tokyo)"
}
},
"required": ["city"]
}
}
}
print(get_weather("Beijing"))
{"temp": 22, "condition": "晴れ"}
▶ サンプル: OpenAI 関数の呼び出し(難易度:⭐⭐)
from openai import OpenAI
client = OpenAI()
tools = [tool_definition]
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "user", "content": "北京の天気は?"}
],
tools=tools,
tool_choice="auto"
)
message = response.choices[0].message
if message.tool_calls:
tool_call = message.tool_calls[0]
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
print(f"モデルが呼び出しを希望: {func_name}")
print(f"引数: {func_args}")
result = get_weather(**func_args)
print(f"ツール結果: {result}")
モデルが呼び出しを希望: get_weather
引数: {'city': 'Beijing'}
ツール結果: {"temp": 22, "condition": "晴れ"}
6. エージェントの計画とメモリ
(1) 計画(Planning)
複雑なタスクは一歩ずつ完了させる必要があります。エージェントの計画能力は以下に現れます。
- タスク分解:「投資する価値があるか分析」を「株価を調べる → PER を計算 → 業界平均と比較 → 提言を出す」に分解
- ステップの順序付け:何を先に、何を後にするか決定
- 動的調整:検索ツールが失敗したら、別のツールや戦略を試す
(2) メモリ
| 種類 | 説明 | 実装 |
|---|---|---|
| 短期メモリ | 現在の会話文脈 | 会話履歴リスト |
| 長期メモリ | セッションをまたぐ知識 | ベクトルデータベース/ファイル保存 |
| 作業メモリ | 現在のタスクの中間結果 | メモ帳/変数 |
短期メモリは単なる会話履歴——各 LLM 呼び出しとともにこれまでのメッセージをすべて渡す。長期メモリには追加の保存メカニズムが必要です。
7. Python で簡単なエージェントを実装する
▶ サンプル: エージェントループ(while ループで実装)(難易度:⭐⭐)
import json
from openai import OpenAI
client = OpenAI()
def get_weather(city: str) -> str:
"""都市の現在の天気を取得する。"""
data = {
"Beijing": '{"temp": 22, "condition": "晴れ"}',
"Tokyo": '{"temp": 18, "condition": "曇り"}',
}
return data.get(city, '{"temp": null, "condition": "不明"}')
available_tools = {
"get_weather": get_weather,
}
tool_schemas = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "指定した都市の現在の天気を取得する",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "都市名"}
},
"required": ["city"]
}
}
}]
def run_agent(user_query: str, max_steps: int = 5) -> str:
messages = [{"role": "user", "content": user_query}]
for step in range(max_steps):
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=tool_schemas,
tool_choice="auto"
)
msg = response.choices[0].message
messages.append(msg)
if not msg.tool_calls:
return msg.content
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
print(f"[ステップ {step+1}] 呼び出し {func_name}({func_args})")
result = available_tools[func_name](**func_args)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
return "エージェントは最大ステップに達しても最終回答に至りませんでした。"
answer = run_agent("北京と東京の天気は?")
print(answer)
[ステップ 1] 呼び出し get_weather({'city': 'Beijing'})
[ステップ 2] 呼び出し get_weather({'city': 'Tokyo'})
北京の天気は 22°C で晴れ、東京は 18°C で曇りです。
▶ サンプル: マルチツールエージェント(検索 + 計算)(難易度:⭐⭐⭐)
import json
from openai import OpenAI
client = OpenAI()
def search_web(query: str) -> str:
"""ウェブ検索をシミュレート。"""
mock_results = {
"Tesla 2024 revenue": "Tesla 2024 総収益: $97.69 billion",
"Tesla 2023 revenue": "Tesla 2023 総収益: $96.77 billion",
"AAPL stock price": "AAPL 現在株価: $195.27、PER: 31.2",
}
for key, val in mock_results.items():
if key.lower() in query.lower():
return val
return "該当結果なし: " + query
def calculate(expression: str) -> str:
"""数式を安全に評価する。"""
allowed = set("0123456789+-*/.() ")
if all(c in allowed for c in expression):
try:
result = eval(expression)
return str(result)
except Exception as e:
return f"計算エラー: {e}"
return "無効な式"
available_tools = {
"search_web": search_web,
"calculate": calculate,
}
tool_schemas = [
{
"type": "function",
"function": {
"name": "search_web",
"description": "情報をウェブで検索する",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "検索クエリ"}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "calculate",
"description": "数式を評価する",
"parameters": {
"type": "object",
"properties": {
"expression": {"type": "string", "description": "評価する数式"}
},
"required": ["expression"]
}
}
}
]
def run_multi_tool_agent(user_query: str, max_steps: int = 10) -> str:
messages = [{"role": "user", "content": user_query}]
for step in range(max_steps):
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=tool_schemas,
tool_choice="auto"
)
msg = response.choices[0].message
messages.append(msg)
if not msg.tool_calls:
return msg.content
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
print(f"[ステップ {step+1}] {func_name}({func_args})")
result = available_tools[func_name](**func_args)
print(f" -> {result}")
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
return "エージェントは最大ステップに達しました。"
answer = run_multi_tool_agent("Tesla の 2024 年収益はいくらで、前年比でどれだけ成長しましたか?")
print(f"\n最終回答:\n{answer}")
[ステップ 1] search_web({'query': 'Tesla 2024 revenue'})
-> Tesla 2024 総収益: $97.69 billion
[ステップ 2] search_web({'query': 'Tesla 2023 revenue'})
-> Tesla 2023 総収益: $96.77 billion
[ステップ 3] calculate({'expression': '(97.69 - 96.77) / 96.77 * 100'})
-> 0.9508080206700424
最終回答:
Tesla の 2024 年収益は $97.69 billion で、2023 年の $96.77 billion と比べて
前年比成長率は約 0.95% です。
▶ サンプル: メモリ付きエージェント(難易度:⭐⭐⭐)
import json
from openai import OpenAI
client = OpenAI()
class MemoryAgent:
def __init__(self, system_prompt: str = "あなたは親切なアシスタントです。"):
self.system_prompt = system_prompt
self.short_term_memory: list = []
self.long_term_memory: list = []
def add_to_long_term(self, fact: str):
self.long_term_memory.append(fact)
print(f"[記憶保存] {fact}")
def get_context(self) -> list:
context = [{"role": "system", "content": self.system_prompt}]
if self.long_term_memory:
mem_str = "\n".join(f"- {m}" for m in self.long_term_memory)
context.append({
"role": "system",
"content": f"長期メモリ:\n{mem_str}"
})
context.extend(self.short_term_memory)
return context
def chat(self, user_input: str) -> str:
self.short_term_memory.append({"role": "user", "content": user_input})
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=self.get_context()
)
reply = response.choices[0].message.content
self.short_term_memory.append({"role": "assistant", "content": reply})
return reply
def remember(self, fact: str):
self.add_to_long_term(fact)
agent = MemoryAgent(system_prompt="あなたは研究アシスタントです。")
r1 = agent.chat("私の名前は Bob で、Apple Inc. に勤めています。")
print(f"Agent: {r1}")
agent.remember("ユーザー名: Bob、勤務先: Apple Inc.")
r2 = agent.chat("私の名前と勤務先は?")
print(f"Agent: {r2}")
Agent: はじめまして、Bob さん!今日はどのようにお手伝いできますか?
[記憶保存] ユーザー名: Bob、勤務先: Apple Inc.
Agent: お名前は Bob さんで、勤務先は Apple Inc. です。
8. エージェントフレームワーク
(1) エージェントフレームワークの比較
| フレームワーク | 特徴 | 適したシナリオ | 言語 |
|---|---|---|---|
| LangChain / LangGraph | エコシステムが豊富、コミュニティが大きい、柔軟だが複雑 | 汎用エージェント開発 | Python / JS |
| OpenAI Assistants API | 公式ホスト、使いやすい、ブラックボックス | プロトタイピング迅速、OpenAI エコシステム | REST / Python |
| AutoGen(Microsoft) | マルチエージェント協調、対話型 | マルチエージェント議論と協力 | Python |
| CrewAI | ロールプレイ、チーム協力 | チームワークフローのシミュレーション | Python |
(2) どう選ぶか
- 入門演習:
whileループで自分のコードを書く(このレッスンの手法に従う)と基本原理を理解できる - プロトタイピング迅速:OpenAI Assistants API——数行のコードで完了
- 本番プロジェクト:制御性が良い LangGraph
- マルチエージェント:AutoGen または CrewAI
9. 総合例:リサーチアシスタントエージェント
▶ サンプル: 「リサーチアシスタントエージェント」の構築(難易度:⭐⭐⭐)
import json
from openai import OpenAI
client = OpenAI()
# --- ツール定義 ---
def search_web(query: str) -> str:
"""リアルタイム情報のウェブ検索をシミュレート。"""
mock_db = {
"Tesla 2024 revenue": "Tesla 2024 総収益: $97.69 billion、純利益: $7.09 billion",
"Tesla 2023 revenue": "Tesla 2023 総収益: $96.77 billion、純利益: $14.99 billion",
"Tesla stock price": "TSLA 現在株価: $352.00、時価総額: $1.13 trillion",
}
for key, val in mock_db.items():
if key.lower() in query.lower():
return val
return f"特定の結果なし: {query}"
def calculate(expression: str) -> str:
"""数式を評価する。"""
allowed = set("0123456789+-*/.() ")
if all(c in allowed for c in expression):
try:
return str(eval(expression))
except Exception as e:
return f"エラー: {e}"
return "無効な式"
def run_code(code: str) -> str:
"""Python コードを実行し出力を返す。"""
import io
import contextlib
output = io.StringIO()
try:
with contextlib.redirect_stdout(output):
exec(code, {"__builtins__": {}})
return output.getvalue() or "出力なしでコードが実行されました。"
except Exception as e:
return f"実行エラー: {e}"
# --- エージェント設定 ---
available_tools = {
"search_web": search_web,
"calculate": calculate,
"run_code": run_code,
}
tool_schemas = [
{
"type": "function",
"function": {
"name": "search_web",
"description": "株価、収益、ニュースなどのリアルタイム情報をウェブで検索する",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "検索クエリ"}
},
"required": ["query"]
}
}
},
{
"type": "function",
"function": {
"name": "calculate",
"description": "数式を評価する(例:(100-90)/90*100)",
"parameters": {
"type": "object",
"properties": {
"expression": {"type": "string", "description": "数式"}
},
"required": ["expression"]
}
}
},
{
"type": "function",
"function": {
"name": "run_code",
"description": "複雑な分析、チャート、データ処理のための Python コードを実行する",
"parameters": {
"type": "object",
"properties": {
"code": {"type": "string", "description": "実行する Python コード"}
},
"required": ["code"]
}
}
}
]
SYSTEM_PROMPT = """あなたはリサーチアシスタントエージェントです。質問に答える際:
1. search_web を使ってリアルタイムデータを探す
2. calculate を使って数式演算する
3. run_code を使って複雑な分析をする
常に推論ステップを順に示すこと。"""
def research_agent(user_query: str, max_steps: int = 10) -> str:
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_query}
]
for step in range(max_steps):
print(f"\n--- ステップ {step + 1} ---")
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=messages,
tools=tool_schemas,
tool_choice="auto"
)
msg = response.choices[0].message
messages.append(msg)
if msg.content:
print(f"思考: {msg.content[:200]}")
if not msg.tool_calls:
return msg.content
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
print(f"行動: {func_name}({json.dumps(func_args)})")
result = available_tools[func_name](**func_args)
print(f"観察: {result[:200]}")
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
return "エージェントは最大ステップに達しました。"
# --- エージェントを実行 ---
answer = research_agent(
"Tesla の 2024 年収益はいくら?前年比でどれだけ成長しましたか?"
"成長率をパーセントで計算してください。"
)
print(f"\n{'='*50}\n最終回答:\n{answer}")
--- ステップ 1 ---
思考: まず Tesla の 2024 年と 2023 年の収益を見つける必要がある。
行動: search_web({"query": "Tesla 2024 revenue"})
観察: Tesla 2024 総収益: $97.69 billion、純利益: $7.09 billion
--- ステップ 2 ---
行動: search_web({"query": "Tesla 2023 revenue"})
観察: Tesla 2023 総収益: $96.77 billion、純利益: $14.99 billion
--- ステップ 3 ---
行動: calculate({"expression": "(97.69 - 96.77) / 96.77 * 100"})
観察: 0.9508080206700424
==================================================
最終回答:
Tesla の 2024 年総収益は $97.69 billion で、2023 年の $96.77 billion と比べて
前年比成長率は約 0.95% です。
❓ よくある質問
📖 まとめ
- AI エージェント:LLM + ツール + メモリ + 計画 = 自律的に行動できる AI
- ReAct:観察 → 思考 → 行動のサイクル。エージェントのコア意思決定モデル
- 関数呼び出し:モデルがツール呼び出しリクエストを生成し、コードがその実行を担う
- 計画:エージェントが複雑なタスクを実行可能なステップに分解する
- メモリ:短期(会話履歴)+ 長期(ベクトルデータベース)= エージェントの知識ベース
- エージェントフレームワーク:LangChain、OpenAI Assistants、AutoGen などが開発を簡略化
📝 練習問題
-
基礎(⭐): 2 つのカスタムツール(
get_populationやget_gdpなど)を定義し、Function Calling 用の JSON Schema 形式でツール定義を書き、available_tools辞書に登録しなさい。 -
応用(⭐⭐): 単一ツールのエージェントループを実装しなさい。名前を
get_exchange_rateとするツールを定義し、ユーザーが「100 USD は何 CNY ですか?」と入力したとき、エージェントが自動的にツールを呼んで結果を返すようにしなさい。 -
チャレンジ(⭐⭐⭐): 検索と計算の両方を必要とする質問にエージェントで答えさせなさい。たとえば「東京の人口は?每人が 1 日 2 kg の水を必要とする場合、東京は 1 日何トンの水を必要とするか?」エージェントは自ら、まず人口データを検索し、次に計算ツールを使って答えを出すよう決定しなければなりません。