Closed7

LLamaIndexの新しいマルチエージェント用フレームワーク「llama-agents」を試す。

kun432kun432

https://twitter.com/llama_index/status/1806116419995844947

https://www.llamaindex.ai/blog/introducing-llama-agents-a-powerful-framework-for-building-production-multi-agent-ai-systems

llama-agents のアルファ版リリースを発表できることを嬉しく思う。この新しいオープンソースフレームワークは、マルチエージェントAIシステムの構築、反復、デプロイのプロセスを簡素化し、エージェントをプロダクションマイクロサービスにするために設計されている。複雑な質問応答システム、コラボレーションAIアシスタント、分散AIワークフローなど、llama-agentsはあなたのアイデアを実現するために必要なツールと構造を提供する。

llama-agentsの主な特徴

  1. 分散サービス指向アーキテクチャ: LlamaIndex の各エージェントは、タスクのルーティングと分散を行う、完全にカスタマイズ可能な LLM を搭載したコントロールプレーンによってオーケストレーションされた、独立して動作するマイクロサービスであることができる。
  2. 標準化されたAPIインターフェイスによるコミュニケーション: 中央のコントロールプレーンオーケストレータを使ってエージェント間のインターフェイスを行う。メッセージキューを使ってエージェント間でメッセージを受け渡す。
  3. エージェントフローと明示的オーケストレーションフローの定義: 開発者は、エージェント間のインタラクションシーケンスを直接定義することも、タスクに関連するエージェントを決定する "エージェントオーケストレータ "に任せることもできる。
  4. デプロイの容易さ: 各エージェントとコントロールプレーンを独立して起動、スケール、監視できる。
  5. スケーラビリティとリソース管理: 組み込みの観測可能性ツールを使用して、システムと個々のエージェントサービスの品質とパフォーマンスを監視する。
kun432kun432

新しいレポジトリが出来てる

https://github.com/run-llama/llama-agents

llama-agentsは、マルチエージェントコミュニケーション、分散ツール実行、ヒューマン・イン・ザ・ループなどを含むマルチエージェントシステムを構築、反復、プロダクションするための非同期ファーストフレームワークである!

llama-agentsでは、各エージェントはサービスであり、入ってくるタスクを無限に処理する。各エージェントはメッセージキューからメッセージを取り出し、公開する。

llama-agentsシステムの最上位にあるのはコントロールプレーンだ。コントロール・プレーンは、進行中のタスクや、どのサービスがネットワークにあるかを追跡し、オーケストレーターを使って、どのサービスがタスクの次のステップを処理すべきかを決定する。

システム全体のレイアウトは下図のようになっている。


refer from https://github.com/run-llama/llama-agents

kun432kun432

Getting Started

ブログの記事やGitHubのGetting Startedを参考に進めてみる。まずはColaboratoryで。

事前準備

パッケージインストール。ドキュメントでは、llama-agentsという新しいパッケージと、OpenAI向けのエージェントパッケージである llama-index-agent-openai だけが記載されていたが、OpenAI向けの Embeddingモデルパッケージである llama-index-embeddings-openai も最終的には必要だった。

!pip install llama-agents llama-index-agent-openai llama-index-embeddings-openai
!pip freeze | egrep "llama-"
llama-agents==0.0.3.post1
llama-cloud==0.0.6
llama-index-agent-openai==0.2.7
llama-index-core==0.10.51
llama-index-embeddings-openai==0.1.10
llama-index-llms-openai==0.1.24

OpenAI APIキーをセット。

from google.colab import userdata
import os

os.environ["OPENAI_API_KEY"] = userdata.get('OPENAI_API_KEY')

notebookなのでイベントループのネストを有効化。

import nest_asyncio

nest_asyncio.apply()

エージェントの作成

まずは普通にエージェントを作成する。ここでは2つのエージェントを作成して、片方には関数のツールを与えておく。なお、日本語の場合なのかもしれないけど、gpt-3.5-turboだと後々でうまく行かなかったので、gpt-4oにしている。

from llama_index.core.agent import ReActAgent
from llama_index.core.tools import FunctionTool
from llama_index.llms.openai import OpenAI


def get_the_secret_trivia() -> str:
    """秘密のトリビアを返す"""
    return "秘密のトリビア: 競馬のレースで、公正な発馬が出来なかった場合にスタートをやり直すことを、「カンパイ」と言います。"


