「たぬき+GPT4を使用して、20分で顧客サポートボットを作成しましょう」

「たぬき+GPT4を使って、顧客サポートボットを20分で作成!」

A programmer Tanuki — created with DALL·E 3

TLDR:このワークフローは、お客様のフィードバックメッセージに応答し、GPT4 + タヌキ(オープンソース)を使用してそれらを優先順位付けされたサポートチケットに解析します。

誰にとって有用ですか? GPT4の機能を複雑なワークフローに簡単に統合したいすべての人。

この記事の内容はどれくらい高度ですか? Pythonの基本的な知識が必要ですが、それだけです。 タヌキが残りを処理します。

この記事は何をしないでしょう。 ツイートを取得したり(API参照)、お客様サポートサービスに投稿したりすることはありません(テックスタックに大いに依存します)。

イントロダクション

GPT4は世界中で話題です。 チャットボットから分類子、データ分析、そして今はビジョンまで、潜在的な使用ケースは多岐にわたります。

残る課題は、言語モデルは自然言語の出力を返すため、構造化された出力を必要とするアプリケーションを作成することです。

また、ゼロショットのLLMs(対話学習モデル)は、アライメントがずれている(LLMsはタスクを理解する方法が異なる場合があり、妄想を引き起こす場合がある)という問題があります。これに対処するため、私たちはタヌキを作成し、アライメントされたLLMパワードアプリケーションを簡単に作成し、構造化された型付き出力を保証します。

ここでは、20分でタヌキを使用して以下を作成する方法を示します。

  1. (カスタマーサポート)チャットボット
  2. (カスタマーサポート)分類器、および
  3. データベースへのログインのための信頼性のある構造化オブジェクト。

簡易的に説明したユースケース

この例のユースケースでは、お客様サポートのチャットボットと内部システムの潜在的な問題の両方として機能するワークフローを作成します。具体的には、会社のサポートアカウントに対するツイートを入力として仮定します。ワークフローはツイートに共感的な返答を作成し、それが会社のサポートチームからのさらなるアクションを必要とするかどうかを分類します。ツイートがさらなるアクションを必要とする場合は、サポートチケットが作成され、さらなるアクションのために内部データベースに保存できます。

この例ではTanukiが使用され、応答を作成し、ツイートを分類し、必要に応じてサポートチケットを作成します。私たちはこのPythonアプリを20分で構築できました。今度は、同じことを行う方法をお教えします。お待ちになれない方は、次のリンクでリポジトリとユースケースを見つけることができます:

  • Tanuki リポジトリ Github
  • この特定のユースケースのコードはこちらまたはGoogle Colabの ノートブックでご確認いただけます。

タヌキとは何であり、なぜこのユースケースに有用なのか?

Tanukiは、必要なLLMやプロンプトの知識がほとんどなく、容易かつシームレスなLLMパワードアプリケーションの構築に役立つオープンソースライブラリです。特にこのユースケースにとって有用なTanukiの機能は次のとおりです:

  • タイプに注意:出力は常にユーザーが指定した型ヒントの構造に従います(LLMでは悪夢となる形式のテキストとなります)。出力はPythonの基本的な型(int、リスト、辞書)やより複雑なタイプ(Pydanticクラスやリテラルなど)として指定することができます
  • デモンストレーションモック例を使用して言語モデルの振る舞いを容易にアライメントできます(インコンテキストラーニングのアイデアに従います)。これらのアライメントステートメントを追加する必要はありませんが、モデルのパフォーマンスを大幅に向上させることが通常できます。モック例を追加するには、メモ帳に書き留めるだけで簡単です。
  • Tanukiは自動的にモデルの蒸留を行います。つまり、教師モデル(GPT-4)は自動的により小さなファインチューニングモデルに蒸留されてコストとレイテンシーの両方で最大15倍の削減が可能になりますが、パフォーマンスは犠牲になりません。

