AI: AI エージェント

最終更新:2026-08-26

1. 学べること

No. 内容
エージェントと通常のチャットボットの違い
ReAct モード(推論 + 行動)
関数呼び出し(Function Calling)
エージェントの計画とメモリ
Python で簡単なエージェントを実装する



2. ストーリー

Bob は AI に「Apple の最新株価を調べて、投資する価値があるか分析して」と頼みたかった。標準の ChatGPT は「インターネットに接続できません。私の学習データのカットオフ時点では…」とだけ答え、情報は古くまったく役に立ちません。

Alice はエージェントフレームワークを使って AI エージェントを作りました。同じ質問をされると、エージェントは自ら決定します。

  1. 検索ツールを開く → AAPL の現在株価が $195.27、PER が 31.2 であると判明
  2. 計算ツールを開く → 想定年率リターンを約 6.8% と計算
  3. 以上の結果に基づき → 投資提言を生成

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、推論と行動)は、エージェントの最も古典的な意思決定モデルです。

  1. 観察(Observation):ユーザー入力またはツールが返した結果を受け取る
  2. 思考(Thought):LLM が現状を分析し、次のステップを決定する
  3. 行動(Action):ツールを呼び出して操作を実行する
  4. 最終回答に至るまでこのプロセスを繰り返す

(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 フロー図

100%
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)

▶ サンプル: ユーティリティ関数の定義(難易度:⭐)

PYTHON
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"))
TEXT 📖 参照専用
{"temp": 22, "condition": "晴れ"}

▶ サンプル: OpenAI 関数の呼び出し(難易度:⭐⭐)

PYTHON
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}")
TEXT 📖 参照専用
モデルが呼び出しを希望: get_weather
引数: {'city': 'Beijing'}
ツール結果: {"temp": 22, "condition": "晴れ"}



6. エージェントの計画とメモリ

(1) 計画(Planning)

複雑なタスクは一歩ずつ完了させる必要があります。エージェントの計画能力は以下に現れます。

(2) メモリ

種類 説明 実装
短期メモリ 現在の会話文脈 会話履歴リスト
長期メモリ セッションをまたぐ知識 ベクトルデータベース/ファイル保存
作業メモリ 現在のタスクの中間結果 メモ帳/変数

短期メモリは単なる会話履歴——各 LLM 呼び出しとともにこれまでのメッセージをすべて渡す。長期メモリには追加の保存メカニズムが必要です。




7. Python で簡単なエージェントを実装する

▶ サンプル: エージェントループ(while ループで実装)(難易度:⭐⭐)

PYTHON
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)
TEXT 📖 参照専用
[ステップ 1] 呼び出し get_weather({'city': 'Beijing'})
[ステップ 2] 呼び出し get_weather({'city': 'Tokyo'})
北京の天気は 22°C で晴れ、東京は 18°C で曇りです。

▶ サンプル: マルチツールエージェント(検索 + 計算)(難易度:⭐⭐⭐)

PYTHON
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}")
TEXT 📖 参照専用
[ステップ 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% です。

▶ サンプル: メモリ付きエージェント(難易度:⭐⭐⭐)

PYTHON
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}")
TEXT 📖 参照専用
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) どう選ぶか




9. 総合例:リサーチアシスタントエージェント

▶ サンプル: 「リサーチアシスタントエージェント」の構築(難易度:⭐⭐⭐)

PYTHON
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}")
TEXT 📖 参照専用
--- ステップ 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% です。

❓ よくある質問

Q エージェントと自動化スクリプトの違いは?
A 自動化スクリプトは固定ルールに従って実行し、自分では考えません。エージェントは LLM に基づいて動的に決定し、予期せぬ状況に出会ったとき戦略を調整でき、エラーで停止するのではありません。
Q エージェントは制御不能になる可能性がある?
A あり得ますが、利用可能なツールを制限し、max_steps 上限を設け、人間参加型(human-in-the-loop)の承認ステップを加え、ツール入力を検証することで緩和できます。
Q 関数呼び出しと通常の API 呼び出しの違いは?
A 通常の API 呼び出しでは、どの API をいつ呼ぶかを自分でコードで決めます。関数呼び出しでは、LLM がどの関数を呼び、どの引数を渡すかを決定します。あなたのコードは関数の実行と結果の返却だけを担います。
Q 直接コードを書く代わりにエージェントをいつ使うべき?
A タスクのステップが不確実で、中間結果に基づいて動的に調整する必要がある場合にエージェントを使います。プロセスが固定でステップが明確なら、直接コードを書く方が信頼性と効率に優れます。
Q エージェントはどれくらいの計算資源を必要とする?
A エージェントの主なコストは LLM 呼び出しにあります。各 ReAct ステップで 1 回の API 呼び出しが必要です。単純なタスクは 2〜3 ステップ、複雑なタスクは 10 ステップ以上かかることも。gpt-4o-mini のような小さなモデルを使えばコストを大幅に削減できます。

📖 まとめ


📝 練習問題

  1. 基礎(⭐): 2 つのカスタムツール(get_populationget_gdp など)を定義し、Function Calling 用の JSON Schema 形式でツール定義を書き、available_tools 辞書に登録しなさい。

  2. 応用(⭐⭐): 単一ツールのエージェントループを実装しなさい。名前を get_exchange_rate とするツールを定義し、ユーザーが「100 USD は何 CNY ですか?」と入力したとき、エージェントが自動的にツールを呼んで結果を返すようにしなさい。

  3. チャレンジ(⭐⭐⭐): 検索と計算の両方を必要とする質問にエージェントで答えさせなさい。たとえば「東京の人口は?每人が 1 日 2 kg の水を必要とする場合、東京は 1 日何トンの水を必要とするか?」エージェントは自ら、まず人口データを検索し、次に計算ツールを使って答えを出すよう決定しなければなりません。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%