Compétences d'agent
Les compétences d’agent (Agent Skills) sont des fichiers markdown avec
frontmatter YAML qui vivent dans saiku-home/skills/. Le launcher les
scanne paresseusement à chaque requête et injecte le catalogue dans le
system prompt du LLM, pour que n’importe quel tour d’AI Ask
— MDX ou Ossie — puisse être routé vers un workflow
créé par l’admin plutôt que d’improviser.
Petite fonctionnalité, valeur disproportionnée : elle permet aux opérateurs de codifier les questions canoniques de leur équipe (« le rollup exec de ce trimestre », « la cohorte de churn », « le rapport de comparaison de magasins ») sans posséder encore un autre outil. La compétence vit dans le dépôt, est versionnée avec le modèle sémantique et passe en revue de code comme tout le reste.
Livré dans saiku v4.7 comme saiku#1426.
Deux chemins d’invocation
Format de fichier
---name: weekly-foodmart-rollupdescription: | Weekly revenue rollup for the FoodMart Sales cube: total Store Sales by Product Family for the last 7 days, compared to the prior 7 days. Flags any family with a >20% swing.cube: unknown_foodmart/FoodMart/FoodMart/Sales---
## Steps
1. Query total `[Measures].[Store Sales]` and `[Measures].[Unit Sales]` broken down by `[Product].[Product Family]` for the last 7 days (`[Time].[Weekly].[Week].&[latest]`).
2. Query the same shape for the prior 7 days (`[Time].[Weekly].[Week].&[latest - 1]`).
3. Present the result as a two-column table with a `Δ vs prior` percentage column derived per family.
4. Highlight any Product Family whose `Δ vs prior` swings by more than 20% in either direction.Frontmatter
| Champ | Requis | Type | Notes |
|---|---|---|---|
name | oui | string | kebab-case, [a-z][a-z0-9-]{0,63}. Utilisé comme slug de slash. |
description | oui | string | Une ligne ou un scalaire de bloc. Affiché dans /ai/skills et le prompt du LLM. |
cube | non | string | Référence connection/catalog/schema/cubeName. Délimite la compétence. |
Les clés de premier niveau inconnues sont rejetées. Une faute de frappe
(descripton) fait surface sous forme d’erreur structurée UNKNOWN_FIELD —
jamais comme une compétence silencieuse et sans nom.
Corps
Tout ce qui suit la clôture --- est le corps. Le markdown est recommandé
mais pas requis ; le corps est traité comme du texte opaque et collé
verbatim dans le prompt du LLM lors d’une correspondance de slash-command.
Gardez-le concis — le LLM doit lire le fichier entier.
Slash command
-
L’utilisateur (ou le widget DimSum en votre nom) poste une question commençant par
/:Fenêtre de terminal curl -sS -X POST -H 'Content-Type: application/json' \-u admin:admin \http://localhost:8080/saiku/api/ai/ask \-d @- <<'EOF'{"question": "/weekly-foodmart-rollup for Q4 instead of this week","cube": {"connectionName":"unknown_foodmart","catalog":"FoodMart","schema":"FoodMart","cubeName":"Sales"}}EOF -
Le service parse le slash et cherche
weekly-foodmart-rollupdans le catalogue. -
Correspondance → la question envoyée au LLM est :
Skill: weekly-foodmart-rollup## Steps1. Query total [Measures].[Store Sales] ……User follow-up: for Q4 instead of this week -
Le LLM exécute les étapes, applique le suivi (« Q4 instead of this week ») au filtre temporel et émet une
AiQueryRequestcomme d’habitude. -
Absence de correspondance → la question voyage inchangée. Le LLM la voit comme un prompt ordinaire avec un slash en tête. Rien ne casse.
Langage naturel
Le catalogue atterrit dans le system prompt du LLM sous la forme :
Available skills (admin-authored workflows). When the user's questionclosely matches one of these — or when the message starts with`/<skill-name>` — use the skill's steps to structure your responseinstead of freewheeling:- /weekly-foodmart-rollup: Weekly revenue rollup for the FoodMart Sales cube…- /store-comp-report: Store-level comp vs same period last year…- /churn-cohort: 30/60/90 day churn cohort split by acquisition channel…Le modèle route de lui-même. Si l’utilisateur demande « how did stores
compare to last year? », le matcher en langage naturel choisit
/store-comp-report ; l’utilisateur ne voit jamais la décision de routage.
Surface REST
Les trois endpoints se trouvent sous le chemin de base standard d’AI Ask.
GET /rest/saiku/api/ai/skills
Le catalogue — des résumés compacts {name, description, cube}.
curl -sS -u admin:admin \ http://localhost:8080/saiku/api/ai/skills | jq{ "skills": [ { "name": "weekly-foodmart-rollup", "description": "Weekly revenue rollup for the FoodMart Sales cube: total Store Sales …", "cube": "unknown_foodmart/FoodMart/FoodMart/Sales" } ]}GET /rest/saiku/api/ai/skills?errors=true
Même forme, plus un tableau errors[] listant chaque fichier qui a échoué
à parser lors de ce scan. Chaque entrée porte un code machine stable pour
que les opérateurs corrigent un mauvais frontmatter sans lire les logs du
serveur.
{ "skills": [ /* … */ ], "errors": [ { "path": "broken.md", "code": "MISSING_FRONTMATTER", "message": "expected leading `---` YAML frontmatter block" } ]}Codes d’erreur stables :
| Code | Quand |
|---|---|
EMPTY_SKILL | Le fichier est vide ou entièrement composé d’espaces. |
MISSING_FRONTMATTER | Pas de clôture --- en tête. |
EMPTY_BODY | Le frontmatter a été parsé mais pas de markdown après la clôture. |
MALFORMED_YAML | Le parseur YAML a rejeté le frontmatter. |
MISSING_FIELD | Champ requis (name / description) non présent. |
BLANK_FIELD | Champ requis présent mais vide / composé uniquement d’espaces. |
TYPE_MISMATCH | Champ présent mais du mauvais type (name: 42). |
INVALID_NAME | name ne correspond pas à [a-z][a-z0-9-]{0,63}. |
UNKNOWN_FIELD | Le frontmatter contient un champ absent du schéma. |
DUPLICATE_NAME | Deux fichiers de compétence ont déclaré le même name. |
IO_ERROR | Impossible de lire le fichier (niveau système de fichiers). |
GET /rest/saiku/api/ai/skills/{name}
Corps complet d’une compétence — le markdown brut. Pratique pour un menu slash d’UI qui prévisualise le workflow avant que l’utilisateur n’appuie sur envoyer.
POST /rest/saiku/api/ai/skills/refresh
Force un rescan (contourne la vérification de signature mtime). Retourne les compteurs frais pour que les opérateurs puissent contrôler le rechargement.
curl -sS -u admin:admin -X POST \ http://localhost:8080/saiku/api/ai/skills/refresh{ "skills": 4, "errors": 0 }Exemple fourni
Les installations fraîches de Saiku déposent un exemple fonctionnel au premier boot — voir weekly-foodmart-rollup.md. Les opérateurs ajoutent les leurs à côté ; celui qui est semé est idempotent (il n’atterrit que quand le fichier cible n’existe pas déjà).
Comment fonctionne le scan
- Les sous-répertoires sont parcourus récursivement.
- Les fichiers non
.mdsont ignorés (unREADME.txtégaré ne fera pas planter le scan). - Les fichiers cassés ne mettent pas à terre le catalogue — une
ParseExceptionsur un fichier laisse les autres intacts. - Les doublons sur
nameproduisent une erreurDUPLICATE_NAMEsur le second fichier chargé ; le premier l’emporte.
Les questions Ossie les récupèrent aussi
Le catalogue de compétences est un unique store par launcher servi à
/rest/saiku/api/ai/skills. Toute compétence dont le champ cube: nomme
une référence Ossie (par ex. pharma/Pharma/Pharma/Sales) est naturellement
délimitée par cette référence lorsqu’elle est routée à travers
/ai/ossie/ask. MDX et Ossie
partagent la même primitive.