0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIエージェント=自律型ではない: Anthropic「Building effective agents」のワークフロー型をDatabricks Free Edition + MLflow Graphビューで体系的に理解する

0
Last updated at Posted at 2026-05-09

はじめに

AIエージェントの話題が盛り上がる中で、「自律型エージェント」ばかりが注目されがちです。Computer Use、Claude Code、Cursor Agent... 確かに派手で目を引きます。

しかし、Anthropicが2024年12月に公開した Building effective agents を読むと、彼らが繰り返し強調しているのは別のメッセージです。

Consistently, the most successful implementations weren't using complex frameworks or specialized libraries. Instead, they were building with simple, composable patterns.

「成功している実装の多くは、複雑なフレームワークではなくシンプルで合成可能なパターンを使っている」と。その「パターン」の中心にあるのが、ワークフロー型 です。

この記事では、

  • Anthropicの整理に沿ったワークフロー型と自律型の違い
  • ワークフロー型を選ぶべき場面
  • Databricks Free Editionで動くサンプルノートブック (Anthropic Cookbookの移植版)
  • MLflow Tracingでワークフロー構造をGraphビュー可視化する勘所

を扱います。サンプルノートブックは GitHubリポジトリ に上げています。

Anthropicによるワークフローとエージェントの定義

Anthropicは「エージェント的システム (agentic systems)」を、まずアーキテクチャの観点で2つに分けています。

Workflows are systems where LLMs and tools are orchestrated through predefined code paths.

Agents, on the other hand, are systems where LLMs dynamically direct their own processes and tool usage, maintaining control over how they accomplish tasks.

要点は「経路を誰が決めるか」です。

  • ワークフロー型: 開発者がコードでフローを規定する。各ステップの中身はLLMなので非決定論的だが、経路は固定。
  • 自律型: LLM自身が経路 (どのツールを呼ぶか、いつ終わるか) を実行時に決める。

ここで誤解しやすいのは、「ワークフロー」という言葉が従来のETLやAirflowのジョブ定義のような完全決定論的なものを連想させる点です。Anthropicの言うワークフローは違います。構造は決定論的だが、各ステップの中身はLLMなので非決定論的 という、ハイブリッドな位置付けです。

スペクトラムで描くとこんな感じです。

Screenshot 2026-05-09 at 15.11.29.JPG

ワークフロー型を選ぶべき理由

実務でAI機能を組むなら、まずワークフロー型から検討するのが筋が良いです。理由は4つあります。

1. 予測可能性とデバッグ容易性

自律型は「なぜこのツールを呼んだのか」「なぜこの順序で動いたのか」が実行ごとに変わります。本番運用では、

  • 同じ入力に対して挙動がブレる
  • 失敗時の原因特定が難しい
  • リグレッションテストが書きづらい

という問題に直面します。ワークフローならフローが固定なので、各ステップ単位で評価・テスト・改善ができます。

2. コストとレイテンシの予測可能性

自律型は「考えてツール呼んで、また考えて...」のループが何ターンも回るので、トークン消費とレイテンシが読めません。ワークフローはLLM呼び出し回数が事前にわかるので、コスト試算もSLO設計もしやすい。

3. 多くの実用タスクは自律性を必要としない

「ドキュメントを要約 → 構造化抽出 → DB登録」みたいな業務タスクは、フローがすでに明確です。ここで自律型を使うのは、決まった道順を歩けばいいのにGPSに毎回ルート計算させるようなもので、過剰設計です。

4. 自律性は失敗のコストを跳ね上げる

エージェントが勝手に判断して動く範囲が広いほど、間違ったときの被害も大きくなります (誤ったメール送信、誤ったDB更新など)。ワークフローは人間が経路を設計しているので、ガードレールを効かせやすい。

Anthropic自身も明確に言っています。

When more complexity is warranted, workflows offer predictability and consistency for well-defined tasks, whereas agents are the better option when flexibility and model-driven decision-making are needed at scale.

「タスクの形が事前に書けるかどうか」が分岐点です。書けるならワークフロー、書けないなら自律型。

5つの基本ワークフローパターン

Anthropicの整理では、ワークフロー型は以下の5パターンに分類されます。

