【第8回】AI記事作成をイベントキュー型マルチエージェントへ発展させる|Dispatcherで処理フローを制御する

スポンサーリンク
この記事は約52分で読めます。

第8回では、第7回で追加した event_log.json によるイベント記録を発展させ、Event QueueDispatcherHandler を導入します。

これにより、main.py がすべての処理を直接制御する構成から、発生したイベントをキューに積み、Dispatcherが eventstatus を見て次の処理を判断する構成へ変更します。

ただし、第8回ではまだ asyncio や複数Workerは使わず、同期処理でイベントキューを順番に処理する「疑似非同期」の構成として実装します。第9回では、この構成を asyncio.Queue に発展させ、本格的な非同期イベント駆動型へ進める予定です。

第7回AI記事作成から何が変わるのか

第7回AI記事作成では、ローカルAIを使ったマルチエージェント記事作成システムに、event_bus.py(発生イベントを記録) と event_types.py(イベント名一覧) を追加しました。

これにより、Planner AI、Researcher AI、Writer AI、Reviewer AI、Validator の処理結果を、次のようなイベントとして記録できるようになりました。

process.started
plan.created
research.completed
draft.created
review.completed
validation.completed
article.approved
article.saved

そして、これらのイベントは event_log.json に保存されます。

ただし、第7回AI記事作成の時点では、まだ main.py が多くの処理判断を担当していました。

たとえば、Reviewer AIの判定が OK ならValidatorへ進み、REVISION_REQUIRED ならWriter AIへ戻す、という分岐は main.py 側に残っていました。

第8回AI記事作成では、この構成をさらに一歩進めます。

今回の目的は、main.py 中心の順番実行から、Event Queue と Dispatcher を使ったイベントキュー型マルチエージェント構成へ整理することです。

第8回AI記事作成の構成

第8回AI記事作成で目指す構成は、次の通りです。

main.py

process.started を発行

Event Queue に積む

Dispatcher がイベントを取り出す

event / status に応じて Handler を呼ぶ

Handler がAI処理や保存処理を実行

次のイベントを Event Queue に積む

つまり、main.py がすべての処理を直接呼び出すのではなく、イベントを起点に処理を進める形へ変更します。

第8回AI記事作成で追加する主な要素は以下です。

event_queue.py
runtime_state.py
dispatcher.py
handlers.py

それぞれの役割は次の通りです。

ファイル役割
event_queue.py発生したイベントを順番に保持する
runtime_state.pykeyword、plan、articleなどの実行状態を保持する
dispatcher.pyevent / status を見て次の処理を判断する
handlers.pyPlanner、Researcher、Writer、Reviewer、Validator、保存処理を実行する
main.py初期化とDispatcherループの起動に役割を絞る

第8回は「正式な非同期処理」ではない

ここで重要なのは、第8回ではまだ asyncio は使わないという点です。

第8回のEvent Queueは、次のような同期処理で動きます。

これは、イベントをキューに積んで順番に処理する構成です。

そのため、構造としてはイベント駆動型に近づいていますが、実行方式としてはまだ完全な非同期処理ではありません。

Event Queueが必要な理由

第7回AI記事作成の構成でも、イベントログは保存できました。

しかし、イベントログはあくまで「何が起きたかの記録」です。

一方、Event Queueは「次に何を処理するか」を管理します。

違いを整理すると、以下のようになります。

仕組み役割
EventBusイベントを記録する
event_log.json発生したイベントの履歴を保存する
EventQueue次に処理すべきイベントを順番に保持する
Dispatcherキューから取り出したイベントを見て処理を振り分ける

第8回では、EventBusとEventQueueを分けて考えます。

EventBus
→ イベント履歴を残す

EventQueue
→ 次に処理するイベントを保持する

この分離により、処理の流れがかなり見えやすくなります。

Dispatcherとは何か

Dispatcherは、イベント駆動型システムの「交通整理役」です。

たとえば、次のようなイベントが来たとします。

review.completed + status OK

この場合、Dispatcherは次の処理へ進めます。

Validatorを実行する

一方で、Reviewer AIが修正必要と判断した場合は、次のようになります。

review.completed + status REVISION_REQUIRED

この場合、Dispatcherは次のように判断します。

article.revision_required を記録
Writer AIへ戻す

つまりDispatcherは、イベントとステータスを見て、次に実行するHandlerを選びます。

event + status

Dispatcher

次のHandler

第8回AI記事作成では、この判断を main.py から dispatcher.py へ移動しました。

Handlerとは何か

