分類ツールの実装
「エージェントの最初のステップは、問い合わせのカテゴリ分類だ。」
田中VPoEが説明する。
「BERTモデルとFAQ検索を組み合わせて、高精度な分類ツールを実装しよう。確信度が低い場合のフォールバックも忘れるな。」
分類ツールの実装
from langchain_core.tools import tool
import torch
from transformers import AutoTokenizer, AutoModelForSequenceClassification
class InquiryClassifier:
"""問い合わせ分類器"""
def __init__(self, model_path, label_map):
self.tokenizer = AutoTokenizer.from_pretrained(model_path)
self.model = AutoModelForSequenceClassification.from_pretrained(model_path)
self.label_map = label_map
self.model.eval()
def classify(self, text):
"""テキストを分類"""
inputs = self.tokenizer(
text, return_tensors='pt',
padding=True, truncation=True, max_length=128,
)
with torch.no_grad():
outputs = self.model(**inputs)
probs = torch.softmax(outputs.logits, dim=-1)
top_prob, top_idx = torch.max(probs, dim=-1)
category = self.label_map[top_idx.item()]
confidence = top_prob.item()
# Top-3 カテゴリ
top3 = torch.topk(probs[0], 3)
alternatives = [
{'category': self.label_map[idx.item()], 'confidence': round(prob.item(), 3)}
for prob, idx in zip(top3.values, top3.indices)
]
return {
'category': category,
'confidence': round(confidence, 3),
'alternatives': alternatives,
}
# ツールとして登録
classifier = InquiryClassifier(
model_path='./models/inquiry_classifier',
label_map={0: '商品問合せ', 1: '返品・交換', 2: '配送', 3: 'アカウント', 4: 'その他'},
)
@tool
def classify_inquiry(text: str) -> dict:
"""問い合わせのカテゴリを分類する"""
result = classifier.classify(text)
# 確信度が低い場合はLLMにフォールバック
if result['confidence'] < 0.7:
llm_result = llm_classify_fallback(text)
result['llm_fallback'] = True
result['llm_category'] = llm_result['category']
else:
result['llm_fallback'] = False
return result
FAQ検索ツール
from sentence_transformers import SentenceTransformer
import numpy as np
class FAQSearchEngine:
"""セマンティックFAQ検索"""
def __init__(self, faqs):
self.model = SentenceTransformer('all-MiniLM-L6-v2')
self.faqs = faqs
self.faq_embeddings = self.model.encode(
[f['question'] for f in faqs]
)
def search(self, query, category=None, top_k=3):
"""クエリに関連するFAQを検索"""
query_embedding = self.model.encode([query])
# コサイン類似度
similarities = np.dot(self.faq_embeddings, query_embedding.T).flatten()
# カテゴリフィルタ
if category:
for i, faq in enumerate(self.faqs):
if faq.get('category') != category:
similarities[i] *= 0.5 # カテゴリ不一致は減衰
# Top-K
top_indices = np.argsort(-similarities)[:top_k]
return [
{
'question': self.faqs[i]['question'],
'answer': self.faqs[i]['answer'],
'relevance': round(float(similarities[i]), 3),
}
for i in top_indices
if similarities[i] > 0.3 # 最低閾値
]
faq_engine = FAQSearchEngine(faq_data)
@tool
def search_faq(query: str, category: str = "") -> list:
"""関連するFAQを検索する"""
return faq_engine.search(query, category)
感情分析ツール
@tool
def analyze_sentiment(text: str) -> dict:
"""問い合わせの感情を分析する"""
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
class SentimentResult(BaseModel):
sentiment: str = Field(description="positive/neutral/negative")
urgency: str = Field(description="low/medium/high/critical")
frustration_level: int = Field(ge=1, le=5, description="1-5のフラストレーション度")
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
structured_llm = llm.with_structured_output(SentimentResult)
prompt = f"""
以下のカスタマーサポート問い合わせの感情を分析してください。
問い合わせ: {text}
"""
result = structured_llm.invoke(prompt)
return result.model_dump()
まとめ
| 項目 | ポイント |
|---|---|
| 分類ツール | BERT + LLMフォールバックの2段構え |
| FAQ検索 | SentenceTransformerでセマンティック検索 |
| 感情分析 | LLM構造化出力で感情・緊急度を分析 |
| 確信度管理 | 低確信度時のフォールバック戦略 |
チェックリスト
- BERT分類ツールを実装できる
- 確信度に基づくフォールバック戦略を設計できる
- セマンティックFAQ検索を実装できる
- 感情分析ツールを実装できる
次のステップへ
分類ツールを実装した。次は回答生成の仕組みを学ぼう。
推定読了時間: 30分