9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

3分で作るDeep Research(OpenAI Agents SDK x Sub-Agent)

Last updated at Posted at 2025-12-17

はじめに

この記事は 博報堂テクノロジーズ Advent Calendar 2025 18日目の記事です。

こんにちは、DXソリューション部の市川です。DXソリューション部ではAIエージェントを活用した製品の販売・開発の受託を行っています。今回は調査の過程で学んだことを記事にしたいと思います。

今回作るもの

OpenAIのcookbookやPerplexityのDeep Researchの構成を参考に、以下のエージェント群を使ってDeep Researchを実装します。

エージェント

  1. Planner:
    • ユーザーの質問の意図を理解し、どのサブエージェントを使うかを判断します
    • 実行順序や依存関係を決定します。大まかな実行手順はあらかじめプロンプトで指示しておきます
    • 各エージェントの出力を統合してレポートを生成します
  2. Web Searcher:
    • Web検索を実行し、他のエージェントで利用しやすい形式に整形します。基本的にはPlannerの提示した検索キーワードを使って検索を行います
  3. Summarizer:
    • 検索結果を要約し、他のエージェントに渡しやすいデータ構造に整形します
  4. Evaluator:
    • 情報の信頼性をチェックし、再調査が必要かどうかPlannerにフィードバックを与えます

実行フロー

セットアップ

pip install openai-agents python-dotenv

コード

import asyncio
import os
from datetime import datetime

from agents import Agent, Runner, WebSearchTool, set_tracing_export_api_key
from dotenv import load_dotenv

# .envファイルにOpenAIのAPIキーを設定
load_dotenv()

# OpenAIのダッシュボード連携
set_tracing_export_api_key(os.getenv("OPENAI_API_KEY"))

# --- Sub Agents ---
searcher_agent = Agent(
    name="web-searcher",
    instructions=(
        "あなたはWeb検索エージェントです。与えられた検索クエリについてWeb検索を行い、"
        "信頼できる公開情報を3〜5件取得してください。"
        "結果は日本語で、JSON配列形式で返します。形式は次の通りです:"
        "[{title: タイトル, url: URL, snippet: 要約}]"
    ),
    tools=[WebSearchTool()],
)

summarizer_agent = Agent(
    name="summarizer",
    instructions=(
        "あなたは要約エージェントです。与えられた複数の検索結果をもとに、"
        "Markdown形式で要約を作成してください。"
        "出力には次の3つのセクションを含めます:\n"
        "1. 要点(3〜5項目の箇条書き)\n"
        "2. 補足情報\n"
        "3. 参考リンク(URLのみのリスト)"
    ),
)

evaluator_agent = Agent(
    name="evaluator",
    instructions=(
        "あなたは評価エージェントです。"
        "要約と元情報の品質を次の3点から評価します:\n"
        "1. カバレッジ\n"
        "2. 情報が新しいか\n"
        "3. 信頼性\n\n"
        "十分であれば「OK」とだけ返してください。"
        "もし不十分な場合は、次の形式で再調査リクエストを出します:\n"
        "`REQUEST_RESEARCH: (再検索の方針を短く記述)`\n\n"
        "例: `REQUEST_RESEARCH: 国内企業の事例を中心に再調査してください`\n\n"
        "注意:\n"
        "あなたは過去のある時点までの情報しか学習していないため、"
        f"現在の日付 {datetime.now().strftime('%Y-%m-%d')} と知識の乖離があることに注意してください。"
    ),
)

# --- Planner ---
instructions = """
あなたはリサーチ全体を統括するプランナーです。

目的:ユーザーの質問に対して、Web検索・要約・評価を組み合わせ、
最終的に信頼性の高いMarkdown形式のレポートを作成します。

手順:
1. 質問内容を分析し、検索クエリを最大3つ作成します。
   (例:「日本 国内 生成AI 導入 2025」など)
2. 作成したクエリを web-searcher に渡して検索を実行します。
3. 得られた検索結果を summarizer に渡し、要約レポートを作成します。
4. 要約を evaluator に渡して評価します。
5. evaluator が 'OK' を返した場合、そのレポートを最終出力とします。
6. evaluator が 'REQUEST_RESEARCH:' を返した場合、指示内容を参考に
   再度1〜4の手順を再度実行します(2回まで)
7. 2回目でも 'OK' が得られなければ、
   不足している点を記した暫定レポートとして出力します。

出力は必ず日本語のMarkdown形式で作成してください。
"""

