AI Agents · Lekcja

Wzorzec pętli pogłębionego researchu

Zapytanie → odczyt → ekstrakcja → synteza → ponowne zapytanie: wieloetapowy research.

Lekcja 3 z 413 kroki

Wzorzec pętli pogłębionego researchu to bezpłatna lekcja AI Agents na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Agents, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Agents zawiera 4 lekcji w sumie.

Czym jest pętla pogłębionego researchu

Pętla pogłębionego researchu to wzorzec agenta, w którym agent iteracyjnie wyszukuje informacje, czyta je, identyfikuje luki w wiedzy i ponownie wyszukuje dane, aż zgromadzi wystarczająco dużo informacji do napisania wyczerpującej odpowiedzi.

W przeciwieństwie do pojedynczego wyszukiwania ten wzorzec naśladuje sposób pracy ludzkiego badacza: eksploracja → nauka → odkrywanie niewiadomych → pogłębianie analizy.

Przegląd architektury pętli

Pętla pogłębionego researchu składa się z pięciu powtarzających się faz:

  1. Początkowe zapytanie — wyszukiwanie na podstawie oryginalnego pytania użytkownika
  2. Odczytanie najważniejszych wyników — wyodrębnienie kluczowych faktów z 3 najlepszych źródeł
  3. Identyfikacja luk — jakie ważne pytania pozostają bez odpowiedzi?
  4. Zapytania uzupełniające — generowanie ukierunkowanych wyszukiwań dotyczących luk
  5. Synteza — połączenie wszystkich zebranych faktów w końcową odpowiedź
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)

Faza 1: Wyszukiwanie początkowe

Pierwsze wyszukiwanie wykorzystuje oryginalne pytanie użytkownika. Należy pobrać 3–5 wyników i wyodrębnić z nich surową treść tekstową. Ta faza koncentruje się na szerokim rozpoznaniu tematu — uzyskaniu ogólnego obrazu jego zakresu.

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

Faza 2: Wyodrębnianie najważniejszych faktów

Należy przekazać surowe wyniki wyszukiwania do LLM-a i poprosić go o wyodrębnienie konkretnych, weryfikowalnych faktów istotnych dla pytania badawczego. Fakty powinny być atomowe — jeden fakt na element.

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)

Faza 3: Identyfikowanie luk w wiedzy

Po każdej iteracji wyszukiwania należy zapytać LLM-a: biorąc pod uwagę dotychczasową wiedzę, jakie ważne aspekty oryginalnego pytania wciąż nie zostały omówione?

Te luki stają się zapytaniami w kolejnej rundzie wyszukiwania.

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)

Faza 4: Generowanie zapytań uzupełniających

Luki w wiedzy należy przekształcić w skuteczne zapytania wyszukiwania. Luka w rodzaju „Nie znamy modelu cenowego” staje się ukierunkowanym zapytaniem, takim jak „GPT-4 API pricing per token 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

Kryteria zakończenia

Bez jasno określonych kryteriów zakończenia pętla będzie działać bez końca. Należy ją zatrzymać, gdy: (1) nie zidentyfikowano żadnych luk, (2) osiągnięto maksymalną liczbę iteracji, (3) wyczerpano budżet tokenów lub (4) nowe fakty są zbyt podobne do już istniejących (malejące korzyści).

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))

Faza 5: Synteza końcowej odpowiedzi

Po zakończeniu pętli należy przekazać wszystkie zebrane fakty do LLM-a w celu ich syntezy. Zadaniem LLM-a jest uporządkowanie faktów w spójną, dobrze zorganizowaną odpowiedź z przypisaniem informacji do źródeł.

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
    ))

Śledzenie źródeł w kolejnych iteracjach

W pętli obejmującej wiele iteracji fakty są zbierane z wielu różnych źródeł. Należy śledzić źródło każdego faktu, aby końcowa odpowiedź mogła dokładnie je cytować.

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)

Równoległe wykonywanie wyszukiwań

W przypadku wielu zapytań uzupełniających należy wykonywać je równolegle za pomocą asyncio, aby skrócić łączny czas researchu. Może to skrócić pętlę obejmującą 3 iteracje z 30 do 15 sekund.

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))

Deduplikacja faktów

Różne źródła często przedstawiają ten sam fakt innymi słowami. Przed syntezą należy usunąć duplikaty faktów za pomocą podobieństwa embeddingów, aby uniknąć wielokrotnego powtarzania tych samych informacji w końcowej odpowiedzi.

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

Sprawdzenie wiedzy

Jaki jest prawidłowy warunek zakończenia pętli pogłębionego researchu, gdy nie znaleziono żadnych luk w wiedzy?

Podsumowanie: wzorzec pętli pogłębionego researchu

Wzorzec pętli pogłębionego researchu wygląda następująco: wyszukiwanie → wyodrębnianie faktów → znajdowanie luk → generowanie zapytań uzupełniających → powtarzanie → synteza. Odzwierciedla on sposób pracy ludzkiego badacza.

Najważniejsze decyzje projektowe to: kryteria zakończenia (maksymalna liczba iteracji, brak luk, malejące korzyści), śledzenie źródeł na potrzeby przypisywania informacji, równoległe wyszukiwanie w celu zwiększenia szybkości oraz deduplikacja faktów przed syntezą. Należy ograniczyć pętlę do 3–4 iteracji, aby zachować równowagę między głębią, kosztem i opóźnieniem.

Bezpłatny start

Ucz się AI Agents dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
60
Lekcje
239

Często zadawane pytania

Czy lekcja „Wzorzec pętli pogłębionego researchu” jest bezpłatna?

Tak — pełny tekst „Wzorzec pętli pogłębionego researchu” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Agents, przejdź na CoddyKit PRO. Kurs AI Agents zawiera 4 lekcji w sumie.

Co nauczysz się w „Wzorzec pętli pogłębionego researchu”?

Zapytanie → odczyt → ekstrakcja → synteza → ponowne zapytanie: wieloetapowy research. Ćwiczysz AI Agents z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć AI Agents?

Nie wymagamy żadnego doświadczenia. AI Agents w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Wzorzec pętli pogłębionego researchu”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji AI Agents?

Tak. Każda lekcja AI Agents zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Tavily i SerpAPI do wyszukiwania przez agenta
  2. Ranking i filtrowanie wyników wyszukiwania
  3. Wzorzec pętli pogłębionego researchu
  4. Łączenie wyszukiwania internetowego z RAG
← Powrót do AI Agents