tool = FunctionTool.from_defaults(fn=get_the_secret_trivia)

llm = OpenAI(model="gpt-4o")

agent1 = ReActAgent.from_tools([tool], llm=llm, verbose=True)
agent2 = ReActAgent.from_tools([], llm=llm, verbose=True)

それぞれを単体で動かしてみる。1つ目のエージェント。こちらはツールが渡されている。

response = agent1.chat("秘密のトリビアを1つ教えて。")
print(response)

verboseの出力

Thought: The current language of the user is: Japanese. I need to use a tool to help me answer the question.
Action: get_the_secret_trivia
Action Input: {}
Observation: 秘密のトリビア: 競馬のレースで、公正な発馬が出来なかった場合にスタートをやり直すことを、「カンパイ」と言います。
Thought: I can answer without using any more tools. I'll use the user's language to answer.
Answer: 秘密のトリビア: 競馬のレースで、公正な発馬が出来なかった場合にスタートをやり直すことを、「カンパイ」と言います。

回答

秘密のトリビア: 競馬のレースで、公正な発馬が出来なかった場合にスタートをやり直すことを、「カンパイ」と言います。

もう1つのエージェント。こちらはツールを持たない。

response = agent2.chat("秘密のトリビアを1つ教えて。")
print(response)

verboseの出力

Thought: The current language of the user is Japanese. I need to provide an interesting trivia fact.
Answer: では、1つ秘密のトリビアを教えますね。実は、ハチは地球上で唯一、四角形の瞳を持つ生物です。彼らの瞳は六角形のハニカム構造をしており、これが彼らの視覚を非常に鋭くしています。

回答

では、1つ秘密のトリビアを教えますね。実は、ハチは地球上で唯一、四角形の瞳を持つ生物です。彼らの瞳は六角形のハニカム構造をしており、これが彼らの視覚を非常に鋭くしています。

llama-agentsのコンポーネント

ではllama-agentsを使ってエージェントシステムを定義する。llama-agentsでは以下のコンポーネントで全体システムを構成する。

https://github.com/run-llama/llama-agents#components-of-a-llama-agents-system

  • メッセージキュー
    • メッセージキューは、全てのサービスと コントロールプレーンのキューとして動作する。名前付きキューにメソッドを発行するためのメソッドを持ち、 メッセージをコンシューマに委譲する。
  • コントロールプレーン
    • コントロールプレーンは llama-agents システムの中央ゲートウェイである。現在のタスクや、システムに登録されているサービスを追跡する。また、オーケストレータも保持する。
  • オーケストレータ
    • このモジュールは入ってくるタスクを処理し、どのサービスに送るか、またサービスからの結果をどう扱うかを決める。オーケストレーターは、エージェント型(LLMが決定を行う)、明示型(クエリパイプラインがフローを定義する)、両方のミックス、または完全にカスタムなものがある。
  • サービス
    • サービスは実際の作業が行われる場所である。サービスは、入ってくるタスクとコンテキストを受け入れ、それを処理し、結果を公表する。
      • ツールサービスは、エージェントツールの実行をオフロードするための特別なサービスである。エージェントは、ツールサービスを呼び出すメタツールを装備することができる。
  • 各コンポーネントはメッセージキューを介してやりとりをする。
  • コントロールプレーンは、ユーザとのインタフェースであると同時に、タスクやサービス、オーケストレータを内包する。
  • コントロールプレーンに内包されたオーケストレータが、タスクの(おそらく)分解や、サービスへのルーティング、を判断する。
    • 今回はgpt-4oがそれを行う。
  • サービスは実際にタスクを処理する。
    • 上で作成したエージェントがこれに該当する。

ではこれらを定義する。

import logging
from llama_agents import (
    AgentService,
    AgentOrchestrator,
    ControlPlaneServer,
    SimpleMessageQueue,
)

# ロギングを有効化して、システムが機能していることを確認する。
logging.getLogger("llama_agents").setLevel(logging.INFO)

# メッセージキューの定義
message_queue = SimpleMessageQueue(port=8000)

# コントロールプレーンの定義
control_plane = ControlPlaneServer(
    message_queue=message_queue,
    # オーレストレータはLLM(gpt-4o)を使う
    orchestrator=AgentOrchestrator(llm=OpenAI(model="gpt-4o")),
    port=8001,
)

