Bez KYC — bez dowodu, bez selfie, bez dokumentów. Płać kryptowalutą: BTC, USDT, USDC, ETH, SOL, LTC
Język: Polski
Pobierz klucz API

Przewodnik · Python · około 60 linii, dowolny LLM

Zbuduj agenta deep research w Pythonie z API wyszukiwania w sieci

Deep research to pętla, a nie model. Ten przewodnik buduje taką, którą przeczytasz w kilka minut: planuje zapytania, wyszukuje w sieci z tekstem stron, trzyma każde źródło tylko raz, szuka luk i pisze odpowiedź z numerowanymi cytatami.

Ostatnia aktualizacja: · 5 min czytania

Szybka odpowiedź

Jak zbudować agenta deep research w Pythonie?

Napisz pętlę, która prosi LLM o zapytania do wyszukiwania, przepuszcza każde przez API wyszukiwania w sieci zwracające tekst stron, trzyma każde źródło tylko raz, prosi o zapytania uzupełniające, a następnie pisze odpowiedź z cytatami. Z LLMWebSearch każde wyszukiwanie zwraca pierwsze 3 strony jako Markdown za jeden kredyt; poniższy skrypt wykonuje sześć wyszukiwań na pytanie. Od 1,20 USD/1K wyszukiwań, bez KYC, płatność kryptowalutą.

Co będzie robił agent?

  1. Plan

    Poproś model o cztery krótkie zapytania, które razem pokrywają pytanie.

  2. Wyszukiwanie

    Uruchom każde zapytanie z read=3, żeby pierwsze trzy strony wróciły jako Markdown.

  3. Trzymaj źródła tylko raz

    Przechowuj wyniki według URL i pomijaj strony już zebrane lub bez tekstu.

  4. Znajdź luki

    Pokaż modelowi dotychczas znalezione tytuły i poproś o dwa zapytania o to, czego brakuje.

  5. Napisz

    Ponumeruj do 12 źródeł i poproś o odpowiedź cytującą je jako [1], [2].

Czego potrzebuję przed rozpoczęciem?

Trzy rzeczy:

  • Klucz API LLMWebSearch w zmiennej środowiskowej LLMWEBSEARCH_API_KEY. Klucze pojawiają się w panelu po pierwszym pakiecie.
  • Dowolny endpoint czatu zgodny z OpenAI, ustawiony przez LLM_BASE_URL, LLM_API_KEY i LLM_MODEL. Modele hostowane i lokalne serwery działają równie dobrze.
  • Python 3.9 lub nowszy z pakietem requests.

Skrypt używa zwykłego HTTP dla obu usług, więc możesz podmienić model bez zmiany kodu wyszukiwania.

Python: deep_research.py
import os

import requests

SEARCH = "https://llmwebsearch.com/api/v1/search"
SEARCH_HEADERS = {"Authorization": "Bearer " + os.environ["LLMWEBSEARCH_API_KEY"]}
# Any OpenAI-compatible chat endpoint works here: set your own base URL, key and model name.
LLM_URL = os.environ.get("LLM_BASE_URL", "https://llm.example.com/v1") + "/chat/completions"
LLM_HEADERS = {"Authorization": "Bearer " + os.environ.get("LLM_API_KEY", "")}
MODEL = os.environ.get("LLM_MODEL", "your-model-name")


def ask_llm(prompt):
    body = {"model": MODEL, "messages": [{"role": "user", "content": prompt}]}
    resp = requests.post(LLM_URL, headers=LLM_HEADERS, json=body, timeout=120)
    resp.raise_for_status()
    return resp.json()["choices"][0]["message"]["content"]


def plan_queries(question, n=4):
    text = ask_llm(f"Write {n} short web search queries, one per line, to answer: {question}")
    queries = [line.strip("-*0123456789. ").strip() for line in text.splitlines()]
    return [q for q in queries if q][:n]


def search(query):
    body = {"q": query, "max_results": 5, "read": 3, "max_chars": 5000}
    resp = requests.post(SEARCH, headers=SEARCH_HEADERS, json=body, timeout=60)
    resp.raise_for_status()
    return resp.json()["results"]


def research(question, rounds=2):
    sources = {}  # url -> result, so the same page is never cited twice
    queries = plan_queries(question)
    for _ in range(rounds):
        for query in queries:
            for r in search(query):
                if r.get("content_status") == "ok" and r["url"] not in sources:
                    sources[r["url"]] = r
        notes = "\n".join(f"- {r['title']}" for r in sources.values())
        queries = plan_queries(f"{question}\nAlready found:\n{notes}\nWhat is still missing?", n=2)
    numbered = list(sources.values())[:12]
    context = "\n\n".join(
        f"[{i}] {r['title']} ({r['url']})\n{r['content']}" for i, r in enumerate(numbered, 1)
    )
    prompt = (
        "Answer the question using only the sources below. Cite them as [1], [2]. "
        "Say so when the sources disagree or do not cover a point.\n\n"
        f"Question: {question}\n\nSources:\n{context}"
    )
    return ask_llm(prompt), [r["url"] for r in numbered]


if __name__ == "__main__":
    answer, urls = research("What changed in the EU rules for general-purpose AI models in 2025?")
    print(answer)
    for i, url in enumerate(urls, 1):
        print(f"[{i}] {url}")

