Przejdź do głównej zawartości

Agent Spaces

Agent Spaces to nazwane persony autorstwa administratora, które ograniczają ask AI. Tam gdzie Agent Skills kodyfikują pojedyncze przepływy, przestrzeń kodyfikuje punkt widzenia: system prompt, listę dozwolonych kostek, listę dozwolonych skilli, sugerowane prompty — wymuszane po stronie serwera, więc bez względu na to, co wysyła wywołujący, LLM widzi głos persony + kostki persony + skille persony.

Utrwalane jako JSON pod saiku-home/agent-spaces/. Launcher skanuje leniwie po sygnaturze mtime (ten sam model co skille — brak wątku obserwatora).

Dostarczone w saiku v4.7 jako saiku#1440.

Co wymusza przestrzeń

Format pliku

saiku-home/agent-spaces/foodmart-sales-analyst.json
{
"id": "foodmart-sales-analyst",
"name": "FoodMart Sales Analyst",
"description": "Weekly and monthly sales rollups over the FoodMart Sales cube.",
"systemPrompt": "You are the FoodMart Sales Analyst. Prefer weekly and monthly time grain unless the user asks otherwise. Lead with the top three lines by absolute value. Flag any figure that swings by more than 20% versus the prior period. Be analytical, brief, and numbers-first.",
"cubeAllowlist": [
{"connectionName": "unknown_foodmart", "catalog": "FoodMart", "schema": "FoodMart", "cubeName": "Sales"}
],
"skillAllowlist": ["weekly-foodmart-rollup"],
"suggestedPrompts": [
"How did Store Sales track last week vs the prior week?",
"Break down Store Sales by Product Family for Q4.",
"/weekly-foodmart-rollup"
]
}
PoleWymaganeTypUwagi
idtakstringkebab-case, [a-z][a-z0-9-]{0,63}. Segment ścieżki w /ai/spaces/{id}/ask.
nametakstringNazwa wyświetlana dla katalogu i paska bocznego.
descriptionniestringJednolinijkowe podsumowanie pokazywane w wyborze przestrzeni.
systemPromptniestringDoklejany przed wbudowanym SYSTEM_PROMPT przy każdym ask.
cubeAllowlisttakAiCubeRef[]Co najmniej jeden wpis. Referencje spoza tej listy zwracają 403 FORBIDDEN.
skillAllowlistniestring[]Filtruje kierowanie slash + katalog LLM. Pusta = wszystkie skille dozwolone.
suggestedPromptsniestring[]Dowolne pytania szybkiego startu, które UI może wyrenderować.

Nieznane klucze najwyższego poziomu są odrzucane, więc literówka (sytemPrompt) ujawnia się jako UNKNOWN_FIELD, a nie jest cicho odrzucana.

Wymuszanie kostki

  1. Wywołujący wysyła POST do /ai/spaces/{id}/ask z opcjonalnym polem cube:

    Okno terminala
    curl -sS -X POST -H 'Content-Type: application/json' \
    -u admin:admin \
    http://localhost:8080/saiku/api/ai/spaces/foodmart-sales-analyst/ask \
    -d '{"question": "How did Store Sales track last week?"}'
  2. Jeśli cube jest pominięte, używany jest pierwszy dozwolony wpis przestrzeni.

  3. Jeśli cube jest podane, musi pasować do wpisu listy dozwolonych przestrzeni na wszystkich czterech współrzędnych (connectionName, catalog, schema, cubeName), inaczej wywołanie zwraca:

    HTTP 403 Forbidden
    {
    "degraded": true,
    "reason": "FORBIDDEN: cube OtherCube is not in space 'foodmart-sales-analyst' allowlist"
    }

To jest zamierzone: UI, które podaje serwerowi nieaktualną referencję kostki, powinno zostać skorygowane, a nie cicho zreinterpretowane na domyślną.

Wstrzyknięcie system promptu

systemPrompt przestrzeni jest doklejany przed wbudowanym SYSTEM_PROMPT po stronie dostawcy. Pełna złożona wiadomość systemowa, którą widzi LLM:

You are a Mondrian OLAP analyst assistant scoped to a single cube. …
[…the built-in tool-choice rails…]
Agent space persona:
You are the FoodMart Sales Analyst. Prefer weekly and monthly time
grain unless the user asks otherwise. Lead with the top three lines by
absolute value. Flag any figure that swings by more than 20% versus the
prior period. Be analytical, brief, and numbers-first.
Cube schema:
{ … the AiSchema JSON … }
Cube ref to echo: { … }

Pola history i question użytkownika jadą poniżej tego wszystkiego jako zwykłe wiadomości — nic, co mogą wstrzyknąć, nie przepisuje persony.

Filtr skilli

Katalog skilli jest filtrowany do skillAllowlist przestrzeni, zanim dotrze do LLM:

  • skillAllowlist jest pusta → wszystkie skille przepływają.
  • skillAllowlist nazywa konkretne skille → tylko te pojawiają się w system prompcie LLM ORAZ tylko te rozwijają się przez slash.

Ask w rodzaju /some-other-skill for Q4 w przestrzeni, która nie ma some-other-skill na liście dozwolonych, spada jako surowy ask — LLM widzi wiadomość dosłownie, bez rozwinięcia. Decyzja o kierowaniu jest jednostronna (deny listy dozwolonych), nigdy częściowa.

Sugerowane prompty

Każda przestrzeń niesie listę suggestedPrompts — 3-6 autorskich pytań szybkiego startu, które UI ujawnia jako chipy:

"suggestedPrompts": [
"How did Store Sales track last week vs the prior week?",
"Break down Store Sales by Product Family for Q4.",
"Which Product Department is up the most month-over-month?",
"/weekly-foodmart-rollup"
]

Wpisy poleceń slash są legalne i zachęcane — sugerowany prompt zaczynający się od / wywołuje nazwany skill bezpośrednio.

Powierzchnia REST

GET /rest/saiku/api/ai/spaces

Katalog podsumowań {id, name, description, suggestedPrompts}.

Okno terminala
curl -sS -u admin:admin \
http://localhost:8080/saiku/api/ai/spaces | jq
{
"spaces": [
{
"id": "foodmart-sales-analyst",
"name": "FoodMart Sales Analyst",
"description": "Weekly and monthly sales rollups over the FoodMart Sales cube.",
"suggestedPrompts": ["How did Store Sales track last week?", ""]
}
]
}

GET /rest/saiku/api/ai/spaces?errors=true

To samo, plus tablica errors[]. Stabilne kody błędów:

KodKiedy
EMPTY_SPACEPlik jest pusty lub całkowicie białe znaki.
MALFORMED_JSONParser JSON odrzucił ciało.
MISSING_FIELDWymagane pole (id, name) nieobecne.
BLANK_FIELDWymagane pole obecne, ale puste / same białe znaki.
TYPE_MISMATCHPole obecne, ale zły typ.
INVALID_IDid nie pasuje do [a-z][a-z0-9-]{0,63}.
EMPTY_ALLOWLISTcubeAllowlist obecne, ale puste — przestrzeń byłaby bezużyteczna.
INVALID_CUBE_REFWpis listy dozwolonych bez współrzędnej (connectionName itp.).
UNKNOWN_FIELDFrontmatter zawiera pole spoza schemy.
DUPLICATE_IDDwa pliki zadeklarowały to samo id.
IO_ERRORNie udało się odczytać pliku (poziom systemu plików).

GET /rest/saiku/api/ai/spaces/{id}

Pełny rekord — zawiera systemPrompt i cubeAllowlist, które podsumowanie pomija. Używany przez UI admina przy edycji persony.

POST /rest/saiku/api/ai/spaces/{id}/ask

Ask ograniczony do przestrzeni. Kształt ciała odzwierciedla /ai/ask, ale pole cube jest opcjonalne:

Okno terminala
curl -sS -X POST -H 'Content-Type: application/json' \
-u admin:admin \
http://localhost:8080/saiku/api/ai/spaces/foodmart-sales-analyst/ask \
-d '{"question": "Break down Store Sales by Product Family for Q4"}'

Koperta odpowiedzi to standardowa AiAskApi.AskResponsemodel, request (AiQueryRequest, który model wyemitował) oraz degraded/reason przy błędzie.