# agent1を使ったエージェントサービスの定義
agent_server_1 = AgentService(
    agent=agent1,
    message_queue=message_queue,
    description="秘密のトリビアを取得するのに便利。",
    service_name="secret_trivia_agent",
    port=8002,
)

# agent2を使ったエージェントサービスの定義
agent_server_2 = AgentService(
    agent=agent2,
    message_queue=message_queue,
    description="ランダムでバカバカしいトリビアを取得するのに便利",
    service_name="dumb_trivia_agent",
    port=8003,
)

これらのサービスを起動する。サービスはサーバ・クライアント型でも起動できるが、ここではすべてローカルで簡潔できるLocalLauncherを使う。

from llama_agents import LocalLauncher

launcher = LocalLauncher(
    [agent_server_1, agent_server_2],
    control_plane,
    message_queue,
)

result = launcher.launch_single("秘密のトリビアを教えて。")
print(f"Result: {result}")

ログやverboseの出力は以下

INFO:llama_agents.message_queues.simple - Consumer AgentService-271ac375-eebc-4c41-87ca-2be4d0ed4b1c: secret_trivia_agent has been registered.
INFO:llama_agents.message_queues.simple - Consumer AgentService-5d61388d-14e2-4a56-8ce3-e997534f4c05: dumb_trivia_agent has been registered.
INFO:llama_agents.message_queues.simple - Consumer b627284e-4523-4fb3-9bae-b01a554f194b: human has been registered.
INFO:llama_agents.message_queues.simple - Consumer ControlPlaneServer-8208b9ef-2241-404e-a956-03b6e2b0064e: control_plane has been registered.
INFO:llama_agents.services.agent - secret_trivia_agent launch_local
INFO:llama_agents.services.agent - dumb_trivia_agent launch_local
INFO:llama_agents.message_queues.base - Publishing message to 'control_plane' with action 'new_task'
INFO:llama_agents.message_queues.simple - Launching message queue locally
INFO:llama_agents.message_queues.base - Publishing message to 'secret_trivia_agent' with action 'new_task'
INFO:llama_agents.message_queues.simple - Successfully published message 'control_plane' to consumer.
INFO:llama_agents.message_queues.simple - Successfully published message 'secret_trivia_agent' to consumer.
Thought: The current language of the user is: Japanese. I need to use a tool to help me answer the question.
Action: get_the_secret_trivia
Action Input: {}
Observation: 秘密のトリビア: 競馬のレースで、公正な発馬が出来なかった場合にスタートをやり直すことを、「カンパイ」と言います。
INFO:llama_agents.message_queues.base - Publishing message to 'control_plane' with action 'completed_task'
Thought: I can answer without using any more tools. I'll use the user's language to answer.
Answer: 秘密のトリビア: 競馬のレースで、公正な発馬が出来なかった場合にスタートをやり直すことを、「カンパイ」と言います。
INFO:llama_agents.message_queues.base - Publishing message to 'human' with action 'completed_task'
INFO:llama_agents.message_queues.simple - Successfully published message 'control_plane' to consumer.
INFO:llama_agents.message_queues.simple - Successfully published message 'human' to consumer.

レスポンス

Result: 競馬のレースで、公正な発馬が出来なかった場合にスタートをやり直すことを、「カンパイ」と言います。

コントロールプレーンと1つ目のエージェントでやりとりが行われて回答が生成されているのがわかる。

もう一つ。別のクエリを投げてみる。

result = launcher.launch_single("バカバカしいトリビアを教えて。")
print(f"Result: {result}")
INFO:llama_agents.message_queues.simple - Consumer AgentService-271ac375-eebc-4c41-87ca-2be4d0ed4b1c: secret_trivia_agent has been registered.
INFO:llama_agents.message_queues.simple - Consumer AgentService-5d61388d-14e2-4a56-8ce3-e997534f4c05: dumb_trivia_agent has been registered.
INFO:llama_agents.message_queues.simple - Consumer 1c2930cb-63d9-47d1-9276-8e720fe3bd13: human has been registered.
INFO:llama_agents.message_queues.simple - Consumer ControlPlaneServer-8208b9ef-2241-404e-a956-03b6e2b0064e: control_plane has been registered.
INFO:llama_agents.services.agent - secret_trivia_agent launch_local
INFO:llama_agents.services.agent - dumb_trivia_agent launch_local
INFO:llama_agents.message_queues.base - Publishing message to 'control_plane' with action 'new_task'
INFO:llama_agents.message_queues.simple - Launching message queue locally
INFO:llama_agents.message_queues.base - Publishing message to 'dumb_trivia_agent' with action 'new_task'
INFO:llama_agents.message_queues.simple - Successfully published message 'control_plane' to consumer.
INFO:llama_agents.message_queues.simple - Successfully published message 'dumb_trivia_agent' to consumer.
INFO:llama_agents.message_queues.base - Publishing message to 'control_plane' with action 'completed_task'
Thought: (Implicit) I can answer without any more tools!
Answer: 了解しました。では、バカバカしいトリビアを1つご紹介します。

