Agent Skills
Agent Skills sind Markdown-Dateien mit YAML-Frontmatter, die in
saiku-home/skills/ leben. Der Launcher scannt sie bei jeder Anfrage
lazy und injiziert den Katalog in den LLM-System-Prompt, sodass jeder
AI-Ask-Turn — MDX oder Ossie — zu
einem von Admins verfassten Workflow routen kann, statt frei zu
improvisieren.
Kleines Feature, überproportionaler Wert: Es lässt Operatoren die kanonischen Fragen ihres Teams kodifizieren („der Exec-Rollup dieses Quartals”, „die Churn-Kohorte”, „der Store-Comp-Report”), ohne noch ein weiteres Tool besitzen zu müssen. Der Skill lebt im Repo, versioniert mit dem Semantikmodell und wird wie alles andere Code-reviewt.
Ausgeliefert in saiku v4.7 als saiku#1426.
Zwei Aufrufpfade
Dateiformat
---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
| Feld | Erforderlich | Typ | Anmerkungen |
|---|---|---|---|
name | ja | string | kebab-case, [a-z][a-z0-9-]{0,63}. Als Slash-Slug verwendet. |
description | ja | string | Eine Zeile oder Block-Skalar. Gezeigt in /ai/skills und im LLM-Prompt. |
cube | nein | string | connection/catalog/schema/cubeName-Ref. Beschränkt den Skill. |
Unbekannte Top-Level-Schlüssel werden abgelehnt. Ein Tippfehler
(descripton) taucht als strukturierter UNKNOWN_FIELD-Fehler auf —
nie als stiller namenloser Skill.
Body
Alles nach dem schließenden ----Zaun ist der Body. Markdown wird
empfohlen, aber nicht gefordert; der Body wird als undurchsichtiger Text
behandelt und bei einem Slash-Command-Treffer wörtlich in den LLM-Prompt
eingefügt. Halten Sie ihn knapp — das LLM muss die ganze Datei lesen.
Slash-Command
-
Der Nutzer (oder das DimSum-Widget in Ihrem Namen) postet eine Anfrage, die mit
/beginnt:Terminal-Fenster 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 -
Der Service parst den Slash und schlägt
weekly-foodmart-rollupim Katalog nach. -
Treffer → die an das LLM gesendete Anfrage lautet:
Skill: weekly-foodmart-rollup## Steps1. Query total [Measures].[Store Sales] ……User follow-up: for Q4 instead of this week -
Das LLM führt die Schritte aus, wendet die Folge („Q4 instead of this week”) auf den Zeitfilter an und gibt wie gewohnt einen
AiQueryRequestaus. -
Fehltreffer → die Anfrage reist unverändert. Das LLM sieht sie als gewöhnlichen Prompt mit einem führenden Slash. Nichts bricht.
Natürliche Sprache
Der Katalog landet im LLM-System-Prompt als:
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…Das Modell routet von selbst. Wenn der Nutzer „how did stores compare
to last year?” fragt, wählt der Natürlichsprach-Matcher
/store-comp-report; der Nutzer sieht die Routing-Entscheidung nie.
REST-Oberfläche
Alle drei Endpunkte sitzen unter dem Standard-AI-Ask-Basispfad.
GET /rest/saiku/api/ai/skills
Der Katalog — kompakte {name, description, cube}-Zusammenfassungen.
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
Gleiche Form, plus ein errors[]-Array, das jede Datei auflistet, die
bei diesem Scan nicht geparst werden konnte. Jeder Eintrag trägt einen
stabilen Maschinencode, sodass Operatoren kaputtes Frontmatter
korrigieren, ohne Server-Logs zu lesen.
{ "skills": [ /* … */ ], "errors": [ { "path": "broken.md", "code": "MISSING_FRONTMATTER", "message": "expected leading `---` YAML frontmatter block" } ]}Stabile Fehlercodes:
| Code | Wann |
|---|---|
EMPTY_SKILL | Datei ist leer oder nur Leerraum. |
MISSING_FRONTMATTER | Kein führender ----Zaun. |
EMPTY_BODY | Frontmatter geparst, aber kein Markdown nach dem schließenden Zaun. |
MALFORMED_YAML | YAML-Parser hat das Frontmatter abgelehnt. |
MISSING_FIELD | Erforderliches Feld (name / description) nicht vorhanden. |
BLANK_FIELD | Erforderliches Feld vorhanden, aber leer / nur Leerraum. |
TYPE_MISMATCH | Feld vorhanden, aber falscher Typ (name: 42). |
INVALID_NAME | name passt nicht zu [a-z][a-z0-9-]{0,63}. |
UNKNOWN_FIELD | Frontmatter enthält ein Feld, das nicht im Schema ist. |
DUPLICATE_NAME | Zwei Skill-Dateien deklarierten denselben name. |
IO_ERROR | Datei konnte nicht gelesen werden (Dateisystem-Ebene). |
GET /rest/saiku/api/ai/skills/{name}
Vollständiger Body eines Skills — das rohe Markdown. Praktisch für ein UI-Slash-Menü, das den Workflow vorschaut, bevor der Nutzer auf Senden drückt.
POST /rest/saiku/api/ai/skills/refresh
Erzwingt einen erneuten Scan (umgeht die mtime-Signaturprüfung). Gibt die frischen Zahlen zurück, damit Operatoren das Neuladen mit einem Blick prüfen können.
curl -sS -u admin:admin -X POST \ http://localhost:8080/saiku/api/ai/skills/refresh{ "skills": 4, "errors": 0 }Mitgeliefertes Beispiel
Frische Saiku-Installationen platzieren beim ersten Boot ein funktionierendes Beispiel — siehe weekly-foodmart-rollup.md. Operatoren fügen ihre eigenen daneben hinzu; das geseedete ist idempotent (landet nur, wenn die Zieldatei noch nicht existiert).
Wie der Scan funktioniert
- Unterverzeichnisse werden rekursiv durchlaufen.
- Nicht-
.md-Dateien werden ignoriert (eine verirrteREADME.txtbringt den Scan nicht zum Absturz). - Kaputte Dateien reißen den Katalog nicht runter — eine
ParseExceptionauf einer Datei lässt die anderen intakt. - Duplikate auf
nameerzeugen einenDUPLICATE_NAME-Fehler auf der zweiten zu ladenden Datei; die erste gewinnt.
Ossie-Anfragen nehmen diese auch auf
Der Skill-Katalog ist ein einzelner Store pro Launcher, bereitgestellt
unter /rest/saiku/api/ai/skills. Jeder Skill, dessen cube:-Feld eine
Ossie-Ref benennt (z. B. pharma/Pharma/Pharma/Sales), wird
natürlicherweise durch diese Ref beschränkt, wenn er über
/ai/ossie/ask geroutet wird.
MDX und Ossie teilen sich dasselbe Primitiv.