# AIエージェント設計論: システム・アーキテクチャ

はじめに

こんにちは。スパイスコード代表の中河です。今日は弊社のAgent Platformのシステムアーキテクチャについて紹介したいと思います。

本記事では、実装の詳細には踏み込まず、プラットフォーム全体のアーキテクチャと、それを構成するミドルウェア群に焦点を当てて解説します。どのようなスタックを選定し、それらをどう組み合わせてAgent Platformを構築しているのかを共有することで、同様のシステムを検討されている方の参考になれば幸いです。


プラットフォーム全体像

Agent Platformのアーキテクチャを俯瞰すると、以下の層構造で構成されています。

graph TD
  subgraph Protocol["Protocol Layer"]
    direction LR
    A2A["A2A (Agent-to-Agent)"] ~~~ MCP_P["MCP"] ~~~ REST["REST API"]
  end
  subgraph Agent["Agent Layer"]
    direction LR
    Agents["Supervisor / Researcher / KnowledgeManager / Designer / ..."]
    LG["LangGraph (状態機械/DAG)"]
  end
  subgraph Kernel["Kernel Layer"]
    direction LR
    MR["Model Routing"] ~~~ Mem["Memory"] ~~~ Met["Metrics (Langfuse)"] ~~~ Run["Runtime (Sandbox)"]
  end
  subgraph Persistent["Persistent Layer"]
    direction LR
    RDB ~~~ GraphDB["Graph DB"] ~~~ S3 ~~~ Kinesis
  end
  subgraph Infra["Infrastructure"]
    direction LR
    EKS["EKS (Kubernetes)"] ~~~ Bedrock["AWS Bedrock"]
  end
  Protocol --> Agent --> Kernel --> Persistent --> Infra

各層の役割は以下の通りです。

責務 主要ミドルウェア
Protocol 外部との通信インターフェース A2A SDK, MCP SDK
Agent ドメイン固有のエージェント群 LangGraph, LangChain
Kernel エージェント共通基盤 Langfuse, DSPy, LangChain
Persistent 状態の永続化 RDB, Graph DB, S3
Infrastructure 実行環境 Kubernetes, AWS Bedrock, Docker

エージェントオーケストレーション — LangGraph

選定理由

エージェントの実行フローを制御するオーケストレーターとして LangGraph を採用しています。LangGraphは有向グラフとして実行フローを定義でき、以下の点が我々の要件に合致しました。

  • 状態機械としてのエージェント: 各エージェントは有向グラフとして定義され、メッセージの入出力、ツール呼び出し、条件分岐を宣言的に記述できる
  • チェックポイントによる状態永続化: 会話の途中状態をRDBに保存し、非同期タスクの再開やロングランニングな処理に対応
  • ストリーミング対応: Server-Sent Events (SSE) 経由でリアルタイムにクライアントへ応答を返却

フラクタルアーキテクチャ

本プラットフォームは フラクタルアーキテクチャ を採用しています。エージェントは他のエージェントをツールとして呼び出すことができ、自己相似的な階層構造を形成します。

graph TD
  S["Supervisor Agent"]
  S --> R["Researcher Agent"]
  S --> D["Designer Agent"]
  S --> K["Knowledge Manager Agent"]
  R --> WS["Web Search Tool"]
  R --> KR["Knowledge Retrieval Tool"]
  R --> BA["Browser Agent (子エージェント)"]
  D --> AC["Automation Compiler Tool"]
  D --> CS["Code Sandbox Tool"]
  K --> SE["Semantic Extraction Tool"]
  K --> MM["Memory MCP Tools"]

エージェントの登録はレジストリパターンで管理されており、登録された任意のエージェントを動的に起動できます。これにより、エージェントの追加・削除がシステム全体に影響を与えず、疎結合な拡張が可能です。


LLMアクセス層 — マルチプロバイダ戦略

LLMへのアクセスは、抽象化されたモデルローダーを通じて行われます。モデルの選択は Provider × Class × Region の3軸で定義され、エージェントごとに必要に応じて最適なモデルを選択できます。

graph TD
  App["Application Context"] --> Router["Model Router<br/>Provider × Class × Region"]
  Router --> Bedrock["Bedrock"]
  Router --> OpenAI["OpenAI"]
  Router --> Anthropic["Anthropic"]
  Router --> VertexAI["VertexAI"]

複数のLLMプロバイダ (AWS Bedrock, OpenAI, Anthropic, GCP Vertex AI, ローカルDockerランナー, OpenAI互換カスタムエンドポイント) に対応しており、タスクの特性やコスト・レイテンシの要件に応じて、エージェント単位で最適なプロバイダとモデルサイズを切り替えられる設計です。プロバイダの差異はアプリケーション層から隠蔽されます。


通信プロトコル — A2A / MCP

Agent Platformの外部インターフェースとして、Googleが提唱する A2A (Agent-to-Agent) プロトコルと、Anthropicが提唱する MCP (Model Context Protocol) の2つのオープン標準を採用しています。

A2A — エージェントの外部通信プロトコル

Agent Platformでは、Agentの外部とのすべてのやり取りにA2Aプロトコルを使用しています。サーバー側としてエージェントの機能を公開するだけでなく、クライアント側として他のサービスやエージェントへリクエストを送信する際にもA2Aを統一的に採用しています。これにより、言語やフレームワークに依存しない標準化されたエージェント間通信が実現されています。

MCP — ツール提供プロトコル

MCPは、エージェントに対して「ツール」として外部機能を提供するためのプロトコルです。トランスポートには Streamable HTTP を採用しています。本プラットフォームでは2つの側面でMCPを活用しています。

MCPサーバーとして (ツール提供側): - Memory MCP Server: セマンティックメモリへの検索・追加・グラフ探索機能を公開

MCPクライアントとして (ツール消費側): - 複数のMCPサーバーに同時接続し、エージェントのツールとして利用

MCPの採用により、メモリ機能は独立したMCPサーバーとして切り出されており、Claude DesktopやClaude Codeなどの外部MCPクライアントからも同じインターフェースでアクセス可能です。

Desktop Session — 動的MCPセッション

エージェントがブラウザ操作を行う際は、Kubernetes上に DesktopSession CRD (Custom Resource Definition) を動的に生成し、分離されたデスクトップ環境のMCPサーバーへ接続します。

graph LR
  A["Agent"] --> B["DesktopSession CRD 作成"] --> C["K8s Pod 起動"] --> D["MCP接続"] --> E["ブラウザ操作"]

これにより、各エージェントセッションが独立したデスクトップ環境を持ち、並列実行時の干渉を防いでいます。


記憶システム — 三層記憶アーキテクチャ

認知科学の記憶モデルに着想を得た三層構造の記憶システムを実装しています。

graph TD
  subgraph WM["Working Memory"]
    WM1["Context Window Manager<br/>LangGraphの状態 + メッセージ要約<br/>ストレージ: RDB (langgraph-checkpoint)"]
  end
  subgraph SM["Short-term Memory"]
    SM1["会話要約 / エピソード<br/>Context Window Managerが自動要約<br/>ストレージ: RDB (checkpoint内)"]
  end
  subgraph LM["Long-term Memory"]
    direction TB
    subgraph LM_Types[" "]
      direction LR
      EP["Episodic<br/>(エピソード記憶)"] ~~~ PR["Procedural<br/>(手続き記憶)"] ~~~ SE["Semantic<br/>(意味記憶)"]
    end
    LMS["ストレージ: RDB + Graph DB + Vector Store"]
    LM_Types --> LMS
  end
  WM --> SM --> LM

Working Memory — コンテキストウィンドウ管理

Context Window Managerが動作し、LLMに渡すメッセージ列をリアルタイムに管理します。

  • トークン数の近似カウント (日本語向けに文字あたりのトークン比率を調整)
  • 上限超過時のメッセージ刈り込み
  • ツールメッセージの保持件数制御

Long-term Memory — 意味記憶 (Semantic Category)

長期記憶の中核をなすのが 圏論 (Category Theory) に基づくセマンティックメモリです。設計の詳細は前回の記事「AIエージェント設計論: 意味記憶と知識表現のアーキテクチャ」で解説していますが、ここでは単純化しプラットフォームにおける位置づけを概観します。

graph BT
  Triple["TripleCategory<br/>(トリプル層: Object + Morphism)"] -->|Functor| Chunk["ChunkCategory<br/>(チャンク層)"]
  Chunk -->|Functor| Resource["ResourceCategory<br/>(リソース層)"]
概念 説明
Category 知識の分類単位
Object 概念・エンティティ
Morphism Object間の関係
Functor Category間の構造保存写像

知識の取り込みは以下のパイプラインで処理されます。

graph TD
  Input["入力テキスト/URL"]
  RC["ResourceCategory作成<br/>(1 Object = 1リソース)"]
  Chunk["チャンキング → ChunkCategory作成 (N Objects)"]
  Triple["Triple抽出 (並列) → TripleCategory作成<br/>Phase 1: チャンク内 Object + Morphism 抽出<br/>Phase 2: チャンク間 Cross-chunk Morphism 抽出"]
  Emb["Embedding生成"]
  Store["RDB永続化 + ベクトルインデックス"]
  Input --> RC --> Chunk -->|"Functor (Chunk → Resource)"| Triple -->|"Functor (Triple → Chunk)"| Emb --> Store

抽出は並列度を制御しながら並列実行され、大量チャンクの処理を効率化しています。

Long-term Memory — 手続き記憶 (Procedural)

エージェントのツール使用パターンを記録・学習する仕組みです。

  • ツール呼び出しのInput/Outputを構造化して保存
  • 類似タスクでの過去の成功パターンをベクトル検索で取得
  • Re-rankerによる関連度の再評価

Long-term Memory — エピソード記憶 (Episode)

タスク単位の会話履歴を構造化して保存します。

  • 過去の類似タスクの検索と参照
  • Chain of Responsibility パターンによるパイプライン型の知識ロード

可観測性 — Langfuse

エージェントの実行フローの可視化・分析には Langfuse を採用しています。LangGraphの実行設定にLangfuseコールバックを注入することで、LLM呼び出し・ツール実行・チェーン実行が自動的にトレースされ、エージェント全体のワークフローを一貫して追跡できます。

また、LangfuseのDataset機能を活用し、Knowledge Manager Agentの知識抽出品質に対する実験を回せる仕組みを構築しています。評価データセットを用意し、Correctness(正確性)やHallucination(幻覚検出)といった指標でエージェントの出力品質を継続的に計測・改善しています。


評価 — DSPy

DSPy は、エージェントの出力品質を LLM as a Judge パターンで評価するために活用しています。Correctness(正確性)やHallucination(幻覚検出)といった評価指標をDSPyのモジュールとして定義し、エージェントが生成した知識や応答をLLMが自動評価します。

graph TD
  DS["Langfuse Dataset"] --> Eval["DSPy Evaluator<br/>(LLM as Judge)"]
  Eval --> Corr["Correctness"]
  Eval --> Hall["Hallucination"]
  Corr --> Score["評価スコア → Langfuse に記録"]
  Hall --> Score
  Score --> RL["Reinforcement Loop<br/>(評価性能の最適化)"]

Langfuseとの連携による評価最適化

なお、LangfuseにもLLM as a Judgeの機構は存在しますが、本プラットフォームではそれを使用していません。評価ロジック自体はDSPyで独自に実装し、Langfuseはあくまでデータセットの管理とスコアの記録基盤として活用しています。Langfuseに蓄積された評価データセットをDSPyが読み込み、LLM as a Judgeの評価を実行し、そのスコアを再びLangfuseに記録するという流れです。

さらに、Runner / Trainer / Environment の抽象で構成される強化学習ループにより、「推論 → 環境ステップ → 振り返り」のサイクルを回すことで、評価系統そのもののパフォーマンスを継続的に改善する仕組みを備えています。これにより、LLMによる自動評価の精度が向上し、エージェントの品質ゲートとしての信頼性が高まります。


まとめ

Agent Platformは、主に以下のOSSミドルウェアを組み合わせて構築されています。

ミドルウェア 役割
LangGraph エージェントオーケストレーション, 状態機械
LangChain LLM抽象化, ツール定義, Embedding
Langfuse 可観測性, トレーシング, 評価データセット
DSPy プロンプト最適化, 評価フレームワーク
A2A SDK Agent-to-Agent プロトコル
MCP SDK Model Context Protocol, ツール提供

設計指針は「標準仕様の採用」と「レイヤードアーキテクチャによる疎結合」です。A2AとMCPによる言語・フレームワーク非依存のエージェント間通信、LangGraphによる宣言的なワークフロー定義、Langfuseによる透明性の高い可観測性が、プロダクション運用の信頼性を担保しています。

AIエージェントの技術領域は急速に変化しています。各レイヤーを疎結合に保ち、ミドルウェアをいつでもより優れた選択肢に入れ替え可能にすることで、特定の技術への依存を最小限に抑え、変化に柔軟に対応できる設計としています。

LLMエージェントによるブラウザ自動化の Self-Healing 実験

スパイスコードの民谷です.

CTO櫻木の以前の検証記事では, LLM エージェントによるブラウザ操作自動化において, 操作ログから Playwright コードを生成して「チェーン」として機械的に再生する方式が効率的であることを示しました. チェーン方式は毎回UIを探索する方式に比べて 3.4 倍高速・費用が 1/5 と大きな効率差がありますが, 一方で, チェーンは Web サイトの DOM セレクタに依存しており, サイト更新でセレクタが変わるとチェーン全体が壊れるという課題があります.

本記事では, その解決策として, LLM エージェントによるチェーンの自動修復, すなわち Self-Healing の実現可能性を検証しました. ここでの Self-Healing とは, 実行失敗したチェーンのセレクタを LLM エージェントが事後的に修正・再登録するプロセスを指します.

検証は3段階で行い, 合計260回の実験を実施しました. 結論として, シンプルアプリでは99%の修復成功率を達成し, 本番の React アプリケーションでも条件次第で80〜100%の成功率を確認しています.

  • 実験1(200回): シンプルな検証用アプリで, 5種類のDOM変異 × 2モデル(Sonnet / Haiku)× 各20回
  • 実験2(20回): 本番の React 管理画面で, 4種類のDOM変異 × 各5回
  • 実験3(40回): プロンプト設計の改善で成功率が上がるかを検証する要因実験

本記事の Self-Healing は, LLM エージェントが環境変化に適応する「Self-Evolving Agents」[*1] の GUI ドメインにおける実践的な取り組みと考えています.

1. はじめに

1.1 手続き記憶としてのチェーンとその課題

graph TD
    LTM["長期記憶<br/>(Long-term Memory)"]
    DM["陳述記憶 / 宣言的記憶<br/>(Declarative Memory)"]
    NDM["非陳述記憶 / 非宣言的記憶<br/>(Non-declarative Memory)"]
    EM["エピソード記憶<br/>(Episodic Memory)<br/><i>個人的な体験の記憶</i>"]
    SM["意味記憶<br/>(Semantic Memory)<br/><i>一般的な知識・事実</i>"]
    PM["手続き記憶<br/>(Procedural Memory)<br/><i>スキル・手順の記憶</i>"]
    OTHER["プライミング, 条件づけ 等"]

    LTM --> DM
    LTM --> NDM
    DM --> EM
    DM --> SM
    NDM --> PM
    NDM --> OTHER

    style PM fill:#f3e5f5,stroke:#7b1fa2,stroke-width:3px

Chain機構と手続き記憶の記事で扱った手続き記憶は「無意識な手続き」に関する記憶であり, LLM の推論をほぼ介さずに高速・低コストで再実行できる知識です. チェーン(2.1節)はこの手続き記憶の一形態です.

通常時はチェーンが無意識的に再生されますが, Web サイトの DOM 構造が更新されてセレクタが変わると, 実行中に予期しないエラー(サプライズ)が発生します. 同記事では, このサプライズを検知した際に, 無意識的な手続き実行から意識的な推論(宣言的記憶)へフォールバックする二重過程の設計を示しました. 本記事では, この意識的フローの実体, すなわち Healer による壊れたチェーンの自動修復 — Self-Healing — の実現可能性を検証します.

1.2 検証ポイント

本記事で検証する問いは以下の3つです.

  1. シンプルアプリと本番Reactの両方で修復は成功するか? — 検証用の小さなアプリで得た結果は, 本番環境でも再現するのか
  2. モデル(Sonnet / Haiku)で実用的な差はあるか? — 低コストモデルと高性能モデルで成功率・費用にどの程度の差があるか
  3. プロンプト設計の改善で成功率はさらに上がるのか? — Healerの基本的な修復力はどの程度か. プロンプトを工夫すれば改善するのか

結論を先に述べると, シンプルアプリでは Sonnet が 99%の修復成功率 を達成し, 本番の React アプリでも変異の種類次第で 80〜100% の成功率を確認しました. モデル間では Sonnet 99% に対して Haiku 75% と明確な差があり, 実ページを確認する Sonnet のアプローチが優位でした. さらにプロンプトの構成要素を変えた要因実験では, 全4パターンが 90〜100% の成功率(各 n=10)を達成し, デバッグ手順や推論プロセスの追加は成功率を改善せず費用のみ最大+55%増加しました. 全実験を通じて修復の成否を最も強く分けたのは, エージェントが実ページの DOM 構造を確認するか否かでした.

2. システム概要

2.1 チェーンとは

本記事で扱う「チェーン」とは, ブラウザ操作ログから自動生成された Playwright コードの JSON 定義です. 各ステップにセレクタと操作内容が記録されており, エージェントを介さず機械的に再生できます. 詳細は以前の検証記事を参照してください.

2.2 アーキテクチャ

アーキテクチャ

壊れたチェーンを修復する専用エージェント BrowserChainHealerAgent(以下, Healer)を構築しました. Healer は LangChain の create_react_agent で構築した ReAct パターン(Thought → Action → Observation を繰り返す)のエージェントであり, ツールの呼び出し順序は LLM が自律的に決定します.

2.3 使用ツール一覧

Healer は以下のツールを組み合わせて修復を行います.

カスタムツール(Healer専用)

ツール 役割
load_browser_source_profile ブラウザプロファイル(Cookie, 認証状態等)の復元
get_chain_blueprint 壊れたチェーン定義(JSON)の取得
submit_fixed_chain 修復チェーンの保存・登録

Playwright MCP ツール(ブラウザ操作) — Playwright MCP を介することで, LLM エージェントがブラウザ操作をツールとして呼び出せます.

ツール 役割
browser_navigate 指定URLへの遷移
browser_snapshot ページのアクセシビリティスナップショットを取得
browser_run_code Playwrightコードの直接実行(セレクタの個別検証に使用)

※ Playwright MCP では30種類以上のツールが利用可能ですが, 今回の修復タスクでは上記3つが主に使用されました.

2.4 想定する修復フロー

プロンプトでは以下のフローを想定して指示を設計しました.

ステップ 内容 使用ツール
1 ブラウザ状態の準備 load_browser_source_profile
2 壊れたチェーン定義を取得 get_chain_blueprint
3 実ページでDOM構造を確認し, セレクタを個別に検証 browser_navigate + browser_snapshot / browser_run_code
4 セレクタを修正 LLMが修正済みJSONを生成
5 修正チェーンを保存 submit_fixed_chain

2.5 プロンプト設計の概要

プロンプトの主な指示は以下の通りです.

  • 修復プロセス: プロファイル読み込み → チェーン取得 → ページ構造を確認 → セレクタ修正 → テスト → 提出
  • セレクタの優先順位: テキストマッチ → ID → data属性 → class
  • 効率性: 修正コードは1回で完成させ, browser_run_code を試行錯誤のために何度も呼び出さないこと(ただし, 実験3で追加する F2: デバッグ手順ではステップバイステップの検証を優先するため, この制約は緩和されます)
  • 提出: 修正が完了したら submit_fixed_chain で保存する

実験1・2では同一のプロンプト(上記の基本構成にセレクタ優先順位とデバッグ手順を含む)を使用しました. 実験3ではプロンプトの構成要素を要因として分解し, 各要素の効果を検証しています(詳細は5章で説明します).

3. 実験1: シンプルアプリでの基礎検証

まず, Self-Healing が原理的に機能するかを確認するため, シンプルな検証用アプリを対象に200回の実験を行いました.

3.1 対象アプリ

検証用に3ページ構成のシンプルなWebアプリケーションを用意しました.

  • ページ構成: login → search → detail
  • 操作ステップ数: 10ステップ
  • フォーム要素数: 5〜10

3.2 DOM変異パターン(5種類)

実際のWebサイト更新で起こりうる5種類のDOM変異パターンを用意しました.

Variant 変異内容
Variant 1: ID変更 #username#user-input
Variant 2: 要素階層移動 ラッパー <div> の追加
Variant 3: テキスト変更 「ログイン」→「サインイン」等
Variant 4: 属性変更 ID削除, data-testiddata-qa
Variant 5: 複合変異 ID/data属性すべて削除, テキスト・階層も変更

Before/After例(Variant 1: ID変更):

<!-- Before -->
<input type="text" id="username" placeholder="ユーザー名">
<button id="login-btn">ログイン</button>

<!-- After -->
<input type="text" id="user-input" placeholder="ユーザー名">
<button id="signin-button">ログイン</button>

各 Variant の DOM 変更が実際にチェーンを壊すことは, 変更前の正常なチェーン定義を各 Variant の DOM に対して直接実行し, セレクタが見つからず失敗することで事前に確認しています.

3.3 実験条件

  • 試行数: 5パターン × 2モデル × 各20回 = 合計200回
  • 実行環境: AWS Bedrock(ap-northeast-1)
  • トレース: 各試行を Langfuse でトレースし, トークン数・費用を記録
  • 成功判定: エージェントが提出した修復済みチェーンを新規ブラウザセッションで再実行し, 全ステップが正常に動作した場合を成功と判定

3.4 使用モデル

