テックブログ

Microsoft Agent Framework入門

Microsoft Agent Framework入門

1. Microsoft Agent Framework とは? SK と AutoGen の“まとめ役”

Semantic Kernel と AutoGen を統合した「次世代エージェント基盤」という位置づけ

Microsoft Agent Framework(以下 MAF)は、Semantic Kernel(SK)のスキル実行・メモリ・プロンプト管理と、AutoGenの会話駆動エージェント協調を、共通のAPI/ランタイムで扱うことを狙った基盤として理解できる。目的は「エージェントの作成・連携・運用を一つの枠組みで完結させる」こと。

.NET / Python 両対応、OSS SDK & ランタイムとしての特徴

  • 言語:.NET と Python の二系統。既存SK/AutoGen資産を活かしやすい。
  • 拡張:LLM、ツール(関数/外部API)、MCP(Model Context Protocol)サーバの取り込みを前提とした設計。
  • デプロイ:ローカル開発→コンテナ→クラウドへ持ち上げやすい実装分割(エージェント/ワークフロー/エッジAPI)。

「周辺ツールがバラバラ」問題をどう解決しようとしているか

従来は「プロンプトはSK」「エージェント対話はAutoGen」「ツールは独自HTTP」「前段は自前API」と散らばりがち。MAFはグラフ化されたワークフロー標準のHTTPエンドポイントでまとめ、観測・権限・デプロイを通しやすくする方向性だ。


2. 単一エージェントの“Hello, Agent”:最小構成を理解する

LLM・ツール・MCPサーバーを組み合わせる基本概念

最小構成は次の3点で足りる。

  1. LLM(推論モデル)
  2. ツール(関数呼び出しやHTTP、DBなど)
  3. MCPサーバ(外部リソースへ統一プロトコルで接続)

エージェントはプロンプトと方針を持ち、必要に応じてツールやMCP経由で外部に手を伸ばす。

PythonでOKな最小コード例(概念コード)

# 概念コード:実API名は環境に合わせて置換してください
from agent_framework import Agent, Tool, MCPClient, LLM
import os

llm = LLM(provider="openai", model="gpt-4o-mini", api_key=os.getenv("OPENAI_API_KEY"))

# ツール(関数呼び出し)例
def get_exchange_rate(pair: str) -> str:
    # 実運用では外部API叩く。ここはダミー。
    rates = {"USD/JPY": 150.12, "EUR/JPY": 163.40}
    return str(rates.get(pair, "N/A"))

fx_tool = Tool.from_function(get_exchange_rate, name="get_exchange_rate", description="為替レート取得")

# 任意のMCPサーバへ接続(例:社内ナレッジ検索)
mcp = MCPClient(url="http://localhost:8001")

agent = Agent(
    name="hello",
    system_prompt="あなたは簡潔で正確なアシスタント。",
    llm=llm,
    tools=[fx_tool],
    mcp_clients=[mcp]
)

print(agent.run("USD/JPYの為替を教えて。根拠も一行で。"))

意図:LLMにツールを“公開”し、必要時のみ呼び出す。MCPは社内検索や計算バックエンド等を統一的に繋ぐ窓口として差し込む。

ローカル環境で動かす手順と確認ポイント

  1. APIキーを環境変数に設定(OPENAI_API_KEYなど)。
  2. LLMのモデル名・エンドポイントを正しく指定(レート制限も確認)。
  3. ログ出力をINFO以上にして、ツール呼び出し/トークン消費量/エラーを観察。

3. マルチエージェント & ワークフロー:グラフとしてタスクを組み立てる

“エージェント”と“ワークフロー”の役割分担

  • エージェント主導(LLM主導):自由度が高く探索的。調査・要約向き。
  • ワークフロー主導(ビジネスロジック主導):手順が固定。入力検証、承認、配信など厳格運用に向く。

グラフベースのワークフロー:ルーティング・ネスト・チェックポイント

ジョブをノード(タスク)とエッジ(遷移)で表す。チェックポイントを挟み、途中結果を保存して再開可能にする。ルーティング条件で分岐し、サブグラフ(ネスト)で複雑度を吸収する。

「リサーチ役」と「要約役」に仕事を振る簡単シナリオ(概念コード)

from agent_framework import Agent, Workflow, Node

researcher = Agent(name="researcher", system_prompt="信頼できるソースを列挙し要点を抜き出す。", llm=llm)
summarizer = Agent(name="summarizer", system_prompt="専門外の人にも伝わる要約を作る。", llm=llm)

wf = Workflow(
  nodes=[
    Node(id="research", run=lambda q: researcher.run(f"以下を調査: {q}")),
    Node(id="summarize", run=lambda txt: summarizer.run(f"以下を200字で要約: {txt}"))
  ],
  edges=[("research", "summarize")]
)

