Skip to main content

SQL function reference

This page documents the public SQL surface registered by the ai extension. The layout follows the DuckDB function reference style: a compact overview table first, then each function with description, example, and result shape.

Table functions must be called from FROM or with CALL, for example:

SELECT *
FROM ai_usage();

Function overview​

FunctionTypeDescription
ai_complete(prompt[, model[, provider]])ScalarCalls a completion model and returns text.
ai_jev(text, questions[, ...])ScalarReturns a typed STRUCT of Jev decisions, batching up to 32 rows per request.
ai_provider_call(request_json, provider := ...)ScalarSends a native JSON body and returns full JSON or buffered SSE events.
ai_try_complete(prompt[, model[, provider]])ScalarCalls a completion model and returns STRUCT(response, error) for row-level failure capture.
ai_complete_json(prompt[, model[, provider]])ScalarCalls a completion model and validates the response as a JSON object or array.
ai_complete_record(prompt, response_schema[, model[, provider]])TableCalls a completion model and projects a JSON object into typed columns from a JSON Schema.
ai_extract_record(text, response_schema[, model[, provider]])ScalarExtracts one typed STRUCT per row from text using a JSON Schema.
ai_completion_request_json(prompt[, model[, provider]])ScalarReturns the completion request JSON without making a network call.
ai_embed(text[, model[, provider]])ScalarCalls an embedding model and returns DOUBLE[].
ai_embedding_request_json(text[, model[, provider]])ScalarReturns the embedding request JSON without making a network call.
ai_similarity(left_text, right_text[, model[, provider]])ScalarEmbeds two strings and returns cosine similarity.
ai_rerank(query, candidate[, model[, provider]])ScalarUses a completion model to score candidate relevance from 0 to 1.
ai_score(input, criteria[, model[, provider]])ScalarScores how well input satisfies criteria from 0 to 1.
ai_summarize(text[, model[, provider]])ScalarSummarizes text with a completion model.
ai_sentiment(text[, model[, provider]])ScalarClassifies text as positive, neutral, or negative.
ai_fix_grammar(text[, model[, provider]])ScalarRewrites text with corrected grammar, spelling, and punctuation.
ai_redact(text[, model[, provider]])ScalarMasks direct personal data, credentials, secrets, and payment identifiers.
ai_translate(text, target_language[, model[, provider]])ScalarTranslates text to the target language.
ai_classify(text, labels[, model[, provider]])ScalarChooses one label from a comma-separated VARCHAR or VARCHAR[] label list.
ai_classify_labels(text, labels[, model[, provider]])ScalarChooses zero or more labels from a comma-separated VARCHAR or VARCHAR[] label list.
ai_classify_result(text, labels[, ...])ScalarReturns multi-label classification as STRUCT(value, error, metadata).
ai_classify_optimized(text, artifact[, ...])ScalarUses a local centroid classifier and falls back to an LLM below the configured confidence margin.
ai_extract(text, instruction[, model[, provider]])ScalarExtracts requested information from text.
ai_filter(text, predicate[, model[, provider]])ScalarEvaluates a natural-language predicate and returns BOOLEAN.
ai_agg(text, instruction[, model[, provider]])AggregateRuns one completion over grouped text values and an instruction.
ai_summarize_agg(text[, model[, provider]])AggregateSummarizes grouped text values.
ai_build_classifier(text, labels[, ...])AggregateBuilds an experimental persisted classifier artifact for cost-optimized single-label classification.
ai_generate_chunks(text[, ...])TableSplits text into deterministic Unicode-aware fixed or recursive chunks.
ai_prep_search(text[, ...])TableProduces retrieval and context-enriched embedding chunks for RAG.
ai_parse_document(content, mime_type, parser_profile[, ...])TableCalls a normalized remote document parser without bundling PDF/OCR dependencies.
ai_sql(question[, schema_context[, model[, provider]]])ScalarGenerates one read-only DuckDB SELECT statement.
ai_query_data(question[, schema_context[, model[, provider]]])TableGenerates one read-only SELECT at bind time and executes it as a subquery.
ai_schema_prompt([include_tables])TableReturns deterministic local catalog context for prompting SQL models.
ai_explain_sql(sql[, ...])TableExplains one read-only DuckDB SELECT statement.
ai_fix_sql(sql[, ...])TableRewrites a broken query as one corrected read-only DuckDB SELECT, or rewrites one line with mode := 'line'.
ai_is_read_only_sql(sql[, check_binding])ScalarReturns whether SQL is one parser-valid read-only SELECT; optionally also checks it binds against the catalog.
ai_validate_read_only_sql(sql[, check_binding])ScalarReturns normalized SQL or raises if it is not one read-only SELECT; optionally also checks it binds against the catalog.
ai_count_tokens(text[, model[, provider]])ScalarReturns a local approximate token count.
ai_recommended_batch_size(input_tokens_per_row, max_output_tokens_per_row, token_limit_per_minute[, request_limit_per_minute[, safety_factor]])ScalarReturns a conservative row batch size for rate-limited AI jobs.
ai_provider_base_url(provider)ScalarReturns the default base URL for a supported provider.
ai_provider_protocol(provider)ScalarReturns the internal provider protocol.
ai_usage()TableReturns recent per-database AI usage events.
ai_usage_summary()TableReturns query-level calls, batches, retries, cache hits, cost, and dropped-event counters.
ai_clear_usage()TableClears the per-database usage event buffer.
ai_clear_cache()TableClears per-database in-memory response and generated-SQL caches.
ai_secrets()TableLists configured duckdb_ai secrets with credentials redacted.
ai_models()TableLists safe external-model metadata and validation status.
ai_provision_endpoint(profile[, ...])TableDry-runs or explicitly submits guarded asynchronous endpoint provisioning.
ai_endpoint_status(operation_id)TableReturns the current normalized endpoint operation status.
ai_deprovision_endpoint(profile)TableExplicitly submits asynchronous endpoint deprovisioning.
ai_model_prices()TableReturns the built-in provider/model pricing catalog.

Native provider JSON​

ai_provider_call(request_json, provider := ..., secret := ..., api := 'chat', base_url := ...) returns a VARCHAR containing the full provider JSON response. It uses existing secret/environment resolution, retries, timeouts, response-size limits, host allowlists and opt-in caching. It never executes tools.

