Fonctions IA dans Trino — AKKO vs upstream¶
Deux familles indépendantes de fonctions IA sont utilisables dans Trino. Elles cohabitent sans collision et ciblent des besoins différents :
| Famille | Préfixe | Invocation | Fournie par |
|---|---|---|---|
| Plugin AKKO (cette plateforme) | akko_ai_* |
globale, sans préfixe de catalogue | plugin AKKO trino-ai-functions |
| Trino upstream | ai_* |
llm.ai.<fonction>(...) via le catalogue llm |
connecteur de catalogue llm Trino 466+ |
TL;DR
Utilisez akko_ai_* pour toute charge de travail en production AKKO —
elles passent par la stack gouvernée AKKO (cache Caffeine, OPA par
rôle, spans d'audit Tempo, multimodal, embeddings). Utilisez la
famille upstream llm.ai.* quand vous voulez un comportement Trino
standard ou pour des démos comparatives. Les deux peuvent être
activées en même temps.
Vue d'ensemble — 23 fonctions AKKO vs 7 upstream¶
| Aspect | AKKO akko_ai_* (plugin global) |
Trino upstream ai_* (llm.ai) |
|---|---|---|
| Invocation | SELECT akko_ai_translate(...) |
SELECT llm.ai.ai_translate(...) (ou ai_translate(...) si llm.ai est dans le search_path) |
| Fonctions disponibles | 23 — texte, multimodal, embeddings, admin | 7 — texte uniquement |
| Fournisseur | akko-ai-service → LiteLLM → Ollama/OpenAI/Anthropic/Mistral |
HTTP direct vers un seul fournisseur (OpenAI, Anthropic ou Ollama) |
| Cache par texte de requête | Caffeine LRU, par worker, 10k entrées, TTL 1 h | aucun |
| Circuit breaker | oui — fail-closed après N erreurs, half-open automatique | aucun |
| RBAC OPA par fonction | oui — allow-list par rôle appliquée côté service | pas intégrée |
| Trace d'audit | spans Tempo + en-tête X-Akko-Ai-Function + Loki audit_type=AI_RBAC |
journalisé seulement côté fournisseur |
| Multimodal | texte + image + audio + PDF | texte uniquement |
| Embeddings + recherche sémantique | akko_ai_embed, akko_ai_similarity, akko_ai_search (embed une fois par texte de requête distinct par worker — l'appel HTTP a lieu une fois quelle que soit la cardinalité) |
indisponible |
| Gestion d'erreur | @SqlNullable — toute erreur renvoie SQL NULL, Trino jamais déstabilisé |
comportement par défaut du plugin (peut remonter en erreur de requête) |
| Modèle de coût | le cache écrase N lignes avec le même texte en 1 appel HTTP | 1 appel HTTP par ligne |
| Licence | Apache 2.0, livrée avec AKKO | Apache 2.0, livrée par Trino upstream |
La famille AKKO akko_ai_* — 23 fonctions¶
Les 23 fonctions sont globales, enregistrées via
Plugin.getFunctions(). On les appelle directement :
Ne jamais préfixer avec ai.default. — ce chemin passe par le
catalogue PostgreSQL ai (fallback PL/Python), pas par le plugin JVM
natif. Si SELECT akko_ai_sentiment(...) renvoie « Function not
registered », l'image custom akko-trino n'est pas déployée — vérifier
kubectl describe pod -l app=trino.
Catégories¶
| Catégorie | Fonctions | Coût |
|---|---|---|
| Scalaires texte (HTTP par entrée distincte) | akko_ai_ask, akko_ai_sentiment, akko_ai_classify, akko_ai_summarize, akko_ai_translate, akko_ai_entities, akko_ai_anomaly, akko_ai_sql, akko_ai_risk, akko_ai_pii, akko_ai_sensitivity, akko_ai_language, akko_ai_keywords |
1 appel LLM par valeur distincte (réduite par le cache) |
| Multimodal | akko_ai_ocr, akko_ai_describe_image, akko_ai_parse_document, akko_ai_transcribe |
1 appel multimodal par entrée |
| Embeddings | akko_ai_embed |
1 appel embed par texte distinct |
| Calcul vectoriel (local pur) | akko_ai_similarity, akko_ai_search |
0 appel HTTP par ligne (après le premier akko_ai_search) |
| Helpers admin | akko_ai_stats, akko_ai_health, akko_ai_version, akko_ai_cache_clear, akko_ai_cb_reset |
aucun |
Scalaires texte¶
| Fonction | Signature | Exemple | Renvoie |
|---|---|---|---|
akko_ai_ask |
(question VARCHAR[, contexte VARCHAR]) |
akko_ai_ask('Qu''est-ce qu''un lakehouse?') |
réponse libre |
akko_ai_sentiment |
(texte VARCHAR) |
akko_ai_sentiment('J''adore') |
POSITIVE / NEUTRAL / NEGATIVE |
akko_ai_classify |
(texte VARCHAR, catégories VARCHAR) |
akko_ai_classify('serveur planté', 'bug,feature') |
une catégorie |
akko_ai_summarize |
(texte VARCHAR[, n INT]) |
akko_ai_summarize(description, 2) |
résumé en N phrases |
akko_ai_translate |
(texte VARCHAR[, langue_cible VARCHAR]) |
akko_ai_translate('Hello', 'French') |
texte traduit |
akko_ai_entities |
(texte VARCHAR) |
akko_ai_entities('Tim Cook chez Apple') |
JSON array [{type, value}] |
akko_ai_anomaly |
(valeur VARCHAR[, contexte VARCHAR]) |
akko_ai_anomaly('150000', 'moyenne 45000') |
JSON {is_anomaly, score, reason} |
akko_ai_sql |
(question VARCHAR[, schéma VARCHAR]) |
akko_ai_sql('top clients', 'orders(id,total)') |
chaîne SQL |
akko_ai_risk |
(profil VARCHAR) |
akko_ai_risk('solde=-5000,inactif') |
score 0–100 |
akko_ai_pii |
(texte VARCHAR) |
akko_ai_pii('Jean, jean@mail.com') |
texte masqué |
akko_ai_sensitivity |
(texte VARCHAR) |
akko_ai_sensitivity('NIR 1 85 07...') |
classe RGPD (personal, sensitive, public) |
akko_ai_language |
(texte VARCHAR) |
akko_ai_language('Bonjour') |
code ISO (fr, en…) |
akko_ai_keywords |
(texte VARCHAR[, n INT]) |
akko_ai_keywords('détection fraude ML', 3) |
mots-clés séparés par virgules |
Multimodal¶
| Fonction | Signature | Rôle |
|---|---|---|
akko_ai_ocr |
(image BYTES) |
image → texte extrait |
akko_ai_describe_image |
(image BYTES[, prompt VARCHAR]) |
image → légende / description |
akko_ai_parse_document |
(pdf BYTES) |
PDF → JSON structuré |
akko_ai_transcribe |
(audio BYTES) |
audio → transcription |
Embeddings et calcul vectoriel¶
| Fonction | Signature | Rôle |
|---|---|---|
akko_ai_embed |
(texte VARCHAR) → ARRAY<DOUBLE> |
embedding 768 dim via nomic-embed-text |
akko_ai_similarity |
(a ARRAY<DOUBLE>, b ARRAY<DOUBLE>) → DOUBLE |
similarité cosinus, local pur — pas d'appel HTTP |
akko_ai_search |
(embedding ARRAY<DOUBLE>, requête VARCHAR) → DOUBLE |
embed la requête une fois par worker (LRU 1024, TTL 1h), puis cosinus local |
Admin et observabilité¶
| Fonction | Rôle |
|---|---|
akko_ai_stats() |
JSON avec état du circuit breaker, latences p50/p95/p99, taux de hit cache, compteurs par fonction |
akko_ai_health() |
UP / DOWN — joignabilité de l'AI Service |
akko_ai_version() |
version du plugin (ex. 2026.04) |
akko_ai_cache_clear() |
vide le cache de résultats (admin uniquement, vérifié via X-Trino-User) |
akko_ai_cb_reset() |
force la fermeture du circuit breaker (admin uniquement) |
Architecture¶
flowchart LR
SQL[SQL Trino<br/>SELECT akko_ai_sentiment...] --> COORD[Coordinateur Trino<br/>JVM]
COORD --> PLUGIN[Plugin<br/>trino-ai-functions]
PLUGIN --> HC[Cache LRU Caffeine<br/>10 000 entrées - TTL 1h]
HC -->|miss| HTTP[Client HTTP/2<br/>java.net.http]
HTTP --> AIS[akko-ai-service<br/>FastAPI + check OPA]
AIS --> LLM[Passerelle LiteLLM]
LLM --> OLL[Ollama<br/>qwen2.5 - nomic-embed-text]
LLM -.optionnel.-> CLOUD[OpenAI / Anthropic / Mistral]
PLUGIN --> JMX[MBean JMX<br/>HdrHistogram]
JMX --> PROM[Prometheus<br/>jmx_exporter]
AIS --> TEMPO[Spans Tempo<br/>trace d'audit]
Chaque invocation akko_ai_*() :
- Cherche le résultat dans un cache LRU Caffeine scopé par utilisateur
(
user:function:sha256(args)). - En cas de miss, ouvre une connexion HTTP/2 (pool de 16) vers l'AI
Service avec
X-Trino-User+X-Akko-Ai-Function: akko_ai_<nom>. - S'authentifie avec un bearer token chargé depuis le Secret K8s
akko-trino-ai. - L'AI Service vérifie le rôle et l'allow-list OPA pour la fonction, enregistre un span Tempo, puis route l'appel via LiteLLM.
- Renvoie la chaîne parsée — ou SQL
NULL(via@SqlNullable) en cas d'erreur. Trino n'est jamais déstabilisé.
Configuration¶
Tout se règle via les variables d'environnement du coordinateur Trino
(dans helm/akko/charts/akko-trino/values.yaml) :
trino:
env:
AKKO_AI_SERVICE_URL: http://akko-akko-ai-service:8000
AKKO_AI_SERVICE_TOKEN:
valueFrom:
secretKeyRef:
name: akko-trino-ai
key: token
AKKO_AI_TIMEOUT_MS: "30000"
AKKO_AI_CB_THRESHOLD: "5"
AKKO_AI_CB_RECOVERY_MS: "60000"
AKKO_AI_RETRY_MAX: "3"
AKKO_AI_POOL_SIZE: "16"
AKKO_AI_CACHE_SIZE: "10000"
AKKO_AI_CACHE_TTL_S: "3600"
AKKO_AI_VERIFY_TLS: "true"
Patterns d'usage¶
Enrichissement inline¶
SELECT id,
akko_ai_sentiment(comment) AS sentiment,
akko_ai_classify(comment, 'fraude,retention,support') AS sujet,
akko_ai_pii(comment) AS masque,
akko_ai_embed(comment) AS vecteur
FROM iceberg.banking.transactions
WHERE ts > current_date - INTERVAL '7' DAY;
Matérialiser les embeddings une fois pour toutes¶
CREATE TABLE iceberg.kb.documents_vec AS
SELECT id, text, akko_ai_embed(text) AS embedding
FROM iceberg.kb.documents;
Recherche sémantique (efficace)¶
akko_ai_search embed la requête une fois par worker (LRU Caffeine
1024) et calcule le cosinus localement :
SELECT id, text,
akko_ai_search(embedding, 'comment rembourser une transaction ?') AS score
FROM iceberg.kb.documents
ORDER BY score DESC
LIMIT 10;
Équivalent mais 10 à 1000 × plus lent (ré-embed la requête ligne par ligne) — à éviter en production :
SELECT id, text,
akko_ai_similarity(embedding, akko_ai_embed('comment rembourser une transaction ?')) AS score
FROM iceberg.kb.documents
ORDER BY score DESC
LIMIT 10;
Observabilité depuis SQL¶
SELECT akko_ai_stats();
-- JMX (nécessite le catalogue jmx de Trino)
SELECT *
FROM jmx.current."dev.akko.trino.ai:type=aihttpclient";
RBAC¶
Les 23 UDF akko_ai_* court-circuitent le check OPA natif
ExecuteFunction de Trino (Trino ne route pas les UDF de plugin à
travers le SPI d'access-control). Le RBAC est donc appliqué au niveau
de l'AI Service : le plugin transmet X-Trino-User +
X-Akko-Ai-Function: akko_ai_<nom> à chaque appel HTTP, et l'AI Service
résout le rôle AKKO de l'utilisateur via l'API admin Keycloak (cache 5
min) puis consulte la matrice par fonction.
Fail-closed : toute erreur de lookup, rôle manquant ou fonction hors de
l'allow-list du rôle renvoie HTTP 403. Le plugin remonte 403 / 401 /
429 en PERMISSION_DENIED Trino (via
io.trino.spi.security.AccessDeniedException), la requête échoue avec
la même classe d'erreur qu'un SELECT refusé par OPA — pas de NULL
silencieux. Les échecs d'infra (5xx, timeout) restent mappés en SQL
NULL pour qu'une panne LLM transitoire ne casse pas les dashboards.
Toute décision est tracée dans une ligne Loki structurée taguée
audit_type=AI_RBAC et dans les compteurs Prometheus
akko_ai_rbac_allowed_total / akko_ai_rbac_denied_total.
Source de vérité : helm/akko/charts/akko-ai-service/values.yaml —
synchronisé avec helm/akko/charts/akko-opa/templates/configmap.yaml.
Voir Admin / RBAC LLM pour la matrice
complète.
akko_ai_similarity(a, b) est du calcul local pur (pas d'HTTP), donc
tourne in-JVM pour tout rôle — filtrer la requête parente via RBAC de
catalogue.
Quotas quotidiens par utilisateur : admin=∞, engineer=1000,
analyst=500, steward=100, viewer=50. Au-delà : HTTP 429 → SQL NULL.
La famille upstream ai_* (catalogue Trino llm)¶
Depuis Trino 466, Trino embarque un catalogue de fonctions IA
natives nommé llm. En Trino 480, le schéma ai expose sept
fonctions :
| Fonction | Signature | Renvoie |
|---|---|---|
ai_gen |
(prompt VARCHAR) |
réponse libre |
ai_translate |
(texte VARCHAR, cible VARCHAR) |
texte traduit |
ai_classify |
(texte VARCHAR, catégories ARRAY<VARCHAR>) |
une catégorie |
ai_analyze_sentiment |
(texte VARCHAR) |
label de sentiment |
ai_extract |
(texte VARCHAR, schéma VARCHAR) |
extraction JSON |
ai_fix_grammar |
(texte VARCHAR) |
texte corrigé |
ai_mask |
(texte VARCHAR) |
texte avec PII masquées |
Ces fonctions vivent dans un catalogue connecteur, donc la forme canonique est entièrement qualifiée :
Chevauchement fonctionnel avec AKKO
Quatre noms se chevauchent : ai_translate / ai_classify /
ai_analyze_sentiment / ai_extract upstream correspondent à peu
près à akko_ai_translate / akko_ai_classify / akko_ai_sentiment
/ akko_ai_entities AKKO. AKKO utilise délibérément le préfixe
akko_ai_* pour lever toute ambiguïté — voir
ADR-026.
Activer le catalogue llm contre la passerelle LiteLLM souveraine AKKO¶
Le connecteur upstream laisse choisir parmi trois fournisseurs. AKKO
fournit un modèle llm.properties qui le pointe vers la passerelle
LiteLLM d'AKKO, pour que les fonctions upstream bénéficient du routage
de modèle souverain (même si elles restent en dehors du cache, de l'OPA
et de l'audit AKKO).
# etc/catalog/llm.properties — router l'IA upstream Trino via AKKO LiteLLM
connector.name=llm
llm.provider=openai
llm.openai.endpoint=http://akko-akko-litellm:4000
llm.openai.api-key=${ENV:AKKO_LITELLM_KEY}
llm.openai.model=qwen2.5:3b
À monter via Helm :
trino:
catalogs:
llm: |
connector.name=llm
llm.provider=openai
llm.openai.endpoint=http://akko-akko-litellm:4000
llm.openai.api-key=${ENV:AKKO_LITELLM_KEY}
llm.openai.model=qwen2.5:3b
env:
AKKO_LITELLM_KEY:
valueFrom:
secretKeyRef:
name: akko-litellm-api
key: key
Après un rollout Trino, les deux familles sont accessibles :
-- Famille AKKO (cache + OPA + audit)
SELECT akko_ai_translate('Hello', 'French');
-- Famille upstream Trino (standard, sans cache, sans OPA)
SELECT llm.ai.ai_translate('Hello', 'French');
Quand utiliser laquelle¶
| Situation | Utiliser |
|---|---|
| Requête de production sur données gouvernées, dashboards, jobs planifiés | akko_ai_* |
| Recherche sémantique, embeddings, multimodal | akko_ai_* (upstream ne les propose pas) |
| Charge réglementée avec audit OPA par utilisateur | akko_ai_* |
| Démo Trino standard ou comparaison upstream | llm.ai.ai_* |
| Notebook ad hoc sans besoin de cache/RBAC | les deux marchent ; akko_ai_* coûte moins sur requêtes multi-lignes grâce au cache |
Dépannage¶
| Symptôme | Cause probable | Résolution |
|---|---|---|
akko_ai_sentiment(...) → « Function not registered » |
image custom akko-trino non déployée |
Vérifier que le pod Trino tourne akko-trino:2026.04, pas trinodb/trino. kubectl describe pod -l app=trino |
Tous les akko_ai_* renvoient NULL |
circuit breaker OPEN après 5+ échecs | SELECT akko_ai_stats() ; attendre 60 s ou appeler akko_ai_cb_reset() |
| 401 / 403 dans les logs AI Service | bearer token désynchronisé | Resynchroniser le Secret akko-trino-ai ; helm upgrade pour redémarrer Trino |
| Première requête très lente | Ollama en train de pull le modèle | Attendre le job ollama-init ; kubectl logs -l app=akko-ollama |
Latence élevée sur akko_ai_search |
texte de requête jamais caché | Passer le texte en littéral constant (akko_ai_search(col, 'ma-requête')) |
jmx.current vide |
catalogue jmx désactivé |
Ajouter jmx.properties au ConfigMap catalogue Trino |
llm.ai.ai_translate absente |
catalogue llm non activé |
Ajouter llm.properties (voir modèle ci-dessus) |
Voir aussi¶
- Services / Plugin Trino AI — image, valeurs Helm, tests
- IA / ADEN — utilise plusieurs de ces fonctions en interne
- IA / Serveurs MCP — expose
akko_ai_*aux agents LLM - Architecture / Données unifiées + IA
- Admin / RBAC LLM
- ADR-026 — préfixe
akko_ai_*