18
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Agentic Workflowの設計と実践:Claude Agent SDKで社内のコンテンツチェックを自動化する

Last updated at Posted at 2025-12-16

はじめに

こんにちは!KIYOラーニングでスタディングの開発を担当している @Kumacchiino です!
AIエージェント構築&運用のアドベントカレンダー向けの記事ということで、社内で行っている業務を、Agentic Workflow デザインパターンを使い効率化しようとしている取り組みについて書こうと思います。

AgenticWorkflows.png

Agentic Workflowとは?

Agentic Workflow(エージェント型ワークフロー)とは、LLMを「一回呼んで答えを返す道具」ではなく、目標達成のために計画→実行→評価→再計画を繰り返し、必要に応じて外部ツールも使い分けるAIエージェントとして動かす一連の仕組みのことです。
タスクを小さなステップに分け、複数のAIエージェントやルール、ツール呼び出しを組み合わせて、状況に応じて次の行動を自律的に選びながら進めます。

従来のワークフローは、人やプログラムが決めた固定の手順をそのまま実行します。
一方、エージェント型ワークフローは、手順自体が半固定または動的であり、途中の結果や環境に合わせてエージェントが次のステップを選び直すのが特徴です。

つまり「フローを設計して実行させる」だけでなく、「フローを走りながら賢く組み替える」アプローチです。

今回取り組んでみた業務課題

弊社では、社内で管理するWebページ数が増えてきたことで、同じ言葉でも書き方が記事ごとにバラつく「表記揺れ」が目立つようになってきました。
その結果、SEO的な評価が分散したり、リライトやレビューのたびに目視チェックの手間がかかったりして、運用コストが徐々に増えていました。

そこで、表記揺れをまとめて洗い出し、修正点を整理したレポートまで自動で出力できる仕組みを作れないかと考え、今回のエージェント型ワークフローを構築して課題解決を試みることにしました。

つくったもの

こちらが今回つくったエージェント型ワークフローの概要図です。

分析対象としたいWebページのURLを指定すると、4つのエージェントが協働して最終的に表記揺れの用語表記統一提案レポートを出力します。

Agentic Workflow diagram-2025-12-09-063125.png

各エージェントの役割

エージェント 役割
マネジメントエージェント 全体の処理を統括し、サブエージェントを適切な順序で呼び出す
コンテンツ取得エージェント 指定されたURLからWebページのテキストを取得
用語分析エージェント 複数のコンテンツを比較して表記ゆれを検出・分類
レポート作成エージェント 分析結果をMarkdownレポートとして整形・出力

エージェント型ワークフローが生み出す価値

従来のルールベースのアプローチと比較して、エージェント型ワークフローには以下のような価値があります。

1. 柔軟な入力への対応

従来のスクレイピング+ルールベース比較では、Webページの構造が変わるたびにパーサーの修正が必要でした。エージェント型ワークフローでは、LLMがコンテンツの意味を理解して処理するため、HTML構造の違いに左右されずに分析できます。

2. 文脈を考慮した表記ゆれ検出

単純な文字列マッチングでは「行政書士講座」と「行政書士試験講座」が異なる表記だと判定できても、それが意図的な使い分けなのか統一すべき表記ゆれなのかは判断できません。エージェント型ワークフローでは、文脈や用途を考慮した上で、SEOや品質管理の観点から優先度付けした提案ができます。

3. 人間が読みやすいレポート出力

検出結果をただ羅列するのではなく、「なぜ統一すべきか」「どの表記に統一すべきか」といった理由付けを含む、人間が判断しやすい形式でレポートを出力できます。

4. 拡張性の高さ

新しい検出カテゴリを追加したい場合、コードを書き換えるのではなくプロンプトを修正するだけで対応できます。また、サブエージェントを追加することで、たとえば「修正案の自動適用」や「競合サイトとの比較」といった機能拡張も容易です。

従来アプローチとの比較