ブログ表記 モデルID 世代
Haiku claude-3-haiku-20240307 Claude 3(2024年3月)
Sonnet claude-sonnet-4-20250514 Claude 4(2025年5月)

なお, 両モデルは世代が異なるため(Claude 3 vs Claude 4, 約1年の差), 純粋なモデルサイズの比較ではなく, 現時点で利用可能な低コストモデルと高性能モデルの実用比較として位置づけています.

3.5 結果: 成功率

Model Variant 1 (ID変更) Variant 2 (階層移動) Variant 3 (テキスト) Variant 4 (属性) Variant 5 (複合) 全体
Haiku 90% 100% 100% 85% 0% 75%
Sonnet 100% 95% 100% 100% 100% 99%

Sonnet 99%(100回中99回), Haiku 75%(100回中75回)で, モデルによって大きな差が出ました. 特に Variant 5(複合変異)では Haiku が 20回中0回成功と完全に失敗しています.

Sonnet の唯一の失敗は Variant 2(階層移動)で発生しました. 他の19回の成功試行が browser_run_code 内に Playwright コードをまとめた2ステップのチェーンを生成したのに対し, この1回では Playwright MCP の高レベルツール(browser_type / browser_click)を個別に呼び出す12ステップのチェーンを生成していました. これらのツールは操作対象を ref(アクセシビリティスナップショットの動的ID)で指定しますが, エージェントはロケータ式を ref に記述しており, 実行時にエラーとなりました. セレクタの修正自体は正しかったものの, チェーンの出力形式を誤ったケースです.

※ 各条件は20回の試行であり, Variant単位の成功率は±10〜15ポイント程度の変動がありうる点にご留意ください.

3.6 ツール使用パターンの差

成功率の差は, 修復アプローチの違いから生じています.

指標 Haiku Sonnet
browser_run_code 使用回数 100試行中99試行で0回 平均7.6回
browser_navigate 使用回数 全試行で0回 全試行で1回
平均所要時間 ~39s ~91s
  • Sonnet: 「実ページを見て直す」アプローチ. 実際のページにブラウザで遷移し, browser_run_code でセレクタを個別に試して動作を検証(平均7.6回). 確認済みのセレクタで修正チェーンを組み立ててからテスト.
  • Haiku: 「チェーン定義だけで直す」アプローチ. 壊れたチェーン定義を読み, セレクタの修正案を一度に生成. 実際のページを開かずに, 修正済みチェーンをそのまま提出.

Sonnet は実ページを確認することで修復精度が高まっています. 一方, Haiku はプロンプトで指示したブラウザ確認ステップを省略し, チェーン定義の文字列情報のみから修正を試みる傾向がありました. Variant 5(複合変異)では ID・data属性・テキストがすべて変更されるため, 実ページを確認しない Haiku は有効なセレクタを特定できず全件が失敗しました.

所要時間の分布

モデル 平均 標準偏差 最小 最大 成功件数
Haiku 39.5s 3.6s 33.3s 48.7s 75/100
Sonnet 91.1s 5.3s 74.4s 108.0s 99/100

※ 所要時間は実行検証で成功した試行のみの統計値

3.7 費用比較

モデル 1回あたり費用 成功率 成功1回あたり費用 所要時間
Haiku $0.016 75% $0.022 39s
Sonnet $0.54 99% $0.55 91s

※「1回あたり費用」は全試行(成功・失敗含む)の平均値. 「成功1回あたり費用」は「1回あたり費用 ÷ 成功率」で算出

Haiku は費用面で約25倍安価ですが, 複合変異(Variant 5)では成功率0%であり, DOM変異の種類を事前に予測できない実運用では信頼性に欠けます. Sonnet は1回あたりの費用は高いものの, 99%の成功率で安定して修復できるため, 実運用では Sonnet が現実的な選択肢です.

3.8 実験1の結論

  • Sonnet は5種類のDOM変異パターンに対して 99%の修復成功率 を達成. Self-Healing は原理的に機能する
  • Haiku は75%にとどまり, 特に複合変異では全件失敗. 実ページを確認しないアプローチの限界
  • 以降の実験はすべて Sonnet で実施する

ただし, この実験はシンプルな3ページ・10ステップのアプリを対象としています. 本番の React アプリケーションでも同様に修復できるのかが次の問いです.

4. 実験2: 本番Reactアプリでの予備検証

実験1でSonnetによるSelf-Healingの基本的な有効性を確認しました. 次に, 本番に近いReactアプリケーションでも修復が機能するかを予備検証します.

4.1 対象アプリ

Next.js + Material-UI(MUI) + ReactFlow で構築された管理画面を対象にしました. 具体的には, オートメーション作成フォーム(条件分岐の設定, タグ・オペレーションの選択を含む複合的なUI操作)で, 約35行のPlaywrightコードで構成されるチェーンです.

実験1のシンプルアプリ(10ステップ, HTMLフォーム)と比較して, 以下の点で複雑です.

  • MUI の Autocomplete/Combobox コンポーネント(内部で多層のDOMを生成)
  • ReactFlow のノード操作(ドラッグ&ドロップ, エッジ接続)
  • Reactの仮想DOM再レンダリングによるDOM構造の動的変化

Next.js + Material-UI(MUI) + ReactFlowの管理画面

4.2 変異方式

実験1・2ともに, サーバー側でDOM構造を切り替える方式 を採用しています. 実験1ではPython(Jinja2テンプレート)による検証用Webアプリの設定切り替え, 実験2ではReactコンポーネントのpropsを設定値に応じて切り替える仕組みです. いずれも, variant番号を変更してアプリを再起動するだけでDOM変異を安定して再現できます.

4.3 DOM変異4種

Variant 変異内容
Variant A placeholder属性の削除(タグ選択 + オペレーション選択の2ヶ所)
Variant B ラベルテキストの変更(「条件で振り分け」→「条件分岐」)
Variant C placeholder削除 + 3つ目のcombobox追加 + テキスト変更(累積的な複合変異)
Variant D 遅延ローディング(タグ選択のAutocompleteが3秒間loading状態)

各 Variant は Healer の修復能力の異なる側面を検証するものです. Variant A の placeholder 削除は, getByPlaceholder が使えなくなった場合に LLM がどの代替セレクタを選択するかを試すケースです. Variant B のラベルテキスト変更はセレクタの値が変わるパターン, Variant C は複数の変更が重なった累積変異, Variant D はバックエンドの応答遅延をシミュレートしたタイミング依存の変異です.

4.4 実験条件

  • モデル: Sonnet のみ(実験1の結論に基づく)
  • プロンプト: 実験1と同一(セレクタ優先順位 + デバッグ手順を含む構成)
  • 試行数: 4パターン × 各5回 = 合計20回
  • 目的: 本番Reactアプリでの修復可能性を確認する予備検証. 実験1とは異なり1回あたり$2〜$4の費用がかかるため, まず各5回で方向性を把握し, 深掘りすべきvariantを実験3で重点的に検証する方針としました.

4.5 結果: Variant別成功率

Variant 変異内容 成功率
Variant A placeholder削除(2ヶ所) 2/5 (40%)
Variant B ラベルテキスト変更 5/5 (100%)
Variant C 複合変異 2/5 (40%)
Variant D 遅延ローディング 4/5 (80%)

Variant B(ラベルテキスト変更)は全5回成功しました. テキストが変わっても, Healer は実ページのDOM構造から正しい代替セレクタを特定できています.

なお, Variant A・C では placeholder 削除に対する代替セレクタの選択で失敗するケースが目立ちました. 後述する実験3では, この placeholder 削除のケースに絞り, プロンプトの構成を変えることで修復品質がどう変わるかを検証しています.

失敗が発生した3つのVariantについて, 個別の要因を分析します.

Variant D(80%): 1件の失敗は遅延ローディングに起因するタイミングの問題です. タグ選択のAutocompleteが3秒間loading状態にあり, オプションが表示される前に getByRole('option', {name: '沖縄'}) をクリックしようとしてタイムアウトしました. セレクタの修正自体は正しいものの, 待機処理が不十分でした. なお, この種の遅延ローディングはバックエンドのレスポンス遅延やAPIの応答時間増加など, 普段の開発でも頻繁に遭遇する変異です. 5回中4回で修復に成功しており, タイミング依存の問題にもHealerが対応できることは実用上の価値が高いと考えています.

Variant A(40%): placeholder属性が削除された2ヶ所について, Healerがどのような代替セレクタを選択したかによって成否が分かれました. 詳細は4.7節で分析します.

Variant C(40%): 複数の変異が同時に適用された結果, placeholder参照のタイムアウト, 新たに追加されたcomboboxによるstrict mode違反, テキスト変更の未対応が重なり失敗しました.

4.6 費用と時間

Variant 平均費用 合計費用 平均時間
Variant A $3.35 $16.73 6.0min
Variant B $3.94 $19.70 6.4min
Variant C $4.30 $21.50 7.2min
Variant D $2.84 $14.22 5.2min
合計 $3.61 $72.15 6.2min

実験1のシンプルアプリ(Sonnet: $0.54/回, 91秒)と比べて, 本番Reactアプリでは1回あたり$2.84〜$4.30, 所要時間5.2〜7.2分と大幅に増加しています. 主な要因は, 操作ステップ数の増加(10ステップ → 約35行のPlaywrightコード)と, MUI Autocomplete/Combobox等のコンポーネントが生成する多層DOM構造です. 特にMUIのComboboxは内部的に複数のARIAロールを持つため, Healerが正しいセレクタを特定するのにより多くのDOM確認(browser_snapshotbrowser_run_code)を必要とし, これが費用と時間の増加に直結しています.

4.7 Variant Aの詳細分析(実験3への橋渡し)

Variant A(40%)の5回の試行を1件ずつ並べて比較したところ, 成功には 2つの条件が同時に満たされる必要がある ことが見えてきました.

試行 オペレーションplaceholder除去 タグのセレクタ戦略 結果
1 残した ✗ getByRole('combobox') NG
2 除去 ✓ getByRole('combobox').all() OK
3 除去 ✓ locator('[role="combobox"]') OK
4 除去 ✓ getByRole('button', {name:'開く'}) NG
5 残した ✗ getByRole('button', {name:'開く'}) NG
  • オペレーション側: placeholder行を除去するか残すかの二値的な問題. 試行1, 5は「存在しないplaceholderを参照するセレクタ」を残したまま提出し, タイムアウトで失敗
  • タグ側: 代替セレクタの選択品質が成否を分ける. combobox ロールで要素を特定したセレクタは成功するが, ボタン名「開く」で要素を特定したセレクタは不適切で失敗

Variant Aの失敗は, (1) 壊れたセレクタをそのまま残す, (2) 不適切な代替セレクタを選択する, という2種類に分類できます. 特にタグ側の代替セレクタの選択品質は, プロンプトの指示内容(例えば, セレクタ候補を複数検討させる, ブラウザで事前検証させる等)で改善できる可能性があります.

4.8 実験2の結論

  • 本番Reactアプリでも Healer は修復チェーンを生成でき, Variant Bでは100%, Variant Dでは80%の成功率を達成
  • 失敗の要因はVariantごとに異なる: タイミングの問題(Variant D), 代替セレクタの選択品質(Variant A), 複合変異の対応困難さ(Variant C)
  • Variant Aの分析から, 代替セレクタの選択品質がプロンプト設計で改善できる可能性がある
  • 実験3では, プロンプトの構成要素を要因として分解し, 修復品質への寄与を検証する

5. 実験3: プロンプト設計によるHealer修復力の探索

実験2では, placeholder 削除を含む Variant A(40%)と Variant C(40%)で修復の失敗が目立ちました. いずれも失敗の多くは placeholder が削除されたセレクタの修復に起因しています. 実験3では, この placeholder 削除の修復パターンを分離し, プロンプトの構成要素を変えることで修復力が改善するかを検証します.

5.1 実験の動機

Variant A・C ではいずれも placeholder が削除されたセレクタの修復失敗が多く(4.7節), getByPlaceholder が使えなくなった場合の代替セレクタ選択が Healer にとって難しい課題であることがわかりました.

そこで, この placeholder 削除の修復パターンを分離し, プロンプトの構成要素を変えることで代替セレクタの選択品質が改善するかを検証することにしました(実験2では1回あたり$3〜$4の費用がかかり, 40回分となるとお財布にやさしくないという事情もあります). 具体的には, タグ選択の placeholder 削除のみ に絞った変異を新設し, プロンプトの構成要素を要因として分解しています. タグ側を選んだ理由は, 代替セレクタに複数の候補(combobox role, button name, locator 等)があり, プロンプトの指示がセレクタ選択品質にどう影響するかを観察しやすいためです.

5.2 プロンプトの要因分解

実験1・2で使用したプロンプト(2.5節)を分析すると, 主に3つの構成要素に分解できます.

要因 内容 OFF ON
F1: セレクタ戦略 セレクタの優先順位と snapshot 確認 指示なし テキスト→ID→data→class の優先順位 + ページの snapshot を確認
F2: デバッグ手順 ステップバイステップの実行と問題箇所の特定 指示なし 1ステップずつ実行して問題箇所を特定する
F3: 推論プロセス 修正前の構造化された思考 指示なし 壊れたセレクタを特定→原因を分析→代替候補を3つ挙げる→最適解を選択

実験1・2のプロンプトは F1(セレクタ戦略)と F2(デバッグ手順)が ON の構成でした. F1 は Self-Healing の基本であるため全パターンで ON に固定し, F2(行動: 実行して確認する)× F3(思考: 考えてから直す)の2×2で検証しました.

パターン F1: セレクタ戦略 F2: デバッグ手順 F3: 推論プロセス 説明
プロンプトA セレクタ戦略のみ(最小構成)
プロンプトB + デバッグ手順(実験1・2と同等の構成)
プロンプトC + 推論プロセス
プロンプトD 全部入り

5.3 実験条件

  • 対象変異: Variant A からタグ側の placeholder 削除のみを抽出(壊れるセレクタ1ヶ所)
  • モデル: Sonnet
  • 試行数: 4パターン × 各10回 = 合計40回
  • 成功判定: 実験1・2と同一(修復済みチェーンを新規ブラウザセッションで再実行し, 全ステップが正常動作すれば成功)

5.4 結果: 成功率

パターン F2: デバッグ F3: 推論 成功率
プロンプトA 10/10 (100%)
プロンプトB 9/10 (90%)
プロンプトC 9/10 (90%)
プロンプトD 9/10 (90%)
合計 37/40 (92.5%)

全パターンで90%以上の成功率を達成しました. placeholder 削除に対する代替セレクタの選択という課題に対して, Healer は高い修復力を示しています.

最小構成の プロンプトA(セレクタ戦略のみ)が10回中10回成功と最も安定しており, デバッグ手順(F2)や推論プロセス(F3)を追加しても成功率は改善しませんでした.

失敗した3件の内訳は以下の通りです.

パターン 試行 失敗したセレクタ 原因
プロンプトC run_01 getByPlaceholder('タグを選択').first() 壊れたセレクタをそのまま使用(修復が行われなかった)
プロンプトB run_03 getByRole('option', { name: '商品金額計' }) タグ選択の修復自体は成功したが, 後続ステップで偶発的にタイムアウト
プロンプトD run_01 getByPlaceholder('タグを選択').first() 壊れたセレクタをそのまま使用(修復が行われなかった)

3件中2件は placeholder 削除を認識できずセレクタが修復されなかったケースであり, 1件は修復対象外のステップでの偶発的な失敗でした.

5.5 費用と時間

パターン F2: デバッグ F3: 推論 平均費用 合計費用 平均時間
プロンプトA $1.00 $10.01 2.8min
プロンプトB $1.73 $17.34 3.6min
プロンプトC $0.98 $9.78 2.8min
プロンプトD $1.33 $13.25 3.1min
合計 $1.26 $50.38 3.1min

費用差の要因を探るため, ツールの使用回数を比較しました.

パターン F2: デバッグ F3: 推論 browser_run_code 平均回数 平均費用
プロンプトA 0.9回 $1.00
プロンプトB 6.0回 $1.73
プロンプトC 0.7回 $0.98
プロンプトD 3.3回 $1.33

F2(デバッグ手順)を ON にしたパターンは browser_run_code の使用回数が大幅に増加しています. 「1ステップずつ実行して問題箇所を特定する」指示に従い, Playwright コードを繰り返し実行してセレクタを検証するため, ツール呼び出し回数とトークン消費が増え, 費用+55%の直接的な原因となっています.

一方, F3(推論プロセス)は「考えてから直す」指示であるため, ツール呼び出し回数はほとんど変わらず, 費用への影響は限定的でした(プロンプトC: $0.98 vs プロンプトA: $1.00, プロンプトD: $1.33 vs プロンプトB: $1.73).

5.6 考察

修復アプローチの違い: ツール使用ログを分析すると, Healer の修復アプローチは大きく3つに分類できました.

修復アプローチ browser_run_code browser_snapshot / browser_navigate 結果
コード実行型: セレクタを個別にコードで検証 1回以上 あり 成功
snapshot型: DOM構造を見て推測で修正 0回 あり 成功
チェーン定義のみ: ページを見ずに修正 0回 なし 失敗

プロンプトA では10回中6回が snapshot 型(browser_run_code = 0回)で修復に成功しています. ページの DOM 構造を browser_snapshot で確認するだけで, Playwright コードを直接実行しなくても適切な代替セレクタを選択できていました.

一方, 失敗した3件のうち2件(プロンプトC run_01, プロンプトD run_01)は browser_navigate すら呼び出さず, チェーン定義の文字列情報だけから修正を試みていました. これは実験1で Haiku が取った「チェーン定義だけで直す」アプローチ(3.6節)と同じパターンであり, 壊れたセレクタ getByPlaceholder('タグを選択') がそのまま残って失敗しています. Sonnet でもまれにこのアプローチを取ることがあり, その場合は修復に失敗します.

プロンプト構成と成功率: 4パターンとも90〜100%の成功率であり, 今回の条件(1ヶ所の placeholder 削除)ではプロンプトの構成による明確な成功率の差は観察されませんでした. ただし各パターン n=10 のため, 90%と100%の差が有意かは判断できません.

プロンプト追加の効果: 今回の条件では, デバッグ手順(F2)と推論プロセス(F3)のいずれを追加しても, 成功率に明確な改善は確認できませんでした. 今回の修復対象は placeholder 削除による1ヶ所のセレクタ破損であり, 「問題箇所の特定」は不要で, 「どの代替セレクタを選ぶか」が成否を分ける課題です. F2 は browser_run_code の使用回数を大幅に増やしますが, snapshot 型のアプローチでも修復に成功しているこの課題では, 追加のコード実行が費用に見合う効果をもたらさなかった可能性があります.

費用の差: 成功率に明確な差がない一方で, F2 ON のパターンは費用が平均+55%高くなっています. 今回の条件では, デバッグ手順の追加は費用の増加に見合う成功率の改善をもたらしませんでした.

5.7 実験3の結論と限界

  • 1ヶ所の placeholder 削除に対して, 全4パターンが90〜100%の成功率を達成. プロンプトの構成による明確な成功率の差は確認できなかった(各 n=10)
  • F2(デバッグ手順)を追加したパターンは費用が平均+55%増加したが, 成功率の改善は確認できなかった
  • 修復の成否を分けたのはプロンプトの構成ではなく, エージェントが実ページを確認したか否かだった(失敗3件中2件がページ未確認型)

ただし, 以下の限界があります.

  • サンプル数: 各パターン n=10 であり, 90%と100%の差が統計的に有意かは判断できない
  • 破損パターンの限定: 今回は placeholder 削除のみを対象とした. 他の種類の破損パターン(DOM構造の大幅な変更, コンポーネントの置換等)やステップ数の多いチェーンに対しても同じ結果が得られるかは未検証
  • Variant A との対比: placeholder 削除パターンを分離して検証した結果であり, 実験2の Variant A とは修復対象のスコープが異なるため, 厳密な対照実験ではない

6. まとめと実務への示唆

6.1 3段階の検証結果

本記事では, 3段階・合計260回の実験を通じて, LLM エージェントによる Self-Healing の実現可能性を検証しました. 冒頭で掲げた3つの検証ポイントに対する回答を整理します.

検証ポイント1: シンプルアプリと本番Reactの両方で修復は成功するか?

成功します. シンプルアプリでは Sonnet が99%の修復成功率を達成し(実験1), 本番の React 管理画面でも Variant B(ラベルテキスト変更)で100%, Variant D(遅延ローディング)で80%の成功率を確認しました(実験2). MUI の Autocomplete/Combobox 等の多層 DOM 構造に対しても, Healer は実ページの DOM を確認して適切な代替セレクタを選択できています. ただし, placeholder 削除のように元のセレクタが根本的に使えなくなり, どの代替セレクタを選ぶべきかをエージェント自身が判断する必要があるケースでは, Variant A(40%)や Variant C(40%)のように成功率が低下しました.

検証ポイント2: モデル(Sonnet / Haiku)で実用的な差はあるか?

明確な差があります. Sonnet 99% に対して Haiku 75%(実験1). 差の主因は修復アプローチの違いです. Sonnet は実ページをブラウザで確認してセレクタを個別に検証する一方, Haiku はチェーン定義の文字列情報のみから修正を試みる傾向がありました. 複合変異(Variant 5)では Haiku が全20回失敗しており, DOM 変異の種類を事前に予測できない実運用では Sonnet が現実的な選択肢です.

検証ポイント3: プロンプト設計の改善で成功率はさらに上がるのか?

1ヶ所の破損に対しては, プロンプトの構成による明確な成功率の差は確認できませんでした. 全4パターンが90〜100%の成功率を達成し(実験3, 各 n=10), デバッグ手順や推論プロセスの追加は費用を最大+55%増加させた一方, 成功率の改善にはつながりませんでした. ただし, この結果は1ヶ所の placeholder 削除に限定した条件であり, より難度の高い修復タスクでは異なる結果になる可能性があります.

