0Pricing
AI Agents · レッスン

顧客コンテキストと履歴の管理

過去の購入履歴、チケット、設定を利用して、パーソナライズされた応答を生成します。

「顧客コンテキストと履歴の管理」はCoddyKit上の無料AI Agentsレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Agents学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Agentsコースには全4レッスンが含まれています。

コンテキストがエージェントを人間らしく感じさせる理由

平凡なカスタマーサービスエージェントと優れたカスタマーサービスエージェントの違いは、コンテキストにあります。エージェントが「サブスクリプションは来週更新される予定です。更新前に一時停止しますか?」と言うと、顧客は単に処理されているのではなく、自分のことを理解してもらえていると感じます。

このレッスンでは、エージェント向けの豊富な顧客コンテキスト層の構築について説明します。

顧客プロフィールのスキーマ

複数の情報源からデータを集約する標準的な顧客プロフィールを定義します。エージェントは各会話の開始時にこのdictを受け取ります。

from dataclasses import dataclass, field
from datetime import date

@dataclass
class CustomerProfile:
    customer_id: str
    name: str
    email: str
    join_date: date
    subscription_tier: str          # 'free', 'pro', 'enterprise'
    account_age_days: int
    lifetime_value_usd: float
    previous_tickets: list[dict] = field(default_factory=list)
    recent_purchases: list[dict]  = field(default_factory=list)
    preferences: dict             = field(default_factory=dict)

    @property
    def is_long_term_customer(self) -> bool:
        return self.account_age_days > 365

if __name__ == '__main__':
    from datetime import date
    profile = CustomerProfile(
        customer_id='cust_1', name='Jane Doe', email='jane@example.com',
        join_date=date(2023, 1, 15), subscription_tier='pro',
        account_age_days=400, lifetime_value_usd=1250.50,
    )
    print(f'{profile.name} ({profile.subscription_tier}) - long-term customer: {profile.is_long_term_customer}')

購入履歴の取得

eコマースのバックエンドから直近N件の注文を取得します。注文日、商品、合計金額、ステータスを含めます。これにより、顧客が何を購入したか、最近の注文に問題があるかどうかをエージェントが把握できます。

import requests

SHOP_API = 'https://api.yourshop.com'
SHOP_KEY  = 'YOUR_SHOP_API_KEY'

def get_purchase_history(customer_id: str, limit: int = 10) -> list[dict]:
    resp = requests.get(
        f'{SHOP_API}/customers/{customer_id}/orders',
        headers={'Authorization': f'Bearer {SHOP_KEY}'},
        params={'limit': limit, 'sort': '-created_at'}
    )
    resp.raise_for_status()
    orders = resp.json()['orders']
    return [
        {
            'order_id':   o['id'],
            'date':       o['created_at'][:10],
            'total_usd':  o['total'],
            'status':     o['status'],
            'items':      [i['name'] for i in o['line_items']]
        }
        for o in orders
    ]

過去のサポートチケットの取得

繰り返し発生している問題を把握するため、直近N件のサポートチケットを取得します。顧客が同じ問題について3回解決対応を受けている場合、それは製品上の問題であるため、適切にエスカレーションしてフラグを付けます。

def get_support_history(customer_id: str, limit: int = 5) -> list[dict]:
    resp = requests.get(
        f'{SHOP_API}/customers/{customer_id}/tickets',
        headers={'Authorization': f'Bearer {SHOP_KEY}'},
        params={'limit': limit, 'sort': '-created_at'}
    )
    resp.raise_for_status()
    tickets = resp.json()['tickets']
    return [
        {
            'ticket_id': t['id'],
            'subject':   t['subject'],
            'status':    t['status'],
            'resolved':  t.get('resolved_at', ''),
            'category':  t.get('category', 'general')
        }
        for t in tickets
    ]

def has_recurring_issue(tickets: list[dict], category: str) -> bool:
    return sum(1 for t in tickets if t['category'] == category) >= 3