観点 従来のアプローチ エージェント型ワークフロー
HTML構造の変化 パーサー修正が必要 LLMが柔軟に対応
表記ゆれの判定 辞書・ルールベース 文脈を考慮した判定
優先度付け 事前定義が必要 動的に判断可能
レポート品質 テンプレート出力 状況に応じた説明文生成
機能拡張 コード修正が必要 プロンプト修正で対応

実装手法について

今回は、Anthropicが公開しているClaude Agent SDKを利用して実装しています。

Claude Agent SDKとは

Claude Agent SDKは、Anthropic社が提供する、Claudeを使った本番対応のAIエージェントを作るための開発キットです。Claude Codeを動かしている同じエージェント基盤(ツール実行・権限管理・コンテキスト管理など)を外部開発者向けに一般化したもので、TypeScript版とPython版があります。ファイル操作やWeb検索、外部API連携(MCP)などのツールを組み合わせ、コーディング支援や業務自動化エージェントを構築できます。

主な特徴として以下のものがあります。

  • サブエージェントの定義と管理
  • カスタムツール(MCP)の作成と統合
  • Claude Codeの機能一式をそのまま利用できる

今回は、Python版を使ってエージェント型ワークフローを構築しました。

全体構成

ClaudeAgentSdk/
├── main.py                      # エントリーポイント
├── .env                         # 環境変数定義
├── requirements.txt             # パッケージ管理
├── src/
│   ├── cli.py                   # CLI引数処理・結果表示
│   ├── config.py                # 設定・定数
│   ├── analyzer.py              # 分析実行ロジック(ClaudeSDKClient使用)
│   ├── tools.py                 # カスタムツール定義
│   ├── agents/
│   │   ├── __init__.py          # エージェント定義の集約
│   │   ├── content_fetcher.py   # コンテンツ取得エージェント
│   │   ├── term_extractor.py    # 用語分析エージェント
│   │   └── report_writer.py     # レポート作成エージェント
│   └── prompts/
│       └── orchestrator.py      # 統括エージェント用プロンプト
└── output/                      # レポート出力先

1. Amazon Bedrockの設定を定義

今回は、Amazon BedrockのClaudeモデルを使うため、環境変数として以下を定義します。
Bedrockを使用することと、モデル名、使用リージョン、Amazon BedrockのAPIキーを設定します。
Amazon BedrockのAPIキーは、AWS IAM上で発行できます。

.env
CLAUDE_CODE_USE_BEDROCK=1
AWS_REGION=ap-northeast-1
AWS_BEARER_TOKEN_BEDROCK=<BEDROCKのAPIキー>
ANTHROPIC_MODEL="jp.anthropic.claude-sonnet-4-5-20250929-v1:0"
ANTHROPIC_SMALL_FAST_MODEL="jp.anthropic.claude-haiku-4-5-20251001-v1:0"

2. カスタムツールの定義

まず、Webページのコンテンツを取得するためのカスタムツールを定義します。Claude Agent SDKの@toolデコレーターを使用することで、MCPツールとして登録できます。

src/tools.py
"""カスタムツール定義"""

from typing import Any

import requests
from bs4 import BeautifulSoup
from claude_agent_sdk import tool, create_sdk_mcp_server


