LESSON

コンテキスト理解

「『何かいいの教えて』と言われたら、文脈なしに推薦できるか?」

田中VPoEが対話ログを見せる。

「夏なのか冬なのか、プレゼント用なのか自分用なのか、予算はいくらか。コンテキストを正しく理解して推薦に反映することが、使える推薦エージェントの条件だ。」

コンテキストの種類

カテゴリ具体例取得方法
明示的コンテキスト「3万円以内で」「赤い色がいい」自然言語解析
暗黙的コンテキスト季節、時間帯、デバイスシステム情報
行動コンテキスト直前に見た商品、カート内容行動ログ
対話コンテキスト前のターンで絞り込んだ条件State管理

嗜好抽出の実装

from langchain_core.tools import tool
from pydantic import BaseModel, Field

class UserPreference(BaseModel):
    """ユーザーの嗜好条件"""
    category: str = Field(default="", description="商品カテゴリ")
    style: str = Field(default="", description="スタイル(カジュアル、フォーマル等)")
    color: str = Field(default="", description="希望の色")
    price_min: int = Field(default=0, description="最低価格")
    price_max: int = Field(default=999999, description="最高価格")
    occasion: str = Field(default="", description="用途(デート、ビジネス等)")
    season: str = Field(default="", description="季節")

@tool
def parse_user_preference(query: str) -> dict:
    """自然言語からユーザーの嗜好条件を抽出する"""
    from langchain_openai import ChatOpenAI

    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
    structured_llm = llm.with_structured_output(UserPreference)

    prompt = f"""
    以下のユーザーの発言から、商品の嗜好条件を抽出してください。
    明示されていない項目は空文字のままにしてください。

    ユーザーの発言: {query}
    """

    result = structured_llm.invoke(prompt)
    return result.model_dump()

対話コンテキストの管理

class ConversationContextManager:
    """対話コンテキストの管理"""

    def __init__(self):
        self.context = {
            'accumulated_preferences': {},
            'shown_items': [],
            'rejected_items': [],
            'turn_history': [],
        }

    def update(self, turn_data):
        """ターンごとにコンテキストを更新"""
        self.context['turn_history'].append(turn_data)

        # 嗜好条件の累積(新しい条件で上書き)
        if 'preferences' in turn_data:
            for key, value in turn_data['preferences'].items():
                if value:  # 空でない値のみ更新
                    self.context['accumulated_preferences'][key] = value

        # 表示済み・拒否済みアイテムの追跡
        if 'shown_items' in turn_data:
            self.context['shown_items'].extend(turn_data['shown_items'])
        if 'rejected_items' in turn_data:
            self.context['rejected_items'].extend(turn_data['rejected_items'])

    def get_effective_preferences(self):
        """累積された有効な嗜好条件を取得"""
        return self.context['accumulated_preferences']

    def get_exclusion_list(self):
        """除外すべきアイテムのリスト"""
        return list(set(
            self.context['shown_items'] + self.context['rejected_items']
        ))

暗黙的コンテキストの活用

from datetime import datetime

class ImplicitContextEnricher:
    """暗黙的コンテキストの付与"""

    def enrich(self, explicit_preferences, system_context):
        """明示的嗜好に暗黙的コンテキストを追加"""
        enriched = dict(explicit_preferences)

        # 季節の推定
        if not enriched.get('season'):
            month = datetime.now().month
            seasons = {
                12: '冬', 1: '冬', 2: '冬',
                3: '春', 4: '春', 5: '春',
                6: '夏', 7: '夏', 8: '夏',
                9: '秋', 10: '秋', 11: '秋',
            }
            enriched['season'] = seasons.get(month, '')

        # 時間帯の考慮
        hour = datetime.now().hour
        if 9 <= hour <= 17:
            enriched['time_context'] = 'business_hours'
        else:
            enriched['time_context'] = 'leisure_hours'

        # デバイス情報
        device = system_context.get('device', 'unknown')
        enriched['device'] = device

        return enriched

まとめ

項目ポイント
明示的嗜好LLMで自然言語から構造化データを抽出
対話コンテキストターンごとに嗜好を累積・更新
暗黙的コンテキスト季節・時間帯・デバイスを自動付与
除外リスト表示済み・拒否済みアイテムを追跡

チェックリスト

  • コンテキストの4つの種類を説明できる
  • LLMによる構造化嗜好抽出を実装できる
  • 対話コンテキストの累積管理を設計できる
  • 暗黙的コンテキストの活用方法を理解した

次のステップへ

コンテキスト理解を実装した。次は推薦理由の生成を学ぼう。

推定読了時間: 30分