Jak działa każda część?

plan_queries prosi model o krótkie zapytania, jedno na linię, i usuwa znaczniki listy. Krótkie zapytania lepiej pasują do tego, jak wyszukiwarki rankują strony, niż pełne pytania.

search wywołuje POST https://llmwebsearch.com/api/v1/search z max_results=5, read=3 i max_chars=5000. Odpowiedź zawiera pięć wyników; pierwsze trzy niosą tekst strony w content.

research prowadzi rundy. Trzyma źródła w słowniku kluczowanym po URL, więc strona znaleziona przez dwa zapytania liczy się raz. Zachowywane są tylko wyniki z content_status równym ok, bo odpowiedź musi opierać się na tekście, który model może przeczytać.

Po każdej rundzie model widzi dotychczas zebrane tytuły i proponuje dwa nowe zapytania o to, czego brakuje. Końcowy prompt numeruje do dwunastu źródeł i ustala zasady cytowania.

Ile kosztuje jeden raport?

Sześć wyszukiwań na pytanie przy domyślnych ustawieniach: cztery w pierwszej rundzie i dwa w drugiej. Przy read równym 3 to sześć kredytów. 25 000 wyszukiwań przy 41,25 USD pokrywa więc ponad 4 000 raportów.

Wywołania modelu kosztują dodatkowo na Twoim rachunku za LLM: trzy wywołania planujące i jedno długie wywołanie odpowiedzi na raport. Wywołanie odpowiedzi niesie do dwunastu stron po 5 000 znaków, więc obniż max_chars, jeśli Twój model jest drogi.

Jak sprawić, żeby szło głębiej?

Zmień liczby, nie strukturę:

  • Więcej rund. rounds=4 pozwala modelowi ścigać jeszcze dwa zestawy luk.
  • Więcej zapytań na rundę. Podnieś n w wywołaniu szukającym luk z 2 do 4.
  • Węższe źródła. Dodaj include_domains do treści zapytania wyszukiwania, aby ograniczyć się do oficjalnych lub akademickich stron.
  • Tylko świeże materiały. Dodaj "time_range": "month" lub "topic": "news".
  • Więcej stron na zapytanie. read=5 czyta pięć stron, po 2 kredyty za wyszukiwanie.

Dodaj regułę zatrzymania, zanim podniesiesz limity: zakończ pętlę, gdy runda przyniesie mniej niż dwa nowe źródła.

Jak zadbać o bezpieczeństwo i kulturę agenta?

Traktuj każdą stronę jako niezaufany tekst. Końcowy prompt mówi modelowi, aby traktował źródła wyłącznie jako dowody; dodaj wyraźną linię, że instrukcje zawarte w źródłach należy ignorować. Nigdy nie pozwól, aby źródło wywołało narzędzie lub zapis do pliku.

Po stronie sieci Nasz czytnik respektuje robots.txt: przedstawia się jako LLMWebSearch, przestrzega reguł, które witryna zapisuje dla niego lub dla wszystkich robotów, i pomija treść każdej strony, której nie wolno mu czytać. Strony, które odmawiają dostępu, wracają bez treści, a skrypt po prostu je pomija. Gdy witryna odrzuca nasz czytnik, wynik wraca bez treści i ze statusem witryny: nigdy nie rozwiązujemy CAPTCHA, nie logujemy się na konta ani nie obchodzimy blokady czy paywalla.

Co może pójść nie tak?

W testach wychodzą trzy rzeczy:

  • Niejasne zapytania. Jeśli plan jest słaby, każda runda znajduje te same strony. Poproś model o zapytania z konkretnymi nazwami i datami.
  • Zbyt mało źródeł z tekstem. Niektóre tematy są za paywallem. Poszerz zapytania lub pozwól na więcej wyników.
  • Zbyt długie prompty. Dwanaście długich stron może przekroczyć kontekst małego modelu. Zmniejsz max_chars lub zostaw osiem źródeł.

Loguj każde zapytanie i zwrócone przez nie URL-e. Czytanie tego logu to najszybszy sposób na poprawę promptu planu.

Agent do pogłębionego researchu: najczęstsze pytania

Czy mogę uruchomić to na lokalnym modelu?

Tak, jeśli lokalny serwer obsługuje format OpenAI chat-completions. Ustaw LLM_BASE_URL na jego adres, a LLM_MODEL na nazwę modelu.

Czy mogę zamienić to w narzędzie MCP?

Tak. Owiń research() w narzędzie MCP albo daj swojemu agentowi zwykłe narzędzie wyszukiwania ze strony MCP i pozwól mu samodzielnie prowadzić pętlę.

Dlaczego nie zapytać search API bezpośrednio o odpowiedź?

Ponieważ LLMWebSearch nie pisze odpowiedzi. API zwraca źródła, a nie gotową odpowiedź: Twój własny model czyta strony, pisze odpowiedź i cytuje adresy URL.

Jak sprawdzić, ile kosztowało każde wyszukiwanie?

Każda odpowiedź zawiera credits_used, a GET https://llmwebsearch.com/api/v1/credits pokazuje Twoje pozostałe saldo bez żadnych kosztów.

Od 1,20 USD/1K wyszukiwań · bez KYC

Pobierz klucz API