Search Shortcut cmd + k | ctrl + k

Call LLMs from SQL to classify, summarize, extract typed fields, embed and search text, or query your tables, with local models or 35+ hosted APIs

Maintainer(s): leonardovida

Installing and Loading

INSTALL ai FROM community;
LOAD ai;

Example

-- 1. Choose where the model runs.
--    Local: any model server on your machine, so data never leaves it. This example uses
--    Ollama with its default model (`ollama pull llama3.2`); llama.cpp, LM Studio and vLLM work too.
SET duckdb_ai_provider = 'ollama';
--    Hosted: put the key in the environment (OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, ...)
--    and pick the provider instead, for example: SET duckdb_ai_provider = 'anthropic';

-- 2. Run model functions over a table like any other SQL function.
CREATE TABLE tickets AS SELECT * FROM (VALUES
    (1, 'I was charged twice for the same invoice. Please refund one of them.'),
    (2, 'The dashboard has been down for every user since 9am.')
) t(id, body);

-- A label, a yes/no check and a summary for every row
SELECT id,
       ai_classify(body, MAP {'billing': 'Charges, invoices and refunds',
                              'outage': 'Something is down for users',
                              'other': 'Anything else'}) AS category,
       ai_filter(body, 'asks for a refund') AS wants_refund,
       ai_summarize(body) AS summary
FROM tickets;

-- Typed fields from a JSON Schema, returned as a STRUCT
SELECT id, r.product_area, r.urgency
FROM (SELECT id, ai_extract_record(body, '{"type": "object",
        "properties": {"product_area": {"type": "string"}, "urgency": {"type": "integer"}},
        "required": ["product_area", "urgency"]}') AS r
      FROM tickets);

-- 3. See what it cost: calls, tokens, failures and estimated spend (NULL for local models)
SELECT sum(calls) AS calls, sum(total_tokens) AS tokens, sum(failures) AS failures,
       sum(estimated_cost_usd) AS estimated_usd
FROM ai_usage_summary();

About ai

The ai extension brings language models into DuckDB SQL. Point a function at a column and it calls the model once per row, several rows at a time, and returns an ordinary DuckDB value (VARCHAR, BOOLEAN, DOUBLE, a typed STRUCT, a LIST or an embedding) that you can filter, join, aggregate and save like any other column.

What you can do

  • Label and rewrite text: ai_classify, ai_classify_labels, ai_sentiment, ai_summarize, ai_translate, ai_fix_grammar, ai_redact, ai_complete.
  • Get typed answers instead of free text: ai_extract_record returns a STRUCT from a JSON Schema (pydantic schemas work), ai_filter a BOOLEAN, ai_score a DOUBLE from 0 to 1, and ai_complete_json validated JSON.
  • Ask several typed questions per row with decision models: ai_decide returns probabilities and confidences from TypeSafe Jev, Cloudflare Clef, Perplexity or a local decision model.
  • Search by meaning: ai_embed, ai_similarity and ai_rerank, with ai_generate_chunks and ai_prep_search to split long documents.
  • Summarize groups with the ai_agg and ai_summarize_agg aggregates.
  • Ask questions about your data: ai_sql writes a validated read-only SELECT from your schema, and ai_query_data runs it.

Any model, local or hosted

Local model servers keep data on your machine: Ollama, llama.cpp, LM Studio, vLLM or any OpenAI-compatible endpoint. Hosted APIs include OpenAI, Anthropic, Google Gemini and Vertex AI, Azure OpenAI, Amazon Bedrock, Mistral, DeepSeek, Groq, Together, OpenRouter, Databricks and Snowflake Cortex, among more than 35 providers. Switching is one setting; the SQL stays the same. Replies are read the way small models write them, so a label in markdown or followed by an explanation still counts.

Safe to run on real tables

  • API keys come only from environment variables or TYPE duckdb_ai secrets, never from SQL arguments. Loading the extension makes no network calls, and allowed_hosts limits where data can be sent.
  • ai_completion_request_json shows a request without sending it. ai_usage() and ai_usage_summary() track calls, tokens, failures and estimated cost.
  • Per-row error handling (on_error := 'null', ai_try_complete), retries with backoff, rate and concurrency limits, and an opt-in response cache keep long batch runs predictable.