Handlerは、実際の処理を実行する関数です。

Dispatcherは「何を実行するか」を判断しますが、AIやツールを実際に呼び出すのはHandlerです。

たとえば、以下のようなHandlerを用意します。

handle_planner()
handle_researcher()
handle_writer()
handle_reviewer()
handle_validator()
handle_save_article()
handle_run_summary()

それぞれの役割は次の通りです。

Handler実行内容
handle_planner()Planner AIで記事設計を作る
handle_researcher()検索クエリ作成、Web検索、調査メモ作成を行う
handle_writer()初稿または修正版の記事を作る
handle_reviewer()Reviewer AIで記事を確認する
handle_validator()Python側でHTML構造をチェックする
handle_save_article()最終記事を保存する
handle_run_summary()実行概要を保存する

このように、DispatcherとHandlerを分けることで、コードの役割が整理されます。

第8回AI記事作成の起動から完了までの流れ

第8回AI記事作成システムの構成図。Event Queueに積まれたイベントをDispatcherが判断し、各Handlerを通じてPlanner AI、Researcher AI、Writer AI、Reviewer AI、Validator、保存処理へ振り分ける流れを示している。

第8回AI記事作成の処理は、次のように進みます。

python main.py

記事キーワードを入力

RuntimeState / EventBus / EventQueue / Dispatcher を初期化

process.started を発行

EventQueue に process.started を追加

Dispatcher が process.started を処理

Planner AI が記事設計を作成

plan.created を発行

Researcher AI が検索・調査メモ作成

research.completed を発行

Writer AI が初稿作成

draft.created を発行

Reviewer AI がレビュー

review.completed を発行

Validator がHTMLチェック

article.approved

final_article.html を保存

article.saved

run_summary.txt を保存

process.completed

順調に進んだ場合、イベントログは次のようになります。

process.started
plan.created
research.query_created
web_search.completed
web_search.completed
web_search.completed
web_search_results.saved
research.completed
draft.created
review.completed
validation.completed
article.approved
article.saved
process.completed

このように、処理の流れがイベント名として残るため、どこで何が起きたかをあとから追いやすくなります。

修正ループもイベントで制御する

第8回で重要なのは、修正ループもイベントで制御する点です。

Reviewer AIが修正必要と判断した場合、次の流れになります。

review.completed + status REVISION_REQUIRED

article.revision_required

writer.revision_requested

draft.revised

review.completed

また、Reviewer AIの判定がOKでも、Python側のValidatorでHTML形式の問題が見つかる場合があります。

その場合は、次の流れになります。

validation.completed + status FAILED

validation.failed

writer.revision_requested

draft.revised

review.completed

つまり、第8回では修正ループが2種類あります。

Reviewer AI起点の修正ループ
Validator起点の修正ループ

Reviewer AIは記事の内容や構成を見ます。
ValidatorはHTML形式やMarkdown混入、styleタグ、scriptタグなどを確認します。

この2つを分けることで、記事品質と出力形式の両方をチェックできます。

イベントの流れを図で表すと以下の様になります。

main.py

├─ process.started を発行

EventQueue


Dispatcher

├─ process.started → handle_planner()
├─ plan.created → handle_researcher()
├─ research.completed → handle_writer()
├─ draft.created → handle_reviewer()
├─ review.completed + OK → handle_validator()
├─ review.completed + REVISION_REQUIRED → handle_writer()
├─ validation.completed + OK → article.approved
├─ validation.completed + FAILED → handle_writer()
└─ article.approved → handle_save_article()

第8回AI記事作成で追加・変更となるファイル

第8回AI記事作成では、以下のファイルが追加・変更となります。

追加:
・event_queue.py
・runtime_state.py
・dispatcher.py
・handlers.py

変更:
・event_types.py
・main.py

基本的にそのまま:
・event_bus.py
・agents/planner.py
・agents/researcher.py
・agents/writer.py
・agents/reviewer.py
・validators.py
・review_parser.py
・mcp_client.py
・mcp_server.py
・web_search_tool.py

第8回のファイル構成は下記の通りとなります。

変更:event_types.py

追加:event_queue.py

追加:handlers.py

追加:dispatcher.py

追加: runtime_state.py

変更:main.py

main.py で変わる点

第7回までの main.py は、次の処理判断をほぼすべて持っていました。

Plannerを実行する
Researcherを実行する
Writerを実行する
Reviewer結果を見る
OKならValidatorへ進む
修正必要ならWriterへ戻す
保存する

第8回では、この判断を Dispatcher に移します。