これらの機能は、以下のユースケースに関連しています:

  1. LLMの出力は他のシステムで使用されます。これにより、出力が常に適切な型付けされることが必要であり、データによるランタイムバグが発生しないようにする必要があります。これは重要です。なぜなら、構造化されたチケットオブジェクトが作成され、与えられたスキーマでデータが期待されるデータベースに記録されるためです。
  2. 何を実行すべきか(およびすべきでないか)は主観的であり、明白ではありません。さらに、言語モデルがクライアントのフィードバックにどのように反応するかは非常に重要です(トーンやメッセージは、既に問題を抱えている顧客を怒らせないように正しくする必要があります)。したがって、アライメントが重要です。LLMが適切な応答と、将来の問題に対処する際の従業員のアクションに合致していることを確認する必要があります。これらの問題に対して言語モデルをアライメントさせることは、本番環境での適切なパフォーマンスを確保する唯一の方法です。
  3. 本番環境でのサポートチケットとフィードバックの数は膨大です。そのため、コストを15倍に削減することは、大規模な節約と長期的な利用の動機づけとなる可能性があります。特にパフォーマンスは一定であり、将来のGPT4のバージョン変更によってワークフローが影響を受けることはありません。

プロジェクトのスコープを確定するため、以下の要件を使用します

まず、以下の一般的なワークフローを想定します:

  • 製品またはサービスに関するユーザーフィードバックメッセージがTwitterアカウントに送信されます。
  • LLMはフィードバックを分析し、共感的に(できる限り最善の方法で)応答します(つまり、チャットボットの側面)。
  • 顧客のフィードバックに基づいて、LLMはフィードバックを「アクションが必要」と分類します(つまり、分類器の側面)。
  • アクションが必要な場合、チャットボットは後でダウンストリームアプリケーションで使用するための顧客チケットオブジェクトを作成します。

このユースケースでは、OpenAIのGPT4を使用します。始めるには、環境変数を設定する必要があります。OpenAI APIキーを使用してください。そのため、.envファイルを作成し、ディレクトリに追加する必要があります。後で.envファイルが読み込まれ、環境変数が正しく解析されます。

OPENAI_API_KEY=sk-XXX

これで、Tanukiを設定するための必要な構成が完了しました!次に、ユースケースの構築方法を見てみましょう。

ワークフローの構築

前述のように、コストが問題でない場合、プロンプトを使用してGPT4を使用することができますが、型付きの出力を得るには追加作業が必要です。数週間あれば、オープンソースのLLMを微調整してこのタスクを処理できます。代わりに、20分でこれを行うためにTanukiを使用します。

最初の作業は、Tanukiをインストールする必要があります

pip install tanuki.py

次に、土台を築きましょう。以下のような入力ツイートオブジェクトが想定されます:

from pydantic import BaseModelclass Tweet(BaseModel):    """    ツイートオブジェクト    nameはユーザーのアカウントです    textは送信されたツイートです    idは一意の分類子です    """    name: str    text: str    id: str

次に、与えられたツイートに対して投稿するために、responsePydanticオブジェクトと、人間が入力メッセージに対してアクションを起こす必要がある場合は、データベースに保存するためにSupportTicketオブジェクトも作成する必要があります。

from typing import Literal, Optionalclass Response(BaseModel):    """    応答オブジェクト、response属性は顧客に送信される応答です    requires_ticketは、着信ツイートが質問であるか、直接の問題であるかを示すブール値です    """    requires_ticket: bool     response: str class SupportTicket(BaseModel):    """    サポートチケットオブジェクト、    issueは顧客が抱えた問題の簡単な説明です    urgencyはチームが問題にどれだけ緊急に応答する必要があるかを伝えます    """    issue: str    urgency: Literal["low", "VoAGI", "high"]

これで、土台を築いたので、実際の関数を作成して、すべての重労働を自動化できるようにします。

まず、tweetからResponseオブジェクトを作成する関数を作成します。入力としてtweetを指定し、出力タイプヒントとしてResponseを指定します。タイプヒントを指定することは重要です。それによって関数を実行する言語モデルに最終出力として何を作成するかを伝えることができます。Tanukiはまた、出力がタイプヒントに準拠していることを常に確認するため、不正なオブジェクトや信頼性の低い出力によって何かが壊れることはありません。

次に、LLMが行う必要のあることに関する概要と@tanuki.patchデコレータを関数のdocstringに追加します。これにより、classify_and_respondからの出力が正しく型付けされ、下流で解析されることが保証されます。

import [email protected] classify_and_respond(tweet: Tweet) -> Response:    """    カスタマーサポートのツイートに感情的で丁寧な返答を行います。    問題に対して関心を持っていることを伝えます。問題が直接の問題か、または質問である場合、チームはそれに応答します。    """

信頼性の高いパフォーマンスを確保し、LLMのパフォーマンスをユーザーへの出力に向けるために、@tanuki.alignデコレータを使用してalign_respondという別の関数を作成します。