planner = Agent(
    name="planner",
    instructions=instructions,
    tools=[
        searcher_agent.as_tool(
            tool_name=searcher_agent.name, tool_description="Web検索を実行し、検索結果をJSONで返す"
        ),
        summarizer_agent.as_tool(
            tool_name=summarizer_agent.name,
            tool_description="検索結果を要約し、Markdownレポートを生成する",
        ),
        evaluator_agent.as_tool(
            tool_name=evaluator_agent.name,
            tool_description="レポートを評価し、再調査が必要か判定する",
        ),
    ],
)

if __name__ == "__main__":
    question = "2025年のワールドシリーズでの山本由伸選手の活躍について調べてください。"
    result = asyncio.run(Runner.run(planner, input=question))
    print(result.final_output)

Output

# 2025年ワールドシリーズにおける山本由伸選手の活躍まとめ

## 概要
ロサンゼルス・ドジャースの山本由伸投手は、2025年ワールドシリーズで歴史的な活躍を見せ、ワールドシリーズMVP("Willie Mays World Series MVP")を受賞しました。ドジャースの2年連続優勝に大きく貢献し、そのパフォーマンスは主要海外メディアやMLB公式でも高く評価されています。

## 主な活躍内容

- **第2戦**: 4安打完投勝利(8奪三振、無四球)
- **第6戦**: 6回を投げて勝利投手
- **第7戦**: 延長戦の2 2/3回を無失点リリーフし、優勝を決定付ける投球

## シリーズ通算成績
- 投球回数:17 2/3回
- 勝利:3勝(2001年ランディ・ジョンソン以来の快挙)
- 防御率:1.02
- 奪三振:15
- 四球:2
- 失点:2
- 被安打:10

## 偉業・意義
- 同じワールドシリーズで3勝をあげたのは2001年以来で、日本人投手としては史上初の快挙。
- 2015年以来のワールドシリーズでの完投勝利。
- “Willie Mays World Series MVP”受賞は、日本人投手初。
- ドジャースの第7戦優勝を決定づけたリリーフ登板は大きな見せ場となった。

## 評価・波及効果
- メジャーリーグ公式サイトやAP通信、Reutersなど多数の主要報道機関が山本投手の歴史的功績を讃えています。
- MVP受賞により、山本選手は名実ともに世界トップクラスの投手として認知されることになり、今後の日本人選手の活躍にも大きな影響を与えると見られています。

## 参考リンク
- [MLB公式: 受賞報道](https://www.mlb.com/news/yoshinobu-yamamoto-wins-2025-world-series-mvp)
- [Reuters: 詳細レポート](https://www.reuters.com/sports/dodgers-yamamoto-named-world-series-most-valuable-player-2025-11-02/)
- [APNews: 試合展開詳細](https://apnews.com/article/5c86d71ebfd8544a75a6bc526df9b8c9)

---

*最終調査ではMLB公式を含む複数の信頼できる一次報道を参照し、事実の裏付けを行いました。*

いい感じ!

Traces

OpenAIのダッシュボードから各エージェントの呼び出し履歴をTracesから確認することができます。右側には呼び出しタイミングと実行時間が表示されます。

traces.png

図をみると、実行フローで想定したように web-searcher が並列に稼働していることが確認できました。以下で述べられているように、Agents SDK では特に設定せずとも必要に応じて並列でツールを実行する場合があります。

Orchestrating multiple agents - OpenAI Agents SDK

ここで、注目したいのが1回目の summarizer と evaluator の呼び出しタイミングが同じとなっていることです。planner の意図を想像すると summarizer の出力を評価するよりも、同じ元データを直接評価した方が効率的と判断した可能性があります(評価するのは結局のところ web-search 結果の信憑性のため)

また、2回目の summarizer 実行後に evaluator が呼び出されず、そのままレポートが出力されています。このときの planner の意図を想像すると、1回目の evaluator の要望が達成されたため、再び評価を行う必要はないと判断したのかもしれません。

このように、planner はプロンプトで指定した手順通りにサブエージェントを呼び出すのではなく、必要に応じてワークフローを最適化するように動作することが期待されます。これは最終的なアウトプットのみが重要で、途中結果は問われないタスクにおいて、特に有効だと言えそうです。

まとめ

本記事ではOpenAI Agents SDKを使って簡単なDeep Researchエージェント群を作成しました。非常に少ない記述でマルチエージェントを構築し、トレースまでできるため、デモやPoCに最適なフレームワークだと思いました。ファイルサーチやMCPとも簡単に連携できるので、web以外のデータにも自然に拡張できるのが嬉しいですね。

9
0
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
9
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?