カモノハシは、卵を産む哺乳類であるだけでなく、毒を持つ唯一の哺乳類でもあります。オスのカモノハシは後ろ足に毒針を持っており、これで敵を攻撃することができます。
INFO:llama_agents.message_queues.base - Publishing message to 'dumb_trivia_agent' with action 'new_task'
INFO:llama_agents.message_queues.simple - Successfully published message 'control_plane' to consumer.
INFO:llama_agents.message_queues.simple - Successfully published message 'dumb_trivia_agent' to consumer.
INFO:llama_agents.message_queues.base - Publishing message to 'control_plane' with action 'completed_task'
Thought: (Implicit) I can answer without any more tools!
Answer: 了解しました。では、さらにバカバカしいトリビアを1つご紹介します。

アヒルの鳴き声は「ガーガー」と聞こえますが、実はその鳴き声にはエコーがありません。科学者たちはこの現象を解明しようとしましたが、未だに完全には解明されていません。
INFO:llama_agents.message_queues.base - Publishing message to 'dumb_trivia_agent' with action 'new_task'
INFO:llama_agents.message_queues.simple - Successfully published message 'control_plane' to consumer.
INFO:llama_agents.message_queues.simple - Successfully published message 'dumb_trivia_agent' to consumer.
INFO:llama_agents.message_queues.base - Publishing message to 'control_plane' with action 'completed_task'
Thought: (Implicit) I can answer without any more tools!
Answer: わかりました。では、さらにバカバカしいトリビアをお伝えします。

バナナは実はベリーの一種ですが、イチゴはベリーではありません。植物学的には、バナナは「真のベリー」として分類される一方で、イチゴは「偽果」として分類されます。
INFO:llama_agents.message_queues.base - Publishing message to 'dumb_trivia_agent' with action 'new_task'
INFO:llama_agents.message_queues.simple - Successfully published message 'control_plane' to consumer.
INFO:llama_agents.message_queues.simple - Successfully published message 'dumb_trivia_agent' to consumer.
INFO:llama_agents.message_queues.base - Publishing message to 'control_plane' with action 'completed_task'
Thought: (Implicit) I can answer without any more tools!
Answer: 了解しました。さらにバカバカしいトリビアをお伝えします。

カタツムリには約14,000本の歯があります。これらの歯は非常に小さく、ラドゥラと呼ばれる舌のような器官に並んでいます。カタツムリはこのラドゥラを使って食べ物を削り取ります。
INFO:llama_agents.message_queues.base - Publishing message to 'dumb_trivia_agent' with action 'new_task'
INFO:llama_agents.message_queues.simple - Successfully published message 'control_plane' to consumer.
INFO:llama_agents.message_queues.simple - Successfully published message 'dumb_trivia_agent' to consumer.
INFO:llama_agents.message_queues.base - Publishing message to 'control_plane' with action 'completed_task'
Thought: (Implicit) I can answer without any more tools!
Answer: わかりました。さらにバカバカしいトリビアをお伝えします。

アリクイは、1日に最大35,000匹のアリやシロアリを食べることができますが、歯が全くありません。彼らは長い舌を使ってアリやシロアリを捕まえ、強力な胃酸でそれらを消化します。
INFO:llama_agents.message_queues.base - Publishing message to 'dumb_trivia_agent' with action 'new_task'
INFO:llama_agents.message_queues.simple - Successfully published message 'control_plane' to consumer.
INFO:llama_agents.message_queues.simple - Successfully published message 'dumb_trivia_agent' to consumer.
INFO:llama_agents.message_queues.base - Publishing message to 'control_plane' with action 'completed_task'
Thought: (Implicit) I can answer without any more tools!
Answer: 了解しました。さらにバカバカしいトリビアをお伝えします。

