CodeWorlds
Powrót do kolekcji
Przewodnik15 min czytaniaZespół CodeWorlds

Tavily, wyszukiwarka zwracająca gotowy kontekst

Tavily zwraca agentowi fragmenty stron z oceną trafności zamiast listy linków. Kredyty, limit planu darmowego, licencja MIT i realne granice narzędzia.

Tavily, wyszukiwarka zwracająca gotowy kontekst

Tavily to API wyszukiwania zbudowane pod modele językowe: na zapytanie odpowiada zbiorem fragmentów treści z liczbową oceną trafności, a nie listą adresów do samodzielnego pobrania. Pakiet tavily-python ma wersję 0.7.27, pakiet @tavily/core wersję 0.7.7, oba na licencji MIT, a rozliczenie idzie w kredytach wycenionych na 0,008 dolara w trybie płatności za użycie.

Co dokładnie wraca z zapytania

Różnica wobec zwykłego API wyszukiwarki sprowadza się do jednej rzeczy: kto wykonuje pracę między znalezieniem adresu a wrzuceniem tekstu do promptu.

Klasyczne API zwraca to, co widać na stronie wyników: tytuł, adres i krótki opis wygenerowany przez wyszukiwarkę pod kątem człowieka klikającego w link. Żeby model mógł z tego skorzystać, Twój kod musi pobrać każdą stronę, poradzić sobie z renderowaniem po stronie przeglądarki, wyciąć nawigację, stopkę i banery zgód, pociąć tekst na fragmenty i zdecydować, które z nich są istotne dla pytania. To cztery osobne miejsca, w których coś się psuje.

Tavily wykonuje ten łańcuch po swojej stronie i zwraca wynik już przetworzony. W polu results każdy element ma title, url, content oraz score, czyli liczbę zmiennoprzecinkową opisującą trafność względem zapytania. Pole content nie jest opisem ze strony wyników, tylko zbiorem fragmentów wyciętych bezpośrednio z treści, przy czym pojedynczy fragment ma najwyżej 500 znaków, a ich liczbę na źródło ustawia parametr chunks_per_source w zakresie od 1 do 3. Fragmenty sklejane są separatorem [...], więc w tekście widać, gdzie kończy się jeden, a zaczyna drugi.

To przesunięcie odpowiedzialności ma cenę i warto ją nazwać wprost. Płacisz za gotowy kontekst, a nie za surowy materiał, więc tracisz kontrolę nad tym, jak przebiega cięcie tekstu i według czego liczona jest trafność. Algorytm oceny nie jest opisany w dokumentacji, a wartość score nie ma zdefiniowanej skali odniesienia. Sami autorzy w poradniku dobrych praktyk piszą tylko tyle, że wyżej znaczy lepiej, a próg odcięcia zależy od zastosowania. Jeśli budujesz system, w którym musisz umieć wytłumaczyć, dlaczego akurat ten akapit trafił do odpowiedzi, ta nieprzejrzystość będzie przeszkadzać.

Drugie podejście reprezentuje Firecrawl, gdzie kupujesz surowy materiał: podajesz adres, dostajesz oczyszczony markdown całej strony i sam decydujesz o cięciu, ocenie i doborze. Wybór między jednym a drugim to wybór między szybkim wdrożeniem a kontrolą nad procesem, a nie między lepszym i gorszym narzędziem.

Wersje, licencja i stan pakietów

Licencja jest tu czysta, co po audytach innych narzędzi z tej kolekcji brzmi jak komplement. Sprawdziłem trzy źródła i wszystkie mówią to samo.

Plik LICENSE w repozytoriach tavily-ai/tavily-python oraz tavily-ai/tavily-js zawiera tekst licencji MIT z notą o prawach autorskich Alpha AI Technologies Inc. z roku 2024. Pole license w rejestrze npm dla @tavily/core ma wartość MIT. Opublikowane paczki faktycznie zawierają plik licencyjny: archiwum npm ma package/LICENSE, archiwum źródłowe z PyPI ma LICENSE w katalogu głównym, a koło instalacyjne ma go w tavily_python-0.7.27.dist-info/licenses/LICENSE.