The body must be a JSON object with a non-empty model. Put generation options, tools, conversation history and reasoning state in that body. Do not also pass SQL model, temperature, token-limit, system or response-format options. Duplicate top-level fields and credential fields are rejected. Credentials belong in DuckDB secrets or environment variables.

api accepts chat, messages, responses, embeddings, rerank and fim. For non-chat APIs, set base_url (or secret BASE_URL) to the complete endpoint; no path is appended. This supports regional and workspace-specific endpoints. TypeSafe Jev uses its native /systemone endpoint automatically with provider := 'typesafe' (alias jev), without an api override. Its body contains model, state, and questions, and its response preserves answers and usage. See the Jev cookbook for several decisions in one call.

The service determines which models support each API. The extension does not convert protocols or supply capabilities a provider does not offer.

SELECT ai_provider_call(
'{"model":"hy4-preview","input":"Explain vector search.","max_output_tokens":512}',
provider := 'hunyuan', api := 'responses',
base_url := 'https://tokenhub-intl.tencentcloudmaas.com/v1/responses'
);

Result shape: the complete non-streaming JSON object, including tool calls, reasoning, usage and finish/status fields. Refused, truncated and tool-only responses remain inspectable; callers must check those fields. HTTP errors and top-level error objects raise errors. fail_on_error := false returns NULL.

Requests with "stream":true buffer SSE and return {"events":[...provider event objects...]} after completion. SQL rows are not delivered incrementally. Missing terminators, invalid event JSON and error events fail. Token usage for streaming remains in the event objects and may be absent from summary usage counters. Native embedding/rerank results retain provider indices; native calls do not automatically batch or reorder them. Use ai_embed for the existing automatic embedding batching behavior.

For tool round trips, supply definitions and message history, extract returned tool calls, perform approved work in the caller, and send tool results with the original call IDs and reasoning/signature fields. Raw JSON is preserved, including large integer values. No tool is executed by this extension.

Plain completion functions additionally accept request_options := '{...}' for provider-native fields such as thinking, enable_thinking, reasoning_effort, preserve_thinking and top_p. Overrides of extension-owned model/input, stream, temperature, token-limit, response-format and cache fields are rejected.

SELECT ai_complete('Explain the proof.', provider := 'deepseek',
request_options := '{"thinking":{"type":"enabled"},"reasoning_effort":"high"}');

Use ai_provider_call for tools and reasoning-only responses. ai_complete continues to return final text. See provider coverage.

Completion functions​

ai_jev(text, questions[, ...])​

Description: Evaluates named Jev decisions and returns a typed STRUCT. No JSON extension or response parsing is needed. The provider is always TypeSafe. Use TYPESAFE_API_KEY or a TYPE duckdb_ai secret. Criteria and options must be constant so the result's field types are known when the query is planned.

Example:

SELECT ai_jev('Production imports are blocked.', {
team: MAP {'technical': 'Bugs and outages', 'other': 'Other issues'},
severity: ['Routine', 'Degraded', 'Blocked'],
urgent: MAP {'true': 'Needs immediate action', 'false': 'Can wait'}
}, model := 'jev-1.13.0', batch_size := 32) AS decision;

Result shape:

STRUCT(team VARCHAR, team_confidence DOUBLE,
severity DOUBLE, severity_confidence DOUBLE, urgent DOUBLE)
Criteria for each fieldMeaningResult
MAP {'label': 'description', ...}Choice among 1 to 255 unique, nonempty labelsVARCHAR plus <field>_confidence DOUBLE
['lowest level', ..., 'highest level']Score over 2 to 10 ordered levelsDOUBLE from 0 to number of levels minus 1, plus confidence
MAP {'true': 'yes criterion', 'false': 'no criterion'}Noul, probability of yesDOUBLE from 0 to 1

Map keys and descriptions and list entries must be non-null strings. Only a map with exactly the lowercase keys true and false is a Noul; other maps are Choices. Descriptions define the task. Question field names are SQL names and are not used as model instructions. Field names, including generated confidence names, must be unique ignoring ASCII case. Confidence is NULL if omitted by the provider. NULL text yields a NULL struct with no request.

OptionDefaultBehavior
modelSecret or TypeSafe environment/default resolutionSet an explicit Jev version to stabilize the model selection.
secretProvider-scoped secret lookupExisting duckdb_ai secret name.
base_urlSecret or TypeSafe environment/default resolutionExisting provider endpoint override.
batch_size32Maximum non-null rows per request, from 1 to 32.
max_request_bytes48000Serialized UTF-8 JSON body cap, from 1024 to 1000000. Splits batches, never truncates data.
on_errorExisting runtime policy, normally failfail aborts the query, null returns NULL for affected rows. capture is unsupported.

Transport options timeout_seconds, retry_count, retry_backoff_ms, max_concurrent_requests, min_request_interval_ms, token_limit_per_minute, allowed_hosts and cache use their existing meanings in Named options. Other named options are rejected. The function inherits common runtime transport settings but ignores generic SQL model, provider, endpoint and generation defaults. Its model and endpoint come from explicit arguments, TypeSafe secrets or the existing provider environment resolution (including generic DUCKDB_AI_* fallbacks).

Batching is confined to each DuckDB execution chunk. Each input row creates one question per field, and answers are mapped by generated keys rather than order. Invalid choices, scores, probabilities and mismatched or missing answers fail the affected batch. With on_error := 'null', all rows in that batch are NULL. A row too large for max_request_bytes fails or becomes NULL on its own, according to the error policy. The byte cap does not guarantee a fit within model token limits. Retries repeat a complete batch. ai_usage() records one ai_jev event per request operation, with usage counted once rather than once per row.

Save results with CREATE TABLE ... AS SELECT ... before reading multiple fields or exporting them. See typed Jev decisions for a complete table-to-Parquet workflow. This function does not generate arbitrary text or extract open-ended strings. Use ai_provider_call for raw distributions, resolved model metadata, custom instructions and shared state.

ai_complete(prompt[, model[, provider]])​

Description: Calls a configured completion provider and returns the completion text as VARCHAR.

Example:

SELECT ai_complete(
'Write one sentence about DuckDB.',
provider := 'openai',
model := 'gpt-4o-mini'
);