result = wf.start(input="次期スマホ決済の動向を3社比較")
print(result)

意図:役割を分けることでプロンプトが簡潔になり、再利用性とデバッグ性が上がる。各ノードでログ・失敗時のリトライ回数・タイムアウトを設定するのが実務的。


4. フロントエンドから叩くエージェントバックエンド

Next.js / React から HTTP 経由で呼ぶ基本パターン

バックエンドはHTTP APIを1本用意。POST /agent/run{query, tools, workflow}等を投げる。フロントはSSE/ストリーミングで途中経過を受け取ると体験が良い。

# FastAPIでバックエンド(概念)
from fastapi import FastAPI, Depends, Header, HTTPException
from pydantic import BaseModel
import time
import os

app = FastAPI()

class RunBody(BaseModel):
    query: str

def auth(authorization: str = Header("")):
    if authorization != f"Bearer {os.getenv('API_TOKEN')}":
        raise HTTPException(status_code=401, detail="unauthorized")

@app.post("/agent/run")
def run_agent(body: RunBody, _: None = Depends(auth)):
    # 実際は agent.run(body.query) など
    answer = agent.run(body.query)
    return {"answer": answer, "took_ms": int(time.time() * 1000) % 777}

意図:APIトークンで最低限の認証をかけ、レスポンスはJSONで統一。SSEにする場合はStreamingResponseを使う。

Next.js(App Router)から呼ぶ例とCORS/認証/レート制限

/* app/api/ask/route.ts:Next.jsからプロキシ */
import { NextRequest, NextResponse } from "next/server";

export async function POST(req: NextRequest) {
  const { query } = await req.json();
  const res = await fetch(process.env.AGENT_API + "/agent/run", {
    method: "POST",
    headers: {
      "content-type": "application/json",
      "authorization": `Bearer ${process.env.AGENT_TOKEN}`,
    },
    body: JSON.stringify({ query }),
    cache: "no-store",
  });
  return new NextResponse(res.body, { status: res.status }); // ストリーム転送も可
}

ポイント:ブラウザ → Next.js(同一オリジン) → エージェントAPIという経路にして、直接CORSを晒さない。Next側でレート制限(Redis等)と入力長制限を掛ける。

「チャット+ツール実行ボタン」UIの最小アーキテクチャ

  • 画面:メッセージ履歴と入力欄、ツール実行トグル。
  • API:/api/askでプロキシ。サーバで監査ログ(traceId, userId, took_ms)。
  • バックエンド:エージェント本体。ツールは安全なホワイトリスト制御。

5. 学生エンジニアが押さえておきたい“現実的な”注意点

プレビュー版前提のリスクとバージョン追従

  • API破壊的変更に備え、ラッパ層(自作のAdapter)を薄く挟む。
  • 依存バージョンを明示固定(Poetry/requirements.lock、PackageReference)。
  • 環境差異を避けるため、コンテナで開発・本番を揃える。

ログと監視:長時間動くエージェントのトラブルシュート

  • ノードごとの開始/終了/例外、LLMトークン使用量、ツール実行回数を計測。
  • タイムアウト・リトライ・サーキットブレーカーをワークフロー側で設定。
  • 外部APIのSLAに合わせ、バックオフ+冪等キーで再実行。

「全部エージェント任せにしない」設計:Human-in-the-loop

  • 高リスク操作(外部通知、発注、書き込み)は要承認ステップを入れる。
  • 提示文は差分表示でレビューしやすくする。
  • 失敗時の再実行ガイド(再プロンプト例、入力例)をUIに組み込む。

付録:.NET版の超小さな雰囲気コード(概念)

// 概念コード:具体API名は手元のSDKに合わせて置換
using AgentFramework;
using AgentFramework.Tools;

var llm = new Llm(provider: "azureopenai", model: "gpt-4o");
var fx = Tool.FromFunc("get_exchange_rate", (string pair) => "...");

var agent = new Agent(
  name: "hello",
  systemPrompt: "短く正確に回答する。",
  llm: llm,
  tools: new[] { fx }
);

var ans = await agent.RunAsync("USD/JPYの今を一言で。");
Console.WriteLine(ans);

意図:言語が違っても「LLM+ツール+(任意でMCP)」の構図は同じ。最小構成で動かしてから、ワークフローや監視を足すのが安全。


まとめ

Microsoft Agent Frameworkは、SKとAutoGenの強みを一つの枠にまとめ、単一エージェント → マルチエージェント → ワークフローへ素直に拡張できる土台を目指す。

フロントはNext.js経由のプロキシで安全に叩き、認証・レート制限・監査をサーバ側に集約。プレビュー期はAPI変化に備え、薄いアダプタと観測を徹底する。最後に、人の確認を要所に入れる設計が現実解だ。


参考リンク