Jedna drobna nieścisłość jednak jest. Pole license w metadanych PyPI dla tavily-python jest puste, podobnie jak nowsze pole license_expression. Informacja o MIT siedzi wyłącznie w klasyfikatorze License :: OSI Approved :: MIT License. Narzędzie zbierające licencje wyłącznie z pola license zobaczy więc pustą wartość i oznaczy pakiet jako nieokreślony. To nie jest problem prawny, tylko konfiguracyjny, ale w raporcie zgodności trzeba go umieć wytłumaczyć.

Trzeba przy tym rozdzielić dwie rzeczy. Otwarte na licencji MIT są klienty, czyli kilka tysięcy linii kodu opakowującego wywołania HTTP. Sama wyszukiwarka to zamknięta usługa działająca pod adresem api.tavily.com i nie ma wariantu do samodzielnego uruchomienia. Przywiązanie do dostawcy jest tu realne i pełne: jeśli Tavily zniknie albo podniesie ceny, nie ma ścieżki awaryjnej poza przepisaniem warstwy wyszukiwania na innego dostawcę.

Zależności są skromne. Klient pythonowy ciągnie requests, httpx oraz tiktoken w wersji co najmniej 0.5.1. Klient javascriptowy ciągnie axios, https-proxy-agent i js-tiktoken. Obecność biblioteki liczącej tokeny wynika z tego, że SDK potrafi przyciąć wynik do zadanego budżetu tokenów przed oddaniem go do modelu.

Pierwsze wywołanie i kształt odpowiedzi

Najkrótsza droga do sprawdzenia, czy narzędzie pasuje, nie wymaga nawet konta. Tryb bez klucza włącza się nagłówkiem i obejmuje wyszukiwanie oraz pobieranie treści.

Code
Bash
pip install tavily-python
npm i @tavily/core

curl -X POST https://api.tavily.com/search \
  -H "Content-Type: application/json" \
  -H "X-Tavily-Access-Mode: keyless" \
  -d '{"query": "zmiany w ustawie o dostepnosci cyfrowej", "max_results": 3}'

Dokumentacja opisuje ten tryb jako darmowy i ograniczony częstotliwością, bez podania konkretnego progu. Odpowiedź ma być identyczna co do schematu z wywołaniem z kluczem, więc nadaje się do sprawdzenia jakości wyników przed założeniem konta.

Wywołanie właściwe wygląda tak. Wszystkie nazwy parametrów poniżej pochodzą ze specyfikacji OpenAPI endpointu /search.

Code
Python
from tavily import TavilyClient

client = TavilyClient(api_key="tvly-...")

odpowiedz = client.search(
    query="stan prawny dyrektywy NIS2 w Polsce",
    search_depth="advanced",
    chunks_per_source=3,
    max_results=5,
    topic="general",
    time_range="month",
    include_domains=["gov.pl", "sejm.gov.pl"],
    include_raw_content=False,
    include_answer=False,
    country="poland",
)

for wynik in odpowiedz["results"]:
    print(round(wynik["score"], 3), wynik["url"])
    print(wynik["content"][:200])

Kilka rzeczy z tego wywołania wymaga komentarza. Parametr search_depth przyjmuje cztery wartości: ultra-fast, fast, basic i advanced, uporządkowane od najniższego opóźnienia do najwyższej trafności. Domyślny jest basic. Wariant ultra-fast zachowuje się inaczej niż pozostałe: zwraca jedno streszczenie na źródło zamiast fragmentów, więc chunks_per_source przestaje działać. Parametr max_results ma zakres od 0 do 20 i wartość domyślną 5. Lista include_domains mieści do 300 pozycji, exclude_domains do 150. Parametr country działa wyłącznie przy topic ustawionym na general, więc przy wyszukiwaniu wiadomości nie ma efektu.

Odpowiedź ma stały kształt i to jest jej największa zaleta przy pisaniu kodu.

Code
JSON
{
  "query": "stan prawny dyrektywy NIS2 w Polsce",
  "results": [
    {
      "title": "Krajowy system cyberbezpieczenstwa",
      "url": "https://www.gov.pl/web/baza-wiedzy/nis2",
      "content": "Fragment pierwszy [...] fragment drugi",
      "score": 0.81025416,
      "raw_content": null,
      "id": "a3f9c2-04"
    }
  ],
  "auto_parameters": { "topic": "general", "search_depth": "basic" },
  "response_time": 1.67,
  "usage": { "credits": 1 },
  "request_id": "123e4567-e89b-12d3-a456-426614174111"
}