align_respondでは、有効な入力と出力の例を示すことで、LLMの出力を整列させます。この整列により、以下のことが実現されます。

  1. 顧客の要求にどのように応えるかを示す
  2. 記録する必要のある顧客からの要求(および内部チケットの作成)を示す

これらの整列は、Pythonのassert文を使用して入力と望ましい出力をモックアップします。以下は、チャットボットの出力オブジェクトの整列文のいくつかの例です。

@tanuki.aligndef align_respond():    input_tweet_1 = Tweet(name = "Laia Johnson",                          text = "I really like the new shovel but the handle broke after 2 days of use. Can I get a replacement?",                          id = "123")    assert classify_and_respond(input_tweet_1) == Response(                                                            requires_ticket=True,                                                             response="Hi, we are sorry to hear that. We will get back to you with a replacement as soon as possible, can you send us your order nr?"                                                            )    input_tweet_2 = Tweet(name = "Keira Townsend",                          text = "I hate the new design of the iphone. It is so ugly. I am switching to Samsung",                          id = "10pa")    assert classify_and_respond(input_tweet_2) == Response(                                                            requires_ticket=False,                                                             response="Hi, we are sorry to hear that. We will take this into consideration and let the product team know of the feedback"                                                            )    input_tweet_3 = Tweet(name = "Thomas Bell",                          text = "@Amazonsupport. I have a question about ordering, do you deliver to Finland?",                          id = "test")    assert classify_and_respond(input_tweet_3) == Response(                                                            requires_ticket=True,                                                             response="Hi, thanks for reaching out. The question will be sent to our support team and they will get back to you as soon as possible"                                                            )    input_tweet_4 = Tweet(name = "Jillian Murphy",                          text = "Just bought the new goodybox and so far I'm loving it!",                          id = "009")    assert classify_and_respond(input_tweet_4) == Response(                                                            requires_ticket=False,                                                             response="Hi, thanks for reaching out. We are happy to hear that you are enjoying the product"                                                            )

上記のようなアサーションは、LLMを意図した動作に整列させることで、幻覚や予期しない障害の可能性を大幅に減らします。私はこれを「テスト駆動の整合性」と考えています(LLMのためのテスト駆動開発)。

同じことを第二部分、つまり、ログ保存のためのサポートチケットの作成にも行う必要があります。パッチと整列関数の構造を同じようにした形で、以下のようになります。

@tanuki.patchdef create_support_ticket(tweet_text: str) -> SupportTicket:    """    ツイートテキストを使用して、内部データベースに保存するためのサポートチケットを作成します。    対応が必要なアクションの短い概要と問題の緊急性を作成します。    """@tanuki.aligndef align_supportticket():    input_tweet_1 = "I really like the new shovel but the handle broke after 2 days of use. Can I get a replacement?"    assert create_support_ticket(input_tweet_1) == SupportTicket(                                                                issue="Needs a replacement product because the handle broke",                                                                 urgency = "high"                                                                )    input_tweet_2 = "@Amazonsupport. I have a question about ordering, do you deliver to Finland?"    assert create_support_ticket(input_tweet_2) == SupportTicket(                                                                issue="Find out and answer whether we currently deliver to Finland",                                                                urgency="low"                                                                )    input_tweet_3 = "Just bought the new goodybox and so far I'm loving it! The cream package was slightly damaged however, would need that to be replaced"    assert create_support_ticket(input_tweet_3) == SupportTicket(                                                                issue="Needs a new cream as package was slightly damaged",                                                                 urgency="VoAGI"                                                                )

全てをまとめるために、analyse_and_respond() 関数を作成して、 必要な場合は応答とサポートチケットを作成します。
これで完了です!

def analyse_and_respond(tweet: Tweet) -> tuple[Optional[SupportTicket], Response]:    # 応答を取得する    response =  classify_and_respond(tweet)    # もし応答がチケットを必要とする場合は、チケットを作成する    if response.requires_ticket:        support_ticket = create_support_ticket(tweet.text)        return response, support_ticket    return response, None

これらの全てを含めた、最終的なコードは以下の通りです:

from dotenv import load_dotenv
load_dotenv()
from pydantic import BaseModel
from typing import Literal, Optional

class Tweet(BaseModel):
    """ツイートオブジェクト
    name: ユーザーのアカウント名
    text: 送信されたメッセージ
    """
    name: str
    text: str
    id: str