Result: VARCHAR

ai_try_complete(prompt[, model[, provider]])​

Description: Calls a configured completion provider and returns a STRUCT(response VARCHAR, error VARCHAR). Successful rows have error = NULL; failed rows have response = NULL and the provider or validation error text. Use this for batch enrichment when one bad row should be written to a rejected rows table instead of failing the whole query.

Example:

WITH attempts AS (
SELECT id, ai_try_complete(prompt, provider := 'openai') AS result
FROM prompts
)
SELECT id, result.response
FROM attempts
WHERE result.error IS NULL;

Result: STRUCT(response VARCHAR, error VARCHAR)

ai_complete_json(prompt[, model[, provider]])​

Description: Calls a completion provider, asks for JSON-only output, and validates that the returned text is a top-level JSON object or array. If response_schema or json_schema is supplied, the output is also validated against the supported JSON Schema subset.

Example:

SELECT ai_complete_json(
'Extract a compact company profile for DuckDB.',
provider := 'openai',
response_schema := '{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}'
);

Result: VARCHAR containing valid JSON

ai_complete_record(prompt, response_schema[, model[, provider]])​

Description: Table function that calls a completion provider, validates the JSON response against response_schema, and projects top-level schema properties as typed DuckDB columns.

Example:

SELECT *
FROM ai_complete_record(
'Extract a compact company profile for DuckDB.',
'{"type":"object","properties":{"name":{"type":"string"},"score":{"type":"number"}},"required":["name"]}',
provider := 'openai'
);

Result: one row with columns derived from response_schema

ai_extract_record(text, response_schema[, model[, provider]])​

Description: Scalar function that calls a completion provider for each input row and returns a typed STRUCT projected from the top-level object properties in response_schema. The schema must be constant so DuckDB can bind the return type.

Example:

SELECT
ticket_id,
extracted.product_area,
extracted.urgency_score
FROM (
SELECT
ticket_id,
ai_extract_record(
subject || ': ' || body,
'{
"type": "object",
"properties": {
"product_area": {"type": "string"},
"urgency_score": {"type": "integer"}
},
"required": ["product_area", "urgency_score"]
}'
) AS extracted
FROM support_tickets
);

Result: one STRUCT value whose fields are derived from response_schema

ai_completion_request_json(prompt[, model[, provider]])​

Description: Builds the provider completion request body and returns it without making a network call. Use this for deterministic tests and provider debugging.

Example:

SELECT ai_completion_request_json(
'Summarize this text.',
provider := 'openai',
model := 'gpt-4o-mini',
temperature := 0.2
);

Result: VARCHAR containing provider request JSON

Embedding functions​

ai_embed(text[, model[, provider]])​

Description: Calls an embedding provider and returns a DuckDB list of doubles.

Example:

SELECT ai_embed(
'DuckDB is an analytical database.',
provider := 'openai',
model := 'text-embedding-3-small'
);

Result: DOUBLE[]

ai_embedding_request_json(text[, model[, provider]])​

Description: Builds the provider embedding request body and returns it without making a network call.

Example:

SELECT ai_embedding_request_json(
'DuckDB vector smoke',
provider := 'openai',
model := 'text-embedding-3-small'
);

Result: VARCHAR containing provider request JSON

ai_similarity(left_text, right_text[, model[, provider]])​

Description: Embeds both input strings with the same provider/model and returns cosine similarity.

Example:

SELECT ai_similarity(
'DuckDB analytics',
'analytical SQL database',
provider := 'openai',
model := 'text-embedding-3-small'
);

Result: DOUBLE

ai_rerank(query, candidate[, model[, provider]])​

Description: Uses a completion model to score how relevant candidate is for query. The provider response must be a single numeric score from 0 to 1. Use it when you want LLM-based reranking over a short candidate set; use ai_similarity for embedding-based semantic comparison at larger scale.

Example:

SELECT *
FROM documents
ORDER BY ai_rerank('analytics database', title || chr(10) || body) DESC
LIMIT 10;

Result: DOUBLE

ai_score(input, criteria[, model[, provider]])​

Description: Uses a completion model with a strict JSON Schema containing one numeric score to evaluate how well input satisfies criteria. Values outside the inclusive [0, 1] range and malformed responses are rejected.

Example:

SELECT ai_score(
ticket_body,
'contains a reproducible production-impacting database issue'
) AS escalation_score
FROM support_tickets;

Result: DOUBLE

Task wrappers​

ai_summarize(text[, model[, provider]])​

Description: Summarizes text and returns only the summary.

Example:

SELECT ai_summarize('DuckDB is an analytical database built for fast local queries.');

Result: VARCHAR

ai_sentiment(text[, model[, provider]])​

Description: Convenience wrapper for ai_classify(text, 'positive, neutral, negative').

Example:

SELECT ai_sentiment('The import finished quickly and the query is fast.');

Result: VARCHAR

ai_fix_grammar(text[, model[, provider]])​

Description: Fixes grammar, spelling, and punctuation while preserving meaning.

Example:

SELECT ai_fix_grammar('duckdb are fast');

Result: VARCHAR

ai_redact(text[, model[, provider]])​

Description: Masks direct personal data, credentials, secrets, and payment identifiers. With provider openai_privacy_filter, sends the raw input text to a local or cloud-hosted OpenAI Privacy Filter service instead of wrapping it in a chat prompt.

Example:

SELECT ai_redact('email alice@example.com');

SELECT ai_redact(
'email alice@example.com token fake-token',
provider := 'openai_privacy_filter',
base_url := 'http://localhost:8080'
);

Result: VARCHAR

ai_translate(text, target_language[, model[, provider]])​

Description: Translates text to target_language while preserving meaning and formatting.

Example:

SELECT ai_translate('hello', 'Dutch');

Result: VARCHAR

ai_classify(text, labels[, model[, provider]])​

Description: Classifies text into exactly one label from labels. labels can be a comma-separated VARCHAR or a VARCHAR[]; use VARCHAR[] when labels may contain commas. Use constant label_descriptions :=, instructions :=, and examples := strings to add label semantics, global rules, and few-shot examples without changing the return type. Configured labels must be non-empty and unique. The returned value is validated against the configured set and canonicalized to its original spelling.

With provider := 'typesafe' (alias jev), this sends a native Jev Choice question rather than generating a label as text. Jev accepts at most 255 options. Use ai_jev for typed decisions with row batching. Use ai_provider_call when you also need the probability distribution or want to bundle several questions against the same input.

Example:

SELECT ai_classify('invoice overdue', 'billing, support');

SELECT ai_classify('invoice overdue', ['billing, overdue', 'support']);

SELECT ai_classify(
'invoice overdue',
['billing', 'support'],
label_descriptions := '{"billing":"payments, invoices, or charges","support":"product help"}',
instructions := 'Prefer billing when an invoice is explicitly mentioned.',
examples := '[{"input":"card charged twice","label":"billing"}]'
);

Result: VARCHAR

ai_classify_labels(text, labels[, model[, provider]])​

Description: Classifies text into zero or more labels from labels. labels can be a comma-separated VARCHAR or a VARCHAR[]; use VARCHAR[] when labels may contain commas. The model must return a JSON array containing only unique members of the configured label set.

Example:

SELECT ai_classify_labels(
'invoice overdue and app is slow',
['billing, overdue', 'performance', 'support']
);

Result: VARCHAR[]

ai_classify_result(text, labels[, model[, provider]])​

Description: Multi-label classification with pipeline-safe diagnostics. It always captures provider and parsing failures instead of failing the full vector, preserves metadata for failed rows, and returns metadata describing the selected provider and model when resolution succeeds.

Example:

WITH classified AS (
SELECT id, ai_classify_result(body, ['billing', 'performance', 'support']) AS result
FROM support_tickets
)
SELECT id, result.value, result.metadata
FROM classified
WHERE result.error IS NULL;

Result: STRUCT(value VARCHAR[], error VARCHAR, metadata VARCHAR)

ai_classify_optimized(text, artifact[, ...])​

Description: Experimental single-label classification. The function embeds text, compares it with the centroids in an ai_build_classifier() artifact, and returns locally when the best/second-best cosine margin meets the artifact threshold. It calls the fallback completion profile only when the artifact is unusable, embedding fails, or the margin is too small. Embeddings are packed and deduplicated by model options across each DuckDB vector chunk.

Example:

SELECT
ticket_id,
result.value,
result.used_fallback,
result.metadata
FROM (
SELECT
ticket_id,
ai_classify_optimized(body, artifact, fallback_profile := 'support_model') AS result
FROM support_tickets
CROSS JOIN classifier_artifacts
);

Result: STRUCT(value VARCHAR, used_fallback BOOLEAN, confidence DOUBLE, error VARCHAR, metadata VARCHAR)

ai_extract(text, instruction[, model[, provider]])​

Description: Extracts requested information from text. When the instruction asks for structured data, the function prompts for concise JSON.

Example:

SELECT ai_extract('name: DuckDB', 'name');

Result: VARCHAR

ai_filter(text, predicate[, model[, provider]])​

Description: Evaluates whether text matches a natural-language predicate. The model output must parse as true or false. With provider := 'typesafe' (alias jev), this sends a native Noul question and returns true for a probability of at least 0.5. Invalid or out-of-range probabilities raise an error. Use ai_provider_call to retain the probability and apply a workload-specific threshold in SQL.

Example:

SELECT ai_filter('invoice overdue', 'is about billing');

Result: BOOLEAN

Aggregate functions​

ai_agg(text, instruction[, model[, provider]])​

Description: Collects all grouped input text. When the input exceeds max_context_chars, the default overflow_policy := 'hierarchical' recursively maps chunks to compact evidence and reduces those partials until a final prompt fits. No input is silently discarded. Use overflow_policy := 'error' when the query must fail instead of issuing a request tree.

Example:

SELECT ai_agg(message, 'List the top three recurring themes')
FROM customer_feedback;

Result: VARCHAR

ai_summarize_agg(text[, model[, provider]])​

Description: Convenience wrapper around ai_agg with the built-in summarization instruction. It uses the same hierarchical overflow behavior and returns one summary per group.

Example:

SELECT customer_id, ai_summarize_agg(note ORDER BY created_at)
FROM support_notes
GROUP BY customer_id;

Result: VARCHAR

ai_build_classifier(text, labels[, ...])​

Description: Experimental relation-level MINIMIZE_COST workflow. The aggregate samples up to sample_size rows, labels them with the configured task model, embeds the successful samples in packed requests, builds one centroid per label, and validates on a deterministic held-out subset. The returned versioned artifact includes quality, fallback margin, embedding profile, labels, and centroids. Version 1 supports single-label classification only.

Example:

CREATE TABLE classifier_artifacts AS
SELECT ai_build_classifier(
body,
['billing', 'performance', 'support'],
optimization := 'minimize_cost',
sample_size := 256,
quality_threshold := 0.85,
confidence_margin := 0.08,
embedding_profile := 'support_embeddings',
profile := 'support_model'
) AS artifact
FROM support_tickets;

Result: VARCHAR containing a versioned JSON classifier artifact, or NULL when fail_on_error := false and training cannot produce a usable artifact.

RAG and document functions​

ai_generate_chunks(input[, ...])​

Description: Local deterministic chunking. fixed splits at exact Unicode code point counts. recursive prefers paragraph, sentence, line, then word boundaries. overlap_percent is limited to 0 through 50; offsets are zero-based Unicode code points and end_offset is exclusive. IDs are stable for the same source text, source ID, strategy, size, overlap, and chunk index. Empty and NULL input return zero rows.

Example:

SELECT *
FROM ai_generate_chunks(
'# Introduction' || chr(10) || chr(10) ||
'DuckDB is an in-process analytical database.',
source_id := 'document-42',
chunk_size := 1000,
overlap_percent := 10,
strategy := 'recursive'
);

Result columns: source_id, chunk_id, chunk_index, start_offset, end_offset, chunk_length, estimated_tokens, chunk.

ai_prep_search(input[, ...])​

Description: Builds retrieval-ready rows from text or Markdown. It keeps the original chunk in chunk_to_retrieve, adds title and the active Markdown heading to chunk_to_embed, preserves page numbers separated by form-feed page breaks, and carries JSON metadata. Line-aware recursive boundaries keep Markdown table rows intact when a row fits the configured chunk size.