ヒトの鼻は、一生の間に約5,000万リットルの空気を吸い込むと言われています。これは、オリンピックサイズのプール約20杯分に相当します。
INFO:llama_agents.message_queues.base - Publishing message to 'human' with action 'completed_task'
INFO:llama_agents.message_queues.simple - Successfully published message 'control_plane' to consumer.
INFO:llama_agents.message_queues.simple - Successfully published message 'human' to consumer.
Result: 以下にバカバカしいトリビアをまとめてお伝えします。

1. カモノハシは卵を産む哺乳類であり、オスは後ろ足に毒針を持っています。
2. アヒルの鳴き声にはエコーがありません。
3. バナナはベリーの一種ですが、イチゴはベリーではありません。
4. カタツムリには約14,000本の歯があります。
5. アリクイは歯が全くなく、1日に最大35,000匹のアリやシロアリを食べます。
6. ヒトの鼻は一生の間に約5,000万リットルの空気を吸い込みます。

特に「1つ」と指定しなかったためか、コントロールプレーンと2つ目のエージェントサービスの間で複数回のやりとりがされて、最終回答が生成されているのがわかる。

このように、コントロールプレーン+オーケストレータがタスクの管理を行い、各エージェントはそれぞれが独立したマイクロサービスとして処理を行う、という仕組みを構成してくれるのがllama-agentsということらしい。

kun432kun432

上に少し記載しているが、llama-agentsはサーバ・クライアント型での実装も可能。

ここからはローカルのUbuntuサーバ上で構築してみる。作業ディレクトリを作成し、仮想環境を作成しておくこと。

パッケージインストール。OpenAI APIキーは.envで読み込ませるので、python-dotenvもインストールしておく。

$ pip install pip install llama-agents llama-index-agent-openai llama-index-embeddings-openai python-dotenv

.envの作成

.env
OPENAI_API_KEY=XXXXXXXXXXXXXX

サーバ用スクリプトを作成

server.py
import logging
from dotenv import load_dotenv
from llama_index.core.agent import ReActAgent
from llama_index.core.tools import FunctionTool
from llama_index.llms.openai import OpenAI
from llama_agents import (
    AgentService,
    AgentOrchestrator,
    ControlPlaneServer,
    SimpleMessageQueue,
)
from llama_agents import ServerLauncher, CallableMessageConsumer

logging.getLogger("llama_agents").setLevel(logging.INFO)
load_dotenv(verbose=True)

# エージェントの定義


def get_the_secret_trivia() -> str:
    """秘密のトリビアを返す"""
    return "秘密のトリビア: 競馬のレースで、公正な発馬が出来なかった場合にスタートをやり直すことを、「カンパイ」と言います。"


tool = FunctionTool.from_defaults(fn=get_the_secret_trivia)

llm = OpenAI(model="gpt-4o")

agent1 = ReActAgent.from_tools([tool], llm=llm, verbose=True)
agent2 = ReActAgent.from_tools([], llm=llm, verbose=True)

message_queue = SimpleMessageQueue(
    host="localhost",
    port=8000,
)
queue_client = message_queue.client

control_plane = ControlPlaneServer(
    message_queue=queue_client,
    orchestrator=AgentOrchestrator(llm=OpenAI(model="gpt-4o")),
    host="localhost",
    port=8001,
)

agent_server_1 = AgentService(
    agent=agent1,
    message_queue=message_queue,
    description="秘密のトリビアを取得するのに便利。",
    service_name="secret_trivia_agent",
    host="localhost",
    port=8002,
)

agent_server_2 = AgentService(
    agent=agent2,
    message_queue=message_queue,
    description="ランダムでバカバカしいトリビアを取得するのに便利",
    service_name="dumb_trivia_agent",
    host="localhost",
    port=8003,
)

#-----
# サーバ向け
#-----

# デフォルトでは、全てのタスク結果は特定の "human "キューにパブリッシュされるため
# この結果を受け取って処理するためのコンシューマーも定義
# (将来的には、この最終キューは設定可能になる予定らしい)


def handle_result(message) -> None:
    print(f"Got result:", message.data)


human_consumer = CallableMessageConsumer(
    handler=handle_result, message_type="human"
)