class Response(BaseModel):
    """応答オブジェクト
    response: 顧客に送信された応答
    requires_ticket: 応答が質問または直接の問題であり、人間の介入と対応を必要とするかどうかを示すブール値
    """
    requires_ticket: bool
    response: str

class SupportTicket(BaseModel):
    """サポートチケットオブジェクト
    issue: 顧客が抱えている問題の簡単な説明
    urgency: チームが問題に対してどれくらい緊急に対応すべきかを伝える
    """
    issue: str
    urgency: Literal["low", "VoAGI", "high"]

# 応答作成
@tanuki.patch
def classify_and_respond(tweet: Tweet) -> Response:
    """顧客サポートツイートのテキストを感情的に、丁寧に応答する。
    問題が直接の問題である場合、サポートチームが修正する必要があると以下で伝える。
    """
@tanuki.aligndef align_respond():
    input_tweet_1 = Tweet(name = "Laia Johnson",
                          text = "新しいシャベルがとても気に入っているが、使用2日目にハンドルが壊れた。交換品をもらえますか?",
                          id = "123")
    assert classify_and_respond(input_tweet_1) == Response(
                                                            requires_ticket=True,
                                                            response="申し訳ありませんが、修理するための交換品をできるだけ早くお届けします。注文番号を教えていただけますか?"
                                                            )
    input_tweet_2 = Tweet(name = "Keira Townsend",
                          text = "アイフォンの新しいデザインが大嫌いです。とても醜いです。サムスンに切り替えます。",
                          id = "10pa")
    assert classify_and_respond(input_tweet_2) == Response(
                                                            requires_ticket=False,
                                                            response="申し訳ありません。お手数をおかけしますが、あなたのフィードバックを製品チームに伝えます。"
                                                            )
    input_tweet_3 = Tweet(name = "Thomas Bell",
                          text = "@Amazonsupport. 注文についての質問があります。フィンランドへの配送はされていますか?",
                          id = "test")
    assert classify_and_respond(input_tweet_3) == Response(
                                                            requires_ticket=True,
                                                            response="お問い合わせいただきありがとうございます。質問はサポートチームに送信され、できるだけ早くご連絡させていただきます。"
                                                            )
    input_tweet_4 = Tweet(name = "Jillian Murphy",
                          text = "新しいおもちゃ箱を購入しましたが、今のところ大好きです!",
                          id = "009")
    assert classify_and_respond(input_tweet_4) == Response(
                                                            requires_ticket=False,
                                                            response="お問い合わせいただきありがとうございます。製品をお楽しみいただけてうれしいです。"
                                                                        )

# サポートチケット作成
@tanuki.patch
def create_support_ticket(tweet_text: str) -> SupportTicket:
    """ツイートのテキストを使用して、内部データベースに保存するためのサポートチケットを作成する。
    解決策の要約と問題の緊急性を作成する。
    """
@tanuki.aligndef align_supportticket():
    input_tweet_1 = "新しいシャベルがとても気に入っているが、使用2日目にハンドルが壊れた。交換品が必要です。"
    assert create_support_ticket(input_tweet_1) == SupportTicket(
                                                                issue="ハンドルが壊れたため、交換品が必要",
                                                                urgency = "high"
                                                                )
    input_tweet_2 = "@Amazonsupport. 注文についての質問があります。フィンランドへの配送はされていますか?"
    assert create_support_ticket(input_tweet_2) == SupportTicket(
                                                                issue="現在フィンランドへの配達状況を確認し、回答する",
                                                                urgency="low"
                                                                )
    input_tweet_3 = "新しいおもちゃ箱を購入しましたが、現時点では大満足です!ただ、クリームパッケージにわずかなダメージがあり、それを交換してほしいです。"
    assert create_support_ticket(input_tweet_3) == SupportTicket(
                                                                issue="クリームパッケージがわずかに損傷しているため、新しいものが必要",
                                                                urgency="VoAGI"
                                                                )

# ワークフローのための最終関数
def analyse_and_respond(tweet: Tweet) -> tuple[Optional[SupportTicket], Response]:
    # 応答を取得する
    response =  classify_and_respond(tweet)
    # 応答がチケットを必要とする場合は、チケットを作成する
    if response.requires_ticket:
        support_ticket = create_support_ticket(tweet.text)
        return response, support_ticket
    return response, None

そして、それで終わりです!これで、いくつかの例でワークフローをテストすることができます。

