pgvector
pgvector adds a vector column and a nearest-neighbor search to Postgres. The database does not call the exchange. Your code gets the vectors from the exchange and stores them in the table.
Before you start
- A workspace with a balance and a
spendkey. See API keys. - A Postgres database where you can run
CREATE EXTENSION vector. - A model name from
GET /v1/models?kind=embedding. See Embeddings.
1. Export the key
export LIQUID_API_KEY=sk-liquid-...
export DATABASE_URL=postgresql://user:password@host:5432/dbname
2. Install the packages
# Python 3.9 or later
pip install openai "psycopg[binary]"
3. Create the table and store vectors
The column length must equal the vector length of the model. text-embedding-3-small returns 1,536 numbers. A model with a different length needs a different column.
SQL
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE documents (
id bigserial PRIMARY KEY,
body text NOT NULL,
embedding vector(1536) NOT NULL
);
CREATE INDEX documents_embedding_idx
ON documents USING hnsw (embedding vector_cosine_ops);
Python
import os
import psycopg
from openai import OpenAI
MODEL = "text-embedding-3-small"
client = OpenAI(
base_url="https://router.inference.ai.exchange/v1",
api_key=os.environ["LIQUID_API_KEY"],
)
def embed(texts):
result = client.embeddings.create(model=MODEL, input=texts)
return [item.embedding for item in result.data]
texts = ["a cat on a bicycle", "a dog in a car"]
with psycopg.connect(os.environ["DATABASE_URL"]) as conn:
for text, vector in zip(texts, embed(texts)):
conn.execute(
"INSERT INTO documents (body, embedding) VALUES (%s, %s::vector)",
(text, str(vector)),
)
query = embed(["an animal on two wheels"])[0]
rows = conn.execute(
"SELECT body, embedding <=> %s::vector AS distance "
"FROM documents ORDER BY distance LIMIT 3",
(str(query),),
).fetchall()
for body, distance in rows:
print(f"{distance:.3f} {body}")
The operator <=> is the cosine distance, so the index uses vector_cosine_ops. Use the same model for the stored texts and for the query.
Notes
- Send the texts in batches of up to 2,048. One request is one auction and has one cap.
- Keep one model for one table. A change of model needs a new column and a new embed of every row. See Embeddings.
- An index of type
hnswsupports vectors of up to 2,000 numbers. For a longer vector, use thehalfvectype or setdimensionsto a shorter length on a model that supports it. - The exchange sets a cap on each request. It is in the
x-liquid-cap-usdresponse header. To limit total spend, set a spending limit on the key. See API keys.
Troubleshooting
| Symptom | Cause and fix |
|---|---|
expected 1536 dimensions, not 1024 |
The column length differs from the model. Create the column with the model's length. |
401 |
The key is wrong, revoked or expired. Export it again. |
model_not_found |
The model is not on the book. Use an exact name from GET /v1/models. |
| A request is refused for lack of funds. | The workspace balance cannot cover the cap. Add funds on the Credits page. |
See Errors for the error codes.
Next steps
- Embeddings: the request, the price and the limits.
- Qdrant and Pinecone: a database that is only for vectors.