サブスクリプションプランとステータスの読み取り

サブスクリプションプランによって、顧客が利用できる権利が決まります。プランでは利用できない機能について尋ねるPro顧客と、同じ質問をするEnterprise顧客とでは、必要な応答が異なります。

def get_subscription_info(customer_id: str) -> dict:
    resp = requests.get(
        f'{SHOP_API}/customers/{customer_id}/subscription',
        headers={'Authorization': f'Bearer {SHOP_KEY}'}
    )
    if resp.status_code == 404:
        return {'tier': 'free', 'status': 'active', 'renewal_date': None}
    resp.raise_for_status()
    sub = resp.json()
    return {
        'tier':         sub['plan'],
        'status':       sub['status'],        # active / past_due / canceled
        'renewal_date': sub.get('current_period_end', '')[:10],
        'cancel_at':    sub.get('cancel_at_period_end', False)
    }

アカウント利用期間の算出

アカウントの利用期間は、顧客のロイヤルティを示します。2021年から利用している顧客と、昨日登録したばかりの顧客は、異なる対応をする必要があります。関係性を築くため、適切な場合は利用期間に触れます。

from datetime import datetime, timezone

def calculate_account_age(join_date_str: str) -> dict:
    join = datetime.fromisoformat(join_date_str.replace('Z', '+00:00'))
    now  = datetime.now(timezone.utc)
    delta = now - join
    years  = delta.days // 365
    months = (delta.days % 365) // 30
    return {
        'days':   delta.days,
        'years':  years,
        'months': months,
        'label':  f'{years} year(s) and {months} month(s)' if years else f'{months} month(s)'
    }

age = calculate_account_age('2021-03-15T00:00:00Z')
print(age['label'])  # e.g. '5 year(s) and 2 month(s)'

LLM用コンテキスト文字列の構築

顧客プロフィールを、システムプロンプトに埋め込む簡潔なコンテキストブロックに変換します。現在のセッションに直接関係する事実だけを含め、短く保ちます。

def build_context_block(profile: CustomerProfile) -> str:
    recent_order = profile.recent_purchases[0] if profile.recent_purchases else None
    last_ticket  = profile.previous_tickets[0]  if profile.previous_tickets  else None
    parts = [
        f'Customer: {profile.name} ({profile.email})',
        f'Account age: {profile.account_age_days} days | Tier: {profile.subscription_tier}',
        f'Lifetime value: USD {profile.lifetime_value_usd:.0f}',
    ]
    if recent_order:
        parts.append(
            f'Last order: {recent_order["date"]} — '
            f'{', '.join(recent_order["items"][:2])} ({recent_order["status"]})'
        )
    if last_ticket:
        parts.append(f'Last ticket: "{last_ticket["subject"]}" ({last_ticket["status"]})')
    return '\n'.join(parts)

コンテキストを使った応答のパーソナライズ

コンテキストブロックをシステムプロンプトに埋め込むことで、明示的に指示しなくてもLLMが応答の中で自然に参照できるようにします。

import openai

client = openai.OpenAI(api_key='YOUR_OPENAI_KEY')

def respond_with_context(user_message: str, profile: CustomerProfile) -> str:
    context = build_context_block(profile)
    system_prompt = (
        f'You are a helpful customer service agent for ShopCo.\n'
        f'Customer context:\n{context}\n\n'
        f'Be warm and personal. Reference their history when relevant. '
        f'Address the customer by first name.'
    )
    resp = client.chat.completions.create(
        model='gpt-4o',
        messages=[
            {'role': 'system', 'content': system_prompt},
            {'role': 'user',   'content': user_message}
        ]
    )
    return resp.choices[0].message.content

顧客コンテキストのキャッシュ

メッセージごとに複数のAPIからプロフィールデータを取得すると、処理が遅くなり、コストも増加します。会話の開始時にプロフィールをキャッシュし、変更される可能性があるフィールド(注文ステータス、チケットステータス)だけを更新します。

import time

