結論ファースト: Tool-calling機能を活用することで、LLMを外部システムとシームレスに連携させ、エージェントアプリケーションを構築できます。HolySheep AIは、レート¥1=$1という破格の料金体系(公式比85%節約)、<50msの低レイテンシ、WeChat Pay/Alipay対応など、開発者に優しい環境を提供します。本記事では、関数スキーマの定義からパラメータ検証の実装まで、Hands-onで解説します。

Tool-Calling APIサービス比較

項目 HolySheep AI OpenAI公式 Anthropic公式 Google AI
為替レート ¥1 = $1(85%節約) ¥7.3 = $1 ¥7.3 = $1 ¥7.3 = $1
GPT-4.1出力 $8/MTok $8/MTok -$ -$
Claude Sonnet 4.5出力 $15/MTok -$ $15/MTok -$
Gemini 2.5 Flash出力 $2.50/MTok -$ -$ $2.50/MTok
DeepSeek V3.2出力 $0.42/MTok -$ -$ -$
レイテンシ <50ms 100-300ms 150-400ms 80-200ms
決済手段 WeChat Pay/Alipay/クレカ クレジットカードのみ クレジットカードのみ クレジットカードのみ
無料クレジット 登録時付与 $5〜$18 $5 $300(90日)
最適なチーム コスト重視・多言語対応 OpenAIエコシステム Anthropicエコシステム Google Cloud統合

Tool-Callingとは

Tool-calling(関数呼び出し)は、LLMがユーザーの意図を理解し、事前に定義した関数を実行する機能です。これにより、データベース検索、API呼び出し、ファイル操作、Webブラウジングなど、現実世界のアクションをLLMに実行させることができます。

私は以前、OpenAIの公式APIでTool-callingを実装していましたが、コスト面で頭を痛めていました。HolySheep AIに移行したところ、同じ品質のまま開発コストを85%削減できました。特に中華圏向けのサービスを開発している場合、WeChat Pay/Alipayでチャージできる点は大きなメリットです。

関数スキーマの定義方法

Tool-callingを実装する第一步は、適切な関数スキーマを定義することです。スキーマはJSON Schema形式で記述し、関数の名前、説明、パラメータ構造を明確に指定します。

スキーマ設計のベストプラクティス

実践的なコード例

例1:基本的なTool-Calling実装(Python)

import requests
import json
from typing import List, Dict, Any, Optional

