Read the full tutorial: https://interfaze.ai/blog/run-llms-inside-postgres
A dynamic Postgres trigger function that runs an LLM request directly in your database for use cases like translation, classification, summarization and more.
- Async execution - non-blocking, model runs async
- Use any Chat completion API compatible LLM
- Reference context from any column within the same row
- Automatically update multiple target columns
- Built-in retry logic with configurable max attempts
Postgres requirements:
- Copy the Postgres setup code from init.sql
- Replace the
API_KEY,BASE_URLandMODEL_NAMEwith your provider of choice. Defaults to Interfaze. - Execute it in your database.
Example table schema:
CREATE TABLE public.user_reviews (
id bigint generated by default as identity not null,
created_at timestamp with time zone not null default now(),
user_id uuid not null default gen_random_uuid (),
review_text text not null,
sentiment text null,
constraint user_reviews_pkey primary key (id)
);Example trigger for sentiment analysis:
DROP TRIGGER IF EXISTS analyze_sentiment ON user_reviews;
CREATE TRIGGER analyze_sentiment
AFTER INSERT OR UPDATE OF review_text ON user_reviews
FOR EACH ROW
WHEN (NEW.review_text IS NOT NULL)
EXECUTE FUNCTION llm.call('Analyze the sentiment of this text and respond with only "positive", "negative", or "neutral". return value in lowercase. Text: {review_text}','sentiment');INSERT INTO user_reviews (review_text) VALUES ('I love this hackathon, I can build anything I want!!!!') RETURNING *;The INSERT returns immediately. The sentiment column will be populated asynchronously by the pg_cron worker within seconds.
| Parameter | Description | Required |
|---|---|---|
| prompt | The prompt to use for the LLM. Supports {column_name} placeholders that get replaced with values from the row. |
Yes |
| target_column(s) | One or more columns to update with the LLM result. Pass additional column names as extra arguments. | Yes |
-- Single column
llm.call('<prompt>','<target_column>');
llm.call('Extract all text from this image: {image_url}','image_description');
-- Multiple columns
llm.call('<prompt>','<target_column_1>','<target_column_2>','<target_column_3>');
llm.call('Analyze the sentiment and translate the following review to Spanish. Text: {user_review_og}','emotion','user_review_es');The function uses JSON schema structured output (response_format with type: json_schema) to ensure the LLM returns a valid JSON object with exactly the specified target column names as keys.
This trigger will be executed only if an insert or change happens to a specific column in a specific table and if that column is not null.
The trigger enqueues a job into llm.queue and returns immediately.
DROP TRIGGER IF EXISTS <trigger_name> ON <table_name>;
CREATE TRIGGER <trigger_name>
AFTER INSERT OR UPDATE OF <column_name> ON <table_name>
FOR EACH ROW
WHEN (NEW.<column_name> IS NOT NULL)
EXECUTE FUNCTION llm.call('<prompt with {column} placeholders>','<target_column>');
-- or with multiple target columns:
EXECUTE FUNCTION llm.call('<prompt with {column} placeholders>','<target_column_1>','<target_column_2>');Example use cases:
All examples are based on this example schema in user_reviews.sql table.
CREATE TRIGGER translate_es
AFTER INSERT OR UPDATE OF user_review_og ON user_reviews
FOR EACH ROW
WHEN (NEW.user_review_og IS NOT NULL)
EXECUTE FUNCTION llm.call('Translate the following text to spanish (es). Only return the spanish text with no additional text. Text: {user_review_og}','user_review_es');CREATE TRIGGER analyze_sentiment
AFTER INSERT OR UPDATE OF user_review_og ON user_reviews
FOR EACH ROW
WHEN (NEW.user_review_og IS NOT NULL)
EXECUTE FUNCTION llm.call('Analyze the sentiment of this text and respond with only "positive", "negative", or "neutral". return value in lowercase. Text: {user_review_og}','emotion');CREATE TRIGGER background_search
AFTER INSERT OR UPDATE OF full_name ON user_reviews
FOR EACH ROW
WHEN (NEW.full_name IS NOT NULL)
EXECUTE FUNCTION llm.call('Give a summary background on {full_name}.','user_background');CREATE TRIGGER vision_ocr
AFTER INSERT OR UPDATE OF attached_image_url ON user_reviews
FOR EACH ROW
WHEN (NEW.attached_image_url IS NOT NULL)
EXECUTE FUNCTION llm.call('Extract all text from this image: {attached_image_url}','image_description');A single trigger can populate multiple columns at once from one LLM call:
CREATE TRIGGER analyze_and_translate
AFTER INSERT OR UPDATE OF user_review_og ON user_reviews
FOR EACH ROW
WHEN (NEW.user_review_og IS NOT NULL)
EXECUTE FUNCTION llm.call(
'Analyze the sentiment and translate the following review to Spanish. Text: {user_review_og}',
'emotion',
'user_review_es'
);