見出し画像

「考えるエージェント」を連鎖的に組み上げる――o1 proと考案した思考システムについて

はじめに

最近、生成AIやLLM(大規模言語モデル)まわりで「思考する」仕組みをどう組み込むか、という話題が増えています。

テキスト生成エンジンに何かを聞いて応えてもらうだけではなく、複数のエージェント(小さな機能を持つAIモジュール)を組み合わせ、それぞれがフィードバックを交換しながら、より良い答えを探索する――そんなシステムが次のステップとして注目されているように感じます。

この記事では、私がo1 proとともに考えた、エージェント同士が連鎖的に思考を紡ぐシステムの試案について共有してみます。

なお、今回お見せするのは、コンセプトレベルの実験的なアーキテクチャです。

そのため、まだ粗い部分も多々あり、試行錯誤の過程自体が「考えること」の面白さを伝える材料になればと思っています。


「考える」とは何か?

人間が頭の中でやっている作業は、実は複雑なプロセスの集合体です。

問題を分解したり、論理的な筋道を立てたり、突拍子もないアイデアをひねり出したり、そしてそれらを何度も見直し、手直ししながら、最終的にひとつの回答にまとめ上げる。

そのプロセスをコンピュータ的な観点でモデル化しようとすると、「分解」「論理的検討」「創造的検討」「統合」「判定」「改善フィードバック」といったステップが浮かび上がります。

今回作った仕組みは、「入力タスク」を一旦細かな「サブタスク」に分解し、各サブタスクに対して論理的なエージェントと創造的なエージェントが並行して考える。

そのうえで「統合・判定エージェント」が成果物を吟味し、必要なら「フィードバックエージェント」が改善提案をする。

これを繰り返すことで、段階的に答えの質を高め、最終的な成果を導き出すことを目指しました。

Mermaidによるワークフロー可視化

当初、このエージェント群をどのように接続するか、手探り状態でした。そこでMermaid記法(Markdown中でフローチャートを描ける記法)を使って、エージェント同士の関係を図示しました。

結果的に、下記のような構造をつくりあげます(以下は改善後の一例です)。

flowchart TD

    Start[入力タスク] --> TaskDecomposer[タスク分解エージェント]
    TaskDecomposer -->|サブタスクリスト| SubtaskLoop["サブタスクリストの繰り返し処理"]
    SubtaskLoop --> FinalIntegration[最終統合]
    FinalIntegration --> Result[最終結果]

    subgraph SubtaskUnit["サブタスクユニット (抽象化)"]
        ST_Input[サブタスク入力] -->|並列実行| LogicAgent[論理的解決エージェント]
        ST_Input -->|並列実行| CreativeAgent[創造的解決エージェント]

        LogicAgent --> SynthesisAgent[統合・判定エージェント]
        CreativeAgent --> SynthesisAgent

        SynthesisAgent -->|不足| FeedbackAgent[フィードバックエージェント]
        FeedbackAgent -->|改善提案| LogicAgent
        FeedbackAgent -->|改善提案| CreativeAgent

        SynthesisAgent -->|合格| ST_Output[サブタスク成果物]
        SynthesisAgent -->|改善上限超過→失敗| Fallback[フォールバック経路]

        FeedbackAgent -->|改善失敗 or 上限| Fallback
    end

    subgraph SubtaskLoop
        direction TB
        STList[サブタスクのリスト]
        STList -->|for each ST| SubtaskUnit
        SubtaskUnit -->|次のサブタスクへ| SubtaskUnit
        SubtaskUnit -->|最後のサブタスク処理後| Done[完了]
    end

    Done --> FinalIntegration

これを視覚化すると、このようになります。

mermaid.liveで視覚化したもの。

この図を見ていただくと、ひとつのサブタスクに対して、論理的・創造的なアプローチが並行実行され、その結果を統合して評価。

もし不十分ならフィードバックを取り入れて再トライ。

この小さなループを必要な回数繰り返し、全てのサブタスクが終わったら最終統合へ――という全体像が俯瞰できます。

フィードバックループが生み出す「進化」

一度で完璧な答えが出せない場合、どのようにして精度を上げていくか?
ここで活躍するのが「フィードバックエージェント」です。

統合・判定エージェントが「まだ足りない」と判断したら、改善のヒントを出す。論理的エージェントや創造的エージェントはそのヒントを受け取り、出力を改良する。

このフィードバックループは、まるで人間が「うーん、もう少し具体例が欲しいかも」などと頭の中で自問自答しているかのような動きを疑似的に再現しようとしています。

ただし、改善が堂々巡りになることもあるでしょう。

そのため「改善上限」を設けたり、最終的にフォールバック経路(諦めてエラーを返すなど)を用意したりしています。これも、人間が思考の行き詰まりで一旦保留したり、別のタスクに切り替えたりするプロセスに似ています。

Pythonでのテンプレート実装

理論を図で示すだけでなく、実際のコードテンプレートにも落とし込みました。

from typing import Any, Dict, List, Optional
import asyncio
import logging

logging.basicConfig(level=logging.INFO)

class BaseAgent:
    async def run(self, input_data: Any) -> Any:
        raise NotImplementedError

class LogicAgent(BaseAgent):
    async def run(self, input_data: Any) -> Dict:
        # 論理的な分析を行う処理
        return {"type": "logic_result", "content": "Some logical conclusion"}

