
OpenAI Agents SDK で カスタマーサービスを実装する
以下のサンプルコードの使い方をまとめました。
前回
1. カスタマーサービス
「OpenAI Agents SDK」で複数のAgentを用いて航空会社の問い合わせ対応システムを実装します。Agent間の「Handoff」や「Tool Calling」を通じた顧客対応の流れを構築しています。
次の2つのToolを定義します。
・faq_lookup_tool()
FAQに関する質問の回答を提供します。
・update_seat()
指定された確認番号の座席を更新します。
次の1つのHookを定義します。
・on_seat_booking_handoff()
Triage Agent から Seat Booking Agent へのHandoffの際に呼ばれるHookです。Seat Booking Agent に処理を渡す前に、ランダムなフライト番号がコンテキストに設定されます。
次の3つのAgentを定義します。
・faq_agent
FAQに特化したAgentです。顧客の質問に対してfaq_lookup_tool()を用いて回答を生成します。回答できない場合は、Triage AgentへHandoffします。
・seat_booking_agent
座席の更新に関する処理を担当するAgentです。顧客から確認番号と新しい座席番号を受け取り、update_seat()を用いてコンテキスト情報を更新します。座席の更新と関係ない場合は、Triage AgentへHandoffします。
・triage_agent
顧客の問い合わせ内容を判別し、適切なAgent(FAQ AgentまたはSeat Booking Agent)にHandoffする役割を持つAgentです。座席予約に関しては、Handoff時にHook関数on_seat_booking_handoffを実行してフライト番号を設定しています。
ファイル構成は、次のとおりです。
・customer_service
・main.py
2. コードの解説
2-1. main.py
from __future__ import annotations as _annotations
import asyncio
import random
import uuid
from pydantic import BaseModel
from agents import (
Agent,
HandoffOutputItem,
ItemHelpers,
MessageOutputItem,
RunContextWrapper,
Runner,
ToolCallItem,
ToolCallOutputItem,
TResponseInputItem,
function_tool,
handoff,
trace,
)
from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX
# 航空会社Agentのコンテキスト
class AirlineAgentContext(BaseModel):
passenger_name: str | None = None # 乗客名
confirmation_number: str | None = None # 確認番号
seat_number: str | None = None # 座席番号
flight_number: str | None = None # フライト番号
# FAQツール
@function_tool(
name_override="faq_lookup_tool",
description_override="FAQに関する質問の回答を提供します。"
)
async def faq_lookup_tool(question: str) -> str:
if "バック" in question or "荷物" in question:
return (
"飛行機にはバッグを1つ持ち込むことができます。"
"重量は50ポンド以下、サイズは22インチ x 14インチ x 9インチである必要があります。"
)
elif "席" in question or "飛行機" in question:
return (
"飛行機には120席あります。"
"ビジネスクラスの座席は22席、エコノミークラスの座席は98席あります。"
"非常口は4列目と16列目です。"
"5列目から8列目はエコノミープラスで、足元に余裕があります。"
)
elif "WiFi" in question or "Wi-Fi" in question:
return "飛行機には無料Wi-Fiがあります。Airline-Wifiにご参加ください"
return "申し訳ありませんが、その質問の答えは分かりません。"
# 座席更新ツール
@function_tool
async def update_seat(
context: RunContextWrapper[AirlineAgentContext], confirmation_number: str, new_seat: str
) -> str:
"""
指定された確認番号の座席を更新します。
Args:
confirmation_number: フライトの確認番号
new_seat: 更新する新しいシート
"""
# 顧客の入力に基づいてコンテキストを更新
context.context.confirmation_number = confirmation_number
context.context.seat_number = new_seat
# incoming handoffによってフライト番号が設定されていることを確認
assert context.context.flight_number is not None, "フライト番号は必須です。"
return f"確認番号 {confirmation_number} の座席を {new_seat} に更新しました。"
# Triage Agent から Seat Booking Agent へのHandoffの際に呼ばれるHook
async def on_seat_booking_handoff(context: RunContextWrapper[AirlineAgentContext]) -> None:
flight_number = f"FLT-{random.randint(100, 999)}"
context.context.flight_number = flight_number
# FAQ Agentの準備
faq_agent = Agent[AirlineAgentContext](
name="FAQ Agent",
handoff_description="航空会社に関する質問に答えてくれる親切なAgentです。",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
あなたは FAQ Agentです。顧客と話しているときは、Triage Agentから転送された可能性があります。
次の手順に従って顧客をサポートします。
# 手順
1. 顧客が最後に尋ねた質問を特定します。
2. faq_lookup_toolを使用して質問に答えます。自分の知識に頼らないでください。
3. 質問に答えられない場合は、Triage Agentに転送します。""",
tools=[faq_lookup_tool],
)
# Seat Booking Agentの準備
seat_booking_agent = Agent[AirlineAgentContext](
name="Seat Booking Agent",
handoff_description="フライトの座席を更新できる便利なAgentです。",
instructions=f"""{RECOMMENDED_PROMPT_PREFIX}
あなたはSeat Booking Agentです。顧客と話しているときは、Triage Agentから転送された可能性があります。
次の手順に従って顧客をサポートします。
# 手順
1. 確認番号を尋ねます。
2. お客様に希望の座席番号を尋ねます。
3. update_seatを使用して、フライトの座席を更新します。
お客様が手順に関係のない質問をした場合は、Triage Agentに転送します。 """,
tools=[update_seat],
)
# Triage Agentの準備
triage_agent = Agent[AirlineAgentContext](
name="Triage Agent",
handoff_description="顧客のリクエストを適切なAgentに委任できるTriage Agentです。",
instructions=(
f"{RECOMMENDED_PROMPT_PREFIX} "
"あなたは役に立つTriage Agentです。質問を他の適切なAgentに委任できます。"
),
handoffs=[
faq_agent,
handoff(agent=seat_booking_agent, on_handoff=on_seat_booking_handoff),
],
)
# 相互Handoff
faq_agent.handoffs.append(triage_agent)
seat_booking_agent.handoffs.append(triage_agent)
# メインの定義
async def main():
current_agent: Agent[AirlineAgentContext] = triage_agent # 最初はTriage Agent
input_items: list[TResponseInputItem] = []
context = AirlineAgentContext()
# 会話IDにランダムなUUIDを使用
conversation_id = uuid.uuid4().hex[:16]
while True:
# メッセージの入力
user_input = input("メッセージを入力: ")
with trace("Customer service", group_id=conversation_id):
# Agentの実行
input_items.append({"role": "user", "content": user_input})
result = await Runner.run(current_agent, input_items, context=context)
# 出力
for new_item in result.new_items:
agent_name = new_item.agent.name
if isinstance(new_item, MessageOutputItem):
print(f"{agent_name}: {ItemHelpers.text_message_output(new_item)}")
elif isinstance(new_item, HandoffOutputItem):
print(
f"Handed off from {new_item.source_agent.name} to {new_item.target_agent.name}"
)
elif isinstance(new_item, ToolCallItem):
print(f"{agent_name}: Calling a tool")
elif isinstance(new_item, ToolCallOutputItem):
print(f"{agent_name}: Tool call output: {new_item.output}")
else:
print(f"{agent_name}: Skipping item: {new_item.__class__.__name__}")
input_items = result.to_input_list()
current_agent = result.last_agent
# メインの実行
if __name__ == "__main__":
asyncio.run(main())
3. コードの実行
(1) ローカルPCでPython仮想環境を準備。
(2) ローカルPCの環境変数「OPENAI_API_KEY」にAPIキーを指定。
・Mac
export OPENAI_API_KEY=sk-...・Windows
set OPENAI_API_KEY=sk-...(3) パッケージのインストール。
pip install openai-agents(4) コードの実行。
python -m customer_service.mainメッセージを入力: 飛行機に持ち込めるバックの数は?
Triage Agent: Skipping item: HandoffCallItem
Handed off from Triage Agent to FAQ Agent
FAQ Agent: Calling a tool
FAQ Agent: Tool call output: 飛行機にはバッグを1つ持ち込むことができます。重量は50ポンド以下、サイズは22インチ x 14インチ x 9インチである必要があります。
FAQ Agent: 飛行機にはバッグを1つ持ち込むことができます。重量は50ポンド以下で、サイズは22インチ x 14インチ x 9インチ以内である必要があります。
メッセージを入力: 座席の更新をお願いします。
FAQ Agent: Skipping item: HandoffCallItem
Handed off from FAQ Agent to Triage Agent
Triage Agent: Skipping item: HandoffCallItem
Handed off from Triage Agent to Seat Booking Agent
Seat Booking Agent: 座席の更新を承ります。まず、確認番号を教えていただけますか?
メッセージを入力: 123です。
Seat Booking Agent: 希望する新しい座席番号を教えてください。
メッセージを入力: 3Aです。
Seat Booking Agent: Calling a tool
Seat Booking Agent: Tool call output: 確認番号 123 の座席を 3A に更新しました。
Seat Booking Agent: 座席を3Aに更新しました。ご利用ありがとうございました。
メッセージを入力: