Microsoft Ship AI Agent Framework: 詳細解説と実装例
1. 概要
Microsoftが公式にリリース(GA – General Availability)した、AI Agentを構築・調整・運用するための統一的なフレームワークについて紹介します。これは以前の2つの製品、Semantic KernelとAutoGenを統合したものです。これは単なるプロダクトニュースではなく、LLMが「質問に答える」のではなく「自ら行動を決定する」システムの設計方法そのものを再定義しています。
本記事では、AI AgentがどのようにChatbotと異なるか、Microsoftが実装した具体的な内容、そして自分の手でJava 21 + Spring Boot 3 + Spring AI(Azure OpenAI統合)を使って最小限のagentを構築して、その内部メカニズムを理解します。MicrosoftのフレームワークはもともとLIBRARY.NETとPythonで動作しますが、アーキテクチャ的なパターンは普遍的です。
2. AI Agentとは何か?
通常のChatbotは質問を受け取り、LLMを1回呼び出し、答えを返します。Agentが異なる点は、思考-行動を複数回繰り返すことです。自らtool(API、データベース、ファイルなど)を呼び出すかどうかを判断し、最終的な答えを提供します。
| 特徴 | Chatbot | AI Agent |
|---|---|---|
| LLM呼び出し回数 | 1回/質問 | 複数回、自動繰り返し |
| 外部toolの使用 | 通常なし | あり、modelが自ら選択 |
| 状態管理 | ステートレスまたはチャット履歴保存 | メモリあり、チェックポイント可能 |
| レイテンシ | 低い | より高い(複数ラウンドトリップ) |
| 信頼性 | 制御しやすい | ガードレール、人間のループが必要 |
2.1. Reason–Act(ReAct)ループ
現在のほぼすべてのagentフレームワークが使用するコアメカニズムはReActです。modelが「考え」(Thought)、行動(Action)、つまりtoolの呼び出しを選択し、結果(Observation)を受け取り、十分な情報が得られるまで繰り返します(最終答:Final Answer)。
Thought: ユーザーが注文ORD-001のステータスを聞いている。確認する必要があります。
Action: lookupOrder("ORD-001")
Observation: 注文ORD-001:ステータスSHIPPED、合計450000ベトナムドン
Thought: 情報が十分です。
Final Answer: ご注文ORD-001は現在配送中です。合計は450,000ベトナムドンです。
これがMicrosoft Agent Framework(以下で使用するSpring AI)が自動化する部分です。手動でこのループを書く必要はなく、toolを宣言してsystem promptを設定するだけです。
3. Microsoftが「リリース」したAI Agentの内容
統合前、Microsoftには2つの開発の方向性がありました:
- Semantic Kernel: 本番環境向けSDK。Type-safe pluginを強調し、Enterprise統合(Azure、.NET)に重点を置き、安定したデプロイに適しています。
- AutoGen: 研究志向。複数agentが互いに「対話」して複雑なtaskを解決するマルチagent会話に強みがあります。
新しいフレームワークは両者の強みを統合し、主な機能は:
- 組み込みのOrchestrationパターン: sequential(agent AからBへ)、concurrent(複数agentが並列で実行し集約)、hand-off(agentが専門のagentにtaskを転送)、group chat(複数agentが答える前に協議)。
- Durable/stateful実行: agentは途中でチェックポイントを作成でき、プロセスクラッシュ時に再開可能です。長期task(数分から数時間)に重要です。
- 組み込みObservability: OpenTelemetryの標準に従うトレース。本番環境で各Thought/Action/Observationステップが見えます。
- 人間のループ: 機密性の高いアクション(払い戻し、データ削除)を実行する前にagentを一時停止して人の確認を待つことができます。
- Azure AI Foundry Agent Service: agentをデプロイするためのホスト型ランタイム。組み込みtoolカタログ(Bing検索、コードインタプリタ、ファイル取得)と、Model Context Protocol(MCP)をサポートしてベンダーロックなしで外部toolを接続できます。
元のフレームワークは.NET/Pythonで実行されますが、パターンは普遍的です。次のセクションでは、Javaでこのパターンを再構築して、コードレベルでそれがどのように機能するかを確認できます。
4. AI Agentのコアアーキテクチャ
最小限のagentには4つのコンポーネントが必要です: Planner(実はLLM)、Tool(agentが呼び出せる関数)、Memory(チャット履歴/tool結果)、Executor(調整ループ)。Spring AIは ChatClient を通じてExecutorとPlannerを既に組み込んでいます。Toolを宣言するだけです。
4.1. Maven依存関係
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-azure-openai-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>
Azure OpenAI接続の設定(MicrosoftのGPT サービス、Azure経由でデプロイ):
spring.ai.azure.openai.api-key=${AZURE_OPENAI_KEY}
spring.ai.azure.openai.endpoint=${AZURE_OPENAI_ENDPOINT}
spring.ai.azure.openai.chat.options.deployment-name=gpt-4o-mini
4.2. agentのためのToolを定義
Toolは通常のJavaメソッドで、@Tool でマークされているため、modelはそれを呼び出せることを知り、パラメータで呼び出す方法を知ります。
public record Order(String id, String status, BigDecimal total) {}
public interface OrderService {
Order findById(String orderId);
}
@Service
public class OrderTools {
private final OrderService orderService;
public OrderTools(OrderService orderService) {
this.orderService = orderService;
}
@Tool(description = "注文コードで注文ステータスと合計金額を照会")
public String lookupOrder(String orderId) {
Order order = orderService.findById(orderId);
return "注文%s:ステータス%s、合計%sベトナムドン"
.formatted(order.id(), order.status(), order.total());
}
}
@Tool の description はmodelが lookupOrder を呼び出すかどうかを決定するために読む内容です。明確で具体的な説明を書くと、agentはtoolをより正確に選択します。
4.3. ChatClient経由でagentが自動的にtoolを呼び出す
@Service
public class SupportAgentService {
private final ChatClient chatClient;
public SupportAgentService(ChatClient.Builder builder, OrderTools orderTools) {
this.chatClient = builder
.defaultSystem("""
あなたはオンラインストアのカスタマーサポートアシスタントです。
注文に関する質問の場合、lookupOrder tool を使用してください。
簡潔で親切な回答をベトナム語で提供してください。
""")
.defaultTools(orderTools)
.build();
}
public String handle(String userMessage) {
return chatClient.prompt()
.user(userMessage)
.call()
.content();
}
}
.defaultTools(orderTools) 行がtoolsetを登録します。ChatClient は内部的にReActループを自動実行します。promptを送信してmodel用のtoolリストを付与し、modelが lookupOrder 呼び出しをリクエストすると、Spring AIは対応するJavaメソッドを自動実行し、結果(Observation)をmodelに戻し、最終回答を受け取ります。ループを手動で書く必要がありません。これがMicrosoft Agent FrameworkとSpring AIが内部的に共通する部分です。
> handle("注文ORD-001はどこにありますか?")
ご注文ORD-001は現在配送中です(SHIPPED)、合計450,000ベトナムドンですね!
注意: modelはそれが「必要」と判断したときだけtoolを呼び出します。すべての質問がtoolをトリガーするわけではありません。ユーザーが「店舗は国際配送していますか?」と聞くと、modelは
lookupOrderを呼び出さずに直接回答します。
5. マルチエージェント: 1つのagentでは不十分な場合
Microsoftがリリースした顕著な機能の1つは hand-off です。複数の専門agent間で会話を転送します。小規模な問題の場合、シンプルなrouterで模擬できます。複雑なマルチagentフレームワークは不要です:
@Service
public class AgentRouter {
private final SupportAgentService orderAgent;
private final RefundAgentService refundAgent;
public AgentRouter(SupportAgentService orderAgent, RefundAgentService refundAgent) {
this.orderAgent = orderAgent;
this.refundAgent = refundAgent;
}
public String route(String userMessage) {
String lower = userMessage.toLowerCase();
if (lower.contains("払い戻し") || lower.contains("refund")) {
return refundAgent.handle(userMessage);
}
return orderAgent.handle(userMessage);
}
}
このrouterは最小限の「orchestrator」の役割を果たします。より大規模には、どのagentを処理するか選択すること自体をLLMに決めさせるべき(modelによるintent分類)です。hard-coded contains() は、intentが非常に小さく安定している場合のデモまたは手動実装にのみ適しています。
6. toolとagentのテスト
agentシステムで最もテストしやすいのは tool です。純粋なJavaメソッドなので、LLMに依存しません。toolは「agentの知能」の基盤なのでしっかりテストしてください。agentはtoolの品質と同等の知能しかありません。
class OrderToolsTest {
@Test
void shouldReturnOrderSummaryWithStatusAndTotal() {
OrderService fakeOrderService = orderId ->
new Order(orderId, "SHIPPED", new BigDecimal("450000"));
OrderTools tools = new OrderTools(fakeOrderService);
String result = tools.lookupOrder("ORD-001");
assertThat(result)
.contains("ORD-001")
.contains("SHIPPED")
.contains("450000");
}
}
OrderService は findById メソッド1つだけなので、mock frameworkを追加する必要がなく、lambdaでfake実装を作ります。このテストには十分でシンプルです。
class AgentRouterTest {
@Test
void shouldRouteRefundKeywordToRefundAgent() {
SupportAgentService orderAgent = mock(SupportAgentService.class);
RefundAgentService refundAgent = mock(RefundAgentService.class);
when(refundAgent.handle(anyString())).thenReturn("払い戻しリクエストを受け付けました");
AgentRouter router = new AgentRouter(orderAgent, refundAgent);
String result = router.route("注文ORD-002の払い戻しが必要です");
assertThat(result).isEqualTo("払い戻しリクエストを受け付けました");
verify(refundAgent).handle(anyString());
verify(orderAgent, never()).handle(anyString());
}
}
注意: unit testで「実際のLLMを呼び出すエンドツーエンドテスト」を書かないでください。結果は非決定的(modelは毎回異なる回答をする可能性がある)で、API呼び出しコストがかかり、CIが遅くflaky になります。上記のようにtool/routerをmockしてテストします。agent動作検証用に別途integration test(手動実行またはnightly)を用意してください。
7. よくあるエラーとagentを使うべきではない場合
- if-elseで解決できることにagentを使う: 行動選択ロジックが既知で固定(例:ORD-\d+ パターンなら常に注文を照会)なら、通常のコードの方が安い、速い、テストしやすいです。毎回LLMに「思考させる」よりもずっと有効です。
- 機密actionに対するガードレールを無視: agentはデータ削除、払い戻し、顧客メール送信toolを呼び出せます。人間による確認(human-in-the-loop)またはtool権限制限がないと、prompt injectionまたはmodelの推論エラーが実損害を引き起こします。
- ループ回数制限がない: modelが継続的に間違ったtoolを選んだり情報不足の場合、ReActループが無限に回り続け、token消費とコストが増加します。常に最大ステップと timeout を設定してください。
- Observabilityの不足: agentが間違った回答をするとき、デバッグするために全Thought/Action/Observation履歴を見られる必要があります。詳細なlog/traceがないと、modelが何を「考えて」エラーに至ったか追跡不可能です。
- レイテンシとコスト: ループの各ステップがLLM呼び出し1回です。単純な質問も2-3回のmodel呼び出しが必要です(各回数百msから数秒)。即座の応答が必要(例:200ms以下)なら、このタイプのagentは不向きです。
8. まとめ
MicrosoftがSemantic KernelとAutoGenを統一フレームワークに統合したことは、明確なトレンドを示しています。AI Agentは「興味深いデモ」から、orchestration、state、observability、およびenterprise他システムと同じ厳密な権限管理が必要な本番インフラへと移行しています。.NET、Python、またはこの記事のJava/Spring AIのどれを使用していても、基本アーキテクチャは4つのブロックを中心に回ります: Planner、Tool、Memory、Executor。これら4つのブロックをマスターすれば、今後出現するあらゆるagentフレームワークを理解・応用できます。