Learn more

  • Documentation: https://leonardovida.github.io/duckdb-ai/docs
  • Function reference: https://leonardovida.github.io/duckdb-ai/docs/functions
  • Cookbooks for ticket triage, semantic search, resumable batch runs and cost tracking: https://leonardovida.github.io/duckdb-ai/docs/cookbooks
  • For agents, the full docs as one text file: https://leonardovida.github.io/duckdb-ai/llms-full.txt

Added Functions

function_name function_type description comment examples
ai_agg aggregate Aggregate: sends all text in a group to the model with one instruction and returns one answer. NULL [SELECT product, ai_agg(review, 'List the top three complaints') FROM reviews GROUP BY product;]
ai_build_classifier aggregate Aggregate (experimental): trains a cheap embedding classifier from model-labeled samples for ai_classify_optimized. NULL [SELECT ai_build_classifier(review, ['positive', 'negative'], optimization := 'minimize_cost') FROM reviews;]
ai_classify scalar Picks exactly one label for each row from the labels you list. NULL [SELECT ai_classify(body, ['billing', 'outage', 'other']) FROM tickets;, SELECT ai_classify(body, 'positive, negative, mixed') FROM reviews;]
ai_classify_labels scalar Picks every label that applies (zero or more) and returns them as a VARCHAR[]. NULL [SELECT ai_classify_labels(review, ['shipping', 'pricing', 'quality']) FROM reviews;]
ai_classify_optimized scalar Classifies with a saved embedding classifier and asks a language model only for uncertain rows. NULL [SELECT ai_classify_optimized(review, classifier) FROM reviews, saved_classifier;]
ai_classify_result scalar Multi-label classification that returns STRUCT(value, error, metadata) instead of failing the query. NULL [SELECT ai_classify_result(review, ['shipping', 'pricing', 'quality']) FROM reviews;]
ai_clear_cache table Table function: clears the in-memory response and generated SQL caches. NULL [SELECT * FROM ai_clear_cache();]
ai_clear_usage table Table function: clears recorded usage events and counters. NULL [SELECT * FROM ai_clear_usage();]
ai_complete scalar Sends a prompt to a language model and returns the response text. NULL [SELECT ai_complete('Describe DuckDB in one sentence.');, SELECT ai_complete('Say hello', provider := 'ollama', model := 'qwen3.8:27b');]
ai_complete_json scalar Asks a model for JSON and returns it after checking it is a valid object or array. NULL [SELECT ai_complete_json('Return a JSON object with the keys name and kind for DuckDB');]
ai_complete_record table Table function: asks a model for one JSON object and returns its fields as typed columns from a JSON Schema. NULL [SELECT * FROM ai_complete_record('Describe DuckDB', '{"type": "object", "properties": {"name": {"type": "string"}, "year": {"type": "integer"}}}');]
ai_completion_request_json scalar Shows the JSON request a completion would send, without calling the provider. Useful for debugging. NULL [SELECT ai_completion_request_json('Say hello', provider := 'openai', model := 'gpt-5.6-luna');]
ai_count_tokens scalar Estimates the number of tokens in the text, locally. NULL [SELECT sum(ai_count_tokens(body)) FROM tickets;]
ai_decide scalar Answers typed questions with a decision model and returns a STRUCT of choices, scores and yes/no probabilities. NULL [SELECT ai_decide(body, {team: MAP {'billing': 'Payments', 'technical': 'Errors and outages'}}, provider := 'ollama') FROM tickets;, SELECT ai_decide(body, {urgent: MAP {'true': 'Needs action now', 'false': 'Can wait'}}, provider := 'cloudflare', model := 'clef-flash') FROM tickets;]
ai_deprovision_endpoint table Table function: starts removing a model serving endpoint. NULL [SELECT * FROM ai_deprovision_endpoint('support_model');]
ai_embed scalar Turns text into an embedding vector (DOUBLE[]) for semantic search. NULL [SELECT ai_embed(body) FROM tickets;, SELECT ai_embed('wrong charge', provider := 'ollama', model := 'nomic-embed-text');]
ai_embedding_request_json scalar Shows the JSON request an embedding would send, without calling the provider. NULL [SELECT ai_embedding_request_json('duck', provider := 'openai', model := 'text-embedding-3-small');]
ai_endpoint_status table Table function: returns the status of an endpoint provisioning operation. NULL [SELECT * FROM ai_endpoint_status('operation-id');]
ai_explain_sql table Table function: explains in plain English what a read-only SELECT does. NULL [SELECT * FROM ai_explain_sql('SELECT region, sum(amount) FROM sales GROUP BY ALL');]
ai_extract scalar Extracts the information you describe from the text and returns it as text. NULL [SELECT ai_extract('Anna is 31 and lives in Rome', 'the age of the person');]
ai_extract_record scalar Extracts typed fields from each row's text and returns a STRUCT shaped by a JSON Schema. NULL [SELECT ai_extract_record(body, '{"type": "object", "properties": {"product": {"type": "string"}, "urgency": {"type": "integer"}}}') FROM tickets;]
ai_filter scalar Returns true when the text matches a condition written in plain English. NULL [SELECT * FROM reviews WHERE ai_filter(review, 'mentions a shipping problem');]
ai_fix_grammar scalar Corrects grammar, spelling and punctuation. NULL [SELECT ai_fix_grammar('thes is a tst');]
ai_fix_sql table Table function: rewrites a broken query into a working read-only SELECT, or fixes one line with mode := 'line'. NULL [SELECT * FROM ai_fix_sql('SELEC 42');, SELECT * FROM ai_fix_sql('SELECT amout FROM sales', error := 'column amout not found', fix_attempts := 2);]
ai_generate_chunks table Table function: splits text into fixed-size or recursive chunks for embedding. NULL [SELECT * FROM ai_generate_chunks('First paragraph. Second paragraph.', chunk_size := 20);]
ai_is_read_only_sql scalar Returns true when the SQL is exactly one read-only SELECT statement. NULL [SELECT ai_is_read_only_sql('SELECT 42');]
ai_jev scalar TypeSafe Jev form of ai_decide: typed decisions with up to 32 rows per request. NULL [SELECT ai_jev(body, {team: MAP {'billing': 'Payments', 'other': 'Other'}}) FROM tickets;]
ai_model_prices table Table function: the built-in per-model token prices used for cost estimates. NULL [SELECT * FROM ai_model_prices() WHERE provider = 'openai';]
ai_models table Table function: lists model profiles created with CREATE EXTERNAL MODEL. NULL [SELECT * FROM ai_models();]
ai_parse_document table Table function: parses a PDF or other file (BLOB) through a remote document parser. NULL [SELECT * FROM ai_parse_document(read_blob('document.pdf').content, 'application/pdf', 'documents');]
ai_prep_search table Table function: builds RAG-ready chunks with titles, headings and page numbers attached for embedding. NULL [SELECT * FROM ai_prep_search('# Billing' || chr(10) || 'Invoices are sent monthly.', title := 'Guide');]
ai_provider_base_url scalar Returns the default API base URL for a provider. NULL [SELECT ai_provider_base_url('openai');]
ai_provider_call scalar Sends a provider-native JSON request and returns the full JSON response, for tools, reasoning and streaming. NULL [SELECT ai_provider_call('{"model": "gpt-5.6-luna", "messages": [{"role": "user", "content": "Hello"}]}', provider := 'openai');]
ai_provider_protocol scalar Returns the wire protocol the extension uses for a provider. NULL [SELECT ai_provider_protocol('anthropic');]
ai_provision_endpoint table Table function: dry-runs provisioning of a model serving endpoint, or submits it with dry_run := false. NULL [SELECT * FROM ai_provision_endpoint('support_model');]
ai_query_cache_stats table Table function: shows size, hits, misses and evictions of the generated SQL cache. NULL [SELECT * FROM ai_query_cache_stats();]
ai_query_data table Table function: answers a question about your tables by generating a read-only SELECT and running it. NULL [SELECT * FROM ai_query_data('total sales by region', include_tables := ['main.sales']);]
ai_recommended_batch_size scalar Suggests how many rows to send per batch to stay under a provider's token and request rate limits. NULL [SELECT ai_recommended_batch_size(200, 100, 100000);]
ai_redact scalar Masks personal data, credentials, secrets and payment numbers in the text. NULL [SELECT ai_redact('Contact [email protected] or +1 555 0100');]
ai_rerank scalar Asks a language model how relevant a candidate text is to a query, from 0 to 1. NULL [SELECT title FROM docs ORDER BY ai_rerank('how to export to Parquet', body) DESC LIMIT 5;]
ai_schema_prompt table Table function: describes your tables and columns as text to give a model context. NULL [SELECT summary FROM ai_schema_prompt(include_tables := ['main.sales']);]
ai_score scalar Rates how well the text meets a criterion, from 0 to 1. NULL [SELECT ai_score(body, 'reports a production outage') FROM tickets;]
ai_secrets table Table function: lists duckdb_ai secrets with API keys redacted. NULL [SELECT * FROM ai_secrets();]
ai_sentiment scalar Labels the sentiment of the text as positive, neutral or negative. NULL [SELECT ai_sentiment(review) FROM reviews;]
ai_similarity scalar Embeds two texts and returns their cosine similarity, from -1 to 1. NULL [SELECT ai_similarity('refund request', 'I want my money back');]
ai_sql scalar Writes one read-only DuckDB SELECT that answers a question about your tables and returns it as text. NULL [SELECT ai_sql('total sales by region');, SELECT ai_sql('total sales by region', include_tables := ['main.sales'], fix_attempts := 2);]
ai_summarize scalar Summarizes the text. NULL [SELECT ai_summarize(body) FROM tickets;]
ai_summarize_agg aggregate Aggregate: summarizes all text values in a group. NULL [SELECT product, ai_summarize_agg(review) FROM reviews GROUP BY product;]
ai_translate scalar Translates the text into the target language. NULL [SELECT ai_translate(body, 'English') FROM tickets;]
ai_try_complete scalar Like ai_complete, but returns STRUCT(response, error) so one failed row does not stop the query. NULL [SELECT r.response, r.error FROM (SELECT ai_try_complete(body) AS r FROM tickets);]
ai_usage table Table function: lists recent model calls with status, latency, tokens and estimated cost. NULL [SELECT function_name, status, total_tokens, estimated_cost_usd FROM ai_usage();]
ai_usage_summary table Table function: totals calls, retries, failures, cache hits, tokens and cost per query. NULL [SELECT * FROM ai_usage_summary();]
ai_usage_totals table Table function: lifetime provider counters that are kept even after old events are dropped. NULL [SELECT * FROM ai_usage_totals();]
ai_validate_read_only_sql scalar Returns the normalized SQL, or raises an error unless it is exactly one read-only SELECT. NULL [SELECT ai_validate_read_only_sql('SELECT 42');]