パターン 概要 用途例
Prompt Chaining タスクを順序付けたステップに分解 アウトライン → 本文、抽出 → 整形 → 出力
Routing 入力を分類して専門ハンドラに振り分け サポートチケット振り分け、難易度別モデル選択
Parallelization 独立サブタスクを並列実行 多観点評価、複数候補同時生成、ガードレール
Orchestrator-Workers 動的にサブタスクを分解 → 並列実行 → 集約 複雑なリサーチ、多ファイル編集
Evaluator-Optimizer 生成LLMと評価LLMをループ 文芸翻訳、複雑な検索、品質改善

この記事では基本の3つ (Chaining, Parallelization, Routing) をDatabricks上で動かしながら見ていきます。

Databricks Free Editionで動かす

Anthropic Cookbookの該当ノートブックanthropic SDKを直接使っているので、そのままでは動きません。Databricks Free Edition向けに以下を変更しています。

  • anthropic SDK → Databricks Model Serving (OpenAI互換クライアント)
  • ANTHROPIC_API_KEY 不要 → Databricksの認証情報を利用
  • util.py の依存を排除 → ヘルパー関数をノートブック内に直接定義
  • ClaudeはFree Editionで使えないので、Free Editionで利用可能なオープンモデルを使用

モデル選定

Free Editionの Serving ページを開くと、利用可能なエンドポイントが確認できます。

Screenshot 2026-05-09 at 14.52.04.JPG

このサンプルでは以下を使い分けます。

用途 モデル 理由
デフォルト databricks-llama-4-maverick MoEでバランスが良い
並列worker databricks-meta-llama-3-1-8b-instruct 軽量で同時実行のコスト・レイテンシを抑える

gpt-oss 系の推論モデルは戻り値がリスト形式 (reasoningと最終回答が分離) になるため、シンプルなXMLタグ抽出と相性が悪いです。動作確認用途であればinstruct系で十分です。

サンプルノートブックウォークスルー

リポジトリ: ai_agent_workflow

セットアップ

%pip install -q -U "mlflow>=3.12" openai databricks-sdk
dbutils.library.restartPython()
import contextvars
import re
from concurrent.futures import ThreadPoolExecutor

import mlflow
from databricks.sdk import WorkspaceClient

w = WorkspaceClient()
client = w.serving_endpoints.get_open_ai_client()

MODEL = "databricks-llama-4-maverick"
SMALL_MODEL = "databricks-meta-llama-3-1-8b-instruct"

mlflow.openai.autolog()

mlflow.openai.autolog() で、OpenAI互換クライアントを通る全LLM呼び出しが自動的にトレースされます。

ヘルパー関数

@mlflow.trace
def llm_call(prompt: str, system_prompt: str = "", model: str = MODEL) -> str:
    messages = []
    if system_prompt:
        messages.append({"role": "system", "content": system_prompt})
    messages.append({"role": "user", "content": prompt})

    response = client.chat.completions.create(
        model=model,
        max_tokens=4096,
        messages=messages,
    )
    return response.choices[0].message.content


def extract_xml(text: str, tag: str) -> str:
    match = re.search(f"<{tag}>(.*?)</{tag}>", text, re.DOTALL)
    return match.group(1).strip() if match else ""

Pattern 1: Prompt Chaining

タスクを順序付けたステップに分解し、前ステップの出力を次ステップの入力にします。

def chain_step(step_no: int, prompt: str, prev_result: str) -> str:
    with mlflow.start_span(name=f"step_{step_no}") as span:
        span.set_inputs({"prompt": prompt, "prev_result": prev_result})
        result = llm_call(f"{prompt}\n\n入力:\n{prev_result}")
        span.set_outputs(result)
        return result


@mlflow.trace
def chain(input_text: str, prompts: list[str]) -> str:
    result = input_text
    for i, prompt in enumerate(prompts, 1):
        result = chain_step(i, prompt, result)
    return result

例として、レポートテキストから数値を抽出 → 並べ替え → マークダウン表に整形、という3ステップを実行します。