class HolySheepToolCaller:
    """HolySheep AI API を使用したTool-calling実装"""
    
    def __init__(self, api_key: str):
        self.api_key = api_key
        self.base_url = "https://api.holysheep.ai/v1"
        self.headers = {
            "Authorization": f"Bearer {api_key}",
            "Content-Type": "application/json"
        }
    
    def define_functions(self) -> List[Dict[str, Any]]:
        """関数スキーマの定義"""
        return [
            {
                "type": "function",
                "function": {
                    "name": "get_weather",
                    "description": "指定された都市の現在の天気を取得します。天気予報の確認や旅行計画に最適です。",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "city": {
                                "type": "string",
                                "description": "天気を知りたい都市名(例:東京、ニューヨーク)",
                                "minLength": 1,
                                "maxLength": 50
                            },
                            "unit": {
                                "type": "string",
                                "description": "温度の単位",
                                "enum": ["celsius", "fahrenheit"],
                                "default": "celsius"
                            }
                        },
                        "required": ["city"]
                    }
                }
            },
            {
                "type": "function",
                "function": {
                    "name": "calculate_tip",
                    "description": "レストランでのチップ額を計算します。割勘や多人数の計算に便利です。",
                    "parameters": {
                        "type": "object",
                        "properties": {
                            "amount": {
                                "type": "number",
                                "description": "請求総額(日本円)",
                                "minimum": 0,
                                "maximum": 1000000
                            },
                            "percentage": {
                                "type": "number",
                                "description": "チップの割合(%)",
                                "minimum": 0,
                                "maximum": 100,
                                "default": 15
                            },
                            "people": {
                                "type": "integer",
                                "description": "分割人数",
                                "minimum": 1,
                                "maximum": 100,
                                "default": 1
                            }
                        },
                        "required": ["amount"]
                    }
                }
            }
        ]
    
    def execute_tool(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
        """ツールの実処理を実行"""
        if tool_name == "get_weather":
            return self._get_weather(arguments["city"], arguments.get("unit", "celsius"))
        elif tool_name == "calculate_tip":
            return self._calculate_tip(
                arguments["amount"],
                arguments.get("percentage", 15),
                arguments.get("people", 1)
            )
        else:
            return {"error": f"Unknown tool: {tool_name}"}
    
    def _get_weather(self, city: str, unit: str) -> Dict[str, Any]:
        """天気取得の実装(ダミー)"""
        weather_conditions = ["晴れ", "曇り", "雨", "雪", "快晴"]
        import random
        temp = random.randint(15, 30)
        if unit == "fahrenheit":
            temp = int(temp * 9/5 + 32)
        return {
            "city": city,
            "weather": random.choice(weather_conditions),
            "temperature": temp,
            "unit": unit
        }
    
    def _calculate_tip(self, amount: float, percentage: float, people: int) -> Dict[str, Any]:
        """チップ計算の実装"""
        tip_amount = amount * (percentage / 100)
        total = amount + tip_amount
        per_person = total / people
        return {
            "original_amount": amount,
            "tip_percentage": percentage,
            "tip_amount": round(tip_amount, 2),
            "total": round(total, 2),
            "split_people": people,
            "per_person": round(per_person, 2)
        }
    
    def chat(self, message: str) -> Dict[str, Any]:
        """Chat Completions API呼び出し"""
        payload = {
            "model": "gpt-4.1",
            "messages": [{"role": "user", "content": message}],
            "tools": self.define_functions(),
            "tool_choice": "auto"
        }
        
        response = requests.post(
            f"{self.base_url}/chat/completions",
            headers=self.headers,
            json=payload
        )
        
        if response.status_code != 200:
            raise Exception(f"API Error: {response.status_code} - {response.text}")
        
        result = response.json()
        
        # Tool-callが要求された場合
        if result.get("choices")[0].get("message").get("tool_calls"):
            tool_calls = result["choices"][0]["message"]["tool_calls"]
            tool_results = []
            
            for tool_call in tool_calls:
                tool_name = tool_call["function"]["name"]
                arguments = json.loads(tool_call["function"]["arguments"])
                
                # パラメータ検証
                validation_error = self._validate_parameters(tool_name, arguments)
                if validation_error:
                    tool_results.append({
                        "tool_call_id": tool_call["id"],
                        "role": "tool",
                        "content": json.dumps({"error": validation_error})
                    })
                    continue
                
                # ツール実行
                result_data = self.execute_tool(tool_name, arguments)
                tool_results.append({
                    "tool_call_id": tool_call["id"],
                    "role": "tool",
                    "content": json.dumps(result_data)
                })
            
            return {"tool_results": tool_results, "original": result}
        
        return result
    
    def _validate_parameters(self, tool_name: str, arguments: Dict[str, Any]) -> Optional[str]:
        """パラメータ検証"""
        functions = self.define_functions()
        schema = None
        
        for func in functions:
            if func["function"]["name"] == tool_name:
                schema = func["function"]["parameters"]
                break
        
        if not schema:
            return f"Unknown function: {tool_name}"
        
        # 必須パラメータチェック
        required = schema.get("required", [])
        for req_param in required:
            if req_param not in arguments:
                return f"Missing required parameter: {req_param}"
        
        # 型と制約チェック
        properties = schema.get("properties", {})
        for param_name, param_spec in properties.items():
            if param_name in arguments:
                value = arguments[param_name]
                param_type = param_spec.get("type")
                
                # 型チェック
                if param_type == "string" and not isinstance(value, str):
                    return f"Parameter '{param_name}' must be a string"
                elif param_type == "number" and not isinstance(value, (int, float)):
                    return f"Parameter '{param_name}' must be a number"
                elif param_type == "integer" and not isinstance(value, int):
                    return f"Parameter '{param_name}' must be an integer"
                
                # 文字列長チェック
                if param_type == "string":
                    if "minLength" in param_spec and len(value) < param_spec["minLength"]:
                        return f"Parameter '{param_name}' must be at least {param_spec['minLength']} characters"
                    if "maxLength" in param_spec and len(value) > param_spec["maxLength"]:
                        return f"Parameter '{param_name}' must be at most {param_spec['maxLength']} characters"
                
                # 数値範囲チェック
                if param_type in ["number", "integer"]:
                    if "minimum" in param_spec and value < param_spec["minimum"]:
                        return f"Parameter '{param_name}' must be at least {param_spec['minimum']}"
                    if "maximum" in param_spec and value > param_spec["maximum"]:
                        return f"Parameter '{param_name}' must be at most {param_spec['maximum']}"
                
                # enumチェック
                if "enum" in param_spec and value not in param_spec["enum"]:
                    return f"Parameter '{param_name}' must be one of: {param_spec['enum']}"
        
        return None


使用例

if __name__ == "__main__": caller = HolySheepToolCaller(api_key="YOUR_HOLYSHEEP_API_KEY") # 天気查询 result = caller.chat("東京、今の天気教えて") print("天気查询結果:", result) # チップ計算 result = caller.chat("5000円の請求で15%チップ、一人暮らしだけど何人で行けばいい?") print("チップ計算結果:", result)

例2:Node.jsでのTool-Calling実装

import https from 'https';

/**
 * HolySheep AI API - Tool-Calling クライアント
 * パラメータ検証を備えた堅牢な実装
 */

class HolySheepToolCaller {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.baseUrl = 'https://api.holysheep.ai/v1';
  }

  /**
   * APIリクエストを実行
   */
  async request(endpoint, method, payload) {
    return new Promise((resolve, reject) => {
      const url = new URL(${this.baseUrl}${endpoint});
      
      const options = {
        hostname: url.hostname,
        port: 443,
        path: url.pathname,
        method: method,
        headers: {
          'Authorization': Bearer ${this.apiKey},
          'Content-Type': 'application/json'
        }
      };

      const req = https.request(options, (res) => {
        let data = '';
        res.on('data', chunk => data += chunk);
        res.on('end', () => {
          try {
            const parsed = JSON.parse(data);
            if (res.statusCode >= 200 && res.statusCode < 300) {
              resolve(parsed);
            } else {
              reject(new Error(API Error: ${res.statusCode} - ${JSON.stringify(parsed)}));
            }
          } catch (e) {
            reject(new Error(Parse Error: ${data}));
          }
        });
      });

      req.on('error', reject);
      req.write(JSON.stringify(payload));
      req.end();
    });
  }

  /**
   * 関数スキーマ定義
   */
  getTools() {
    return [
      {
        type: 'function',
        function: {
          name: 'search_products',
          description: 'ECサイトを検索して商品を取得します。在庫確認や価格比較に便利です。',
          parameters: {
            type: 'object',
            properties: {
              query: {
                type: 'string',
                description: '検索キーワード',
                minLength: 1,
                maxLength: 100
              },
              category: {
                type: 'string',
                description: '商品カテゴリ',
                enum: ['electronics', 'clothing', 'food', 'books', 'home']
              },
              max_price: {
                type: 'number',
                description: '最大価格(日本円)',
                minimum: 0,
                maximum: 1000000
              },
              min_price: {
                type: 'number',
                description: '最小価格(日本円)',
                minimum: 0,
                maximum: 1000000
              },
              limit: {
                type: 'integer',
                description: '取得件数(1-50)',
                minimum: 1,
                maximum: 50,
                default: 10
              }
            },
            required: ['query']
          }
        }
      },
      {
        type: 'function',
        function: {
          name: 'convert_currency',
          description: '通貨両替額を計算します。旅行や国際取引に役立ちます。',
          parameters: {
            type: 'object',
            properties: {
              amount: {
                type: 'number',
                description: '金額',
                minimum: 0.01
              },
              from_currency: {
                type: 'string',
                description: '変換元通貨コード',
                enum: ['JPY', 'USD', 'CNY', 'EUR', 'GBP', 'KRW']
              },
              to_currency: {
                type: 'string',
                description: '変換先通貨コード',
                enum: ['JPY', 'USD', 'CNY', 'EUR', 'GBP', 'KRW']
              }
            },
            required: ['amount', 'from_currency', 'to_currency']
          }
        }
      }
    ];
  }

  /**
   * パラメータ検証
   */
  validateParameters(toolName, args) {
    const tools = this.getTools();
    const tool = tools.find(t => t.function.name === toolName);
    
    if (!tool) {
      return { valid: false, error: Unknown tool: ${toolName} };
    }

    const schema = tool.function.parameters;
    const { properties, required = [] } = schema;

    // 必須パラメータチェック
    for (const param of required) {
      if (args[param] === undefined || args[param] === null) {
        return { valid: false, error: Missing required parameter: ${param} };
      }
    }

    // 各パラメータの検証
    for (const [key, value] of Object.entries(args)) {
      if (!properties[key]) {
        return { valid: false, error: Unknown parameter: ${key} };
      }

      const spec = properties[key];
      
      // 型チェック
      if (spec.type === 'string' && typeof value !== 'string') {
        return { valid: false, error: Parameter '${key}' must be a string };
      }
      if (spec.type === 'number' && typeof value !== 'number') {
        return { valid: false, error: Parameter '${key}' must be a number };
      }
      if (spec.type === 'integer' && !Number.isInteger(value)) {
        return { valid: false, error: Parameter '${key}' must be an integer };
      }

      // 文字列制約
      if (spec.type === 'string') {
        if (spec.minLength && value.length < spec.minLength) {
          return { valid: false, error: Parameter '${key}' must be at least ${spec.minLength} characters };
        }
        if (spec.maxLength && value.length > spec.maxLength) {
          return { valid: false, error: Parameter '${key}' must be at most ${spec.maxLength} characters };
        }
      }

      // 数値制約
      if (spec.type === 'number' || spec.type === 'integer') {
        if (spec.minimum !== undefined && value < spec.minimum) {
          return { valid: false, error: Parameter '${key}' must be at least ${spec.minimum} };
        }
        if (spec.maximum !== undefined && value > spec.maximum) {
          return { valid: false, error: Parameter '${key}' must be at most ${spec.maximum} };
        }
      }

      // 列挙値チェック
      if (spec.enum && !spec.enum.includes(value)) {
        return { valid: false, error: Parameter '${key}' must be one of: ${spec.enum.join(', ')} };
      }
    }

    // 追加のビジネスロジック検証
    if (toolName === 'search_products') {
      if (args.min_price && args.max_price && args.min_price > args.max_price) {
        return { valid: false, error: 'min_price cannot be greater than max_price' };
      }
    }

    if (toolName === 'convert_currency') {
      if (args.from_currency === args.to_currency) {
        return { valid: false, error: 'from_currency and to_currency must be different' };
      }
    }

    return { valid: true };
  }

  /**
   * ツール実行
   */
  async executeTool(toolName, args) {
    console.log(Executing tool: ${toolName} with args:, args);

    switch (toolName) {
      case 'search_products':
        return this.searchProducts(args);
      case 'convert_currency':
        return this.convertCurrency(args);
      default:
        throw new Error(Unknown tool: ${toolName});
    }
  }

  /**
   * 商品検索の実装
   */
  searchProducts({ query, category, max_price, min_price, limit = 10 }) {
    // ダミー実装
    const products = [
      { id: 1, name: 'ワイヤレスヘッドフォン', price: 15000, category: 'electronics' },
      { id: 2, name: '棉T恤', price: 3500, category: 'clothing' },
      { id: 3, name: 'オーガニック紅茶', price: 2500, category: 'food' },
      { id: 4, name: 'TypeScript入門', price: 2800, category: 'books' },
      { id: 5, name: '調節可能デスク', price: 45000, category: 'home' },
    ];

    let results = products.filter(p => {
      const matchQuery = p.name.includes(query);
      const matchCategory = !category || p.category === category;
      const matchMaxPrice = !max_price || p.price <= max_price;
      const matchMinPrice = !min_price || p.price >= min_price;
      return matchQuery && matchCategory && matchMaxPrice && matchMinPrice;
    });

    return results.slice(0, limit);
  }

  /**
   * 通貨変換の実装
   */
  convertCurrency({ amount, from_currency, to_currency }) {
    // ダミー為替レート
    const rates = {
      'JPY': { 'USD': 0.0067, 'CNY': 0.048, 'EUR': 0.0061, 'GBP': 0.0053, 'KRW': 8.9 },
      'USD': { 'JPY': 149.5, 'CNY': 7.2, 'EUR': 0.92, 'GBP': 0.79, 'KRW': 1330 },
      'CNY': { 'JPY': 20.8, 'USD': 0.14, 'EUR': 0.13, 'GBP': 0.11, 'KRW': 185 },
      'EUR': { 'JPY': 163, 'USD': 1.09, 'CNY': 7.8, 'GBP': 0.86, 'KRW': 1450 },
      'GBP': { 'JPY': 190, 'USD': 1.27, 'CNY': 9.1, 'EUR': 1.16, 'KRW': 1690 },
      'KRW': { 'JPY': 0.11, 'USD': 0.00075, 'CNY': 0.0054, 'EUR': 0.00069, 'GBP': 0.00059 }
    };

    const rate = rates[from_currency]?.[to_currency];
    if (!rate) {
      throw new Error(Exchange rate not available: ${from_currency} to ${to_currency});
    }

    const converted = amount * rate;

    return {
      original: { amount, currency: from_currency },
      converted: { amount: converted.toFixed(2), currency: to_currency },
      rate: rate
    };
  }

  /**
   * チャット実行
   */
  async chat(message) {
    const payload = {
      model: 'gpt-4.1',
      messages: [{ role: 'user', content: message }],
      tools: this.getTools(),
      tool_choice: 'auto'
    };

    const response = await this.request('/chat/completions', 'POST', payload);
    const choice = response.choices?.[0];

    if (!choice?.message?.tool_calls) {
      return { reply: choice?.message?.content };
    }

    // ツール呼び出しの処理
    const toolResults = [];
    
    for (const toolCall of choice.message.tool_calls) {
      const toolName = toolCall.function.name;
      let args;
      
      try {
        args = JSON.parse(toolCall.function.arguments);
      } catch (e) {
        toolResults.push({
          tool_call_id: toolCall.id,
          role: 'tool',
          content: JSON.stringify({ error: 'Invalid JSON arguments' })
        });
        continue;
      }

      // パラメータ検証
      const validation = this.validateParameters(toolName, args);
      
      if (!validation.valid) {
        toolResults.push({
          tool_call_id: toolCall.id,
          role: 'tool',
          content: JSON.stringify({ error: validation.error })
        });
        continue;
      }

      // ツール実行
      try {
        const result = await this.executeTool(toolName, args);
        toolResults.push({
          tool_call_id: toolCall.id,
          role: 'tool',
          content: JSON.stringify(result)
        });
      } catch (e) {
        toolResults.push({
          tool_call_id: toolCall.id,
          role: 'tool',
          content: JSON.stringify({ error: e.message })
        });
      }
    }

    return {
      tool_calls: choice.message.tool_calls,
      tool_results: toolResults
    };
  }
}