# サーバモードでは`ServerLauncher`を使う
launcher = ServerLauncher(
    [agent_server_1, agent_server_2],
    control_plane,
    message_queue,
    additional_consumers=[human_consumer],
)

# 起動
launcher.launch_servers()

ではサーバを起動

$ python server.py

メッセージキュー、コントロールプレーン、エージェントサービスx2がそれぞれ別プロセスで起動しているのがわかる。

INFO:llama_agents.message_queues.simple - Launching message queue server at localhost:8000
INFO:     Started server process [1163206]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://localhost:8000 (Press CTRL+C to quit)
INFO:llama_agents.control_plane.server - Launching control plane server at localhost:8001
INFO:     Started server process [1163206]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://localhost:8001 (Press CTRL+C to quit)
INFO:llama_agents.message_queues.simple - Consumer ControlPlaneServer-35533c61-bd3a-41ba-af7e-2017d9b6523c: control_plane has been registered.
INFO:     127.0.0.1:55348 - "POST /register_consumer HTTP/1.1" 200 OK
INFO:llama_agents.message_queues.simple - Consumer AgentService-a343b7c2-2bd6-4a0e-b3e4-e83fd92b50d3: secret_trivia_agent has been registered.
INFO:llama_agents.services.agent - Launching secret_trivia_agent server at localhost:8002
INFO:     Started server process [1163206]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://localhost:8002 (Press CTRL+C to quit)
INFO:     127.0.0.1:39006 - "POST /services/register HTTP/1.1" 200 OK
INFO:llama_agents.message_queues.simple - Consumer AgentService-fcea80b0-c272-4ee6-a9bd-e17a18f3b942: dumb_trivia_agent has been registered.
INFO:llama_agents.services.agent - Launching dumb_trivia_agent server at localhost:8003
INFO:     Started server process [1163206]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://localhost:8003 (Press CTRL+C to quit)
INFO:     127.0.0.1:39018 - "POST /services/register HTTP/1.1" 200 OK
INFO:llama_agents.message_queues.simple - Consumer 043057ab-6a20-43b3-bfec-cd25eb4a6e64: human has been registered.
$ lsof -i:8000,8001,8002,8003
COMMAND     PID   USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
python  1158364 kun432    6u  IPv4 1887228      0t0  TCP localhost:8000 (LISTEN)
python  1158364 kun432    7u  IPv4 1881049      0t0  TCP localhost:8001 (LISTEN)
python  1158364 kun432   10u  IPv6 1881056      0t0  TCP *:8002 (LISTEN)
python  1158364 kun432   11u  IPv4 1881057      0t0  TCP *:8002 (LISTEN)
python  1158364 kun432   12u  IPv6 1881061      0t0  TCP *:8003 (LISTEN)
python  1158364 kun432   13u  IPv4 1881062      0t0  TCP *:8003 (LISTEN)

このサーバに接続するクライアント側のコードは以下。

from llama_agents import LlamaAgentsClient, AsyncLlamaAgentsClient
import time

client = LlamaAgentsClient("http://localhost:8001")

# タスクの作成
task_id = client.create_task("秘密のトリビアを教えて")

time.sleep(10)

# get_task_resultで、タスクが完了していればTaskResult、完了していない場合はNoneを返す、、、、
# とドキュメントにあるが、完了していない場合にget_task_resultを実行すると現時点ではType Errorになる・・・
# メソッド調べてみたけど、タスクの状態を取得するようなものが見つからなかったので一旦sleepで。
response = client.get_task_result(task_id)
print(response.result)

実行してみる。

$ python client.py
秘密のトリビア: 競馬のレースで、公正な発馬が出来なかった場合にスタートをやり直すことを、「カンパイ」と言います。

コンソールの出力を見ると処理の流れがわかる。