enrich := false is fully local and deterministic. enrich := true makes one model call for concise document-level context and captures a row-level error when fail_on_error := false.

Example:

SELECT *
FROM ai_prep_search(
'# Billing' || chr(10) || chr(10) ||
'The invoice was charged twice.',
source_id := 'ticket-42',
title := 'Duplicate charge',
metadata := json_object('uri', '/tickets/42'),
chunk_size := 1000,
overlap_percent := 10,
enrich := false
);

Result columns: source_id, chunk_id, chunk_index, chunk_to_retrieve, chunk_to_embed, heading, page, start_offset, end_offset, metadata, error.

ai_parse_document(content, mime_type, parser_profile[, ...])​

Description: Sends binary content to the optional companion control plane's normalized document parser. The core extension performs base64 transport and schema normalization only; it does not bundle PDF, Office, OCR, or vendor SDK dependencies. For local extraction, use DuckDB's community pdf extension and pass its Markdown or text output to ai_prep_search().

Example:

SELECT *
FROM ai_parse_document(
read_blob('contract.pdf').content,
'application/pdf',
'document-ai',
pages := '1-10',
fail_on_error := false
);

Result columns: document_id, page, element_index, element_type, text, markdown, bbox, confidence, metadata, error.

SQL assistant functions​

ai_sql(question[, schema_context[, model[, provider]]])​

Description: Calls a completion model to generate one DuckDB SELECT statement, strips common markdown code fences, and rejects output that is not one read-only SELECT. When schema_context is omitted, the function builds local catalog context from ai_schema_prompt(). With fix_attempts := N (0 to 5, default 0), the function verifies the generated SQL binds against the current catalog and, when it does not, feeds the bind error back to the model for up to N correction rounds before failing.

Example:

SELECT ai_sql('count orders by status');

Example with self-correction:

SELECT ai_sql('count orders by status', fix_attempts := 2);

Result: VARCHAR containing a read-only DuckDB SELECT

ai_query_data(question[, schema_context[, model[, provider]]])​

Description: Table function that generates one read-only DuckDB SELECT at bind time and executes it as a subquery. Successful generated SQL is cached in the current DuckDB database instance for repeated binds with the same question, schema context, and output-affecting options. Use on_error := 'null' to return an empty error-shaped relation instead of failing the bind.

With fix_attempts := N (0 to 5, default 0), the function verifies the generated SQL binds against the current catalog before returning it. When binding fails — a hallucinated column, a wrong function name, a typo — the DuckDB bind error is fed back to the model for up to N correction rounds. Each correction is a regular model call and appears in ai_usage() alongside an ai_query_data_fix_attempt event. Cached SQL is re-verified on cache hits when fix_attempts > 0, so entries that stopped binding after a schema change are repaired instead of failing.

Example:

SELECT *
FROM ai_query_data(
'count orders by status',
schema_context := (SELECT summary FROM ai_schema_prompt(include_tables := ['main.orders']))
);

Example with self-correction (useful in views, scheduled queries, and other non-interactive contexts):

SELECT *
FROM ai_query_data(
'revenue by pickup borough',
include_tables := ['trips', 'zones'],
fix_attempts := 2
);

Result: the result columns of the generated query

ai_schema_prompt([include_tables])​

Description: Table function that returns one summary row with deterministic DuckDB catalog context. include_tables and exclude_tables accept table, schema.table, or catalog.schema.table names. sample_rows includes bounded sample rows for local DuckDB tables during execution.

Example:

SELECT summary
FROM ai_schema_prompt(
include_tables := ['main.orders'],
exclude_tables := ['main.internal_audit'],
sample_rows := 3
);

Result: one summary VARCHAR column

ai_explain_sql(sql[, ...])​

Description: Table function that explains one read-only DuckDB SELECT statement using optional schema context.

Example:

SELECT explanation
FROM ai_explain_sql(
'SELECT status, count(*) FROM orders GROUP BY status',
include_tables := ['main.orders']
);

Result: one explanation VARCHAR column

ai_fix_sql(sql[, ...])​

Description: Table function that asks the model to rewrite a broken query as one corrected read-only DuckDB SELECT statement. With mode := 'line', it rewrites only the line identified by an error message and returns the detected line number plus replacement line.

In query mode, pass error := to include the failure message in the correction prompt — the error text is usually what makes the fix reliable. Passing error without an explicit mode selects line mode for backward compatibility, so combine it with mode := 'query' for full-query rewrites. Query mode also accepts fix_attempts := N (0 to 5, default 0) to verify the corrected SQL binds against the current catalog and re-correct with the bind error for up to N rounds.

Example:

SELECT sql
FROM ai_fix_sql('SEELECT status, count(*) FRUM orders GROUP BY status');

Example with the error message and bind verification:

SELECT sql
FROM ai_fix_sql(
'SELECT statuss, count(*) FROM orders GROUP BY statuss',
mode := 'query',
error := 'Binder Error: Referenced column "statuss" not found',
fix_attempts := 1
);

Result: one sql VARCHAR column

Example:

SELECT line_number, replacement_line
FROM ai_fix_sql(
'SEELECT status FROM orders',
mode := 'line',
error := 'Parser Error: syntax error at or near "SEELECT" LINE 1'
);

Line-mode result: line_number BIGINT, replacement_line VARCHAR

SQL validation functions​

ai_is_read_only_sql(sql[, check_binding])​

Description: Returns whether sql parses as exactly one read-only DuckDB SELECT statement. With check_binding set to true, the statement must also bind against the current catalog — hallucinated tables, columns, or functions return false even when the SQL parses. The bind check runs in the current session, so temporary tables are visible, and nothing is executed.

Example:

SELECT ai_is_read_only_sql('SELECT 42');
SELECT ai_is_read_only_sql('SELECT missing_column FROM my_table', true);

Result: BOOLEAN

ai_validate_read_only_sql(sql[, check_binding])​

Description: Returns the input SQL when it is one read-only DuckDB SELECT; otherwise raises an error. With check_binding set to true, the statement must also bind against the current catalog.

Example:

SELECT ai_validate_read_only_sql('SELECT count(*) FROM my_table');
SELECT ai_validate_read_only_sql('SELECT count(*) FROM my_table', true);

Result: VARCHAR

ai_count_tokens(text[, model[, provider]])​

