AI Agent 개발이 활발해지는 가운데, 도구 호출(tool calling) 프레임워크 선택이 시스템 성능을 좌우하는 핵심 과제가 되었습니다. 본 기사에서는 현재 가장 널리 사용되는 두 가지 접근법인 ReAct(Reasoning + Acting)와 Plan-and-Execute를 심층 비교하고, HolySheep AI를 활용한 실전 구현 방법을 소개합니다.
背景:なぜ工具调用フレームワークが重要か
ECプラットフォームのAIカスタマーサービスでは、ユーザーの質問に応じて「在庫確認」「注文履歴取得」「返金の複雑条件判定」を連続実行する必要があります。こうした複雑なタスクをAI Agentに実行させるには、以下の要件が必要です:
- 複数ツールの协调呼び出し
- 段階的な推論プロセス
- エラー時の恢复と替代手段
- リアルタイム性とコスト効率
私は以前、某EC企業のRAGシステムを構築する際、ReActとPlan-and-Executeの両方を試しました。結論として、プロジェクトの特性によって最適な選択が異なることを実感しました。以下、その知見を共有します。
ReActとは:同期的推論・実行パターン
核心概念
ReAct(Reasoning + Acting)は、「推論」と「実行」を1ステップ内で交互に行う同期的アプローチです。各ステップで以下のプロセスを繰り返します:
- Think:現在の状況分析与次のアクション决定
- Act:ツール呼び出しの実行
- Observe:実行結果の观察
メリット
- 実装がシンプルで理解しやすい
- 实时反馈によりエラーにすぐ対応可能
- デバッグが容易(步骤単位でログ出力可能)
デメリット
- 長いタスクではトークン消费が较多
- план提前最適化不可
- ツール呼び出し回数が多くなりやすい
Plan-and-Executeとは:分離型アーキテクチャ
核心概念
Plan-and-Executeは、任务を「計画立案」と「実行」の2段階で分離するアプローチです。最初に完全なアクションプランを作成し、その後一括実行を行います。
メリット
- 長いタスクでもトークン消费を削減可能
- план安定性が高く、复杂な задачに向く
- 実行前にエラーを预测・规避可能
デメリット
- 実装复杂度が高い
- リアルタイム性への課題
- エラー恢复のレイテンシ增加
実戦コード比較:HolySheep AI API活用
ReAct実装例
import requests
import json
class ReActAgent:
def __init__(self, api_key: str):
self.base_url = "https://api.holysheep.ai/v1"
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
def call_llm(self, messages: list, tools: list = None) -> dict:
"""HolySheep AI API呼び出し"""
payload = {
"model": "gpt-4.1",
"messages": messages,
"temperature": 0.7,
"max_tokens": 2048
}
if tools:
payload["tools"] = tools
response = requests.post(
f"{self.base_url}/chat/completions",
headers=self.headers,
json=payload
)
return response.json()
def execute_tool(self, tool_name: str, args: dict) -> str:
"""ツールエミュレーション"""
tools_map = {
"get_order_status": self._get_order_status,
"check_inventory": self._check_inventory,
"process_refund": self._process_refund
}
return tools_map.get(tool_name, lambda x: "Unknown tool")(args)
def _get_order_status(self, args):
order_id = args.get("order_id")
return json.dumps({"order_id": order_id, "status": "shipped", "eta": "2days"})
def _check_inventory(self, args):
sku = args.get("sku")
return json.dumps({"sku": sku, "available": True, "quantity": 50})
def _process_refund(self, args):
order_id = args.get("order_id")
amount = args.get("amount", 0)
return json.dumps({"refund_id": f"REF-{order_id}", "amount": amount, "status": "processed"})
def run(self, user_query: str, max_iterations: int = 10):
"""ReAct実行ループ"""
messages = [
{"role": "system", "content": """あなたはECサイトのAIカスタマーエージェントです。
ユーザーは注文関連の問題で連絡してきます。
利用可能なツール:get_order_status, check_inventory, process_refund
回答は日本語で行ってください。"""},
{"role": "user", "content": user_query}
]
tools = [
{
"type": "function",
"function": {
"name": "get_order_status",
"description": "注文状況を確認",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}}}
}
},
{
"type": "function",
"function": {
"name": "check_inventory",
"description": "在庫確認",
"parameters": {"type": "object", "properties": {"sku": {"type": "string"}}}
}
},
{
"type": "function",
"function": {
"name": "process_refund",
"description": "返金処理",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}, "amount": {"type": "number"}}}
}
}
]
for i in range(max_iterations):
print(f"--- Iteration {i+1} ---")
response = self.call_llm(messages, tools)
if "choices" not in response:
print(f"API Error: {response}")
break
choice = response["choices"][0]
if choice.get("finish_reason") == "stop":
final_response = choice["message"]["content"]
messages.append({"role": "assistant", "content": final_response})
break
# ツール呼び出し処理
if "tool_calls" in choice["message"]:
tool_call = choice["message"]["tool_calls"][0]
tool_name = tool_call["function"]["name"]
args = json.loads(tool_call["function"]["arguments"])
print(f"Executing: {tool_name} with {args}")
result = self.execute_tool(tool_name, args)
messages.append({
"role": "assistant",
"content": None,
"tool_calls": choice["message"]["tool_calls"]
})
messages.append({
"role": "tool",
"tool_call_id": tool_call["id"],
"name": tool_name,
"content": result
})
else:
messages.append({"role": "assistant", "content": choice["message"]["content"]})
break
return messages[-1]["content"]
実行例
api_key = "YOUR_HOLYSHEEP_API_KEY"
agent = ReActAgent(api_key)
result = agent.run("注文番号ORD-12345の状況を教えていただき、在庫があれば交換の手配をお願いします。")
print(f"\n最終回答:\n{result}")
Plan-and-Execute実装例
import requests
import json
from typing import List, Dict, Any
from enum import Enum
class TaskStatus(Enum):
PENDING = "pending"
COMPLETED = "completed"
FAILED = "failed"
class PlanStep:
def __init__(self, step_id: int, action: str