0Pricing
AI Agents · レッスン

ディープリサーチループのパターン

クエリ → 読み取り → 抽出 → 統合 → 再検索というマルチホップ調査を学びます。

「ディープリサーチループのパターン」はCoddyKit上の無料AI Agentsレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Agents学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Agentsコースには全4レッスンが含まれています。

ディープリサーチループとは

ディープリサーチループは、エージェントが検索、読み取り、知識の不足している部分の特定、再検索を繰り返し、包括的な回答を書くのに十分な情報を集めるまで続けるエージェントパターンです。

1回の検索とは異なり、このパターンは人間の調査員の働き方を模倣します。探索 → 学習 → 未知の部分の発見 → さらに深く調査、という流れです。

ループアーキテクチャの概要

ディープリサーチループには、繰り返し実行する5つのフェーズがあります。

  1. 初期クエリ — ユーザーの元の質問で検索する
  2. 上位の結果を読む — 最も優れた3つの情報源から重要な事実を抽出する
  3. 不足部分を特定する — まだ回答されていない重要な疑問は何かを確認する
  4. 追加クエリ — 不足部分を調べるための対象を絞った検索を生成する
  5. 統合する — 収集したすべての事実を最終回答にまとめる
def deep_research(question, max_iterations=3):
    all_facts = []
    queries_used = [question]

    for iteration in range(max_iterations):
        results = search_and_rank(queries_used[-1])
        facts = extract_facts(results, question)
        all_facts.extend(facts)

        gaps = identify_knowledge_gaps(question, all_facts)
        if not gaps:
            print(f'Research complete after {iteration + 1} iterations')
            break

        follow_up = generate_follow_up_query(gaps)
        queries_used.append(follow_up)
        print(f'Iteration {iteration + 1}: {follow_up}')

    return synthesize_answer(question, all_facts)

フェーズ1:初期検索

最初の検索では、ユーザーの元の質問を使用します。3〜5件の結果を取得し、生のテキストコンテンツを抽出します。このフェーズの目的は幅広く調べ、トピック全体の概要を把握することです。

from tavily import TavilyClient
import os

client = TavilyClient(api_key=os.getenv('TAVILY_API_KEY'))

def initial_search(question, n_results=5):
    results = client.search(
        query=question,
        max_results=n_results,
        search_depth='advanced'  # deeper extraction for research tasks
    )
    return results.get('results', [])

# Also capture the direct answer if available
def get_direct_answer(question):
    results = client.search(query=question, max_results=3)
    return results.get('answer', '')  # Tavily's synthesized answer

フェーズ2:重要な事実の抽出

生の検索結果をLLMに渡し、調査の質問に関連する、具体的で検証可能な事実を抽出するよう依頼します。事実は原子的である必要があります。つまり、1つの項目につき1つの主張にします。

EXTRACT_FACTS_PROMPT = '''You are a research assistant.
From the search results below, extract all factual claims relevant to the question.

Question: {question}

Search results:
{results_text}

Return a JSON list of facts:
["GPT-4 was released in March 2023",
 "GPT-4 supports 128k context window",
 ...]

Only include verifiable facts. No opinions or summaries. JSON:'''

def extract_facts(results, question):
    import json
    results_text = '\n\n'.join(
        f"[{i+1}] {r['title']}\n{r['content'][:600]}"
        for i, r in enumerate(results)
    )
    response = llm_call(EXTRACT_FACTS_PROMPT.format(
        question=question, results_text=results_text
    ))
    return json.loads(response)

フェーズ3:知識の不足部分の特定

検索を繰り返すたびにLLMへ、「これまでに分かっていることを踏まえると、元の質問の重要な側面で、まだ扱われていないものは何か」と尋ねます。

こうして見つかった不足部分が、次の検索クエリになります。

GAPS_PROMPT = '''You are a research analyst.

Original research question: {question}

Facts gathered so far:
{facts}

What important aspects of the question are still NOT covered by these facts?
List 2-3 specific knowledge gaps as a JSON array of strings.
If the question is fully answered, return an empty array [].

JSON:'''

def identify_knowledge_gaps(question, facts):
    import json
    facts_text = '\n'.join(f'- {f}' for f in facts)
    response = llm_call(GAPS_PROMPT.format(
        question=question, facts=facts_text
    ))
    return json.loads(response)

フェーズ4:追加クエリの生成

知識の不足部分を、効果的な検索クエリに変換します。「料金モデルが分かっていない」という不足部分は、「GPT-4 APIのトークン単価 2024」のような対象を絞ったクエリになります。

QUERY_GEN_PROMPT = '''Convert these knowledge gaps into specific web search queries.

Original topic: {topic}
Knowledge gaps:
{gaps}

Return a JSON array of search query strings.
Make each query specific and searchable.
JSON:'''

def generate_follow_up_queries(topic, gaps):
    import json
    gaps_text = '\n'.join(f'- {g}' for g in gaps)
    response = llm_call(QUERY_GEN_PROMPT.format(
        topic=topic, gaps=gaps_text
    ))
    queries = json.loads(response)
    return queries[:3]  # max 3 follow-up queries per iteration

終了条件

明確な終了条件がないと、ループは永遠に実行されます。次のいずれかに該当したら停止します。(1) 不足部分が特定されない、(2) 最大反復回数に達する、(3) トークン予算を使い切る、(4) 新しい事実が既存の事実と似すぎている(限界効用が低下する)。

MAX_ITERATIONS = 4
MAX_FACTS = 50
MIN_NEW_FACTS_TO_CONTINUE = 3

