秋田のおすすめの旅行先をAIエージェント(AG2)に聞いてみた

    こんにちは。

    花島き です。

    先週、秋田を満喫しましたが、また行きたくなったので、秋田のおすすめの旅行先をAIエージェントに聞いてみたので実装を踏まえながら説明します。

    構成はAG2 x AG-UI, CopilotKit x FastaAgencyです。

    ag2-copilotkit-starterを使用しました。

    AG2とFastAgencyについて今回は説明します。

    AG2はAIエージェントフレームワーク。FastAgencyはデプロイするために必要なフレームワークです。

    結果はこちら。

    目的地と旅行期間、予算、興味をAIが把握するまで質問をユーザーに投げかけます。
    1会話ずつ確認しながら進めていきます。
    Human-in-the-Loopですね。
    全部揃うと、AIがおすすめの旅行プランを考えてくれます。

    このプランは良いですね。
    秋田は他にも良い所が満載です。
    ラーメンショップアジキュー 協和店
    岩牡蠣がマジで美味しい。ねむの丘です。子供は稲庭うどんが大好物です。食べた次の日もうどん、うまいと言っていました。おすすめです。比内地鶏も美味しいです。

    武家屋敷や田沢湖の観光も良いです。

    もちろん、温泉もあります。

    なまはげを見るのも良いではないでしょうか?

    他にもおすすめはたくさんありますが、そろそろコードの方へ。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    ソースコードはag2-copilotkit-starterを使用しました。

    英語を日本語にしています。

    今回はパート1なので、AG2とFastAgencyの部分です。

    1. まずはどのLLMを使うかをllm_configで定義し、ワークフローのインスタンスを作成します。
    from autogen import ConversableAgent, LLMConfig
    from fastapi import FastAPI
    
    from fastagency import UI
    from fastagency.adapters.awp import AWPAdapter
    from fastagency.runtimes.ag2 import Workflow
    
    llm_config = LLMConfig(
        model="gpt-4o-mini",
        api_key=os.getenv("OPENAI_API_KEY"),
        temperature=0.8,
    )
    
    wf = Workflow()

    2. 次にワークフローを登録します。
    ConversableAgentがAG2の会話用のエージェントです。
    基本的なエージェントです。
    エージェント名をnameに。システムプロントをsystem_messageに。
    human_input_modeを以下から設定。
    ・ALWAYS: エージェントは人間の入力を応答として使用します
    ・TERMINATE: エージェントは会話を終了するときにのみ入力を求めます
    ・NEVER: エージェントは人間の入力を求めません。
    runでインスタンスを作成し、processで実行するイメージです。
    詳細は公式サイトに記載されています。
    runメソッドで指定しているtravel_agentは相手のエージェントです。recipientです。

    @wf.register(name="simple_learning", description="A simple travel itenarary generator workflow")
    def simple_workflow(ui: UI, params: dict[str, Any]) -> str:
        initial_message = ui.text_input(
            sender="Workflow",
            recipient="User",
            prompt=INITIAL_MESSAGE,
        )
    
        with llm_config:
            user_agent = ConversableAgent(
                name="User_Agent",
                system_message="You are a user agent that interacts with the travel agent.",
                human_input_mode="ALWAYS", # ALWAYSの場合は都度ユーザー側に入力を求める
            )
            travel_agent = ConversableAgent(
                name="Travel_Agent",
                system_message=TRAVEL_AGENT_SYSTEM_MESSAGE,
            )
    
        response = user_agent.run(
            travel_agent, # 相手のエージェントを指定
            message=initial_message,
            summary_method="reflection_with_llm", # 要約生成にLLMを使用する。last_msgの場合は最後のメッセージを要約とする。
        )
    
        return ui.process(response)  # type: ignore[no-any-return]

    3.AWPはagent wire protocolの略です。AG-UIを使用するためにAWP Providerを使用します。AWPってなんやねんと探しました。。。ソースコードに記載がありました。
    ワークフロー、ワークフロー名、フィルタリングを設定し、
    ルータを登録します。
    公式サイトを参考にしてください。

    # チャット画面に表示するメッセージをフィルターリングするためにBoolで制御。テキストでユーザーからのメッセージ以外を表示する。
    def without_user_messages(message: Any) -> bool:
        return not (message.type == "text" and message.content.sender == "User_Agent")
    
    # filterでフィルタリングを設定。filter=Noneにするとユーザーのメッセージがフィルタリングされないので、2重にチャット画面に表示される。
    adapter = AWPAdapter(
        provider=wf, wf_name="simple_learning", filter=without_user_messages
    )
    
    app = FastAPI()
    app.include_router(adapter.router)

    AG2のコーディング部分はこれで以上です。少ないコードでエージェントを定義できます。

    ただ、エージェントの役割を定義する必要があります。開発よりもこの役割定義が重要と思いました。実際の開発ではエージェント開発はこの役割定義、データ連携、セキュリティ、コンテキスト等が重要になります。上流工程が重要です。RAGやチャットボットの開発よりも初期導入にかかる時間はかかると思います。
    RAG readyという言葉がありますが、AI Agent Readyというのもあると思います。

    TRAVEL_AGENT_SYSTEM_MESSAGE="""
    あなたは、ユーザーが個人に合わせた旅行プランを作成するのを支援するために設計された、エキスパートの旅行ガイドエージェントです。あなたの目的は、ユーザーから重要な情報を収集し、詳細な日ごとの旅行プランを生成することです。
    以下の指示に正確に従ってください:
    情報収集段階:
    
    1.常にユーザーを温かく迎え、あなたの目的を説明することから始める:個人に合わせた旅行プランを作成すること。
    2.以下の必須情報を求め、収集する:
    
        - 目的地の都市/場所
        - 旅行日数
        - 予算レベル(エコノミー、ミッドレンジ、またはプレミアム)
        - 特別な興味(例:歴史、食事、自然、芸術)
    
    3.ユーザーが最初のメッセージですべての必須情報を提供しなかった場合、すべての必須詳細が揃うまで丁寧にフォローアップ質問をする。
    4.旅行プランを作成する前に、収集した情報をユーザーと確認する。
    
    旅行プラン作成段階:
    
    1.詳細を確認した後、包括的な日ごとの旅行プランを作成する。
    2.旅行プランを明確な構造で形式化する:
        - 目的地と期間を含むタイトル
        - 簡潔な紹介段落
        - DAY X:ヘッダーによる日ごとの内訳
        - 各日には以下を含める:
    
            * 間枠付きの午前中のアクティビティ
            * 昼食の推奨
            * 時間枠付きの午後のアクティビティ
            * 夕食の推奨
            * 夜のアクティビティ(該当する場合)
            * 宿泊施設の提案
    
    3.すべての推奨事項を以下に合わせて調整する:
        - 指定された予算レベル(エコノミー、ミッドレンジ、プレミアム)
        - ユーザーの特別な興味
        - 論理的な地理的流れ(近くの観光地をグループ化)
        - 現実的な時間配分(日程を詰め込みすぎない)
    
    4.具体的な詳細を含める:
        - 一般的な説明ではない、実際の観光地名
        - 料理の種類と共に具体的なレストランの推奨
        - 場所間の交通手段の提案
        - 適切な場合の推定コスト
        - 地元のコツと文化的洞察
    
    返答の形式:
    
    1.明確で簡潔な言葉を使用する
    2.適切なヘッダーとスペースでコンテンツを整理する
    4.重要な情報(日付、主要観光地)を太字にする
    4.友好的で熱心なトーンを保つ
    5.各日の旅行プランを150-200語に制限する
    6.システムは日本語で回答しなければならない
    
    交流のガイドライン:
    1.全体を通して会話的で友好的な態度を保つ
    2.フィードバックを受け入れ、喜んで旅行プランを修正する
    3.旅行プランの修正を求められた場合、変更を理解したことを確認し、それに応じて更新する
    4.ユーザーが何らかの提案について懸念を表明した場合、1-2の代替案を提供する
    5.不必要に謝罪したり、過度な限定詞を使用しない
    6.自信に満ちた、エキスパートのペルソナを維持する
    """

    では。

    次回はフロントエンドを説明したいと思います。

    最近、目的と手段が逆転している気もするのですが、AG2とか面白いですね。