Overloaded Functions

This extension does not add any function overloads.

Added Types

This extension does not add any types.

Added Settings

name description input_type scope aliases
duckdb_ai_aggregate_model Default model for ai_agg and ai_summarize_agg VARCHAR GLOBAL []
duckdb_ai_allowed_hosts Comma-separated hosts that provider and log requests may reach; empty allows all hosts VARCHAR GLOBAL []
duckdb_ai_base_url Provider endpoint override, for example a gateway or self-hosted server URL VARCHAR GLOBAL []
duckdb_ai_cache Reuse successful responses for identical requests, in memory for this DuckDB instance BOOLEAN GLOBAL []
duckdb_ai_cache_max_entries Maximum number of cached responses (0 to 1000000); 0 stores nothing, -1 uses the default BIGINT GLOBAL []
duckdb_ai_cache_ttl_seconds Maximum age of cached responses in seconds (0 to 31536000); 0 never expires, -1 uses the default BIGINT GLOBAL []
duckdb_ai_completion_model Default model for ai_complete, ai_complete_json, ai_complete_record, ai_rerank and ai_score VARCHAR GLOBAL []
duckdb_ai_connect_timeout_seconds Connection timeout for each provider request in seconds (1 to 31536000); -1 uses the default BIGINT GLOBAL []
duckdb_ai_embedding_model Default embedding model for ai_embed, ai_similarity and the classifier functions VARCHAR GLOBAL []
duckdb_ai_input_token_price_per_million Input token price in USD per million tokens for estimated_cost_usd; -1 disables manual pricing DOUBLE GLOBAL []
duckdb_ai_log_endpoint HTTP endpoint that receives usage logs; prompt text is excluded unless log_include_text is set VARCHAR GLOBAL []
duckdb_ai_log_format Usage log payload format: generic_json or otlp_json VARCHAR GLOBAL []
duckdb_ai_log_include_text Include prompt and response text in usage logs (off by default) BOOLEAN GLOBAL []
duckdb_ai_log_sample_rate Fraction of usage events sent to the log endpoint (0 to 1); -1 uses the default DOUBLE GLOBAL []
duckdb_ai_log_strict Fail the SQL query when a usage log cannot be delivered BOOLEAN GLOBAL []
duckdb_ai_log_tags Tags added to every usage log, for example 'app=triage,env=prod' VARCHAR GLOBAL []
duckdb_ai_max_concurrent_requests Maximum provider requests in flight at once (0 to 64); 0 removes the limit, -1 uses the default BIGINT GLOBAL []
duckdb_ai_min_request_interval_ms Minimum milliseconds between the starts of provider requests (0 to 60000); -1 uses the default BIGINT GLOBAL []
duckdb_ai_model Default model for every ai_* function unless model := or a function-family model setting is set VARCHAR GLOBAL []
duckdb_ai_on_error Failed provider calls: fail stops the query, null returns NULL, capture also keeps the error where the function returns one VARCHAR GLOBAL []
duckdb_ai_output_token_price_per_million Output token price in USD per million tokens for estimated_cost_usd; -1 disables manual pricing DOUBLE GLOBAL []
duckdb_ai_prompt_cache Send provider-side prompt caching hints (OpenAI, Anthropic, xAI) for repeated prompt prefixes BOOLEAN GLOBAL []
duckdb_ai_provider Default provider for ai_* functions, for example 'ollama', 'openai' or 'anthropic' VARCHAR GLOBAL []
duckdb_ai_response_format Default completion response format: text, json_object or json_schema VARCHAR GLOBAL []
duckdb_ai_response_schema Default JSON Schema for structured completion responses VARCHAR GLOBAL []
duckdb_ai_retry_backoff_ms Base wait between retries in milliseconds (0 to 60000), with jitter; -1 uses the default BIGINT GLOBAL []
duckdb_ai_retry_count Retries after network errors and retryable statuses such as 429 and 5xx (0 to 10); -1 uses the default BIGINT GLOBAL []
duckdb_ai_sql_assistant_model Default model for ai_sql, ai_query_data, ai_explain_sql and ai_fix_sql VARCHAR GLOBAL []
duckdb_ai_task_model Default model for text tasks such as ai_classify, ai_summarize, ai_translate and ai_filter VARCHAR GLOBAL []
duckdb_ai_timeout_seconds Timeout for each provider request in seconds; 0 uses the extension default BIGINT GLOBAL []
duckdb_ai_token_limit_per_minute Cap on estimated provider tokens per rolling minute (0 to 10000000000); 0 removes the cap, -1 uses the default BIGINT GLOBAL []
duckdb_ai_use_builtin_model_prices Estimate cost from the built-in ai_model_prices() catalog when no manual price is set BOOLEAN GLOBAL []