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

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

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