Claude API Function Calling で複雑なLLMワークフローを実装する完全ガイド【2026年4月最新】
Claude 3.5 Sonnet の Function Calling を使った実践的な実装方法を解説。エラーハンドリング、マルチステップ処理、コスト最適化まで網羅した開発者向けガイド。
Claude API Function Calling とは?なぜ今注目されるのか
2024年10月にリリースされた Claude 3.5 Sonnet の Function Calling(Tool Use)機能は、2026年4月現在、LLMを使った複雑なワークフロー構築の標準手法として確立しています。
従来のプロンプトベースのアプローチでは、「外部APIを呼び出してその結果を使って次の処理を実行する」といったマルチステップの処理を実装する際、プロンプトインジェクションのリスクや出力パースの不安定さが課題でした。
Function Calling は、LLMが構造化されたJSON形式で関数呼び出しを返す仕組みにより、これらの問題を根本から解決します。ChatGPT の Function Calling と異なり、Claude は複数ツールの並列呼び出しやエラー後の自動リトライ提案など、より実用的な機能を備えています。
本記事では、2026年4月時点の最新ドキュメント(Anthropic公式 2026年3月29日更新)に基づき、実際のコード例とともに実装方法を解説します。
Claude Function Calling の基本実装
基本的なツール定義と呼び出し
Claude API でツールを使用するには、tools パラメータでツールのスキーマを定義し、モデルに渡します。
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
// ツールの定義
const tools = [
{
name: "get_weather",
description: "指定された都市の現在の天気情報を取得します",
input_schema: {
type: "object",
properties: {
city: {
type: "string",
description: "都市名(例: Tokyo, New York)",
},
unit: {
type: "string",
enum: ["celsius", "fahrenheit"],
description: "温度の単位",
},
},
required: ["city"],
},
},
];
// Claude API 呼び出し
const message = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 1024,
tools: tools,
messages: [
{
role: "user",
content: "東京の現在の天気を教えてください",
},
],
});
console.log(message.content);
ツール実行結果の返却とマルチターン処理
Claude がツールの使用を提案した場合、stop_reason が "tool_use" になります。この場合、開発者側でツールを実行し、結果を次のリクエストで返す必要があります。
// Claude のレスポンスからツール呼び出しを検出
const toolUseBlock = message.content.find(
(block) => block.type === "tool_use"
);
if (toolUseBlock && toolUseBlock.type === "tool_use") {
// ツールを実行(例: 天気API呼び出し)
const weatherData = await fetchWeatherAPI(toolUseBlock.input.city);
// 実行結果を Claude に返す
const followUpMessage = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 1024,
tools: tools,
messages: [
{
role: "user",
content: "東京の現在の天気を教えてください",
},
{
role: "assistant",
content: message.content, // Claude の最初のレスポンス全体
},
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: toolUseBlock.id,
content: JSON.stringify(weatherData),
},
],
},
],
});
console.log(followUpMessage.content);
}
処理フローの全体像
sequenceDiagram
participant User as ユーザー
participant App as アプリケーション
participant Claude as Claude API
participant Tool as 外部ツール/API
User->>App: "東京の天気を教えて"
App->>Claude: messages.create() + tools定義
Claude->>App: stop_reason: "tool_use"<br/>tool_use block
App->>Tool: fetchWeatherAPI("Tokyo")
Tool->>App: { temp: 15, condition: "晴れ" }
App->>Claude: tool_result を含む messages
Claude->>App: 最終回答テキスト
App->>User: "東京は現在15度、晴れです"
上図は Claude Function Calling の典型的な処理フローを示しています。ユーザーの質問→ツール提案→実行→結果返却→最終回答という流れが1サイクルです。
複数ツールの並列実行と依存関係の制御
並列実行可能なツールの定義
Claude 3.5 Sonnet は1回のレスポンスで複数のツールを同時に提案できます。これにより、独立した処理を並列実行してレイテンシを削減できます。
const tools = [
{
name: "get_stock_price",
description: "指定された銘柄の現在の株価を取得",
input_schema: {
type: "object",
properties: {
symbol: { type: "string", description: "銘柄コード(例: AAPL)" },
},
required: ["symbol"],
},
},
{
name: "get_company_news",
description: "指定された企業の最新ニュースを取得",
input_schema: {
type: "object",
properties: {
company: { type: "string", description: "企業名" },
},
required: ["company"],
},
},
{
name: "calculate_portfolio_value",
description: "ポートフォリオの現在価値を計算",
input_schema: {
type: "object",
properties: {
holdings: {
type: "array",
items: {
type: "object",
properties: {
symbol: { type: "string" },
shares: { type: "number" },
},
},
},
},
required: ["holdings"],
},
},
];
const message = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 2048,
tools: tools,
messages: [
{
role: "user",
content: "AppleとMicrosoftの株価と最新ニュースを調べてください",
},
],
});
// 複数のツール呼び出しを検出
const toolUseBlocks = message.content.filter(
(block) => block.type === "tool_use"
);
console.log(`${toolUseBlocks.length} 個のツールが並列実行されます`);
// 出力例: "4 個のツールが並列実行されます"
// get_stock_price(AAPL), get_stock_price(MSFT), get_company_news(Apple), get_company_news(Microsoft)
並列実行の実装パターン
// 並列実行とエラーハンドリング
const toolResults = await Promise.allSettled(
toolUseBlocks.map(async (toolUse) => {
if (toolUse.type !== "tool_use") return null;
try {
let result;
switch (toolUse.name) {
case "get_stock_price":
result = await fetchStockPrice(toolUse.input.symbol);
break;
case "get_company_news":
result = await fetchCompanyNews(toolUse.input.company);
break;
default:
throw new Error(`未知のツール: ${toolUse.name}`);
}
return {
type: "tool_result" as const,
tool_use_id: toolUse.id,
content: JSON.stringify(result),
};
} catch (error) {
// エラーをClaudeに返す(エラー処理の推奨パターン)
return {
type: "tool_result" as const,
tool_use_id: toolUse.id,
content: JSON.stringify({ error: error.message }),
is_error: true,
};
}
})
);
// 成功した結果のみを抽出
const successfulResults = toolResults
.filter((r) => r.status === "fulfilled" && r.value !== null)
.map((r) => (r.status === "fulfilled" ? r.value : null));
ツール間の依存関係を持つワークフロー
一部のツールが他のツールの結果に依存する場合、複数回のAPI呼び出しを連鎖させます。
// ステップ1: ユーザーIDから注文履歴を取得
const step1 = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 1024,
tools: [
{
name: "get_user_orders",
description: "ユーザーの注文履歴を取得",
input_schema: {
type: "object",
properties: {
user_id: { type: "string" },
},
required: ["user_id"],
},
},
],
messages: [
{ role: "user", content: "ユーザーID user_123 の注文履歴を分析して" },
],
});
// ツール実行(注文履歴取得)
const orders = await getUserOrders("user_123");
// ステップ2: 注文履歴から推奨商品を計算
const step2 = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 1024,
tools: [
{
name: "recommend_products",
description: "注文履歴から推奨商品を計算",
input_schema: {
type: "object",
properties: {
order_history: { type: "array" },
},
required: ["order_history"],
},
},
],
messages: [
{ role: "user", content: "ユーザーID user_123 の注文履歴を分析して" },
{ role: "assistant", content: step1.content },
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: step1.content.find((b) => b.type === "tool_use")!.id,
content: JSON.stringify(orders),
},
],
},
],
});
flowchart LR
A["ユーザー入力"] --> B["Claude API 呼び出し 1<br/>get_user_orders"]
B --> C["注文履歴取得<br/>外部API"]
C --> D["Claude API 呼び出し 2<br/>recommend_products"]
D --> E["推奨商品計算<br/>外部API"]
E --> F["最終レスポンス"]
上図は依存関係のあるツール呼び出しのフローです。前のツールの結果が次のツールの入力になる場合、複数回のAPI呼び出しが必要です。
エラーハンドリングとリトライ戦略
is_error フラグを使ったエラー通知
Claude 3.5 では、ツール実行失敗時に is_error: true フラグを付けて結果を返すことで、モデルにエラー発生を明示的に伝えることができます。
const toolResult = {
type: "tool_result" as const,
tool_use_id: toolUse.id,
content: JSON.stringify({
error: "API rate limit exceeded. Please try again in 60 seconds.",
error_code: "RATE_LIMIT",
retry_after: 60,
}),
is_error: true, // エラーフラグ
};
const response = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 1024,
tools: tools,
messages: [
{ role: "user", content: "最新のニュースを取得して" },
{ role: "assistant", content: previousResponse.content },
{ role: "user", content: [toolResult] },
],
});
// Claude は自動的に代替案を提案する
// 例: "APIのレート制限に達しました。1分後に再試行するか、別の情報源を使用しますか?"
自動リトライとエクスポネンシャルバックオフ
async function executeToolWithRetry(
toolName: string,
input: any,
maxRetries = 3
) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await executeTool(toolName, input);
} catch (error) {
if (attempt === maxRetries - 1) throw error;
const waitTime = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
console.log(`リトライ ${attempt + 1}/${maxRetries} (${waitTime}ms 待機)`);
await new Promise((resolve) => setTimeout(resolve, waitTime));
}
}
}
部分的な成功の処理
複数ツールの並列実行時、一部が失敗した場合でも成功した結果を Claude に返すことで、可能な範囲で回答を生成できます。
const toolResults = await Promise.allSettled(toolUseBlocks.map(executeTool));
const resultsForClaude = toolResults.map((result, index) => {
const toolUse = toolUseBlocks[index];
if (result.status === "fulfilled") {
return {
type: "tool_result" as const,
tool_use_id: toolUse.id,
content: JSON.stringify(result.value),
};
} else {
return {
type: "tool_result" as const,
tool_use_id: toolUse.id,
content: JSON.stringify({ error: result.reason.message }),
is_error: true,
};
}
});
// 部分的な結果でも Claude に返す
const response = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 1024,
tools: tools,
messages: [
{ role: "user", content: originalQuery },
{ role: "assistant", content: previousResponse.content },
{ role: "user", content: resultsForClaude },
],
});
// Claude: "株価は取得できましたが、ニュースAPIがエラーを返しました。株価情報のみでよろしいですか?"
tool_choice による実行制御とコスト最適化
tool_choice パラメータの使い方
tool_choice パラメータを使うことで、ツール使用の強制/禁止/特定ツール指定が可能です。
// パターン1: ツール使用を強制(必ず何かしらのツールを呼び出す)
const forceToolUse = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 1024,
tools: tools,
tool_choice: { type: "any" }, // いずれかのツールを必ず使用
messages: [{ role: "user", content: "データを取得して" }],
});
// パターン2: 特定のツールを強制
const forceSpecificTool = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 1024,
tools: tools,
tool_choice: { type: "tool", name: "get_weather" }, // get_weather を必ず使用
messages: [{ role: "user", content: "今日の予定を教えて" }],
});
// パターン3: ツール使用を自動判断(デフォルト)
const autoToolUse = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 1024,
tools: tools,
tool_choice: { type: "auto" }, // Claude が必要に応じて判断
messages: [{ role: "user", content: "こんにちは" }],
});
コスト最適化のベストプラクティス
2026年4月現在、Claude 3.5 Sonnet の料金は入力: $3.00 / 1M tokens、出力: $15.00 / 1M tokensです。Function Calling を多用すると、以下の理由でコストが増加します。
- ツール定義のスキーマがトークンを消費(毎回リクエストに含まれる)
- マルチターンの会話履歴が累積(tool_result を含む全履歴を毎回送信)
// ❌ コストが高い例: 不要なツールまで毎回定義
const allTools = [
weatherTool,
stockTool,
newsTool,
databaseTool,
emailTool,
calendarTool,
]; // 6個のツール × 平均200トークン = 1200トークン/リクエスト
// ✅ コスト最適化: 必要なツールのみ動的に選択
function selectRelevantTools(userQuery: string) {
if (userQuery.includes("天気")) return [weatherTool];
if (userQuery.includes("株価")) return [stockTool];
return []; // ツール不要な場合は空配列
}
const message = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 1024,
tools: selectRelevantTools(userInput), // 動的に絞り込む
messages: [{ role: "user", content: userInput }],
});
Prompt Caching との組み合わせ
2026年3月のアップデートで、Function Calling がPrompt Caching と併用可能になりました。ツール定義を system プロンプト内でキャッシュすることで、トークンコストを最大90%削減できます。
const response = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 1024,
system: [
{
type: "text",
text: "あなたは天気予報アシスタントです。",
cache_control: { type: "ephemeral" }, // この部分をキャッシュ
},
],
tools: tools.map((tool) => ({
...tool,
cache_control: { type: "ephemeral" }, // ツール定義もキャッシュ
})),
messages: [{ role: "user", content: "東京の天気は?" }],
});
// 2回目以降のリクエスト: キャッシュヒットで入力トークンが1/10に
実践的なユースケース: RAGシステムの実装
ベクトル検索ツールの統合
const ragTools = [
{
name: "search_knowledge_base",
description: "社内ドキュメントから関連情報を検索",
input_schema: {
type: "object",
properties: {
query: { type: "string", description: "検索クエリ" },
top_k: {
type: "number",
description: "取得する上位結果の数",
default: 5,
},
},
required: ["query"],
},
},
{
name: "get_document_metadata",
description: "ドキュメントのメタデータ(作成日、著者など)を取得",
input_schema: {
type: "object",
properties: {
document_id: { type: "string" },
},
required: ["document_id"],
},
},
];
// RAGワークフロー
const ragResponse = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 2048,
tools: ragTools,
messages: [
{
role: "user",
content: "2025年度の売上目標について教えて",
},
],
});
// Claude が自動的に search_knowledge_base("2025年度 売上目標") を呼び出し
const searchTool = ragResponse.content.find(
(b) => b.type === "tool_use" && b.name === "search_knowledge_base"
);
if (searchTool && searchTool.type === "tool_use") {
// ベクトル検索実行(Pinecone / Weaviate / Qdrant など)
const searchResults = await vectorDB.search(searchTool.input.query, {
top_k: searchTool.input.top_k || 5,
});
// 検索結果をClaudeに返す
const finalResponse = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 2048,
tools: ragTools,
messages: [
{ role: "user", content: "2025年度の売上目標について教えて" },
{ role: "assistant", content: ragResponse.content },
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: searchTool.id,
content: JSON.stringify(searchResults),
},
],
},
],
});
console.log(finalResponse.content);
// Claude: "社内資料によると、2025年度の売上目標は前年比120%の15億円です(出典: 経営計画書2025.pdf, 2024年12月作成)"
}
情報源の引用と信頼性向上
// 検索結果にメタデータを含める
const searchResultWithMetadata = searchResults.map((result) => ({
content: result.text,
metadata: {
document_id: result.id,
title: result.title,
created_at: result.created_at,
author: result.author,
confidence_score: result.score, // ベクトル検索の類似度スコア
},
}));
// Claude に引用を促すシステムプロンプト
const response = await client.messages.create({
model: "claude-3-5-sonnet-20250929",
max_tokens: 2048,
system:
"回答する際は必ず情報源(ドキュメント名、作成日)を明示してください。",
tools: ragTools,
messages: [
/* ... */
],
});
// 出力例:
// "2025年度の売上目標は15億円です。
// **出典**: 経営計画書2025.pdf(2024年12月1日作成、著者: 経営企画部)
// 信頼度スコア: 0.94"
まとめ
Claude API の Function Calling は、2026年4月現在、以下の点で実用的なLLMワークフロー構築の中核技術となっています。
- 構造化された出力: JSON Schema による厳密なパラメータ検証
- 並列実行: 独立したツールを同時呼び出しでレイテンシ削減
- エラーハンドリング:
is_errorフラグによる明示的なエラー通知 - コスト最適化: Prompt Caching との併用で最大90%のトークン削減
- 実用的なユースケース: RAG、マルチステップ分析、外部API統合
実装のポイント:
- ツール定義は必要最小限に絞り、動的に選択する
- 並列実行可能なツールは
Promise.allSettledでまとめて実行 - エラー時は
is_error: trueで Claude に通知し、代替案を提案させる tool_choiceで実行を制御し、不要なAPI呼び出しを防ぐ- Prompt Caching でツール定義をキャッシュし、コストを削減
これらのテクニックを組み合わせることで、信頼性とコスト効率を両立した複雑なAIシステムを構築できます。
参考リンク
- Anthropic公式ドキュメント: Tool use (function calling) - 2026年3月29日更新
- Anthropic公式ブログ: Introducing Claude 3.5 Sonnet - 2024年10月発表
- Anthropic Cookbook: Tool Use Examples - GitHub公式サンプル集
- Prompt Caching with Claude - Anthropic公式ドキュメント
- Claude API Pricing (2026年4月最新) - Anthropic公式料金ページ