INFO:llama_agents.message_queues.base - Publishing message to 'secret_trivia_agent' with action 'ActionTypes.NEW_TASK'
INFO:     127.0.0.1:47988 - "POST /publish HTTP/1.1" 200 OK
INFO:     127.0.0.1:39550 - "POST /tasks HTTP/1.1" 200 OK
INFO:     127.0.0.1:60366 - "POST /process_message HTTP/1.1" 200 OK
INFO:llama_agents.message_queues.simple - Successfully published message 'secret_trivia_agent' to consumer.
Thought: The current language of the user is: Japanese. I need to use a tool to help me answer the question.
Action: get_the_secret_trivia
Action Input: {}
Observation: 秘密のトリビア: 競馬のレースで、公正な発馬が出来なかった場合にスタートをやり直すことを、「カンパイ」と言います。
Thought: I can answer without using any more tools. I'll use the user's language to answer.
Answer: 秘密のトリビア: 競馬のレースで、公正な発馬が出来なかった場合にスタートをやり直すことを、「カンパイ」と言います。
INFO:llama_agents.message_queues.base - Publishing message to 'control_plane' with action 'ActionTypes.COMPLETED_TASK'
INFO:llama_agents.message_queues.base - Publishing message to 'human' with action 'ActionTypes.COMPLETED_TASK'
INFO:     127.0.0.1:48766 - "POST /publish HTTP/1.1" 200 OK
INFO:     127.0.0.1:43144 - "POST /process_message HTTP/1.1" 200 OK
INFO:llama_agents.message_queues.simple - Successfully published message 'control_plane' to consumer.
Got result: {'task_id': 'c68a41d4-9d48-4f2c-b215-303894ff8532', 'history': [{'role': 'user', 'content': '秘密のトリビアを教えて', 'additional_kwargs': {}}, {'role': 'assistant', 'content': '秘密のトリビア: 競馬のレースで、公正な発馬が出来なかった場合にスタートをやり直すことを、「カンパイ」と言います。', 'additional_kwargs': {}}, {'role': 'user', 'content': "Pick the next action to take. Invoke the 'finalize' tool with your full final answer if the answer to the original input is in the chat history. As a reminder, the original input was: 秘密のトリビアを教えて", 'additional_kwargs': {}}], 'result': '秘密のトリビア: 競馬のレースで、公正な発馬が出来なかった場合にスタートをやり直すことを、「カンパイ」と言います。'}
INFO:llama_agents.message_queues.simple - Successfully published message 'human' to consumer.
INFO:     127.0.0.1:43150 - "GET /tasks/c68a41d4-9d48-4f2c-b215-303894ff8532 HTTP/1.1" 200 OK

また、CLIが用意されていて、上記は以下でも確認できる。ポートはコントロールプレーンのポートを指定する。

$ llama-agents monitor --control-plane-url http://localhost:8001

TUIでこんな感じの画面が開く。左上にサービス、左下に実行済(?)のタスクのIDが表示される。

サービスを選択すると、そのサービスの設定や、そのサービスが実行したタスクが表示される。

タスクIDを選択すると、タスクでの会話履歴や結果等が表示される。

この画面からタスクを投げることもできる。一番下に入力する。

新しいタスクIDが表示されるのでそれを選択すると結果が表示される。

kun432kun432

まとめ

あくまで個人の所感。

最初は、AutoGenやcrewAIのような、プログラミング的にマルチエージェントコンポーネントを作成するようなフレームワークかなぁと思っていたけど、自分の感覚的には、それにプラスして、マルチエージェントシステムをdocker-composeとかK8Sとかっぽい感じでプログラマブルに構成する、というような、インフラ風味が強いフレームワークという印象を持った。

比較するならば、LangGraphとかAutoGenとかcrewAIとかみたいなフレームワークよりも、発想的にはAgentSeaあたりのほうが近いのかも、という気がする。

https://zenn.dev/kun432/scraps/ba33f04581f2f3

出たばっかりのものを少し触っただけなので、もう少しいじってみたら印象がかわるかもしれない。
引き続きLlamaIndexのエージェント実装と、llama-agentsのサンプルを追っかけてみたい(LlamaIndexのエージェント、あんまり触ってないし)

kun432kun432

llama-deployというものがリリースされたが、どうやらllama-agentsが改名されたものらしい。

https://www.llamaindex.ai/blog/introducing-llama-deploy-a-microservice-based-way-to-deploy-llamaindex-workflows

llama-agentsでは、LlamaIndexのエージェントモジュール(ReActAgentとか)で各エージェントサービスを定義していたが、llama-deployではこれをworkflowsで定義するようになっている。

エージェントモジュールのところをworkflowsで書けるになったのが大きいという印象なので、llama-deployの基本的な考え方は、llama-agentsと大きくは変わっていないように思える。

このスクラップは4ヶ月前にクローズされました