main.py

最初のイベント process.started を発行

EventQueue に積む

Dispatcher が event / status を見て処理を振り分ける

つまり main.py は、処理本体ではなく起動役に近づきます。

第8回AI記事作成の実行結果

実際に以下のキーワードで実行しました。

2026年時点の最新AIモデル

実行中、1回目のReviewer AIでは判定JSONが見つからず、UNKNOWN になりました。

そのため、Dispatcherは安全側に判断し、Writer AIへ修正を依頼しました。

その後、2回目のレビューでは REVISION_REQUIRED が返り、さらに修正が行われました。

3回目のレビューでは、次のようなJSONが返りました。

{
"status": "OK",
"summary": "構成、論理性、網羅性、読みやすさのすべてが高レベルで保たれており、プロフェッショナルな記事として即座に公開可能です。",
"issues": [
"最後のCTA要素がメインコンテンツのタグ構造の外側に独立している点。構造的な連続性を保つため、HTMLの囲みタグでラップするか、メインコンテンツの最後尾に統合すると、より完成度が高まります。"
],
"next_action": "SAVE"
}

その後、Python側HTMLチェックもOKとなり、最終記事が保存されました。

Reviewer AI JSON判定 + Python側HTMLチェック の判定:OK

[8] 最終HTMLを保存中...

完了しました。
保存先: output/20260520_034447_2026年時点の最新AIモデル/final_article.html
保存状態:Reviewer AI のJSON判定とPython側HTMLチェックのOK後に保存しました。
Reviewer最終JSON判定:OK
イベントログ: output/20260520_034447_2026年時点の最新AIモデル/event_log.json

この結果から、Dispatcherによる分岐処理が機能していることを確認できます。

ターミナル出力

(UTF-8)

(SHIFT-JIS)

出力記事

(UTF-8)

(SHIFT-JIS)

event_log.json

(UTF-8)

(SHIFT-JIS)

第8回AI記事作成で保存されるファイル

実行後、output/日時_キーワード/ 配下に以下のファイルが保存されます。

plan.txt
research_query.txt
web_search_results.json
research_note.txt
draft_1.html
review_1.txt
review_result_1.json
draft_2.html
review_2.txt
review_result_2.json
draft_3.html
review_3.txt
review_result_3.json
validation_3.txt
final_article.html
run_summary.txt
event_log.json

特に重要なのは、次の3つです。

ファイル確認内容
event_log.jsonイベントが期待通りに流れたか
review_result_*.jsonReviewer AIのJSON判定が取得できたか
final_article.html最終記事が保存されたか

event_log.json を見ることで、処理がどの順番で進んだか、どこで修正ループに入ったかを確認できます。

第9回AI記事作成へ向けて

第8回では、Event Queueを導入しましたが、処理はまだ同期的に進みます。

つまり、1つのイベントを取り出し、処理が終わったら次のイベントへ進む形です。

第9回AI記事作成では、この構成をさらに発展させ以下のような要素を追加する予定です。

asyncio.Queue
非同期Dispatcher
Worker
リトライ制御
タイムアウト制御
失敗イベントの再投入

第8回AI記事作成で作った EventQueueDispatcherHandler の考え方は、そのまま第9回の非同期化につながります。

第8回AI記事作成は、本格的な非同期イベント駆動型へ進むための重要な土台といえます。

まとめ:main.py中心からDispatcher中心へ

第8回では、AI記事作成システムをイベントキュー型マルチエージェントへ発展させました。

これまでの構成では、main.py が処理の中心でした。

main.py がPlannerを呼ぶ
main.py がResearcherを呼ぶ
main.py がWriterを呼ぶ
main.py がReviewer結果を判定する
main.py が保存する

第8回では、これを次の形へ変更しました。

main.py は最初のイベントを発行する
EventQueue がイベントを保持する
Dispatcher がイベントを見て処理を判断する
Handler が実際の処理を実行する

この変更により、AIエージェントごとの役割が整理され、修正ループやエラー処理もイベントとして扱いやすくなりました。

第8回AI記事作成は、まだ完全な非同期処理ではありません。

しかし、イベント駆動型マルチエージェントの考え方を実装として理解するには、非常に重要なステップです。

次回は、この構成を asyncio.Queue とWorkerへ発展させ、本格的な非同期イベント駆動型へ進めます。

予定しているテーマは次の通りです。

【第9回】AI記事作成を非同期イベント駆動型へ発展させる
|asyncio.QueueとWorkerでマルチエージェントを並行制御する