API
REST-API Endpunkte für KI-Integration, Content-Management und Dokumentation.
API-Referenz
Chat API
RAG-Chat mit Vektorsuche und LLM-Integration
Docs API
Dokumentations-CRUD, Suche und RAG-Chat
Tasks API
Task-Management, Zuweisungen, KI-Ausführung
Content API
Content-Aufträge erstellen und bearbeiten
Explorer API
Dokumente, Chunks, Taxonomie, Hybrid-Suche
Config API
System-Prompts und RAG-Konfiguration
Services
OllamaService, QdrantService, ClaudeService
Architektur
Alle APIs sind vollständig in PHP implementiert:
Browser (HTMX/JS)
↓
PHP Controller (/src/Controller/Api/)
├── ChatController.php (RAG-Chat)
├── DocsController.php (Dokumentation)
├── TaskController.php (Task-Management)
├── ContentController.php (Content-Aufträge)
├── ExplorerController.php (Doc2Vector Explorer)
└── ConfigController.php (Konfiguration)
↓
PHP Services (/src/Infrastructure/AI/)
├── AIConfig.php (Config & Factory)
├── ChatService.php (RAG-Orchestrator)
├── OllamaService.php (Embeddings & LLM)
├── QdrantService.php (Vektorsuche)
└── ClaudeService.php (Anthropic LLM)
↓
┌─────────────┬─────────────┬─────────────┐
│ Ollama API │ Qdrant API │ Claude API │
│ :11434 │ :6333 │ anthropic │
└─────────────┴─────────────┴─────────────┘
Endpunkte-Übersicht
Chat API
| Methode | Pfad | Beschreibung |
|---|---|---|
| POST | /api/v1/chat | Chat-Nachricht senden |
| GET | /api/v1/chat/search | Vektorsuche |
| GET | /api/v1/chat/stats | Statistiken |
Docs API
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | /api/v1/docs | Dokumente auflisten |
| GET | /api/v1/docs/{id} | Dokument nach ID |
| GET | /api/v1/docs/path/{path} | Dokument nach Pfad |
| GET | /api/v1/docs/search | Semantische Suche |
| GET | /api/v1/docs/hierarchy | Dokumentationsbaum |
| POST | /api/v1/docs | Dokument erstellen |
| PUT | /api/v1/docs/{id} | Dokument aktualisieren |
| DELETE | /api/v1/docs/{id} | Dokument löschen |
| POST | /api/v1/docs/chat | RAG-Chat |
Tasks API
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | /api/v1/tasks | Tasks auflisten |
| GET | /api/v1/tasks/statistics | Statistiken |
| GET | /api/v1/tasks/{id} | Task-Details |
| POST | /api/v1/tasks | Task erstellen |
| PUT | /api/v1/tasks/{id} | Task aktualisieren |
| DELETE | /api/v1/tasks/{id} | Task löschen |
| POST | /api/v1/tasks/{id}/assign | Task zuweisen |
| PUT | /api/v1/tasks/{id}/status | Status ändern |
| GET | /api/v1/tasks/{id}/results | Ergebnisse abrufen |
| POST | /api/v1/tasks/{id}/results | Ergebnis speichern |
| POST | /api/v1/tasks/{id}/execute | KI-Ausführung |
Content API
| Methode | Pfad | Beschreibung |
|---|---|---|
| PUT | /api/v1/content/{id} | Auftrag aktualisieren |
Explorer API
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | /api/v1/explorer/stats | Statistiken |
| GET | /api/v1/explorer/dokumente | Dokumente-Liste |
| GET | /api/v1/explorer/dokumente/{id} | Dokument-Details |
| GET | /api/v1/explorer/seiten | Seiten-Liste |
| GET | /api/v1/explorer/seiten/{id} | Seite-Details |
| GET | /api/v1/explorer/chunks | Chunks-Liste |
| GET | /api/v1/explorer/chunks/{id} | Chunk-Details |
| GET | /api/v1/explorer/taxonomie | Taxonomie |
| GET | /api/v1/explorer/entities | Entities |
| POST | /api/v1/explorer/suche | Hybrid-Suche |
Config API
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | /api/v1/config/{id} | Config abrufen |
| POST | /api/v1/config/{id} | Config aktualisieren |
Response-Format
Alle APIs verwenden ein einheitliches JSON-Response-Format:
Erfolg
{
"success": true,
"data": { ... },
"meta": {
"total": 100,
"limit": 50,
"offset": 0
}
}
Fehler
{
"success": false,
"error": "Fehlermeldung"
}
Authentifizierung
Schreibende Operationen (POST, PUT, DELETE) erfordern einen CSRF-Token:
X-CSRF-TOKEN: {token}
Services
| Service | Pfad | Funktion |
|---|---|---|
| AIConfig | /src/Infrastructure/AI/AIConfig.php | Config & Factory |
| ChatService | /src/Infrastructure/AI/ChatService.php | RAG-Orchestrator |
| OllamaService | /src/Infrastructure/AI/OllamaService.php | Embeddings & LLM |
| QdrantService | /src/Infrastructure/AI/QdrantService.php | Vektorsuche |
| ClaudeService | /src/Infrastructure/AI/ClaudeService.php | LLM-Antworten |
Docs API
REST-API für Dokumentations-Management mit CRUD-Operationen, semantischer Suche und RAG-Chat.
| Controller | Controller\Api\DocsController |
|---|---|
| Base-URL | /api/v1/docs |
| Datenbank | ki_dev.dokumentation |
| Format | JSON |
Endpoints-Übersicht
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | /api/v1/docs | Liste aller Dokumente |
| GET | /api/v1/docs/{id} | Dokument nach ID |
| GET | /api/v1/docs/path/{path} | Dokument nach Pfad |
| GET | /api/v1/docs/search | Semantische Suche |
| GET | /api/v1/docs/hierarchy | Dokumentationsbaum |
| POST | /api/v1/docs | Dokument erstellen |
| PUT | /api/v1/docs/{id} | Dokument aktualisieren |
| DELETE | /api/v1/docs/{id} | Dokument löschen |
| POST | /api/v1/docs/chat | RAG-Chat mit Dokumentation |
Dokumente auflisten
GET /api/v1/docs?status=published&parent_id=51&search=apache&limit=50&offset=0
| Parameter | Typ | Default | Beschreibung |
|---|---|---|---|
| status | string | - | published, draft |
| parent_id | int | - | Filter nach Parent-Dokument |
| search | string | - | Volltextsuche in Titel/Content |
| limit | int | 50 | Max. Ergebnisse (max 100) |
| offset | int | 0 | Pagination-Offset |
Response
{
"success": true,
"data": [
{
"id": 1,
"parent_id": null,
"slug": "server",
"path": "/server",
"title": "Server",
"description": "Server-Dokumentation",
"status": "published",
"depth": 0,
"created_at": "2025-12-20T10:00:00",
"updated_at": "2025-12-27T12:00:00"
}
],
"meta": {
"total": 100,
"limit": 50,
"offset": 0
}
}
Dokument nach ID
GET /api/v1/docs/{id}?include_children=1&include_breadcrumb=1
| Parameter | Typ | Beschreibung |
|---|---|---|
| include_children | 0|1 | Kind-Dokumente einschließen |
| include_breadcrumb | 0|1 | Breadcrumb-Pfad einschließen |
Response
{
"success": true,
"data": {
"id": 51,
"title": "API",
"path": "/api",
"content": "...",
...
},
"children": [...],
"breadcrumb": [
{"id": 51, "title": "API", "path": "/api"}
]
}
Dokument nach Pfad
GET /api/v1/docs/path/api/chat
Liefert Dokument mit Pfad /api/chat.
Semantische Suche
GET /api/v1/docs/search?q=Apache+SSL&limit=5&category=Betrieb
| Parameter | Typ | Default | Beschreibung |
|---|---|---|---|
| q | string | required | Suchanfrage |
| limit | int | 5 | Max. Ergebnisse |
| category | string | - | Taxonomie-Kategorie-Filter |
Response
{
"success": true,
"data": [
{
"chunk_id": 42,
"content": "Apache SSL Konfiguration...",
"score": 0.92,
"dokument_title": "Apache",
"path": "/server/apache"
}
],
"meta": {
"query": "Apache SSL",
"limit": 5,
"count": 3
}
}
Dokumentationsbaum
GET /api/v1/docs/hierarchy
Liefert vollständigen Dokumentationsbaum als verschachtelte Struktur.
Response
{
"success": true,
"data": [
{
"id": 1,
"title": "Server",
"path": "/server",
"children": [
{"id": 2, "title": "SSH", "path": "/server/ssh", "children": []},
{"id": 3, "title": "UFW", "path": "/server/ufw", "children": []}
]
}
]
}
Dokument erstellen
POST /api/v1/docs
Content-Type: application/json
{
"title": "Neues Dokument",
"slug": "neues-dokument",
"content": "Inhalt
Text...
",
"description": "Beschreibung",
"parent_id": 51,
"status": "draft",
"sort_order": 10
}
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| title | string | Ja | Dokumenttitel |
| slug | string | Ja | URL-Slug (eindeutig pro Parent) |
| content | string | Nein | HTML-Inhalt |
| description | string | Nein | Kurzbeschreibung |
| parent_id | int | Nein | Parent-Dokument-ID |
| status | string | Nein | draft (default) oder published |
| sort_order | int | Nein | Sortierreihenfolge |
Response (201 Created)
{
"success": true,
"data": {...},
"message": "Dokument erstellt"
}
Dokument aktualisieren
PUT /api/v1/docs/{id}
Content-Type: application/json
{
"title": "Aktualisierter Titel",
"content": "Neuer Inhalt
",
"description": "Neue Beschreibung",
"status": "published"
}
Alle Felder sind optional - nur übergebene Felder werden aktualisiert.
Dokument löschen
DELETE /api/v1/docs/{id}
Wichtig: Dokumente mit Unterdokumenten können nicht gelöscht werden. Lösche zuerst alle Kind-Dokumente.
Fehler-Response
{
"success": false,
"error": "Dokument hat Unterdokumente. Lösche diese zuerst."
}
RAG-Chat
POST /api/v1/docs/chat
Content-Type: application/json
{
"question": "Wie konfiguriere ich Apache SSL?",
"model": "mistral",
"limit": 5
}
| Parameter | Typ | Default | Beschreibung |
|---|---|---|---|
| question | string | required | Benutzer-Frage |
| model | string | mistral | LLM-Modell (Ollama) |
| limit | int | 5 | Max. Kontext-Chunks |
Response
{
"success": true,
"data": {
"answer": "Um Apache SSL zu konfigurieren...",
"sources": [
{"title": "Apache", "path": "/server/apache", "score": 0.89}
],
"model": "mistral",
"tokens": {"input": 1200, "output": 350}
}
}
Fehlerbehandlung
| HTTP Code | Bedeutung |
|---|---|
| 400 | Fehlende oder ungültige Parameter |
| 404 | Dokument nicht gefunden |
| 500 | Server-Fehler |
Services
| Service | Beschreibung |
|---|---|
| DokumentationRepository | CRUD-Operationen für Dokumente |
| ChunkSearchService | Semantische Suche über Chunks |
| DocumentationChatUseCase | RAG-Chat mit Dokumentation |
Verwandte Dokumentation
]]>Config API
REST-API für Config-Management. Ermöglicht das Abrufen und Aktualisieren von System-Konfigurationen wie Prompts, Strukturen und Autorenprofile.
| Controller | Controller\Api\ConfigController |
|---|---|
| Base-URL | /api/v1/config |
| Datenbank | ki_content.content_config |
| UseCase | UseCases\Config\ManageConfigUseCase |
Endpoints-Übersicht
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | /api/v1/config/{id} | Config abrufen |
| POST | /api/v1/config/{id} | Config aktualisieren |
Config abrufen
GET /api/v1/config/{id}
Response
{
"id": 1,
"name": "System Prompt",
"type": "system_prompt",
"content": "Du bist ein hilfreicher Assistent...",
"version": "1.5"
}
Response-Felder
| Feld | Typ | Beschreibung |
|---|---|---|
| id | int | Config-ID |
| name | string | Config-Name |
| type | string | Config-Typ (siehe unten) |
| content | string | Config-Inhalt |
| version | string | Aktuelle Version |
Fehler-Response (404)
{
"error": "Config nicht gefunden"
}
Config aktualisieren
POST /api/v1/config/{id}
Content-Type: application/x-www-form-urlencoded
X-CSRF-TOKEN: {token}
content=Neuer+Config-Inhalt...
Request-Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
| content | string | Neuer Config-Inhalt |
Hinweis: Die Version wird automatisch inkrementiert (1.5 → 1.6).
Response
{
"success": true,
"version": "1.6",
"message": "Version 1.6 gespeichert"
}
Fehler-Response (400)
{
"error": "Validierungsfehler..."
}
Authentifizierung
Das POST-Endpoint erfordert einen gültigen CSRF-Token im Header:
X-CSRF-TOKEN: abc123...
Config-Typen
| Typ | Beschreibung | Beispiel |
|---|---|---|
| author_profile | Autorenprofile für Schreibstil | Karl Kratz Stil, Akademisch |
| structure | Output-Strukturen | LinkedIn-Post, Blog-Artikel |
| organization | Organisations-Infos | Firmenkontext |
| contract | Content-Verträge | Qualitätsregeln |
| rule | Einzelne Regeln | Formatvorgaben |
| system_prompt | System-Prompts für Chat | RAG-Prompt, Coaching-Prompt |
| critic | Kritik-Prompts | Qualitätsprüfer |
Versionierung
Jede Änderung erstellt eine neue Version:
- Version wird automatisch inkrementiert (Minor-Version)
- Format:
MAJOR.MINOR(z.B. 1.5 → 1.6) - Historie wird in
content_config_historygespeichert
Fehlerbehandlung
| HTTP Code | Bedeutung |
|---|---|
| 400 | Validierungsfehler |
| 403 | CSRF-Token ungültig |
| 404 | Config nicht gefunden |
| 500 | Server-Fehler |
Datenmodell
content_config (ki_content)
| Feld | Typ | Null | Beschreibung |
|---|---|---|---|
| id | int(11) | NO | Primärschlüssel |
| type | enum | NO | author_profile, structure, organization, contract, rule, system_prompt, critic |
| name | varchar(100) | NO | Config-Name |
| slug | varchar(100) | NO | URL-Slug |
| description | text | YES | Beschreibung |
| content | longtext | NO | Config-Inhalt |
| version | varchar(20) | YES | Aktuelle Version (Default: 1.0) |
| status | enum | YES | draft, active, deprecated (Default: draft) |
| parent_id | int(11) | YES | Parent-Config (optional) |
| prompt_id | int(11) | YES | Verknüpfter Prompt |
| sort_order | int(11) | NO | Sortierung (Default: 0) |
| created_at | datetime | YES | Erstellungsdatum |
| updated_at | datetime | YES | Letzte Änderung |
Verwandte Dokumentation
]]>Chat API
RAG-basierter Chat mit Vektorsuche und LLM-Integration. Verwendet lokale Embeddings (Ollama), Vektorsuche (Qdrant) und Claude (Anthropic) oder Ollama als LLM.
Endpoints-Übersicht
| Methode | Pfad | Controller | Beschreibung |
|---|---|---|---|
| POST | /api/v1/chat | Api\ChatController | Einfache Chat-Anfrage (JSON) |
| GET | /api/v1/chat/search | Api\ChatController | Chunk-Suche |
| GET | /api/v1/chat/stats | Api\ChatController | Pipeline-Statistiken |
| POST | /chat/{uuid}/message | ChatController | Chat-Nachricht senden (HTML/HTMX) |
JSON API: POST /api/v1/chat
Einfache Chat-Anfrage mit festen Einstellungen.
| Controller | Controller\Api\ChatController |
|---|---|
| Service | Infrastructure\AI\ChatService |
Request
POST /api/v1/chat
Content-Type: application/json
{
"message": "Was ist systemische Therapie?"
}
| Parameter | Typ | Beschreibung |
|---|---|---|
| message | string | Benutzer-Frage (required) |
Hinweis: Dieser Endpunkt verwendet feste Einstellungen: Claude Opus 4.5, Collection "dokumentation_chunks", Limit 5. Für konfigurierbare Optionen den HTML-Endpunkt verwenden.
Response
{
"answer": "Systemische Therapie ist ein psychotherapeutischer Ansatz...",
"sources": [
{
"title": "Einführung in die systemische Therapie",
"content": "...",
"score": 0.89,
"path": "/Documents/therapie/einfuehrung.pdf"
}
],
"model": "claude-opus-4-5-20251101",
"tokens": 1234
}
HTML-Endpunkt: POST /chat/{uuid}/message
Vollständig konfigurierbarer Chat mit Session-Unterstützung.
| Controller | Controller\ChatController |
|---|
Request
POST /chat/{uuid}/message
Content-Type: application/x-www-form-urlencoded
message=Was+ist+systemische+Therapie%3F
&model=anthropic
&collections[]=documents
&collections[]=dokumentation
&contextLimit=5
&systemPromptId=1
&structureId=2
&qualityCheck=1
Parameter
| Parameter | Typ | Default | Beschreibung |
|---|---|---|---|
| message | string | required | Benutzer-Frage |
| model | string | "anthropic" | "anthropic" (Claude) oder "ollama" (lokal) |
| collections[] | string[] | ["documents"] | Qdrant Collections (Array) |
| contextLimit | int | 5 | Max. Kontext-Chunks (3/5/10/15) |
| systemPromptId | int | null | System-Prompt aus content_config |
| structureId | int | null | Output-Struktur |
| qualityCheck | int | 0 | Qualitätsprüfung aktivieren |
| author_profile_id | int | null | Autorenprofil für Schreibstil |
GET /api/v1/chat/search
Suche nach relevanten Chunks ohne LLM-Anfrage.
GET /api/v1/chat/search?q=systemische+therapie&limit=5
Response
{
"results": [
{"id": 42, "score": 0.89, "payload": {...}}
]
}
GET /api/v1/chat/stats
Pipeline-Statistiken (Doc2Vector).
{
"dokumente": 15,
"seiten": 120,
"chunks": 450,
"tokens": 125000,
"analyzed": 400,
"synced": 380
}
RAG-Pipeline
1. Embedding erstellen (OllamaService)
question → mxbai-embed-large → [1024-dim vector]
2. Vektorsuche (QdrantService)
vector → Qdrant :6333 → top-k similar chunks
3. Kontext aufbauen (ChatService)
chunks → formatierter Kontext mit Quellenangaben
max. 3000 tokens (~12000 chars)
4. LLM-Anfrage (ClaudeService oder OllamaService)
system_prompt + rag_prompt + context → answer
5. Response zusammenstellen (ChatService)
answer + sources + metadata + usage
Fehlerbehandlung
| HTTP Code | Bedeutung |
|---|---|
| 400 | Fehlende oder ungültige Parameter |
| 500 | Service-Fehler (Ollama, Qdrant, Claude) |
| 503 | Service nicht verfügbar |
Content API
REST-API für das Content Studio.
| Controller | Controller\Api\ContentController |
|---|---|
| Base-URL | /api/v1/content |
| Format | JSON |
| Authentifizierung | CSRF-Token erforderlich |
Endpoints
| Methode | Endpoint | Beschreibung |
|---|---|---|
| PUT | /api/v1/content/{id} | Auftrag aktualisieren |
PUT /api/v1/content/{id}
Aktualisiert einen bestehenden Content-Auftrag.
Request-Body
{
"title": "Neuer Titel", // required
"briefing": "Aktualisiertes Briefing", // required
"author_profile_id": 1, // optional
"contract_id": 1, // optional
"structure_id": 1 // optional
}
Beispiel
curl -X PUT https://dev.campus.systemische-tools.de/api/v1/content/1 \
-H "Content-Type: application/json" \
-H "X-CSRF-TOKEN: abc123..." \
-d '{
"title": "Blogpost über Teamcoaching",
"briefing": "Schreibe einen informativen Artikel...",
"author_profile_id": 1,
"structure_id": 1
}'
Response (200 OK)
{
"success": true,
"data": {
"id": 1,
"title": "Blogpost über Teamcoaching",
"briefing": "Schreibe einen informativen Artikel...",
"status": "draft",
"author_profile_id": 1,
"contract_id": null,
"structure_id": 1,
"profile_name": "Akademisch",
"contract_name": null,
"structure_name": "Blog-Artikel",
"created_at": "2025-12-20 10:00:00",
"updated_at": "2025-12-20 12:30:00"
}
}
Error-Responses
// 400 Bad Request
{
"success": false,
"error": "Titel ist erforderlich"
}
// 404 Not Found
{
"success": false,
"error": "Auftrag nicht gefunden"
}
Workflow-Endpoints (HTMX)
Die folgenden Endpoints werden primär über HTMX aufgerufen und liefern HTML-Fragmente:
| Methode | Endpoint | Beschreibung |
|---|---|---|
| POST | /content/{id}/generate | Content generieren |
| POST | /content/{id}/critique | Kritik-Runde starten |
| POST | /content/{id}/revise | Revision erstellen |
| POST | /content/{id}/approve | Content genehmigen |
| POST | /content/{id}/decline | Content ablehnen |
Tasks API
REST-API für Task-Management mit Zuweisungen, Ergebnissen und KI-Ausführung.
| Controller | Controller\Api\TaskController |
|---|---|
| Base-URL | /api/v1/tasks |
| Format | JSON |
Endpoints
Tasks auflisten
GET /api/v1/tasks?status=pending&type=ai_task&limit=50&offset=0
| Parameter | Typ | Beschreibung |
|---|---|---|
| status | string | pending, in_progress, completed, failed, cancelled |
| type | string | human_task, ai_task, mixed |
| search | string | Volltextsuche |
| limit | int | Max. Ergebnisse (default: 50) |
| offset | int | Pagination-Offset |
Task erstellen
POST /api/v1/tasks
Content-Type: application/json
{
"title": "Dokumentation prüfen",
"description": "Alle Links in der Doku validieren",
"type": "ai_task",
"due_date": "2025-12-25T12:00:00Z"
}
Task-Details abrufen
GET /api/v1/tasks/{id}
Liefert Task mit Assignments und Results.
Task aktualisieren
PUT /api/v1/tasks/{id}
Content-Type: application/json
{
"title": "Neuer Titel",
"description": "Neue Beschreibung",
"type": "mixed",
"due_date": "2025-12-30T18:00:00Z"
}
Task löschen
DELETE /api/v1/tasks/{id}
Status ändern
PUT /api/v1/tasks/{id}/status
Content-Type: application/json
{
"status": "in_progress",
"updated_by": "claude",
"updated_by_type": "ai"
}
Task zuweisen
POST /api/v1/tasks/{id}/assign
Content-Type: application/json
{
"assignee": "claude",
"assignee_type": "claude",
"model_name": "claude-3-5-sonnet",
"notes": "Priorität hoch"
}
Ergebnis speichern
POST /api/v1/tasks/{id}/results
Content-Type: application/json
{
"executor": "claude",
"executor_type": "claude",
"model_name": "claude-3-5-sonnet",
"response": "Task erfolgreich abgeschlossen",
"status": "success",
"tokens_input": 1500,
"tokens_output": 500
}
Ergebnisse abrufen
GET /api/v1/tasks/{id}/results
KI-Ausführung
POST /api/v1/tasks/{id}/execute
Content-Type: application/json
{
"model": "mistral",
"auto_complete": true
}
Führt den Task mit lokalem Ollama aus.
Statistiken
GET /api/v1/tasks/statistics
Liefert Statistiken zu Tasks, Token-Verbrauch und Modell-Nutzung.
Response
{
"success": true,
"data": {
"tasks": {
"by_status": {"pending": 10, "completed": 50, ...},
"by_type": {"ai_task": 30, "human_task": 20, ...},
"total": 60
},
"tokens": {
"total_input": 150000,
"total_output": 50000,
"total": 200000
},
"models": [
{"model_name": "claude-opus-4-5", "count": 25, "total_tokens": 80000},
{"model_name": "mistral", "count": 15, "total_tokens": 40000}
]
}
}
Response-Format
Erfolg
{
"success": true,
"data": { ... },
"meta": {
"total": 42,
"limit": 50,
"offset": 0
}
}
Fehler
{
"success": false,
"error": "Fehlermeldung"
}
Task-Objekt
{
"id": 100,
"uuid": "76c8b3ed-...",
"title": "Dokumentation prüfen",
"description": "...",
"type": "ai_task",
"status": "pending",
"created_by": "mcp-tasks",
"created_by_type": "ai",
"parent_task_id": null,
"due_date": "2025-12-25T12:00:00",
"created_at": "2025-12-20T10:00:00",
"updated_at": "2025-12-20T10:00:00",
"completed_at": null
}
UseCases
| UseCase | Beschreibung |
|---|---|
| GetTasksUseCase | Tasks laden und filtern |
| CreateTaskUseCase | Task erstellen |
| UpdateTaskStatusUseCase | Status ändern |
| DeleteTaskUseCase | Task löschen |
| AssignTaskUseCase | Zuweisung erstellen |
| SaveTaskResultUseCase | Ergebnis speichern |
| ExecuteAITaskUseCase | KI-Ausführung mit Ollama |
Verwandte Dokumentation
]]>AI Services
PHP-Service-Klassen für KI-Integration. Native HTTP-Clients für Ollama, Qdrant und Claude API.
| Pfad | /src/Infrastructure/AI/ |
|---|---|
| Namespace | Infrastructure\AI |
| Contract | layered-architecture-pruefung_v1.0.yaml |
| Status | Produktiv (Migration von Python abgeschlossen) |
AIConfig
Zentralisierte Konfiguration und Service-Factory für alle AI-Services.
| Datei | AIConfig.php |
|---|---|
| Typ | readonly class |
| Funktion | Config-Management, Service-Factory, Credentials-Loading |
Properties
final readonly class AIConfig
{
public string $ollamaHost; // http://localhost:11434
public string $qdrantHost; // http://localhost:6333
public string $anthropicApiKey; // sk-ant-... (aus credentials.md)
public string $embeddingModel; // mxbai-embed-large
public string $claudeModel; // claude-opus-4-5-20251101
public string $defaultCollection; // documents
}
Factory-Methoden
// Config erstellen (lädt API-Key aus credentials.md)
$config = AIConfig::fromCredentialsFile();
// Einzelne Services erstellen
$ollama = $config->createOllamaService();
$qdrant = $config->createQdrantService();
$claude = $config->createClaudeService();
// Vollständiger ChatService (alle Dependencies)
$chatService = $config->createChatService();
Verwendung
use Infrastructure\AI\AIConfig;
// Einfachster Weg: ChatService direkt nutzen
$config = AIConfig::fromCredentialsFile();
$chat = $config->createChatService();
$result = $chat->chat('Was ist systemisches Coaching?');
// Alternative: Einzelne Services für spezielle Aufgaben
$config = AIConfig::fromCredentialsFile();
$ollama = $config->createOllamaService();
$embedding = $ollama->getEmbedding('Text zum Einbetten');
OllamaService
Embedding-Generierung und LLM-Generierung via Ollama REST API.
| Datei | OllamaService.php |
|---|---|
| Host | http://localhost:11434 |
| Embedding-Model | mxbai-embed-large |
| LLM-Model | gemma3:4b-it-qat |
| Dimension | 1024 |
Methoden
final readonly class OllamaService
{
public function __construct(string $host = 'http://localhost:11434');
/**
* Generiert Embedding-Vektor für Text.
* @return array<int, float> 1024-dimensionaler Vektor
* @throws RuntimeException
*/
public function getEmbedding(
string $text,
string $model = 'mxbai-embed-large'
): array;
/**
* Generiert Text-Antwort mit Ollama-LLM.
* @throws RuntimeException
*/
public function generate(
string $prompt,
string $model = 'gemma3:4b-it-qat'
): string;
/**
* Prüft ob Ollama API erreichbar ist.
*/
public function isAvailable(): bool;
}
Code-Beispiel
use Infrastructure\AI\OllamaService;
$ollama = new OllamaService('http://localhost:11434');
// Embedding erstellen
$embedding = $ollama->getEmbedding('Hello World');
// Returns: [0.123, -0.456, 0.789, ...] (1024 floats)
// Text generieren
$response = $ollama->generate('Explain quantum computing.');
// Returns: "Quantum computing is a type of computing that..."
// Health Check
if ($ollama->isAvailable()) {
echo "Ollama läuft";
}
API-Aufruf
POST http://localhost:11434/api/embeddings
Content-Type: application/json
{
"model": "mxbai-embed-large",
"prompt": "Text zum Einbetten"
}
Response:
{
"embedding": [0.123, -0.456, ...]
}
QdrantService
Vektorsuche via Qdrant REST API.
| Datei | QdrantService.php |
|---|---|
| Host | http://localhost:6333 |
| Collection | documents |
| Distance | Cosine |
| Timeout | 30s |
Methoden
final readonly class QdrantService
{
public function __construct(string $host = 'http://localhost:6333');
/**
* Sucht ähnliche Dokumente per Vektor-Similarity.
* @param array<int, float> $vector Embedding-Vektor
* @return array<int, array{id: int|string, score: float, payload: array}>
* @throws RuntimeException
*/
public function search(
array $vector,
string $collection = 'documents',
int $limit = 5
): array;
/**
* Prüft ob Collection existiert.
*/
public function collectionExists(string $collection): bool;
/**
* Prüft ob Qdrant API erreichbar ist.
*/
public function isAvailable(): bool;
/**
* Holt Collection-Informationen.
* @return array<string, mixed>|null
* @throws RuntimeException
*/
public function getCollectionInfo(string $collection): ?array;
}
Code-Beispiel
use Infrastructure\AI\QdrantService;
$qdrant = new QdrantService('http://localhost:6333');
// Vektorsuche
$vector = [0.123, -0.456, 0.789, ...]; // 1024-dimensional
$results = $qdrant->search($vector, 'documents', 5);
// Returns: [
// ['id' => 1, 'score' => 0.89, 'payload' => ['content' => '...', 'title' => '...']],
// ['id' => 2, 'score' => 0.76, 'payload' => ['content' => '...', 'title' => '...']]
// ]
// Collection prüfen
if ($qdrant->collectionExists('documents')) {
$info = $qdrant->getCollectionInfo('documents');
echo "Vektoren: " . $info['vectors_count'];
}
API-Aufruf
POST http://localhost:6333/collections/documents/points/search
Content-Type: application/json
{
"vector": [0.123, -0.456, ...],
"limit": 5,
"with_payload": true
}
Response:
{
"result": [
{
"id": 1,
"score": 0.89,
"payload": {
"content": "...",
"document_title": "..."
}
}
]
}
ClaudeService
LLM-Anfragen via Anthropic API.
| Datei | ClaudeService.php |
|---|---|
| API | https://api.anthropic.com/v1/messages |
| API Version | 2023-06-01 |
| Model | claude-opus-4-5-20251101 |
| Max Tokens | 4000 |
| Timeout | 120s |
Methoden
final readonly class ClaudeService
{
public function __construct(string $apiKey);
/**
* Sendet Prompt an Claude und gibt Antwort zurück.
* @return array{text: string, usage: array{input_tokens: int, output_tokens: int}}
* @throws RuntimeException
*/
public function ask(
string $prompt,
?string $systemPrompt = null,
string $model = 'claude-opus-4-5-20251101',
int $maxTokens = 4000
): array;
/**
* Erstellt RAG-Prompt mit Kontext.
*/
public function buildRagPrompt(string $question, string $context): string;
/**
* Liefert Standard-System-Prompt für RAG.
*/
public function getDefaultSystemPrompt(): string;
/**
* Prüft ob Claude API erreichbar ist.
*/
public function isAvailable(): bool;
}
Code-Beispiel
use Infrastructure\AI\ClaudeService;
$claude = new ClaudeService('sk-ant-...');
// Einfache Anfrage
$result = $claude->ask('Explain quantum computing');
echo $result['text'];
echo "Tokens: " . $result['usage']['output_tokens'];
// Mit System-Prompt
$system = 'You are a physics teacher.';
$result = $claude->ask('Explain relativity', $system);
// RAG-Prompt erstellen
$question = 'Was ist systemisches Coaching?';
$context = '[Quelle 1: Coaching Grundlagen]\nSystemisches Coaching betrachtet...';
$prompt = $claude->buildRagPrompt($question, $context);
$systemPrompt = $claude->getDefaultSystemPrompt();
$result = $claude->ask($prompt, $systemPrompt);
API-Aufruf
POST https://api.anthropic.com/v1/messages
Content-Type: application/json
x-api-key: sk-ant-...
anthropic-version: 2023-06-01
{
"model": "claude-opus-4-5-20251101",
"max_tokens": 4000,
"system": "Du bist ein hilfreicher Assistent...",
"messages": [
{
"role": "user",
"content": "..."
}
]
}
Response:
{
"content": [
{
"type": "text",
"text": "..."
}
],
"usage": {
"input_tokens": 100,
"output_tokens": 200
}
}
ChatService
Orchestriert RAG-Pipeline mit allen Services. Vollständiger Ablauf: Embedding → Vektorsuche → Kontext → LLM-Antwort.
| Datei | ChatService.php |
|---|---|
| Abhängigkeiten | OllamaService, QdrantService, ClaudeService |
| Pipeline-Schritte | 6 (Embedding, Search, Context, LLM, Sources, Response) |
Methoden
final readonly class ChatService
{
public function __construct(
OllamaService $ollama,
QdrantService $qdrant,
ClaudeService $claude
);
/**
* Führt vollständige RAG-Chat-Pipeline aus.
* @return array{
* question: string,
* answer: string,
* sources: array,
* model: string,
* usage?: array,
* chunks_used: int
* }
* @throws RuntimeException
*/
public function chat(
string $question,
string $model = 'anthropic',
string $collection = 'documents',
int $limit = 5
): array;
}
Code-Beispiel
use Infrastructure\AI\AIConfig;
// Mit Factory (empfohlen)
$config = AIConfig::fromCredentialsFile();
$chat = $config->createChatService();
$result = $chat->chat(
question: 'Was ist systemisches Coaching?',
model: 'anthropic',
collection: 'documents',
limit: 5
);
echo $result['answer'];
echo "Chunks: " . $result['chunks_used'];
foreach ($result['sources'] as $source) {
echo $source['title'] . " (Score: " . $source['score'] . ")";
}
Response-Struktur
{
"question": "Was ist systemisches Coaching?",
"answer": "Systemisches Coaching ist ein Ansatz...",
"sources": [
{
"title": "Coaching Grundlagen",
"score": 0.89,
"content": "..."
}
],
"model": "anthropic",
"usage": {
"input_tokens": 234,
"output_tokens": 567
},
"chunks_used": 5
}
Fehlerbehandlung
Alle Services werfen RuntimeException bei Fehlern:
| Service | Fehlerfall |
|---|---|
| OllamaService | API nicht erreichbar, ungültiges Embedding, Timeout |
| QdrantService | API nicht erreichbar, Collection fehlt, ungültige Antwort |
| ClaudeService | API nicht erreichbar, ungültiger API-Key, Rate-Limit, Timeout |
| ChatService | Embedding-Fehler, Search-Fehler, keine Dokumente, LLM-Fehler |
try {
$result = $chat->chat('Was ist systemisches Coaching?');
} catch (RuntimeException $e) {
error_log('Chat failed: ' . $e->getMessage());
// Fehlerbehandlung
}
Konfiguration
Alle Konfigurationswerte werden von AIConfig verwaltet:
| Parameter | Default-Wert | Quelle |
|---|---|---|
| ollamaHost | http://localhost:11434 | AIConfig |
| qdrantHost | http://localhost:6333 | AIConfig |
| anthropicApiKey | sk-ant-... | /var/www/docs/credentials/credentials.md |
| embeddingModel | mxbai-embed-large | AIConfig |
| claudeModel | claude-opus-4-5-20251101 | AIConfig |
| defaultCollection | documents | AIConfig |
Custom-Konfiguration
use Infrastructure\AI\AIConfig;
// Vollständig custom
$config = new AIConfig(
ollamaHost: 'http://192.168.1.100:11434',
qdrantHost: 'http://192.168.1.101:6333',
anthropicApiKey: 'sk-ant-...',
embeddingModel: 'mxbai-embed-large',
claudeModel: 'claude-opus-4-5-20251101',
defaultCollection: 'my_docs'
);
$chat = $config->createChatService();Explorer API
REST-API für den Doc2Vector Explorer mit Dokumenten, Seiten, Chunks, Entitäten, Taxonomie und Suche.
| Controller | Controller\Api\ExplorerController |
|---|---|
| Base-URL | /api/v1/explorer |
| Datenbank | ki_content (documents, chunks, entities, ...) |
Endpoints-Übersicht
| Methode | Pfad | Beschreibung |
|---|---|---|
| GET | /api/v1/explorer/stats | Statistiken |
| GET | /api/v1/explorer/dokumente | Alle Dokumente |
| GET | /api/v1/explorer/dokumente/{id} | Dokument-Details |
| GET | /api/v1/explorer/seiten | Alle Seiten |
| GET | /api/v1/explorer/seiten/{id} | Seiten-Details |
| GET | /api/v1/explorer/chunks | Alle Chunks |
| GET | /api/v1/explorer/chunks/{id} | Chunk-Details |
| GET | /api/v1/explorer/taxonomie | Taxonomie-Kategorien |
| GET | /api/v1/explorer/entities | Entitäten gruppiert |
| POST | /api/v1/explorer/suche | Hybrid-Suche |
Statistiken
GET /api/v1/explorer/stats
Liefert Übersicht über alle Daten:
{
"success": true,
"data": {
"dokumente": 15,
"seiten": 120,
"chunks": {
"total": 450,
"tokens": 125000,
"analyzed": 400,
"synced": 380
},
"taxonomy_categories": [...]
}
}
Dokumente
Liste aller Dokumente
GET /api/v1/explorer/dokumente
Liefert alle Quelldokumente mit Statistiken.
Dokument-Details
GET /api/v1/explorer/dokumente/{id}
Liefert Dokument mit zugehörigen Seiten und Taxonomie.
Seiten
Seiten auflisten
GET /api/v1/explorer/seiten?search=&parent_id=&limit=50&offset=0
| Parameter | Typ | Beschreibung |
|---|---|---|
| search | string | Suche in Inhalt |
| parent_id | int | Filter nach Parent-Dokument |
| limit | int | Max. Ergebnisse (max 50) |
| offset | int | Pagination-Offset |
Seiten-Details
GET /api/v1/explorer/seiten/{id}
Liefert Seite mit Chunks und Unterseiten.
Chunks
Chunks auflisten
GET /api/v1/explorer/chunks?category=&status=&search=&limit=50&offset=0
| Parameter | Typ | Beschreibung |
|---|---|---|
| category | string | Taxonomie-Kategorie |
| status | string | Chunk-Status |
| search | string | Suche in Content |
| limit | int | Max. Ergebnisse (max 50) |
| offset | int | Pagination-Offset |
Chunk-Details
GET /api/v1/explorer/chunks/{id}
Liefert Chunk mit allen Metadaten:
{
"success": true,
"data": {
"id": 42,
"chunk_index": 3,
"content": "...",
"token_count": 280,
"entities": [
{"name": "Carl Rogers", "type": "PERSON"}
],
"keywords": ["Therapie", "Empathie"],
"qdrant_id": "abc123..."
}
}
Taxonomie
GET /api/v1/explorer/taxonomie
Liefert Top-Kategorien und Keywords:
{
"success": true,
"data": {
"categories": [...],
"top_keywords": [...]
}
}
Entitäten
GET /api/v1/explorer/entities
Liefert Entitäten gruppiert nach Typ.
Hybrid-Suche
POST /api/v1/explorer/suche
Content-Type: application/json
{
"query": "Systemische Therapie",
"category": "Psychotherapie",
"limit": 10
}
Kombiniert Vektor- und Keyword-Suche:
{
"success": true,
"data": {
"query": "Systemische Therapie",
"results": [...],
"suggestions": [...],
"count": 8
}
}
Response-Format
{
"success": true,
"data": { ... },
"meta": {
"total": 450,
"limit": 50,
"offset": 0
}
}
Datenmodell
documents (ki_content)
| Feld | Typ | Beschreibung |
|---|---|---|
| id | int | Primärschlüssel |
| filename | varchar | Dateiname |
| title | varchar | Titel |
| source | varchar | Quelle (Nextcloud-Pfad) |
| page_count | int | Seitenanzahl |
| status | enum | pending, processing, completed, error |
chunks (ki_content)
| Feld | Typ | Beschreibung |
|---|---|---|
| id | int | Primärschlüssel |
| document_id | int | FK zu documents |
| chunk_index | int | Position in Dokument |
| content | text | Chunk-Inhalt |
| token_count | int | Token-Anzahl |
| embedding_model | varchar | Verwendetes Modell |
| qdrant_id | varchar | Qdrant-Vektor-ID |
entities (ki_content)
| Feld | Typ | Beschreibung |
|---|---|---|
| id | int | Primärschlüssel |
| name | varchar | Entity-Name |
| canonical_name | varchar | Normalisierter Name |
| type | enum | PERSON, CONCEPT, ORGANIZATION, ... |