profile_cache: dict[str, dict] = {}  # customer_id -> {profile, fetched_at}
CACHE_TTL = 300  # 5 minutes

def get_cached_profile(customer_id: str) -> CustomerProfile | None:
    entry = profile_cache.get(customer_id)
    if entry and time.time() - entry['fetched_at'] < CACHE_TTL:
        return entry['profile']
    return None

def set_cached_profile(customer_id: str, profile: CustomerProfile):
    profile_cache[customer_id] = {
        'profile': profile,
        'fetched_at': time.time()
    }

履歴から要注意の状況を検出

履歴から、特別な対応が必要なパターンを把握できます。たとえば、直近3件の注文に不具合があった顧客、先月解約すると言っていた顧客、または7年間利用しているユーザーなどです。

def assess_risk_flags(profile: CustomerProfile) -> list[str]:
    flags = []

    # Check for cancellation risk
    cancel_keywords = ['cancel', 'unsubscribe', 'quit', 'competitor']
    for ticket in profile.previous_tickets:
        if any(kw in ticket.get('subject', '').lower() for kw in cancel_keywords):
            flags.append('cancellation_risk')
            break

    # Defective product pattern
    defective = sum(1 for o in profile.recent_purchases if o.get('status') == 'refunded')
    if defective >= 2:
        flags.append('product_quality_issue')

    # High-value customer
    if profile.lifetime_value_usd > 5000:
        flags.append('high_value_customer')

    return flags

顧客コンテキストの構築パイプライン全体

すべてのデータソースを、会話の開始時に一度だけ呼び出す assemble_context() 関数に集約します。

from datetime import date

def assemble_context(email: str) -> CustomerProfile:
    # Try cache first
    # In production: look up customer_id from email in your user DB
    customer_id = 'CUST_123'

    cached = get_cached_profile(customer_id)
    if cached:
        return cached

    # Fetch from all sources
    sub    = get_subscription_info(customer_id)
    orders = get_purchase_history(customer_id)
    tickets = get_support_history(customer_id)

    profile = CustomerProfile(
        customer_id=customer_id,
        name='Alice Smith',
        email=email,
        join_date=date(2021, 3, 15),
        subscription_tier=sub['tier'],
        account_age_days=calculate_account_age('2021-03-15T00:00:00Z')['days'],
        lifetime_value_usd=1240.00,
        previous_tickets=tickets,
        recent_purchases=orders
    )
    set_cached_profile(customer_id, profile)
    return profile

エージェントが「2021年からご利用いただいていますね」と言えるようにする顧客コンテキストの要素はどれですか

応答をパーソナライズするには、顧客プロフィールにある具体的なデータポイントを参照する必要があります。この発言を可能にするフィールドを特定する、実践的な想起問題です。

顧客コンテキストの振り返り

優れたカスタマーサービスエージェントは、購入履歴、サポートチケット、サブスクリプションプラン、アカウント利用期間から詳細なプロフィールを構築します。簡潔なコンテキストブロックをシステムプロンプトに埋め込み、セッション中はキャッシュし、状況が深刻化する前にリスクフラグで要注意の状況を検出します。

よくある質問

「顧客コンテキストと履歴の管理」レッスンは無料ですか?

はい。「顧客コンテキストと履歴の管理」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Agentsコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Agentsコースには全4レッスンが含まれています。

「顧客コンテキストと履歴の管理」で何を学びますか?

過去の購入履歴、チケット、設定を利用して、パーソナライズされた応答を生成します。 ブラウザで直接実行するハンズオンコードでAI Agentsを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

AI Agentsを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAI Agentsは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「顧客コンテキストと履歴の管理」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAI Agentsレッスンでコードを書いて実行できますか?

はい。すべてのAI Agentsレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. チケットの振り分けとエスカレーションロジック
  2. CRM 連携:Salesforce と HubSpot
  3. 有人引き継ぎのプロトコル
  4. 顧客コンテキストと履歴の管理
← AI Agentsに戻る