data_processing_steps = [
    "以下のテキストから数値とそのコンテキストだけを抽出してください...",
    "すべての数値を降順に並び替えてください...",
    "並び替えたデータをマークダウンの表に整形してください...",
]

report = """
Q3パフォーマンスサマリー:
顧客満足度は92%に上昇しました。
売上は前期比で45%増加。
新規ユーザー数は2,900%伸長。
解約率は8%まで低下。
"""

final_table = chain(report, data_processing_steps)

MLflow UIのGraphビューで見ると、chain をルートに step_1, step_2, step_3 がsiblings (兄弟) として並ぶ構造が表示されます。

Screenshot 2026-05-09 at 14.53.14.JPG

Graphビューは親子関係を表示するもので、実行順序は表現しません。Chainの「前ステップの出力を次ステップが受け取る」という順次実行の様子は、Timelineビューに切り替えると階段状に確認できます。

Screenshot 2026-05-09 at 14.55.23.JPG

Pattern 2: Parallelization

独立した複数のサブタスクを並列実行します。注意点はスレッド境界を超えるトレースの伝搬です。

def parallel_worker(prompt: str, input_item: str, model: str, worker_id: int) -> str:
    with mlflow.start_span(name=f"worker_{worker_id}") as span:
        span.set_inputs({"prompt": prompt, "input": input_item, "model": model})
        result = llm_call(f"{prompt}\n\n入力:\n{input_item}", "", model)
        span.set_outputs(result)
        return result


@mlflow.trace
def parallel(prompt: str, inputs: list[str], n_workers: int = 4, model: str = SMALL_MODEL) -> list[str]:
    with ThreadPoolExecutor(max_workers=n_workers) as executor:
        futures = []
        for i, x in enumerate(inputs):
            # 親spanコンテキストをworkerスレッドに伝搬
            ctx = contextvars.copy_context()
            futures.append(executor.submit(ctx.run, parallel_worker, prompt, x, model, i))
        return [f.result() for f in futures]

ステークホルダー4種に対して並列に影響分析を実行する例です。

stakeholders = [
    "顧客: 価格に敏感、UX重視、利便性を求める",
    "従業員: 雇用の安定、福利厚生、職場環境",
    "投資家: ROI、市場ポジション、成長性",
    "サプライヤー: 取引の安定性、支払い条件",
]

impact_prompt = "新しいAI製品ローンチがこのステークホルダーに与える影響を、ポジティブ面・ネガティブ面の両方から3点ずつ簡潔に分析してください。"

impact_results = parallel(impact_prompt, stakeholders)

Graphビューでは parallel から worker_0 ~ worker_3 が4本扇状に広がる構造が表示されます。

Screenshot 2026-05-09 at 14.42.17.JPG

Timelineビューに切り替えると、4つのworkerが同時刻に並走している様子が確認でき、これがParallelizationの本質です。

Screenshot 2026-05-09 at 14.59.36.JPG

Pattern 3: Routing

入力をまずLLMで分類し、結果に応じて専門プロンプトに振り分けます。

@mlflow.trace
def classify(input_text: str, routes: dict[str, str], model: str) -> str:
    selector_prompt = f"""以下の入力を分析し、最適なルートを選択してください。
ルート候補: {list(routes.keys())}
...
"""
    route_response = llm_call(selector_prompt, model=model)
    selected_route = extract_xml(route_response, "selection")
    # フォールバック処理省略
    return selected_route


@mlflow.trace
def handle(selected_route: str, input_text: str, routes: dict[str, str]) -> str:
    selected_prompt = routes[selected_route]
    return llm_call(f"{selected_prompt}\n\n問い合わせ内容:\n{input_text}")


@mlflow.trace
def route(input_text: str, routes: dict[str, str], classifier_model: str = MODEL) -> str:
    selected_route = classify(input_text, routes, classifier_model)
    return handle(selected_route, input_text, routes)

カスタマーサポートのチケット振り分けが典型例です。

support_routes = {
    "billing": "あなたは請求担当のサポート担当者です...",
    "technical": "あなたは技術サポート担当者です...",
    "account": "あなたはアカウント管理担当者です...",
}

Graphビューでは routeclassify + handle の2段構造が見えます。

Screenshot 2026-05-09 at 14.54.22.JPG