class CreativeAgent(BaseAgent):
    async def run(self, input_data: Any) -> Dict:
        # 創造的なアイデア生成処理
        return {"type": "creative_result", "content": "Some creative idea"}

class SynthesisAgent(BaseAgent):
    def __init__(self, max_feedback_loops: int = 3):
        self.max_feedback_loops = max_feedback_loops
        self.feedback_count = 0

    async def run(self, logic_output: Dict, creative_output: Dict) -> Dict:
        # 両者を統合し、品質判定する
        # 簡易的には、ランダムまたは条件によって不十分判定する例
        # 本当は、より詳細な判定ロジックが必要
        if self.feedback_count < self.max_feedback_loops:
            # 擬似的に判断を行う。ここでは毎回50%で不十分としてみる
            from random import random
            if random() < 0.5:
                return {"status": "insufficient", "message": "Needs improvement"}
            else:
                return {"status": "ok", "result": "Synthesis complete"}
        else:
            return {"status": "fail", "message": "Feedback loop max exceeded"}

class FeedbackAgent(BaseAgent):
    async def run(self, synthesis_feedback: Dict) -> Dict:
        # 不十分な点に対する改善策提案
        return {"improvement": "Try a different approach or add more detail"}

class SubtaskUnit:
    def __init__(self, max_feedback_loops: int = 3):
        self.logic_agent = LogicAgent()
        self.creative_agent = CreativeAgent()
        self.synthesis_agent = SynthesisAgent(max_feedback_loops=max_feedback_loops)
        self.feedback_agent = FeedbackAgent()
        self.max_feedback_loops = max_feedback_loops

    async def run_subtask(self, input_data: Any) -> Dict:
        # 並列実行でロジックとクリエイティブを同時実行
        logic_task = asyncio.create_task(self.logic_agent.run(input_data))
        creative_task = asyncio.create_task(self.creative_agent.run(input_data))
        logic_result, creative_result = await asyncio.gather(logic_task, creative_task)

        feedback_count = 0

        while True:
            synthesis_result = await self.synthesis_agent.run(logic_result, creative_result)

            if synthesis_result["status"] == "ok":
                # 成功時
                return {"subtask_status": "completed", "result": synthesis_result["result"]}

            elif synthesis_result["status"] == "insufficient":
                feedback_count += 1
                if feedback_count > self.max_feedback_loops:
                    # 改善上限超過
                    return {"subtask_status": "failed", "reason": "Feedback loop exceeded"}

                # フィードバックエージェントで改善案取得
                feedback_suggestions = await self.feedback_agent.run(synthesis_result)
                # 改善案をもとにロジック、クリエイティブ出力を更新(簡易例)
                logic_result["content"] += " + improved based on feedback"
                creative_result["content"] += " + improved idea"
                
            else:
                # failなどフォールバック処理
                return {"subtask_status": "failed", "reason": "Synthesis failed after max attempts"}

class FinalIntegrationAgent(BaseAgent):
    async def run(self, results: List[Dict]) -> Dict:
        # 複数サブタスクの結果を統合する処理
        combined = " | ".join(r.get("result", "N/A") for r in results if r["subtask_status"] == "completed")
        return {"final_result": combined}

async def main():
    # タスク分解 (ダミー)
    subtasks = ["subtask1_input", "subtask2_input", "subtask3_input"]

    # サブタスク群の実行
    subtask_unit = SubtaskUnit(max_feedback_loops=3)
    subtask_results = []
    for st_input in subtasks:
        result = await subtask_unit.run_subtask(st_input)
        if result["subtask_status"] != "completed":
            logging.error(f"Subtask failed: {result}")
            # ここでフォールバック処理が必要なら追加
            break
        subtask_results.append(result)

    # 全サブタスク結果を統合
    final_agent = FinalIntegrationAgent()
    final_output = await final_agent.run(subtask_results)
    print("Final Result:", final_output)

if __name__ == "__main__":
    asyncio.run(main())

ここで重要なのは、「汎用的なサブタスク処理ユニット」を用意し、サブタスクが増えても同じロジックで処理を拡張できることです。

また、論理的処理と創造的処理をasyncioを用いて並列実行したり、改善ループをwhileで回して統合・判定のフィードバックを受け取ったり、といった非同期・反復処理を行います。

このあたりのコードはあくまで雛形で、実際には潜在的なバグの修正や、各エージェント内の処理ロジック、ログの整理、エラー時の扱い、そしてRAGなどの実業務データへの対応といった追加実装が必要です。

それでも、このテンプレートは「考えるエージェント」を組み合わせる全体像を感じ取れる出発点になってくれると思います。

おわりに

「考えるエージェント」を連鎖的につなげ、o1 proという最新のモデルを用いて、試行錯誤を行ってみると、まるで思考の生態系がコード上に形成されていくかのような不思議な感覚がありました。

もちろん、まだまだ荒削りで、これをそのまま実用に活かせるわけではありません。

でも、こうした「思考の仕組み」を技術で再現していく過程は、人間がどのようにして知恵を絞っているのか、逆にそれを再発見する手がかりにもなるように感じます。

もし同じような興味をお持ちであれば、ぜひこのアイデアを参考に、自分なりの「考えるエージェント」を育ててみてください。

技術と思索が交差する場所には、まだまだ面白い未踏の領域が広がっています。

いいなと思ったら応援しよう!