6.2 費用の全体像

実験 試行数 合計費用 1回あたり平均費用
実験1: シンプルアプリ(Sonnet) 100 $54.34 $0.54
実験1: シンプルアプリ(Haiku) 100 $1.64 $0.016
実験2: 本番React 20 $72.15 $3.61
実験3: プロンプト要因実験 40 $50.38 $1.26
合計 260 $178.51

実験2・3の新規実験費用は合計 $122.53 でした. 本番 React アプリ(実験2)の費用がシンプルアプリ(実験1)の約7倍に増加しているのは, 操作ステップ数の増加と MUI コンポーネントの多層 DOM に起因する browser_snapshot / browser_run_code の呼び出し増によるものです. 実験3では placeholder 削除の修復パターンに絞ったことで, 本番 React アプリでありながら平均 $1.26/回まで費用が抑えられています.

6.3 実務への示唆

今回の実験から得られた, Self-Healing を実運用に導入する際の示唆を3点挙げます.

1. 修復の難度は変異の種類によって大きく異なる

実験2では, ラベルテキスト変更(Variant B: 100%)や遅延ローディング(Variant D: 80%)は高い成功率でしたが, placeholder 削除(Variant A: 40%)では成功率が低下しました. テキストやタイミングの変異ではセレクタの修正方針が比較的明確ですが, placeholder 削除のようにセレクタ戦略自体の変更が求められるケースでは, LLM がどの代替セレクタを選ぶかの判断品質が成否を左右します. 修復対象の変異タイプに応じてプロンプトや検証戦略を調整することが重要です.

2. プロンプトの追加指示は費用対効果を見て判断する

今回の条件では, 「ステップバイステップで確認せよ」「候補を3つ挙げて最適解を選べ」といった追加指示は, ツール呼び出し回数を増やして費用を押し上げた一方, 成功率の改善は確認できませんでした. プロンプトへの指示追加にはツール呼び出し増加による費用増が伴うため, 修復タスクの難度に応じて費用対効果を検証しながら判断する必要があります.

3. 「ページを見る」ことが修復の前提条件

全3実験を通じて, 修復の成否を最も強く分けたのは「実ページの DOM 構造を確認するか否か」でした. 実験1では Haiku が実ページを見ずに全件失敗(Variant 5), 実験3でも Sonnet がまれにページ未確認で失敗するケースがありました. 逆に, browser_snapshot で DOM を確認しさえすれば, browser_run_code でコードを実行しなくても修復に成功しています(snapshot 型, 5.6節). プロンプトの設計で最も重視すべきは, エージェントが必ず実ページを確認するフローを組み込むことです.

6.4 今後の課題

以下の課題が残っています.

  • セレクタ戦略の変更を伴う修復: placeholder 削除のように元のセレクタ戦略が根本的に使えなくなるケースでは, 実験2で成功率40%(Variant A)と課題が残りました. 代替セレクタの選択品質を向上させるプロンプト設計や検証戦略のさらなる探索が必要です
  • 大規模なチェーン: 今回の対象は最大35行の Playwright コードでした. ステップ数が100を超えるような大規模チェーンでの修復性能は未検証です
  • サンプル数: 実験3は各パターン n=10 であり, 90%と100%の差の統計的有意性は判断できません. より大きなサンプルでの検証が求められます
  • 修復経験の蓄積: 現在の Healer は修復を独立に実行しており, 過去の修復パターンを学習・再利用する仕組みはありません. 修復経験の蓄積により, 類似パターンの修復精度と速度が向上する可能性があります

6.5 おわりに

本記事では, LLM エージェントによるブラウザ自動化チェーンの Self-Healing を, シンプルアプリから本番 React アプリまで段階的に検証しました. 260回の実験を通じて, Healer はシンプルアプリでは99%, 本番 React アプリでも条件次第で80〜100%の修復成功率を達成し, Self-Healing が実用可能な水準にあることを確認できました. 今後はセレクタ戦略の変更を伴う修復の品質向上や修復経験の蓄積など, 実運用に向けた課題に取り組んでいきます.

スパイスコードでは, このような AI を使ったチャレンジングな機能開発に取り組んでいます. LLM エージェントの設計・検証を一緒に推進してくれるエンジニアを募集中です. 興味を持った方は, ぜひカジュアルにお話ししましょう!

採用情報はこちら


*1: Gao et al., "A Survey of Self-Evolving Agents", TMLR 2026. エージェントが経験を蓄積し環境変化に適応するフレームワークを体系化した研究.

AIエージェント設計論: 意味記憶と知識表現のアーキテクチャ

こんにちは。スパイスコード代表の中河です。今日は前回の弊社 CTO 櫻木の記事の続きとして、弊社のエピソード・意味記憶に関する実装フレームワークを紹介したいと思います。

長くなってしまったので、ざっくりまとめ:

  • 知識の表現には圏論(Category Theory)を採用。Object(対象)と Morphism(関係)という統一モデルで、多くの知識抽出手法の出力を格納できます。Functor(関手)で異なる知識グラフを紐づけ、知識の出自追跡や横断的な検索を実現しています
  • トリプル抽出・命題分解といった抽出手法からGraphRAG的なもう少し包含的な手法まで Pluggable(差し替え可能)に運用できる。フレームワーク側は変えなくて OK
  • 実運用ではドメインに特化した Category を追加することで、特定タスクの精度を向上させています
  • 意味記憶の定着へはエピソード記憶(体験)→ 意味記憶(知識)への固定化と、外部データからの直接抽出、2つの入力経路があります

1. 導入 — 記憶の分類と意味記憶の位置づけ

前回の記事: AI エージェントの手続き記憶 — Chain 機構の設計

今回はその続編として、長期記憶のもう一つの柱である意味記憶(Semantic Memory)に焦点を当てます。

記憶の分類

まず、生物学的知能における記憶の全体像を改めて整理します。

graph TD
    LTM["長期記憶<br/>(Long-term Memory)"]
    DM["陳述記憶 / 宣言的記憶<br/>(Declarative Memory)"]
    NDM["非陳述記憶 / 非宣言的記憶<br/>(Non-declarative Memory)"]
    EM["エピソード記憶<br/>(Episodic Memory)<br/><i>個人的な体験の記憶</i>"]
    SM["意味記憶<br/>(Semantic Memory)<br/><i>一般的な知識・事実</i>"]
    PM["手続き記憶<br/>(Procedural Memory)<br/><i>スキル・手順の記憶</i>"]
    OTHER["プライミング, 条件づけ 等"]

    LTM --> DM
    LTM --> NDM
    DM --> EM
    DM --> SM
    NDM --> PM
    NDM --> OTHER

    style SM fill:#e8f4fd,stroke:#1976d2,stroke-width:3px
    style PM fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,stroke-dasharray:5 5

前回の記事で扱った手続き記憶は「どうやるか(How)」の知識です。具体的には、高階関数として構成された tool chain の組み合わせ、あるいはタスク実行のための Python コードとして永続化され、LLM の推論を介さずに高速・低コストで再実行できる形態をとります。これに対し、意味記憶は「何であるか(What)」の知識です。たとえば、食品業界における商品の規格情報、アレルゲンの分類体系、取引先間の関係性といった構造化された知識は、すべて意味記憶の領域に属します。

なぜ AI エージェントに意味記憶が必要か

LLM は pre-training によって膨大な世界知識を獲得していますが、特定のドメインにおける専門知識 — とりわけ運用の中で蓄積される業務固有の知識 — は事前学習だけではカバーできません。AI エージェントが長期的に価値を発揮するには、以下の能力が不可欠です。

  • 体験からの知識抽出: タスク実行の記録(エピソード記憶)から、再利用可能な構造化知識(意味記憶)へと変換する
  • 外部知識の取り込み: 商品規格書、業務マニュアル、取引先データなど、外部ドキュメントから知識を抽出・統合する
  • 知識の体系的な管理: 断片的な情報を Entity と Relation のネットワークとして組織化し、推論可能な形で保持する

これはまさに、生物学的脳における記憶の固定化(Memory Consolidation)— 海馬での一時的な記憶が大脳新皮質の長期記憶へと再編成されるプロセス — に対応する機構です。

この記事の概要

本記事では、以下の 4 つの観点から意味記憶のアーキテクチャを論じます。

  1. 記憶の固定化メカニズム — 生物学的知能における海馬-新皮質間の記憶転送と、AI エージェントにおける知識構造化パイプラインの対応関係
  2. 圏論を用いた知識表現 — Category Theory のフレームワークを応用し、ドメイン知識の Entity ・ Relation ・ Property を数学的に整理する手法
  3. Pluggable な知識抽出戦略 — トリプル抽出、命題分解、GraphRAG など、入力ソースや要件に応じて切り替え可能な抽出パイプラインの設計
  4. 意味記憶の形成パイプライン — エピソード記憶や外部データから意味記憶が形成される全体フローと、Knowledge Graph への永続化

2. 生物学的知能における記憶の固定化

AI エージェントの意味記憶アーキテクチャを設計する前に、そのインスピレーションの源である生物学的知能の記憶メカニズムを概観します。ここでは特に、記憶の固定化(Memory Consolidation) — 一時的な体験の記録が、構造化された長期知識へと変換されるプロセス — に焦点を当てます。

注意: 以下の記述は、脳の機能局在に関する知見を大幅に単純化しています。実際の脳はここで描くような単純な二分法では動作しておらず、海馬と新皮質は常に相互作用しながら記憶処理を行っています。ここでの目的は、AI システム設計に有用なメンタルモデルを構築することであり、神経科学の厳密な記述ではありません。

2.1 エピソード記憶と意味記憶の神経科学的基盤

エピソード記憶と意味記憶の区分は、Endel Tulving (1972) が Organization of Memory において提唱したものです。Tulving は意味記憶を「言語の使用に必要な記憶を提供する心的シソーラス」、エピソード記憶を「時間的に特定されたエピソードや出来事、およびそれらの間の時空間的関係の記憶」と定義しました。

この区分は、神経心理学的な症例研究によって支持されています (Greenberg & Verfaellie, 2010)。

  • 内側側頭葉(MTL)損傷患者(例: 患者 H.M.): エピソード記憶に重度の障害がみられるが、発症前に獲得された意味記憶は概ね保持されている。固定化された意味記憶が新皮質に存在することを示唆する所見である。
  • 意味性認知症患者: 意味記憶に広範かつ重度の障害がみられるが、エピソード記憶は比較的保たれている。前側頭葉の変性と関連する、相補的なパターンである。

この二重解離は、エピソード記憶と意味記憶が異なる神経基盤に依存していることを示唆しています。

海馬(Hippocampus) は、エピソード記憶の高速形成を担う構造と考えられています。進行中の体験の各要素を迅速に結びつけ(binding)、スパースな符号化とパターン分離により、異なる記憶痕跡間の重複を最小化するとされています。これにより、個別のエピソードを one-shot learning で高忠実度に保存できると考えられています。海馬の損傷は前向性健忘(新しいエピソード記憶の形成不能)と、時間的に傾斜した逆向性健忘(最近の記憶ほど失われやすい)を引き起こすことが知られており、これが記憶固定化の標準モデルの重要な根拠となりました (Squire & Alvarez, 1995)。

新皮質(Neocortex) は、意味記憶の長期保存を担うと考えられています。海馬とは異なり、新皮質の学習は遅く漸進的であり、多数のエピソードにわたる統計的規則性と潜在的構造を抽出するとされています。分散的で重複する表現(distributed, overlapping representations)を用いることで、カテゴリ構造や一般化可能なルールを自然に捕捉すると言われています。

2.2 Complementary Learning Systems (CLS) Theory

なぜ脳はこのような二重構造を必要とするのでしょうか。McClelland, McNaughton, & O'Reilly (1995) は、その原論文 "Why there are complementary learning systems in the hippocampus and neocortex" (Psychological Review) において、コネクショニストモデルの根本的な問題から出発してこの問いに答えました。

その問題とは 破滅的干渉(catastrophic interference) です。ニューラルネットワークが新しい情報を学習すると、以前に学習した情報が完全に上書きされてしまう傾向があります。McClelland らはこの制約を、脳の二重記憶アーキテクチャの説明的フレームワークへと転換しました。

海馬 = Fast Learner:

  • スパース符号化とパターン分離により、異なる記憶痕跡間の干渉を最小化
  • 任意の連合の one-shot learning が可能
  • 個別エピソードを高忠実度で保存
  • 新皮質の「教師」として機能し、保存されたエピソードを再生(replay)して新皮質の漸進的学習を駆動

新皮質 = Slow Learner:

  • 分散的で重複する表現により、多数のエピソードにわたる統計的規則性を自然に捕捉
  • 学習は遅く、interleaved でなければならない — 破滅的干渉を回避するため
  • 多くのエピソードにわたって漸進的に統合し、意味的知識を構築
  • 文脈非依存的な構造化知識の柔軟な検索をサポート

CLS 理論における固定化メカニズムは次のように説明されます。まず記憶は海馬系のシナプス変化として保存されます。次にこれらの海馬痕跡が新皮質での最近の体験の再現(replay)を支持します。各再現に伴い新皮質のシナプスが漸進的に変化し、最終的に遠隔記憶は蓄積された新皮質変化に基づくようになります。この interleaved replay により、新皮質は古い記憶と新しい記憶の混合に曝されるため、既存の知識を破壊することなく新しい情報を漸進的に受容できます。

CLS 理論のアップデート: Kumaran, Hassabis, & McClelland (2016) は "What Learning Systems do Intelligent Agents Need?" (Trends in Cognitive Sciences, 20, 512-534) において、CLS 理論を大幅に拡張しました。主要な更新点は以下の通りです。

  • 海馬 replay の役割を拡大 — 体験統計の goal-dependent(目標依存的)な重み付けが可能
  • 海馬痕跡の反復的活性化が、エピソード的詳細だけでなく一部の汎化もサポートしうることを示した
  • 既存の知識構造(schema)と整合的な情報に対しては、新皮質学習が高速化しうることを示した — これは元の理論からの重大な拡張である
  • CLS 原理を人工知能(強化学習、deep learning における experience replay)と明示的に結びつけた

schema-consistent 情報の高速新皮質学習は、Tse et al. (2007) の実験で劇的に示されました。ラットがスキーマを獲得した後、スキーマと整合的な新しい連合は 1 回の試行で学習され、その記憶の固定化はわずか 48 時間以内に完了しました。McClelland (2013) はこの知見を CLS 理論に組み込み、新情報が既存スキーマと整合する場合、通常の遅い interleaving 過程を経ずに新皮質ネットワークへ迅速に統合されうると提案しました。

2.3 Sleep Replay と記憶の固定化

記憶の固定化において重要な役割を果たすと考えられているのが、睡眠中のオフライン再処理です。

睡眠 replay(sleep replay)とは、覚醒時の体験中に活動していた海馬のニューロン発火パターンが、睡眠中に自発的に再活性化される現象です。この再活性化は、システム固定化を駆動する「オフライン再学習試行」として機能すると考えられています。

Rasch & Born (2013) の包括的レビュー (Physiological Reviews) は、睡眠と記憶の関係について以下の主要知見をまとめています。

  • 初期の理論は睡眠の受動的役割(干渉からの保護)を主張したが、現在の理論は睡眠中に記憶がシステム固定化を経る能動的役割を強調している
  • 徐波睡眠(SWS) は宣言的記憶の固定化に特に重要であり、REM 睡眠は手続き記憶や情動記憶の処理により寄与する
  • 新たに獲得された記憶は SWS 中に自発的に replay され、海馬から新皮質へと再活性化が流れる

2.4 AI エージェント設計への示唆

以上の神経科学的知見は、AI エージェントの記憶アーキテクチャ設計に対して明確なアナロジーを提供します。

生物学的メカニズム AI エージェントにおける対応
海馬 — 体験の高速符号化、one-shot learning エピソード記憶ストア — タスク実行ログの即時記録、個別の体験を高忠実度で保存
新皮質 — 分散表現、統計的規則性の漸進的抽出 意味記憶(Knowledge Graph) — 構造化された知識の長期保存、多数のエピソードからのパターン抽出
記憶の固定化 — 海馬から新皮質への段階的再編成 知識抽出パイプライン — エピソード記憶からの構造化知識の抽出・統合
Sleep replay — オフラインでの再活性化と再処理 バッチ処理パイプライン — 非同期的な知識抽出・統合ジョブ
Catastrophic interference 回避 — interleaved replay 増分的な知識グラフ更新 — 既存知識との整合性を保ちながらの漸進的統合
Schema-consistent 高速学習 — 既存スキーマと整合的な情報の迅速な新皮質統合 スキーマベースの高速取り込み — 既存のオントロジーに適合する情報の効率的な構造化

Kumaran et al. (2016) が明示的に指摘したように、CLS 理論の原理は deep learning におけるexperience replayと直接的な対応関係があるとされています。DQN(Deep Q-Network)が過去の体験をバッファに蓄積し、ランダムにサンプリングして interleaved training を行う手法は、海馬 replay による新皮質学習の計算論的アナロジーです。

我々の AI エージェントにおける意味記憶システムも、同様の原理に基づいて設計されています。タスク実行の記録(エピソード記憶)は即時に保存され、非同期の知識抽出パイプライン(固定化プロセス)がこれらのエピソードから Entity、Relation、Property を抽出して知識グラフ(意味記憶)へと統合します。このとき、既存のオントロジー(schema)と整合的な情報は効率的に統合される一方、新しいカテゴリの知識は段階的に取り込まれます — まさに CLS 理論が予測する動態です。

次のセクションでは、この異なる意味記憶の構造を統一フレームワークで取り扱うため、圏論(Category Theory)のフレームワークを導入します。

3. 圏論による統一的な知識表現フレームワーク

3.1 なぜ圏論か

AI エージェントの意味記憶は、リソース知識(ツリー構造)、トリプル知識(密なネットワーク)、チャンク知識(局所的クラスタ)、エピソード知識など、異質なグラフ構造を統一的に扱う必要があります。圏論(Category Theory)を採用する理由は 2 つあります。

  1. 異質なグラフ構造の統一表現: 異なる種類の知識グラフを「対象と射からなる圏」という共通モデルで表現し、Functor によってグラフ間の関係を統一的に扱える
  2. 抽出精度に応じた圏の構造の選択: 知識抽出パイプラインは「自由圏の構築(LLM 抽出)→ 商圏の構築(重複排除)」の 2 段階で構成される(Section 3.5)。抽出精度が高いドメインでは商圏まで進め、重複排除と同一視により推論的な検索に適した密なグラフを構築できる。精度が十分でないドメインでは自由圏に留め、ベクトル検索による柔軟なマッチングに重きを置くことができる

3.2 圏論の基本概念

圏論の基本概念を、ソフトウェアエンジニア向けにコンパクトに整理します。厳密な定義は Awodey, Category Theory (2nd ed., Oxford, 2010) および Mac Lane, Categories for the Working Mathematician (2nd ed., Springer, 1998) に準拠しています。

圏(Category)

C は以下のデータから構成されます。

  1. 対象(Object)の集まり Ob(C)
  2. 対象の各ペア (A, B) に対する射(Morphism)の集まり Hom(A, B)。射 f in Hom(A, B) を f : A -> B と書く
  3. 射の合成(Composition): Hom(B, C) x Hom(A, B) -> Hom(A, C)、すなわち (g, f) |-> g . f
  4. 各対象 A に対する恒等射(Identity Morphism) id_A : A -> A

これらは 2 つの公理を満たす必要があります。

  • 結合律(Associativity): h . (g . f) = (h . g) . f
  • 単位律(Identity Law): id_B . f = f = f . id_A

ソフトウェアエンジニアの言葉で言えば、圏とは「ノード(対象)とエッジ(射)からなるグラフに、エッジの合成規則と各ノードの自己ループ(恒等射)を加えたもの」です。重要なのは、合成の結合律が保証されている点 — これにより、複数の射の合成を括弧の付け方に依存せず一意に計算できます。

関手(Functor)

圏 C から圏 D への関手 F : C -> D は、構造を保存する写像です。

  • 対象の写像: A |-> F(A)
  • 射の写像: (f : A -> B) |-> (F(f) : F(A) -> F(B))

以下の 2 条件を満たします。

  • 合成の保存: F(g . f) = F(g) . F(f)
  • 恒等射の保存: F(id_A) = id_{F(A)}

ソフトウェアの文脈では、関手は「グラフ間の構造保存変換」に相当します。あるグラフのノードとエッジを別のグラフのノードとエッジに変換しつつ、接続関係を壊さないマッピングです。

自由圏(Free Category)

有向グラフ G が与えられたとき、G から生成される自由圏 F(G) は以下のように定義されます。

  • 対象: G の頂点
  • : G 上のパス(辺の有限列)。長さ 0 のパス(空パス)が恒等射
  • 合成: パスの連結

自由圏の本質は普遍性(Universal Property)にあります。任意の圏 D と任意のグラフ準同型 H : G -> U(D)(U は圏の「下に横たわるグラフ」を取る忘却関手)に対し、H を一意に拡張する関手 H' : F(G) -> D が存在します。