Pola query, results, images, response_time i answer są w specyfikacji oznaczone jako wymagane. Pole usage pojawia się po ustawieniu include_usage na prawdę i jest jedynym sposobem, żeby poznać koszt pojedynczego wywołania w chwili jego wykonania, zamiast czekać na panel rozliczeniowy.

Pięć endpointów i podział pracy między nimi

Dokumentacja miejscami zaprzecza sama sobie i lepiej to wiedzieć, zanim zaczniesz szukać czegoś, czego rzekomo nie ma. Dział z najczęstszymi pytaniami wymienia trzy endpointy: Search, Extract i Crawl. Referencja API opisuje dodatkowo Map, Research, Usage i Logs. Stan faktyczny odpowiada referencji, dział pytań jest po prostu nieodświeżony.

Podział obowiązków jest sensowny i przekłada się wprost na koszt. Search znajduje strony i zwraca z nich fragmenty. Extract przyjmuje znane adresy i zwraca ich pełną treść. Map przechodzi serwis jak graf i zwraca samą listę adresów, bez pobierania treści. Crawl łączy Map z Extract, czyli przechodzi serwis i od razu pobiera zawartość. Research uruchamia agenta, który wyszukuje, analizuje źródła i pisze raport z przypisami.

Code
Python
tresc = client.extract(
    urls=[
        "https://www.gov.pl/web/baza-wiedzy/nis2",
        "https://eur-lex.europa.eu/eli/dir/2022/2555/oj",
    ],
    extract_depth="advanced",
    format="markdown",
    query="obowiazki podmiotow kluczowych",
    chunks_per_source=5,
    timeout=30,
    include_usage=True,
)

mapa = client.map(url="https://docs.tavily.com", instructions="strony o SDK w Pythonie")

Przy pobieraniu treści extract_depth przyjmuje basic albo advanced, przy czym wariant zaawansowany sięga po tabele i treści osadzone, kosztem dłuższego czasu odpowiedzi. Pole format przyjmuje markdown albo text, domyślnie markdown, a wariant tekstowy bywa wolniejszy. Parametr timeout mieści się w zakresie od 1 do 60 sekund, a bez jawnej wartości obowiązuje 10 sekund dla trybu podstawowego i 30 dla zaawansowanego. Podanie query włącza przesortowanie fragmentów pod kątem intencji i dopiero wtedy działa chunks_per_source, tutaj w zakresie od 1 do 5.

Endpoint Research zachowuje się inaczej niż pozostałe, bo jest asynchroniczny. Tworzysz zadanie, dostajesz request_id i odpytujesz o stan albo słuchasz strumienia.

Code
Python
zadanie = client.research(
    input="Porownaj wymogi raportowania incydentow w NIS2 i w DORA",
    model="pro",
    citation_format="numeric",
    output_length="long",
    include_domains=["eur-lex.europa.eu"],
    stream=False,
)

print(zadanie["request_id"], zadanie["status"])

Model mini opisany jest jako nastawiony na wąskie, dobrze określone pytania, a pro na tematy złożone wymagające wielu ujęć. Ta różnica przekłada się na przedziały kosztu, o czym za chwilę. Osobny limit częstotliwości dla tworzenia zadań badawczych wynosi 20 żądań na minutę i jest ten sam dla kluczy deweloperskich i produkcyjnych, natomiast odpytywanie o stan zadania podlega limitowi ogólnemu.

Kredyty, cennik i limit planu darmowego

Rozliczenie idzie w kredytach, a przelicznik zależy od tego, którego endpointu użyjesz i z jakimi parametrami. Kredyty resetują się pierwszego dnia miesiąca, niezależnie od daty rozliczenia.

OperacjaKoszt w kredytach
Search basic, fast, ultra-fast1 za żądanie
Search advanced2 za żądanie
Extract basic1 za każde 5 udanych pobrań
Extract advanced2 za każde 5 udanych pobrań
Map bez instrukcji1 za każde 10 zwróconych stron
Map z instructions2 za każde 10 zwróconych stron
Crawlsuma kosztu mapowania i pobierania
Research miniod 4 do 110 za żądanie
Research prood 15 do 250 za żądanie

