o1に作業手順書を生成させるcookbookを読んでみた
概要
OpenAI cookbookの以下の記事が興味深かったので内容をまとめました。
※ 記事自体は2024年9月12日に公開されたものです。Using reasoning for routine generation
背景
LLMを活用したカスタマーサービスソリューションを開発する際、最初のステップとして、ナレッジベースの文書をLLMが理解して実行できる一連のルーチンに変換するタスクが挙げられます。
ここでのルーチンとは、LLMが効率的に実行できるように設計された一連の手順を指します。
各ルーチンは、ステップが明確なアクションに対応するように構成されています。アクションには、ユーザーへの応答、関数呼び出しのトリガー、または追加の関連ナレッジの取得が含まれます。
しかしナレッジベース文書のほとんどはLLMにとっては複雑で、人間が解釈しやすいような構造です。複雑な図、複数のステップから成るプロセス、意思決定ツリーが含まれることが多く、LLMベースのソリューションで推論するのは困難です。
このような文書をLLMが理解しやすいルーチンへ変換したいですが、一から設計するのはなかなか困難な場合があります。様々なユーザシナリオを考慮しながらアクションを明確に定義したり、必要な外部ツール(関数)の洗い出しと中身の定義など、考慮する点が多いです。
そこで、o1を用いてZero-Shotでナレッジベース文書を効率的に分解し、LLMが解釈しやすいルーチンを生成しよう、というのがcookbookの趣旨になります。
ナレッジベース文書の選択
cookbook内では、OpenAI Webサイトで公開されているヘルプセンターの記事を使用しています。
How do I delete my payment method
How can I get a Business Associate Agreement (BAA) with OpenAI?
How can I set up prepaid billing?
How do I submit a VAT exemption request
OpenAIのAPIの支払いに関するQAを使用しているようです。
これらの記事をcsvに保存したものが以下に公開されています。
csvはpolicy,contentのカラムを持ちます。
- policy: 問い合わせに対する対応方針(支払い方法の削除、ビジネスアソシエイトの契約、etc)
- content: Webサイトで公開されているヘルプセンターのQA記事
このcsvを読み込み、o1-previewへ渡して初期ルーチンを生成します。
o1を使用した手順生成
ナレッジ文書からルーチン生成には、o1モデルを使用しています。
ポリシーをルーチンに変換するための手順は次のとおりです。
- 外部向け文書から内部SOP(Standard Operating Procedures:標準作業手順書)ルーチンへのポリシーの変換
- ポリシーを具体的な行動とサブ行動に分解する
- ステップ間の移動に関する具体的な条件の概要
- 外部の知識や行動が必要になる可能性がある場所を特定し、その情報を取得するために使用できる関数を定義する
cookbookでは以下のプロンプトを用いてこの手順を促しています。
※ 日本語訳したものを表示しています。原文は引用元で確認ください。
CONVERSION_PROMPT = """
あなたは、外部向けのヘルプセンター記事を、LLM 向けに最適化された内部向けのプログラム実行可能なルーチンに変換するという任務を負った、役に立つアシスタントです。
このルーチンを使用するLLM は、ポリシーを読み、顧客からの質問に答え、ケースを解決に導くという任務を負います。
以下の手順に従ってください:
1. **カスタマー サービス ポリシーを注意深く確認**して、すべての手順が考慮されていることを確認します。手順やポリシーを省略しないことが重要です。
2. **指定された形式を使用して、**手順を論理的なステップ バイ ステップの順序に整理**します。
3. **次の形式を使用します**:
- **メイン アクションには番号が付けられます** (例: 1、2、3)。
- **サブアクションには、関連するメイン アクションの下に文字が付けられます** (例: 1a、1b)。
**サブアクションは新しい行で開始する必要があります**
- **明確な条件を使用して条件を指定します'if...then...else' ステートメント** (例: '製品が 30 日以内に購入された場合は...')。
- **顧客からさらに情報を必要とする指示の場合**、追加情報を尋ねる丁寧でプロフェッショナルなプロンプトを提供します。
- **外部システムからのデータを必要とするアクションの場合**、関数名にバックティックを使用して関数を呼び出すステップを記述します (例: `check_delivery_date 関数を呼び出す`)。
- **ステップでカスタマー サービス エージェントがアクションを実行する必要がある** (例: 払い戻しを処理する) 場合は、このアクションの関数呼び出しを生成します (例: `process_refund 関数を呼び出す`)。
- **新しい関数を定義する** 場合は、その目的と必要なパラメータについて簡単に説明します。
- **アシスタントがユーザーに代わって実行できるアクションがある場合**、このアクションの関数呼び出しを含め (例: `change_email_address 関数を呼び出す`)、関数がその目的と必要なパラメータで定義されていることを確認します。
- このアクションはヘルプセンターの記事で明示的に定義されていない可能性がありますが、ユーザーが問い合わせをより早く解決できるようにするために実行できます
- **ケース解決の前のステップでは、さらにサポートできることがないか常に尋ねる必要があります**。
- **ケース解決の最終アクションで終了する**: `case_resolution` 関数の呼び出しは常に最終ステップである必要があります。
4. すべてのステップが会社のポリシー、プライバシー規制、および法的要件に準拠していることを確認し、**コンプライアンスを確保します**。
5. 標準ポリシーの範囲外のシナリオのステップを指定して、**例外またはエスカレーションを処理します**。
**重要**: 不明な点がある場合は、「わかりません」と応答してください。
カスタマー サービス ポリシーをフォーマットされたルーチンに変換し、プログラムで簡単に理解して実行できるようにします。
"""
ルーチン生成の関数コード
def generate_routine(policy):
try:
messages = [
{
"role": "user",
"content": f"""
{CONVERSION_PROMPT}
POLICY:
{policy}
"""
}
]
response = client.chat.completions.create(
model=MODEL,
messages=messages
)
return response.choices[0].message.content
except Exception as e:
print(f"An error occurred: {e}")
ルーチン生成の関数を呼び出すコード
def process_article(article):
routine = generate_routine(article['content'])
return {"policy": article['policy'], "content": article['content'], "routine": routine}
with ThreadPoolExecutor() as executor:
results = list(executor.map(process_article, articles))
cookbook内では入力したpolicy,contentと生成されたルーチンの結果をdataframeに保存して確認しています。ここでは1例目のpolicy「支払い方法の削除」の中身を見てみます。
※ 日本語訳したものを表示しています。原文は引用元で確認ください。
o1にインプットしたcontent
支払い方法を削除するにはどうすればよいですか?
1 週間以上前に更新
アカウントの未払い料金を補填するため、お支払い方法をファイルに保存しています。お支払い方法への請求を停止するには、以下の手順に従ってください。
## ChatGPT
ChatGPT Plus サブスクリプションをキャンセルして、いつでもそれ以上の請求を停止できます。
ChatGPT サイドバーの [マイプラン] をクリックします。
ポップアップ ウィンドウで [サブスクリプションの管理] をクリックします。
[プランをキャンセル] を選択します。
キャンセルは次の請求日の翌日に有効になり、それまでは引き続きサービスを利用できます。次の請求期間に請求されないようにするには、次の請求日の 24 時間前までにサブスクリプションをキャンセルしてください。
## API
未払いの使用料を補填するため、お支払い方法をファイルに保存する必要があります。請求概要で [有料アカウントをキャンセル] をクリックすると、従量課金制サービスをキャンセルできます。当月の請求書が発行されると、現在のカードへの請求は行われなくなります。
引き続きサービスをご利用になる場合は、請求概要ページで新しいお支払い方法を追加し、「デフォルトとして設定」を選択してください。その後、古いお支払い方法を削除できるようになります。
o1により生成された手順書
1. 顧客のアカウントを確認します。
a. アカウントを見つけるために、顧客にメールアドレスまたはアカウントIDを丁寧に尋ねます。
b. `verify_customer_account(email_or_account_id)`を呼び出します。
2. 顧客の身元を確認します。
a. 顧客に、身元を確認するためのセキュリティ情報 (ファイルに保存されている支払い方法の最後の4桁など) を提供するよう丁寧に依頼します。
b. `verify_customer_identity(account_id, security_information) `を呼び出します。
c. 顧客の身元が確認できない場合は、次の操作を行います。
- セキュリティ上の理由から、身元確認なしでは先に進めないことを顧客に通知します。
- 身元を確認する方法についてのガイダンスを提供します。
- 手順6に進みます。
3. 顧客のアカウントの種類を判断します。
a. `check_account_type(account_id) `を呼び出します。
4. 顧客が ChatGPT Plusサブスクライバーの場合は、次の操作を行います。
a. ChatGPT Plusサブスクリプションのキャンセルについてサポートが必要かどうかを顧客に尋ねます。
b.顧客が同意する場合は、次の処理を行います。
- `cancel_subscription(account_id)` を呼び出します。
- サブスクリプションがキャンセルされ、次回の請求日の翌日にキャンセルが有効になることを顧客に通知します。
- それまでは引き続きサービスをご利用いただけることを顧客に通知します。
c. そうでない場合:
- 顧客がサブスクリプションをキャンセルするための次の手順を提供します。
- ChatGPT サイドバーで **[マイプラン]** をクリックします。
- ポップアップ ウィンドウで **[サブスクリプションの管理]** をクリックします。
- **[プランのキャンセル]** を選択します。
- キャンセルの有効日とそれまでの継続的なアクセスについて顧客に通知します。
- 次の請求期間の請求を回避するために、次の請求日の少なくとも24時間前までにキャンセルするように顧客にアドバイスします。
5. そうでない場合、顧客がAPIユーザーの場合は、次の処理を行います。
a. 未払いの使用コストを計算するために、支払い方法をファイルに保存する必要があることを顧客に通知します。
b. 従量課金制サービスのキャンセルについてサポートが必要かどうかを顧客に尋ねます。
c.顧客が同意する場合は、次の操作を実行します。
- `cancel_paid_account(account_id)` を呼び出します。
- 当月の請求書が発行された後は、現在のカードに請求が行われないことを顧客に通知します。
d. それ以外の場合:
- 顧客が従量課金制サービスをキャンセルするための次の手順を提供します。
- **請求の概要** ページに移動します。
- **「有料アカウントをキャンセル」** をクリックします。
- 当月の請求書が発行された後は、現在のカードに請求されなくなることを顧客に通知します。
e. 顧客がサービスの使用を継続しながら支払い方法の変更を希望する場合:
- 顧客に、新しい支払い方法の追加とデフォルトとして設定するためのサポートが必要かどうかを確認します。
- 顧客が同意する場合:
- 新しい支払い方法の詳細を丁寧に要求します。
- `add_payment_method(account_id, payment_details)` を呼び出します。
- `set_default_payment_method(account_id, new_payment_method_id)` を呼び出します。
- `delete_payment_method(account_id, old_payment_method_id)` を呼び出します。
- 古い支払い方法が削除され、新しい支払い方法がデフォルトとして設定されていることを顧客に通知します。
- そうでない場合:
- 顧客に、請求の概要ページで新しい支払い方法を追加するように指示します。
- 新しい支払い方法として **[デフォルトとして設定]** を選択するように依頼します。
- 古い支払い方法を削除できることを顧客に伝えます。
6. 他にサポートできることがないか顧客に尋ねます。
7. `case_resolution()` を呼び出します。
---
**関数定義:**
- `verify_customer_account(email_or_account_id)`: 顧客のメール アドレスまたはアカウント ID を使用して、顧客のアカウントを確認します。
**Parameters:** `email_or_account_id`
- `verify_customer_identity(account_id, security_information)`: セキュリティ情報を使用して顧客の ID を確認します。
**Parameters:** `account_id`, `security_information`
- `check_account_type(account_id)`: 顧客のアカウント タイプ (ChatGPT Plus 加入者または API ユーザー) を取得します。
**Parameters:** `account_id`
- `cancel_subscription(account_id)`: 顧客の ChatGPT Plus サブスクリプションをキャンセルします。
**Parameters:** `account_id`
- `cancel_paid_account(account_id)`: 顧客の API 従量課金制サービスをキャンセルします。
**Parameters:** `account_id`
- `add_payment_method(account_id, payment_details)`: 顧客のアカウントに新しい支払い方法を追加します。
**Parameters:** `account_id`, `payment_details`
- `set_default_payment_method(account_id, payment_method_id)`: 顧客のデフォルトとして支払い方法を設定します。
**Parameters:** `account_id`, `payment_method_id`
- `delete_payment_method(account_id, payment_method_id)`: 顧客のアカウントから支払い方法を削除します。
**Parameters:** `account_id`, `payment_method_id`
- `case_resolution()`: ケースを解決し、完了としてマークします。
生成された手順書から読み取れること
cookbookでは、生成結果から以下の4つの洞察を得ています:(※ 私の解釈でまとめています。)
-
サンプル応答: policyを実行するときにLLMが実行可能なサンプル応答を効果的に生成。
- ※ policy: ユーザの問い合わせに対する対応指針。例:ユーザーに指示します:"最初のクレジットの量を確認して購入してください。")
-
個別のステップ化: o1モデルは、問題をLLMが実行する必要がある個別のアクションに分解する用途に向く。各命令は明確に定義されており、解釈が容易。
-
アクションに必要な関数定義: ルーチンの出力には、外部情報の取得やアクションのトリガー等の明確に定義された関数を含む。 (例:
review_and_apply_tax_exemption
,get_billing_plan
,update_payment_method
)
LLMは外部システムとやり取りする必要があることが多く、関数呼び出しを活用することは、外部システムとやり取りしてアクションを実行する効果的な方法。 -
IFTTTロジックでの手順記述: LLMに最適なIFTTT(If This, Then That)ロジックを効果的に採用。(例: "顧客がサポートを要求した場合は、手順3fに進みます。")
このタイプの解釈は、元のナレッジベース文書に複雑なワークフローや図が含まれている場合に非常に役立つ。
この仕組みが今後Agentでどう使われるか?
o1によるルーチン生成をAgentシステムに統合して、以下のような特定の顧客の問い合わせに対処できるようになります。
- 顧客がプリペイド請求の設定などのタスクに関するサポートを要求した場合、分類子を使用して適切なルーチンを決定し、それをLLMに提供して顧客と直接やり取りすることができます。
- 支払いの設定方法についてユーザーに指示を与えるだけでなく、システムがユーザーに代わってアクションを実行することもできます。
感想
o1 + プロンプトで、ヘルプページのドキュメントから具体的な手順書の作成ができることに驚きました。プロンプトはカスタマーセンター向けにはなっていますが、カスタマイズして他のユースケースにも応用できそうです。
cookbookでは関数の定義(関数名、引数、関数の実行内容の説明文)まででしたが、この定義を基に関数の中身の作成もLLMに生成させればAGI(汎用人工知能)のような仕組みに繋がりそうと勉強になりました。(もちろんテスト/評価の仕組みも必要ですが。。)
Discussion