Headless Supply-Demand-Matching-Plattform für IT-Dienstleister und Freelancer.
ApplicationOps automatisiert den Matching-Prozess zwischen Projektanfragen (Offers) und Dienstleistern (Provider Profiles). Die Engine bewertet Kandidaten nicht nur nach Stichworten, sondern versteht semantische Zusammenhänge zwischen Skills — z. B. erkennt sie, dass "Observability" und "Prometheus" zusammengehören.
- Semantisches Matching: pgvector-Cosinus-Ähnlichkeit + LLM-gestützte Skill-Normalisierung + Ontologie-Mapping
- Evidence-Backed Profiles: Lebensläufe werden per Docling (OCR/KI) geparst und automatisch in strukturierte Nachweise umgewandelt
- Case-Lifecycle: Vollständiger Workflow von NEW → MATCHING → POSITIONING → DOCUMENTING → REVIEW → SUBMITTED → WON/LOST
- Feedback-Learning: Verlorene Deals fließen zurück ins Matching — welche Skills fehlten? Welche wurden überbewertet?
- MCP-Integration: Model Context Protocol für KI-Agenten (Claude, Copilot, Zed Agent)
- Multi-Tenant-fähig: Mandantentrennung über
ownerType/ownerId
┌──────────────────────────────────────────────────────────────┐
│ REST API (:8081) │
│ ProviderProfile │ ProjectOffer │ Case │ Evidence │ Feedback │
├──────────────────────────────────────────────────────────────┤
│ MCP Server │
│ createProvider │ createOffer │ matchProviders │ parseCv ... │
├──────────────────────────────────────────────────────────────┤
│ Domain Services │
│ MatchingService │ CaseService │ ArtifactDraftingService │
│ EvidenceService │ CvDocumentParser │ FeedbackService │
├──────────────────────────────────────────────────────────────┤
│ AI Layer │
│ SpringAiClient (ChatModel) │ SkillExtractionService │
│ SkillNormalizationService │ EmbeddingService (mistral-embed)│
├──────────────────────────────────────────────────────────────┤
│ Infrastructure │
│ PostgreSQL 17 + pgvector │ NATS JetStream │ MinIO/S3 │
│ Redis │ Docling Worker │ Typst Worker │
└──────────────────────────────────────────────────────────────┘
1. pgvector Cosine Similarity (ivfflat index, probes=10)
→ Top-K Kandidaten aus allen aktiven Providern
2. LLM Skill Normalization (Mistral, gecached in skill_concept)
→ "observability" → "prometheus, grafana, opentelemetry"
→ Transferability: AWS → Azure (20% Gewichtung)
3. Weighted Scoring (chunked, PriorityQueue top-N)
→ 60% Skill-Overlap + 25% Erfahrung + 15% Kapazität
→ Non-linear Boost bei >70% Overlap (×1.15)
Dieses Projekt ist neben seiner Funktion als Matching-Plattform auch eine produktive Fallstudie für Spring AI. Es wurde bewusst als realer Anwendungsfall konzipiert — nicht als Demo oder Spielzeug — um die Praxistauglichkeit von Spring AI in einer Echtsystem-Umgebung zu validieren.
| Feature | Konkreter Einsatz | Spring AI Komponente |
|---|---|---|
| Chat Completions | Skill-Extraktion aus CV-Text, Matching-Rationale, Positionierungstexte | ChatModel via SpringAiClient (OpenAI-kompatibel → Mistral) |
| Embeddings | Vektorisierung von Provider-Profilen für pgvector-Cosinus-Ähnlichkeit | EmbeddingModel (mistral-embed, 1536d) |
| pgvector Store | Speicherung und Abfrage von Embeddings in PostgreSQL 17 | spring-ai-pgvector-store |
| MCP Server | 14 Tools für KI-Agenten (Claude, Copilot, Zed) | spring-ai-starter-mcp-server-webmvc |
| Prompt Templates | DB-gestützte Prompt-Verwaltung mit Versionierung | PromptRegistry + Flyway-Migrationen |
Positiv:
- Spring AI 1.1.7 läuft stabil mit Spring Boot 4.0.6 — die anfängliche Skepsis war unbegründet. Der
ChatModel-Ansatz ist sauber abstrahiert und provider-agnostisch. - Die OpenAI-Kompatibilität von Mistral funktioniert out-of-the-box. Kein Custom-Code nötig, nur
spring.ai.openai.*Properties. - MCP Server Integration via
@McpToolAnnotationen ist erstaunlich einfach — 14 Tools in einer Klasse, kein Boilerplate. - pgvector als PostgreSQL-Erweiterung spart eine separate Vector-DB — gerade für kleinere bis mittlere Projekte ideal.
Herausforderungen:
- Die Spring AI Dokumentation ist noch lückenhaft. Vieles musste durch Source-Code-Reading und Experimente erschlossen werden.
max_tokensist nicht direkt imChatModel-Interface steuerbar — wir haben einen Workaround über ein eigenesAiClient.complete(key, text, maxTokens)gebaut.- Embedding-Caching für wiederholte gleiche Texte fehlt in Spring AI — wir cachen selbst über
EmbeddingService. - Die MCP-Integration in IDEs (Zed, VS Code) ist noch in den Kinderschuhen — Tool-Discovery funktioniert, aber die UX ist ausbaufähig.
Fazit: Spring AI ist produktionsreif für den von uns genutzten Scope. Wer eine KI-Integration in ein bestehendes Spring-Boot-Projekt einbauen will, findet hier ein erprobtes Referenzprojekt.
- Java 21+
- Docker & Docker Compose
- Mistral API Key (console.mistral.ai)
docker compose up -d postgres nats redis minioexport MISTRAL_API_KEY="your-key"
export DB_PASSWORD="appops"
export STORAGE_ACCESS_KEY="minioadmin"
export STORAGE_SECRET_KEY="minioadmin"./mvnw -pl application-ops-api spring-boot:runDie API ist unter http://localhost:8081 erreichbar. Health-Check: http://localhost:8081/actuator/health
cd workers/docling-worker
.venv/bin/python main.pydocker compose --profile full up -dStartet: PostgreSQL, NATS, Redis, MinIO, Typst Worker, ApplicationOps API (Docker)
| Methode | Pfad | Beschreibung |
|---|---|---|
POST |
/api/v1/providers |
Provider anlegen |
GET |
/api/v1/providers?page=0&size=20 |
Provider listen (paginiert) |
POST |
/api/v1/offers |
Projektanfrage erstellen |
POST |
/api/v1/offers/{id}/match |
Matching auslösen |
POST |
/api/v1/cases |
Case aus Offer erstellen |
POST |
/api/v1/cases/{id}/assign-provider |
Provider zuweisen |
POST |
/api/v1/cases/{id}/submit |
Case einreichen |
POST |
/api/v1/cases/{id}/won |
Als gewonnen markieren |
POST |
/api/v1/source-documents/upload |
CV/PDF hochladen (→ MinIO → Docling) |
POST |
/api/v1/providers/{id}/parse-document/{docId} |
CV per KI in strukturierte Daten umwandeln |
POST |
/api/v1/cases/{id}/feedback |
Feedback nach Abschluss |
# 1. Offer mit Skills erstellen
curl -X POST http://localhost:8081/api/v1/offers \
-H "Content-Type: application/json" \
-d '{
"title":"GenAI Platform Architect",
"description":"Aufbau einer GenAI-Plattform mit RAG und MCP.",
"requirements":"{\"requiredSkills\":[\"Python\",\"LangChain\",\"RAG\",\"Kubernetes\",\"MCP\"]}"
}'
# 2. Matching auslösen
curl -X POST http://localhost:8081/api/v1/offers/{offerId}/match
# 3. Case erstellen und Provider zuweisen
curl -X POST http://localhost:8081/api/v1/cases \
-H "Content-Type: application/json" \
-d '{"offerId":"{offerId}","caseType":"APPLICATION"}'Die Engine stellt folgende Tools via Model Context Protocol bereit:
| Tool | Beschreibung |
|---|---|
createProvider |
Provider-Profil anlegen |
createOffer |
Projektanfrage erstellen |
listProviders |
Alle Provider auflisten |
listOffers |
Alle Offers auflisten |
createCase |
Case aus Offer starten |
matchProviders |
Matching mit Skill-Liste auslösen |
completeMatching |
Provider zuweisen |
parseCv |
Strukturierte CV-Daten persistieren |
parseProviderDocument |
CV-PDF per KI parsen → Skills + Nachweise |
draftCv |
CV-Artifact generieren |
draftProposal |
Proposal-Artifact generieren |
markWon / markLost |
Case abschließen |
recordFeedback |
Feedback erfassen |
extractSkills |
Skills aus Freitext extrahieren |
application-ops/
├── application-ops-api/ # REST Controller, MCP Tools, DTOs
├── application-ops-core/ # Domain-Modell, Services, AI-Layer
├── application-ops-integration/ # NATS, MinIO/S3, Event Bus
├── workers/
│ ├── docling-worker/ # PDF → Markdown (Docling + RapidOCR)
│ └── typst-worker/ # JSON → PDF-Rendering (Typst)
├── docs/ # Audits, Architektur-Entscheidungen
├── compose.yaml # Docker Compose (Entwicklung + Produktion)
├── Dockerfile # Multi-Stage Produktions-Image
└── pom.xml # Maven Parent POM
| Komponente | Technologie |
|---|---|
| Sprache | Java 21 |
| Framework | Spring Boot 4.0.6 |
| Datenbank | PostgreSQL 17 + pgvector (Cosinus-Ähnlichkeit) |
| Messaging | NATS JetStream |
| Object Storage | MinIO (dev) / AWS S3 (prod) |
| KI | Mistral AI (small + embed) |
| OCR/PDF | Docling + RapidOCR |
| PDF-Rendering | Typst |
| Observability | OpenTelemetry → Grafana Alloy → Tempo/Loki |
| Caching | Redis |
| Testing | JUnit 5, Mockito, Testcontainers, ArchUnit |
GNU Affero General Public License v3.0 (AGPLv3)
- Community: Kostenlos nutzen, modifizieren, hosten — aber Änderungen müssen offengelegt werden
- Enterprise: Kommerzielle Lizenz ohne AGPL-Pflichten unter licensing@bentech.app
Copyright (c) 2026 Skander Ben Abdelmalak | bentech.app
- Schmidt & Hunter (1998): Strukturierte Nachweise verbessern Auswahlvalidität um 0.16
- Bhola et al. (2020): LLM-basierte Skill-Extraktion übertrifft regelbasierte Ansätze um 23% F1
- Autor & Handel (2013): Erfahrungskurve flacht bei 12–15 Jahren ab (Experience Ceiling)
- Campion et al. (1997): Strukturierte Interviews haben Validität 0.51 vs. 0.38 unstrukturiert
- ESCO (European Commission): Ontologie-Referenz für Skill-Normalisierung