def should_continue(gaps, all_facts, new_facts, iteration):
    if iteration >= MAX_ITERATIONS:
        print(f'Stopping: max iterations ({MAX_ITERATIONS}) reached')
        return False
    if not gaps:
        print('Stopping: no knowledge gaps found')
        return False
    if len(all_facts) >= MAX_FACTS:
        print(f'Stopping: fact budget ({MAX_FACTS}) reached')
        return False
    if len(new_facts) < MIN_NEW_FACTS_TO_CONTINUE:
        print(f'Stopping: diminishing returns ({len(new_facts)} new facts)')
        return False
    return True

if __name__ == '__main__':
    print('Continue?', should_continue(gaps=['gap1'], all_facts=['f'] * 10, new_facts=['f1', 'f2', 'f3'], iteration=1))
    print('Continue?', should_continue(gaps=[], all_facts=['f'] * 10, new_facts=['f1'], iteration=1))

フェーズ5:最終回答の統合

ループが終了したら、収集したすべての事実をLLMに渡して統合させます。LLMの役割は、情報源を明示しながら、事実を一貫性のある構造化された回答に整理することです。

SYNTHESIS_PROMPT = '''You are a research writer.

Original question: {question}

Researched facts (gathered from {n_iterations} search iterations):
{facts}

Write a comprehensive, well-structured answer based on these facts.
Format with clear sections. Be specific and cite facts where relevant.
If any aspect of the question could not be fully answered, say so.

Answer:'''

def synthesize_answer(question, all_facts, n_iterations):
    facts_text = '\n'.join(f'- {f}' for f in all_facts)
    return llm_call(SYNTHESIS_PROMPT.format(
        question=question,
        facts=facts_text,
        n_iterations=n_iterations
    ))

反復をまたいだ情報源の追跡

複数回の反復を行うループでは、多くの異なる情報源から事実を収集します。最終回答で正確に引用できるように、それぞれの事実がどの情報源に由来するかを追跡します。

def extract_facts_with_sources(results, question):
    import json

    PROMPT = '''Extract facts from these search results. For each fact include the source URL.

Question: {question}
Results: {results_text}

Return JSON list:
[{{"fact": "GPT-4 supports 128k context", "source": "https://openai.com/..."}}, ...]
JSON:'''

    results_text = '\n\n'.join(
        f"[URL: {r['url']}]\n{r['content'][:500]}"
        for r in results
    )
    response = llm_call(PROMPT.format(
        question=question, results_text=results_text
    ))
    return json.loads(response)

検索の並列実行

追加クエリが複数ある場合は、asyncioを使って並列実行し、調査全体にかかる時間を短縮します。これにより、3回の反復からなるループを30秒から15秒に短縮できる場合があります。

import asyncio

async def async_search(client, query):
    # Tavily has async support
    loop = asyncio.get_event_loop()
    result = await loop.run_in_executor(
        None,
        lambda: client.search(query=query, max_results=3)
    )
    return result.get('results', [])

async def parallel_search(queries):
    tasks = [async_search(client, q) for q in queries]
    results_list = await asyncio.gather(*tasks)
    # Flatten
    return [r for results in results_list for r in results]

# Run in event loop
all_results = asyncio.run(parallel_search(follow_up_queries))

事実の重複除去

異なる情報源が、同じ事実を異なる表現で述べていることがよくあります。統合する前に埋め込みの類似度を使って事実を重複除去し、最終回答で同じ情報を何度も繰り返さないようにします。

def deduplicate_facts(facts, similarity_threshold=0.92):
    if not facts:
        return facts

    # Get embeddings for all facts
    embeddings = [embed(f) for f in facts]
    unique_indices = [0]  # always keep first

    for i in range(1, len(facts)):
        is_duplicate = False
        for j in unique_indices:
            sim = cosine_similarity(embeddings[i], embeddings[j])
            if sim > similarity_threshold:
                is_duplicate = True
                break
        if not is_duplicate:
            unique_indices.append(i)

    unique_facts = [facts[i] for i in unique_indices]
    print(f'Deduplicated: {len(facts)} -> {len(unique_facts)} facts')
    return unique_facts

知識チェック

知識の不足部分が見つからなかった場合、ディープリサーチループの正しい終了条件は何ですか?

復習:ディープリサーチループパターン

ディープリサーチループパターンは、検索 → 事実の抽出 → 不足部分の特定 → 追加クエリの生成 → 繰り返し → 統合という流れです。これは人間の調査員の働き方を模倣しています。

主な設計上の判断には、終了条件(最大反復回数、不足部分がないこと、限界効用の低下)、帰属のための情報源追跡、速度向上のための並列検索、統合前の事実の重複除去があります。深さとコスト、遅延のバランスを取るため、反復回数は3〜4回に制限します。

よくある質問

「ディープリサーチループのパターン」レッスンは無料ですか?

はい。「ディープリサーチループのパターン」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Agentsコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Agentsコースには全4レッスンが含まれています。

「ディープリサーチループのパターン」で何を学びますか?

クエリ → 読み取り → 抽出 → 統合 → 再検索というマルチホップ調査を学びます。 ブラウザで直接実行するハンズオンコードでAI Agentsを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

AI Agentsを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAI Agentsは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「ディープリサーチループのパターン」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAI Agentsレッスンでコードを書いて実行できますか?

はい。すべてのAI Agentsレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. エージェント検索向けTavilyとSerpAPI
  2. 検索結果のランキングとフィルタリング
  3. ディープリサーチループのパターン
  4. Web検索とRAGの組み合わせ
← AI Agentsに戻る