// 使用例
async function main() {
  const caller = new HolySheepToolCaller('YOUR_HOLYSHEEP_API_KEY');

  try {
    // 商品検索
    const result1 = await caller.chat('ワイヤレスヘッドフォン探してる、5万円以下のやつ');
    console.log('商品検索結果:', JSON.stringify(result1, null, 2));

    // 通貨変換
    const result2 = await caller.chat('100ドルって日本円でいくら?');
    console.log('通貨変換結果:', JSON.stringify(result2, null, 2));

  } catch (error) {
    console.error('Error:', error.message);
  }
}

main();

パラメータ検証の実装パターン

スキーマレベルでの検証

関数スキーマ自体に制約を定義することで、LLMが最初から正しいパラメータを生成する可能性を高められます。以下の点是に注意してください:

アプリケーションレベルでの検証

LLMは完璧ではないため、APIレベルでの検証は不可欠です。以下の多層防御を実装することを推奨します:

# 検証の多層防御パターン

class ValidationLayer:
    """パラメータ検証の多層防御"""
    
    def __init__(self):
        self.error_messages = []
    
    def validate(self, tool_name: str, args: dict, schema: dict) -> tuple[bool, list]:
        """
        パラメータ検証のメインエントリーポイント
        Returns: (is_valid, error_messages)
        """
        self.error_messages = []
        
        # ステップ1: 必須パラメータの存在確認
        self._check_required_fields(args, schema)
        
        # ステップ2: 型チェック
        self._check_types(args, schema)
        
        # ステップ3: 範囲チェック(数値・文字列長)
        self._check_ranges(args, schema)
        
        # ステップ4: 列挙値の検証
        self._check_enums(args, schema)
        
        # ステップ5: ビジネスロジック検証
        self._check_business_rules(tool_name, args)
        
        return len(self.error_messages) == 0, self.error_messages
    
    def _check_required_fields(self, args: dict, schema: dict):
        """必須フィールドの存在確認"""
        required = schema.get("required", [])
        for field in required:
            if field not in args or args[field] is None:
                self.error_messages.append(f"必須パラメータ '{field}' が不足しています")
    
    def _check_types(self, args: dict, schema: dict):
        """型チェック"""
        properties = schema.get("properties", {})
        for key, value in args.items():
            if key not in properties:
                continue
            
            spec = properties[key]
            expected_type = spec.get("type")
            
            if expected_type == "string" and not isinstance(value, str):
                self.error_messages.append(f"'{key}' は文字列である必要があります")
            elif expected_type == "number" and not isinstance(value, (int, float)):
                self.error_messages.append(f"'{key}' は数値である必要があります")
            elif expected_type == "integer" and not isinstance(value, int):
                self.error_messages.append(f"'{key}' は整数である必要があります")
            elif expected_type == "boolean" and not isinstance(value, bool):
                self.error_messages.append(f"'{key}' は真偽値である必要があります")
            elif expected_type == "array" and not isinstance(value, list):
                self.error_messages.append(f"'{key}' は配列である必要があります")
            elif expected_type == "object" and not isinstance(value, dict):
                self.error_messages.append(f"'{key}' はオブジェクトである必要があります")
    
    def _check_ranges(self, args: dict, schema: dict):
        """範囲チェック"""
        properties = schema.get("properties", {})
        for key, value in args.items():
            if key not in properties:
                continue
            
            spec = properties[key]
            
            # 数値範囲
            if isinstance(value, (int, float)):
                if "minimum" in spec and value < spec["minimum"]:
                    self.error_messages.append(f"'{key}' は {spec['minimum']} 以上の値が必要です")
                if "maximum" in spec and value > spec["maximum"]:
                    self.error_messages.append(f"'{key}' は {spec['maximum']} 以下の値が必要です")
            
            # 文字列長
            if isinstance(value, str):
                if "minLength" in spec and len(value) < spec["minLength"]:
                    self.error_messages.append(f"'{key}' は {spec['minLength']} 文字以上必要です")
                if "maxLength" in spec and len(value) > spec["maxLength"]:
                    self.error_messages.append(f"'{key}' は {spec['maxLength']} 文字以下にしてください")
            
            # 配列長
            if isinstance(value, list):
                if "minItems" in spec and len(value) < spec["minItems"]:
                    self.error_messages.append(f"'{key}' は {spec['minItems']} 個以上の要素が必要です")
                if "maxItems" in spec and len(value) > spec["maxItems"]:
                    self.error_messages.append(f"'{key}' は {spec['maxItems']} 個以下にしてください")
    
    def _check_enums(self, args: dict, schema: dict):
        """列挙値チェック"""
        properties = schema.get("properties", {})
        for key, value in args.items():
            if key not in properties:
                continue
            
            spec = properties[key]
            if "enum" in spec and value not in spec["enum"]:
                self.error_messages.append(
                    f"'{key}' は次のいずれかの値である必要があります: {', '.join(map(str, spec['enum']))}"
                )
    
    def _check_business_rules(self, tool_name: str, args: dict):
        """ビジネスロジック検証"""
        if tool_name == "search_products":
            if "min_price" in args and "max_price" in args:
                if args["min_price"] > args["max_price"]:
                    self.error_messages.append("最小価格は最大価格以下である必要があります")
        
        elif tool_name == "booking":
            if "start_date" in args and "end_date" in args:
                if args["start_date"] > args["end_date"]:
                    self.error_messages.append("開始日は終了日より前である必要があります")
        
        elif tool_name == "transfer":
            if args.get("amount", 0) > args.get("balance", 0):
                self.error_messages.append("送金額は残高を超えることはできません")