Description: Returns a local approximate token count. This function does not call a provider.

Example:

SELECT ai_count_tokens('DuckDB local analytics');

Result: BIGINT

Description: Returns a conservative number of rows to process per batch or minute for a rate-limited AI job. input_tokens_per_row can come from avg(ai_count_tokens(prompt)), max_output_tokens_per_row should match the planned max_tokens, and safety_factor defaults to 0.8.

Example:

SELECT ai_recommended_batch_size(100, 200, 200000, 500);

Result: BIGINT

Provider metadata functions​

ai_provider_base_url(provider)​

Description: Returns the default base URL for a supported provider after alias normalization.

Example:

SELECT ai_provider_base_url('ollama');

Result: VARCHAR

ai_provider_protocol(provider)​

Description: Returns the internal request protocol used for provider request and response shaping.

Example:

SELECT ai_provider_protocol('anthropic');

Result: VARCHAR

Usage and catalog table functions​

ai_usage()​

Description: Returns recent completion, embedding, and local usage events for the current DuckDB database instance. The buffer keeps the latest 1,024 events.

Example:

SELECT *
FROM ai_usage()
ORDER BY event_id DESC;

Result columns: event_id, created_at, event, function_name, query_id, operation_id, parent_operation_id, provider, protocol, model, character counts, token counts, cached-token counts, elapsed time, retry count, HTTP status, cache hit flag, status, error, and estimated cost.

ai_usage_summary()​

Description: Groups the retained usage buffer by query_id. calls counts per-input events (one event per request for ai_jev), while batch_count counts distinct provider request operation IDs, so packed embedding execution is visible without losing row-level token and error details. The result also includes retries, cache hits, total tokens, elapsed time, estimated cost, retained events, and counters for usage or log events dropped from bounded buffers.

Example:

SELECT query_id, provider, calls, batch_count, retries, cache_hits,
estimated_cost_usd, dropped_events
FROM ai_usage_summary()
ORDER BY estimated_cost_usd DESC;

Result columns: query_id, provider, model, calls, batch_count, retries, failures, cache_hits, total_tokens, elapsed_ms, estimated_cost_usd, retained_events, dropped_events, queued_log_events, dropped_log_events.

ai_clear_usage()​

Description: Clears the current DuckDB database instance's usage event buffer and returns one confirmation row.

Example:

SELECT *
FROM ai_clear_usage();

Result: one cleared BOOLEAN column

ai_clear_cache()​

Description: Clears the current DuckDB database instance's opt-in in-memory response cache, ai_query_data() generated-SQL cache, and bounded query-local ai_similarity() embedding cache, then returns one confirmation row.

Example:

SELECT *
FROM ai_clear_cache();

Result: one cleared BOOLEAN column

ai_secrets()​

Description: Lists configured duckdb_ai secrets with credential values redacted.

Example:

SELECT name, provider, model, base_url, has_api_key
FROM ai_secrets();

Result columns: name, provider, model, base_url, scope, storage, persistent, has_api_key

CREATE EXTERNAL MODEL and ai_models()​

Description: CREATE EXTERNAL MODEL registers a non-secret model profile in DuckDB's local secret catalog. The object stores provider routing, a reference to a TYPE duckdb_ai credential secret, capabilities, and safe JSON options; it never stores API keys. Existing profile := resolution checks external models first and then falls back to a credential-secret profile with that name.

Example:

CREATE OR REPLACE SECRET azure_ai (
TYPE duckdb_ai,
AI_PROVIDER 'azure',
API_KEY '...'
);

CREATE OR REPLACE EXTERNAL MODEL support_model
WITH (
provider = 'azure',
model = 'gpt-4o',
location = 'https://my-resource.openai.azure.com/openai/v1',
credential = 'azure_ai',
model_type = 'completion',
capabilities = 'completion,json_schema',
options = '{"max_input_tokens":128000,"max_batch_inputs":512,"input_token_price_per_million":2.5,"output_token_price_per_million":10}'
);

SELECT ai_complete('Summarize this ticket.', profile := 'support_model');
SELECT * FROM ai_models();

Embedding profiles can set max_batch_inputs, max_inputs, max_batch_tokens, max_request_bytes, context_size or max_input_tokens, embedding_dimensions, and native_batch_support in options. Packing uses these limits before sending requests and recursively splits provider HTTP 413 responses. Declared embedding dimensions are validated against provider output. Completion profiles enforce declared input-token and request-byte limits before issuing an HTTP request. model_type must be completion or embedding. Profiles can also set non-negative input_token_price_per_million and output_token_price_per_million; an explicit per-call or session price takes precedence.

ai_models() result columns: name, provider, model, location, credential, model_type, capabilities, options, max_batch_inputs, max_batch_tokens, max_request_bytes, context_tokens, embedding_dimensions, native_batch_jobs, input/output token prices, storage, persistent, and validation_status.

Endpoint control-plane functions​

Description: Optional table functions for an external, asynchronous endpoint service. Registration and inference never create billable cloud resources. ai_provision_endpoint() defaults to a local dry run. Submission requires both dry_run := false and a positive max_hourly_cost_usd; the service is expected to make operations idempotent and keep cloud credentials server-side.

SELECT * FROM ai_provision_endpoint('support_model');

SELECT *
FROM ai_provision_endpoint(
'support_model',
dry_run := false,
max_hourly_cost_usd := 5.00
);

SELECT * FROM ai_endpoint_status('operation-id');
SELECT * FROM ai_deprovision_endpoint('support_model');

Set DUCKDB_AI_CONTROL_PLANE_URL for applied operations and optionally DUCKDB_AI_CONTROL_PLANE_TOKEN for bearer authentication. The normalized result columns are operation_id, status, endpoint_url, estimated_hourly_cost_usd, action_required, and response.

ai_model_prices()​

Description: Returns the small built-in provider/model pricing catalog used by opt-in cost estimation.

Example:

SELECT provider, model, operation, input_token_price_per_million
FROM ai_model_prices();

Result columns: provider, model, operation, input_token_price_per_million, output_token_price_per_million, source_url, source_note, last_reviewed

Named options​

Completion functions accept constant named options unless noted otherwise. Provider credentials are resolved from environment variables or DuckDB secrets, not from direct API key arguments.

