Run a local LLM (Ollama) inside Oracle APEX
Private, on-prem AI for APEX — call a local Ollama model from PL/SQL or register it as an APEX Generative AI Service, so prompts never leave your network.
For sensitive workloads you may not want to send data to a cloud LLM. Ollama runs open-weight models on your own machine or server and exposes them over a local HTTP API. Oracle APEX can call that API from PL/SQL — or, from APEX 26.1, use it as a built-in AI provider — so inference stays on infrastructure you control.
Run Ollama
Install Ollama and pull a small instruct model (llama3.2 is the 3B model, about 2 GB). The Windows app runs in the background after install; on Linux the server usually runs as a systemd service — if it isn't running, start it with ollama serve. Either way it serves an HTTP API on http://localhost:11434.
# Install Ollama from https://ollama.com/download (it runs in the background), then: ollama pull llama3.2 ollama run llama3.2 "Say hello in one sentence" curl.exe http://localhost:11434/api/version
⚠ Can the database actually reach Ollama?
127.0.0.1:11434 by default. The examples below use host.docker.internal, which works when the database runs in a container under Docker Desktop (on Linux Docker Engine, start the container with --add-host=host.docker.internal:host-gateway — that name then points at the Docker bridge gateway, not at loopback, so Ollama must also listen beyond 127.0.0.1: run systemctl edit ollama.service, add Environment="OLLAMA_HOST=0.0.0.0:11434" under [Service], then reload systemd and restart Ollama). If the database is on another server, use the Ollama host's name or IP and set the same OLLAMA_HOST=0.0.0.0:11434 on that host. A local Ollama server does not check API keys, so keep port 11434 on a trusted network and never expose it to the internet.Allow the database to make the call
Outbound network calls are blocked until a network ACL allows them. APEX_WEB_SERVICE and the APEX AI features make the call as the APEX engine schema (for example APEX_260100 on APEX 26.1) — not as APEX_PUBLIC_USER and not as your parsing schema. Many installs already grant it during setup, so check first. Connect as a DBA to the PDB where APEX is installed — Oracle AI Database 26ai is always a container database, and CDB$ROOT has no APEX, so the grant below fails there with PLS-00201 on APEX_APPLICATION. Replace FREEPDB1 with your PDB name:
ALTER SESSION SET CONTAINER = FREEPDB1; SELECT host, lower_port, upper_port, principal, privilege FROM dba_host_aces ORDER BY host, principal;
If there is no matching entry, grant connect on just the Ollama host and port. Run this as SYS (or another user allowed to run DBMS_NETWORK_ACL_ADMIN) in the same APEX PDB session; APEX_APPLICATION.g_flow_schema_owner resolves to the current APEX engine schema, so the script survives APEX upgrades:
BEGIN
DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
host => 'host.docker.internal',
lower_port => 11434,
upper_port => 11434,
ace => xs$ace_type(privilege_list => xs$name_list('connect'),
principal_name => APEX_APPLICATION.g_flow_schema_owner,
principal_type => xs_acl.ptype_db));
END;
/ℹ Calling UTL_HTTP yourself?
UTL_HTTP directly instead of APEX_WEB_SERVICE, grant the same ACE to your parsing schema as well — otherwise you get ORA-24247: network access denied by access control list (ACL). On Autonomous Database the network rules are different (outbound calls must use HTTPS), so this guide targets a self-managed database.Call the model from PL/SQL
Post to Ollama's /api/generate endpoint. Set "stream": false — the API streams by default — and read the generated text from the response field. Building the body with JSON_OBJECT_T escapes quotes in user input for you.
DECLARE
l_req json_object_t := json_object_t();
l_resp CLOB;
l_answer CLOB;
BEGIN
l_req.put('model', 'llama3.2');
l_req.put('prompt', 'Summarize in one sentence: order 1001 shipped two days late because of a customs hold.');
l_req.put('stream', false);
apex_web_service.set_request_headers(
p_name_01 => 'Content-Type',
p_value_01 => 'application/json');
l_resp := apex_web_service.make_rest_request(
p_url => 'http://host.docker.internal:11434/api/generate',
p_http_method => 'POST',
p_body => l_req.to_clob,
p_transfer_timeout => 120);
IF apex_web_service.g_status_code <> 200 THEN
raise_application_error(-20001,
'Ollama returned HTTP ' || apex_web_service.g_status_code || ': ' ||
dbms_lob.substr(l_resp, 500, 1));
END IF;
-- The generated text is in the "response" field
l_answer := json_object_t.parse(l_resp).get_clob('response');
dbms_output.put_line(l_answer);
END;
/For multi-turn conversations use /api/chat with a messages array instead. Ollama also offers an OpenAI-compatible API under http://localhost:11434/v1 (for example /v1/chat/completions), which is handy if your code already speaks the OpenAI format.
Or: register Ollama as an APEX Generative AI Service (APEX 26.1+)
From APEX 26.1, Ollama and OpenAI-compatible endpoints are built-in AI providers. In App Builder go to Workspace Utilities → Generative AI, click Create, choose the Ollama provider, enter the Ollama server URL as the Base URL, set AI Model to llama3.2, give it a Static ID such as LOCAL_OLLAMA, and click Test Connection. The same network ACL applies. Which Ollama API APEX calls depends on the release: APEX 26.1 uses Ollama's native /api/chat and /api/embed; in APEX 26.2 new Ollama services default to the Responses API (Chat Completions is deprecated), selectable under Advanced → Provider API. Ollama added its OpenAI-compatible /v1/responses endpoint in v0.13.3, so upgrade older Ollama installs before using that default. The service can then back the declarative AI features or be called from PL/SQL running in that workspace's apps with APEX_AI:
DECLARE
l_answer CLOB;
BEGIN
l_answer := apex_ai.generate(
p_prompt => 'Summarize in one sentence: order 1001 shipped two days late because of a customs hold.',
p_system_prompt => 'You are a concise assistant for an order-management app.',
p_service_static_id => 'LOCAL_OLLAMA');
dbms_output.put_line(l_answer);
END;
/💡 Keep prompts grounded
Check your understanding
Check your understanding
0% · 0/3What's the main reason to run a local LLM?
How does PL/SQL reach Ollama?
Which principal needs the network ACL for APEX_WEB_SERVICE calls?
Need this delivered?
Request a quote