DEV Community

Cover image for Azure AI on HorizonDB (Microsoft Foundry Azure OpenAI from SQL)
Franck Pachot
Franck Pachot

Posted on

Azure AI on HorizonDB (Microsoft Foundry Azure OpenAI from SQL)

The azure_ai extension on HorizonDB adds generative AI functions to PostgreSQL, allowing users to utilize Azure AI's generation, ranking, and embedding models. Here's a four-step example that demonstrates how to define default models, set up endpoints, register them, and use the in SQL queries.

1. Allow and install the extension

The azure_ai extension must be set in azure.extensions from the parameter group:

Once enabled, you can CREATE EXTENSION:

postgres=> SHOW azure.extensions;

             azure.extensions
------------------------------------------
 pg_diskann,vector,pg_textsearch,azure_ai

(1 row)

postgres=> CREATE EXTENSION IF NOT EXISTS azure_ai;

CREATE EXTENSION

Enter fullscreen mode Exit fullscreen mode

The functions are available, but I don't have access to an AI model yet:

postgres=> SELECT azure_ai.generate(
            'Hello'
           );

ERROR:  Endpoint not found.
DETAIL:  Please set/register the model.

Enter fullscreen mode Exit fullscreen mode

An AI Model Management feature is coming to HorizonDB, currently in private preview, which is basically a zero-setup mode for azure_ai, but for the moment, I will do it manually.

2. Deploy a model in Azure

I go to the Microsoft Foundry | Azure OpenAI, hit "Create" and select "Azure OpenAI":

I set my resource group and region:

I use the default network setting that allows all networks, including the internet, to access this resource.

Once created, the next step is to "go to resource" in order to deploy a model:

In the model catalog, I select the chat models, for LLM tasks and generation purposes:

I hit "Uset this model" and deploy gpt-4o-mini:

The URL and API key is displayed in the Home section:

The details for the available models is in the Deployments section:

I can also get the parameters from the Python sample:

endpoint = "https://frankpachot-ai.openai.azure.com/"
model_name = "gpt-4o-mini"
deployment = "gpt-4o-mini"

subscription_key = "<your-api-key>"
api_version = "2024-12-01-preview"

client = AzureOpenAI(
    api_version=api_version,
    azure_endpoint=endpoint,
    api_key=subscription_key,
Enter fullscreen mode Exit fullscreen mode

This information will be used to register the model from PostgreSQL.

I'll use them directly, but in production, keys should be stored in a secrets management system instead of being hardcoded in SQL.

3. Register the model in PostgreSQL

In HorizonDB, I can add AI models with model_registry.model_add() which takes the following parameters:

parameter meaning
alias SQL name
endpoint where to call the model
deployment which model instance
model_name metadata / capability
api_version protocol version
auth_type how to authenticate
key credential

The deployment name must exactly match the one defined in Azure. This is not the model name but the deployment identifier.

Here is the registration with the information from the chat model I deployed:

postgres=> SELECT model_registry.model_add(
    'default-chat',                                 -- alias
    'https://frankpachot-ai.openai.azure.com/',     -- azure_endpoint
    'gpt-4o-mini',                                  -- deployment name
    'gpt-4o-mini',                                      -- model name
    '2024-12-01-preview',                           -- api_version
    'subscription-key',                             -- auth type
    'FR3Xcz5VXiHSbz8Eqeo5qXsyKqgxrFeYCSuqOv...'     -- api_key
);

                       model_add
--------------------------------------------------------
 Model 'default-chat' (gpt-4o-mini) added successfully.

(1 row)


Enter fullscreen mode Exit fullscreen mode

PostgreSQL can now invoke the Azure OpenAI deployment.

With this solution, the database itself doesn’t host the model. It only contains the information needed to call it, such as the endpoint, deployment, and key, but the calls to Azure OpenAI are transparent to the users.

4. Use the model from SQL queries

Now, azure_ai.generate() can use the registered model for generative AI:

postgres=> SELECT azure_ai.generate(
    'Who is Slonik and how does he look like? context:'|| version()
  , 'default-chat'
);

generate     
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Slonik is a mascot for PostgreSQL, often depicted as a friendly, cartoonish elephant. He typically has a blue-gray body, large floppy ears, and a cheerful expression. Slonik embodies the PostgreSQL community's spirit and is often used in promotional materials and events related to PostgreSQL.
(1 row)

postgres=>
Enter fullscreen mode Exit fullscreen mode

The model name default-chat is the default for this function. I can omit it.

Instead of employing the model for text generation, I can utilize it to validate my text with azure_ai.is_true().

Let's verify the correct names for our favorite database:

postgres=> select azure_ai.is_true( format (
           '%s is the right name for Slonik''s database', unnest
            )), string_agg(unnest,',') from unnest(ARRAY[
            'PostgreSQL','Postgres','PG','pgsql','postgresql',
            'POSTGRES','pgdb','postgres-db','SQL','psql',
            'postmaster','postgré','postgrès','posgress',
            'posgresql','postgrasql','postgray','postgrest',
            'postgrezql','postgrex','postgresesql','postgresequel',
            'Post-Ingres',' Post-Gres-Q-L','Postgres95','pg-sql',
            'pgserver','pg-database','HorizonDB',
            'slonik-db','elephant-db','the elephant'
             ]) group by 1 order by 1 desc;

agg
---------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 t       | PostgreSQL,Postgres,postgresql,POSTGRES,the elephant
 f       | PG,pgsql,pgdb,postgres-db,SQL,psql,postmaster,postgré,postgrès,posgress,posgresql,postgrasql,postgray,postgrest,postgrezql,postgrex,postgresesql,postgresequel,Post-Ingres, Post-Gres-Q-L,Postgres95,pg-sql,pgserver,pg-database,HorizonDB,slonik-db,elephant-db

(2 rows)

Enter fullscreen mode Exit fullscreen mode

Ok, according to gpt-4o-mini, "The Elephant" is a valid name for PostgreSQL.

The chat model can also be used to extract structured information from unstructured text. For example, from the version() banner I'm interested in the PostgreSQL compatibility version, and the name of the managed service:

postgres=> SELECT version();

                                                        version
-----------------------------------------------------------------------------------------------------------------------
 PostgreSQL 17.9 (Azure HorizonDB (70f3b593ec7)(release)) on x86_64-pc-linux-gnu, compiled by gcc (GCC) 13.2.0, 64-bit
(1 row)

postgres=> SELECT azure_ai.extract(
             version() , -- text from which to extract
             ARRAY['PostgreSQL compatibility','Cloud service name']
            );

                                    extract
-------------------------------------------------------------------------------
 {"Cloud service name": "Azure HorizonDB", "PostgreSQL compatibility": "17.9"}

(1 row)

Enter fullscreen mode Exit fullscreen mode

In order to generate embeddings, I need to deploy a dedicated model:

With the same method I used for chat models, I got the endpoint, name, and key to access this embedding model:

postgres=> SELECT model_registry.model_add(
    'default-embedding',                            -- alias
    'https://franckpachot-ai.openai.azure.com/',     -- azure_endpoint
    'text-embedding-3-small',                       -- deployment name
    'text-embedding-3-small',                       -- model name
    '2024-12-01-preview',                           -- api_version
    'subscription-key',                             -- auth type
    'FR3Xcz5VXiHSbz8Eqeo5qXsyKqgxrFeYCSuqOv...'     -- api_key
);

                              model_add
---------------------------------------------------------------------
 Model 'default-embedding' (text-embedding-3-small) added successfully.

(1 row)

Enter fullscreen mode Exit fullscreen mode

Using the alias default-embedding, which I defined when registering the model deployment, I can generate embeddings for specific text:

postgres=> SELECT azure_openai.create_embeddings(
    'default-embedding',
    'hello world'
);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 create_embeddings                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
----------------------------------------------------------------
{-0.006729126,-0.03918457,0.03414917,0.028747559,-0.024841309,-0.041992188,-0.030288696,0.049316406,-0.013969421,-0.017669678,0.015396118,-0.026992798,-0.020980835,-0.027801514,0.008583069,0.03567505,-0.053619385,-0.0023059845,0.008773804,0.048034668,0.037078857,-0.009239197,-0.008781433,0.011428833,0.0140686035,-0.002161026,-0.037597656,0.04547119,0.0112838745,-0.03967285,0.0234375,-0.050628662,0.011985779,...}
(1 row)

postgres=>

Enter fullscreen mode Exit fullscreen mode

Note that the azure_ai extension deploys functions in different namespaces. High‑level semantic operations, independent of the model vendor, such as generate(), is_true(), extract(), rank() are in the azure_ai schema. In contrast, create_embeddings, which returns vectors and is tied to the OpenAI API, is in the azure_openai schema.

I have also enabled pg_vector to use the vector data type and operators for generated embeddings. Here is an example using a prompt to find PostgreSQL settings related to shared buffer cache memory:

postgres=> CREATE EXTENSION vector;

CREATE EXTENSION

postgres=> WITH settings AS (
  SELECT name, short_desc, azure_openai.create_embeddings('default-embedding',
      row_to_json(pg_settings)::text
  )::vector AS embedding FROM pg_settings
) SELECT
  name, short_desc FROM settings
  ORDER BY embedding <=> azure_openai.create_embeddings('default-embedding',
    'Buffer cache shared memory allocated by PostgreSQL'
  )::vector LIMIT 5;

            name            |                                       short_desc
----------------------------+----------------------------------------------------------------------------------------
 effective_cache_size       | Sets the planner's assumption about the total size of the data caches.
 shared_memory_type         | Selects the shared memory implementation used for the main shared memory region.
 shared_buffers             | Sets the number of shared memory buffers used by the server.
 shared_memory_size         | Shows the size of the server's main shared memory area (rounded up to the nearest MB).
 dynamic_shared_memory_type | Selects the dynamic shared memory implementation used.

(5 rows)

Enter fullscreen mode Exit fullscreen mode

I haven't set an index or stored embeddings here. This example simply demonstrates how it works in a stateless demo. The similarity search uses the cosine distance operator <=> to compare data from pg_settings with my prompt, returning the Top-5 matches. In a real application, you would generate the embeddings within an AI pipeline, then store and index them using pg_vector or DiskANN, rather than calling azure_openai.create_embeddings() on each query, except for the prompt.

AzureAI also provides functions for re-ranking the results of a similarity search. Ideally, a dedicated ranking model should be used. Here, I didn't deploy one and used the chat model for demonstration.:

postgres=> WITH
 settings AS (
  SELECT name, short_desc, row_to_json(pg_settings)::text AS doc,
      azure_openai.create_embeddings( 'default-embedding',
        row_to_json(pg_settings)::text
      )::vector AS embedding FROM pg_settings),
 candidates as (
  SELECT name, short_desc, doc FROM settings
  ORDER BY embedding <=> azure_openai.create_embeddings( 'default-embedding',
    'Buffer cache shared memory allocated by PostgreSQL'
  )::vector LIMIT 20 ),
 reranked AS ( SELECT * FROM azure_ai.rank(
    'Setting the buffer cache shared memory allocated by PostgreSQL',
    ARRAY (SELECT doc FROM candidates),  -- text to rank
    ARRAY (SELECT name FROM candidates), -- id of the item
    'default-chat'
  )
)
SELECT r.*, s.short_desc
 FROM settings s JOIN reranked r ON r.id = s.name
 ORDER BY r.rank LIMIT 5
;

             id             | rank | score |                                       short_desc
----------------------------+------+-------+----------------------------------------------------------------------------------------
 shared_buffers             |    1 |   0.9 | Sets the number of shared memory buffers used by the server.
 effective_cache_size       |    2 |   0.8 | Sets the planner's assumption about the total size of the data caches.
 shared_memory_type         |    3 |   0.7 | Selects the shared memory implementation used for the main shared memory region.
 shared_memory_size         |    4 |   0.5 | Shows the size of the server's main shared memory area (rounded up to the nearest MB).
 dynamic_shared_memory_type |    5 |   0.4 | Selects the dynamic shared memory implementation used.
(5 rows)

Enter fullscreen mode Exit fullscreen mode

I registered two models for this demonstration:

postgres=> SELECT * FROM model_registry.model_list_all();

       alias       |       model_name       |        registry_type        | model_creator | model_users |   status   |          created_at           |          updated_at           |                 endpoint                 |    auth_type     |    api_version     |    deployment_name
-------------------+------------------------+-----------------------------+---------------+-------------+------------+-------------------------------+-------------------------------+------------------------------------------+------------------+--------------------+------------------------
 default-chat      | gpt-4o-mini            | Bring Your Own Model (BYOM) | franck        | public      | registered | 2026-06-26 15:53:44.045341+00 | 2026-06-26 15:53:44.045341+00 | https://frankpachot-ai.openai.azure.com/ | subscription-key | 2024-12-01-preview | gpt-4o-mini
 default-embedding | text-embedding-3-small | Bring Your Own Model (BYOM) | franck        | public      | registered | 2026-06-26 16:16:00.059347+00 | 2026-06-26 16:16:00.059347+00 | https://frankpachot-ai.openai.azure.com/ | subscription-key | 2024-12-01-preview | text-embedding-3-small

(2 rows)

postgres=>

Enter fullscreen mode Exit fullscreen mode

When embeddings are stored and indexed, the embedding search is the cheap first pass: it finds settings that are close to the question in the vector space. The reranker is the precise second pass: it looks again at the selected candidates and sorts them by relevance to the question. This is useful because vector similarity gives good candidates, but not always the best order. In this example, I even re-rank them with a more precise question.

Here is a final example, where I store the content of this blog post into a PostgreSQL table and call azure_ai to generate a pitch:

postgres=> CREATE TEMP TABLE blog(raw text);

CREATE TABLE

postgres=> \copy blog FROM PROGRAM ' curl -s "https://dev.to/franckpachot/azure-ai-on-horizondb-fbk" | tr -d "\r" | tr "\n" " " ' WITH (format text);

COPY 1

postgres=> SELECT azure_ai.generate(
           'Generate a short LinkedIn post to pitch (tech, not marketing) this article, in 5 small bullet points:' || raw
           ) FROM blog;

                                                                    generate
------------------------------------------------------------------------------------------------------------------------------------------------
 🚀 Exciting news for tech enthusiasts! Check out this article on integrating Azure AI with HorizonDB:                                         +
                                                                                                                                               +
 - **Generative AI Functions**: The `azure_ai` extension brings powerful generative AI capabilities directly to PostgreSQL.                    +
 - **Seamless Integration**: Easily install and configure the extension without altering your database architecture.                           +
 - **Model Management**: Learn how to deploy and register AI models in Azure with straightforward steps.                                       +
 - **Efficient Data Processing**: Utilize external AI models for tasks like text generation while keeping your data local.                     +
 - **Future of Databases**: This extension showcases how AI can enhance traditional database systems, merging functionality with SQL integrity.+
                                                                                                                                               +
 🔗 Read more here: [Azure AI on HorizonDB](https://dev.to/franckpachot/azure-ai-on-horizondb-fbk)
(1 row)

Enter fullscreen mode Exit fullscreen mode

Conclusion

The azure_ai extension on HorizonDB (currently in preview) exposes generative AI functions directly in PostgreSQL. It does not run models locally: it stores connection details and calls external Azure AI endpoints from SQL.

This extension is only available in HorizonDB and not in upstream PostgreSQL or Azure Database for PostgreSQL. The feature depends on HorizonDB-specific integration with Azure AI services and the model registry.

The examples here show direct calls from SQL, but this is mostly for demonstration. In practice, embeddings are generated once, in workflows defined with pg_durable functions, stored with pg_vector datatypes, and indexed with HSNW or DiskANN. Queries generate embeddings for the parameters.

Top comments (0)