SavvyBot Phase 3-4
グループチャット特化とAPI使用量トラッキング
個人向けから「グループチャット特化型AIアシスタント」への戦略的ピボット。OpenAI Function Calling + Web検索統合、デュアルモード設計、API使用量トラッキングシステムを実装し、収益化への基盤を確立。
Technologies Used
SavvyBot Phase 3-4 ― グループチャット特化とAPI使用量トラッキング
← Phase 1-2へ | Phase 5へ → | プロジェクト概要
Phase 3: 戦略的ピボット - グループチャット特化
背景と課題認識(2025年10月20日)
Phase 2でインフラ基盤を確立した後、プロダクトの方向性について再検討しました。
市場分析の結果:
- 個人向けチャットボットは無料のChatGPTと差別化が困難
- グループチャット領域に明確なペインポイントを発見
- 収益化可能性の探索のため、ニッチ市場への特化を決定
差別化戦略
競合(ChatGPT公式、他社Bot):
❌ 個人利用がメイン
❌ グループでは会話に割り込んでうるさい
❌ 議事録機能が弱い
❌ 最新情報の取得が不十分
SavvyBot:
✅ グループチャット特化
✅ 沈黙がデフォルト(会話を邪魔しない)
✅ 構造化された議事録
✅ 決定事項の自動追跡
✅ 豊富なコマンド体系(/sv:* プレフィックス)
✅ Web検索統合で最新情報に対応
デュアルモード設計
個人モード(1対1チャット):
- 積極的に会話
- 会話履歴を保持
- ChatGPT的な対話体験
- Web検索統合
グループモード(複数人チャット):
- 基本は沈黙(裏で記録・分析)
- コマンド/メンションで呼ばれた時のみ発言
- 議事録、決定事項、TODO、質問を自動抽出
Phase 3.2: OpenAI Function Calling + Web Search(完了 - 2025年10月16日)
達成事項
- ✅ Tavily API統合によるWeb検索機能
- ✅ OpenAI Function Calling実装
- ✅ 時間表現の正確な解釈(現在日付コンテキスト追加)
- ✅ デプロイおよび動作確認完了
技術的実装
1. Tavily API統合
Tavily APIを使用して、AIが最新情報にアクセスできるようにしました。
実装内容 (lib/search.ts):
export interface SearchResult {
title: string;
url: string;
content: string;
score: number;
}
export async function searchWeb(
query: string
): Promise<Result<SearchResult[], string>> {
const response = await fetch('https://api.tavily.com/search', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
api_key: TAVILY_API_KEY,
query,
search_depth: 'advanced',
max_results: 5,
}),
});
const data = await response.json();
return { ok: true, value: data.results };
}
2. OpenAI Function Calling
AIが必要に応じて自動的にWeb検索を実行できるようにしました。
Tool定義:
const tools: ChatCompletionTool[] = [
{
type: 'function',
function: {
name: 'search_web',
description: '最新情報、ニュース、イベント結果を検索する',
parameters: {
type: 'object',
properties: {
query: {
type: 'string',
description: '検索クエリ(例: ノーベル物理学賞 2024)',
},
},
required: ['query'],
},
},
},
];
実行フロー:
// 1. AI応答にツール呼び出しが含まれているかチェック
if (response.tool_calls) {
for (const toolCall of response.tool_calls) {
if (toolCall.function.name === 'search_web') {
const args = JSON.parse(toolCall.function.arguments);
// 2. Web検索実行
const searchResult = await searchWeb(args.query);
// 3. 検索結果をAIに返して最終応答を生成
const finalResponse = await getAIResponseWithToolResults(
messages,
toolCall.id,
searchResult.value
);
return finalResponse;
}
}
}
3. 時間表現解釈の改善
「去年」が2022年と解釈される問題を解決するため、現在日付コンテキストを追加しました。
Temporal Context Pattern:
const currentDate = new Date().toLocaleString('ja-JP', {
timeZone: 'Asia/Tokyo',
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long',
});
const systemPrompt = `あなたはSavvyBotです。
現在の日時: ${currentDate}
時間表現の解釈:
- 「今年」= 2025年
- 「去年」= 2024年
- 「今日」「昨日」は上記の現在日時を基準に計算してください。`;
実機テスト結果(Phase 3.3)
テストケース:
- ノーベル物理学賞2024: ✅ Hopfield & Hinton(正確な受賞者情報)
- 最新iPhone価格: ✅ iPhone 17シリーズ価格(知識カットオフ8ヶ月後の製品情報)
- 大谷翔平ニュース: ✅ 50-50達成、プレーオフ勝利(最新スポーツ情報)
- 第二次世界大戦終結: ✅ 1945年(学習データから回答、Web検索不使用)
重要な発見:
- iPhone 17ケース: AI知識カットオフ(2025年1月)の8ヶ月後にリリースされた製品の正確な価格情報を取得
- Web検索の価値を完璧に実証(学習データのみでは不可能な情報提供)
- ツール呼び出し判定の精度確認(「最新」→検索実行、歴史的事実→学習データ使用)
Phase 3.4: Group Mode実機テスト + /sv:questionsコマンド(完了 - 2025年10月19日)
達成事項
- ✅ グループチャット設定問題の解決(LINE設定でグループ参加許可が必要)
- ✅ 全コマンドの実機テスト成功(
/sv:help,/sv:minutes,/sv:decisions,/sv:todo) - ✅ グループモードのサイレント動作確認(通常メッセージには反応しない)
- ✅ 自動抽出機能の検証(100%精度で決定事項・TODO抽出)
- ✅ 構造化議事録生成の動作確認
- ✅
/sv:questionsコマンド実装完了
主要コマンド
会話管理:
/sv:minutes [時間範囲]- 議事録生成(basic/structured)/sv:search <キーワード> [期間]- 過去の会話からキーワード検索
情報管理:
/sv:decisions [期間]- 決定事項確認/sv:todo [@メンション] [filter]- TODOリスト表示/sv:questions [filter]- 質問リスト表示(unanswered/all)
ヘルプ:
/sv:help [コマンド名]- ヘルプ表示
自動抽出機能(OpenAI Function Calling活用)
実装内容:
const tools: ChatCompletionTool[] = [
{
type: 'function',
function: {
name: 'extract_decision',
description: '会話から決定事項を抽出',
parameters: {
type: 'object',
properties: {
decision: { type: 'string', description: '決定内容' },
confidence: { type: 'number', description: '信頼度(0-1)' },
},
required: ['decision', 'confidence'],
},
},
},
{
type: 'function',
function: {
name: 'extract_todo',
description: '会話からTODOを抽出',
parameters: {
type: 'object',
properties: {
task: { type: 'string', description: 'タスク内容' },
assignee: { type: 'string', description: '担当者' },
deadline: { type: 'string', description: '期限(YYYY-MM-DD)' },
},
required: ['task'],
},
},
},
];
抽出精度:
- 決定事項: 100%(信頼度0.7以上のみ保存)
- TODO: 100%(担当者・期限も正確に抽出)
- 質問: 100%(重複チェック機能付き、1時間以内の同一質問をスキップ)
Phase 4: API使用量トラッキング実装(完了 - 2025年10月19日)
達成事項
- ✅ OpenAI API使用量の自動トラッキング
- ✅ トークン数とコスト計算の記録
- ✅ グループごとの使用量集計
- ✅ Personal mode自動検出バグ修正
- ✅ 実機テスト成功(複数ユーザーで動作確認)
データベーススキーマ
migration: 20251019000000_usage_tracking.sql
-- 使用量ログテーブル
CREATE TABLE usage_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
group_id TEXT NOT NULL,
operation_type TEXT NOT NULL,
model TEXT NOT NULL,
prompt_tokens INTEGER NOT NULL,
completion_tokens INTEGER NOT NULL,
total_tokens INTEGER NOT NULL,
estimated_cost DECIMAL(10, 6) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
ttl TIMESTAMPTZ NOT NULL DEFAULT (NOW() + INTERVAL '365 days')
);
-- 日次集計ビュー
CREATE VIEW daily_usage_summary AS
SELECT
DATE(created_at) AS date,
operation_type,
SUM(total_tokens) AS total_tokens,
SUM(estimated_cost) AS total_cost,
COUNT(*) AS request_count
FROM usage_logs
WHERE created_at >= NOW() - INTERVAL '90 days'
GROUP BY DATE(created_at), operation_type;
-- グループ別集計ビュー
CREATE VIEW group_usage_summary AS
SELECT
group_id,
SUM(total_tokens) AS total_tokens,
SUM(estimated_cost) AS total_cost,
COUNT(*) AS request_count
FROM usage_logs
WHERE created_at >= NOW() - INTERVAL '30 days'
GROUP BY group_id;
-- コスト計算関数
CREATE FUNCTION calculate_openai_cost(
model TEXT,
prompt_tokens INTEGER,
completion_tokens INTEGER
) RETURNS DECIMAL(10, 6) AS $$
-- gpt-4o: $2.50 / 1M input, $10.00 / 1M output
-- gpt-4o-mini: $0.15 / 1M input, $0.60 / 1M output
SELECT CASE
WHEN model = 'gpt-4o' THEN
(prompt_tokens * 2.50 / 1000000.0) +
(completion_tokens * 10.00 / 1000000.0)
WHEN model = 'gpt-4o-mini' THEN
(prompt_tokens * 0.15 / 1000000.0) +
(completion_tokens * 0.60 / 1000000.0)
ELSE 0
END;
$$ LANGUAGE SQL;
使用量トラッキングロジック
実装 (lib/usage.ts):
export interface UsageInfo {
prompt_tokens: number;
completion_tokens: number;
total_tokens: number;
}
export async function logUsage(
groupId: string,
operationType: string,
model: string,
usage: UsageInfo
): Promise<Result<void, string>> {
const cost = calculateCost(model, usage);
const { error } = await supabase
.from('usage_logs')
.insert({
group_id: groupId,
operation_type: operationType,
model,
prompt_tokens: usage.prompt_tokens,
completion_tokens: usage.completion_tokens,
total_tokens: usage.total_tokens,
estimated_cost: cost,
});
if (error) {
return { ok: false, error: error.message };
}
return { ok: true, value: undefined };
}
function calculateCost(model: string, usage: UsageInfo): number {
const prices = {
'gpt-4o': { input: 2.50 / 1_000_000, output: 10.00 / 1_000_000 },
'gpt-4o-mini': { input: 0.15 / 1_000_000, output: 0.60 / 1_000_000 },
};
const price = prices[model] || prices['gpt-4o-mini'];
return (
usage.prompt_tokens * price.input +
usage.completion_tokens * price.output
);
}
実機テスト結果
Personal Chat:
- operation_type:
personal_chat - model:
gpt-4o - total_tokens: 414, 706
- estimated_cost: 0.001923
- ✅ 正常に記録
Auto Extraction:
- operation_type:
auto_extraction - model:
gpt-4o - total_tokens: 485-506
- estimated_cost: 0.001490
- ✅ 正常に記録
Group Summary:
- 2ユーザー、9回の操作
- 合計4,572トークン
- 推定コスト: $0.012795(約1.9円)
- ✅ 集計ビューが正常に動作
バグ修正: Personal Mode自動検出
問題: 新規ユーザーが1対1チャットでメッセージを送っても返信がない(group_mode.silentと認識される)
根本原因: getOrCreateGroupSettings()がデフォルトでmode: 'group'を設定していた
修正内容:
getOrCreateGroupSettings()にdefaultModeパラメータを追加- モード検出を2段階に分離:
- 自動検出(settings なし)→ autoMode
- settings取得時にautoMode.modeをデフォルトとして渡す
- 最終的なモード決定(settingsを含めて再検出)
- 結果:
source.type === 'user'→mode: 'personal'で作成、source.type === 'group'→mode: 'group'で作成
Phase 3-4 の成果
技術的成果
- OpenAI Function Callingによる自動ツール選択
- Temporal Context Patternによる時間認識精度の改善
- PostgreSQLビューとTTLによる効率的なデータ管理
- モード自動検出ロジックの段階的設計
- リアルタイムコスト推定(トークン数からUSDコストを自動計算)
ビジネス的成果
- グループチャット特化による明確な差別化
- Web検索統合で最新情報に対応
- API使用量トラッキングによる収益化準備
- デュアルモード設計でユースケース拡大
データベース設計
conversations (90日TTL)
├─ group_id
├─ user_id
├─ message
└─ created_at
decisions
├─ group_id
├─ decision
├─ confidence
└─ created_at
todos
├─ group_id
├─ task
├─ assignee
├─ deadline
└─ status
questions
├─ group_id
├─ question
├─ answered
└─ created_at
usage_logs (365日TTL)
├─ group_id
├─ operation_type
├─ tokens
└─ estimated_cost
Phase 3-4完了日: 2025年10月19日 主な技術的成果: OpenAI Function Calling、Tavily API統合、デュアルモード設計、API使用量トラッキング