Nieudane pobranie strony nie jest liczone, podobnie jak nieudane mapowanie. Przykład z dokumentacji: przejście dziesięciu stron z podstawowym pobieraniem to 1 kredyt za mapowanie plus 2 za pobranie, razem 3 kredyty. Te same dziesięć stron z pobieraniem zaawansowanym to 1 plus 4, razem 5 kredytów.

Plany miesięczne wyglądają następująco: Researcher daje 1000 kredytów miesięcznie za darmo, Project 4000 kredytów za 30 dolarów, Bootstrap 15 000 kredytów za 100 dolarów, Startup 38 000 kredytów za 220 dolarów, Growth 100 000 kredytów za 500 dolarów. Tryb płatności za użycie kosztuje 0,008 dolara za kredyt. Enterprise wyceniany jest indywidualnie.

Arytmetyka się zgadza, co po doświadczeniach z innymi cennikami wymaga sprawdzenia. Dzieląc cenę przez liczbę kredytów wychodzi kolejno 0,0075, 0,00667, 0,00579 i 0,005 dolara, a dokumentacja podaje 0,0075, 0,0067, 0,0058 i 0,005, czyli te same liczby po zaokrągleniu. Zgadza się też deklarowany zakres planów miesięcznych od 0,0075 do 0,005 dolara za kredyt.

Limit planu darmowego jest realnym ograniczeniem i trzeba go przeliczyć na własne zastosowanie. Tysiąc kredytów to tysiąc wyszukiwań podstawowych albo pięćset zaawansowanych na miesiąc. Agent wykonujący trzy wyszukiwania zaawansowane na rozmowę zużyje ten limit po niecałych 170 rozmowach. Do prototypu wystarczy, do produkcji nie. Jeden zapis w dokumentacji jest przy tym łatwy do przeoczenia: klucze produkcyjne, z limitem 1000 żądań na minutę zamiast 100, wymagają aktywnego planu płatnego albo włączonej płatności za użycie. Na planie darmowym zostajesz przy limicie deweloperskim.

Zniżka dla studentów istnieje, ale warunki nie są opublikowane, a kwalifikację ustala się mailowo z pomocą techniczną. Wsparcie mailowe przysługuje planom płatnym, a umowa na dostępność i czas reakcji wyłącznie planowi Enterprise.

Świeżość wyników i czego nikt nie gwarantuje

To pytanie zadaje się zwykle po pierwszym wpadnięciu na nieaktualną odpowiedź w produkcji, więc lepiej wyjaśnić je wcześniej.

Gwarancji świeżości nie ma żadnej. Dokumentacja opisuje wyniki jako aktualne i czasu rzeczywistego, ale nigdzie nie podaje ani opóźnienia indeksu, ani terminu, w jakim nowa strona staje się wyszukiwalna, ani zobowiązania umownego w tej sprawie. Jedyne wiążące zapisy o dostępności usługi dotyczą planu Enterprise i mówią o czasie działania oraz reakcji wsparcia, a nie o aktualności danych.

To, co dostajesz, to filtry po dacie, a nie obietnica pokrycia. Parametr time_range przyjmuje day, week, month, year oraz ich jednoliterowe skróty. Parametry start_date i end_date przyjmują daty w formacie roczno-miesięczno-dziennym. Dokumentacja zaznacza istotny szczegół: filtrowanie odbywa się według daty publikacji albo daty ostatniej aktualizacji strony. Serwis, który podbija datę modyfikacji przy każdym przebudowaniu, przejdzie przez filtr time_range ustawiony na dzień, mimo że treść pochodzi sprzed lat. Filtr zawęża zbiór, ale go nie weryfikuje.

Praktyczny wniosek jest taki, że przy zastosowaniach zależnych od aktualności trzeba dołożyć własną warstwę kontroli. Ustaw topic na news albo finance, bo te kategorie opisane są jako nastawione na bieżące wydarzenia. Poproś model o wypisanie daty widocznej w treści fragmentu i porównaj ją z dzisiejszą po swojej stronie. Przy pytaniach o stan bieżący, gdzie cena błędu jest wysoka, sensowniej jest sięgnąć bezpośrednio do źródła danych niż do wyszukiwarki.

