0Pricing
AI Agents · 课时

深度研究循环模式

查询 → 阅读 → 提取 → 综合 → 再次查询的多跳研究流程。

深度研究循环模式 是 CoddyKit 上的免费 AI Agents 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 AI Agents 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 AI Agents 课程共包含 4 节课。

什么是深度研究循环

深度研究循环是一种智能体模式:智能体会反复搜索、阅读、识别知识缺口并再次搜索,直到收集到足够的信息来撰写全面的答案。

与单次搜索不同,这种模式模拟了人类研究者的工作方式:探索 → 学习 → 发现未知内容 → 深入研究。

循环架构概览

深度研究循环包含五个重复执行的阶段:

  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,并要求它提取与研究问题相关的具体且可验证的事实。事实应当是原子的,也就是每项只包含一个陈述。

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 每个令牌的接口价格 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 次迭代,以平衡研究深度、成本和延迟。

常见问题解答

「深度研究循环模式」课时是免费的吗?

是的 — 「深度研究循环模式」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 AI Agents 课程的其余内容,请升级到 CoddyKit PRO。 AI Agents 课程共包含 4 节课。

「深度研究循环模式」这节课中我会学到什么?

查询 → 阅读 → 提取 → 综合 → 再次查询的多跳研究流程。 你通过在浏览器中直接运行的动手代码来练习 AI Agents,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 AI Agents 需要有经验吗?

无需任何先前经验。CoddyKit 上的 AI Agents 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「深度研究循环模式」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 AI Agents 课中编写并运行代码吗?

能。每节 AI Agents 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 Tavily 和 SerpAPI 搜索
  2. 对搜索结果进行排序与筛选
  3. 深度研究循环模式
  4. 结合网络搜索与 RAG
← 返回 AI Agents