@tool("fetch_webpage", "URLからWebページを取得してテキストを抽出する", {"url": str})
async def fetch_webpage(args: dict[str, Any]) -> dict[str, Any]:
    """Webページを取得してテキストを抽出するカスタムツール"""
    url = args["url"]
    try:
        headers = {
            "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"
        }
        response = requests.get(url, headers=headers, timeout=30)
        response.raise_for_status()
        response.encoding = response.apparent_encoding

        soup = BeautifulSoup(response.text, "html.parser")

        # タイトルを取得
        title = soup.title.string if soup.title else "タイトルなし"

        # main id="main"タグを探す
        main_content = soup.find("main", id="main")
        if main_content:
            # mainタグ内の不要な要素を削除
            for tag in main_content(["script", "style", "nav", "footer", "header", "aside"]):
                tag.decompose()
            text = main_content.get_text(separator="\n", strip=True)
        else:
            # mainタグが見つからない場合はbody全体からテキストを抽出
            body = soup.body if soup.body else soup
            for tag in body(["script", "style", "nav", "footer", "header", "aside"]):
                tag.decompose()
            text = body.get_text(separator="\n", strip=True)

        # テキストが長すぎる場合は切り詰める
        max_length = 50000
        if len(text) > max_length:
            text = text[:max_length] + "\n\n... (以降省略)"

        return {
            "content": [
                {
                    "type": "text",
                    "text": f"URL: {url}\nタイトル: {title}\n\n取得したコンテンツ:\n{text}"
                }
            ]
        }
    except requests.exceptions.Timeout:
        return {
            "content": [{"type": "text", "text": f"タイムアウトエラー: {url} への接続がタイムアウトしました"}],
            "is_error": True,
        }
    except requests.exceptions.RequestException as e:
        return {
            "content": [{"type": "text", "text": f"リクエストエラー: {str(e)}"}],
            "is_error": True,
        }
    except Exception as e:
        return {
            "content": [{"type": "text", "text": f"エラー: {str(e)}"}],
            "is_error": True,
        }


def create_web_mcp_server():
    """Webコンテンツ取得用のMCPサーバーを作成する"""
    return create_sdk_mcp_server(
        name="web",
        version="1.0.0",
        tools=[fetch_webpage],
    )

ポイントは以下の通りです:

  • @toolデコレーターで、ツール名・説明・引数スキーマを定義
  • create_sdk_mcp_server()でMCPサーバーとしてパッケージ化
  • BeautifulSoupでHTMLをパースし、メインコンテンツのみ抽出

3. サブエージェントの定義

Claude Agent SDKのAgentDefinitionを使って、3つのサブエージェントを定義します。

コンテンツ取得エージェント

src/agents/content_fetcher.py
"""content_fetcher エージェント定義"""

from claude_agent_sdk import AgentDefinition

content_fetcher_agent = AgentDefinition(
    description="URLからWebページのコンテンツを取得するエージェント",
    prompt="""\
あなたはWebコンテンツ取得専門のエージェントです。
指定されたURLからWebページのコンテンツを取得してください。

## 取得手順
1. mcp__web__fetch_webpageツールを使用してWebページのテキストを取得
2. 取得したコンテンツをそのまま返却

## 重要な注意事項
- セクション構造(見出し、段落の区切り)を保持して取得してください
- 見出しタグ(h1, h2, h3等)の階層構造が分かるように出力してください
- 取得したコンテンツはそのまま返してください(要約や加工は不要)""",
    tools=["mcp__web__fetch_webpage"],
    model="haiku",
)

用語分析エージェント

src/agents/term_extractor.py
"""term_extractor エージェント定義"""

from claude_agent_sdk import AgentDefinition

term_extractor_agent = AgentDefinition(
    description="複数のコンテンツを比較して表記ゆれを検出するエージェント",
    prompt="""\
あなたは用語表記分析専門のエージェントです。
複数のWebページコンテンツを比較し、表記ゆれを検出してください。

## 検出カテゴリ(優先順位順)

### 優先度 高
#### A. 講座名・商品名・コース名の表記ゆれ
SEOに直結しやすい最重要カテゴリ。公式名称(マスタ)と異なる書き方を検出。

検出例:
- 「行政書士講座」vs「行政書士試験講座」vs「行政書士試験対策講座」
- 「スタディング行政書士」vs「STUDYing 行政書士」

#### B. 固有用語・試験制度名・法令名の表記ゆれ
検索クエリの軸になるため統一対象。

### 優先度 中
#### C. 同義語/言い換えの混在
同じ意味の単語がランダムに使い分けられている場合。

#### D. 同一訴求ブロックの文章不一致【今回の主旨】
同じセクション・意図の文章がページ間で異なるケースを検出。

### 優先度 低
#### E. 表記ルールの揺れ
漢字/ひらがな/カタカナ/英数字/記号などの揺れ。

## 出力形式【構造化】

以下のJSON形式で出力してください:

{
  "summary": {
    "total_count": 10,
    "priority_high": 3,
    "priority_medium": 5,
    "priority_low": 2
  },
  "items": [
    {
      "id": 1,
      "priority": "",
      "category": "A",
      "category_name": "講座名・商品名・コース名",
      "target": "講座名称",
      "variations": [
        {"url": "URL1", "text": "行政書士講座"},
        {"url": "URL2", "text": "行政書士試験講座"}
      ],
      "recommended": "行政書士講座",
      "reason": "公式名称として統一"
    }
  ]
}
""",
    tools=[],
    model="opus",
)

