【生成AI】なぜマルチエージェントのコードにasyncとawaitをよく見かけるのか?

マルチエージェントのコードを見るとasyncとawaitをよく見かけます。

Python公式ドキュメントで学び直します。

目次

asyncio — 非同期 I/O

asyncioは、async/await構文を使い並行処理のコードを書くためのライブラリ。

高性能なネットワークとウェブサーバ、データベース接続ライブラリ、分散タスクキューなどの複数の非同期Python フレームワークの基盤として使われている。

高レベルAPI

asyncioは次の目的で高レベルAPIを提供する。

  • 並行でPythonコルーチンを起動し、実行全体を管理
  • ネットワークIOとIPCを執り行う
  • subprocessesを管理
  • キューを使ってタスクを分散する
  • 並列処理のコードを同期させる

低レベルAPI

ライブラリやフレームワークの開発者が次の事をするための低レベルAPI

  • ネットワーク通信、サブプロセス の実行、OSシグナルの取り扱いなどのための非同期APIを提供するイベントループの作成と管理を行う
  • Transportを使った効率的なprotocolを実装する
  • コールバックを用いたライブラリと async/await 構文を使ったコードの橋渡し

コルーチン

コルーチンはasync def 文で実装できる。

async/await構文で宣言し、asyncioを使ったアプリケーションを書くのに推奨される方法。

実行や一時停止ができる処理とも言える。

“hello”を出力し、そこから1秒待って”world”を出力するコード

import asyncio

async def main():
    print('hello')
    await asyncio.sleep(1)
    print('world')

asyncio.run(main())
$ python async-1.py 

Hello
World!

 1秒待機した後”hello”と出力し、更に2秒待機してから”world”と出力するコード

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    print(f"started at {time.strftime('%X')}")

    await say_after(1, 'hello')
    await say_after(2, 'world')

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())
$ python async-2.py 

started at 15:33:24
hello
world
finished at 15:33:27

1つ目のsay_helloの完了を待って、2つ目のsay_helloを実行。計3秒かかりました。

タスク

タスクは、イベントループのコルーチンを実行し、実行結果などを管理するのに使われる。

イベントループとは、タスクをスケジュールし、1つのタスクのみを実行する。

2つのコルーチンを並行して走らせるコード

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main3():
    task1 = asyncio.create_task(
        say_after(1, 'hello'))

    task2 = asyncio.create_task(
        say_after(2, 'world'))

    print(f"started at {time.strftime('%X')}")

    # Wait until both tasks are completed (should take
    # around 2 seconds.)
    await task1
    await task2

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main3())
$ python async-3.py

started at 15:46:18
hello
world
finished at 15:46:20

同時に2つのsay_helloが実行されたので、計2秒に短縮された!

マルチエージェントの実装イメージが湧いてきたよ

asyncio.TaskGroupを使って、2つのコルーチンを並行して走らせるコード

Python-3.11で追加されたTaskGroupを使って、先程のコードを書くことができる。

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main4():
    async with asyncio.TaskGroup() as tg:
        task1 = tg.create_task(
            say_after(1, 'hello'))

        task2 = tg.create_task(
            say_after(2, 'world'))

        print(f"started at {time.strftime('%X')}")

    # The await is implicit when the context manager exits.

    print(f"finished at {time.strftime('%X')}")


asyncio.run(main4())
$ python async-4.py

started at 15:59:51
hello
world
finished at 15:59:53

結果は先程と同じで計2秒。

まとめ

asyncioライブラリを用いたasync/await、さらにコルーチンとタスクを用いて実際にコードを動かしてみました。

「なぜマルチエージェントのでasync/awaitが使われるのか?」

例えば監督者(オーケストレータ)のエージェントが複数のAIエージェントを並列に起動し、最後にそれぞれの実行結果をまとめる。

いわゆる非同期処理のためということがよくわかりました。

目次