OptionTypeApplies toDescription
modelVARCHARCompletion, embedding, SQL assistant, aggregateProvider model name.
providerVARCHARCompletion, embedding, SQL assistant, aggregateProvider name or alias.
profile, secret, secret_nameVARCHARCompletion, embedding, SQL assistant, aggregateDuckDB secret name or profile.
temperatureDOUBLECompletion, SQL assistant, aggregateOptional sampling temperature between 0 and 2. When omitted, the provider or model default is used.
system_promptVARCHARCompletion, SQL assistant, aggregateOptional system message for providers that support chat-style payloads.
max_tokensBIGINTCompletion, SQL assistant, aggregateMaximum provider output tokens. Must be greater than 0. OpenAI, Cloudflare, MiniMax, Moonshot/Kimi, and Snowflake requests emit the current max_completion_tokens API field; other compatible providers retain max_tokens.
base_urlVARCHARCompletion, embedding, SQL assistant, aggregateProvider or gateway base URL override.
timeout_secondsBIGINTCompletion, embedding, SQL assistant, aggregateHTTP timeout. Must be greater than 0.
connect_timeout_secondsBIGINTCompletion, embedding, SQL assistant, aggregateHTTP connection timeout from 1 to 31536000 seconds. It must be less than or equal to the total timeout when a provider call runs.
retry_countBIGINTCompletion, embedding, SQL assistant, aggregateRetry count from 0 to 10 for curl failures and retryable HTTP status codes. Retries honor Retry-After on 429/5xx responses when present.
retry_backoff_msBIGINTCompletion, embedding, SQL assistant, aggregateBase retry backoff from 0 to 60000 milliseconds; exponential jitter is added per retry.
max_concurrent_requestsBIGINTCompletion, embedding, SQL assistant, aggregatePer-database request concurrency cap from 0 to 64.
min_request_interval_msBIGINTCompletion, embedding, SQL assistant, aggregatePer-database minimum interval between provider request starts.
token_limit_per_minuteBIGINTCompletion, embedding, SQL assistant, aggregatePer-database estimated token cap per rolling minute. 0 disables the token cap.
cacheBOOLEANCompletion, embedding, SQL assistant, aggregateEnables the current database instance's in-memory response cache for successful provider responses.
cache_ttl_secondsBIGINTCompletion, embedding, SQL assistant, aggregateOptional response-cache expiration from 0 to 31536000 seconds. 0 means entries do not expire by age. The DUCKDB_AI_CACHE_TTL_SECONDS environment variable sets the default.
cache_max_entriesBIGINTCompletion, embedding, SQL assistant, aggregateMaximum in-memory response-cache entries from 0 to 1000000. 0 disables response-cache storage. The DUCKDB_AI_CACHE_MAX_ENTRIES environment variable sets the default.
prompt_cacheBOOLEANCompletion, task wrappers, and SQL assistantEmits provider-side prompt-cache controls where supported. OpenAI requests include a stable prompt_cache_key; GPT-5.6 requests also mark the stable system-message prefix with an explicit cache breakpoint. Anthropic requests attach ephemeral cache control to the system prompt; xAI requests send x-grok-conv-id. The DUCKDB_AI_PROMPT_CACHE environment variable enables this by default.
allowed_hostsVARCHARCompletion, embedding, SQL assistant, aggregateComma-separated provider/logging host allowlist. Entries may be hostnames, host:port, full URLs, *.example.com, or *.
on_errorVARCHARCompletion, embedding, SQL assistant, aggregateError handling mode: fail, null, or capture. capture is used by ai_try_complete; scalar/table functions that cannot return an error field use NULL behavior.
fail_on_errorBOOLEANCompletion, embedding, SQL assistant, aggregateCompatibility alias: true maps to on_error := 'fail', false maps to on_error := 'null'.
response_formatVARCHARCompletion and SQL assistanttext, json_object, or json_schema. Poe's Chat Completions API ignores this field, so non-text formats are rejected for that provider.
response_schema, json_schemaVARCHARCompletion and SQL assistantJSON Schema object for provider-enforced structured output where supported, including OpenAI-compatible APIs, Anthropic, Cohere, llama.cpp, and Ollama, plus local response validation. Poe is excluded because its Chat Completions API ignores response_format.
input_token_price_per_millionDOUBLECompletion, embedding, SQL assistant, aggregateManual input-token price for cost estimation.
output_token_price_per_millionDOUBLECompletion, SQL assistant, aggregateManual output-token price for cost estimation.
use_builtin_model_pricesBOOLEANCompletion, embedding, SQL assistant, aggregateEnables lookup from ai_model_prices() when manual prices are not supplied.
log_formatVARCHARCompletion, embedding, SQL assistant, aggregategeneric, json, generic_json, otlp, or otlp_json.
log_tagsVARCHARCompletion, embedding, SQL assistant, aggregateComma-separated tags copied into usage log payloads.
log_sample_rateDOUBLECompletion, embedding, SQL assistant, aggregateStable sampling rate from 0 to 1.
log_include_textBOOLEANai_complete_record; all families through duckdb_ai_log_include_text or DUCKDB_AI_LOG_INCLUDE_TEXTInclude prompt/output text in outbound usage logs. Defaults to false.
log_strictBOOLEANai_complete_record; all families through duckdb_ai_log_strict or DUCKDB_AI_LOG_STRICTPost outbound usage logs synchronously and fail the SQL query when logging fails. Without strict logging, outbound logs are queued asynchronously on a best-effort basis.

See Runtime behavior for the execution semantics behind volatility, per-database state, concurrency, cancellation, retries, response caching, and egress allowlisting.

SQL assistant table functions also accept:

OptionTypeDescription
schema_context, schemaVARCHARPrompt context to use instead of generated local catalog context.
include_tablesVARCHAR[]Limit generated local catalog context to matching tables.
exclude_tablesVARCHAR[]Remove matching tables from generated local catalog context.
sample_rowsBIGINTInclude up to 100 sample rows per local table.
modeVARCHARai_fix_sql only. query or full rewrites the full query; line rewrites one error line.
errorVARCHARai_fix_sql only. Error text included in the correction prompt; in line mode it also identifies the target line. Without an explicit mode, passing error selects line mode.
fix_attemptsBIGINTai_sql, ai_query_data, and ai_fix_sql query mode. Number of bind-verified self-correction rounds from 0 to 5. Default 0 keeps single-shot behavior.