レポート作成エージェント

src/agents/report_writer.py
"""report_writer エージェント定義"""

from claude_agent_sdk import AgentDefinition

report_writer_agent = AgentDefinition(
    description="分析結果をMarkdownレポートとして出力するエージェント",
    prompt="""\
あなたはレポート作成専門のエージェントです。
用語表記分析の結果をMarkdownレポートとして整形し、ファイルに出力してください。
Writeツールを使用して、指定されたパスにレポートを保存してください。

**重要**: 各ページを横並びで比較できる形式でレポートを作成してください。

## レポートテンプレート

# 用語表記統一レポート

## 概要

- **分析日時**: YYYY年MM月DD日
- **検出数**: N件(高: N件 / 中: N件 / 低: N件)

## 表記ゆれ比較

### 1. [セクション名] - [対象の説明]

**優先度**: 高 / 中 / 低

| ページ | 現状の記載 |
|-------|----------|
| A | (ページAの記載内容をそのまま引用) |
| B | (ページBの記載内容をそのまま引用) |

**差異ポイント**:
- (具体的にどこが違うかを箇条書き)

**推奨表記**:
> (統一すべき文章)
""",
    tools=["Write", "Read"],
    model="sonnet",
)

サブエージェントの定義を集約するファイルも用意します。

src/agents/__init__.py
"""エージェント定義"""

from claude_agent_sdk import AgentDefinition

from src.agents.content_fetcher import content_fetcher_agent
from src.agents.term_extractor import term_extractor_agent
from src.agents.report_writer import report_writer_agent

AGENTS: dict[str, AgentDefinition] = {
    "content_fetcher": content_fetcher_agent,
    "term_extractor": term_extractor_agent,
    "report_writer": report_writer_agent,
}


def define_agents() -> dict[str, AgentDefinition]:
    """サブエージェントを定義する"""
    return AGENTS

4. オーケストレーター(マネジメントエージェント)の設定

オーケストレーターは、3つのサブエージェントを順番に呼び出し、全体の処理を統括します。

src/prompts/orchestrator.py
"""オーケストレーター用プロンプト"""

from datetime import datetime
from pathlib import Path

ORCHESTRATOR_SYSTEM_PROMPT = """\
あなたは用語表記統一のためのオーケストレーターエージェントです。
サブエージェントを適切に活用し、Webページの用語分析とレポート生成を行ってください。

## 利用可能なサブエージェント
1. content_fetcher: mcp__web__fetch_webpageツールでURLからコンテンツを取得
2. term_extractor: 複数コンテンツの用語比較・表記ゆれ検出
3. report_writer: 分析結果をMarkdownレポートとして出力(Writeツール使用)

## 検出対象の表記ゆれカテゴリ

### 優先度 高
A. 講座名・商品名・コース名の表記ゆれ
B. 固有用語・試験制度名・法令名の表記ゆれ

### 優先度 中
C. 同義語/言い換えの混在
D. 同一訴求ブロックの文章不一致【今回の主旨】

### 優先度 低
E. 表記ルールの揺れ

Taskツールを使用してサブエージェントを呼び出してください。"""


