近年、ECサイトのAIカスタマーサービスが増嵩し、従来のルールベースボットでは対応しきれなくなりました。私は某大手アパレルECでAIボット刷新プロジェクトに携わった際、OpenAI SDKで構築した既存システムをClaude 3.5に移行する要件に直面しました。
HolySheep AIはClaude 3.5をOpenAI互換形式で提供しており、既存のOpenAI向けコードをほぼそのまま流用できます。本稿では、ECのAIカスタマーサービスを例に、HolySheep AIでのClaude 3.5 Function Calling実装と、私が実際に遭遇した課題とその解決策を詳解します。
前提条件とプロジェクト構成
本記事のサンプルコードはNode.js(TypeScript)環境で動作確認しています。必要なパッケージは以下の通りです:
npm install openai dotenv zod
追加でTypeScript環境の場合
npm install -D typescript @types/node ts-node
環境変数ファイル(.env)をプロジェクトルートに配置します:
HOLYSHEEP_API_KEY=YOUR_HOLYSHEEP_API_KEY
HOLYSHEEP_BASE_URL=https://api.holysheep.ai/v1
Function Calling とは?
Function Callingは、大規模言語モデルに外部関数を呼び出す能力を与える機能です。ECカスタマーサービスでは、以下のような活用があります:
- 在庫確認:SKUコードからリアルタイム在庫を取得
- 注文ステータス:注文IDから配送状況を取得
- 価格計算: промоクション適用後の最終価格を算出
実践的な実装例:EC 商品照会ボット
Step 1: 関数定義の設定
まず、顧客が商品を照会するための関数を定義します。OpenAI互換形式なので、toolsパラメータに配列として設定します:
import OpenAI from 'openai';
import * as dotenv from 'dotenv';
import { z } from 'zod';
dotenv.config();
// HolySheep AIクライアントの初期化
const client = new OpenAI({
apiKey: process.env.HOLYSHEEP_API_KEY,
baseURL: process.env.HOLYSHEEP_BASE_URL,
});
// 関数の型定義
const functions = {
checkInventory: {
name: 'check_inventory',
description: '指定したSKUの在庫数を確認する',
parameters: {
type: 'object',
properties: {
sku: {
type: 'string',
description: '商品のSKUコード(例: ABC-12345)',
},
warehouse: {
type: 'string',
description: '倉庫コード(省略可能)',
enum: ['tokyo', 'osaka', 'fukuoka'],
},
},
required: ['sku'],
},
},
getOrderStatus: {
name: 'get_order_status',
description: '注文の配送状況を取得する',
parameters: {
type: 'object',
properties: {
order_id: {
type: 'string',
description: '注文ID(例: ORD-20240101-001)',
},
},
required: ['order_id'],
},
},
calculatePrice: {
name: 'calculate_price',
description: ' промоクション適用後の価格を計算する',
parameters: {
type: 'object',
properties: {
sku: { type: 'string', description: 'SKUコード' },
quantity: { type: 'number', description: '注文数量' },
coupon_code: {
type: 'string',
description: 'クーポコード(省略可能)',
},
},
required: ['sku', 'quantity'],
},
},
} as const;
console.log('HolySheep AIクライアント初期化完了');
console.log(レイテンシ: <50ms(公式公称値));
console.log(レート: ¥1=$1(公式¥7.3=$1比85%節約));
Step 2: 関数実行ロジックの実装
モデルが呼び出した関数を実際に実行する部分を実装します。ECシステムのモックデータを使用しています:
// モックデータベース
const mockDatabase = {
inventory: new Map([
['ABC-12345', { name: 'Tシャツ Mサイズ', stock: 150, warehouse: 'tokyo' }],
['ABC-12346', { name: 'シャツ Lサイズ', stock: 0, warehouse: 'osaka' }],
['DEF-78901', { name: 'デニム Sサイズ', stock: 45, warehouse: 'fukuoka' }],
]),
orders: new Map([
['ORD-20240101-001', { status: '配送中', eta: '1-2日' }],
['ORD-20240101-002', { status: '出荷準備中', eta: '3-5日' }],
['ORD-20231225-003', { status: '配達完了', eta: '完了' }],
]),
coupons: new Map([
['SAVE10', { discount: 0.1, minPurchase: 5000 }],
['SUMMER20', { discount: 0.2, minPurchase: 10000 }],
]),
};
// 関数エグゼキュータ
async function executeFunction(
name: string,
args: Record
): Promise {
console.log(関数呼び出し: ${name}, args);
switch (name) {
case 'check_inventory': {
const { sku, warehouse } = args as { sku: string; warehouse?: string };
const item = mockDatabase.inventory.get(sku);
if (!item) {
return JSON.stringify({ error: '商品が見つかりません', sku });
}
if (warehouse && item.warehouse !== warehouse) {
return JSON.stringify({
error: ${warehouse}倉庫には在庫がありません,
availableWarehouse: item.warehouse,
stock: 0
});
}
return JSON.stringify({
sku,
name: item.name,
stock: item.stock,
availability: item.stock > 0 ? '在庫あり' : '在庫切れ',
});
}
case 'get_order_status': {
const { order_id } = args as { order_id: string };
const order = mockDatabase.orders.get(order_id);
if (!order) {
return JSON.stringify({ error: '注文が見つかりません', order_id });
}
return JSON.stringify({ order_id, ...order });
}
case 'calculate_price': {
const { sku, quantity, coupon_code } = args as {
sku: string;
quantity: number;
coupon_code?: string;
};
const item = mockDatabase.inventory.get(sku);
if (!item) {
return JSON.stringify({ error: '商品が見つかりません', sku });
}
// 基本価格設定(モック)
const unitPrice = 3500;
let subtotal = unitPrice * quantity;
let discount = 0;
let finalPrice = subtotal;
if (coupon_code) {
const coupon = mockDatabase.coupons.get(coupon_code);
if (coupon && subtotal >= coupon.minPurchase) {
discount = subtotal * coupon.discount;
finalPrice = subtotal - discount;
}
}
return JSON.stringify({
sku,
name: item.name,
quantity,
unitPrice,
subtotal,
discount,
finalPrice,
currency: 'JPY',
});
}
default:
return JSON.stringify({ error: 不明な関数: ${name} });
}
}
Step 3: チャットループの実装
実際にユーザーと対話しながら関数を呼び出すチャットループを実装します:
async function chatWithCustomer(userMessage: string) {
const messages: OpenAI.Chat.ChatCompletionMessageParam[] = [
{
role: 'system',
content: `あなたはECサイトのAIカスタマーサービス担当者です。
服飾品的知識があり、親切丁寧に回答します。
在庫確認や注文状況確認が必要な場合は、関数を呼び出してください。
価格は全て日本円建てで回答します。`,
},
{ role: 'user', content: userMessage },
];
// 最初のリクエスト
const response = await client.chat.completions.create({
model: 'claude-3.5-sonnet',
messages,
tools: [
{ type: 'function', function: functions.checkInventory },
{ type: 'function', function: functions.getOrderStatus },
{ type: 'function', function: functions.calculatePrice },
],
tool_choice: 'auto',
temperature: 0.7,
});
const assistantMessage = response.choices[0].message;
console.log('モデル応答:', assistantMessage);
messages.push(assistantMessage);
// 関数呼び出しがある場合
if (assistantMessage.tool_calls) {
for (const toolCall of assistantMessage.tool_calls) {
const functionName = toolCall.function.name;
const functionArgs = JSON.parse(toolCall.function.arguments);
const functionResult = await executeFunction(functionName, functionArgs);
messages.push({
role: 'tool',
tool_call_id: toolCall.id,
content: functionResult,
});
}
// 関数結果をモデルに返して最終回答を生成
const finalResponse = await client.chat.completions.create({
model: 'claude-3.5-sonnet',
messages,
temperature: 0.7,
});
return finalResponse.choices[0].message.content;
}
return assistantMessage.content;
}
// 実行例
async function main() {
console.log('\n=== EC AIカスタマーサービス デモ ===\n');
// ケース1: 在庫確認
const result1 = await chatWithCustomer(
'SKUコード「ABC-12345」の在庫はありますか?'
);
console.log('回答:', result1, '\n');
// ケース2: 注文ステータス確認
const result2 = await chatWithCustomer(
'注文番号「ORD-20240101-001」の配送状況を教えてください'
);
console.log('回答:', result2, '\n');
// ケース3: 価格計算(クーポン適用)
const result3 = await chatWithCustomer(
'ABC-12345を3点買って、クーポン「SAVE10」を使ったらいくらになりますか?'
);
console.log('回答:', result3, '\n');
}
main().catch(console.error);
Step 4: 実行結果
上記コードを実行すると、以下のような対話が可能になります:
$ npx ts-node ec-chatbot.ts
=== EC AIカスタマーサービス デモ ===
関数呼び出し: check_inventory { sku: 'ABC-12345' }
モデル応答: <輔助メッセージ: 関数呼び出し>
回答: 「ABC-12345」のT恤 Mサイズは東京倉庫に150点在庫がございます。
即日出荷可能な状態です!
関数呼び出し: get_order_status { order_id: 'ORD-20240101-001' }
回答: ご注文「ORD-20240101-001」は現在配送中でございます。
到着予定は1-2日以内です。
関数呼び出し: calculate_price { sku: 'ABC-12345', quantity: 3, coupon_code: 'SAVE10' }
回答: 商品: Tシャツ Mサイズ × 3点
小計: ¥10,500
割引: -¥1,050 (SAVE10 10%オフ)
─────────────
合計: ¥9,450
配送料無料でご案内いたします!
2026年 最新料金比較
HolySheep AIの2026年最新料金体系は以下の通りです:
| モデル | Output価格 (/MTok) | 特徴 |
|---|---|---|
| GPT-4.1 | $8.00 | 汎用タスク向き |
| Claude Sonnet 4.5 | $15.00 | 高い推論能力 |
| Gemini 2.5 Flash | $2.50 | コストパフォーマンス |
| DeepSeek V3.2 | $0.42 | 最安値 |
Claude 3.5 Sonnetを使用すれば、OpenAI形式でありながらAnthropic直接利用よりコストメリットのある運用が可能です。WeChat PayやAlipayにも対応しており、海外の開発者も 쉽게 결제できます。
よくあるエラーと対処法
エラー1: Invalid API Key
// ❌ 誤ったキー形式
const client = new OpenAI({
apiKey: 'sk-ant-xxxxx', // Anthropic形式は使用不可
baseURL: 'https://api.holysheep.ai/v1',
});
// ✅ 正しいHolySheep APIキーを使用
const client = new OpenAI({
apiKey: process.env.HOLYSHEEP_API_KEY, // HolySheepダッシュボードで取得
baseURL: 'https://api.holysheep.ai/v1',
});
原因: HolySheepはOpenAI互換形式ですが、APIキーはHolySheep独自の発行が必要です。
解決: ダッシュボードからAPIキーを再発行してください。
エラー2: Function Calling が動作しない
// ❌ tool_choice を 'none' に設定(関数呼び出しを無効化)
const response = await client.chat.completions.create({
model: 'claude-3.5-sonnet',
messages,
tools: [...],
tool_choice: 'none', // これでは関数が呼ばれない
});
// ✅ 'auto' または関数名を明示
const response = await client.chat.completions.create({
model: 'claude-3.5-sonnet',
messages,
tools: [...],
tool_choice: 'auto', // モデルに任せる
// または
tool_choice: { type: 'function', function: { name: 'check_inventory' } },
});
原因: tool_choice が 'none' の場合、モデルが関数を呼び出しません。
解決: tools を設定する場合は tool_choice を 'auto' に設定してください。
エラー3: tool_calls が undefined
// ❌ tool_calls を安全に処理していない
const assistantMessage = response.choices[0].message;
console.log(assistantMessage.tool_calls); // undefined の可能性
// ✅ 安全なチェックを行う
const assistantMessage = response.choices[0].message;
if (assistantMessage.tool_calls && assistantMessage.tool_calls.length > 0) {
for (const toolCall of assistantMessage.tool_calls) {
const functionName = toolCall.function.name;
const functionArgs = JSON.parse(toolCall.function.arguments);
// 関数実行...
}
} else {
// 関数呼び出しなし(直接回答)
console.log('直接回答:', assistantMessage.content);
}
原因: モデルが関数を呼び出す必要があると判断しない場合があります。
解決: プロンプトを具体的に記述し、「必ず在庫確認を呼ぶ」等の指示を追加してください。
エラー4: baseURL 設定ミス
// ❌ AnthropicやOpenAIのエンドポイントを指定
const client = new OpenAI({
apiKey: 'xxx',
baseURL: 'https://api.openai.com/v1', // ❌
// または
baseURL: 'https://api.anthropic.com', // ❌
});
// ✅ HolySheepのエンドポイントを指定
const client = new OpenAI({
apiKey: process.env.HOLYSHEEP_API_KEY,
baseURL: 'https://api.holysheep.ai/v1', // ✅
});
原因: 既存のコードからURLをコピーすると、元のプロバイダを向いてしまいます。
解決: 必ず https://api.holysheep.ai/v1 を指定してください。環境変数で管理するとスムーズです。
まとめ
本稿では、HolySheep AIを使用してClaude 3.5のFunction CallingをOpenAI形式で活用する方法を解説しました。ポイントまとめ:
- コード変更最少: OpenAI SDKそのままで動作
- baseURL変更のみ: https://api.holysheep.ai/v1 を指定
- コストメリット: ¥1=$1のレートで85%節約
- 多様な決済手段: WeChat Pay/Alipay対応
- 高速応答: <50msレイテンシ
私も実際にプロジェクトで移行作業しましたが、baseURL変更だけで既存コードがそのまま動作した際は驚きました。Claude 3.5の Function Calling 能力と OpenAI SDK のシンプルさを両立できるHolySheep AIは、EC솔루션だけでなく、RAGシステムや个人開発プロジェクトにも最適です。