Aggregate functions also accept:

OptionTypeDescription
instruction, taskVARCHARConstant instruction for ai_agg.
separatorVARCHARSeparator inserted between grouped input values.
max_context_charsBIGINTMaximum grouped text characters sent to the model.
overflow_policyVARCHARhierarchical (default) recursively reduces every input, while error rejects groups that exceed max_context_chars.

Classification functions also accept:

OptionTypeDescription
label_descriptionsVARCHARConstant label semantics, commonly encoded as JSON.
instructionsVARCHARConstant global classification rules.
examplesVARCHARConstant few-shot examples, commonly encoded as JSON.

ai_build_classifier() additionally accepts optimization := 'minimize_cost', sample_size, quality_threshold, confidence_margin, embedding_model, embedding_provider, and embedding_profile. ai_classify_optimized() accepts fallback_profile plus completion options for the uncertain-row fallback.

Provider settings and secrets​

Supported provider names and aliases are:

ProviderAliasesCompletion supportEmbedding supportDefault completion model
ollamanoneYesYesllama3.2
openainoneYesYesgpt-5.6-luna
azureazure_openai, azure-openaiYesYesgpt-4o
anthropicclaudeYesNoclaude-haiku-4-5
bedrockaws_bedrock, amazon_bedrock, bedrock_mantleYesNoopenai.gpt-oss-120b
cerebrascerebras_cloudYesNogpt-oss-120b
cloudflareworkers_ai, cloudflare_workers_ai, cloudflare_aiYesYes@cf/zai-org/glm-4.7-flash
coherecohere_aiYesYescommand-a-plus-05-2026
dashscopeqwen, alibaba, alibaba_model_studio, model_studioYesYesqwen-plus
databricksmosaic, mosaic_ai, databricks_aiYesNodatabricks-gpt-oss-120b
deepinfradeepinfra_aiYesYesmeta-llama/Meta-Llama-3.1-8B-Instruct-Turbo
deepseeknoneYesNodeepseek-v4-flash
fireworksfireworks_aiYesYesaccounts/fireworks/models/gpt-oss-20b
geminigcp, google, google_geminiYesYesgemini-3.7-flash
groqgroqcloud, groq_cloudYesNoopenai/gpt-oss-20b
huggingfacehf, hugging_face, huggingface_hubYesNoopenai/gpt-oss-120b
hunyuantencent, tencent_hunyuanYesNohy3
minimaxmini_maxYesNoMiniMax-M2.7
mistralnoneYesYesmistral-small-latest
moonshotkimi, moonshot_ai, kimi_apiYesNokimi-k3
nebiusnebius_token_factory, token_factoryYesNometa-llama/Meta-Llama-3.1-70B-Instruct
nvidianvidia_nim, nimYesNonvidia/nemotron-3-super-120b-a12b
openrouternoneYesYesopenai/gpt-4o-mini
perplexitypplxYesNosonar
poepoe_apiYesNoGPT-5.4
qianfanbaidu, baidu_qianfan, ernie, wenxinYesNoernie-4.5-turbo-128k
sambanovasambanova_ai, samba_nova, sambacloudYesNoMeta-Llama-3.3-70B-Instruct
siliconflowsilicon_flowYesNoQwen/Qwen2.5-72B-Instruct
snowflakenoneYesNoclaude-sonnet-4-5
stepfunstep, step_funYesNostep-3.5-flash
togethertogether_aiYesYesmeta-llama/Llama-3.3-70B-Instruct-Turbo
vercelvercel_ai_gateway, vercel_gateway, ai_gatewayYesYesopenai/gpt-4o-mini
vertexgoogle_vertex, vertex_ai, gcp_vertexYesNogoogle/gemini-2.5-flash
volcenginevolcano_engine, volcengine_ark, doubao, arkYesNodoubao-seed-2-1-pro-260628
xaix.ai, x-ai, grokYesNogrok-4.6
zaizhipuYesYesglm-4.7-flash
openai_privacy_filterprivacy_filter, pii_filter, opfRedaction onlyNoopenai/privacy-filter
openai_compatiblelocal, openai-compatible, local_openai, local-models, local_modelsYesYesgpt-4o-mini
llamacppllama.cpp, llama-cpp, llama_cpp, llama-server, llama_serverYesYesdefault (llama-server answers with its loaded model)

Session defaults can be configured with DuckDB settings:

SET duckdb_ai_provider = 'openai';
SET duckdb_ai_model = 'gpt-5.6-luna';
SET duckdb_ai_embedding_model = 'text-embedding-3-small';
SET duckdb_ai_base_url = 'https://api.openai.com/v1';
SET duckdb_ai_timeout_seconds = 120;
SET duckdb_ai_allowed_hosts = 'api.openai.com,collector.example';
SET duckdb_ai_cache = true;

duckdb_ai_model is the global model fallback. Family-specific model settings override it for their function groups, while per-call model := ... still takes highest precedence:

SettingApplies to
duckdb_ai_completion_modelai_complete, ai_complete_json, ai_complete_record, ai_completion_request_json, ai_rerank, ai_score
duckdb_ai_task_modelai_summarize, ai_sentiment, ai_fix_grammar, ai_redact, ai_translate, ai_classify, ai_classify_labels, ai_classify_result, ai_extract, ai_filter, classifier labeling and fallback
duckdb_ai_aggregate_modelai_agg, ai_summarize_agg
duckdb_ai_sql_assistant_modelai_sql, ai_query_data, ai_explain_sql, ai_fix_sql
duckdb_ai_embedding_modelai_embed, ai_embedding_request_json, ai_similarity, ai_build_classifier, ai_classify_optimized

Model resolution order is:

  1. Per-call model := ...
  2. External model selected through profile := ...
  3. Matching function-family setting
  4. duckdb_ai_model
  5. Provider default model

Credentials should use environment variables or DuckDB secrets:

CREATE OR REPLACE SECRET openai_ai (
TYPE duckdb_ai,
AI_PROVIDER 'openai',
API_KEY '...',
MODEL 'gpt-5.6-luna'
);

SELECT ai_complete('hello', secret := 'openai_ai');