def build_orchestrator_prompt(urls: list[str], output_path: Path) -> str:
    """オーケストレーターエージェント用のプロンプトを構築する"""
    urls_formatted = "\n".join(f"- {url}" for url in urls)
    today = datetime.now().strftime("%Y年%m月%d日")

    return f"""\
以下のWebページの用語表記を分析し、統一提案レポートを作成してください。

## 本日の日付
{today}

## 分析対象URL
{urls_formatted}

## 実行手順

### ステップ1: コンテンツ取得
content_fetcherエージェントを使用して、各URLからコンテンツを取得してください。

### ステップ2: 用語分析
すべてのURLからコンテンツを取得したら、term_extractorエージェントを使用して分析してください。

### ステップ3: レポート生成
report_writerエージェントを使用して、分析結果をMarkdownレポートとして出力してください。
出力先ファイルパス: {output_path}

## 重要な注意事項
- 各ステップの結果を次のステップに確実に引き継いでください
- レポートは必ずWriteツールで指定されたパスに保存してください"""

5. 分析実行ロジック

ClaudeSDKClientを使って、オーケストレーターを起動し、ストリーミングでレスポンスを受信します。

src/analyzer.py
"""用語表記分析の実行ロジック"""

from pathlib import Path

from claude_agent_sdk import (
    ClaudeAgentOptions,
    ClaudeSDKClient,
    AssistantMessage,
    ResultMessage,
    SystemMessage,
    TextBlock,
    ToolUseBlock,
    ToolResultBlock,
)

from src.config import PROJECT_ROOT, ALLOWED_TOOLS, MODEL_ORCHESTRATOR
from src.agents import define_agents
from src.prompts import ORCHESTRATOR_SYSTEM_PROMPT, build_orchestrator_prompt
from src.tools import create_web_mcp_server


async def run_terminology_analysis(
    urls: list[str],
    output_path: Path,
    verbose: bool = False,
    logger=None,
) -> dict:
    """用語表記分析を実行する"""

    log = logger or print

    # エージェント定義
    agents = define_agents()

    # オーケストレータープロンプト
    prompt = build_orchestrator_prompt(urls, output_path)

    # カスタムツールを含むMCPサーバーを作成
    web_server = create_web_mcp_server()

    # オプション設定
    options = ClaudeAgentOptions(
        system_prompt=ORCHESTRATOR_SYSTEM_PROMPT,
        permission_mode="acceptEdits",
        cwd=str(PROJECT_ROOT),
        agents=agents,
        mcp_servers={"web": web_server},
        allowed_tools=ALLOWED_TOOLS,
        model=MODEL_ORCHESTRATOR
    )

    result = {
        "success": False,
        "output_path": None,
        "error": None,
        "cost": None,
        "duration_ms": None
    }

    try:
        # ClaudeSDKClientを使用(カスタムツールはclientでのみサポート)
        async with ClaudeSDKClient(options=options) as client:
            await client.query(prompt)

            async for message in client.receive_response():
                # システムメッセージ(サブエージェント開始など)
                if isinstance(message, SystemMessage):
                    if message.subtype == "agent:task:start":
                        agent_type = message.data.get("subagent_type", "unknown")
                        description = message.data.get("description", "")
                        log(f"  → サブエージェント開始: {agent_type} ({description})")
                    elif message.subtype == "agent:task:complete":
                        log(f"  ✓ サブエージェント完了")

                # アシスタントメッセージ(ツール使用、テキスト出力)
                if isinstance(message, AssistantMessage):
                    for block in message.content:
                        if isinstance(block, ToolUseBlock):
                            tool_name = block.name
                            if tool_name == "Task":
                                subagent = block.input.get("subagent_type", "unknown")
                                desc = block.input.get("description", "")
                                log(f"[Orchestrator] サブエージェント呼び出し: {subagent} - {desc}")
                            elif tool_name == "mcp__web__fetch_webpage":
                                url = block.input.get("url", "")
                                log(f"[Agent] Webページ取得中: {url}")
                            elif tool_name == "Write":
                                file_path = block.input.get("file_path", "")
                                log(f"[Agent] ファイル書き込み: {file_path}")

                if isinstance(message, ResultMessage):
                    result["success"] = not message.is_error
                    result["cost"] = message.total_cost_usd
                    result["duration_ms"] = message.duration_ms

                    if message.is_error:
                        result["error"] = message.result
                    else:
                        result["output_path"] = str(output_path)

    except Exception as e:
        result["error"] = str(e)

    return result