Tavily kontra alternatywy

Cztery podejścia do tego samego problemu, uszeregowane według tego, ile pracy zostaje po Twojej stronie.

CechaTavilyFirecrawlKlasyczne API wyszukiwarkiWyszukiwanie u dostawcy modelu
Co wracafragmenty treści z oceną trafnościpełna strona w markdownietytuł, adres, krótki opisodpowiedź modelu z odnośnikami
Kto pobiera i czyści HTMLdostawcadostawcaTwój koddostawca
Kto tnie tekst na fragmentydostawcaTwój kodTwój koddostawca
Jednostka rozliczeniakredyt za wywołanie lub stronękredyt za stronęzapytanietokeny plus opłata za narzędzie
Kontrola nad doborem źródełlisty domen, filtry datpełna, sam podajesz adresylisty domen zależnie od dostawcyograniczona
Możliwość samodzielnego hostowaniabrakserwer otwarty, licencja AGPL-3.0brakbrak
Licencja klientówMITMITzależnie od dostawcylicencja SDK dostawcy

Reguła wyboru jest krótka. Tavily bierzesz, gdy agent ma zadać pytanie do sieci i dostać materiał gotowy do wklejenia w prompt, a Ty nie chcesz utrzymywać własnego pobierania stron. Firecrawl bierzesz, gdy adresy są znane albo pochodzą z jednego serwisu i zależy Ci na pełnej treści oraz kontroli nad cięciem. Klasyczne API wyszukiwarki wybierasz, gdy potrzebujesz samych adresów, na przykład do własnego indeksu. Wyszukiwanie wbudowane u dostawcy modelu, dostępne w Claude i w OpenAI, wybierasz, gdy zależy Ci na jak najmniejszej liczbie ruchomych części, a nie na kontroli nad doborem źródeł.

W tym zestawieniu brakuje jeszcze jednego podejścia. Exa buduje własny indeks na osadzeniach, więc zapytanie opisujące sens szukanej strony trafia tam lepiej niż zestaw słów kluczowych. Cena jest dwojaka: przy zapytaniu o konkretną nazwę własną, numer wersji albo kod błędu dopasowanie dosłowne zwykle wygrywa z semantycznym, a indeks i model rankingu są zamknięte, bez wariantu do uruchomienia u siebie, więc przywiązanie do dostawcy jest tam pełne.

Warstwa integracyjna zwykle nie jest problemem. Tavily ma gotowe narzędzia w LangChain i w LlamaIndex, serwer zdalny w protokole MCP oraz interfejs wiersza poleceń. Do zadań wymagających klikania w interfejs, logowania czy wypełniania formularzy żadne z tych narzędzi nie wystarczy i tam wchodzi sterowanie przeglądarką w rodzaju browser-use.

Typowe błędy

Pierwszy to zostawienie search_depth na wartości domyślnej i zdziwienie jakością wyników. Tryb basic jest kompromisem między czasem a trafnością, a autorzy w poradniku dla agentów zalecają wprost advanced z chunks_per_source ustawionym na 3. Kosztuje dwa kredyty zamiast jednego, więc różnicę widać w rachunku, ale przy pytaniach niszowych widać ją też w odpowiedziach.

Drugi to włączenie auto_parameters bez czytania konsekwencji. Ta flaga pozwala usłudze dobrać parametry samodzielnie, ale dokumentacja zaznacza, że search_depth może zostać podniesione do advanced, gdy usługa uzna to za korzystne. Każde takie żądanie kosztuje wtedy dwa kredyty zamiast jednego, bez ostrzeżenia w kodzie.

Trzeci to traktowanie time_range jak gwarancji świeżości. Filtr działa na dacie publikacji albo ostatniej modyfikacji, a tę drugą część serwisów podbija przy każdym przebudowaniu strony. Zawężenie do ostatniego dnia nie oznacza, że treść jest z ostatniego dnia.

Czwarty to uruchamianie crawl w celu poznania rozmiaru serwisu. Przechodzenie z pobieraniem kosztuje sumę mapowania i pobierania, podczas gdy samo map kosztuje jeden kredyt za dziesięć stron i zwraca listę adresów. Kolejność jest oczywista dopiero po pierwszym rachunku.