POST /rest/saiku/api/ai/spaces/{id}/ask/stream

Wariant strumieniowy ask-a ograniczonego do przestrzeni. Emituje tę samą schemę Server-Sent Events co /ai/ask/stream (modelintentchunkfinal) z zastosowanym zakresem persony — klient widzi identyczne zdarzenia na drucie, czy uderza /ai/ask/stream, czy to lustro ograniczone do przestrzeni. Wyniki przestrzeni-nie-znaleziono i kostki-spoza-listy-dozwolonych ujawniają się jako zdarzenie error, po którym następuje zdegradowany final, więc czytnik obsługuje błędy zakresu i błędy dostawcy tak samo.

Okno terminala
curl -sS -N -X POST -H 'Content-Type: application/json' \
-u admin:admin \
http://localhost:8080/saiku/api/ai/spaces/foodmart-sales-analyst/ask/stream \
-d '{"question": "Break down Store Sales by Product Family for Q4"}'

POST /rest/saiku/api/ai/spaces/refresh

Wymuś ponowny skan (omija sprawdzenie sygnatury mtime).

Autorowanie przestrzeni w panelu admina

Przestrzenie nie muszą już być ręcznie pisanym JSON-em. Admin → Agent spaces to pełny edytor: napisz system prompt, odhacz kostki na liście dozwolonych (wspartej odkrywaniem kostek na żywo, więc możesz dopuścić tylko istniejące kostki), wylistuj skille i sugerowane prompty, i zapisz. Usunięcie przestrzeni usuwa jej plik JSON.

Edytor jest wsparty przez powierzchnię CRUD bramkowaną adminem. Te endpointy wymagają ROLE_ADMIN i zwracają pełną personę (system prompt + lista dozwolonych kostek włączone, w przeciwieństwie do zredagowanego publicznego katalogu powyżej):

Metoda + ścieżkaCel
GET /rest/saiku/admin/agent-spacesWylistuj każdą personę w całości, do edycji.
GET /rest/saiku/admin/agent-spaces/errorsBłędy parsowania dla wadliwych plików.
PUT /rest/saiku/admin/agent-spaces/{id}Utwórz lub zamień personę. id jest walidowane (kebab-case, zabezpieczone przed path-traversal) przed zapisaniem pliku JSON.
DELETE /rest/saiku/admin/agent-spaces/{id}Usuń personę i jej plik.

Osadzanie przestrzeni

<saiku-embed kind="ai" space="foodmart-sales-analyst"> wrzuca asystenta ograniczonego do persony na dowolną stronę. Lista dozwolonych kostek i system prompt są wymuszane po stronie serwera dokładnie tak jak dla ask-a REST, więc osadzony asystent nie może być zsterowany poza swoją personę. Zobacz przewodnik po embedowaniu.

Dołączone przykłady

Świeże instalacje Saiku umieszczają dwie działające persony:

  • FoodMart Sales Analyst — analityczny, zwięzły, liczby-najpierw. weekly-foodmart-rollup na jego liście dozwolonych skilli, więc /weekly-foodmart-rollup jest dostępny jako polecenie slash.
  • FoodMart Finance Ops — ostrożny, precyzyjny, skupiony na marży. Pusta skillAllowlist = wszystkie skille dozwolone.

Obie ograniczają się do kostki FoodMart Sales — świeże demo ma persony gotowe do kliknięcia bez żadnego autorowania przez operatora.

Nie-cele dla v1

  • Zakres per-użytkownik lub per-rola. Przestrzenie są per-launcher w v1; wielodostępne workspace’y mogą nakładać zakres, mapując katalogi workspace na korzenie rejestru per-workspace — odroczone.
  • Nadpisanie zakresu danych per-przestrzeń. Osadzone zapytania już wymuszają wymuszone filtry na poziomie wierszy (stosuj-albo-zawiedź-zamknięcie — zobacz przewodnik po embedowaniu), ale przypinanie filtrów RLS konkretnie do ask-ów ograniczonych do przestrzeni jest wciąż śledzone razem z pracą nad Ossie RLS w saiku#1393.

Dokąd dalej