6. エントリーポイント

main.py
"""
用語表記統一ツール

使用方法:
    python main.py URL1 URL2 [URL3 ...]
    python main.py -o output/report.md URL1 URL2
    python main.py -v URL1 URL2  # 詳細ログ
"""

import asyncio
import sys

from dotenv import load_dotenv

from src.cli import parse_arguments, get_output_path, print_summary
from src.analyzer import run_terminology_analysis

# 環境変数の読み込み
load_dotenv()


async def main():
    """メイン関数"""
    args = parse_arguments()

    # URL検証
    if len(args.urls) < 2:
        print("警告: 比較分析には2つ以上のURLを指定することを推奨します")

    # 出力パス決定
    output_path = get_output_path(args.output)

    print(f"分析対象: {len(args.urls)}ページ")
    for url in args.urls:
        print(f"  - {url}")
    print(f"出力先: {output_path}")
    print("分析を開始します...\n")

    # 分析実行
    result = await run_terminology_analysis(
        urls=args.urls,
        output_path=output_path,
        verbose=args.verbose
    )

    # 結果表示
    print_summary(result)

    return 0 if result["success"] else 1


if __name__ == "__main__":
    exit_code = asyncio.run(main())
    sys.exit(exit_code)

7. 設定ファイル

src/config.py
"""設定・定数定義"""

from pathlib import Path

# プロジェクトルートディレクトリ
PROJECT_ROOT = Path(__file__).parent.parent.absolute()
OUTPUT_DIR = PROJECT_ROOT / "output"

# 許可するツール
ALLOWED_TOOLS = ["Task", "mcp__web__fetch_webpage", "Write", "Read"]

# モデル設定
MODEL_ORCHESTRATOR = "jp.anthropic.claude-haiku-4-5-20251001-v1:0"

8. CLI引数処理・結果表示

src/cli.py
"""コマンドライン引数処理・結果表示"""

import argparse
from datetime import datetime
from pathlib import Path

from src.config import OUTPUT_DIR


def parse_arguments() -> argparse.Namespace:
    """コマンドライン引数をパースする"""
    parser = argparse.ArgumentParser(
        description="複数のWebページの用語表記を分析し、統一提案を行うツール"
    )
    parser.add_argument(
        "urls",
        nargs="+",
        help="分析対象のWebページURL(スペース区切りで複数指定可能)"
    )
    parser.add_argument(
        "-o", "--output",
        type=str,
        default=None,
        help="出力ファイルパス(デフォルト: output/terminology_report_YYYYMMDD_HHMMSS.md)"
    )
    parser.add_argument(
        "-v", "--verbose",
        action="store_true",
        help="詳細な実行ログを表示"
    )
    return parser.parse_args()


def get_output_path(custom_path: str | None = None) -> Path:
    """出力ファイルパスを決定する"""
    if custom_path:
        path = Path(custom_path)
        path.parent.mkdir(parents=True, exist_ok=True)
        return path

    # outputディレクトリがなければ作成
    OUTPUT_DIR.mkdir(exist_ok=True)

    # タイムスタンプ付きファイル名を生成
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    return OUTPUT_DIR / f"terminology_report_{timestamp}.md"


def print_summary(result: dict) -> None:
    """実行結果のサマリーを表示する"""
    print("\n" + "=" * 60)
    print("用語表記統一分析 - 実行結果")
    print("=" * 60)

    if result["success"]:
        print("ステータス: 成功")
        print(f"出力ファイル: {result['output_path']}")
    else:
        print("ステータス: 失敗")
        print(f"エラー: {result['error']}")

    if result["cost"]:
        print(f"実行コスト: ${result['cost']:.4f}")
    if result["duration_ms"]:
        print(f"実行時間: {result['duration_ms'] / 1000:.2f}")

    print("=" * 60)