def main():    """    この関数は、入力されたツイートを分析して、応答出力と必要な場合はチケット出力を返します。    """    # alignステートメントを登録するためにalign_respondを呼び出す    align_respond()    align_supportticket()    input_tweet_1 = Tweet(name = "ジャック・ベル",                          text = "ブロー @Argos 私の注文が届かなかった理由はなんですか?2週間前に注文しました。ひどいサービス",                          id = "1")    response, ticket = analyse_and_respond(input_tweet_1)        print(response)    # requires_ticket=True     # response="こんにちは、ジャックさん、これを聞いてとても残念です。すぐに調査し、できるだけ早く連絡させていただきます。"        print(ticket)    # issue="お客様の注文が2週間経っても届かなかった"    # urgency='高'    input_tweet_2 = Tweet(name = "ケイシー・モンゴメリー",                          text = "@Argos 配達時間は3週間でしたが、1週間と約束されました。ファンではありません。 ",                          id = "12")    response, ticket = analyse_and_respond(input_tweet_2)        print(response)    # requires_ticket=True     # response="こんにちは、ケイシーさん、配送に遅れが発生して申し訳ありません。この問題について調査し、できるだけ早く連絡させていただきます。"        print(ticket)    # issue='約束されたよりも配達時間が長かった'    # urgency='VoAGI'    input_tweet_3 = Tweet(name = "ジャック・パロウ",                          text = "@Argos 新しいロゴはかなり醜いですね。なぜ変更したのか不思議です",                          id = "1123")    response, ticket = analyse_and_respond(input_tweet_3)    print(response)    # requires_ticket=False     # response="こんにちは、ジャック・パロウさん、新しいロゴがお気に召さないようで申し訳ありません。該当チームにフィードバックを伝えます。知らせてくれてありがとう。"        print(ticket)    # None

期待通りに動作しているようです!出力は良く見え、アラインメントしたトーンに従って作成されており、必要に応じて適切な緊急度でチケットが作成されています。

これを作成するのに30分以内で済みました。

次には何か

これはただの小さな例でしたが、それでも開発者は簡単にTanukiを使用してLLMパワードの関数やアプリを作成できることを示しています。

もしこれが興味深いと思われた場合、詳しく学んだり、関与したりするには、ぜひ私たちのDiscordに参加してください。これは私たちが作成したただ一つのユースケースです。他にも (例えば、ウェブスクレイピングからの構造化データの作成、自然言語でToDoアイテムを記述してToDoリストアプリを作成、深い言語をブロックするなど) 多くのユースケースがあります。

もし質問があれば、コメントでお知らせください。または、私たちのDiscordでお知らせください。近いうちにお会いしましょう!

We will continue to update VoAGI; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

機械学習

もし芸術が私たちの人間性を表現する方法であるなら、人工知能はどこに適合するのでしょうか?

MITのポストドクターであるジヴ・エプスタイン氏(SM '19、PhD '23)は、芸術やその他のメディアを作成するために生成的AIを...

人工知能

「コマンドバーの創設者兼CEO、ジェームズ・エバンスによるインタビューシリーズ」

ジェームズ・エバンズは、CommandBarの創設者兼CEOであり、製品、マーケティング、顧客チームを支援するために設計されたAIパ...

人工知能

「ゲイリー・ヒュースティス、パワーハウスフォレンジクスのオーナー兼ディレクター- インタビューシリーズ」

ゲイリー・ヒュースティス氏は、パワーハウスフォレンジックスのオーナー兼ディレクターであり、ライセンスを持つ私立探偵、...

人工知能

ムーバブルインクのCEO兼共同創設者であるヴィヴェク・シャルマ氏についてのインタビュー・シリーズ

ビヴェクは2010年にムーバブルインクを共同設立し、急速な成長を遂げながら、600人以上の従業員を擁し、世界有数の革新的なブ...

人工知能

「LeanTaaSの創設者兼CEO、モハン・ギリダラダスによるインタビューシリーズ」

モーハン・ギリダラダスは、AIを活用したSaaSベースのキャパシティ管理、スタッフ配置、患者フローのソフトウェアを提供する...

人工知能

「Ami Hever、UVeyeの共同創設者兼CEO - インタビューシリーズ」

עמיר חבר הוא המנכל והמייסד של UVeye, סטארט-אפ ראיה ממוחשבת בלמידה עמוקה, המציבה את התקן הגלובלי לבדיקת רכבים עם זיהוי...