{"id":274,"date":"2026-05-17T17:28:32","date_gmt":"2026-05-17T15:28:32","guid":{"rendered":"https:\/\/www.coremind.ch\/wordpress\/?p=274"},"modified":"2026-05-17T17:28:32","modified_gmt":"2026-05-17T15:28:32","slug":"ai-task-in-home-assistant-strukturierte-llm-antworten","status":"publish","type":"post","link":"https:\/\/www.coremind.ch\/wordpress\/ai-task-in-home-assistant-strukturierte-llm-antworten\/","title":{"rendered":"AI Task in Home Assistant: strukturierte LLM-Antworten"},"content":{"rendered":"<p>Wer l\u00e4nger mit Home Assistant arbeitet, kennt das Muster: Eine Automation kann <em>etwas ausl\u00f6sen<\/em>, aber nicht <em>etwas entscheiden<\/em>. Sobald eine Nachricht formuliert, eine Bedingung interpretiert oder ein Foto ausgewertet werden soll, h\u00f6rt YAML auf zu helfen. Genau hier setzt das <strong>AI-Task-Framework<\/strong> an, das seit Home Assistant 2025.7 verf\u00fcgbar ist und mit den Releases seither stabilisiert wurde. In meiner Installation l\u00e4uft die Entit\u00e4t <code>ai_task.openai_ai_task_2<\/code> produktiv \u2013 und das ver\u00e4ndert, was eine Automation \u00fcberhaupt sein kann.<\/p>\n<h2>Das Problem: Logik in Templates ist Selbstmord auf Raten<\/h2>\n<p>Fr\u00fchere Versuche, LLM-Antworten in Home Assistant zu nutzen, liefen \u00fcber <code>conversation.process<\/code> plus <code>notify<\/code>. Das funktioniert, aber das Ergebnis ist ein Fliesstext, den die Automation nicht zuverl\u00e4ssig weiterverarbeiten kann. Wer aus dieser Antwort einen booleschen Wert extrahieren wollte \u2013 \u00abSoll der Roborock heute Abend fahren oder nicht?\u00bb \u2013 k\u00e4mpfte mit Regex-Templates, Whitespace und gelegentlichen Halluzinationen.<\/p>\n<p><code>ai_task.generate_data<\/code> l\u00f6st genau dieses Problem. Die Aktion akzeptiert ein <strong>Schema-Argument<\/strong> und zwingt das Modell, eine strukturierte Antwort gem\u00e4ss diesem Schema zu liefern. Aus dem Fliesstext-Generator wird ein deterministischer Datenlieferant.<\/p>\n<h2>Schritt 1: Die Entit\u00e4t als Standard hinterlegen<\/h2>\n<p>In <code>entitaeten.md<\/code> taucht die Entit\u00e4t als <code>ai_task.openai_ai_task_2<\/code> auf, daneben die alte <code>conversation.openai_conversation<\/code>. Beide kommen aus der OpenAI-Integration, erf\u00fcllen aber unterschiedliche Rollen. Unter <em>Einstellungen \u2192 Sprachassistenten \u2192 AI Tasks<\/em> l\u00e4sst sich pro Aufgabentyp (Text, Bild) eine bevorzugte Entit\u00e4t festlegen. Wer das tut, kann die Entit\u00e4ts-ID in jedem <code>action<\/code>-Aufruf weglassen.<\/p>\n<h2>Schritt 2: Eine Automation mit strukturiertem Output<\/h2>\n<p>Ein konkretes Beispiel aus meiner Installation: Eine Morgenroutine fasst um 06:30 Uhr Wetter, Heizungsstatus und anstehende Kalendereintr\u00e4ge zu einer einzigen Ansage zusammen. Die Ansage wird \u00fcber <code>assist_satellite.announce<\/code> auf den <code>home_assistant_voice_0a204b_assist_satellit<\/code> gespielt.<\/p>\n<pre><code class=\"language-yaml\">\nalias: \"Morgen-Briefing\"\ntriggers:\n  - trigger: time\n    at: \"06:30:00\"\nactions:\n  - action: ai_task.generate_data\n    data:\n      task_name: \"morgen_briefing\"\n      instructions: >\n        Fasse die folgenden Daten in einem freundlichen,\n        kurzen Schweizer-Hochdeutsch-Text zusammen (max. 60 W\u00f6rter).\n        Erw\u00e4hne Heiz-COP nur, wenn unter 3.5. Erw\u00e4hne Regen nur,\n        wenn Wahrscheinlichkeit > 50 %.\n      structure:\n        ansage:\n          description: \"Der vorlesefertige Text\"\n          required: true\n          selector:\n            text:\n        ist_kritisch:\n          description: \"true, wenn ein Sensor Warnung liefert\"\n          required: true\n          selector:\n            boolean:\n      attachments:\n        - \"{{ states('weather.home') }}\"\n        - \"{{ states('sensor.cta_cop_aktuell') }}\"\n        - \"{{ state_attr('calendar.familie', 'message') }}\"\n    response_variable: result\n  - action: assist_satellite.announce\n    target:\n      entity_id: assist_satellite.home_assistant_voice_0a204b_assist_satellit\n    data:\n      message: \"{{ result.data.ansage }}\"\n<\/code><\/pre>\n<p>Der entscheidende Block ist <code>structure<\/code>. Er definiert ein Mini-Schema mit zwei Feldern: einer fertigen Ansage und einem booleschen Kritisch-Flag. Der <code>response_variable<\/code>-Mechanismus gibt das Ergebnis als <code>result.data.ansage<\/code> und <code>result.data.ist_kritisch<\/code> weiter \u2013 kein Parsen, kein Fluchen.<\/p>\n<h2>Schritt 3: Bilder analysieren \u2013 mit <code>attachments<\/code><\/h2>\n<p>Die zweite St\u00e4rke von AI Task ist die Bild-Analyse. Die Aktion akzeptiert \u00fcber das <code>attachments<\/code>-Feld Media-Source-IDs, etwa von einer Kamera oder vom Roborock-Snapshot. Damit l\u00e4sst sich eine Frage wie \u00abSteht das Garagentor offen?\u00bb oder \u00abLiegt ein Paket vor der Haust\u00fcre?\u00bb direkt aus der Automation heraus beantworten, ohne den Umweg \u00fcber separate Vision-Services.<\/p>\n<pre><code class=\"language-yaml\">\n- action: ai_task.generate_data\n  data:\n    task_name: \"paket_check\"\n    instructions: \"Ist auf dem Bild ein Paket sichtbar? Antworte strikt boolean.\"\n    structure:\n      paket_gesichtet:\n        required: true\n        selector:\n          boolean:\n    attachments:\n      - media_content_id: \"media-source:\/\/camera\/camera.haustur_snapshot\"\n        media_content_type: \"image\/jpeg\"\n  response_variable: paket\n<\/code><\/pre>\n<h2>Worauf zu achten ist<\/h2>\n<p>Drei Punkte aus drei Monaten Produktivbetrieb. Erstens: <strong>Kostenkontrolle<\/strong>. Jeder Aufruf erzeugt einen API-Call \u2013 wer AI Task in jeder Minuten-Automation aufruft, sieht das auf der Rechnung. Zweitens: <strong>Datenschutz<\/strong>. OpenAI ist der naheliegende Backend, aber wer sensible Kameradaten verarbeitet, sollte den Wechsel auf einen lokalen Backend wie Ollama oder LM Studio pr\u00fcfen; das AI-Task-Interface ist Backend-agnostisch. Drittens: <strong>Schema diszipliniert die Antworten<\/strong> \u2013 aber nicht die Qualit\u00e4t. Wer schlechte Instruktionen schreibt, bekommt deterministisch schlechte Daten zur\u00fcck.<\/p>\n<p>Wer den Voice-Assistant-Teil dieses Setups bereits eingerichtet hat, kennt das Zusammenspiel von <code>assist_satellite<\/code> und Pipeline. Eine zweite, sehr lohnende Erg\u00e4nzung auf der Sensor-Seite ist der mmWave-Sensor, <a href=\"https:\/\/www.coremind.ch\/wordpress\/?p=268\">\u00fcber den ich k\u00fcrzlich im Detail geschrieben habe<\/a>. Zusammen entsteht ein Haus, das <em>sieht<\/em>, <em>zuh\u00f6rt<\/em>, <em>einsch\u00e4tzt<\/em> \u2013 und das alles in lokal kontrollierbaren YAML-Aktionen statt fremder Cloud-Magie.<\/p>\n<p><strong>Quellen:<\/strong> <a href=\"https:\/\/www.home-assistant.io\/integrations\/ai_task\/\">AI Task \u2013 Home Assistant Docs<\/a>, <a href=\"https:\/\/developers.home-assistant.io\/docs\/core\/entity\/ai-task\/\">AI Task Entity \u2013 Developer Docs<\/a>, <a href=\"https:\/\/www.home-assistant.io\/blog\/2025\/09\/11\/ai-in-home-assistant\/\">Building the AI-powered local smart home<\/a>, <a href=\"https:\/\/peyanski.com\/unlock-the-power-of-ai-task-in-home-assistant\/\">Kiril Peyanski: Unlock the Power of AI Task<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wer l\u00e4nger mit Home Assistant arbeitet, kennt das Muster: Eine Automation kann etwas ausl\u00f6sen, aber nicht etwas entscheiden. Sobald eine Nachricht formuliert, eine Bedingung interpretiert oder ein Foto ausgewertet werden soll, h\u00f6rt YAML auf zu helfen. Genau hier setzt das AI-Task-Framework an, das seit Home Assistant 2025.7 verf\u00fcgbar ist und mit den Releases seither stabilisiert &#8230; <a title=\"AI Task in Home Assistant: strukturierte LLM-Antworten\" class=\"read-more\" href=\"https:\/\/www.coremind.ch\/wordpress\/ai-task-in-home-assistant-strukturierte-llm-antworten\/\" aria-label=\"Mehr Informationen \u00fcber AI Task in Home Assistant: strukturierte LLM-Antworten\">Weiterlesen<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-274","post","type-post","status-publish","format-standard","hentry","category-allgemein"],"_links":{"self":[{"href":"https:\/\/www.coremind.ch\/wordpress\/wp-json\/wp\/v2\/posts\/274","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.coremind.ch\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.coremind.ch\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.coremind.ch\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.coremind.ch\/wordpress\/wp-json\/wp\/v2\/comments?post=274"}],"version-history":[{"count":1,"href":"https:\/\/www.coremind.ch\/wordpress\/wp-json\/wp\/v2\/posts\/274\/revisions"}],"predecessor-version":[{"id":276,"href":"https:\/\/www.coremind.ch\/wordpress\/wp-json\/wp\/v2\/posts\/274\/revisions\/276"}],"wp:attachment":[{"href":"https:\/\/www.coremind.ch\/wordpress\/wp-json\/wp\/v2\/media?parent=274"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.coremind.ch\/wordpress\/wp-json\/wp\/v2\/categories?post=274"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.coremind.ch\/wordpress\/wp-json\/wp\/v2\/tags?post=274"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}