9. パッケージ管理ファイル

requirements.txt
claude-agent-sdk==0.1.13
python-dotenv==1.2.1
requests>=2.31.0
beautifulsoup4>=4.12.0

実行方法

venvを使った場合は、以下のように実行できます。

# 仮想環境のアクティベート
source venv/bin/activate

# 依存関係のインストール
pip install -r requirements.txt

# 実行
python main.py https://example.com/page1 https://example.com/page2

実行の流れ

  1. main.pyがCLI引数を解析して、run_terminology_analysis()を呼び出す
  2. マネジメントエージェントがプロンプトに従ってTaskツールでサブエージェントを呼び出す
  3. コンテンツ取得エージェントが各URLからWebページのコンテンツを取得
  4. 用語分析エージェントが取得したコンテンツを比較して表記ゆれを検出
  5. レポート作成エージェントが分析結果をMarkdownレポートとして出力

実際にやってみた結果

今回は、弊社が作成・管理しているWebページを対象に、上記のエージェント型ワークフローを実行してみました。

実行すると以下のようなMarkdown形式のレポートが生成されます。

スクリーンショット 2025-12-09 16.03.36.png

スクリーンショット 2025-12-09 17.54.57.png

まだまだ改善の余地はありますが、それなりのレポートが生成できているのではないかと思います。
実際に社内で運用する際には、事業部の方とアウトプットの形についてコミュニケーションを取って擦り合わせをして、プロンプトやカスタムツールを修正して運用まで持っていく予定です。

まとめ

今回は、Claude Agent SDKを使ってAgentic Workflowパターンを実装し、Webページの表記揺れを検出するツールを構築しました。

今回の取り組みで得られた知見

  • エージェント分割の重要性: タスクを適切な粒度でサブエージェントに分割することで、それぞれの役割が明確になり、プロンプトの設計がしやすくなると感じました
  • カスタムツールの柔軟性: @toolデコレーターを使うことで、BeautifulSoupによるスクレイピングなど、独自の処理を簡単にエージェントに組み込めました
  • 段階的な品質向上: 最初から完璧を目指すのではなく、動くものを作ってからプロンプトやツールを改善していくアプローチが効果的と思いました

Claude Agent SDKの使いやすさ

Claude Agent SDKは、特に以下の点が便利でした。

  • AgentDefinitionによるサブエージェントの宣言的な定義
  • MCPサーバーを介したカスタムツールの統合

Claude Codeのノウハウも活かすことができるので、普段からClaude Codeを使っている開発者は、Claude Agent SDKはとっつきやすいかと思います。

さいごに

Claude Agent SDKに限らず、さまざまなAIエージェントフレームワークが登場しており、個人や社内で使うレベルのAIエージェント・エージェント型ワークフローであれば、比較的短期間で構築できる環境が整っていると思います。

まずは社内のPoCから始めてノウハウを蓄積し、段階的にプロダクトの本番環境への適用・機能開発を進めていくのが良いアプローチだと考えています。

この記事が、AIエージェント・エージェント型ワークフロー導入を検討されている方の参考になれば幸いです!

KIYOラーニング株式会社について

当社のビジョンは『世界一「学びやすく、分かりやすく、続けやすい」学習手段を提供する』ことです。革新的な教育サービスを作り成長させていく事で、オンライン教育分野でナンバーワンの存在となり、世界に展開していくことを目指しています。

プロダクト

  • スタディング:「学びやすく・わかりやすく・続けやすい」オンライン資格対策講座
  • スタディングキャリア:資格取得者の仕事探しやキャリア形成を支援する転職サービス
  • AirCourse:受け放題の動画研修がついたeラーニングシステム(LMS)

KIYOラーニング株式会社では一緒に働く仲間を募集しています

18
14
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
18
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?