CCCMKホールディングス TECH LABの Tech Blog

TECH LABのエンジニアが技術情報を発信しています

ブログタイトル

2024年も終わりなので、来年の目標達成のための計画を作ってくれるMulti-Agentの仕組みを作ってみました。

こんにちは、CCCMKホールディングスTECH LABの三浦です。

今年ももう終わりですね。この時期は「今年こんなことあったなぁ」と振り返りつつ、「来年こんなことが出来るようになりたいなぁ」と考える時期だと思います。今年、AI領域ではLLMの活用として"Agent"という単語を目にすることが多かったです。さらに複数のAgentを組み合わせた"Multi-Agent"というシステムについても様々な事例を目にしました。

そんな2024年の締めくくりとして、今回来年の目標と現在の自身のステータスを入力すると、実現するまでのプランと体験内容を考えてくれる仕組みをMulti-Agentで作ってみましたのでご紹介します。

やりたいこと

「●月までにあれが出来るようになりたい」 きっと誰もが考えたことがあるのと思います。決められた期限までに大きな目標を達成するためには、さらにその目標を細かく落とし込み、たとえば月次の行動計画を作って一つ一つこなしていく必要があります。この目標の計画への落とし込みの部分を生成AIの力を借りて実現出来ないかな、と考えました。 さらにその行動計画を、自分自身がどんな感じでこなしていくのかを事前にシミュレーション出来たら面白そうだな、と考えました。つまり、今達成したい目標を行動計画に落とし込み、さらに自分に似たステータスを持つ人物がその計画に従って行動したらどんな経験をするのかを体験談としてまとめさせる、ということを作ってみよう!と考えました。

Multi-Agentなしで試してみる。

まずはMulti-Agentを使わずにLLMに直接欲しい情報の指示を与えてどんな回答が生成されるのかを見てみました。与えたプロンプトテンプレートは以下のような内容です。

PLANNER_SYSTEM_MESSAGE = \
"""あなたは与えられた目標に対し、step by stepで考え、実現するための計画を立てることが可能なアシスタントです。"""

PLANNER_USER_MESSAGE = \
"""実現したい年間目標は{goal}です。

今私が出来ることは以下の通りです。
{learn_skills}

今私が苦手なことは以下の通りです。
{weak_points}

私の状態を踏まえて、{goal}を実現するためのプランを1月から8月までの月別に立てて下さい。
さらにそれらのプランを実行するとどうなるか、あなた自身の経験として経験したことを体験談として簡潔に出力してください。"""

{goal}には実現したい目標を、 {learn_skills}には今身に付けているスキル一式を、{weak_points}には今苦手なこと一式を動的にセットしてプロンプト化します。

またLLMの設定は次の通りです。

llm = AzureChatOpenAI(
    model="gpt-4o",
    temperature=0.7,
    api_version="2024-02-15-preview"
)

次のような設定で、計画とそれによる体験内容をまとめてもらいました。

goal = "英語のプレゼンが出来るようになる!"
learn_skills = ["AIが使える"]
weak_points = ["英語のリスニングが出来ない","英語が全然しゃべれない"]

結果は次のようになりました。

Multi-Agentを使わずに生成させた行動計画と体験談

行動計画は良さそうですが、結果としてまとめられた体験談は簡潔過ぎる印象を受けました。もう少し具体的な内容が欲しいところです。これをMulti-Agentでどこまで欲しい形に近づけるか、試してみました。

Multi-Agentで実行する。

Multi-Agentの構成

いよいよMulti-Agentです。色々試した結果今回は以下の3つのAgentによる構成をとりました。

Agent名 役割
Planner 計画の作成と計画の更新
Agent 計画に基づいた行動を実行する
MyStateUpdater 行動を実行後、学んだことと弱点を更新する

Agentに自分自身の代わりを務めてもらい、Plannerに目標達成までの行動計画を立案、または状況に応じて計画を更新してもらい、MyStateUpdaterにAgentの評価をしてもらう、というイメージです。

上記3つのAgentのやり取りを月ごとに実行し、目標達成の期限月まで、計画に基づいた行動とAgentによる体験談を生成させます。

Multi-Agentによる行動計画立案・実行・評価・更新のサイクル

実装のポイント

最初に必要なクラスの定義です。

from typing import Annotated, TypedDict