Piąty to brak obsługi odpowiedzi 429. Limit dla klucza deweloperskiego to 100 żądań na minutę, dla produkcyjnego 1000, dla przechodzenia serwisu 100 niezależnie od rodzaju klucza, dla tworzenia zadań badawczych 20, a dla endpointu zużycia 10 na dziesięć minut. Odpowiedź niesie nagłówek retry-after z liczbą sekund i to jego wartość powinna sterować ponowieniem.

Szósty to pominięcie include_usage. Bez tego pola nie znasz kosztu wywołania w momencie jego wykonania, a przy zadaniach badawczych rozpiętość jest ogromna, bo pojedyncze żądanie na modelu pro mieści się w przedziale od 15 do 250 kredytów. To różnica między jednym a szesnastoma procentami całego darmowego limitu miesięcznego.

Siódmy to trzymanie klucza po stronie przeglądarki. Klient javascriptowy działa też w przeglądarce, więc pokusa jest realna, a skutek taki sam jak przy każdym innym kluczu API: rachunek obciąża Ciebie, a klucz widzi każdy, kto otworzy narzędzia deweloperskie.

FAQ

Czym Tavily różni się od zwykłego API wyszukiwarki?

Zwykłe API zwraca tytuł, adres i opis ze strony wyników, a pobranie i oczyszczenie treści zostaje po Twojej stronie. Tavily zwraca fragmenty wycięte z samej treści, każdy najwyżej pięćsetznakowy, wraz z liczbową oceną trafności w polu score. Kupujesz gotowy kontekst zamiast surowca, płacąc kontrolą nad tym, jak przebiega cięcie i ocena.

Ile realnie wystarcza plan darmowy?

Tysiąc kredytów miesięcznie, czyli tysiąc wyszukiwań podstawowych albo pięćset zaawansowanych. Karta nie jest wymagana, kredyty resetują się pierwszego dnia miesiąca. Klucz produkcyjny z limitem 1000 żądań na minutę wymaga jednak planu płatnego albo włączonej płatności za użycie, więc na planie darmowym zostajesz przy 100 żądaniach na minutę.

Czy Tavily gwarantuje świeżość wyników?

Nie. Dokumentacja opisuje wyniki jako aktualne, ale nie podaje opóźnienia indeksu ani żadnego zobowiązania w tej sprawie. Dostajesz filtry time_range, start_date i end_date, działające na dacie publikacji lub ostatniej aktualizacji strony. Umowa o dostępności i czasie reakcji dotyczy wyłącznie planu Enterprise i nie obejmuje aktualności danych.

Czy da się uruchomić Tavily u siebie?

Nie. Na licencji MIT otwarte są klienty, czyli tavily-python i @tavily/core, natomiast sama wyszukiwarka jest zamkniętą usługą pod adresem api.tavily.com. Przywiązanie do dostawcy jest pełne, więc warstwę wyszukiwania w swoim kodzie warto trzymać za własnym interfejsem, żeby wymiana dostawcy nie oznaczała przepisywania aplikacji.

Kiedy wybrać Firecrawl zamiast Tavily?

Gdy znasz adresy albo pracujesz w obrębie jednego serwisu i potrzebujesz pełnej treści strony, a nie wybranych fragmentów. Firecrawl daje też serwer do samodzielnego uruchomienia na licencji AGPL-3.0, czego Tavily nie oferuje. W drugą stronę: gdy punktem wyjścia jest pytanie, a nie adres, Tavily oszczędza cały etap pobierania i cięcia.

Czy trzeba zakładać konto, żeby to przetestować?

Nie. Tryb bez klucza obejmuje wyszukiwanie i pobieranie treści, włącza się nagłówkiem X-Tavily-Access-Mode: keyless i zwraca odpowiedzi identyczne co do schematu z wywołaniami z kluczem. Dokumentacja opisuje go jako darmowy i ograniczony częstotliwością, bez podania progu, więc nadaje się do oceny jakości wyników, a nie do pracy produkcyjnej.

Pełną specyfikację parametrów znajdziesz w referencji API, przelicznik kredytów w dziale o cenniku, a kod klientów w repozytoriach tavily-python i tavily-js.

Czytaj dalej

Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie