qua_add_external_ai_model#
Registers an external generative AI model — the endpoint, format and model identity that the
AI functions invoke. The model is stored as an
instance-scoped connection under the internal AI Model provider and is listed by the
sys.external_models view.
The registration carries no API key. A model’s key resolves at call time from a credential, by the model’s endpoint URL — see Provider API keys below.
Syntax#
qua_add_external_ai_model [ @name = ] N'name'
, [ @api_format = ] N'api_format'
, [ @location = ] N'location'
, [ @model = ] N'model'
[ , [ @parameters = ] N'parameters' ]
Arguments#
[ @name = ] N’name’
The model’s registration name — the value used to bind it to a session and to drop it. sysname. The name must be unique among the instance’s connections.
[ @api_format = ] N’api_format’
The provider wire format: Anthropic, OpenAI or Azure OpenAI. sysname. The value is
matched case-insensitively and stored in the canonical spelling above; any other value is rejected
at registration.
[ @location = ] N’location’
The full HTTPS endpoint the requests are sent to. nvarchar(4000). For Azure OpenAI the
deployment and api-version are part of the URL. This is also the name a credential must carry
to supply this model’s API key — see Provider API keys below.
[ @model = ] N’model’
The provider-side model identifier, for example claude-sonnet-5 or gpt-4o.
nvarchar(128). Azure OpenAI takes the deployment from the endpoint URL; the value is still
recorded for the catalog view.
[ @parameters = ] N’parameters’
Optional JSON object of provider request parameters, merged into every request the model serves —
for example N'{"max_tokens":1024,"temperature":0.2}'. A parameter overrides the same-named
request field. The keys messages, model, system and stream are controlled by the AI
function and are rejected.
The reserved sql_rest_options key is consumed by Querona itself and is never forwarded to the
provider:
Option |
Description |
|---|---|
|
Ceiling, in seconds (0–600, default 20), applied to a wait the provider requests through the
|
Remarks#
A single registered model is used by the AI functions automatically. When more than one model is registered, bind the session’s ambient model by name:
EXEC sys.sp_set_session_context N'ai_default_model', N'MyClaude';
Provider API keys#
A model’s API key is never part of its registration — it resolves at call time from a
CREDENTIAL or
DATABASE SCOPED CREDENTIAL
whose name is the model’s @location endpoint URL, matched by the same prefix rule
OPENROWSET (BULK ...) uses for direct-URL authentication (name equals the URL, or is a prefix of
it ending at a / boundary). Highest precedence first:
A database scoped credential in the calling database — a per-database override, for example a tenant-specific key on a shared cluster.
A server credential — a cluster-wide default available to every database.
A call with no matching credential at either scope fails, naming the endpoint (never any key material).
-- once, any node: every database's Anthropic models use this key by default
CREATE CREDENTIAL [https://api.anthropic.com] WITH IDENTITY = 'anthropic', SECRET = 'sk-ant-default...';
-- a single tenant database: its models use the tenant's own key instead
USE TenantDb;
CREATE DATABASE SCOPED CREDENTIAL [https://api.anthropic.com] WITH IDENTITY = 'anthropic', SECRET = 'sk-ant-tenant...';
A credential that matches but carries no secret#
An AI call always consumes the winning credential’s secret — there is no identity-only authentication mode for an AI endpoint. When the winning credential carries no secret, the call fails with a clear error naming the credential (never any key material): “The credential ‘…’ carries no secret, but its authentication mode requires one.”
A credential legally holds no secret in two ordinary situations: it was created identity-only
(SECRET is optional), or a later ALTER restated the identity and omitted SECRET, which
clears the stored secret. Because a database scoped credential wins outright over the server-level
default, an identity-only database scoped credential also shadows a working cluster key for its
database:
-- the cluster default works everywhere:
CREATE CREDENTIAL [https://api.anthropic.com] WITH IDENTITY = 'anthropic', SECRET = 'sk-ant-default...';
USE TenantDb;
-- legal, but for an AI endpoint always a misconfiguration: no secret to send.
CREATE DATABASE SCOPED CREDENTIAL [https://api.anthropic.com] WITH IDENTITY = 'Managed Identity';
-- this database's AI calls now fail, naming the identity-only credential that
-- outranks the working cluster default; other databases are unaffected.
SELECT AI_SUMMARIZE(review_text) FROM hotel_reviews;
-- recovery is one statement, picked up by the very next call (resolution is
-- per call and never cached):
DROP DATABASE SCOPED CREDENTIAL [https://api.anthropic.com];
The same error after an ALTER on the endpoint credential means the ALTER did not restate
SECRET and has cleared the key;
ALTER CREDENTIAL [<endpoint>] WITH IDENTITY = '<identity>', SECRET = '<api-key>' restores it.
Example#
Registers an Anthropic and an Azure OpenAI model, creates their credentials, then summarizes with the bound model.
EXEC qua_add_external_ai_model
@name = N'MyClaude',
@api_format = N'Anthropic',
@location = N'https://api.anthropic.com/v1/messages',
@model = N'claude-sonnet-5',
@parameters = N'{"max_tokens":1024}';
CREATE CREDENTIAL [https://api.anthropic.com/v1/messages] WITH IDENTITY = 'anthropic', SECRET = '<api-key>';
EXEC qua_add_external_ai_model
@name = N'MyAzureGpt',
@api_format = N'Azure OpenAI',
@location = N'https://myresource.cognitiveservices.azure.com/openai/deployments/gpt-4o/chat/completions?api-version=2024-06-01',
@model = N'gpt-4o';
CREATE CREDENTIAL [https://myresource.cognitiveservices.azure.com] WITH IDENTITY = 'azure', SECRET = '<api-key>';
EXEC sys.sp_set_session_context N'ai_default_model', N'MyClaude';
SELECT AI_SUMMARIZE(review_text) AS summary FROM hotel_reviews;