よくあるエラーと対処法

エラー1:Missing required parameter

原因: LLMが関数の必須パラメータを省略して呼び出す

解決策:

# パラメータ不足を検出した場合のフォールバック処理

def handle_missing_parameter(tool_name: str, missing_param: str, llm_response: dict) -> dict:
    """
    不足パラメータを検出した際の処理
    ユーザーに必要な情報を запросить
    """
    return {
        "status": "requires_input",
        "message": f"'{missing_param}' の値が必要です。提供してください。",
        "tool_name": tool_name,
        "missing_parameter": missing_param,
        "suggestion": f"例: 「{missing_param}: [値]」のように指定してください"
    }

使用例

try: validation_result = validation_layer.validate(tool_name, args, schema) if not validation_result[0]: # 最初の不足パラメータを通知 missing_param = extract_missing_param(validation_result[1]) return handle_missing_parameter(tool_name, missing_param, response) except ValidationError as e: print(f"Validation failed: {e}")

エラー2:Invalid parameter type

原因: LLMが型変換を誤って実行(例:数値を文字列として送信)

解決策:

# 型自動変換を用いた堅牢なパラメータ処理

import ast

def safe_parse_parameter(value: Any, expected_type: str) -> tuple[bool, Any]:
    """
    パラメータを安全な型に変換 محاولة
    Returns: (success, parsed_value)
    """
    if expected_type == "integer":
        try:
            if isinstance(value, str):
                # 文字列から整数への変換
                return True, int(float(value))
            return True, int(value)
        except (ValueError, TypeError