How to

How do I add computed columns with LLM calls in Python?

A computed column is a value produced by an expression or an LLM call when the row or its dependencies change, then cached. A declarative data pipeline is that schema: you name the columns, and the engine decides which rows run. Adding an LLM call is an assignment on the class, not a job you schedule around a table.

Updated · Part of How do I ... in Python?

Before you start

About 10 min.

  • Python 3.11+
  • pip install -U 'pixeltable[serve]'
  • pxt init in the project root
  • An OpenAI API key for gpt-4o-mini

1. Start with the stored field the model will read

A computed column is an expression over other columns. The source text (or image, or document) is stored. The model output is derived.

import pixeltable as pxt
from pixeltable.functions.openai import chat_completions
TableModel = pxt.model_base()
class Docs(TableModel, name='docs'):
text: pxt.String

2. Assign the LLM call on the class

Computed fields are assignments, not annotations. chat_completions returns a response object; .choices[0].message.content is the string you cache. Insert a row and that expression runs. Edit the text and dependents of that row recompute.

class Docs(TableModel, name='docs'):
text: pxt.String
summary = chat_completions(
messages=[{'role': 'user', 'content': text}],
model='gpt-4o-mini',
).choices[0].message.content

3. Chain another column on the cached output

A declarative data pipeline is a graph of these assignments. A second call can classify the summary. Unchanged rows keep both caches. You do not enqueue each step.

class Docs(TableModel, name='docs'):
text: pxt.String
summary = chat_completions(
messages=[{'role': 'user', 'content': text}],
model='gpt-4o-mini',
).choices[0].message.content
label = chat_completions(
messages=[{
'role': 'user',
'content': 'Classify as bug, feature, or question. Reply with one word.\n\n' + summary,
}],
model='gpt-4o-mini',
).choices[0].message.content
# pxt schema update app.py docs -f

Computed LLM columns versus a job around the table

Computed LLM columns versus a job around the table
Computed columnA scheduled job
You writeAn assignment on the classA worker that reads and writes rows
Runs whenThe row or a dependency changesA cron tick or a queue
CachePer row, with lineageA column you overwrite by hand
FailureThat row, visibleA retry of the batch

Where Pixeltable fits

In Pixeltable a computed column is an assignment on TableModel. chat_completions is one expression. Insert a row and the LLM runs; unchanged rows stay cached. That is a declarative data pipeline, not an Airflow task or a LangChain chain with no store. See Pixeltable vs LangChain and Pixeltable vs Supabase (edge functions are not this cache).

import pixeltable as pxt
from pixeltable.functions.openai import chat_completions
TableModel = pxt.model_base()
class Docs(TableModel, name='docs'):
text: pxt.String
summary = chat_completions(
messages=[{'role': 'user', 'content': text}],
model='gpt-4o-mini',
).choices[0].message.content

Questions

Is a computed column an edge function?
No. An edge function runs on a request and does not cache per row by default. A computed column stores the result with the row and recomputes when dependencies change. Pixeltable vs Supabase covers Neon/Supabase functions.
Does every insert call the model again for old rows?
No. Unchanged rows keep their cached values. A new or edited source column recomputes dependents of that row. That is incremental computation.
Can the LLM see an image or a document?
Yes, if the provider UDF accepts that type. Text is chat_completions on a string. Gemini generate_content accepts an image and a prompt as contents. Use the UDF that matches the modality.