Ключови моменти
Embeddings работят най-добре, когато имаш добър chunking, метаданни и измерване на качеството, а не само „най-новия модел“.
За да използваш embeddings, превърни всеки документ (текст, код, описания на продукти) в вектор, запази векторите във vector store (например Postgres + pgvector или специализирана услуга) и при търсене вгради (embed) заявката, намери най-близките вектори и върни най-добрите пасажи/документи. Embeddings са практичният „мост“ между естествен език и математическо търсене по смисъл.
Embeddings са основата на семантичното търсене, препоръки, класификация по сходство, deduplication и Retrieval-Augmented Generation (RAG). Идеята е проста: еднакви по смисъл текстове се оказват близки като вектори, а различните се отдалечават.
Ако ти трябва търсене „какво има предвид човекът“, embeddings почти винаги са по-точни от чисто търсене по ключови думи.
В тази HOW-TO статия ще минем през целия pipeline: подготовка на данни, chunking, избор на модел, съхранение, индексиране, kNN търсене, re-ranking и практики за продукция.
Преди да пишеш код, фиксирай какво оптимизираш. Най-честите сценарии:
Избери метрика за оценка. Практични варианти:
Precision@k и Recall@k за търсенеMRR (Mean Reciprocal Rank) за „колко високо е правилният резултат“Събери малък тестов набор: 30-100 реални заявки + очаквани документи. Това ще ти спести дни „тунинг на сляпо“.
Embeddings работят най-добре, когато входът е чист и последователен. Минимални правила:
„Chunk“ е парче текст, което вграждаш като един вектор. Добрият chunking решава повече проблеми от смяната на модел.
Практични подходи:
Насоки:
Добави метаданни към всеки chunk:
doc_id, source, url (ако имаш), section_title, updated_at, languagerepo, path, symbol, commitВ продукция точността най-често пада заради лош chunking и мръсни данни, не заради „лош модел“.
Най-честият вариант е да използваш готов embedding модел (например през API). Важно е:
from openai import OpenAI
client = OpenAI()
def embed_texts(texts):
# texts: list[str]
resp = client.embeddings.create(
model="text-embedding-3-small",
input=texts,
)
return [d.embedding for d in resp.data]
import OpenAI from "openai";
const client = new OpenAI();
export async function embedTexts(texts) {
const resp = await client.embeddings.create({
model: "text-embedding-3-small",
input: texts,
});
return resp.data.map(d => d.embedding);
}
Практика: използвай отделен job за ingest (ETL), който:
Така търсенето става евтино и бързо: при заявка embed-ваш само query-то.
Ако вече използваш Postgres, pgvector е често най-прагматичният избор: една база, транзакции, лесни join-ове с метаданни.
CREATE TABLE doc_chunks (
id bigserial PRIMARY KEY,
doc_id text NOT NULL,
chunk_index int NOT NULL,
content text NOT NULL,
embedding vector(1536),
metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
created_at timestamptz NOT NULL DEFAULT now()
);
-- Индекс за ANN (пример: HNSW)
CREATE INDEX doc_chunks_embedding_hnsw
ON doc_chunks
USING hnsw (embedding vector_cosine_ops);
Забележки:
vector(1536) е пример. Провери размерността на избрания модел и я фиксирай в схемата.SELECT
doc_id,
chunk_index,
content,
1 - (embedding <=> $1) AS score
FROM doc_chunks
WHERE metadata->>'language' = 'bg'
ORDER BY embedding <=> $1
LIMIT 10;
Тук $1 е embedding на заявката.
Embeddings рядко са достатъчни сами. Добави филтри:
updated_at)Често работи много добре комбинация:
Това пази latency разумен и качва точността.
За някои заявки хората очакват точни съвпадения (номера на фактура, кодове, имена). Hybrid подход:
Embeddings проектите често работят „на лаптоп“, но се чупят в продукция. Минимален production checklist:
Най-важният „трик“ за стабилно качество е да измерваш Recall@k на реални заявки всяка седмица и да следиш регресии след ingest промени.
Ако вече имаш Postgres и данните ти не са огромни, pgvector е отличен старт. Ако имаш много милиони вектори, сложни multi-tenant нужди или искаш управлявано скалиране, специализирана услуга може да е по-лесна.
При cosine similarity обикновено работиш с нормализирани вектори или с оператори, които го управляват. Важно е да следваш препоръките на конкретния store/индекс.
Няма универсално число. Започни със секции/параграфи и тествай с реални заявки. Ако често връщаш „не това“, намали размера; ако губиш контекст, увеличи и добави overlap.
Първо оправи cleaning + chunking, после добави метаданни филтри и re-ranking. Това често носи по-голям ефект от смяна на embedding модел.
Запази старите вектори, добави нова колона/таблица за новите embeddings и прави dual-retrieval за период. После премини към новите, когато метриките са стабилни.
Цени и наличности на embedding модели и услуги се променят. Провери официалните страници за pricing и документацията на избрания vector store (например OpenAI pricing/model docs и документацията на pgvector) преди да фиксираш архитектурни решения.
Ето работеща рамка, която можеш да приложиш за вътрешна база знания (Confluence/Notion/Wiki), сайт с документация или help center:
model и model_version в metadata).ANALYZE/поддръжка, ако си на Postgres.