MLflow Tracing活用の勘所

ワークフロー型は「ステップが見えること」が価値です。MLflow Tracingと相性が良く、Graphビューで構造を直感的に把握できます。とはいえ、実装でハマりやすいポイントがいくつかあるのでまとめます。

1. autologだけでは構造が見えない

mlflow.openai.autolog() は単発のOpenAI API呼び出しを拾うだけで、ワークフローの親子関係は記録されません。各ワークフロー関数に @mlflow.trace を付けるか、mlflow.start_span で囲むことで階層構造ができます。

2. @mlflow.trace と start_span の使い分け

方法 特徴 用途
@mlflow.trace 関数名がspan名になる 名前が固定で良い場合
mlflow.start_span(name=...) span名を動的指定 worker_0, worker_1 のように番号を振りたい場合

これは見た目以上に重要です。MLflowのGraphビューは、同じ親の下にある同名のsibling spanを ×N と集約表示 します。@mlflow.trace def parallel_worker(...): で4回呼ぶと、Graph上では1ノードに ×4 と表示され、4本並列の構造が見えなくなります。動的命名にすることで4ノードが横並びで描画されます。

3. Graphビューは構造、Timelineビューは時間

MLflowのGraphビューは「親子関係」を表示し、実行順序は表現しません。たとえば Chain と Parallelization は、Graph上ではどちらも「親 → 複数子」の同じ形に見えます。違いはTimelineビューで明確になります。

ビュー 見えるもの 向いているパターン
Graph 構造 (親子関係、分岐) Routing、Orchestrator-Workers
Timeline 時間軸 (順次/並列、レイテンシ) Chain、Parallelization

両方を切り替えながら見るのが基本です。

4. ThreadPoolExecutorではcontextvarsを伝搬する

Pythonのcontextvarsはスレッド境界を超えないため、ThreadPoolExecutor.submit で呼ばれたworkerでは親span情報が失われ、各workerが独立したトレースになってしまいます。

MLflow公式FAQ で示されている対処はシンプルです。

# NG: workerが独立トレースになる
executor.submit(parallel_worker, prompt, x, model, i)

# OK: 親コンテキストを伝搬
ctx = contextvars.copy_context()
executor.submit(ctx.run, parallel_worker, prompt, x, model, i)

ctx.run でラップするだけなので、覚えておけば手間ではありません。

5. Graphビュー (MLflow 3.11.1+)

MLflow 3.11.1で追加されたGraphビュー は、ワークフロー型と自律型の構造の違いを示すのに最適です。トレース詳細画面の上部で Graph に切り替えるだけで使えます。

ワークフローの形そのものが視覚化されるので、ハンズオン教材や設計レビューで価値を発揮します。

6. 実用上のTips

  • autolog + decorator併用: autologで内側 (LLM呼び出し) を、decoratorで外側 (ワークフロー) を取る、の二層構成が基本
  • 入出力が大きいときはset_inputs/set_outputsで明示: 自動キャプチャだと冗長なときに有用
  • トレース検索: name = 'parallel' のようなSQLライクなフィルタで特定パターンだけ抽出可能

まとめ

  • AIエージェント = 自律型ではない。Anthropicの整理ではエージェント的システムには ワークフロー型自律型 がある。
  • ワークフロー型は 構造は決定論的、各ステップの中身は非決定論的 というハイブリッド。実用システムの大多数はこちらで十分。
  • 「タスクの形が事前に書けるか」が選定基準。書けるならワークフロー、書けないなら自律型。
  • MLflow Tracing (3.11.1+) のGraphビューはワークフロー構造の可視化に強力。@mlflow.tracestart_span を使い分け、ThreadPoolExecutor 利用時は contextvars.copy_context() で親コンテキストを伝搬。

派手な自律型エージェントの裏で、堅実な業務システムを支えているのはワークフロー型です。Anthropicが言う通り「シンプルで合成可能なパターン」から始めて、必要な部分だけ自律性を増やしていくのが、現実的なアプローチだと思います。

参考リンク

はじめてのDatabricks

はじめてのDatabricks

Databricks無料トライアル

Databricks無料トライアル

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?