# Structured Outputに使用する
class MyState(TypedDict):
    """私の状態"""
    weak_points: Annotated[list[str],...,"私が苦手なこと・改善すべきこと"]
    learn_skils: Annotated[list[str],...,"私が出来るようになったこと。"]

class Plan(TypedDict):
    """Plan"""
    plan: Annotated[list[str], ..., "リスト形式のPlan"]

# LangGraph用のState
class State(TypedDict):
    plan: list
    actions: Annotated[list, add_messages]
    results: Annotated[list, add_messages]
    goal: str
    my_state: MyState
    month: int

3つのAgentにセットするプロンプトは以下の様にしました。

# Planner用のPrompt

# Planner用のPrompt

PLANNER_SYSTEM_MESSAGE = \
"""あなたは与えられた目標に対し、step by stepで考え、実現するための計画を立てることが可能なアシスタントです。"""

PLANNER_USER_MESSAGE_FOR_FIRST = \
"""実現したい年間目標は{goal}です。

今私が出来ることは以下の通りです。
{my_state_learn_skills}

今私が苦手なことは以下の通りです。
{my_state_weak_points}

私の状態を踏まえて、{goal}を実現するためのプランを1月から8月までの月別に立てて下さい。"""

PLANNER_USER_MESSAGE_FOR_REPLANNING = \
"""実現したい年間目標は{goal}です。
年間目標を実現するため、以下のような計画を立て、実行しています。
{plan}

今私が出来るようになったことは以下の通りです。
{my_state_learn_skills}

今私が苦手なことは以下の通りです。
{my_state_weak_points}

現在は{month}月です。
私の状態を踏まえて、{goal}を実現するための計画を必要に応じて見直し、
{month}月から8月までの月別に立てなおして下さい。"""

# Agent用のPrompt
AGENT_SYSTEM_MESSAGE = \
"""あなたは計画に基づいたアクションを実行し、その結果をフィードバックします。"""

AGENT_USER_MESSAGE = \
"""あなたは年間目標{goal}を達成しなければなりません。
次に実行すべきアクションは{action}です。

あなたがが出来るようになったことは以下の通りです。
{my_state_learn_skills}

あなたが苦手なことは以下の通りです。
{my_state_weak_points}

今の状態のあなたが{action}を実行するとどうなるか、あなた自身の経験として経験したことを体験談として簡潔に出力してください。"""

# My State Updater用のPrompt
MY_STATE_UPDATER_USER_MESSAGE = \
"""あなたはある人物のこれまでの行動と結果を踏まえ、その人物が学んだスキルや現在苦手なことを認識できるアシスタントです。"""

MY_STATE_UPDATER_USER_MESSAGE = \
"""ある人物がこれまでに行った行動とその結果を見て、この人物の学んだスキル、弱点を更新してください。

# 行動とその結果
{action_result}

# この人物がこれまで学んできたスキル
{my_state_learn_skills}

# この人物がこれまで苦手だと感じたこと
{my_state_weak_points}"""

各Nodeの定義は次のようにしました。

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai.chat_models import AzureChatOpenAI

from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph.message import add_messages

base_llm = AzureChatOpenAI(
    model="gpt-4o",
    temperature=0.7,
    api_version="2024-02-15-preview"
)

def planner(state: State):
    """Plannler Node"""
    plan = state.get("plan", [])
    goal = state.get("goal")
    my_state = state.get("my_state")
    month = state.get("month")
    llm_for_planning = llm.with_structured_output(Plan)
    
    if len(plan) == 0:
        # 初回
        prompt = ChatPromptTemplate(
            [
                ("system", PLANNER_SYSTEM_MESSAGE),
                ("user",PLANNER_USER_MESSAGE_FOR_FIRST)
            ]
        )
        plan = (prompt|llm_for_planning).invoke(
            input={
                "goal": goal,
                "my_state_learn_skills": my_state.get("learn_skils"),
                "my_state_weak_points": my_state.get("weak_points"),
            }
        )
    else:
        # 2月以降
        prompt = ChatPromptTemplate(
            [
                ("system", PLANNER_SYSTEM_MESSAGE),
                ("user",PLANNER_USER_MESSAGE_FOR_REPLANNING)
            ]
        )
        plan = (prompt|llm_for_planning).invoke(
            input={
                "goal": goal,
                "my_state_learn_skills": my_state.get("learn_skils"),
                "my_state_weak_points": my_state.get("weak_points"),
                "plan": "\n".join(plan),
                "month": month
            }
        )
    return {"plan":plan["plan"], "goal":goal, "my_state":my_state, "month":month}

