Where we left off
Lesson 1 enabled the vector extension. This lesson uses it: create a table with a vector column, put a vector in, get it back out, as a normal Python list.
Declaring a vector column
CREATE TABLE items ( id bigserial PRIMARY KEY, content text NOT NULL, embedding vector(3))vector(3) means every value in this column is a fixed-length list of exactly 3 floating point numbers. The number is not a default or a maximum, it's an exact, enforced dimension: Postgres will reject an insert of a 4-number vector into a vector(3) column. Real embedding models produce much longer vectors (Gemini's gemini-embedding-001 produces 3072 numbers by default), 3 is used here only so the printed output stays readable.
The problem: Postgres doesn't know what a Python list is
Naively, you might expect psycopg to turn a Python list like [1.0, 2.0, 3.0] into a vector automatically. It won't, a plain list adapts to a Postgres array type by default, not a vector, and inserting it will fail with a type mismatch. Two extra pieces close this gap:
from pgvector.psycopg import register_vectorfrom pgvector.utils import Vector
register_vector(conn)register_vector(conn) (from the pgvector Python package, a companion to the extension) teaches this specific connection how to translate Postgres's vector type to and from Python. Vector(...) is a thin wrapper you put around a Python list to say "adapt this one as a vector, specifically."
conn.execute( "INSERT INTO items (content, embedding) VALUES (%s, %s)", ("first item", Vector([1.0, 2.0, 3.0])),)Getting it back out
row = conn.execute("SELECT embedding FROM items WHERE id = 1").fetchone()print(row[0]) # [1.0, 2.0, 3.0]print(type(row[0])) # <class 'numpy.ndarray'>Once register_vector has run, reading a vector column back gives you a NumPy array, not a Python list, NumPy is what the rest of the Python data/ML ecosystem (including embedding models) already expects vectors to look like.
The dimension enforcement is real, not advisory:
try: conn.execute( "INSERT INTO items (content, embedding) VALUES (%s, %s)", ("wrong size", Vector([1.0, 2.0, 3.0, 4.0])), )except psycopg.errors.DataException as exc: print(f"Inserting a 4-dimensional vector into vector(3) failed: {exc}")Checkpoint
vector(N): a column type holding a fixed-length, exact-dimension list of floats.register_vector(conn): teaches one connection how to translate Postgres'svectortype to and from Python.Vector([...]): wraps a Python list sopsycopgadapts it as avector, not a Postgres array.- Values come back out as NumPy arrays, once
register_vectorhas run.
If anything here still feels unclear, ask before moving to Lesson 4, where these toy 3-number vectors get replaced with real embeddings.