はじめに
こんにちは。スパイスコード代表の中河です。今日は弊社の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エージェントの技術領域は急速に変化しています。各レイヤーを疎結合に保ち、ミドルウェアをいつでもより優れた選択肢に入れ替え可能にすることで、特定の技術への依存を最小限に抑え、変化に柔軟に対応できる設計としています。