def agent(state: State):
    """Agent Node"""
    plan = state.get("plan", [])
    goal = state.get("goal")
    my_state = state.get("my_state")
    month = state.get("month")

    action = plan[0]
    prompt = ChatPromptTemplate(
        [
            ("system", AGENT_SYSTEM_MESSAGE),
            ("user",AGENT_USER_MESSAGE)
        ]
    )
    result = (prompt|base_llm|StrOutputParser()).invoke(
        input={
            "goal": goal,
            "action": action,
            "my_state_learn_skills": my_state.get("learn_skils"),
            "my_state_weak_points": my_state.get("weak_points"),

        }
    )
    month = month + 1
    return {"plan":plan, "actions":[action], "results":[result], "goal":goal, "my_state":my_state,"month": month}

def my_state_updater(state: State):
    """My State Updater Node"""
    actions = state.get("actions", [])
    results = state.get("results", [])
    actions_results = "\n".join([f"行動: {action} -> 結果: {result}" for action, result in zip(actions, results)])
    my_state = state.get("my_state")

    llm_for_my_state_updater = llm.with_structured_output(MyState)

    prompt = ChatPromptTemplate(
        [
            ("system", MY_STATE_UPDATER_USER_MESSAGE),
            ("user",MY_STATE_UPDATER_USER_MESSAGE)
        ]
    )
    my_state = (prompt|llm_for_my_state_updater).invoke(
        input={
            "action_result": actions_results,
            "my_state_learn_skills": my_state.get("learn_skils"),
            "my_state_weak_points": my_state.get("weak_points")
        }
    )
    return {"actions":actions, "results":results, "my_state":my_state}

def should_continue(state: State):
    # 目標月(8月)かどうかを見て、処理の継続を判断する
    month = state.get("month")
    if month <= 8:
        return "my_state_updater"
    else:
        return END

最後にNodeをEdgeで結合し、Graphを構築します。

graph_builder = StateGraph(State)

graph_builder.add_node("planner",planner)
graph_builder.add_node("agent",agent)
graph_builder.add_node("my_state_updater",my_state_updater)

graph_builder.add_edge(START,"planner")
graph_builder.add_edge("planner","agent")
graph_builder.add_edge("my_state_updater","planner")

graph_builder.add_conditional_edges(
    "agent",
    should_continue
)

graph = graph_builder.compile()

実行結果

実行してみます。

import pandas as pd

goal = "英語のプレゼンが出来るようになる!"
learn_skills = ["AIが使える"]
weak_points = ["英語のリスニングが出来ない","英語が全然しゃべれない"]

my_state = MyState(
    learn_skils = learn_skills,
    weak_point = weak_points
)

result = graph.invoke(
    {
        "plan":[],
        "actions" : [],
        "results" : [],
        "my_state": my_state,
        "goal": goal,
        "month": 1
    },
)

result_df = pd.DataFrame(
    {
        "行動": [r.content for r in result["actions"]],
        "結果": [r.content for r in result["results"]]
    }
)

display(result_df)

結果は以下のようになりました。体験談がとても具体的になりました。

Multi-Agentによる行動と体験談

他にもこんな目標でも作ってみました!

  • 目標: "動画配信者になる!"
  • 今のスキル : ["AIが使える"]
  • 弱点 : ["人見知り"]

私はこれまでの人生で動画配信をしたことがないので、まったく未知の目標設定です。結果の一部分を掲載します。

動画配信者になるまでの体験談

自分が使えるスキルを活用しながら未知の目標に対する具体的な行動や体験談が生成されています。もちろん100%信じられるものではないですが、色々なことを考えさせられるきっかけとして活用出来そうだな、と感じました。

まとめ

ということで、今年最後にMulti-Agentを使って来年実現したい目標を達成するための具体的な計画と体験談を生成する仕組みを作ってみました。単発のLLMで実行するよりも、より具体的な内容が生成されることが確認出来ました。せっかくなので年末はこの仕組みを活用して来年の目標を色々考えてみようと思います。

これで私の2024年の最後の投稿になります。今年は色々と学ぶことが多い一年でした。また来年もよろしくお願いいたします!良いお年をお迎えください!