はじめに
本記事で扱う「AIエージェント」とは、単にユーザーの質問にテキストで答えるチャットボットではありません。
「ツール(API)を使って、外部システムに自律的に関与し、実際に行動を行うもの」 を指します。
例えば、
- ユーザーの代わりにチケットを調査し、
- データベースを検索し、
- 結果に応じて業務システムにデータを書き込み、
- Slackで通知を送る。
といった、一連の泥臭い実務を代行するシステムです。
現在、Dify や LangGraph といった「ノードを線で繋ぐワークフロー型」のツールが常識になりつつあります。しかし、これらを使ってプロダクションレベルのエージェントを組もうとすると、ほぼすべての開発者が同じ地獄に突き当たります。
- 「条件分岐を増やしていくうちに、巨大で硬直化したスパゲッティコードになる」
- 「プロンプトやモデルを少し弄っただけで、全体の連携がガラガラと崩壊する」
- 「2ステップ目の思考に入った瞬間、AIが急激に馬鹿になり、迷走を始める」
この記事では、なぜ従来のワークフロー型(直列フロー)設計が本質的に破綻するのか、そのメカニズムを暴きます。
And, その解法として最先端のAIエージェントフレームワーク 「Synapse」 が採用している、「State(状態)駆動設計」と「自律型ReActループのコード制御」 について、現場のリアルな知見を交えて徹底解説します。
1. ワークフロー型設計が内包する「限界」
従来の多くのエージェント開発は、人間が「分岐・検証・リトライ」のノードを静的に線で繋ぐ 「ワークフロー型設計」 です。
一見、確実でコントロールしやすいように見えますが、ここには本質的な限界があります。
何が起きるか:複雑性の指数関数的爆発
AI の判断ミスや例外処理をカバーしようと「検証 ➔ 差し戻し」のノードをワークフローに追加していくと、実行パスは指数関数的に複雑化します。
エラーや例外に対応するノードを1つ増やすたびに、条件分岐は倍増します。
最終的に、人間の認知の限界を超えた「誰も触れないスパゲッティ・グラフ」が完成します。
なぜ起きるか:正解前提フローの破綻
ワークフロー型の最大の問題は、**「前のノードの出力が正しいことを前提に進んでしまう」**点にあります。
AIの出力は「100%の正解」か「0%の誤り」かという単純なものではありません。「70%くらいは合っているが、細かいニュアンスが間違っている」という中途半端な出力が日常茶飯事です。
それにも関わらず、
[意図解釈] ➔ [検索] ➔ [評価] ➔ [回答生成]
と直列にパイプラインを繋いでしまうと、最初の解釈がわずかにズレただけで、後の処理はすべてその「ズレ」を前提に動いてしまいます。チェーンが長くなるほど、このズレは雪だるま式に増幅し、最終的に目も当てられないハルシネーション(嘘)となって出力されます。
2. 単一エージェント設計で直面する「3つの壁」
自律的にツールを選択してループを回す「ReAct(Reasoning and Acting)」を実装しようとすると、今度は以下の問題にぶつかります。
壁①:ツール選択が安定しない
AIがその場のノリでツールを選んでしまい、毎回異なるルートを通ったり、全く関係のないツールを誤用し始めたりする。
壁②:1つ答えたら途中で処理を放棄する
いくつかのステップを踏んで調査すべきタスクであるにも関わらず、1つ目のツールの結果(例:「データが1件見つかりました」)が返ってきた時点で、「仕事が終わった」と勘違いして途中で回答を生成してしまう。
壁③:2ステップ目の崖(急激な知能低下)
1ターン目のツール実行は完璧だったのに、2ターン目に入った瞬間にAIが急に的外れな判断を始め、無限ループに陥るか、フリーズする。
これらの原因は、AIモデルの性能不足ではありません。
「AIエージェントの思考プロセスと記憶の構造設計」 が間違っているからです。
3. 問題の正体
原因①:初期思考が固定されていない
エージェントがツールを実行するたびに、毎回その場で、
- 「自分は今、何をやるべきか」
- 「ゴールはどこなのか」
- 「次に何をするべきか」
を確率的に再判断している状態です。
LLMは本質的に確率でトークンを出力するエンジンです。判断の機会を何度も与えれば与えるほど、ブレる確率は掛け算で跳ね上がります。
【初期思考がない場合の迷走】
➔ ターン1: 「ユーザー情報を取得した」
➔ ターン2: 「次に何をすべきだっけ? あ、そうだ、ログを検索しよう」 (ブレ発生)
➔ ターン3: 「データが取れたから、もう終わっていいか」 (中途半端な終了)
初期思考がコードとして固定されていない限り、AIエージェントを制御することは不可能です。
原因②:「生ログの山」による脳内コンテキストの溺死(2ステップ目の崖)
実戦でAIが2ステップ目以降に急激に馬鹿になる最大の原因がこれです。
多くのフレームワークは、AIが実行したツールの結果(数千行のJSON、生HTML、APIの生レスポンスなど)を、そのまま会話履歴(コンテキスト)に積み上げていきます。
【脳内デスクの散らかり(ログ積み上げ型)】
[ AIの脳内コンテキスト ]
┌────────────────────────────────────────────────────────────┐
│ ユーザー: 「最新のユーザーAのステータスを確認して」 │
│ AIの思考: 「まずはDBを検索しよう」 │
│ ツール結果: { id: 1, name: "A", status: "active", ... │
│ (数万文字のノイジーなDBログがそのまま積まれる)│
│ ... } │
│ AIの思考: 「えーっと、情報が多すぎて何を確認してたっけ…」 │
└────────────────────────────────────────────────────────────┘
情報過多の紙クズの山に埋もれたAIは、2ステップ目にして既に溺死しています。
「何を確認するために(目的)」「何を行って(行動)」「何が分かったか(事実)」という本質的な文脈が、巨大な生のログデータの中に埋没してしまうため、思考が完全に迷走するのです。
4. Synapseが提示する「状態駆動(State-centric)」アーキテクチャ
この地獄を解決するために、Synapse Frameworkが採用したのが**「ReActプロセスの強制分離」と「State(記憶)の完全整理」**です。
解決策①:認知プロセスの3段階分離と「初期思考の固定」
エージェントの思考ループを、以下の3つのフェーズに厳格に分離し、コード(システム側)で実行順序を強制します。
① 初期思考(意図・ゴール・タスクの定義)
│
▼
② 実行(定義したタスクに基づくツールの実行)
│
▼
③ 評価(実行結果が「ゴール」を満たしているかの自己レビュー)
AIに最初のステップで、以下の3つを一度に確定させ、**Local State(手元のメモ帳)**に書き込ませます。
- 意図: 「この質問は、ユーザーの何を解決しようとしているのか」
- ゴール(完了条件): 「どういう情報が揃えば、この仕事は完了と言えるのか」
- タスクリスト: 「完了までに必要な具体的な作業手順は何か」
そして、この初期思考(ゴールとタスクリスト)を手元のメモ帳にピン留めして固定します。
ツールの実行結果が戻ってくるたびに「次は何をしようか」と考えさせるのではなく、「固定されたタスクリストの消化」と「ゴールを満たしたか」という基準だけで評価と次のアクションを実行させます。
これにより、1つの情報が手に入っただけで勝手に仕事を投げ出す「中途半端な終了」は根底から絶滅します。
解決策②:「会話履歴」と「State(仕事の記憶)」の絶対的分離
Synapseでは、LLMに渡す文脈から「生ログ」を完全に排除します。
- 会話履歴 (History): ユーザーとのやり取り(口調や対話の文脈)だけを保持。
- State(確定した記憶): 整理整頓された進捗状況ボード。
ツールを実行して生データが返ってきたら、AIにその結果から**「確定した事実(facts)」と「次の追加タスク(tasks)」**というエッセンスだけを取り出させ、Stateに書き込ませます。そして、用済みの膨大な生データは、机の上の「紙クズ」として完全破棄します。
【生ログ完全破棄 & 知見抽出のプロセス】
[ 1. ツールを実行する ]
│ (数千行 of HTMLやJSONなどの、膨大でノイジーな「生データ」が返ってくる)
▼
[ 2. 評価・エッセンス抽出 ]
│ (AI自身が「この生データの中で、本当に必要な知見は何か?」を抜き出す)
├────────────────────────────────────────────┐
▼ (本当に必要なエッセンスだけ) ▼ (用済みの膨大な生データ)
[ 3. 手元のメモ帳 & 共有ボードを更新 ] [ 4. 机の上の「紙クズ」として完全破棄!]
- facts: 「ユーザーAはプレミアム会員である」 ※AIの脳内コンテキストから、
- tasks: 「ユーザーAのステータス確認 ➔ 完了」 ノイズになる生ログを完全に消し去る
│
▼
[ 次の思考ステップは、整理整頓されたクリーンなデスクから再スタート! ]
次のターンでAIが読むのは、数万行の生ログではなく、極限まで圧縮・構造化された「State」だけです。
デスクが常に片付いているため、2ステップ目、3ステップ目に入ってもAIの知能は全く低下せず、一貫した自律思考を維持できます。
解決策③:コールドスタートを防ぐ initialToolName と先制自律RAG
実戦でAIが最も的外れな計画(初期思考)を立てやすいのが、手元に前提知識が「何もない」状態の1ターン目です(コールドスタート問題)。
チケット対応をする際、「チケットID: T100」だけを渡されて「さあ計画を立てて」と言われても、AIはチケットのタイトルすら知りません。
Synapseは、この「迷う必要のない初手」をシステム側で強制実行する initialToolName を提供します。
【initialTool によるコールドスタート防止】
[ ユーザーの依頼 ] ➔ 「チケット T100 の対応方針を考えて」
│
▼ (AIが最初の計画を立てる前に...)
[ initialTool が自動で先制発火! ]
│ システムが裏側で自動で「fetch_ticket_details」を叩き、前提知識を先行取得
▼
[ エージェントの Local State(短期記憶)に、コンテキストが自動で補完される ]
│ 「チケット T100 は、ログイン不可に関する深刻度Highの問い合わせである」
▼
[ 完璧な前提知識を持った状態で、極めて精度の高い『初手の計画(タスクリスト)』を立案! ]
AIに「何も知らない状態」から当てずっぽうで計画を立てさせるのではなく、「前提知識を最初から持った状態」で最高のスタートを切らせる。この設計こそが、商用エージェントの初手の精度を劇的に向上させるための決定打となります。
5. TypeScript による実装例
Synapse Frameworkを使用し、この「State駆動」と「initialToolName」を組み合わせた型安全な自律エージェントの実装コードです。
import { Network, GeminiAdapter, AgentConfig, ToolDefinition } from "@synapse-agent/framework";
// 1. 推論エンジン(LLM)の初期化
const llm = new GeminiAdapter({
apiKey: process.env.GEMINI_API_KEY,
});
// 2. エージェントの定義(State駆動と初手ツールを強制)
const agents: AgentConfig[] = [{
name: "ticket_agent",
prompt: `
あなたは顧客サポートのスペシャリストです。
チケットの内容を確認し、社内マニュアルを参照して、適切な対応方針を決定してください。
`,
tools: ["fetch_ticket", "search_manual", "respond_to_customer"],
enableState: true, // 【重要】State駆動を有効化
initialToolName: "fetch_ticket" // 【重要】初手は必ずチケット取得を実行してコンテキストを作る
}];
// 3. ツールと「評価基準(evaluation)」のカプセル化
const tools: ToolDefinition[] = [
{
name: "fetch_ticket",
summary: "指定されたIDのチケット詳細を取得します。",
schema: {
args: [{ name: "ticketId", type: "STRING", required: true, desc: "チケットID" }]
},
// AI自身が実行結果をどう評価すべきかの契約
evaluation: "チケットが存在しない、または取得に失敗した場合は、エラーをStateに書き込み停止せよ。"
},
{
name: "search_manual",
summary: "社内マニュアルを検索します。",
schema: {
args: [{ name: "query", type: "STRING", required: true, desc: "検索クエリ" }]
},
evaluation: "検索結果が0件の場合は、検索ワードをより抽象的な表現に変えて再検索を試みよ。"
}
];
// 4. 実行ネットワークの構築
const network = new Network({
llm,
agents,
tools,
onToolCall: async (call, ctx) => {
console.log(`[System: ToolCall] Running ${call.name}...`);
if (call.name === "fetch_ticket") {
return {
ticketId: call.args.ticketId,
title: "ログイン画面でエラーコード 500 が発生する",
status: "OPEN",
userEmail: "user@example.com"
};
}
if (call.name === "search_manual") {
return {
articles: ["エラーコード500は、認証サーバーのタイムアウトが原因である可能性があります。セッションのクリアを案内してください。"]
};
}
}
});
// 5. 実行
await network.verifyLicense();
network.resetStates();
const result = await network.get("ticket_agent").chat({
ticketId: "T-100"
});
console.log("\n====== 最終回答 ======");
console.log(result.finalText);
console.log("\n====== 抽出された State (記憶) ======");
console.log(JSON.stringify(result.states, null, 2));
実行時に構築される「State」の遷移
このプログラムを実行すると、裏側でStateが以下のように極限まで整理されて遷移していきます。数万文字のノイズは一切含まれません。
{
"local": {
"goals": ["チケット T-100 の問題原因を特定し、顧客への案内文を作成する"],
"tasks": [
{ "id": 1, "desc": "チケット詳細の取得", "status": "COMPLETED" },
{ "id": 2, "desc": "エラーコード 500 に関するマニュアル検索", "status": "COMPLETED" },
{ "id": 3, "desc": "対応方針の策定と案内文の作成", "status": "IN_PROGRESS" }
]
},
"global": {
"facts": [
"チケット T-100 は、ログイン時のエラーコード 500 に関するトラブルである",
"マニュアルによると、エラーコード 500 の原因は認証サーバーのタイムアウトである",
"解決策として顧客にセッションのクリアを案内する必要がある"
],
"openQuestions": []
}
}
まとめ:AIエージェントの新たな標準設計へ
「プロンプトエンジニアリング」や「アドホックな有向グラフの構築」でAIの賢さに依存する開発は、もう終わりにしましょう。
エージェント自身に「解釈/計画 ➔ 実行 ➔ 評価」の自律した認知プロセス(State)を持たせ、それをコード(システム)で厳格に支配することこそが、AIエージェントを極限までシンプルに、そして無限にスケールさせるための唯一の答えです。
「Stateを持たないAI」は、単なるテキスト生成器に過ぎません。
「Stateを制御されたAI」こそが、最後まで仕事をやり遂げる真の「自律的人格」となり得るのです。
- GitHub Repository: https://github.com/masakiohta-wq/synapse-agent
-
npm パッケージ:
npm i @synapse-agent/framework