Embeddingi OpenAI, czyli tekst zamieniony na liczby
Osadzenie to zamiana fragmentu tekstu na listę liczb tak dobranych, że teksty o zbliżonym znaczeniu leżą blisko siebie. Na tym stoi wyszukiwanie semantyczne, systemy rekomendacji, grupowanie dokumentów i cała warstwa odnajdywania kontekstu w aplikacjach opartych o modele językowe.
OpenAI oferuje dwa modele z tej rodziny, mniejszy i większy, oraz jeden starszy, którego producent odradza w nowych projektach. Ta oferta nie zmieniła się od dłuższego czasu i to jest fakt, który ma znaczenie przy wyborze, o czym w osobnej sekcji.
Praktyczna zaleta jest prozaiczna: to najprostsza droga do działającego wyszukiwania semantycznego. Jedno wywołanie API, żadnej infrastruktury, koszt liczony w groszach przy typowych wolumenach.
Dwa modele i wybór między nimi
Mniejszy model zwraca wektor o tysiącu pięciuset trzydziestu sześciu wymiarach i kosztuje około dwóch centów za milion tokenów. Większy zwraca trzy tysiące siedemdziesiąt dwa wymiary i kosztuje trzynaście centów za milion tokenów, czyli sześć i pół raza tyle.
Reguła wyboru jest krótsza, niż mogłoby się wydawać. Zacznij od mniejszego. Przy większości zastosowań różnica w trafności jest niewielka, a różnica w koszcie przechowywania i wyszukiwania rośnie liniowo z liczbą wymiarów, więc płacisz ją przy każdym zapytaniu, nie tylko przy indeksowaniu.
Po większy sięgaj wtedy, gdy zmierzysz, że mniejszy nie wystarcza. Nie „gdy podejrzewasz", tylko „gdy zmierzysz na własnym zestawie pytań z oczekiwanymi odpowiedziami", bo to jedyny sposób, żeby się o tym przekonać.
Starszy model wciąż działa i kosztuje pięć razy więcej niż mniejszy nowy przy gorszej jakości. Jeśli masz projekt zbudowany na nim, przejście jest opłacalne, przy czym wymaga przeliczenia całego zbioru od nowa, bo wektory z różnych modeli są nieporównywalne.
Pierwsze wywołanie
from openai import OpenAI
klient = OpenAI()
odpowiedz = klient.embeddings.create(
model="text-embedding-3-small",
input=["Jaki jest okres wypowiedzenia?", "Warunki rozwiazania umowy"],
)
wektory = [d.embedding for d in odpowiedz.data]Zwróć uwagę na listę przekazaną jako wejście. Jedno wywołanie przyjmuje wiele tekstów naraz i to jest najprostsza optymalizacja w całym tym obszarze, a zarazem najczęściej pomijana. Przetwarzanie tysiąca fragmentów pojedynczo to tysiąc podróży do API, a partiami po sto to dziesięć. Różnica w czasie indeksowania bywa kilkudziesięciokrotna.
Porównanie dwóch wektorów to iloczyn skalarny, bo modele tej rodziny zwracają wektory znormalizowane.
import numpy as np
def podobienstwo(a, b):
return float(np.dot(a, b))Wynik bliski jedynce oznacza teksty o zbliżonym znaczeniu, bliski zeru oznacza brak związku. Warto wiedzieć, że wartości rzadko schodzą poniżej zera przy tekście naturalnym, więc próg odcięcia dobiera się empirycznie, a nie z teorii. W praktyce oznacza to, że liczba w rodzaju 0,7 nic nie mówi sama z siebie i trzeba zobaczyć rozkład wyników dla własnego zbioru, zanim ustawisz jakikolwiek próg.
Skracanie wymiarów
To jest funkcja niedoceniana, a przy większych zbiorach rozstrzygająca o kosztach.
Modele tej rodziny pozwalają skrócić zwracany wektor bez przeliczania go od nowa. Podajesz liczbę wymiarów mniejszą od domyślnej i dostajesz krótszy wektor, który nadal działa sensownie, bo model uczono w sposób upychający najważniejszą informację na początku listy.
odpowiedz = klient.embeddings.create(
model="text-embedding-3-small",
input=fragmenty,
dimensions=512,
)Zysk jest podwójny. Baza wektorowa zajmuje trzykrotnie mniej miejsca, a wyszukiwanie działa szybciej, bo porównuje krótsze wektory. Strata w trafności bywa na tyle mała, że przy wielu zastosowaniach nie da się jej zauważyć bez pomiaru.
Praktyczna rada brzmi: sprawdź to na swoich danych przed zbudowaniem indeksu. Weź pięćdziesiąt realnych pytań z oczekiwanymi odpowiedziami, zaindeksuj ten sam zbiór przy pełnej i skróconej liczbie wymiarów i porównaj trafność. Jeśli różnica wynosi jeden procent, a oszczędność trzy czwarte miejsca, decyzja jest oczywista.
Zastrzeżenie techniczne: skrócone wektory warto znormalizować, bo obcięcie zaburza długość. Większość bibliotek robi to sama, natomiast przy własnej implementacji łatwo o tym zapomnieć.
Koszty i tryb wsadowy
Rachunek za osadzenia jest zwykle najmniejszą pozycją w budżecie aplikacji opartej o modele językowe, i warto to powiedzieć wprost, bo ludzie tracą czas na optymalizowanie niewłaściwej rzeczy.
Zaindeksowanie stu tysięcy fragmentów po pięćset tokenów to pięćdziesiąt milionów tokenów, czyli około jednego dolara przy mniejszym modelu. Wyszukiwanie kosztuje jeszcze mniej, bo zapytanie ma kilkanaście tokenów.
Prawdziwe koszty leżą gdzie indziej: w wywołaniach modelu generującego odpowiedź oraz w utrzymaniu bazy wektorowej. To tam warto szukać oszczędności.
Jeśli mimo wszystko indeksujesz miliony dokumentów, tryb wsadowy zbija cenę o połowę w zamian za wynik dostarczany w ciągu doby. Przy jednorazowym przetworzeniu archiwum to jest oczywisty wybór, przy indeksowaniu na bieżąco bezużyteczny.
Warto też zbudować pamięć podręczną na wektory. Ten sam fragment tekstu przetworzony dwa razy daje ten sam wynik, więc zapisanie skrótu treści razem z wektorem pozwala pominąć wszystko, co się nie zmieniło. Przy archiwum aktualizowanym przyrostowo to zamienia nocne przeliczanie całości w kilkuminutowe uzupełnienie różnicy.
Osobno warto zaplanować obsługę limitów po stronie API. Przy indeksowaniu dużego zbioru trafisz na ograniczenie liczby zapytań na minutę, a biblioteka domyślnie ponawia takie odpowiedzi, przy czym bez własnego opóźnienia narastającego proces potrafi utknąć na godziny. Rozsądny układ to partie po kilkadziesiąt fragmentów, kilka równoległych wątków i zapis postępu do pliku, żeby przerwany przebieg dało się wznowić od miejsca, w którym stanął, a nie od początku.
Cięcie tekstu, czyli decyzja ważniejsza od modelu
Osadzenia liczy się dla fragmentów, a sposób podziału tekstu na fragmenty wpływa na trafność wyszukiwania bardziej niż wybór między dwoma modelami. To najczęściej pomijana część całego procesu.
Fragment zbyt krótki nie niesie dość kontekstu, żeby na cokolwiek odpowiedzieć. Dwa zdania wyrwane ze środka umowy brzmią sensownie i nie mówią, której strony dotyczą ani w jakich okolicznościach obowiązują.
Fragment zbyt długi rozmywa znaczenie. Wektor jest uśrednieniem całej treści, więc strona tekstu obejmująca cztery różne tematy daje wektor, który nie leży blisko żadnego z nich.
Rozsądny punkt wyjścia to fragmenty odpowiadające sekcjom dokumentu, o długości kilkuset do tysiąca kilkuset znaków, z niewielkim zachodzeniem na siebie. Zachodzenie rozwiązuje problem zdania przeciętego na pół przez granicę fragmentu.
Dwie rzeczy poprawiają trafność bardziej niż strojenie długości. Pierwsza to dopisanie do każdego fragmentu nagłówka sekcji i tytułu dokumentu, z którego pochodzi. Fragment zaczynający się od słów „Rozdział 4, Warunki wypowiedzenia" niesie kontekst, którego samo zdanie nie ma. Druga to odfiltrowanie nagłówków, stopek i numerów stron przed indeksowaniem, bo powtarzalny tekst obecny w każdym fragmencie rozmywa jego znaczenie.
Przejrzyj dwadzieścia wygenerowanych fragmentów, zanim zbudujesz cokolwiek dalej. Kwadrans tej pracy pokazuje zwykle, że parametry wymagają korekty, a to zmienia jakość odpowiedzi bardziej niż jakiekolwiek strojenie promptu.
Wyszukiwanie hybrydowe
Osadzenia same w sobie mają jedną słabość, którą warto znać, zanim zbudujesz na nich całą warstwę wyszukiwania.
Wyszukiwanie po znaczeniu gubi dokładne dopasowania. Zapytanie o numer faktury, kod błędu, nazwę własną albo identyfikator produktu może nie trafić w dokument zawierający dokładnie tę wartość, bo wektory operują na znaczeniu, a ciąg znaków w rodzaju kodu produktu żadnego znaczenia dla modelu nie ma.
Rozwiązaniem jest połączenie dwóch sposobów wyszukiwania: klasycznego, opartego na dopasowaniu słów, oraz semantycznego, opartego na wektorach. Wyniki obu łączy się w jedną listę, dając system radzący sobie zarówno z pytaniem opisowym, jak i z konkretnym numerem.
Większość baz wektorowych obsługuje to dziś wprost, więc nie trzeba budować tego samodzielnie. Warto natomiast sprawdzić, czy Twoja obsługuje, zanim zdecydujesz o wyborze, bo dołożenie tego później oznacza drugi indeks obok pierwszego. Jeśli w systemie działa już Elasticsearch, masz to praktycznie za darmo: silnik odwróconego indeksu obsługuje dopasowanie po słowach i po wektorach w jednym zapytaniu, a dokładanie osobnej bazy wektorowej rzadko się wtedy opłaca.
Trzecim elementem, dokładanym zwykle na końcu, jest zmiana kolejności wyników przez osobny model oceniający dopasowanie pary zapytanie i fragment. To kosztuje dodatkowe wywołanie na każde zapytanie i potrafi wyraźnie podnieść trafność, bo taki model widzi zapytanie i fragment razem, a nie tylko odległość dwóch punktów w przestrzeni.
Stan konkurencji
Tu trzeba powiedzieć rzecz, której materiały producenta nie powiedzą, a która ma znaczenie przy wyborze na nowy projekt.
Oferta OpenAI w tym obszarze nie zmieniła się od dawna, podczas gdy konkurencja w 2026 roku wypuściła modele idące dalej. Pojawiły się rozwiązania obsługujące wiele rodzajów treści naraz, w tym obrazy i dźwięk, oraz modele wyspecjalizowane w konkretnych dziedzinach, wypadające lepiej na tekstach prawniczych albo na kodzie.
To nie znaczy, że modele OpenAI przestały być dobrym wyborem. Znaczy, że przestały być wyborem domyślnym bez zastanowienia. Jeśli budujesz wyszukiwanie po dokumentach tekstowych w języku angielskim albo polskim, są nadal rozsądne, tanie i przewidywalne. Jeśli potrzebujesz obsługi obrazów, wyszukiwania po kodzie albo wysokiej jakości w wąskiej dziedzinie, warto sprawdzić alternatywy.
Dwie alternatywy warto sprawdzić w pierwszej kolejności, bo obejmują przeciwne końce skali. BGE to modele o otwartych wagach, które uruchomisz u siebie i zapłacisz wyłącznie za sprzęt, co przy dużym wolumenie zmienia rachunek zasadniczo. Osadzenia Vertex AI idą w drugą stronę, dokładając kontrolę regionu przetwarzania i rozliczenie w ramach Google Cloud.
Sposób sprawdzenia jest zawsze ten sam i zajmuje popołudnie. Zestaw pięćdziesięciu realnych pytań z oczekiwanymi odpowiedziami, zaindeksowanie tego samego zbioru dwoma modelami i porównanie, ile razy właściwy dokument trafił do pierwszej piątki wyników. Publiczne zestawienia mierzą zadania, które rzadko przypominają Twoje.
Embeddingi OpenAI kontra alternatywy
| Rozwiązanie | Mocna strona | Słabość | Kiedy wybrać |
|---|---|---|---|
| OpenAI | Prostota, niska cena, przewidywalność | Oferta bez zmian od dawna, tylko tekst | Wyszukiwanie po dokumentach tekstowych |
| Cohere | Dobre wyniki wielojęzyczne, zmiana kolejności wyników | Osobny dostawca do rozliczenia | Zbiory w wielu językach |
| Gemini | Obsługa wielu rodzajów treści naraz | Częste zmiany nazw modeli | Wyszukiwanie po obrazach i dokumentach |
| Model lokalny | Zero kosztu za token, dane nie wychodzą | Wymaga sprzętu i utrzymania | Dane, które nie mogą opuścić firmy |
Ostatni wiersz zasługuje na uwagę, bo bywa pomijany. Modele osadzeń uruchamiane lokalnie są dziś na tyle dobre, że przy wyszukiwaniu po dokumentach firmowych różnica względem usług płatnych bywa niewielka, a dane nie opuszczają infrastruktury. Koszt to sprzęt i utrzymanie, więc przy małym zbiorze się nie opłaca, przy dużym bywa rozstrzygający.
Typowe błędy
Pierwszy to wysyłanie fragmentów pojedynczo zamiast partiami. Różnica w czasie indeksowania bywa kilkudziesięciokrotna, a zmiana to jedna linia kodu.
Drugi to mieszanie wektorów z różnych modeli w jednym indeksie. Są nieporównywalne, więc wyszukiwanie zwraca wyniki losowe. Zmiana modelu wymaga przeliczenia całego zbioru.
Trzeci to wybór większego modelu bez pomiaru. Płacisz sześć i pół raza więcej i zwiększasz koszt przechowywania, często bez zauważalnej różnicy w trafności.
Czwarty to pominięcie skracania wymiarów przy dużym zbiorze. Trzykrotnie mniejszy indeks przy stracie rzędu procenta to zwykle dobry interes.
Piąty to optymalizowanie kosztu osadzeń zamiast kosztu generowania odpowiedzi. Ta pierwsza pozycja jest zwykle kilkadziesiąt razy mniejsza od drugiej i szkoda na nią czasu.
Szósty to brak pamięci podręcznej przy archiwum aktualizowanym przyrostowo. Przeliczanie wszystkiego od nowa przy każdej zmianie to koszt i czas wyrzucone bez powodu.
FAQ
Który model wybrać na start?
Mniejszy z dwóch nowych. Przy większości zastosowań różnica w trafności wobec większego jest niewielka, a koszt przechowywania i wyszukiwania rośnie razem z liczbą wymiarów. Po większy sięgaj dopiero wtedy, gdy zmierzysz, że mniejszy nie wystarcza.
Ile to kosztuje?
Zaindeksowanie stu tysięcy fragmentów po pięćset tokenów to około jednego dolara przy mniejszym modelu. Tryb wsadowy zbija tę kwotę o połowę w zamian za wynik w ciągu doby. To zwykle najmniejsza pozycja w budżecie aplikacji opartej o modele językowe.
Czy mogę skrócić wektor po fakcie?
Tak, modele tej rodziny pozwalają podać mniejszą liczbę wymiarów przy wywołaniu, bez utraty sensowności wyniku. Przy dużym zbiorze to trzykrotnie mniejszy indeks kosztem niewielkiej straty trafności, którą warto zmierzyć na własnych danych.
Czy przy zmianie modelu trzeba przeliczyć wszystko?
Tak. Wektory z różnych modeli leżą w różnych przestrzeniach i są nieporównywalne, więc mieszanie ich w jednym indeksie daje wyniki losowe. To warto uwzględnić przy planowaniu, bo przeliczenie dużego archiwum zajmuje czas.
Gdzie trzymać gotowe wektory?
W bazie wektorowej albo w rozszerzeniu do bazy relacyjnej. Przy małym zbiorze wystarczy rozwiązanie opisane w tekście o pgvectorze, przy większym warto rozważyć Qdranta albo Chromę.
Dokumentację modeli opisuje strona OpenAI, a stawki znajdziesz w cenniku.