{"id":660,"date":"2026-04-25T22:48:39","date_gmt":"2026-04-25T21:48:39","guid":{"rendered":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/?p=660"},"modified":"2026-06-16T22:49:21","modified_gmt":"2026-06-16T21:49:21","slug":"spring-ai-kuenstliche-intelligenz-in-java-anwendungen","status":"publish","type":"post","link":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/?p=660","title":{"rendered":"Spring AI \u2013 K\u00fcnstliche Intelligenz in Java-Anwendungen"},"content":{"rendered":"\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Hinweis:<\/strong>&nbsp;Dieser Artikel basiert auf&nbsp;<strong>Spring AI 2.0.0<\/strong>&nbsp;(GA), das Spring Boot 4.0.x\/4.1.x voraussetzt.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">KI ist l\u00e4ngst nicht mehr nur ein Python-Thema. Mit&nbsp;<strong>Spring AI<\/strong>&nbsp;bringt das Spring-Team eine offizielle Abstraktionsschicht f\u00fcr Large Language Models (LLMs) und verwandte KI-Dienste in das Java-\u00d6kosystem. Das Ziel: KI-Funktionen mit denselben bekannten Mustern nutzen, die Spring-Entwickler von JPA, REST und Messaging gewohnt sind \u2013 inklusive Auto-Configuration, Dependency Injection und Testbarkeit.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Installation<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Spring AI wird wie jedes andere Spring Boot Modul \u00fcber den Starter integriert:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>org.springframework.ai<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">groupId<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>spring-ai-starter-model-openai<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">artifactId<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">dependency<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">F\u00fcr den Zugriff auf OpenAI wird ein API-Key ben\u00f6tigt:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">spring.ai.openai.api-key=${OPENAI_API_KEY}\nspring.ai.openai.chat.model=gpt-4o\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Spring AI unterst\u00fctzt zahlreiche Provider \u00fcber dieselbe einheitliche API: Anthropic, Ollama, Mistral, Azure OpenAI, Google GenAI, DeepSeek, Groq, NVIDIA, Perplexity und weitere.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Der ChatClient<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Das zentrale Bean ist der&nbsp;<code>ChatClient<\/code>. Er wird \u00fcber einen Builder erstellt und kann System-Prompts erhalten:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-keyword\">@Configuration<\/span>\nclass AIConfig {\n\n    <span class=\"hljs-keyword\">@Bean<\/span>\n    ChatClient chatClient(ChatClient.Builder builder) {\n        <span class=\"hljs-selector-tag\">return<\/span> <span class=\"hljs-selector-tag\">builder<\/span>\n            <span class=\"hljs-selector-class\">.defaultSystem<\/span>(\"<span class=\"hljs-selector-tag\">Du<\/span> <span class=\"hljs-selector-tag\">bist<\/span> <span class=\"hljs-selector-tag\">ein<\/span> <span class=\"hljs-selector-tag\">hilfsbereiter<\/span> <span class=\"hljs-selector-tag\">Java-Experte<\/span>. \" +\n                \"<span class=\"hljs-selector-tag\">Antworte<\/span> <span class=\"hljs-selector-tag\">pr<\/span>\u00e4<span class=\"hljs-selector-tag\">gnant<\/span> <span class=\"hljs-selector-tag\">in<\/span> <span class=\"hljs-selector-tag\">Deutsch<\/span>.\")\n            <span class=\"hljs-selector-class\">.build<\/span>();\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Einfache Verwendung:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">@Service\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">CodeAssistant<\/span> <\/span>{\n\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> ChatClient chatClient;\n\n    <span class=\"hljs-keyword\">public<\/span> CodeAssistant(ChatClient chatClient) {\n        this.chatClient = chatClient;\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> String erklaereFehler(String fehlermeldung) {\n        <span class=\"hljs-keyword\">return<\/span> chatClient.prompt()\n            .user(<span class=\"hljs-string\">\"Erkl\u00e4re diesen Java-Fehler: {fehler}\"<\/span>, fehlermeldung)\n            .call()\n            .content();\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><code>call()<\/code>&nbsp;sendet den Prompt synchron. F\u00fcr asynchrone Streaming-Verarbeitung gibt es&nbsp;<code>stream().chatResponse()<\/code>&nbsp;mit R\u00fcckgabe eines&nbsp;<code>Flux&lt;ChatResponse&gt;<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">Flux&lt;<span class=\"hljs-built_in\">String<\/span>&gt; stream = chatClient.prompt()\n    .user(<span class=\"hljs-string\">\"Erkl\u00e4re mir Java Streams\"<\/span>)\n    .stream()\n    .content();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Prompt Templates und Structured Outputs<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Spring AI bietet Prompt-Templates mit Platzhaltern, \u00e4hnlich wie&nbsp;<code>@Query<\/code>&nbsp;in Spring Data JPA:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">String antwort = chatClient.prompt()\n    .user(u -&gt; u.text(<span class=\"hljs-string\">\"\"<\/span><span class=\"hljs-string\">\"\n        Generiere eine Java-Klasse mit folgenden Eigenschaften:\n        - Klassenname: {className}\n        - Felder: {fields}\n        - Mit Gettern, Settern und Konstruktor.\n        Gib NUR den Java-Code zur\u00fcck, keine Erkl\u00e4rungen.\n        \"<\/span><span class=\"hljs-string\">\"\"<\/span>)\n        .param(<span class=\"hljs-string\">\"className\"<\/span>, <span class=\"hljs-string\">\"Person\"<\/span>)\n        .param(<span class=\"hljs-string\">\"fields\"<\/span>, <span class=\"hljs-string\">\"name:String, alter:int\"<\/span>))\n    .call()\n    .content();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">F\u00fcr strukturierte JSON-Antworten bietet Spring AI den&nbsp;<code>BeanOutputConverter<\/code>&nbsp;und die praktische&nbsp;<code>.entity()<\/code>-Methode:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">record Person(<span class=\"hljs-built_in\">String<\/span> name, int alter, <span class=\"hljs-built_in\">String<\/span> email) {}\n\n&lt;em&gt;<span class=\"hljs-comment\">\/\/ Einfache Variante mit ChatClient:&lt;\/em&gt;<\/span>\nPerson person = chatClient.prompt()\n    .user(<span class=\"hljs-string\">\"Gib eine zuf\u00e4llige Person zur\u00fcck.\"<\/span>)\n    .call()\n    .entity(Person.class);\n\nSystem.out.println(person.name()); <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ Automatisch deserialisiert<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Die&nbsp;<code>.entity()<\/code>-Methode generiert automatisch ein JSON-Schema, weist das LLM an, g\u00fcltiges JSON im Zielformat zur\u00fcckzugeben, und deserialisiert die Antwort. F\u00fcr komplexere Typen wie Listen verwendet man&nbsp;<code>ParameterizedTypeReference<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">List<\/span>&lt;Person&gt; personen = chatClient.prompt()\n    .user(<span class=\"hljs-string\">\"Gib 5 zuf\u00e4llige Personen zur\u00fcck.\"<\/span>)\n    .call()\n    .entity(<span class=\"hljs-keyword\">new<\/span> ParameterizedTypeReference&lt;<span class=\"hljs-keyword\">List<\/span>&lt;Person&gt;&gt;() {});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">F\u00fcr noch zuverl\u00e4ssigere Ergebnisse unterst\u00fctzt Spring AI auch&nbsp;<strong>Native Structured Output<\/strong>&nbsp;bei kompatiblen Modellen (z.B. GPT-4o, Claude 3.5+):<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">Person person = chatClient.prompt()\n    .advisors(AdvisorParams.ENABLE_NATIVE_STRUCTURED_OUTPUT)\n    .user(<span class=\"hljs-string\">\"Gib eine zuf\u00e4llige Person zur\u00fcck.\"<\/span>)\n    .call()\n    .entity(Person<span class=\"hljs-class\">.<span class=\"hljs-keyword\">class<\/span>);\n<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Tool Calling<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">LLMs k\u00f6nnen \u00fcber Tool Calling externe Java-Methoden als \u201eWerkzeuge&#8220; aufrufen \u2013 das Modell entscheidet selbst, wann und mit welchen Argumenten:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">@Component\npublic <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">WetterService<\/span> <\/span>{\n\n    @Tool(description = <span class=\"hljs-string\">\"Gibt das aktuelle Wetter f\u00fcr eine Stadt zur\u00fcck\"<\/span>)\n    public <span class=\"hljs-built_in\">String<\/span> currentWeather(\n            @ToolParam(description = <span class=\"hljs-string\">\"Die Stadt\"<\/span>) <span class=\"hljs-built_in\">String<\/span> stadt) {\n        &lt;em&gt;<span class=\"hljs-comment\">\/\/ Ruft echte Wetter-API auf&lt;\/em&gt;<\/span>\n        <span class=\"hljs-keyword\">return<\/span> api.getWetter(stadt);\n    }\n}\n\n&lt;em&gt;<span class=\"hljs-comment\">\/\/ Im ChatClient registrieren:&lt;\/em&gt;<\/span>\n<span class=\"hljs-built_in\">String<\/span> antwort = chatClient.prompt()\n    .user(<span class=\"hljs-string\">\"Wie ist das Wetter in Hamburg?\"<\/span>)\n    .tools(<span class=\"hljs-keyword\">new<\/span> WetterService())\n    .call()\n    .content();\n\n<span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ Das LLM erkennt, dass es das Wetter-Tool f\u00fcr \"Hamburg\" aufrufen muss,<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n<span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ Spring AI f\u00fchrt die Java-Methode aus und gibt das Ergebnis ans LLM zur\u00fcck<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Das LLM erh\u00e4lt eine Beschreibung der verf\u00fcgbaren Tools und ihrer Parameter. Bei Bedarf ruft es sie selbstst\u00e4ndig auf \u2013 ganz ohne If-Then-Logik im Code. Spring AI registriert automatisch einen&nbsp;<code>ToolCallingAdvisor<\/code>, der den gesamten Tool-Calling-Lebenszyklus verwaltet.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Embeddings und Vektor-Datenbanken<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">F\u00fcr semantische Suche und RAG (Retrieval Augmented Generation) bietet Spring AI das&nbsp;<code>EmbeddingModel<\/code>-Interface:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">@Service\n<span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">EmbeddingService<\/span> <\/span>{\n\n    <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">final<\/span> EmbeddingModel embeddingModel;\n\n    <span class=\"hljs-keyword\">public<\/span> EmbeddingService(EmbeddingModel embeddingModel) {\n        this.embeddingModel = embeddingModel;\n    }\n\n    <span class=\"hljs-keyword\">public<\/span> float&#91;] textZuVektor(String text) {\n        <span class=\"hljs-keyword\">return<\/span> embeddingModel.embed(text);\n    }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">In Kombination mit einer Vektor-Datenbank wie Pgvector (PostgreSQL), Redis, Pinecone oder einer der vielen anderen unterst\u00fctzten Datenbanken entsteht eine vollst\u00e4ndige RAG-Pipeline:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">&lt;em&gt;<span class=\"hljs-comment\">\/\/ Dokumente indizieren&lt;\/em&gt;<\/span>\nvektorStore.add(<span class=\"hljs-keyword\">List<\/span>.of(\n    <span class=\"hljs-keyword\">new<\/span> Document(<span class=\"hljs-string\">\"Spring Boot ist ein Framework...\"<\/span>,\n        Map.of(<span class=\"hljs-string\">\"quelle\"<\/span>, <span class=\"hljs-string\">\"docs\"<\/span>))));\n\n&lt;em&gt;<span class=\"hljs-comment\">\/\/ Semantisch suchen&lt;\/em&gt;<\/span>\n<span class=\"hljs-keyword\">List<\/span>&lt;Document&gt; treffer = vektorStore.similaritySearch(\n    SearchRequest.builder()\n        .query(<span class=\"hljs-string\">\"Wie starte ich Spring Boot?\"<\/span>)\n        .topK(<span class=\"hljs-number\">3<\/span>)\n        .build());\n\n&lt;em&gt;<span class=\"hljs-comment\">\/\/ Dem LLM als Kontext mitgeben&lt;\/em&gt;<\/span>\nString prompt = String.format(<span class=\"hljs-string\">\"\"<\/span><span class=\"hljs-string\">\"\n    Beantworte die Frage basierend auf diesen Dokumenten:\n    %s\n    \n    Frage: %s\n    \"<\/span><span class=\"hljs-string\">\"\"<\/span>, treffer, frage);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Noch eleganter geht es mit dem&nbsp;<code>QuestionAnswerAdvisor<\/code>, der RAG direkt in den ChatClient integriert:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">String<\/span> antwort = chatClient.prompt()\n    .advisors(<span class=\"hljs-keyword\">new<\/span> QuestionAnswerAdvisor(vektorStore))\n    .user(<span class=\"hljs-string\">\"Wie starte ich Spring Boot?\"<\/span>)\n    .call()\n    .content();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">So kann das LLM auf unternehmenseigene Dokumente zugreifen, die nie in seinem Trainingsdatensatz waren.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Bild- und Audio-Generierung<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Spring AI abstrahiert auch multimodale Modelle:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">&lt;em&gt;<span class=\"hljs-comment\">\/\/ Bildgenerierung mit DALL-E&lt;\/em&gt;<\/span>\nImageResponse response = imageModel.call(\n    <span class=\"hljs-keyword\">new<\/span> ImagePrompt(<span class=\"hljs-string\">\"Ein roter Vogel auf einem blauen Baum\"<\/span>,\n        OpenAiImageOptions.builder()\n            .quality(<span class=\"hljs-string\">\"hd\"<\/span>)\n            .n(<span class=\"hljs-number\">1<\/span>)\n            .height(<span class=\"hljs-number\">1024<\/span>)\n            .width(<span class=\"hljs-number\">1024<\/span>)\n            .build()));\n\n<span class=\"hljs-built_in\">String<\/span> imageUrl = response.getResult().getOutput().getUrl();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Neben der Bildgenerierung unterst\u00fctzt Spring AI auch Audio-Transkription (Whisper) und Text-to-Speech \u00fcber dieselbe einheitliche API.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Advisors und Chat Memory<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Spring AI 2.0 f\u00fchrt die&nbsp;<strong>Advisors API<\/strong>&nbsp;ein \u2013 ein m\u00e4chtiges Konzept, das wiederkehrende KI-Muster kapselt. Advisors k\u00f6nnen Prompts transformieren, Kontext hinzuf\u00fcgen oder Antworten modifizieren:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">String<\/span> antwort = chatClient.prompt()\n    .advisors(\n        <span class=\"hljs-keyword\">new<\/span> MessageChatMemoryAdvisor(chatMemory),  &lt;em&gt;<span class=\"hljs-comment\">\/\/ Konversationsged\u00e4chtnis&lt;\/em&gt;<\/span>\n        <span class=\"hljs-keyword\">new<\/span> QuestionAnswerAdvisor(vektorStore),     &lt;em&gt;<span class=\"hljs-comment\">\/\/ RAG&lt;\/em&gt;<\/span>\n        <span class=\"hljs-keyword\">new<\/span> SimpleLoggerAdvisor()                   &lt;em&gt;<span class=\"hljs-comment\">\/\/ Logging&lt;\/em&gt;<\/span>\n    )\n    .user(userText)\n    .call()\n    .content();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Mit&nbsp;<code>ChatMemory<\/code>&nbsp;l\u00e4sst sich zustandsbehaftete Konversation umsetzen \u2013 das LLM &#8222;erinnert&#8220; sich an fr\u00fchere Nachrichten:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">ChatMemory chatMemory = MessageWindowChatMemory.builder()\n    .maxMessages(<span class=\"hljs-number\">20<\/span>)\n    .build();\n\n<span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">em<\/span>&gt;<\/span>\/\/ Bei jedem Aufruf die Conversation-ID mitgeben:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">em<\/span>&gt;<\/span><\/span>\n<span class=\"hljs-built_in\">String<\/span> antwort = chatClient.prompt()\n    .advisors(MessageChatMemoryAdvisor.builder(chatMemory).build())\n    .advisors(a -&gt; a.param(ChatMemory.CONVERSATION_ID, sessionId))\n    .user(<span class=\"hljs-string\">\"Mein Name ist Max\"<\/span>)\n    .call()\n    .content();\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code-Sprache:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Model Context Protocol (MCP)<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Eine der wichtigsten Neuerungen in Spring AI 2.0 ist die Unterst\u00fctzung des&nbsp;<strong>Model Context Protocol (MCP)<\/strong>&nbsp;\u2013 ein offener Standard f\u00fcr die Verbindung von KI-Assistenten mit externen Datenquellen und Tools. \u00dcber MCP k\u00f6nnen LLMs dynamisch auf APIs, Datenbanken und andere Ressourcen zugreifen, ohne dass diese fest im Code verdrahtet sein m\u00fcssen.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Fazit<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Spring AI 2.0 katapultiert Java in die KI-Welt, ohne dass Entwickler das Spring-\u00d6kosystem verlassen m\u00fcssen. Die Abstraktion \u00fcber&nbsp;<code>ChatClient<\/code>,&nbsp;<code>EmbeddingModel<\/code>&nbsp;und Tool Calling folgt denselben Mustern wie JPA-Templates oder REST-Clients. Besonders die Kombination aus Advisors, Tool Calling, RAG \u00fcber Vektor-Datenbanken und MCP macht Java-Anwendungen zu ernstzunehmenden KI-Applikationen \u2013 mit Testbarkeit, Konfigurierbarkeit und Produktionstauglichkeit, wie man es von Spring gewohnt ist.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hinweis:&nbsp;Dieser Artikel basiert auf&nbsp;Spring AI 2.0.0&nbsp;(GA), das Spring Boot 4.0.x\/4.1.x voraussetzt. KI ist l\u00e4ngst nicht mehr nur ein Python-Thema. Mit&nbsp;Spring AI&nbsp;bringt das Spring-Team eine offizielle Abstraktionsschicht f\u00fcr Large Language Models (LLMs) und verwandte KI-Dienste in das Java-\u00d6kosystem. Das Ziel: KI-Funktionen mit denselben bekannten Mustern nutzen, die Spring-Entwickler von JPA, REST und Messaging gewohnt sind \u2013 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4,5],"tags":[],"class_list":["post-660","post","type-post","status-publish","format-standard","hentry","category-plain_java","category-spring"],"_links":{"self":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/660","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=660"}],"version-history":[{"count":1,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/660\/revisions"}],"predecessor-version":[{"id":661,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=\/wp\/v2\/posts\/660\/revisions\/661"}],"wp:attachment":[{"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=660"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=660"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.xn--javaeinfacherklrt-4qb.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=660"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}