G ---H---> U(D)
|            ^
|eta_G       |U(H')
v            |
U(F(G)) ----+

つまり自由圏は、「グラフ構造を完全に保存する、最も一般的な圏」です。グラフに対して余計な等式を一切課さず、すべてのパスを独立な射として保持します。ソフトウェアの比喩を使えば、自由圏は「グラフのパスを全列挙したインデックス」のようなものです。

商圏(Quotient Category)

圏 C 上の合同関係(Congruence) R とは、各 Hom(A, B) 上の同値関係であって、合成と両立するものです。すなわち、f ~ f' かつ g ~ g' ならば g . f ~ g' . f' が成立します。

合同関係 R による商圏 C/R は以下のように構成されます。

  • 対象: C と同じ
  • : 同値類 [f](射 f の同値類)
  • 合成: [g] . [f] = [g . f](合同関係により well-defined)

商圏の要点は、特定の射を「同じもの」として同一視する操作です。

圏の提示: 自由圏 + 関係 = 圏

「基本となる矢印(生成元)」と「ルートの同一視ルール(関係)」を組み合わせることで、目的の圏を定義できます。具体的には以下のステップを踏みます。

  1. 生成元: ベースとなる有向グラフ G を指定する
  2. 関 係: 「このルートとあのルートは結果が同じ」という等式の集合 E を指定する
  3. 構 成: グラフ上のすべてのパスの集まり(自由圏 F(G))を、ルールの通りに同一視してまとめる(商圏 C = F(G) / R_E)

ソフトウェアの設計に例えると、「取り得るすべての状態遷移や処理のルート(自由圏)を洗い出し、最終的な結果や状態が同じになるルート同士を同一視する(重複排除・正規化)ことで、システムの本質的な振る舞いやデータ構造を抽出する」というパイプラインに対応します。

3.3 グラフ構造へのマッピング

圏論の概念を、我々の意味記憶システムの具象構造にマッピングします。

圏論の概念 意味記憶システムにおける対応
Category(圏) 知識グラフ全体(1つの抽出単位)
Object(対象) グラフのノード(Entity)
Morphism(射) グラフのエッジ(Relation)
Identity Morphism(恒等射) 自己参照エッジ(Entity の Self-loop)
Functor(関手) グラフ間の構造保存マッピング

知識の種類に応じて、4つの CategoryType を定義しています。

class CategoryType(IntEnum):
    """Type of semantic category."""
    CHUNK = 0     # テキストチャンクから抽出された知識グラフ
    RESOURCE = 1  # 構造化リソースから抽出された知識グラフ
    EPISODE = 3   # エピソード記憶から汎化された知識グラフ
    TRIPLE = 4    # トリプル形式で抽出された知識グラフ

各 CategoryType はそれぞれ異なる抽出手法から生成されますが、いずれも同一のデータモデル — Object(ノード)と Morphism(エッジ)の集合 — として表現されます。

@dataclass
class ExtractedCategory:
    """1 つの圏 = 1 つの知識グラフ"""
    name: str
    description: str
    objects: list[ExtractedObject]      # 対象 = ノード群
    morphisms: list[ExtractedMorphism]  # 射 = エッジ群
    hierarchy_level: int | None = None  # 抽象度レベル
    functors: list[ExtractedFunctor] | None = None  # 他の圏への関手

@dataclass
class ExtractedObject:
    """対象 = グラフのノード"""
    id: str
    name: str
    description: str
    properties: dict[str, Any]
    uri: str | None = None     # ソースリソース URI
    chunk: str | None = None   # ソーステキスト

@dataclass
class ExtractedMorphism:
    """射 = グラフのエッジ"""
    id: str
    name: str
    source_object_id: str   # domain(始域)
    target_object_id: str   # codomain(終域)
    description: str
    is_identity: bool       # 恒等射かどうか
    properties: dict[str, Any]

以下の Mermaid 図は、CategoryType 間の Functor 関係を示しています。異なる抽出手法から生成された知識グラフ同士が、Functor によって関連付けられます。

graph TB
    subgraph "CategoryType = RESOURCE (1)"
        R_CAT["Resource Category<br/><i>構造化リソースから抽出</i>"]
        R_OBJ1["Object: 商品 A"]
        R_OBJ2["Object: 規格 X"]
        R_OBJ1 -->|"Morphism: has_spec"| R_OBJ2
    end

    subgraph "CategoryType = TRIPLE (4)"
        T_CAT["Triple Category<br/><i>トリプル形式で抽出</i>"]
        T_OBJ1["Object: 商品 A"]
        T_OBJ2["Object: カテゴリ Y"]
        T_OBJ1 -->|"Morphism: belongs_to"| T_OBJ2
    end

    subgraph "CategoryType = CHUNK (0)"
        C_CAT["Chunk Category<br/><i>テキストチャンクから抽出</i>"]
        C_OBJ1["Object: 商品 A"]
        C_OBJ2["Object: 原材料 Z"]
        C_OBJ1 -->|"Morphism: contains"| C_OBJ2
    end

    subgraph "CategoryType = EPISODE (3)"
        E_CAT["Episode Category<br/><i>エピソードから汎化</i>"]
        E_OBJ1["Object: 発注パターン"]
        E_OBJ2["Object: 商品 A"]
        E_OBJ1 -->|"Morphism: targets"| E_OBJ2
    end

    R_CAT -.->|"Functor"| T_CAT
    T_CAT -.->|"Functor"| C_CAT
    E_CAT -.->|"Functor"| R_CAT

    style R_CAT fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
    style T_CAT fill:#fce4ec,stroke:#c62828,stroke-width:2px
    style C_CAT fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
    style E_CAT fill:#fff3e0,stroke:#e65100,stroke-width:2px

他の例として、例えば、同じ商品規格書のテキストに対して、トリプル抽出と命題分解をそれぞれ適用した場合を考えます。トリプル抽出は「商品 A — 含有 → 小麦」のような Entity 間の関係を抽出し、TripleCategory に格納します。命題分解は「商品 A は小麦を主原料とする北海道産の製品である」のような atomic な命題を抽出し、PropositionCategory に格納します。TripleCategory と PropositionCategory はいずれも、ソーステキストの ChunkCategory を Functor で参照します。つまり、同じチャンクから抽出された異なる粒度の知識が、ChunkCategory を介して Functor Element で紐づけられます。これにより、トリプルの構造的な関係と命題の文脈的な情報を横断的に検索・統合できます。

Functor は ExtractedFunctor として実装されており、ソース圏の Object をターゲット圏の Object にマッピングする要素のリストを保持します。

@dataclass
class ExtractedFunctor:
    """関手 = 圏間の構造保存マッピング"""
    name: str
    description: str
    elements: list[ExtractedFunctorElement]  # Object 間のマッピング
    target_category_name: str | None = None

@dataclass
class ExtractedFunctorElement:
    """関手の 1 要素 = Object 間の対応"""
    source_object_id: str
    target_object_id: str

3.4 4 つの圏の役割と階層構造

4 つの圏は、それぞれ異なる知識の側面を表現しています。

役割 含まれる Object の例
ResourceCategory 知識元のファイルや URL を表す。1つのリソース(ファイル、URL、ドキュメント)が 1 つの Object となる 「商品 A 規格書.pdf」「https://example.com/product-a
EpisodeCategory 過去のエピソード(タスク実行の体験)を表す。エージェントの行動履歴から汎化された知識が含まれる 「発注パターン」「在庫調整手順」
ChunkCategory テキストチャンクそのものを表す。チャンキングされた文書の各パッセージが 1 つの Object となる 「商品 A の規格書 第 2 段落」「発注履歴レポート 冒頭部」
TripleCategory トリプル分解(Subject-Predicate-Object)の結果を表す。抽出された Entity が Object となり、Relation が Morphism となる 「商品 A」「小麦」「北海道」(Object)、「含有」「産地」(Morphism)

重要な点は、これらの圏はそれぞれ独立して存在するのではなく、階層構造を持ち、Functor Element によって互いの Object 同士が紐づいていることです。

階層レベルと Functor 生成

抽出パイプラインは、各圏を階層レベル順に生成します。各レベルの処理が完了すると、上位レベルの圏から直前の下位レベルの圏への Functor が自動生成されます。

graph TB
    subgraph "Level 2"
        TRIPLE["TripleCategory<br/><i>トリプル分解結果</i>"]
    end
    subgraph "Level 1"
        CHUNK["ChunkCategory<br/><i>テキストチャンク</i>"]
    end
    subgraph "Level 0"
        RESOURCE["ResourceCategory<br/><i>知識元ファイル/URL</i>"]
    end

    TRIPLE -.->|"Functor<br/>(自動生成)"| CHUNK
    CHUNK -.->|"Functor<br/>(自動生成)"| RESOURCE

    style TRIPLE fill:#fce4ec,stroke:#c62828,stroke-width:2px
    style CHUNK fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
    style RESOURCE fill:#e3f2fd,stroke:#1565c0,stroke-width:2px

つまり、1つの入力データから抽出される複数の圏は、Functor で自動的に連鎖する構造を形成します。EpisodeCategory もエピソード記憶パイプラインにおいて同様の階層に組み込まれ、エピソードから抽出されたトリプルとの間に Functor が生成されます。

Functor Element による Object 間の紐づけ

Functor は圏と圏の間の構造ですが、実際に Object 同士を紐づけるのは Functor Element です。1つの Functor Element が「ソース圏のある Object」と「ターゲット圏のある Object」の対応を 1 件記録し、Functor に紐づく複数の Functor Element が 2 つの圏の間の Object 群のマッピングを構成します。

例えば、TripleCategory → ChunkCategory の Functor では、トリプル抽出時に各 Object がどのチャンクから抽出されたかを追跡しており、Functor Element はその出自関係に基づいて Object 同士を紐づけます。

graph LR
    subgraph "TripleCategory"
        T1["Object: 商品 A"]
        T2["Object: 小麦"]
        T1 -->|"Morphism: 含有"| T2
    end

    subgraph "ChunkCategory"
        C1["Object: 規格書 第 3 段落"]
    end

    subgraph "ResourceCategory"
        R1["Object: 商品 A 規格書.pdf"]
    end

    T1 -.->|"Functor Element"| C1
    T2 -.->|"Functor Element"| C1
    C1 -.->|"Functor Element"| R1

    style T1 fill:#fce4ec,stroke:#c62828,stroke-width:2px
    style T2 fill:#fce4ec,stroke:#c62828,stroke-width:2px
    style C1 fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
    style R1 fill:#e3f2fd,stroke:#1565c0,stroke-width:2px

この構造は、知識の出自追跡(Provenance Tracking)を可能にします。エージェントが「商品 A は小麦を含有する」というトリプルを利用する際に、Functor Element を辿ることで、その根拠となる Chunk テキスト(規格書 第 3 段落)と元のリソース(商品 A 規格書.pdf)まで遡ることができます。

EpisodeCategory の場合も同様に、エピソードから抽出されたトリプルとの間に Functor Element が生成され、「この知識はどのタスク実行で得られたか」というエピソード的文脈を保持します。一方、Section 5.2 で後述する外部データ(規格書等)からの直接抽出の場合、EpisodeCategory への Functor は生成されません — 体験を経由しない知識にはエピソード的文脈が存在しないためです。

ドメイン特化 Category の追加

ResourceCategory、ChunkCategory、EpisodeCategory、TripleCategory の 4 つは汎用的な基本圏ですが、このフレームワークは特定のドメインや業務タスクに特化した構造を持つ Category を自由に追加して運用できる設計になっています。

例えば、食品業界であれば「アレルゲン管理に特化した Category」を定義し、アレルゲン物質を Object、含有関係や閾値を Morphism として構造化することが考えられます。物流ドメインであれば「配送ルート最適化 Category」を定義し、倉庫・配送先を Object、配送経路を Morphism として表現できます。

新たに追加されたドメイン特化 Category も、既存の基本圏と同じ Object/Morphism のデータモデルに従うため、Functor Element によって基本圏の Object と紐づけることができます。つまり、ドメイン固有の知識構造を導入しても、既存のストレージ、検索、重複排除の仕組みはそのまま利用でき、他の Category との横断的な知識統合も自然に実現されます。

これは圏論ベースのフレームワークがもたらす拡張性の核心です。「対象と射からなる圏」という抽象度の高い統一モデルを採用しているからこそ、ドメインごとに異なる知識構造を同一のフレームワーク内に共存させることができます。

3.5 実装の圏論的構造

我々の知識抽出パイプラインは、圏論的に見ると以下の 2 段階で構成されています。

第 1 段階: 自由圏の構築(LLM 抽出)

LLM による知識抽出は、入力テキストから有向グラフ G を生成し、その自由圏 F(G) を構築するプロセスに対応します。LLM が抽出した全ての Object と Morphism はそのまま保持され、パス間の等式は一切課されません。

第 2 段階: 商圏の構築(重複排除)

抽出されたグラフには重複が含まれます — 同一の Entity が異なる名前で抽出されたり、異なるチャンクから同じ Relation が抽出されたりします。これを解消するのが deduplication(重複排除)プロセスであり、圏論的には合同関係による商圏の構築に対応します。

「商品 A」と「商品 A」と「Product A」が同一 Entity であるという同値関係を定義し、これらを 1 つの同値類に同一視する。この操作は、自由圏 F(G) 上に合同関係 R を定義し、商圏 F(G)/R を構成することと対応しています。

全体として: 意味記憶 = F(G) / R = 自由圏 / 合同関係

3.6 制約事項

我々の実装は、圏論の公理(結合律・単位律・合成の網羅性)を完全には保証していません。LLM による知識抽出は本質的に確率的であり、抽出されたグラフが厳密な圏を構成するとは限らないためです。

ただし、Section 3.1 で述べたように、これは段階的に対処可能な制約です。抽出精度が十分でないドメインでは自由圏に留めて公理に依存しない運用を行い、精度が高いドメインでは商圏まで進めて重複排除や同一視といった圏論の構造的特性を積極的に活用できます。公理の成立度合いが抽出精度と連動する設計により、圏論は精度に応じて実質的な計算上の恩恵を提供するフレームワークとして機能しています。

3.7 なぜ万能か — Section 4 への橋渡し

ここまでの議論を振り返ると、圏論による知識表現の核心的な強みが見えてきます。

GraphRAG のようにドキュメントをチャンク分割して Entity-Relation を抽出する手法も、Proposition ベースで atomic な命題を抽出する手法も、トリプル形式で主語-述語-目的語を抽出する手法も、出力は常に「ノードの集合とエッジの集合」です。圏論の言葉で言えば、これは「対象と射からなる圏」です。

この汎用性により、以下が可能になります。

  1. 同一モデルへの格納: あらゆる抽出手法の出力を ExtractedCategory(対象と射のリスト)として統一的に格納できる
  2. Functor による横断的関連付け: 異なる CategoryType の知識グラフ間で、Object 同士のマッピング(Functor)を定義し、知識を横断的に統合できる
  3. 抽出手法の Pluggable 化: 入力ソースや要件に応じて抽出手法を切り替えても、下流のストレージや検索の仕組みを変更する必要がない

この汎用性は、自由圏の普遍性(Universal Property)に裏付けられています。任意のグラフから圏を構成できるという自由圏の性質が、多様な抽出手法の出力を統一モデルに受け入れる能力を保証し、関手の概念が異なる知識グラフ間の構造保存的な関連付けを可能にします。

次のセクションでは、この統一フレームワークの上で実際にどのような知識抽出戦略(Extraction Strategy)が動作するかを詳しく見ていきます。

4. Pluggable な知識抽出戦略

4.1 フレームワークがもたらす Pluggability

Section 3.7 で述べたように、あらゆる知識抽出手法の出力は Category/Object/Morphism モデルとして統一的に格納できます。新しい抽出戦略の追加は「テキストから ExtractedCategory への変換ロジックを書く」ことに帰着し、下流のストレージ・検索・重複排除はすべて抽出手法に依存しません。

本セクションでは、この原理が具体的にどう機能するかを、3つの代表的な抽出手法(トリプル抽出、命題分解、GraphRAG)のマッピングを通じて示します。

graph TB
    INPUT["入力テキスト"]

    subgraph "抽出戦略(Pluggable)"
        S1["トリプル抽出"]
        S2["命題分解"]
        S3["GraphRAG"]
        S4["将来の手法..."]
    end

    subgraph "統一データモデル(不変)"
        CAT["ExtractedCategory"]
        OBJ["Object 群(Node)"]
        MOR["Morphism 群(Edge)"]
        CAT --- OBJ
        CAT --- MOR
    end

    subgraph "下流パイプライン(不変)"
        STORE["Knowledge Graph 永続化"]
        DEDUP["重複排除(商圏)"]
        SEARCH["検索・推論"]
    end

    INPUT --> S1
    INPUT --> S2
    INPUT --> S3
    INPUT --> S4
    S1 --> CAT
    S2 --> CAT
    S3 --> CAT
    S4 --> CAT
    CAT --> DEDUP --> STORE --> SEARCH

    style CAT fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
    style S1 fill:#fce4ec,stroke:#c62828
    style S2 fill:#e8f5e9,stroke:#2e7d32
    style S3 fill:#fff3e0,stroke:#e65100
    style S4 fill:#f3e5f5,stroke:#7b1fa2,stroke-dasharray:5 5

4.2 トリプル抽出と命題分解

テキストから構造化された知識を抽出する代表的なアプローチとして、トリプル抽出命題分解があります。

トリプル抽出(Triple Extraction) は、テキストから (Subject, Predicate, Object) 形式のトリプルを抽出する手法です。OpenIE(Banko et al., 2007)に始まり、REBEL(Cabot and Navigli, Findings of EMNLP 2021)による seq2seq 化を経て、現在は LLM ベースの抽出(KGGen: Mo et al., arXiv:2502.09956, 2025)が主流です。我々の実装でも DSPy を用いた LLM ベースのトリプル抽出を採用しています。トリプル (Subject, Predicate, Object) は射 Predicate : Subject -> Object として圏の構造に直接対応し、マッピングは最も直截的です。

命題分解(Proposition Extraction) は、テキストを原子的な命題(proposition)に分解するアプローチです。Chen et al.(arXiv:2312.06648, 2023; EMNLP 2024)は "Dense X Retrieval" において、Atomic(単一事実)・ Minimal(最小限の情報)・ Self-contained(自己完結的)な命題を検索単位として提案し、パッセージ単位やセンテンス単位と比較して検索精度の大幅な向上を示しました。命題分解では各命題が Object、命題間の関係(supports, contradicts 等)が Morphism となります。

2 つのアプローチの本質的な違いは、何を中心に据えるかです。トリプル抽出では Entity 間の Relation が主役で密なネットワークを形成し、命題分解では atomic な事実が独立した情報単位として機能します。どちらも最終的には Object + Morphism の集合として ExtractedCategory に格納され、フレームワーク側から見れば違いは抽出ロジックのみです。

4.3 エンティティ + 関係の構造化抽出(Microsoft GraphRAG)

Edge et al.(arXiv:2404.16130, 2024)が提案したGraphRAGは、トリプル抽出をさらに発展させ、抽出されたグラフに対するコミュニティ検出と階層的要約を組み合わせたアプローチです。

パイプライン概要

GraphRAG の知識抽出パイプラインは 4 つの段階から構成されます。

  1. ソースドキュメントのチャンク分割: テキストをチャンクに分割する。論文では、チャンクサイズ 600 トークンが 2400 トークンに比べて約 2 倍の Entity 参照を抽出できることが報告されている
  2. Entity ・ Relationship 抽出: LLM プロンプトにより、各チャンクから Entity(ノード)、Relationship(エッジ)、および Claim(共変量)を抽出する。Gleaningsと呼ばれる技法で、LLM を複数ラウンド呼び出して前のラウンドで見逃された Entity の追加抽出を促す
  3. Leiden アルゴリズムによるコミュニティ検出: 構築されたグラフに対して Leiden アルゴリズム(Traag, Waltman, and van Eck, Scientific Reports, 2019)を適用し、階層的なコミュニティ構造を検出する。Leiden アルゴリズムは louvain 法を改良したもので、局所的ノード移動、refinement フェーズ(poorly connected なコミュニティの分割)、集約の 3 フェーズからなり、well-connected なコミュニティを保証する
  4. コミュニティ要約: LLM が各コミュニティの要約を生成し、そのクラスタ内の主要なテーマと関係を捕捉する

マッピング: GraphRAG → Category/Object/Morphism

GraphRAG の出力には、Entity、Relationship、そして Community という 3 つの構造が含まれます。これらは圏論のフレームワークに以下のようにマッピングされます。

GraphRAG 要素 圏論の概念 データモデル
Entity Object(対象) ExtractedObject — Entity 名と description を格納
Relationship Morphism(射) ExtractedMorphism — 2 つの Entity 間の関係
Community(低レベル) Category(圏) ExtractedCategory — コミュニティ内の Entity 群と Relationship 群
Community(上位レベル) 上位 Category ExtractedCategory with hierarchy_level — 階層レベルを指定
コミュニティ間の包含関係 Functor(関手) ExtractedFunctor — 下位コミュニティの Node を上位コミュニティの Node にマッピング

特に重要なのは、Leiden アルゴリズムが生成する階層的コミュニティ構造が、hierarchy_level 属性を持つ複数の ExtractedCategory として自然に表現できる点です。下位レベルの Category から上位レベルの Category への Functor は、コミュニティのネスト構造(ある小さなコミュニティがより大きなコミュニティに包含される関係)を圏論的に記述します。

graph TB
    subgraph "hierarchy_level = 2"
        C2["Category: 食品流通全体<br/>(上位コミュニティ)"]
    end

    subgraph "hierarchy_level = 1"
        C1A["Category: 冷蔵品グループ"]
        C1B["Category: 常温品グループ"]
    end

    subgraph "hierarchy_level = 0"
        C0A["Category: 乳製品"]
        C0B["Category: 鮮魚"]
        C0C["Category: 調味料"]
        C0D["Category: 乾物"]
    end

    C0A -.->|"Functor"| C1A
    C0B -.->|"Functor"| C1A
    C0C -.->|"Functor"| C1B
    C0D -.->|"Functor"| C1B
    C1A -.->|"Functor"| C2
    C1B -.->|"Functor"| C2

    style C2 fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
    style C1A fill:#e8f5e9,stroke:#2e7d32
    style C1B fill:#e8f5e9,stroke:#2e7d32
    style C0A fill:#fff3e0,stroke:#e65100
    style C0B fill:#fff3e0,stroke:#e65100
    style C0C fill:#fff3e0,stroke:#e65100
    style C0D fill:#fff3e0,stroke:#e65100

4.4 Chunking 手法との組み合わせ

知識抽出戦略は、入力テキストの Chunking 手法と密接に関連します。どの抽出手法を用いるにしても、長大なドキュメントをどのような単位に分割するかは抽出品質に直接影響します。

主要な Chunking 手法を概観します。

  • Fixed-size Chunking: テキストを固定トークン数(例: 256, 512, 1024)で分割する最もシンプルな手法。文の途中で分割される可能性がある
  • Semantic Chunking: Greg Kamradt が提唱し、LangChain で実装された手法。連続する文の embedding 間の cosine similarity を計算し、類似度が閾値を下回る地点でブレークポイントを設定する
  • Context-enriched Chunking(Contextual Retrieval): Anthropic(2024)が発表した手法。LLM を用いて各チャンクにドキュメント全体における位置づけを説明する短いコンテキストを付与してから embedding する。top-20-chunk 検索の失敗率を最大 67%削減した
  • Late Chunking: Jina AI(Gunther et al., arXiv:2409.04701, 2024)が提案した手法。従来の「チャンク分割 → embedding」の順序を逆転させ、長コンテキスト embedding モデルでドキュメント全体をまず transformer 層に通し、トークンレベルの文脈化表現を得てからチャンク境界で mean pooling を適用する

これらの Chunking 手法もまた、圏論のフレームワーク内で表現できます。各チャンクを Object(ノード)とし、チャンク間の隣接関係や親子関係を Morphism(エッジ)とすれば、1つの Chunking の結果は ExtractedCategory として表現可能です。

この発想を拡張すると、抽出戦略と Chunking の階層的な組み合わせが可能になります。例として、以下のような 3 レベルの階層を考えます。

graph TB
    subgraph "Level 2: Triples"
        T1["Category: チャンク 1 のトリプル群"]
        T2["Category: チャンク 2 のトリプル群"]
        T3["Category: チャンク 3 のトリプル群"]
    end

    subgraph "Level 1: Chunks"
        CH1["Category: チャンク 1"]
        CH2["Category: チャンク 2"]
        CH3["Category: チャンク 3"]
    end

    subgraph "Level 0: Resource"
        R["Category: ドキュメント全体"]
    end

    T1 -.->|"Functor<br/>(出自追跡)"| CH1
    T2 -.->|"Functor<br/>(出自追跡)"| CH2
    T3 -.->|"Functor<br/>(出自追跡)"| CH3

    CH1 -.->|"Functor<br/>(出自追跡)"| R
    CH2 -.->|"Functor"| R
    CH3 -.->|"Functor"| R

    style T1 fill:#fce4ec,stroke:#c62828
    style T2 fill:#fce4ec,stroke:#c62828
    style T3 fill:#fce4ec,stroke:#c62828
    style CH1 fill:#e8f5e9,stroke:#2e7d32
    style CH2 fill:#e8f5e9,stroke:#2e7d32
    style CH3 fill:#e8f5e9,stroke:#2e7d32
    style R fill:#e3f2fd,stroke:#1565c0,stroke-width:2px

Level 2(Triples)から Level 1(Chunks)への Functor は各トリプルがどのチャンクから抽出されたかを追跡し、Level 1 から Level 0(Resource)への Functor はチャンクのソースドキュメントへの出自を記録します。Section 3.4 と同じく、抽象度の高い知識(トリプル)を上位レベル、知識元(リソース)を下位レベルとする体系です。各レベルの Category は hierarchy_level 属性で区別され、Functor 群がレベル間の構造的な接続を提供します。このように Chunking と抽出を Functor で結ぶことで、抽出されたトリプルからソースチャンク、さらにソースドキュメントへの遡行が、グラフ構造として自然に表現されます。

4.5 まとめ: フレームワーク側は変えない

本セクションで見てきたように、トリプル抽出、命題分解、GraphRAG の Entity-Relationship 抽出、そして各種 Chunking 手法は、それぞれ異なるアルゴリズムと異なる目的を持ちながらも、すべて同一のデータモデル — Category/Object/Morphism — に変換可能です。

この設計の要点は明確です。

  • 不変なもの: ExtractedCategory / ExtractedObject / ExtractedMorphism のデータモデル、Neo4j への永続化ロジック、重複排除(商圏)の機構、Functor によるグラフ間接続
  • 変わるもの: テキストから Graph への変換ロジック — すなわち、どのような手法で Entity と Relation を抽出するかという部分のみ

新しい抽出手法が学術コミュニティで提案されたとき — 例えば、より高精度な LLM ベースのトリプル抽出や、ドメイン特化型の構造化抽出手法が登場したとき — フレームワーク側のコードを変更する必要はありません。新しい手法の出力を ExtractedCategory に変換するロジックを追加するだけで、既存のパイプライン全体がそのまま利用できます。

次のセクションでは、これらの抽出戦略がどのようにパイプラインとして統合され、エピソード記憶や外部データソースから意味記憶が形成される全体フローを見ていきます。

5. 意味記憶の形成パイプライン

Section 3 で圏論に基づく統一データモデル(Category/Object/Morphism)を定義し、Section 4 で Pluggable な知識抽出戦略を論じました。本セクションでは、これらの部品がどのようにパイプラインとして統合され、意味記憶が実際に形成される全体フローを示します。

意味記憶の形成には2 つの入力経路が存在します。エピソード記憶からの固定化(体験を通じた学習)と、外部データからの直接抽出(体験を介さない知識の取り込み)です。これは神経科学的にも支持される構造であり、まずそれぞれの経路を知識獲得の神経科学的プロセスとシステムパイプラインの対比で解説し、最後に両経路の統合を論じます。

5.1 エピソード記憶からの固定化(体験からの学習)

第一の経路は、エージェントのタスク実行という体験を起点とする意味記憶の形成です。Section 2 で述べた記憶の固定化(Memory Consolidation)— 海馬での一時的なエピソード記憶が新皮質の長期的な意味記憶へと再編成されるプロセス — のシステム実装に相当します。

知識獲得の神経科学的プロセス(3段階)

生物学的知能における体験からの知識獲得は、以下の 3 段階で進行すると考えられています。

  1. エピソード記憶化 — タスク実行の体験が海馬に高速符号化される。CLS 理論(McClelland et al., 1995)によれば、海馬はスパース符号化とパターン分離により、個別のエピソードを one-shot learning で高忠実度に保存するとされる
  2. 意味記憶化 — 海馬に保存されたエピソード記憶が、睡眠中の replay(Rasch & Born, 2013)を通じて新皮質に漸進的に転送されると考えられている。このプロセスで、個別の体験から文脈非依存的な構造化知識(意味記憶)が抽出・固定化されるとされる
  3. 意味記憶の整理 — 新皮質において、重複する知識の統合、関連する知識間のリンク形成、そして重要度に基づくスコアリングが行われると考えられている。Tse et al. (2007) の実験では、既存のスキーマと整合的な新情報が迅速に統合されることが示されている

システムパイプライン(4段階)

上記の神経科学的プロセスに対応するシステムパイプラインは、以下の 4 段階で構成されています。

  1. エピソード記憶化 — タスク実行の完了後、AgentEpisodeKnowledge が生成され、Kinesis ストリームに送出される。これが海馬への高速符号化に対応する
  2. Extraction — Kinesis Consumer がストリームからエピソードを取得し、EpisodeKnowledgeGenerator -> EpisodeKnowledgeFilter -> EpisodeKnowledgePreChunker のパイプラインを経て、トリプル抽出(extract_triples_from_episode)が実行される。ここで個別の体験から構造化された知識(Entity + Relation)が抽出される
  3. RDB への保存 — 抽出された ExtractedCategory / ExtractedObject / ExtractedMorphism / ExtractedFunctor が、それぞれ AgentSemanticCategoryKnowledge / AgentSemanticObjectKnowledge / AgentSemanticMorphismKnowledge / AgentSemanticFunctorKnowledge として RDB に永続化される
  4. Vector Search & Graph DB への Indexing — 永続化された Object と Morphism の embedding が OpenSearch にベクトルインデックスとして登録され、同時に Neo4j/Neptune にグラフ構造(Node + Edge)として書き込まれる。CategoryVectorRetrievalGateway がベクトル検索を、CategoryGraphGateway がグラフトラバーサルを担う

対応表

脳神経 システム
海馬への一時保存(高速符号化) Kinesis ストリーム + AgentEpisodeKnowledge
新皮質への固定化(構造化) Extraction(EpisodeKnowledgeGenerator -> トリプル抽出)
エピソードと意味知識の関連づけ Functor(Episode Category -> Triple Category)
記憶の整理・統合 Dedup(RecordLinkageService + EdgeDeduplicationService)+ Scoring -> RDB / Vector / Graph

パイプライン全体図

graph LR
    subgraph "体験(覚醒時)"
        TASK["タスク実行"]
        EPK["AgentEpisode<br/>Knowledge 作成"]
        TASK --> EPK
    end

    subgraph "Kinesis ストリーム(海馬)"
        KIN["Kinesis<br/>Stream"]
    end

    subgraph "Extraction(固定化)"
        GEN["Generator"]
        FIL["Filter"]
        PCH["PreChunker"]
        TRI["トリプル抽出"]
        GEN --> FIL --> PCH --> TRI
    end

    subgraph "永続化(新皮質)"
        RDB["RDB<br/>Category / Object<br/>Morphism / Functor"]
        VEC["OpenSearch<br/>ベクトル Index"]
        GDB["Neo4j / Neptune<br/>グラフ構造"]
    end

    EPK --> KIN
    KIN --> GEN
    TRI --> RDB
    RDB --> VEC
    RDB --> GDB

    style TASK fill:#fff3e0,stroke:#e65100,stroke-width:2px
    style KIN fill:#e8eaf6,stroke:#283593,stroke-width:2px
    style TRI fill:#fce4ec,stroke:#c62828,stroke-width:2px
    style RDB fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
    style VEC fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
    style GDB fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px

5.2 外部データからの直接抽出(知識の取り込み)

第二の経路は、エピソード(体験)を経由しない意味記憶の形成です。商品規格書、業務マニュアル、マスタデータなどの外部リソースから、構造化された知識を直接抽出・取り込みます。

脳神経的なアナロジー

この経路には、強力な神経科学的裏付けがあります。

Vargha-Khadem et al. (1997) は Science 誌において、出生時・ 4 歳・ 9 歳にそれぞれ両側海馬の損傷(MRI で確認)を受けた 3 名の患者を対象とする症例研究を報告しました。

これらの患者は、日常生活のエピソード(いつ、どこで、何をしたか)に関する記憶が重度に障害されていたにもかかわらず、通常の学校に通い、言語能力、識字力、事実的知識において平均下位から平均の水準を達成しました。すなわち、エピソード記憶の形成能力が著しく損なわれた状態であっても、意味記憶(事実的知識)の獲得は可能だったのです。

この知見は、意味記憶がエピソード記憶から独立した経路でも形成されうることを示しています。Vargha-Khadem らは、海馬はエピソード記憶(体験の記憶)には必須であるが、意味記憶(事実的知識)の獲得には必ずしも必要でないという見解を提唱しました。

日常的なアナロジーで言えば、これは教科書を読んで学ぶプロセスに相当します。我々は教科書から「東京は日本の首都である」という事実を、東京を訪れるという体験なしに獲得できます。体験(エピソード)を経由せず、構造化されたテキストから直接的に意味知識を獲得する経路です。

ユースケース: 商品規格書からの意味記憶抽出

食品業界における具体例として、商品規格書(原材料、アレルゲン、栄養成分、産地等を記載した文書)からの知識抽出を考えます。

規格書は ResourceCategory(CategoryType = RESOURCE)として取り込まれます。パイプラインは以下の階層的な処理を行います。

  1. 規格書全体を ResourceCategory として登録
  2. テキストの Chunking(SemanticKnowledgePreChunker
  3. 各チャンクからのトリプル抽出(SemanticKnowledgeMemory

例えば、ある商品の規格書から以下のようなトリプルが抽出されます。

  • 「商品 A — 含有 -> 小麦」(アレルゲン情報)
  • 「商品 A — 産地 -> 北海道」(産地情報)
  • 「商品 A — 栄養成分 -> タンパク質 15g」(栄養成分)

これらはそれぞれ Object(商品 A、小麦、北海道、タンパク質 15g)と Morphism(含有、産地、栄養成分)として構造化され、Knowledge Graph に統合されます。

重要な違いは、この経路ではエピソード記憶が介在しないため、Episode Category との紐づけ(Functor)が生成されない点です。Vargha-Khadem et al. (1997) の患者が事実を知っていても「いつ・どこでそれを学んだか」を思い出せなかったのと同様に、外部データから抽出された知識は「どのタスク実行で得られたか」というエピソード的文脈を持ちません。

システムパイプライン(4段階)

  1. データ取り込み — Loader(API/ファイル)が外部リソースを取得し、AgentSemanticKnowledgeInput として登録する
  2. Extraction — リソースを SemanticKnowledgePreChunker で Chunking 後、SemanticKnowledgeFilter を経て、トリプル抽出が実行される
  3. RDB への保存AgentSemanticCategoryKnowledge / AgentSemanticObjectKnowledge / AgentSemanticMorphismKnowledge を RDB に永続化する。ただし AgentSemanticFunctorKnowledge のうち Episode Category への Functor は生成されない
  4. Vector Search & Graph DB への Indexing — エピソード経路と同一のインフラ(OpenSearch + Neo4j/Neptune)にインデキシングされる

5.3 両経路の統合

2 つの経路は入力ソースと前処理が異なりますが、最終的に同一のデータモデルに収束します

graph TB
    subgraph "経路 1: エピソード記憶からの固定化"
        TASK["タスク実行<br/>(体験)"]
        EPK["AgentEpisode<br/>Knowledge"]
        KIN["Kinesis<br/>Stream"]
        E_EXT["Episode<br/>Extraction"]
        E_FUN["Functor 生成<br/>(Episode → Triple)"]
        TASK --> EPK --> KIN --> E_EXT
        E_EXT --> E_FUN
    end

    subgraph "経路 2: 外部データからの直接抽出"
        SRC["外部リソース<br/>(規格書等)"]
        SKI["AgentSemantic<br/>KnowledgeInput"]
        S_EXT["Resource<br/>Extraction"]
        SRC --> SKI --> S_EXT
    end

    subgraph "統一データモデル(収束点)"
        CAT["Category<br/>(AgentSemanticCategoryKnowledge)"]
        OBJ["Object<br/>(AgentSemanticObjectKnowledge)"]
        MOR["Morphism<br/>(AgentSemanticMorphismKnowledge)"]
        CAT --- OBJ
        CAT --- MOR
    end

    subgraph "永続化 & Indexing"
        RDB["RDB"]
        VEC["OpenSearch<br/>ベクトル Index"]
        GDB["Neo4j / Neptune<br/>グラフ構造"]
        DEDUP["重複排除<br/>(RecordLinkage<br/>+ EdgeDedup)"]
    end

    E_EXT --> CAT
    E_FUN --> CAT
    S_EXT --> CAT
    CAT --> DEDUP
    DEDUP --> RDB
    RDB --> VEC
    RDB --> GDB

    style TASK fill:#fff3e0,stroke:#e65100,stroke-width:2px
    style SRC fill:#e0f2f1,stroke:#00695c,stroke-width:2px
    style CAT fill:#e3f2fd,stroke:#1565c0,stroke-width:3px
    style OBJ fill:#e3f2fd,stroke:#1565c0
    style MOR fill:#e3f2fd,stroke:#1565c0
    style RDB fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
    style VEC fill:#f3e5f5,stroke:#7b1fa2
    style GDB fill:#fce4ec,stroke:#c62828
    style DEDUP fill:#fff8e1,stroke:#f57f17

この統合が自然に機能する理由は、Section 3 で導入した圏論のフレームワークにあります。

同一のデータモデルへの収束: 両経路とも、最終出力は ExtractedCategory(Object 群 + Morphism 群)です。エピソード経由であれ外部データ経由であれ、抽出された Entity と Relation は同じ Category/Object/Morphism モデルとして格納されます。

Knowledge Graph 上での自然な統合: エピソード経由で抽出された「商品 A — 在庫不足 -> 発注推奨」というトリプルと、規格書から抽出された「商品 A — 含有 -> 小麦」というトリプルは、共通の Object「商品 A」を介して Graph 上で自然に接続されます。重複排除(RecordLinkageService + WithinBatchDuplicateDetector)が同一 Entity の同定を行い、商圏の構築(Section 3.5)により統合された Graph が形成されます。

Functor による横断的な関連付け: エピソード経由の知識は FunctorType を通じて Episode Category と Triple Category の間に構造保存的なマッピングを持ちます。一方、外部データ経由の知識は Resource Category と Triple Category の間に Functor を持ちます。これらの Functor により、あるトリプルが「どのエピソードから抽出されたか」あるいは「どのリソースから抽出されたか」を遡行的に追跡できます。ただし、外部データ経由の知識が Episode Category への直接的な Functor を持つことはありません — これは Vargha-Khadem et al. (1997) の知見と対応する設計上の選択です。

全体として、この 2 経路の統合は、生物学的知能が体験と教示の両方から知識を獲得し、それらを単一の意味記憶ネットワークに統合するプロセスの計算論的実装と位置づけることができます。

6. 結論と今後の展望

6.1 記憶システム全体のまとめ

本記事では、AI エージェントの意味記憶(Semantic Memory)エピソード記憶(Episodic Memory)のアーキテクチャを、生物学的知能の設計原理を出発点として論じてきました。前回の記事で扱った手続き記憶(Procedural Memory)= Chain 機構と合わせると、AI エージェントの記憶システムにおける主要な 3 つの柱をカバーしたことになります。

graph TD
    LTM["長期記憶<br/>(Long-term Memory)"]
    DM["陳述記憶 / 宣言的記憶<br/>(Declarative Memory)"]
    NDM["非陳述記憶 / 非宣言的記憶<br/>(Non-declarative Memory)"]
    EM["エピソード記憶<br/>(Episodic Memory)<br/><i>個人的な体験の記憶</i>"]
    SM["意味記憶<br/>(Semantic Memory)<br/><i>一般的な知識・事実</i>"]
    PM["手続き記憶<br/>(Procedural Memory)<br/><i>スキル・手順の記憶</i>"]
    OTHER["プライミング, 条件づけ 等"]

    LTM --> DM
    LTM --> NDM
    DM --> EM
    DM --> SM
    NDM --> PM
    NDM --> OTHER

    style SM fill:#e8f4fd,stroke:#1976d2,stroke-width:3px,color:#000
    style PM fill:#f3e5f5,stroke:#7b1fa2,stroke-width:3px,color:#000
    style EM fill:#fff3e0,stroke:#e65100,stroke-width:3px,color:#000
    style OTHER fill:#f5f5f5,stroke:#9e9e9e,stroke-width:1px,stroke-dasharray:5 5

手続き記憶(前回) では、大脳基底核のチャンキング機構を出発点に、Chain 機構によるタスク実行パイプラインの設計を論じました。手続き記憶の実体は、高階関数として構成された tool chain の組み合わせ、またはタスク実行 Python コードです。一度学習(記録)された Chain は LLM の推論を介さずに決定的に再実行でき、エラー時のみ自己修復機構が介入します。スキルの自動化、エラーモニタリング、そしてサブルーチンの階層的な組み合わせが、エージェントの「どうやるか(How)」の知識を構成します。

エピソード記憶・意味記憶(今回) では、海馬-新皮質間の記憶の固定化(Memory Consolidation)メカニズムを出発点に、エピソード記憶の即時記録から Knowledge Graph による構造化知識の長期保存に至るアーキテクチャを論じました。CLS 理論(McClelland et al., 1995)が示す二重記憶システムの原理を、エピソード記憶ストアと Knowledge Graph の関係に適用し、圏論(Category Theory)のフレームワークを用いて多様な知識抽出手法の出力を統一的に表現する仕組みを構築しました。

振り返ると、本記事の各セクションは以下のように有機的に接続しています。

  • Section 2 が生物学的知能の記憶固定化メカニズムを概観し、AI システム設計のメンタルモデルを提供した
  • Section 3 が圏論のフレームワークを導入し、Category/Object/Morphism という統一的なデータモデルを定義した
  • Section 4 がこの統一モデルの上で動作する Pluggable な知識抽出戦略(トリプル抽出、命題分解、GraphRAG)を論じた
  • Section 5 が 2 つの入力経路(エピソード記憶からの固定化と外部データからの直接抽出)を統合するパイプライン全体像を示した

生物学的知能の設計原理を AI システム設計に応用するこのアプローチの核心は、脳のメカニズムを忠実に再現することではなく、進化が数億年かけて洗練した情報処理の構造的パターンを、エンジニアリング上の設計指針として抽出することにあります。CLS 理論が Fast Learner(海馬)と Slow Learner(新皮質)の分離を説明するように、我々のシステムもエピソード記憶の即時記録と意味記憶の漸進的構築を分離しています。圏論が数学の諸分野に共通する構造的パターンを抽象化するように、我々のフレームワークも多様な知識抽出手法の出力に共通するグラフ構造を抽象化しています。

6.2 今後の課題

現在のアーキテクチャは知識グラフ(Object ・ Morphism)の抽出・格納・検索という基盤を確立していますが、生物学的知能の記憶システムが持ついくつかの重要な機能についてはパイプラインとしての自動化に至っていません。

これらの機能は現在、専用の Knowledge Manager Agent を介して人間が Knowledge Graph を直接操作する運用(不要な知識の削除、スコアの調整、知識の修正・統合、確信度の評価など)で対応しています。完全自動化に至っていない理由は、運用の安定性を重視しているためです。意味記憶の自動的な書き換えや削除は、誤った操作がエージェントの後続の推論に連鎖的な影響を及ぼすリスクがあります。現段階では、人間が最終判断を行う運用が合理的と考えています。

その上で、段階的に自動化の範囲を広げるべく、以下の 4 つの方向で実験を進めています。

6.2.1 忘却メカニズム

人間の記憶において、忘却は欠陥ではなく不可欠な機能です。不要な情報の pruning により、関連性の高い知識への効率的なアクセスが維持され、知識の検索空間が適切なサイズに保たれます。

現状、llm_score(LLM による重要度評価)と human_score(人間によるフィードバック)によるスコアリングは存在しますが、低スコアの知識を自律的に除去・降格する仕組みは組み込んでいません。実験中のアプローチとして、スコアベースの pruning、使用頻度に基づく減衰(Decay)、コンテキストに対する関連度の動的評価(Relevance scoring)を検討しています。

6.2.2 記憶の再固定化

Nader, Schafe, & LeDoux (2000) は、Nature 誌において、既に固定化された記憶も再活性化時に再び不安定になり、更新可能であることを示しました。この記憶の再固定化(Reconsolidation)は、記憶が一度固定化されれば永続的に安定するという従来の仮説を覆す発見でした。

現状、一度格納された知識が検索・利用時に自動的に再評価・更新される仕組みは組み込んでいません。実験中のアプローチとして、検索・利用時に関連知識を自律的に再評価・更新する仕組み — 記憶を想起するたびにその記憶が一時的に可塑的になり、更新されうるという再固定化の計算論的実装 — の導入を検討しています。

6.2.3 メタ認知的な記憶管理

生物学的知能は、自らの知識の状態を認識するメタ認知(Metacognition)の能力を備えています。「何を知っていて何を知らないか」を把握し、知識の確信度を評価し、情報源の信頼性を判断する能力です。

現状、知識の確信度管理(抽出信頼度、ソース品質、複数ソースからの裏付け)、出典の信頼性評価、時間経過に伴う知識の鮮度管理といったメタ認知的機能が体系化されていません(一部時間を取り扱う機能等は入っていますが、体系化されているとは言い難い)。エージェントが「この知識は確実か」「この情報は最新か」「この回答に十分な根拠があるか」といった判断を自律的に下せるようになることが、意味記憶システムの信頼性を次の段階に引き上げる鍵となります。

6.2.4 圏論的公理への接近

Section 3.6 で述べたように、現在の実装は圏論の公理(結合律、単位律、合成の網羅性)を完全には保証していません。LLM による抽出が本質的に確率的である以上、抽出直後のグラフが厳密な圏を構成しないことは避けられません。しかし、抽出精度の向上により公理に即した構造へ近づけることは、上述の自律的な再評価・更新の仕組みにとって重要な基盤となります。例えば、射の合成が結合律を満たすかどうかを検証できれば、矛盾する知識の検出や、再固定化における更新の整合性チェックに活用できます。抽出品質の改善と公理検証の段階的な導入は、知識グラフの構造的な信頼性を高め、忘却・再固定化・メタ認知の各機構がより確かな基盤の上で動作することを可能にします。


参考文献

神経科学・認知科学:

  • Tulving, E. (1972). Episodic and semantic memory. In E. Tulving & W. Donaldson (Eds.), Organization of Memory (pp. 381-403). Academic Press.
  • McClelland, J. L., McNaughton, B. L., & O'Reilly, R. C. (1995). Why there are complementary learning systems in the hippocampus and neocortex: Insights from the successes and failures of connectionist models of learning and memory. Psychological Review, 102(3), 419-457.
  • Squire, L. R., & Alvarez, P. (1995). Retrograde amnesia and memory consolidation: A neurobiological perspective. Current Opinion in Neurobiology, 5(2), 169-177.
  • Vargha-Khadem, F., Gadian, D. G., Watkins, K. E., Connelly, A., Van Paesschen, W., & Mishkin, M. (1997). Differential effects of early hippocampal pathology on episodic and semantic memory. Science, 277(5324), 376-380.
  • Nader, K., Schafe, G. E., & LeDoux, J. E. (2000). Fear memories require protein synthesis in the amygdala for reconsolidation after retrieval. Nature, 406(6797), 722-726.
  • Frankland, P. W., & Bontempi, B. (2005). The organization of recent and remote memories. Nature Reviews Neuroscience, 6(2), 119-130.
  • Tse, D., Langston, R. F., Kakeyama, M., Bethus, I., Spooner, P. A., Wood, E. R., Witter, M. P., & Morris, R. G. M. (2007). Schemas and memory consolidation. Science, 316(5821), 76-82.
  • Greenberg, D. L., & Verfaellie, M. (2010). Interdependence of episodic and semantic memory: Evidence from neuropsychology. Journal of the International Neuropsychological Society, 16(5), 748-753.
  • McClelland, J. L. (2013). Incorporating rapid neocortical learning of new schema-consistent information into complementary learning systems theory. Journal of Experimental Psychology: General, 142(4), 1190-1210.
  • Rasch, B., & Born, J. (2013). About sleep's role in memory. Physiological Reviews, 93(2), 681-766.
  • Kumaran, D., Hassabis, D., & McClelland, J. L. (2016). What learning systems do intelligent agents need? Complementary learning systems theory updated. Trends in Cognitive Sciences, 20(7), 512-534.

圏論:

  • Mac Lane, S. (1998). Categories for the Working Mathematician (2nd ed.). Springer.
  • Awodey, S. (2010). Category Theory (2nd ed.). Oxford University Press.

知識抽出手法:

  • Banko, M., Cafarella, M. J., Soderland, S., Broadhead, M., & Etzioni, O. (2007). Open information extraction from the web. In Proceedings of the 20th International Joint Conference on Artificial Intelligence (IJCAI) (pp. 2670-2676).
  • Angeli, G., Premkumar, M. J., & Manning, C. D. (2015). Leveraging linguistic structure for open domain information extraction. In Proceedings of the 53rd Annual Meeting of the Association for Computational Linguistics (ACL) (pp. 344-354).
  • Traag, V. A., Waltman, L., & van Eck, N. J. (2019). From Louvain to Leiden: Guaranteeing well-connected communities. Scientific Reports, 9, 5233.
  • Cabot, P.-L., & Navigli, R. (2021). REBEL: Relation extraction by end-to-end language generation. In Findings of the Association for Computational Linguistics: EMNLP 2021 (pp. 2370-2381).
  • Chen, T., Wang, H., Chen, S., Yu, W., Ma, K., Zhao, X., Zhang, H., & Yu, D. (2023). Dense X retrieval: What retrieval granularity should we use? arXiv preprint arXiv:2312.06648. (EMNLP 2024)
  • Edge, D., Trinh, H., Cheng, N., Bradley, J., Chao, A., Mody, A., Truitt, S., Metropolitansky, D., Ness, R. O., & Larson, J. (2024). From local to global: A graph RAG approach to query-focused summarization. arXiv preprint arXiv:2404.16130.
  • Anthropic. (2024). Introducing contextual retrieval. Anthropic Research Blog.
  • Gunther, M., Mohr, I., Williams, D. J., Wang, B., & Xiao, H. (2024). Late chunking: Contextual chunk embeddings using long-context embedding models. arXiv preprint arXiv:2409.04701.
  • Mo, B., Yu, K., Kazdan, J., Cabezas, J., Mpala, P., Yu, L., Cundy, C., Kanatsoulis, C., & Koyejo, S. (2025). KGGen: Extracting knowledge graphs from plain text with language models. arXiv preprint arXiv:2502.09956.

AIエージェントの設計思想:Chain機構と手続き記憶

スパイスコード CTO の櫻木です (X: https://x.com/ysrhspyoshi)。これまでの記事では、AI Agentにおける「コンテキストエンジニアリング」の重要性と、tool chain toolを用いた実装アプローチ、そして実際のブラウザ自動化タスクにおける定量的な実験結果を報告してきました。

前回までの記事:

今回は、私たちがエージェント設計の際に参考にしている理論的基盤について、認知科学神経科学の観点から説明します。Chain機構と自己修復機能のハイブリッドアーキテクチャは、人間の脳における「二重過程(Dual-Process)」の制御戦略を参考に設計されています。

目次

  1. なぜ理論的基盤が重要なのか
  2. Chain機構の神経科学的基盤:手続き記憶とチャンキング
  3. 自己修復機能の神経科学的基盤:エラーモニタリングと認知制御
  4. 二重過程理論:不確実性に基づく調停メカニズム
  5. 実装への示唆:生物学的知能から学ぶ設計原則
  6. まとめ

1. なぜ理論的基盤が重要なのか

前回の記事で報告したように、Method C(Chain方式)は Method A(毎回探索する方式)と比較して3.4倍高速、コスト1/5.5という結果が得られました。このアーキテクチャの効率性は、単なる工学的な最適化だけでなく、生物学的知能の仕組みを参考にした設計に基づいています。

1.1 「固定のワークフローとの違い」という問い

Chain機構の説明をすると、よく「それは単なる固定のワークフローでは?」という質問を受けます。確かに、決定的な操作シーケンスを事前定義して実行するという点では似ています。

しかし、決定的な違いがあります。固定のワークフローは、予期せぬ状況(サプライズ)に対して脆弱です。UIが変わる、要素が見つからない、タイムアウトが発生する——こうした状況で、固定ワークフローは単に失敗します。

私たちのChain機構は、人間の手続き記憶(Procedural Memory)を参考にしています。人間は、習熟した作業を無意識に(低コストで)遂行しますが、予期せぬ障害に直面した時、瞬時に宣言的記憶(Declarative Memory)エピソード記憶(Episodic Memory)を動員し、柔軟に行動を変容させます。これは、複数の記憶システムが協調する脳のアーキテクチャによって実現されています。

本記事では、この「低コストな自動実行」と「柔軟な適応」の両立が、どのような認知神経科学的メカニズムに基づいているのかを説明します。

1.2 生物学的知能を参考にした設計

生物学的脳は、限られた計算リソース(エネルギー)の中で、複雑な環境下での意思決定と行動実行を数億年かけて最適化してきました。その結果として獲得された神経メカニズムは、効率性と柔軟性のトレードオフに対する参照可能な解となっています。

私たちのChain機構と自己修復機能は、これらの理論を参考に設計しており、その理論的背景を理解することで:

  • 設計判断の根拠が明確になる:「なぜこの実装が正しいのか」を説明できる
  • 改善の方向性が見える:脳の仕組みから、次のステップへのヒントを得られる
  • 未知の問題への対応力が上がる:原理原則を理解していれば、新しい課題にも応用できる


2. Chain機構の神経科学的基盤:手続き記憶とチャンキング

第1回の記事で紹介したChain機構は、一連の操作を単一の実行単位としてカプセル化し、LLMの推論を介さずに高速実行する仕組みです。これは、生物学的脳における「手続き記憶(Procedural Memory)」の形成プロセスを参考にしています。

2.0 記憶システムの分類と役割

脳の記憶システムは大きく以下のように分類されます:

手続き記憶(Procedural Memory)

運動技能や習慣(例:自転車の乗り方、タイピング)。意識的なアクセスが不要で、高速・低コスト。大脳基底核を中心とした神経回路で実現されます。

宣言的記憶(Declarative Memory)

言語化可能な知識。意識的なアクセスが必要で、柔軟だがコストが高い。海馬と大脳皮質の連携で実現されます。

  • エピソード記憶(Episodic Memory):個人的な経験(例:昨日のミーティングで何が起きたか)
  • 意味記憶(Semantic Memory):一般的な事実(例:東京は日本の首都)

私たちのアーキテクチャとの対応:

固定のワークフローは「手続き記憶のみ」の状態に相当します。一方、私たちのアーキテクチャは、通常時は手続き記憶(Chain)で高速実行し、エラー時には宣言的記憶(LLMの知識)やエピソード記憶(過去の操作ログ)を参照して適応するという、複数の記憶システムの協調を実装しています。

この協調メカニズムこそが、固定ワークフローにはない「柔軟性」を実現する鍵となります。

重要な注意:機能局在主義について

以降の説明では便宜上、特定の脳領域と機能を対応付けて説明しますが、これは古典的な機能局在主義(functional localization) の立場を取るものではありません。現代の神経科学が示すように、脳機能は特定の領域に局在するのではなく、広範な皮質・皮質下領域を含む分散的なネットワークとして実現されています。例えば、大脳基底核による習慣学習も、前頭前皮質視床線条体など複数の領域が協調して初めて機能します。

ここで示す脳領域と機能の対応関係は、各神経回路が担う中心的な役割を概念的に示したものであり、設計の着想を得るための理論的な参照点として理解してください。私たちのAIアーキテクチャも同様に、各コンポーネントが独立して機能するのではなく、相互に連携するシステムとして設計されています。

2.1 大脳基底核によるシーケンス学習

MIT Ann Graybielらの研究は、ラットが迷路タスクを学習する過程で、線条体大脳基底核の一部)の神経活動パターンが変化することを示しました[1][2]。

学習初期(探索フェーズ)

  • 神経活動は動作全体に分散して発火
  • 高い認知負荷、逐次的な意思決定
  • AIの対応:Method A(毎回UIを探索)、Agentic Loop

学習後期(習慣フェーズ)

  • 神経活動はシーケンスの開始と終了時に集中
  • 低い認知負荷、バリスティック(弾道的)な実行
  • AIの対応:Method C(Chain実行)

この変化は「チャンキング(Chunking)」と呼ばれ、複雑な動作シーケンスが脳内で単一の「実行ユニット」として再表現されたことを意味します。

┌─────────────────────────────────┐
│    学習初期(探索フェーズ)      │
├─────────────────────────────────┤
│ ステップ1 → 推論 → 実行          │
│ ステップ2 → 推論 → 実行          │
│ ステップ3 → 推論 → 実行          │
│         (高コスト)               │
└─────────────────────────────────┘
              ↓ チャンキング
┌─────────────────────────────────┐
│    学習後期(Chain化)           │
├─────────────────────────────────┤
│ Chain開始 → [1+2+3] → Chain終了  │
│         (低コスト)               │
└─────────────────────────────────┘

2.2 ACT-R理論:宣言的知識から手続き的知識へ

認知アーキテクチャACT-R(John Anderson)は、人間の知識が「宣言的知識」から「手続き的知識」へと変換されるメカニズムを定式化しています[3][4]。

プロダクション・コンパイル(Production Compilation)

  1. 構成(Composition):連続して実行される複数のルールを結合

    • Before: ルールA(検索)→ ルールB(実行)
    • After: ルールAB(一括実行)
  2. 手続き化(Proceduralization):変数を定数に置き換え、メモリアクセスを不要化

    • Before: IF 目標=ログイン AND 要素=変数x THEN x を検索して実行
    • After: IF 目標=ログイン THEN #login-button をクリック(検索なし)

私たちのChain生成プロセスとの対応:

# 第1回記事で紹介したChain生成の流れ
1. Agenticモードで操作を実行(探索)
2. 操作ログを解析
3. playwright-mcpのbrowser_run_codeを含むChainとして保存
4. 次回以降はChain IDを参照するだけで実行(コンパイル済み)

これは、ACT-Rのプロダクション・コンパイルを、LLMとブラウザ自動化の文脈で実装したものです。

2.3 階層的強化学習(HRL):オプションとしてのChain

強化学習の分野では、行動の階層化は「オプション(Options)」として定式化されています[5][6]。オプションは以下の3要素で定義されます:

  • 開始条件(I):どの状態でこのオプションが実行可能か(例:ログインページ)
  • 方策(π):オプション内部での行動選択ルール(例:Chainに含まれる一連の操作)
  • 終了条件(β):いつこのオプションを終了するか(例:ダッシュボード到達)

Chain機構の数学的表現:

Chain_Login = <I, π, β>
  I = {state: login_page}
  π = [enter_username, enter_password, click_submit]
  β = {state: dashboard}

Botvinick (2012)の研究によれば、前頭前皮質(PFC)が現在の文脈に応じて適切なオプション(Chain)を選択し、大脳基底核がその内部の具体的なアクション(チャンク)を実行するという役割分担が行われています[7]。

実装への示唆:

  • Chainを選択するための「メタエージェント」の設計
  • Chain間の依存関係を考慮した階層的構造の導入

3. 自己修復機能の神経科学的基盤:エラーモニタリングと認知制御

Chain機構は効率的ですが、環境変化に対して脆弱です。この問題に対処するのが「自己修復(Self-Repair)」機能であり、これは脳における「認知制御(Cognitive Control)」システムに対応します。

3.1 前帯状皮質(ACC)によるエラー検知

脳波(EEG)研究において、エラー発生直後(50-100ms後)に前頭部で観測されるERN(Error-Related Negativity)という信号の発生源は、前帯状皮質(ACC)であることが特定されています[8][9]。

ACCは単なるエラーだけでなく、「予測誤差(Prediction Error)」全般を監視しています。Haydenらの研究は、予期せぬ結果がACCニューロンを活性化させ、行動戦略の変更を引き起こすことを示しました[10]。

AIエージェントにおける実装:

# Chain実行中の予測誤差検知
try:
    execute_chain(chain_id)  # 期待:正常実行
except NoSuchElementException:
    # 実際:要素が見つからない → 予測誤差
    trigger_self_repair()  # ACCによる介入要請に相当

3.2 期待される制御価値(EVC)理論

Shenhav & Botvinick (2013)のEVC理論によれば、ACCは「認知制御を発動するコスト」と「それによって得られる報酬の増加分」を常に天秤にかけています[11]。

通常時(Chain実行):
  - 制御コスト: 低
  - 成功確率: 高
  → 自動処理を継続

エラー時(予測誤差大):
  - 成功確率: 低下
  - 制御を発動した場合の期待価値: 上昇
  → Agenticモードへ切り替え

この理論は、常時LLMを使うのではなく、エラー時のみ高コストな推論を行うという設計方針に対応しています。

3.3 頭頂葉による高速な微調整

より軽微なエラーに対しては、大規模な再プランニングではなく、局所的な調整で対応できます。後頭頂皮質(PPC)は、意識的な介入なしに即座に行動を修正する「オートパイロット」機能を持つことが示されています[12][13]。

実装例:

# 軽微な変動への対応(小脳・頭頂葉的)
element = wait_for_element(selector, timeout=5)  # 待機
if not element:
    element = find_nearby(selector, radius=10)  # 近傍探索

これにより、完全な再プランニング(前頭前皮質的)を発動する前に、低コストな修正で対応する階層的なエラー処理が可能になります。


4. 二重過程理論:不確実性に基づく調停メカニズム

ここまで、Chain(習慣)とAgentic(熟慮)を個別に論じてきましたが、最も重要なのはこれらをいかに統合・制御するかです。

4.1 モデルフリーとモデルベースの競合

Daw, Niv, & Dayan (2005)の研究によれば、脳内には二つの並列する強化学習システムが存在します[14][15]:

システム 神経基盤 特徴 AI対応
モデルフリー(MF) 背外側線条体 低コスト、環境変化への適応が遅い Chain機構
モデルベース(MB) 前頭前皮質、海馬 高コスト、柔軟で適応的 Agentic推論

4.2 ベイズ的不確実性による調停(Arbitration)

脳はこれらのシステムをランダムに切り替えるのではなく、各システムの予測の「不確実性(Uncertainty)」を常に推定し、より確実性の高いシステムに制御権を委ねています[14]。

安定期(エラー率低):
  MFの不確実性: 低 → Chain実行
  MBの不確実性: 高(不要)

不安定期(エラー発生):
  MFの信頼度: 急低下
  MBの相対的信頼性: 上昇 → Agenticへ切替

私たちのアーキテクチャとの対応:

# デフォルトでChainを試行
confidence_chain = estimate_chain_reliability(chain_id, recent_errors)

if confidence_chain > threshold:
    execute_chain()  # モデルフリー的実行
else:
    execute_agentic()  # モデルベース的探索

第2回の記事で報告したように、Method Cは標準偏差4.0秒という安定性を示しました。これは、Chainの信頼性が維持されている限り、低コストな決定的実行を継続できることを意味します。

4.3 代理試行錯誤(VTE):海馬による未来シミュレーション

新規環境やChainが失敗した場合、エージェントはAgenticモードに移行します。この時、複数の候補アクションを評価する必要があります。

David Redishらの研究によれば、ラットが迷路の分岐点で左右を見やる「代理試行錯誤(VTE)」の最中、海馬の場所細胞が未来の経路を高速で再生(スイープ)する現象が観測されています[16][17]。

VTEの構成要素 機能的役割 AIエージェント
停止(Pause) 自動行動の抑制 Chainの中断
場所細胞のスイープ 将来経路のシミュレーション Tree of Thoughts / Planner
評価(Valuation) 報酬予測 LLMによるスコアリング

実装例:

# Planner / MCTS的なアプローチ
candidates = extract_possible_actions(dom)
for action in candidates:
    simulated_outcome = llm.predict(action, current_state)
    score = evaluate_goal_proximity(simulated_outcome)
best_action = max(candidates, key=score)


5. 実装への示唆:生物学的知能から学ぶ設計原則

これらの神経科学的知見から、次のような設計原則が導かれます。

5.1 階層的なエラー処理

前回の実験で、自己修復フェーズのコストが初回実行より低い傾向が見られました(例: Site B Chain で$1.74 → $0.30)。これをさらに洗練させるために:

レベル1(小脳・頭頂葉的):Wait / Retry / 近傍探索
  → コスト: 極小、成功率: 中

レベル2(ACC的):Chain内の部分修正
  → コスト: 小、成功率: 高

レベル3(PFC的):完全な再プランニング
  → コスト: 大、成功率: 最高

実装案:

try:
    execute_chain()
except MinorError:
    retry_with_wait()  # レベル1
except ChainError:
    repair_chain_step()  # レベル2
except MajorError:
    full_agentic_replanning()  # レベル3

5.2 成功パターンの自動コンパイル

ACT-Rのプロダクション・コンパイルを参考に、Agenticモードでの成功した修復シーケンスを新しいChainとして保存する機能を検討しています。

# 修復成功時
if self_repair_succeeded:
    new_chain = compile_from_trace(repair_log)
    save_chain(new_chain, context=current_task)
    # 次回から同じエラーには新Chainで対応

5.3 メタ認知的パラメータの動的調整

脳内ドーパミンレベルが探索と活用のバランスを調整するように、エラー率に応じて探索の「温度」を動的に調整するメタパラメータを導入:

# エラー率が高い → 探索を増やす
exploration_temp = base_temp * (1 + error_rate)

# エラー率が低い → Chainを優先
if error_rate < threshold:
    prefer_chain = True

5.4 Chainの選択的抑制(RIF)

認知心理学における「検索誘導性忘却(Retrieval-Induced Forgetting)」の知見から、失敗したChainを積極的に抑制する機能:

# 失敗したChainの信頼度を下げる
if chain_failed:
    reliability_scores[chain_id] *= decay_factor
    mark_as_bad_path(chain_id)

これにより、エージェントは過去の失敗(保続エラー)にとらわれず、新しい解を効率的に探索できます。


6. まとめ

6.1 理論と実践の統合

第1回の記事で提示したコンテキストエンジニアリングの設計思想、第2回で実証した定量的な性能改善、そして今回示した認知科学神経科学的な理論的基盤は、一本の線でつながっています。

アーキテクチャの設計方針:

  1. 生物学的な制御戦略の参照:脳における「習慣と熟慮の使い分け」を参考にした設計
  2. 計算論的なトレードオフの考慮:コストと柔軟性のバランスをベイズ的調停理論に基づいて実装
  3. 階層的な制御構造:低次の自動処理から高次の計画まで、段階的に対応

なお、本記事で示した脳領域とAIコンポーネントの対応関係は、あくまで設計の着想源としての概念的な対応です。機能局在主義的に特定の機能が特定の領域に厳密にマッピングされているという考えは支持していません。

6.2 実験結果との対応

第2回の実験結果は、これらの理論に基づく設計方針を支持するものとなっています:

設計方針 実験結果
Chainによる高速化 Method C: 26.3秒 vs A: 88.2秒(3.4倍)
決定的実行による安定性 Method C: σ=4.0秒 vs A: σ=25.9秒(1/6)
初回学習コストの償却 2-3回で損益分岐、年間$100以上削減
選択的な高コスト処理 Method C: $0.188/回 vs A: $1.034/回(1/5.5)

6.3 今後の展望

今後、認知科学神経科学の知見をさらに参考に、以下の方向で開発を進めていく予定です:

  1. エピソード記憶の活用:海馬的な経験の索引化と再利用
  2. メタ学習の導入前頭前皮質的な「学習の学習」
  3. 多Agent協調:脳の機能分化に倣った役割分担

また現在の開発状況では、ツールセットを事前定義してあるため、小さな問題空間向けの実装としては必要十分ですが、人の脳と比較すると陳述記憶との連携が不十分で、大きな問題空間におけるタスクでは課題が残ります。 大きな問題空間向けの実装として陳述記憶との連携強化を通し、直面したタスクに合わせて自身で問題空間を調整する仕組みを構築することを検討・検証しています。

6.4 終わりに

AI Agentの実装において、理論的裏付けのある設計は、単なる試行錯誤を超えた確実性と予測可能性を提供します。

認知科学神経科学の知見は、以下のような実践的な価値を提供します:

  • 設計判断の根拠:「なぜこのアーキテクチャなのか」を説明できる
  • デバッグの指針:どこが壊れているか、脳のモデルから推測できる
  • 拡張の方向性:次に実装すべき機能が見えてくる

スパイスコードでは、このような学術的な思想に基づいたAI Agent開発を推進しています。興味を持った方、一緒にチャレンジングな開発に取り組みたい方は、ぜひお話ししましょう!

https://corp.spicescode.co.jp/


主要引用文献

神経科学・認知神経科学

  1. Graybiel, A. M. (1998). The basal ganglia and chunking of action repertoires. Neurobiology of Learning and Memory.
  2. Jin, X., & Costa, R. M. (2010). Shaping action sequences in basal ganglia circuits. Current Opinion in Neurobiology.
  3. Anderson, J. R. (1993). Rules of the mind. Lawrence Erlbaum Associates.
  4. Taatgen, N. A., & Anderson, J. R. (2002). Production compilation: A simple mechanism to model complex skill acquisition. Human Factors.

強化学習・計算論的神経科学:

  1. Sutton, R. S., Precup, D., & Singh, S. (1999). Between MDPs and semi-MDPs: A framework for temporal abstraction in reinforcement learning. Artificial Intelligence.
  2. Botvinick, M. M. (2012). Hierarchical reinforcement learning and decision making. Current Opinion in Neurobiology.
  3. Botvinick, M. M., Niv, Y., & Barto, A. C. (2009). Hierarchically organized behavior and its neural foundations: A reinforcement-learning perspective. Cognition.

エラーモニタリング・認知制御:

  1. Botvinick, M. M., Cohen, J. D., & Carter, C. S. (2004). Conflict monitoring and anterior cingulate cortex: An update. Trends in Cognitive Sciences.
  2. Hayden, B. Y., et al. (2011). Surprise signals in anterior cingulate cortex: Neuronal encoding of unsigned reward prediction errors driving adjustment in behavior. Journal of Neuroscience.
  3. Shenhav, A., Botvinick, M. M., & Cohen, J. D. (2013). The expected value of control: An integrative theory of anterior cingulate cortex function. Neuron.

頭頂葉・小脳:

  1. Desmurget, M., et al. (1999). Role of the posterior parietal cortex in updating reaching movements to a visual target. Nature Neuroscience.
  2. Pisella, L., et al. (2000). An 'automatic pilot' for the hand in human posterior parietal cortex. Nature Neuroscience.

意思決定・調停メカニズム:

  1. Daw, N. D., Niv, Y., & Dayan, P. (2005). Uncertainty-based competition between prefrontal and dorsolateral striatal systems for behavioral control. Nature Neuroscience.
  2. Redish, A. D. (2016). Vicarious trial and error. Nature Reviews Neuroscience.
  3. Cisek, P. (2007). Cortical mechanisms of action selection: The affordance competition hypothesis. Philosophical Transactions of the Royal Society B.

検索誘導性忘却:

  1. Tempel, T., et al. (2013). Retrieval-induced forgetting in motor memory. Psychological Science.

関連記事


高階関数ツールを使ったAI Agent検証 - ブラウザ操作自動化タスクで3.4倍高速・コスト1/5を実現

スパイスコード CTO の櫻木です. 前回の記事では, スパイスコードでのAI Agent 開発におけるコンテキストエンジニアリングの考え方, 高階関数的なツール設計, 安全なコード実行, そして自己学習サイクルの重要性を紹介しました. 今回はその延長として, 実際のブラウザ操作タスクを題材に, その効果を検証したアウトプットイメージを共有したいと思います.


1. はじめに

前回の記事: tech-blog.localmet.com

前回の記事では, AI Agent開発における

  • コンテキストエンジニアリングの重要性
  • 高階関数的なツール設計とコード実行によるアプローチ
  • Artifact IDによる参照
  • 自己修復による継続的改善

を紹介しました. 今回はその設計思想を実際のブラウザ業務自動化タスクに適用し, ウォームアップ+90回の試行を通じて3つの実行方式を定量的に比較した実験結果を報告します.

実験のポイントは毎回LLMがUIを探索するのではなく, 初回に操作手順を学習し, 以降は決定的に実行する仕組みが, 実運用でどれだけ効果を発揮するかです.

1.1 実験の目的

  • ブラウザ操作タスクにおける 3 方式の性能比較
  • 成果物の回収精度 (欠損・重複なし) の検証
  • 操作ログを再利用したチェーン再生の有効性評価
  • tool chain toolの設計が, 実運用でどれだけ効くかの実証

1.2 概要

前回記事で紹介したコンテキストエンジニアリングの設計思想を, 実際のブラウザ業務自動化タスクに適用し, 3つの実行方式を比較しました.

比較した3方式:

  • Method A (Baseline): 毎回UIを探索する従来方式
  • Method B (Workflow): 操作ログから内製CDPツールのワークフローを生成し, 再生
  • Method C (Chain): 操作ログからplaywrightコードを生成し, 前回記事で紹介したtool chain toolで再生

実験結果 - Method Cが最も優れた性能を示しました

  • 速度: Method Aと比較して3.4倍高速(88.2秒 → 26.3秒)
  • コスト: Method Aと比較して約1/5.5($1.034/回 → $0.188/回)
  • 安定性: 標準偏差4.0秒と最も小さく、変動係数15.3%で予測可能性が高い

主要な示唆:

  • 「探索」と「実行」の分離により、LLMの推論能力を判断に集中させ、実行は決定的な機構に任せることで高速・低コスト・安定を実現
  • 初回に操作手順を学習すれば、以降は機械的に実行可能(学習への投資として正当化)
  • 複雑なサイトほど連鎖的実行のメリットが大きい(Site B: 113秒 → 31.5秒)
  • 安定的なワークフロー実行とエージェントによる柔軟性の担保の良いとこどり

2. 実験の全体設計

2.1 対象タスク

  • 対象期間の発注書や証憑をブラウザ経由でダウンロードする業務を想定
  • 欠損や重複がない状態 (MECE) で成果物を取得することがゴール

2.2 比較する 3 方式

  • Method A (Baseline): 毎回UIを探索し操作を逐次実行する従来方式
  • Method B (Workflow): 操作ログから内製CDPツールのワークフローを生成し, 再生
  • Method C (Chain): 操作ログからplaywrightコードを生成し, 前回記事で紹介したtool chain toolを使って再生

※ 方式BとCは思想としては近く, 実装ランタイムの違いが主な差分です.

methods

2.3 試行条件

  • 各方式 × 3サイト × 10回の試行
  • 合計試行数: 90回(各方式30回ずつ)
  • 収集する指標: 実行時間, LLMコスト, 成功率, 実行の安定性(標準偏差
  • 使用LLMモデル: anthropic.claude-sonnet-4-20250514-v1:0 (Claude Sonnet 4.5)

全ての試行は同一のタスク「指定月の発注書を全てダウンロード」を入力プロンプトとし,各サイトの特性(ページ構造,認証方式,ダウンロードフロー)が異なる環境で評価しています.

重要な前提条件:

  • Method A: 毎回ゼロからUI探索を実行(学習なし)
  • Method B・C: 事前に初回実行と自己修復によってワークフロー/チェーンが確立された状態での実行を評価

つまり,Method BとCの実験結果は「既に学習済みの手順を再生する性能」を測定したものです.初回実行や自己修復のコストは別途5.4節で補足データとして記載しています.


3. エージェントの設計思想

前回の記事で紹介した「コンテキストエンジニアリング」の考え方は, 今回の実験でも中心的な役割を果たします.

  • 入出力を最小化し, 大量データを LLM に流し込まない
  • 中間結果は外部成果物として保存し, 参照は ID のみ
  • エージェントが複雑な処理を直接抱え込まず, ツールの連鎖で解決する

この設計により, 長い UI 操作や大量の成果物処理でも, LLM の負荷と失敗率を抑制を期待します.

context_compression_avoidance


4. エージェントとツールの概要

4.1 共通ツール

  • デスクトップ共有ツール: waylandスタックで構成される仮想ディスプレイをnovncを利用することでエージェントが見る画面をユーザに共有する機能
  • Artifact系ツール: LLMに大量データを渡さず,IDのみで参照する機能の提供. コンテキスト圧縮ツール
  • ログイン情報取得ツール: ログイン用のid,passwordなどを安全に扱うためのツール
  • 2要素認証対応ツール: totpやメールでの2段階認証を解くためのツール

4.2 3種の方式

4.2.1 MethodA

  • 役割: UIを毎回探索して操作を実行
  • 主要ツール:
    • Playwright MCPツール群(ブラウザ操作の基本)
  • 特徴: ReActパターンで毎回LLMが推論しながらツールを選択・実行

4.2.2 MethodB

  • 役割: ワークフロー(Blueprint)を管理・実行
  • 主要ツール:
    • 既存ワークフロー取得ツール
    • 内製CDPワークフロー実行ツール
    • 操作ログ解析ツール
    • ログからワークフロー生成・保存を行うツール
  • サブエージェント
    • 失敗時のフォールバック用エージェント(探索的再実行)
    • ワークフロー修復エージェント
  • 特徴: 決定的な操作シーケンスをJSON形式で保存・再生

4.2.3 MethodC

  • 役割: browser_run_codeを含む高階関数連鎖をtool chain toolを使い実行
  • 主要ツール:
    • tool chain tool(探索モードでの操作収集も兼ねる)
    • 操作ログ解析ツール
    • Chainの取得・保存などを行う管理ツール
    • Playwright MCPツール群(探索モード用)
  • サブエージェント
    • 解析された操作ログからtool chain toolへのinputを生成するエージェント
    • tool chain修復エージェント
  • 特徴: playwright-mcpbrowser_run_code を呼び出す高階関数としてtool chain toolを利用. 探索モードではplaywright-mcpの通常ツールで操作収集を行う

Method CにおけるAgent-Tool連携の典型的なフロー:

  1. 初回実行(探索フェーズ)

    • BrowserChainAgent: Chain実行ツール呼び出し
    • 既存Chainなし → playwright-mcpで操作を実行・ログ収集
    • 操作ログを解析しサブエージェントへartifact_idを渡す
    • サブエージェントが browser_run_code呼び出しを含む高階関数連鎖を生成(Artifact化)
    • Chain保存: ArtifactをChainとして保存
  2. 2回目以降(実行フェーズ)

    • BrowserChainAgent: Chain実行ツール呼び出し
    • 既存Chain取得 → tool chain toolで直接実行
    • LLMの推論は最小限(「このChainを実行」のみ)
  3. 失敗時(自己修復フェーズ)

    • Chain実行失敗 → サブエージェントに修復依頼
    • 修復用のエージェントがステップバイステップで操作を実行し、エラーを元にchainの修復を実施
    • 新しいChainを生成・保存

ブラウザ操作タスクでは, 様々な外的要因により, 決定的な実行が毎回成功する保証はありません. その要因がサイト側のUI変更であるのか, 一時的な障害起因であるのか, はたまたネットワーク障害要因なのか, 自律的に検証・修復を実施できることでLLMの柔軟性と決定的な実行の高速性・安定性を両立しようという試みです.

4.3 特徴的なツール

4.3.1 高階関数的なツール

  • ワークフローJSONを引数に取り,CDP経由で実行するツール (MethodB)
  • playwright-mcpbrowser_run_code: playwrightコードを引数に取り,Playwright操作を実行 (MethodC)
  • playwright-codeを含んだ「操作手順」を引数として受け取るメタツール (MethodC)

4.3.2 自己修復ツール

  • ワークフロー失敗時に差分修正するツール
  • ワークフローが使えない場合に探索的実行に切り替えるツール
  • UI変更への自動対応を実現

5. 実験結果

5.1 実行時間の比較

5.1.1 エージェント別の比較

全90回の試行から得られた実行時間の統計は以下の通りです.

方式 平均 中央値 最小 最大 標準偏差
A (Baseline) 88.2秒 78.8秒 54.9秒 172.6秒 25.9秒
B (Workflow) 40.2秒 37.2秒 33.8秒 54.5秒 5.4秒
C (Chain) 26.3秒 24.2秒 21.5秒 33.1秒 4.0秒

performance_summary

主要な結果:

  • Method Cは Method Aと比較して3.4倍高速(88.2秒 → 26.3秒)
  • Method Bは Method Aと比較して2.2倍高速(88.2秒 → 40.2秒)
  • Method Cは最も安定しており,標準偏差はMethod Aの約1/6(25.9秒 → 4.0秒)

5.1.2 サイト別の内訳

各サイトの特性により,実行時間には顕著な違いが見られました.

サイト Method A Method B Method C
Site A 78.4秒 37.6秒 23.3秒
Site B 112.8秒 47.0秒 31.5秒
Site C 73.4秒 36.1秒 24.1秒

site_breakdown

Site Bは全方式で実行時間が長い傾向にあり,これはページ構造の複雑さや待機時間の影響と考えられます.一方で,Method CはSite Bでも31.5秒と,Method AのSite A/C(最速サイト)よりも高速です.

5.1.3 個別試行のばらつき

各試行の実行時間とコストの関係を散布図で可視化しました.

scatter

Method Aは試行ごとのばらつきが大きく,特にSite Bでは54秒から173秒まで約3倍の差があります.これは,LLMが毎回UIを探索するため,推論経路が安定しないことが原因です.

一方,Method BとCは初回にワークフロー/チェーンを生成した後は決定的な実行が可能なため,ばらつきが小さく安定しています.

5.2 LLMコストの比較

5.2.1 エージェント別の比較

各方式のLLM利用コスト(USD)を比較しました.

方式 平均コスト/回 総コスト(30回) Aとの比率
A (Baseline) $1.034 $31.02 1.0x
B (Workflow) $0.262 $7.87 0.25x(1/4
C (Chain) $0.188 $5.63 0.18x(1/5.5

cost_comparison

Method Cは Method Aと比較してコストが約1/5.5と圧倒的に経済的です.これは,チェーン実行時にはLLMの推論が最小限で済むためです.

5.2.2 時間とコスト

time_cost_tradeoff

この散布図から,Method Cが「高速かつ低コスト」の理想的な領域に位置していることが分かります.Method Aは全ての試行が右上(遅くて高コスト)に分布しています.

5.3 成功率と安定性

成功率(全30回中の成功数):

  • Method A: 96.7%(29/30)
  • Method B: 100%(30/30)
  • Method C: 100%(30/30)

Method BとCは全試行で成功しました.Method Aは1回の失敗があり,実行時間が54.9秒となり,早期に処理が終了しました.これは,毎回UIを探索する方式特有の不安定性を示しています.

一方,Method BとCは既に確立された手順を実行するため,より高い信頼性を示しました.

注意: 今回の実験は各方式30回の試行であり,統計的に十分な回数とは言えません.特にMethod BとCの100%成功率は,より多くの試行を重ねることで変動する可能性があります.本結果は3方式の傾向を示すものとして解釈してください.

実行時間の安定性(標準偏差):

stability_comparison

方式 標準偏差 変動係数(CV)
A (Baseline) 25.9秒 29.4%
B (Workflow) 5.4秒 13.4%
C (Chain) 4.0秒 15.3%

Method Cは標準偏差が4.0秒と最も小さく,実行時間の予測可能性が高いことを示しています.変動係数(標準偏差/平均)で見ると,Method Aは約30%のばらつきがあるのに対し,Method BとCは約13-15%と安定しています.

5.4 初回実行と自己修復のコスト(ウォームアップ)

Method BとCには,初回実行時にワークフロー/チェーンを生成する「探索フェーズ」と, 生成されたものが失敗した場合に修復する「自己修復フェーズ」があります.これらのコストを参考値として記載します.
共に今回のウォームアップでは初回実行 -> ログからワークフロー/チェーンを生成 -> 失敗 -> 自己修復 -> 完了の流れを観測しました.

Method B (Workflow)

サイト 初回実行 自己修復
Site A $0.54, 58秒 $1.75, 428秒
Site B $0.94, 102秒 $0.65, 72秒
Site C $0.62, 64秒 $1.44, 167秒

Method C (Chain)

サイト 初回実行 自己修復
Site A $1.45, 129秒 $0.70, 68秒
Site B $1.74, 164秒 $0.30, 42秒
Site C $1.91, 155秒 $1.09, 107秒

考察:

  • 初回実行のコストは$0.54〜$1.91と幅があるが,一度チェーン/ワークフローを生成すれば,以降は$0.19〜$0.26の低コストで実行可能
  • 自己修復が必要な場合でも,多くのケースで初回よりも短時間・低コストで修復できている
  • これは,操作ログから学習する仕組みが有効に機能していることを示す

6. 解説

実験結果から,Method BとCがMethod Aを大きく上回る性能を示しました.以下,技術的な観点から各方式の差異をより詳しく解説します.

6.1 コンテキスト効率の違い

6.1.2 Method A(逐次探索型)の課題

Method Aは毎回LLMがUIを探索するため,以下のコンテキスト消費が発生します:

  1. ページ全体のスナップショット: 各ステップでDOMやスクリーンショットを解析
  2. 要素の探索と推論: どのボタンをクリックすべきか,どのフィールドに入力すべきかを毎回推論
  3. エラーリカバリ: UI要素が見つからない場合の再試行ループ

これらが積み重なり,1回の実行で平均35,000トークン程度を消費しました(実測値).結果として:

  • 実行時間が長い: LLMの推論時間が支配的
  • コストが高い: トークン消費量に比例してコストが増大
  • 不安定: 推論経路が毎回異なるため,実行時間にばらつきが生じる

6.1.3 Method BとC(再生型)の優位性

一方,Method BとCは初回と失敗した場合のみ探索し,その結果を決定的な手順として保存します:

  1. 初回: UIを探索して操作ログを収集(コスト高・時間長)
  2. 連鎖生成: ログからワークフローJSON(Method B)またはbrowser_run_code呼び出しを含む高階関数連鎖(Method C)を生成
  3. 2回目以降: 生成された手順を機械的に実行(コスト低・時間短)

2回目以降は,LLMの推論がほぼ不要で,確立された手順を直接実行するため:

  • トークン消費は約5,000〜8,000程度(約1/5)
  • 実行時間は決定的な処理のみなので安定
  • コストは劇的に削減

speed_comp

6.2 標準偏差から見る安定性の本質

Method Aの標準偏差25.9秒(変動係数29.4%)という値は,業務自動化において致命的です.なぜなら:

  • スケジューリング困難: 実行時間が予測できないため,バッチ処理の計画が立てられない
  • SLA違反リスク: 最悪ケースで172秒かかる可能性があり,タイムアウトリスクが高い
  • リソース確保の困難: ピーク時のリソースに合わせる必要があり,コスト効率が悪化

Method CとBの標準偏差4.0秒・5.4秒(変動係数13-15%)は,安定した業務運用が可能なレベルです. なんらかの業務を柔軟性を担保したLLMを用いて自動化したいとき, 実際に人がやる場合と比べてどれぐらい安く済むのかは非常に重要になってきます.

6.3 初回コストの償却可能性

Method BとCの初回実行コストは$0.54〜$1.91と,Method Aの平均$1.03より高い場合もあります.しかし:

  • 2回目以降: $0.19〜$0.26で実行可能
  • 損益分岐点: 約2〜3回の実行で初回コストを回収
  • 月次運用: 毎月10回実行する場合,年間で約$100以上のコスト削減

業務の反復頻度を考えると,Method BとCの初回投資は十分に正当化されます.

6.4 なぜMethod CはMethod Bより速いのか

Method CとBの平均実行時間を比較すると,Cが約35%高速です(26.3秒 vs 40.2秒).この差の要因は:

  • 実装ランタイムの違い
  • 実行の最適化度(タイムアウトなど)
  • 補助ツールの利用

により生まれており, 工夫次第で大差ないものになると考えています.

6.5 前回記事で紹介したコンテキストエンジニアリングとの関連

前回の記事で紹介した「高階関数的なツール設計」と「コンテキスト圧迫の回避」が,今回の実験結果で実証されました.

高階関数的なツール設計:

  • playwright-mcpbrowser_run_code は「playwrightコードを引数に取り,ブラウザ操作を実行する」高階関数
  • 更にMethod Cの連鎖は,複数のbrowser_run_code呼び出しを含む高階関数として構成される
  • 中間結果はartifact IDとして保存され,LLMのコンテキストに載らない

コンテキスト圧迫の回避:

  • 操作ログ(数万トークン)→ Chain ID(数トークン)に圧縮
  • LLMは「このChainを実行する」という判断のみを処理
  • 実際の実行はLLMの外で,高階関数実行エンジンがbrowser_run_codeを順次呼び出す

これにより,Method CはLLMの能力を「判断」に集中させ,「実行」は決定的な機構に任せることで,高速・低コスト・安定を実現しています.


7. 今回の実験で得られた示唆

7.1 「探索」と「実行」の分離が鍵

今回の実験で最も重要な示唆は,探索フェーズと実行フェーズを分離することの有効性です.

従来のアプローチ(Method A)は,毎回「探索しながら実行する」ため,コストと時間がかかります.一方,Method BとCは:

  1. 初回: 探索に集中し,決定的な手順を抽出
  2. 2回目以降: 抽出した手順を機械的に再生

この分離により,LLMの「柔軟な推論能力」と「決定的な実行の高速性」を両立できます.

7.2 コード連鎖生成は「学習」の一形態

Method BとCの連鎖生成は,実質的にAI Agentが業務手順を学習していると言えます.

  • 人間が初めて業務を行う際も,最初は試行錯誤しながら手順を理解します
  • 2回目以降は,覚えた手順を素早く実行できます
  • AI Agentも同様に,初回の「学習コスト」を払えば,以降は効率的に実行できる

この視点で見ると,初回実行の$0.54〜$1.91というコストは「学習への投資」であり,十分にROIが見込めます.

7.3 エージェント連携の実証

前回の記事で紹介したtool chain toolが,実運用レベルで機能することが実証されました. 更にメインエージェントと各サブエージェントが明確な役割を持ち,成果物をIDで引き渡すことで,全体として複雑な業務を自動化できています.

7.4 自己修復の重要性

実験データから,自己修復フェーズのコストは初回実行より低い傾向が見られました(例: Site B Chain で$1.74 → $0.30).

これは,Healer Agentが:

  • 失敗の原因を特定
  • 最小限の修正で対応
  • 全体を再生成せず,部分修正で済ませる

という賢い動作をしていることを示します.この自己修復能力により,UI変更などの環境変化にも柔軟に対応できます.


8. 今後の展開

今回の実験で得られた知見をもとに,以下の方向で開発を進めていきます.

8.1 自動メンテナンス

現在は初回実行と自己修復で手動的に連鎖を更新していますが,今後は:

  • UI変更の自動検知: 定期実行で失敗パターンを検知
  • 差分修復: 全体を再生成せず,変更箇所のみを更新するようにプロンプト
  • バージョン管理の有効活用: 保持している業務フローの履歴をエージェントが活用できるように

これにより,Webサイトの仕様変更にも自動で追従できる仕組みを目指します.

8.2 連鎖の横展開と再利用

類似した業務間で連鎖を再利用できれば,初回実行コストをさらに削減できます:

  • パターンライブラリ: 「ログイン→検索→ダウンロード」などの汎用パターンを抽出
  • テンプレート化: サイト固有の部分だけをパラメータ化
  • 転移学習的なアプローチ: Site Aで学習した連鎖をSite Bに適用

これにより,新しいサイトへの対応時間を大幅に短縮できます.

8.3 他の業務領域への展開

今回はブラウザ操作に焦点を当てましたが,同様のアプローチは他の領域にも適用可能です:

  • データ抽出・変換: 複雑なExcel処理やPDF解析の手順を連鎖として定式化
  • API連携: 複数サービス間のデータ連携フローを連鎖として定式化
  • レポート生成: データ収集→分析→可視化の一連の流れを連鎖として定式化

前回の記事で紹介した「コード実行」と組み合わせることで,より幅広い業務を自動化できます.

8.4 知識の蓄積と活用

実行ログと連鎖を蓄積することで,組織全体の「業務知識ベース」を構築できます:

  • ベストプラクティスの抽出: 成功率の高い連鎖パターンを分析
  • Knowledge化: 前回記事で紹介したElasticsearch索引を活用し,類似タスクに推薦
  • LLM as a Judgeによる評価: 連鎖の品質を自動評価し,改善提案

これにより,AIエージェントが「使うほど賢くなる」システムを実現します.


9. おわりに

今回の実験では,90回の試行を通じて,ブラウザ操作自動化タスクにおける3つのアプローチを定量的に比較しました.

主要な成果:

  • Method Cは Method Aと比較して3.4倍高速,コスト1/5.5を達成
  • 標準偏差4.0秒という高い安定性で,業務運用に耐える信頼性を実証
  • 初回の「学習コスト」を払えば,以降は決定的な実行が可能
  • 複雑なサイトほど連鎖的実行の効果が大きい

前回の記事で紹介した「コンテキストエンジニアリング」の考え方が,実験結果として明確に裏付けられました.特に:

  1. 高階関数的なツール設計: 連鎖をartifact IDで管理し,LLMのコンテキストを圧迫しない
  2. 探索と実行の分離: LLMの推論能力を「判断」に集中させ,「実行」は決定的な機構に任せる
  3. エージェント連携: 複数エージェントの協調により,複雑な業務を段階的に処理

これらの設計思想が組み合わさることで,AI Agentを実運用レベルに引き上げることができます.

実験を通じて:

  • AIは「毎回考える」必要はない.一度学習した手順は機械的に実行すべき
  • 複雑さは敵ではなく,むしろ連鎖的実行のメリットを最大化する要因
  • 初回コストは投資であり,反復業務では確実にROIが見込める

今後も,実験結果を蓄積しながら,より実用的なAI Agent開発のノウハウを発信していきます.

スパイスコードでは,このような AI を使ったチャレンジングな機能開発に取り組んでいます.興味を持った方は,ぜひお話ししましょう!

https://corp.spicescode.co.jp/


参考 (前回の記事)

tech-blog.localmet.com

高階関数によるAI Agentのコンテキストエンジニアリング

スパイスコード CTO の櫻木です. スパイスコードは,「ロカルメ・オーダー」

order.localmet.com

という AI Agent を内包した ERP サービスを開発・提供しているスタートアップです. 本記事では我々の AI Agent 開発におけるコンテキストエンジニアリングに関する取り組みを紹介します.

1 コンテキストエンジニアリングの重要性

AI Agentの作成において「コンテキストエンジニアリング」が重要であることは以前より周知されています. blog.langchain.com

以前は人間がLLMへ直接プロンプトを与えていたため「プロンプトエンジニアリング」に意識が向いていました. しかし,AI Agentは人の手がほとんど介在しないまま自律的に推論と実行を繰り返します. そのため単なるプロンプトエンジニアリングだけでなく,「エージェントが参照するコンテキストをどう設計するか」が決定的に重要になります. コンテキストエンジニアリングでは必要十分な情報だけを安全に供給することにより

  1. LLM の推論力を最大限引き出す
  2. LLM が抱える入力長制約を回避する
  3. “Lost in the Middle”問題を回避する

ことを目的とします. この視点がなければ,エージェントは複雑な業務フローの途中で意図せぬ結果に陥りがちです. 本記事ではこのコンテキストエンジニアリングに対するスパイスコードでの取り組みをロカルメオーダーに内包している電子メール注文書受領Agentとデータ抽出 Agentの例を使って紹介します.

2 tool利用によるコンテキスト圧迫問題

我々が提供しているAI Agentは以下のようなツールを使うことができます

  • 自前のmcpサーバ経由でユーザに代わりロカルメオーダー上のデータを操作・抽出
  • お客様の代わりに電子メールの確認・操作(注文書のダウンロード・アップロード)

これらのツールで課題になるのが目的を達成するために使うツールの入出力によるコンテキストの圧迫です. 以下の例のように

  1. ツールの入出力のデータ量が大きい場合
  2. 繰り返し処理が生じる場合

それぞれでコンテキストの圧迫が発生することは想像に難くないと思います.

例1

特定の店舗にある在庫の平均原価額取得

TOOL CALL: localmet_mcp.get_shop(query: "shopA")
    returns shopA

TOOL CALL: localmet_mcp.get_stocks(shopId: shopA.id)
    returns 10000 rows stock info -> ❌

TOOL CALL: average_cost_by_sku(stocks: 10000 rows stock info) -> ❌
    returns 1000 rows averaged stock info -> ❌

例2

特定期間における電子メールから注文書を抽出, 一部のメールではいわゆるPPAPが利用されている

TOOL CALL: get_emails(from: 'YYYYMMDD', to: 'YYYYMMDD')
    returns 1000 emails -> ❌

以下対象全てに対して実行 -> ❌
TOOL CALL: evaluate_order_email(id: 'email1')
    returns {
        is_order_related,
        urls,
        password_candidates,
        attachments
    }

TOOL CALL: handle_file(attachmentId: 'attachment1', passwordCandidates: tooManyCandidates) -> ❌

TOOL CALL: handle_url(url 'example.com', passwordCandidates: tooManyCandidates) -> ❌

3 高階関数, コード実行によるアプローチ

上記のような問題に対して我々は大きく分けて2つのアプローチを用いて対策しています. 現在それぞれ独立した機構として設計しユースケースに応じて使い分けていますが全てを統合したアプローチも検討中です. 重要な点はどちらも高階関数ツールを用意し,中間処理をコンテキストに載せないことです. 更に最終結果に関してもartifactとして保存し, idのみを返すことで次に実行するchainに再利用したり, サマリのみをユーザに提供することができます.

3.1 tool chain tool

mcpツール含め, ツール群を全てchain toolを経由して使用させることで無駄な中間ツールの出力を削減した上で最終的な結果はartifactとして保存しidのみ返す

例1

Tool Input

{
    context: "shopAある在庫の平均原価額取得"
    purpose: "shopAの存在確認をした上で全在庫を取得しskuごとに平均コストを算出する"
    tool_names: ["mcp_get_shop", "mcp_get_stocks", "average_cost_by_sku"]
    each_args: {
        "mcp_get_shop": { "query": "shopA"},
        "mcp_get_stocks": { "shopId": "get_shop.id"},
        "average_cost_by_sku": { "stocks": "get_stocks.result" },
    },
    expected_result: "skuごとの平均在庫金額リスト"
}

Tool Output

{
    "artifactId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

例2

こちらはより内部状態の管理を明確にしたもの,artifactとして保存されるのは最終的結果に加えてプロセス全体の最終状態なども含める

Tool Input

{
    "initial_state": {
        "purpose": "YYYYMMDDからYYYYMMDDまでのメールから注文書googleDriveへアップロード",
        "password_candidates_all": []
    },
    {
        "steps": [
            {
                "tool_name": "mailbox_message_search_tool",
                "arguments": {
                    "after": "2025/11/01",
                    "before": "2025/12/31"
                },
                "result_key": "search"
            },
            {
                "items_key": ".search.messages",
                "item_alias": "message",
                "body": [
                    {
                        "tool_name": "mailbox_body_extractor_tool",
                        "arguments": {
                            "subject": ".message.subject",
                            "body": ".message.snippet"
                        },
                        "result_key": "body_collect"
                    },
                    {
                        "predicate": ".body_collect.password_candidates",
                        "body": [
                            {
                                "operation": "extend",
                                "target_key": "password_candidates_all",
                                "value_from": ".body_collect.password_candidates"
                            }
                        ]
                    }
                ]
            },
            {
                "items_key": ".search.messages",
                "item_alias": "message",
                "body": [
                    // 1件づつに対する処理
                ]
            }
        ]
    }
}

Tool Output

{
    "artifactId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

3.2 コード実行

tech-blog.localmet.com で紹介しているような安全な実行環境においてコード実行し, 最終的な結果はartifactとして保存しidのみ返す. こちらはまだ実験段階ではありますがDSLよりAI Agentにとって明瞭で強力なツールになると考えています.

Tool Input

def exec():
    shop = mcp_get_shop("shopA")
    stocks = mcp_get_stocks(shop.id)
    return average_cost_by_sku(stocks)

Tool Output

{
    "artifactId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

4 自己学習サイクルによる継続的改善

我々は以下の3段階のフィードバックループを実装することにより複雑なDSL, コード生成の難しさを解決しています.

実行時の自己修復

Pydantic modelによるバリデーションに加え,実行可能性も評価します.エラー時は詳細なエラー情報をエージェントに返却し,自己修復を促します.

# 例: shopIdが存在しないケース
{
    "error": "ValidationError",
    "detail": "shopId 'invalid-id' not found",
    "suggestion": "Use mcp_search_shop first"
}

成功パターンのKnowledge化

成功した実行ログに対して:

  1. LLM as a Judge または人間が品質評価
  2. 高評価のパターンをElasticsearchに索引化
  3. タスクコンテキストでベクトル検索
  4. 類似パターンをSystem Promptに注入

学習曲線

  • 初回実行: 平均2-3回のvalidation失敗を経て成功
  • Knowledge化後: 同様のタスクはほぼ一発で成功
  • 運用数ヶ月: 頻出タスクの初回成功率が向上

この仕組みにより,エージェントは使うほど賢くなり, 懸念される可能性のあるJSON生成の不安定性も実運用では問題になりません.

┌─────────────────────────────────────────┐
│         初回実行 (Cold Start)            │
├─────────────────────────────────────────┤
│ LLM生成 → ❌ → 修正 → ❌ → 修正 → ✅     │
│              (平均2-3回)                 │
└─────────────────────────────────────────┘
                    ↓
         ┌──────────────────┐
         │  評価 + 索引化    │
         └──────────────────┘
                    ↓
┌─────────────────────────────────────────┐
│      2回目以降 (Warm Start)              │
├─────────────────────────────────────────┤
│ Knowledge検索 → LLM生成 → ✅            │
│              (ほぼ一発)                  │
└─────────────────────────────────────────┘

5 高階関数で表現していることのメリット

どのアプローチも,「処理定義(関数)を引数に取り,新しい複合処理(関数)を返す」高階関数として設計されています. これによってエージェントが逐次実行した場合と比較してコンテキストエンジニアリングの文脈で大きな強みがあります. それ以外にも以下のようなメリットがありました.

  • 宣言と実行の分離:エージェントは JSON 宣言を返すだけで,実動作に費やすトークンを削減.実行側は常に同じ検証ルールで評価するため,一貫性を確保.
  • 合成の安全性:chain tool は バリデーションや入出力の取り扱いを内部に閉じ込めているので,関数合成(ツール連鎖)時の型崩れや引数抜けをチェーン内で吸収可能
  • 秘匿情報の安全性:秘匿情報の受け渡しをchain内に閉じ込めることでLLMに対する入出力にそれらの情報が顕在化しない.
  • 知識の再利用:高階関数ツールへのInputとその結果をロギング -> LLM as a Judgeなどで評価 -> Knowledge として保存することで,同じ宣言を別エージェントが再評価したり,成果の出た構成をテンプレ化したりできる.
  • プロセスの階層化:テンプレ化したchain toolをchain toolで利用することで複雑なパターンを容易に表現
  • スケーリング: 並列実行可能な箇所が明確かつ処理機構は閉じているため,スケール時にコントロールが容易

6 今後の展望

  • Python サンドボックス応用:既存の sandbox を使って,chain tool が動的な Python タスクを compile/decompile できるモジュールを挟み,宣言の一部をコード化 → 検証 → 再宣言するハイブリッド実行を検討中.
  • コード実行との連携:Anthropic が提唱するような MCP ベースのコード実行環境とも親和性が高く,彼らが提唱するsearch_toolsと組み合わせることによってより効率的で安全な状態に拡張できる可能性が高い.
  • healerの構築, playwright-healerのように出力されたtool inputに対してより適切な構造に自律的に修正を促すエージェントとの協調

tech-blog.localmet.com www.anthropic.com

終わりに

スパイスコードでは現在積極的に採用を行なっています. この記事を読んでAIを使ったチャレンジングな機能を開発してみたいと思った方,興味を持った方はぜひお話ししましょう!

corp.spicescode.co.jp

引用

arxiv.org blog.langchain.com www.anthropic.com

コンパイラ技術を使用したAI Agentの安定性を向上させる仕組み

スパイスコード代表の中河です。 スパイスコードは、「ロカルメ・オーダー」

order.localmet.com

という AI Agent を内包した ERP サービスを開発・提供しているスタートアップです。
本ブログでは、私たちの AI Agent がどのような仕組みで動いているのか、そして他の Agent とは何が異なるのかについて、ご紹介していく予定です。
第 2 回目となる今回は、「コンパイラ技術を使用した AI Agent の安定性を向上させる仕組み」として、第 1 回目に続いて古の技術を用いた弊社の AI Agent の仕組みについて、その概要をご紹介します。
※ Sandbox 技術の続きはそのうち別記事として書く予定です

AIエージェントアーキテクチャ

TL;DR: ロカルメ・オーダーでは Automation RPA と呼ばれる RPA を内蔵しているのですが、同じく内蔵している AI Agent がそれらを構築・実行する機能を持っており、特に構築部分では少し特殊なアーキテクチャを採用しています。


1. なぜいま “コンパイラ技術” なのか

  • AI Agentをプロダクトに投入するためにはパフォーマンスの安定性が大きな壁となる。

  • AI Agentが確率的に出力した結果をコンパイラ技術を通じて、確定的な物へ変換する事が出来る。

  • コンパイラ技術を元にAI Agentにフォードバックを行い自己改善するループを構築できる。

Automation RPA

例えば上記のようなワークフローを弊社のAI Agentが構築する場合、いきなりワークフローのデータ構造を出力するのではなく

  1. Python コードの出力
  2. Python コードを中間コードへ変換
  3. 中間コードをAutomationの処理構造に変換

という処理を行なっており、コンパイラのフロントエンド・バックエンドのようなアーキテクチャになっています。


2. アーキテクチャと実装

コンパイラアーキテクチャ概要

2.1 Python コードの出力

AI Agentはドキュメントや人間からの自然言語での指示を入力として以下のテンプレートを元にprocess関数を実装したPythonコードを出力します

import copy
from typing import Any
from {evaluate_module} import ( # you must keep this line
    {evaluate_functions}
)
from {process_module} import ( # you must keep this line
    {process_functions}
)

def process(arg: Any) -> Any:
    target = copy.deepcopy(arg)
    # your code, should convert target object
    return target

# you should keep following code
target = {target}
print(process(target))
2.2 Python コードを中間コードへ変換

コンパイラ・フロントエンドは Python の ast モジュールを使用し、AI Agent が出力した Python コードを構文解析して S 式で記述された中間コードを生成します。 この段階で文法エラーや事前に定めた制約に出力コードが従っていない場合にはエラーを返し、AI Agent にフィードバックします。 また、S 式で設計された中間コードは様々な用途に応用可能な仕様になっています。

2.3 中間コードをAutomationの処理構造に変換

コンパイラ・バックエンドは S 式フォーマットの中間コードを Automation の処理構造に変換します。 Automation の処理構造は JSON で記述され、ロカルメ・オーダー本体で実行されます。

構築されたAutomation


3. プロダクトでの構成例

実際のプロダクトでは、今回紹介した AI Agent 機構は独自の Agent OS(仮称)の上で独立したマイクロサービスとして動作し、Automation の実行系などは Go で実装されたロカルメ・オーダー本体で実行されるようになっています。


4. まとめと展望

  • 本手法のメリット: コンパイラ技術を使用して、ある程度 AI Agent の安定性を担保できる
  • 課題: 相変わらず実装が複雑で運用が大変
  • 次の一手: 今回はコンパイラ部分のみにフォーカスしてご紹介しました。そのうちアーキテクチャ図には記載したもののご紹介していなかった逆コンパイラ部分の仕組みもご紹介したいと思います。こちらはいわゆる human‑in‑the‑loop を実現する部分で、少し? 特殊な実装になっています ※ 他のコンテンツとの兼ね合いで、順番が前後する可能性があります ;-)

参考文献