# Local Model Service Protocol (LMSP) 1.0, Entwurf > Made for Agent veröffentlicht offene, maschinenlesbare Protokolle, mit denen KI-Agenten, Modelle und Werkzeuge einander finden und miteinander kommunizieren können. Den Anfang macht LMSP, das Local Model Service Protocol. Source: https://madeforagent.com/de/llms-full.txt Updated: 2026-11-08 --- # Protokoll für lokale Modelldienste (LMSP) > LMSP ist ein offenes Protokoll zum Finden und Aufrufen von Sprachmodellen auf Ihrem Gerät. Es definiert Diensterkennung, Modellkatalog, Streaming, persistente Aufgaben und OpenAI-Kompatibilität. Source: https://madeforagent.com/de/lmsp/ Language: de Updated: 2026-11-08 ## Was LMSP leistet {#what} LMSP (Local Model Service Protocol) ist ein offenes Protokoll für Software, die Sprachmodelle auf dem eigenen Gerät oder im lokalen Netzwerk des Nutzers ausführt, und für die Clients, die diese Software verwenden. Ein dauerhaft laufender lokaler Dienst beschreibt sich unter einer wohlbekannten Adresse selbst und listet seine Modelle auf. Er beantwortet Generierungsanfragen mit JSON oder mit Server-Sent Events und führt lange Generierungen als persistente Aufgaben aus, die sich abbrechen und nach einem Verbindungsabbruch erneut verfolgen lassen. Derselbe Dienst spricht außerdem die OpenAI-API, sodass die heute vorhandenen Clients weiter funktionieren. LMSP ersetzt weder die OpenAI-API noch Ollama oder MCP. Es vereint ihre Stärken in einer Protokollschicht, die für dauerhaft laufende lokale Dienste gebaut ist. ## Auf einen Blick {#glance} | Thema | Zusammenfassung | | --- | --- | | Standardadresse | `http://127.0.0.1:17832` | | Dienstbeschreibung | `GET /.well-known/lmsp.json` | | Kernschnittstelle | `/lmsp/v1`, JSON über HTTP, Streaming mit Server-Sent Events | | Kompatibilitätsschnittstellen | `/v1` für OpenAI-Clients, optional `/api` für Ollama-Clients | | Erkennung | Manuelle Adresse, Prüfen lokaler Adressen, optional mDNS und DNS-SD (`_lmsp._tcp.local.`) | | Authentifizierung | Bearer-Tokens aus einer lokalen Kopplung | | Persistenz | Eingebettetes SQLite, mit Aufgaben, die einen Neustart überstehen | | Vertrag | OpenAPI 3.2 | ## Ausprobieren {#try} Läuft auf Ihrem Rechner ein LMSP-Dienst, ist das der gesamte Ablauf. Koppeln Sie sich zuerst, um ein Token zu erhalten, wie in [Abschnitt 10.2](https://madeforagent.com/de/lmsp/1.0/security.md#pairing) beschrieben, und legen Sie es in `LMSP_TOKEN` ab. ```sh # 1. Den Dienst erkennen curl http://127.0.0.1:17832/.well-known/lmsp.json # 2. Die lokalen Modelle auflisten curl http://127.0.0.1:17832/lmsp/v1/models \ -H "Authorization: Bearer $LMSP_TOKEN" # 3. Eine Antwort generieren curl http://127.0.0.1:17832/lmsp/v1/responses \ -H "Authorization: Bearer $LMSP_TOKEN" \ -H "Content-Type: application/json" \ -d '{"model":"qwen3:14b-q4_k_m","input":[{"type":"message","role":"user","content":[{"type":"input_text","text":"Hello"}]}]}' ``` ## Wie LMSP zu anderen Protokollen steht {#related} | Protokoll | Was es abdeckt | Verhältnis zu LMSP | | --- | --- | --- | | OpenAI-API | Gehostete Modelle. Die Responses-API ist ihre neueste Schnittstelle. | LMSP folgt für seine Kernschnittstelle der Responses-Struktur, und ein Dienst bietet daneben eine OpenAI-kompatible Schnittstelle an. | | Ollama | Eine lokale Laufzeitumgebung, die bereits OpenAI-kompatible Endpunkte bereitstellt. | Sie kann als Adapter hinter einem LMSP-Dienst sitzen, und LMSP definiert optionale Ollama-kompatible Endpunkte. | | MCP | Verbindet Agenten mit Tools und Kontext. | LMSP verbindet Agenten mit Modellen. Beide bevorzugen zustandslose Erkennung statt verpflichtender Sitzungen. | | A2A | Zusammenarbeit zwischen Agenten. | LMSP übernimmt Service Cards und explizite Aufgabenzustände für seine Dienstbeschreibung und seine Aufgaben. | ## Ressourcen {#resources} - Die [Spezifikation, Version 1.0 (Entwurf)](https://madeforagent.com/de/lmsp/1.0.md). - Der OpenAPI-Vertrag, als [JSON](https://madeforagent.com/lmsp/1.0/openapi.json) oder [YAML](https://madeforagent.com/lmsp/1.0/openapi.yaml). - [llms.txt](https://madeforagent.com/de/llms.txt) und [llms-full.txt](https://madeforagent.com/de/llms-full.txt), für Sprachmodelle. - Jede Seite ist als Markdown verfügbar. Ersetzen Sie den abschließenden Schrägstrich ihrer Adresse durch `.md`, zum Beispiel [`/de/lmsp/1.0/tasks.md`](https://madeforagent.com/de/lmsp/1.0/tasks.md). ## Häufig gestellte Fragen ### Was ist LMSP? LMSP, das Local Model Service Protocol, ist ein offenes Protokoll für Sprachmodell-Dienste, die auf dem eigenen Gerät oder im lokalen Netzwerk des Nutzers laufen. Es legt fest, wie Clients einen Dienst finden, seine Modelle auflisten, Antworten anfordern, Ausgaben streamen und lange Aufgaben ausführen. ### Ersetzt LMSP die OpenAI-API, Ollama oder MCP? Nein. LMSP baut auf ihnen auf. Die Kernschnittstelle folgt der Struktur von OpenAI Responses, ein Dienst kann OpenAI-kompatible und Ollama-kompatible Endpunkte anbieten, und das Protokoll übernimmt von MCP die zustandslose Erkennung und von A2A die Aufgabenzustände. ### Können bestehende OpenAI-Clients einen LMSP-Dienst nutzen? In der Regel ja. Sie brauchen eine andere Basis-URL und das LMSP-Token als API-Schlüssel. Den Dienst finden sie nicht automatisch, denn die Erkennung setzt einen Client voraus, der LMSP unterstützt. ### Wie findet ein Client einen lokalen LMSP-Dienst? Er probiert drei Dinge nacheinander aus. Zuerst eine von Hand eingegebene Adresse, dann die übliche lokale Adresse, unter der er /.well-known/lmsp.json abruft, und zuletzt optional die mDNS- und DNS-SD-Suche nach _lmsp._tcp.local. im lokalen Netzwerk. ### Ist ein Modelldienst auf localhost sicher? Nicht automatisch, denn Webseiten können versuchen, lokale Ports zu erreichen. LMSP-Dienste binden sich standardmäßig an Loopback, verlangen Bearer-Tokens aus einer lokalen Kopplung, prüfen die Header Origin und Host und verlangen im LAN-Modus eine Authentifizierung. ### In welchem Zustand ist die Spezifikation? Version 1.0 ist ein erster öffentlicher Entwurf und kann sich noch inkompatibel ändern. Der englische Text ist maßgeblich, Übersetzungen dienen der Bequemlichkeit. --- # Überblick > Überblick über den Entwurf von LMSP 1.0. Was das Local Model Service Protocol ist, auf welchen Entwürfen es aufbaut, seine Schichtenarchitektur, wie die Spezifikation zu lesen ist und welche Begriffe durchgehend gelten. Source: https://madeforagent.com/de/lmsp/1.0/ Language: de Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 1.1 Zusammenfassung {#abstract} Das Local Model Service Protocol (LMSP) legt fest, wie Clients Sprachmodell-Dienste finden und nutzen, die auf dem eigenen Gerät oder im lokalen Netzwerk des Nutzers laufen. Es spezifiziert die Diensterkennung, einen Modellkatalog, synchrone und gestreamte Generierung sowie asynchrone Aufgaben, die Neustarts überstehen. Außerdem legt es fest, wie ein Dienst neben der LMSP-Schnittstelle eine OpenAI-kompatible Schnittstelle anbietet, damit bestehende Clients weiter funktionieren. LMSP ersetzt weder die OpenAI-API noch Ollama oder MCP. Es vereint ihre Stärken in einer Protokollschicht, die für einen dauerhaft laufenden lokalen Dienst gebaut ist. ## 1.2 Status dieses Dokuments {#status} Dies ist der erste öffentliche Entwurf von LMSP 1.0, veröffentlicht am 2026-11-08. „LMSP“ ist ein Arbeitsname. Der Text ist offen für Rückmeldungen und kann sich bis zur Fertigstellung von 1.0 inkompatibel ändern. Der englische Text ist maßgeblich. Übersetzungen dienen der Bequemlichkeit; bei Abweichungen gilt der englische Text. ## 1.3 Entwurfsgrundlage {#design-basis} LMSP greift auf bewährte Entwürfe zurück, statt neue zu erfinden: - **OpenAI Responses API.** Strukturierte Ausgabeelemente, semantische Server-Sent Events und Hintergrundausführung mit Abfrage und Abbruch für lang laufende Arbeit. Sie ist die Referenz für die zentrale Konversationsschnittstelle von LMSP. Siehe [gestreamte Antworten](https://developers.openai.com/api/docs/guides/streaming-responses) und [Hintergrundmodus](https://developers.openai.com/api/docs/guides/background). - **Ollama.** Es stellt die OpenAI-kompatiblen Endpunkte `/v1/models`, `/v1/chat/completions` und `/v1/responses` bereit, was zeigt, dass ein Dienst plus eine OpenAI-Anpassungsschicht die Einführungskosten drastisch senkt. Siehe [Ollamas OpenAI-Kompatibilität](https://docs.ollama.com/api/openai-compatibility). - **Model Context Protocol (MCP).** Sein neuestes Design geht von der verpflichtenden Sitzungsinitialisierung zur zustandslosen Erkennung über: Jede Anfrage trägt ihre eigenen Versionsangaben, und Clients erfahren die Fähigkeiten über eine Erkennungsschnittstelle. Das passt zu lokalen Diensten, bei denen Neustarts, Client-Abstürze und abgebrochene Verbindungen den Protokollzustand nicht beschädigen dürfen. Siehe [MCP](https://modelcontextprotocol.io/). - **Agent2Agent (A2A).** Service Cards, explizite Aufgabenzustände, Aufgabenabonnements und Abbruch haben die Dienstbeschreibung und das asynchrone Aufgabenmodell von LMSP geprägt. Siehe [A2A](https://a2a-protocol.org/). ## 1.4 Architektur {#architecture} LMSP ist in drei Schichten organisiert, oberhalb der Adapter, die mit den Modell-Laufzeitumgebungen sprechen: ```text +---------------------------------------------------------------+ | Discovery mDNS / DNS-SD + well-known service document | +---------------------------------------------------------------+ | Core model catalog, responses, SSE, async tasks | +---------------------------------------------------------------+ | Compatibility OpenAI API, optional Ollama API | +---------------------------------------------------------------+ | Adapters llama.cpp, Ollama, vLLM, custom runtimes | +---------------------------------------------------------------+ ``` - **Erkennung.** mDNS/DNS-SD und ein Dokument mit der Dienstbeschreibung unter einer wohlbekannten Adresse ([Seite 3](https://madeforagent.com/de/lmsp/1.0/discovery.md)). - **Kern.** Der Modellkatalog, synchrone Antworten, Server-Sent Events und asynchrone Aufgaben ([Seiten 5 bis 7](https://madeforagent.com/de/lmsp/1.0/models.md)). - **Kompatibilität.** Eine OpenAI-kompatible API und optional eine Ollama-kompatible API ([Seite 8](https://madeforagent.com/de/lmsp/1.0/compatibility.md)). - **Adapter.** Brücken zu llama.cpp, Ollama, vLLM oder einer eigenen Laufzeitumgebung. Das Leitprinzip lautet **ein Modell-Ausführungskern, zwei Schnittstellenfamilien**. Ein Dienst bietet die LMSP-Schnittstelle und die OpenAI-Schnittstelle über demselben Kern an, sodass es genau eine Stelle gibt, an der Modelle geladen, Anfragen ausgeführt und Aufgaben verfolgt werden. ## 1.5 Konformitätssprache {#conformance} Die Schlüsselwörter **MUSS/MÜSSEN** (MUST), **DARF NICHT/DÜRFEN NICHT** (MUST NOT), **ERFORDERLICH** (REQUIRED), **SOLLTE/SOLLTEN** (SHOULD), **SOLLTE NICHT/SOLLTEN NICHT** (SHOULD NOT), **EMPFOHLEN** (RECOMMENDED), **KANN/KÖNNEN** (MAY) und **OPTIONAL** (OPTIONAL) sind in diesem Dokument wie in [BCP 14](https://www.rfc-editor.org/info/bcp14) ([RFC 2119](https://www.rfc-editor.org/rfc/rfc2119), [RFC 8174](https://www.rfc-editor.org/rfc/rfc8174)) beschrieben zu interpretieren, wenn und nur wenn sie fett und in Großbuchstaben erscheinen. Andernfalls sind es gewöhnliche Wörter. Jede Seite ist als normativ oder informativ gekennzeichnet. Normative Seiten legen Anforderungen fest; informative Seiten geben Hinweise. Beispiele sind informativ. JSON ist UTF-8, und Feldnamen verwenden `snake_case`. ## 1.6 Terminologie {#terminology} | Begriff | Bedeutung | | --- | --- | | Dienst | Ein dauerhaft laufender Prozess, der LMSP implementiert und Modelle über Adapter ausführt. | | Client | Software, die einen Dienst findet und aufruft: ein Agent, eine Anwendung oder ein Tool. | | Adapter | Die Komponente, die den Dienst mit genau einer Modell-Laufzeitumgebung wie llama.cpp, Ollama oder vLLM verbindet. | | Modell | Ein lokal verfügbares Modell, identifiziert durch eine stabile `id`. | | Antwort | Das Ergebnis einer Generierungsanfrage: Ausgabeelemente, Nutzung und ein Status. | | Aufgabe | Eine persistierte, asynchrone Ausführung einer Antwortanfrage mit explizitem Zustand. | | Ereignis | Ein Server-Sent Event mit Sequenznummer, das während der Generierung einer Antwort ausgesendet wird. | --- # Transport und Betrieb > Standard-Lauschadressen, Transport, Streaming-Format und URL-Aufbau eines LMSP-Dienstes sowie sein Betrieb als Betriebssystemdienst, getrennt von den Modellprozessen. Source: https://madeforagent.com/de/lmsp/1.0/transport/ Language: de Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 2.1 Standardbetrieb {#deployment} Ein Dienst **MUSS** standardmäßig auf den Loopback-Adressen `127.0.0.1` und `::1` lauschen. Der übliche Port ist `17832`, wodurch die Standard-Basisadresse `http://127.0.0.1:17832` lautet. | Eintrag | Wert | | --- | --- | | Lauschadressen | `127.0.0.1` und `::1` | | Transport | HTTP/1.1 oder HTTP/2 mit JSON | | Streaming | Server-Sent Events, `Content-Type: text/event-stream` | | Präfix der Kernschnittstelle | `/lmsp/v1` | | OpenAI-kompatibles Präfix | `/v1` | | Dienstbeschreibung | `GET /.well-known/lmsp.json` | | Maschinenlesbarer Vertrag | `GET /lmsp/v1/openapi.json` | | Optionaler lokaler Kanal | Unix-Domain-Socket oder Windows Named Pipe | Anfragen und Antworten verwenden JSON in UTF-8 (`Content-Type: application/json`), außer Streams (`text/event-stream`) und Fehlern (`application/problem+json`). Zeitstempel sind ganze Zahlen: Sekunden seit der Unix-Epoche. Bezeichner sind opake Zeichenfolgen; ein Typpräfix wie `resp_` oder `task_` ist **EMPFOHLEN**. Der Schnittstellenvertrag ist ein OpenAPI-3.2-Dokument. OpenAPI 3.2 kann Server-Sent Events, JSON Lines und JSON Sequences beschreiben, sodass die Streaming-Endpunkte im selben Dokument wie alles andere spezifiziert werden. Der Vertrag für diese Version ist unter [`/lmsp/1.0/openapi.json`](https://madeforagent.com/lmsp/1.0/openapi.json) veröffentlicht. Ein Dienst **KANN** außerdem Verbindungen über einen Unix-Domain-Socket oder eine Windows Named Pipe mit derselben HTTP-Semantik annehmen. In 1.0 bleibt es Erweiterungen überlassen, wie solche Endpunkte bekannt gemacht werden. ## 2.2 Dauerbetrieb {#operation} Ein Dienst **SOLLTE** vom Betriebssystem gehostet werden: launchd unter macOS, systemd unter Linux und der Windows-Dienstmanager unter Windows. Der Dienstprozess und die Modellprozesse **SOLLTEN** getrennt sein. Ein Modellabsturz **SOLLTE** nur die Aufgaben betreffen, die dieses Modell verwenden. Er **SOLLTE NICHT** die Diensterkennung, den Modellkatalog oder Abfragen zu früheren Aufgaben unverfügbar machen. --- # Diensterkennung > Wie LMSP-Clients einen lokalen Dienst per manueller Konfiguration, Loopback-Prüfung und optionalem mDNS/DNS-SD finden und wie das Dokument mit der Dienstbeschreibung unter der wohlbekannten Adresse zu lesen ist. Source: https://madeforagent.com/de/lmsp/1.0/discovery/ Language: de Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 3.1 Erkennungsmethoden {#methods} Ein Client erkennt einen Dienst, indem er diese Methoden der Reihe nach versucht: 1. **Manuelle Konfiguration.** Der Nutzer gibt die Adresse des Dienstes direkt ein. 2. **Prüfen üblicher lokaler Adressen.** Der Client ruft `/.well-known/lmsp.json` von Kandidatenadressen ab. Die üblichen Kandidaten sind `http://127.0.0.1:17832` und `http://[::1]:17832`. 3. **LAN-Erkennung.** Der Client sucht mit mDNS und DNS-SD nach `_lmsp._tcp.local.`. Eine Methode ist erfolgreich, wenn sie eine gültige Dienstbeschreibung liefert ([Abschnitt 3.3](https://madeforagent.com/de/lmsp/1.0/discovery.md#service-description)). Eine vom Nutzer manuell eingegebene Adresse hat immer Vorrang vor gefundenen. ## 3.2 LAN-Ankündigung {#mdns} DNS-SD nutzt PTR-Einträge, um Dienstinstanzen zu finden, SRV-Einträge, um Host und Port zu erhalten, und TXT-Einträge, um eine kleine Menge zusätzlicher Informationen zu transportieren. Zusammen mit mDNS ermöglicht es die konfigurationsfreie Erkennung in einem lokalen Netzwerk ([RFC 6763](https://www.rfc-editor.org/rfc/rfc6763), [RFC 6762](https://www.rfc-editor.org/rfc/rfc6762)). Ein Beispiel für eine Ankündigung: ```text Service type: _lmsp._tcp.local. Instance name: Workstation LMSP._lmsp._tcp.local. TXT record: v=1 id=svc_01J8M4Y8K6M5E6K6Z7Z0Y8W3M2 path=/ auth=pairing ``` | TXT-Schlüssel | Bedeutung | | --- | --- | | `v` | Version des Ankündigungsformats. `1` für LMSP 1.0. | | `id` | Die Dienst-ID, gleich `service.id` in der Dienstbeschreibung. | | `path` | URL-Pfad der Dienstwurzel. Clients rufen `{path}.well-known/lmsp.json` ab. | | `auth` | Hinweis zur Authentifizierung. `pairing` bedeutet, dass sich ein Client koppeln muss, bevor er den Dienst nutzt. | Regeln: - Ein Dienst **DARF NICHT** Zugriffstokens, Modelllisten, Dateipfade oder andere sensible Informationen in den TXT-Eintrag schreiben. Der Eintrag lokalisiert den Dienst nur. Die tatsächlichen Fähigkeiten **MÜSSEN** aus der Dienstbeschreibung gelesen werden. - Ein Dienst **MUSS** die mDNS-Ankündigung standardmäßig deaktiviert lassen. Sie wird nur aktiviert, wenn der Nutzer die LAN-Erkennung ausdrücklich einschaltet. Ein Dienst, der nur auf dem lokalen Rechner genutzt wird, kündigt sich nicht an. - Ein Dienst, der sich im LAN ankündigt, muss über Loopback hinaus lauschen, was nur im LAN-Modus erlaubt ist ([Abschnitt 10.5](https://madeforagent.com/de/lmsp/1.0/security.md#lan)). - Ein Client **MUSS** den TXT-Eintrag als ungeprüften Hinweis behandeln und den Dienst bestätigen, indem er seine Beschreibung liest. ## 3.3 Dienstbeschreibung {#service-description} ```http GET /.well-known/lmsp.json ``` Ein Dienst **MUSS** dieses Dokument als `application/json` ausliefern, ohne eine Authentifizierung zu verlangen. ```json { "protocol": "lmsp", "versions": ["1.0"], "service": { "id": "svc_01J8M4Y8K6M5E6K6Z7Z0Y8W3M2", "name": "Workstation Local Models", "version": "1.0.0" }, "interfaces": [ { "kind": "lmsp", "version": "1.0", "url": "http://127.0.0.1:17832/lmsp/v1", "transport": "http+json" }, { "kind": "openai", "version": "responses+chat", "url": "http://127.0.0.1:17832/v1", "transport": "http+json" } ], "capabilities": { "streaming": true, "tasks": true, "event_resume": true, "conversations": true, "model_management": true }, "authentication": { "type": "bearer", "pairing_url": "http://127.0.0.1:17832/lmsp/v1/pair" }, "openapi": "http://127.0.0.1:17832/lmsp/v1/openapi.json" } ``` | Feld | Bedeutung | | --- | --- | | `protocol` | Immer `"lmsp"`. | | `versions` | Die vom Dienst unterstützten LMSP-Versionen als `major.minor`-Zeichenfolgen. | | `service` | `id` ist eine stabile Dienstkennung, `name` ein Anzeigename und `version` die Version der Dienstsoftware. | | `interfaces` | Die angebotenen Schnittstellen. Jede hat ein `kind` (`lmsp`, `openai` oder `ollama`), eine `version`, eine Basis-`url` und einen `transport`. Bei `openai` nennt `version` die bereitgestellten API-Familien, etwa `responses+chat`. | | `capabilities` | Boolesche Funktionsschalter, unten aufgeführt. | | `authentication` | `type` ist `bearer`. `pairing_url` ist die Adresse, unter der Clients einen Kopplungscode gegen ein Token eintauschen ([Abschnitt 10.2](https://madeforagent.com/de/lmsp/1.0/security.md#pairing)). | | `openapi` | URL des OpenAPI-Dokuments, das die LMSP-Schnittstelle beschreibt. | Capability-Schalter: | Schalter | Bedeutung | | --- | --- | | `streaming` | Antworten können als Server-Sent Events gestreamt werden. **MUSS** in 1.0 `true` sein. | | `tasks` | Asynchrone Aufgaben sind verfügbar. **MUSS** in 1.0 `true` sein. | | `event_resume` | Ereignisströme von Aufgaben können abonniert und fortgesetzt werden (`GET /lmsp/v1/tasks/{task_id}/events`). | | `conversations` | Der Dienst speichert Antworten, sodass `store` und `previous_response_id` funktionieren und `GET /lmsp/v1/responses/{response_id}` verfügbar ist. | | `model_management` | Modelle können explizit geladen und entladen werden. | ## 3.4 Verhalten des Clients {#client-behavior} Ein Client: - **SOLLTE** die höchste Version aus `versions` wählen, die er ebenfalls unterstützt. - **SOLLTE** aus `interfaces` die LMSP- oder die OpenAI-Schnittstelle wählen, je nachdem, was er sprechen kann. - **MUSS** nur die Fähigkeiten verwenden, die die Beschreibung deklariert. Ein fehlender Schalter bedeutet `false`. - **MUSS** Erweiterungsfelder ignorieren, die er nicht kennt. - **SOLLTE** die Dienstbeschreibung regelmäßig und bei einer fehlgeschlagenen Anfrage erneut lesen, statt sie ewig zwischenzuspeichern. - **SOLLTE** sich einen gewählten Dienst anhand von `service.id` merken und nicht anhand seiner Adresse, weil sich Adressen ändern können. --- # Endpunkte > Die vollständige Tabelle der Endpunkte von LMSP 1.0 mit Methode, Pfad, Verbindlichkeit und Zweck sowie die Konventionen für Pfade, Authentifizierung und optionale Endpunkte. Source: https://madeforagent.com/de/lmsp/1.0/endpoints/ Language: de Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 4.1 Endpunkt-Tabelle {#table} Ein konformer Dienst **MUSS** jeden als erforderlich markierten Endpunkt implementieren. Er **KANN** die optionalen implementieren und zeigt sie über die Capability-Schalter seiner [Dienstbeschreibung](https://madeforagent.com/de/lmsp/1.0/discovery.md#service-description) an. | Methode | Pfad | Verbindlichkeit | Zweck | | --- | --- | --- | --- | | GET | `/.well-known/lmsp.json` | Erforderlich | [Erkennung von Dienst und Fähigkeiten](https://madeforagent.com/de/lmsp/1.0/discovery.md#service-description) | | GET | `/lmsp/v1/openapi.json` | Erforderlich | Maschinenlesbare Schnittstellenspezifikation | | GET | `/lmsp/v1/health` | Erforderlich | [Liveness- und Readiness-Prüfung](https://madeforagent.com/de/lmsp/1.0/common-rules.md#health) | | POST | `/lmsp/v1/pair` | Erforderlich | [Kopplungscode gegen ein Bearer-Token eintauschen](https://madeforagent.com/de/lmsp/1.0/security.md#pairing) | | GET | `/lmsp/v1/models` | Erforderlich | [Lokale Modelle auflisten](https://madeforagent.com/de/lmsp/1.0/models.md#list) | | GET | `/lmsp/v1/models/{model_id}` | Erforderlich | [Ein Modell abrufen](https://madeforagent.com/de/lmsp/1.0/models.md#operations) | | POST | `/lmsp/v1/responses` | Erforderlich | [Synchrone oder gestreamte Generierung](https://madeforagent.com/de/lmsp/1.0/responses.md#request) | | GET | `/lmsp/v1/responses/{response_id}` | Optional | [Eine gespeicherte Antwort abrufen](https://madeforagent.com/de/lmsp/1.0/responses.md#sync) | | POST | `/lmsp/v1/tasks` | Erforderlich | [Eine asynchrone Generierungsaufgabe erstellen](https://madeforagent.com/de/lmsp/1.0/tasks.md#create) | | GET | `/lmsp/v1/tasks/{task_id}` | Erforderlich | [Eine asynchrone Aufgabe abrufen](https://madeforagent.com/de/lmsp/1.0/tasks.md#create) | | POST | `/lmsp/v1/tasks/{task_id}/cancel` | Erforderlich | [Eine asynchrone Aufgabe abbrechen](https://madeforagent.com/de/lmsp/1.0/tasks.md#cancel) | | GET | `/lmsp/v1/tasks/{task_id}/events` | Optional | [Den Ereignisstrom abonnieren oder fortsetzen](https://madeforagent.com/de/lmsp/1.0/tasks.md#events) | | POST | `/lmsp/v1/models/{model_id}/load` | Optional | [Ein Modell vorab laden](https://madeforagent.com/de/lmsp/1.0/models.md#operations) | | POST | `/lmsp/v1/models/{model_id}/unload` | Optional | [Ein Modell entladen](https://madeforagent.com/de/lmsp/1.0/models.md#operations) | Die OpenAI-kompatiblen Endpunkte unter `/v1` und die optionalen Ollama-kompatiblen Endpunkte sind auf [Seite 8](https://madeforagent.com/de/lmsp/1.0/compatibility.md) aufgeführt. ## 4.2 Konventionen {#conventions} - **Bodys.** Anfrage- und Antwort-Bodys sind JSON (`application/json`), außer Ereignisströmen (`text/event-stream`) und Fehlern (`application/problem+json`). - **Pfadparameter.** Ein Name in geschweiften Klammern, etwa `{model_id}`, ist ein Platzhalter. Werte **MÜSSEN** prozentcodiert werden. Eine Modell-ID wie `qwen3:14b-q4_k_m` wird als `qwen3%3A14b-q4_k_m` gesendet. - **Authentifizierung.** Jeder Endpunkt verlangt `Authorization: Bearer `, außer `/.well-known/lmsp.json`, `/lmsp/v1/openapi.json`, `/lmsp/v1/health` und `/lmsp/v1/pair`. - **Optionale Endpunkte.** Ein optionaler Endpunkt, den der Dienst nicht implementiert, **MUSS** mit `501 Not Implemented` und dem Fehlercode `unsupported_capability` antworten. - **Versionen und Fehler.** Anfragen können Versions-Header tragen, und jeder Fehler verwendet ein einheitliches Format. Beides ist auf [Seite 9](https://madeforagent.com/de/lmsp/1.0/common-rules.md) definiert. - **Vertrag.** Das unter [`/lmsp/1.0/openapi.json`](https://madeforagent.com/lmsp/1.0/openapi.json) veröffentlichte OpenAPI-Dokument ist die maschinenlesbare Form dieser Seite. Wo beide voneinander abweichen, ist der Text maßgeblich. --- # Modellkatalog > Wie ein LMSP-Dienst seine lokalen Modelle auflistet, das Modellobjekt und seine Capability-Schalter, die Zustände des Modell-Lebenszyklus, stabile Modell-IDs und Katalogrevisionen. Source: https://madeforagent.com/de/lmsp/1.0/models/ Language: de Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 5.1 Modelle auflisten {#list} ```http GET /lmsp/v1/models?capability=chat&ready_only=false Authorization: Bearer ``` | Abfrageparameter | Bedeutung | | --- | --- | | `capability` | Gibt nur Modelle zurück, die die genannte Fähigkeit haben, zum Beispiel `chat`, `embeddings` oder `tools`. | | `ready_only` | Bei `true` werden nur Modelle zurückgegeben, deren `status` `ready` ist. Standardwert ist `false`. | ```json { "object": "list", "catalog_revision": "42", "data": [ { "id": "qwen3:14b-q4_k_m", "object": "model", "display_name": "Qwen3 14B Q4_K_M", "owned_by": "local", "family": "qwen3", "revision": "sha256:8f27c1a4e9b05d36f2a7c8e1b4d90a63c5e2f7b8a1d4c9e60b3f5a7d2c8e1b04", "status": "ready", "capabilities": { "chat": true, "completion": true, "embeddings": false, "tools": true, "vision": false, "structured_output": true, "streaming": true }, "input_modalities": ["text"], "output_modalities": ["text"], "context_window": 32768, "max_output_tokens": 8192, "runtime": { "backend": "llama.cpp", "device": "metal", "load_on_demand": true } } ] } ``` Damit Clients nicht immer wieder den vollständigen Katalog abrufen müssen, **SOLLTE** ein Dienst einen `ETag`-Header, ein Feld `catalog_revision` oder beides zurückgeben: - `catalog_revision` ist eine opake Zeichenfolge, die sich ändert, sobald sich der Katalog ändert. - Ein Dienst, der `ETag` sendet, **SOLLTE** auf ein passendes `If-None-Match` mit `304 Not Modified` antworten. ## 5.2 Modellobjekt {#object} | Feld | Bedeutung | | --- | --- | | `id` | Stabile Modellkennung, die in jeder Anfrage verwendet wird, die ein Modell benennt. | | `object` | Immer `"model"`. | | `display_name` | Menschenlesbarer Name. Der Nutzer kann ihn ändern. | | `aliases` | Optionale Liste alternativer Namen. Sie sind rein informativ. | | `owned_by` | Woher das Modell stammt. `local` für auf diesem Gerät installierte Modelle. | | `family` | Modellfamilie, etwa `qwen3`. | | `revision` | Digest des Modellinhalts, etwa `sha256:8f27...`. | | `status` | Lebenszyklus-Zustand ([Abschnitt 5.3](https://madeforagent.com/de/lmsp/1.0/models.md#lifecycle)). | | `capabilities` | Boolesche Schalter: `chat`, `completion`, `embeddings`, `tools`, `vision`, `structured_output` und `streaming`. | | `input_modalities`, `output_modalities` | Die Arten von Inhalt, die das Modell liest und schreibt. `text` ist die einzige in 1.0 definierte Modalität. | | `context_window` | Maximale Anzahl an Kontext-Tokens. | | `max_output_tokens` | Maximale Anzahl an Tokens in einer Antwort. | | `runtime` | `backend` (zum Beispiel `llama.cpp`), `device` (zum Beispiel `metal`) und `load_on_demand`. | | `error` | Vorhanden, wenn `status` `error` ist. Ein Problemobjekt ([Abschnitt 9.3](https://madeforagent.com/de/lmsp/1.0/common-rules.md#errors)). | Die `id` eines Modells **MUSS** stabil sein. Anzeigename und Aliase kann der Nutzer ändern; sie **DÜRFEN NICHT** als Primärschlüssel verwendet werden. ## 5.3 Modell-Lebenszyklus {#lifecycle} ```text installed --> loading --> ready --> unloading --> installed | +-----> error ``` | Status | Bedeutung | | --- | --- | | `installed` | Das Modell existiert, ist aber nicht geladen. | | `loading` | Speicher wird zugewiesen oder die Laufzeitumgebung wird initialisiert. | | `ready` | Das Modell kann Anfragen sofort verarbeiten. | | `unloading` | Ressourcen werden freigegeben. | | `error` | Das Laden ist fehlgeschlagen. Das Modellobjekt **SOLLTE** einen strukturierten Fehler enthalten. | Eine neue Ladeanfrage versetzt ein Modell im Zustand `error` zurück nach `loading`. Benennt eine Anfrage ein Modell, das `installed` ist und dessen `runtime.load_on_demand` `true` ist, lädt der Dienst es im Rahmen der Anfrage. Kann das Modell nicht sofort verwendet werden und wird nicht bei Bedarf geladen, antwortet der Dienst mit `409` und `model_not_ready`. Schlägt das Laden fehl, lautet der Fehler `model_load_failed`. ## 5.4 Modelloperationen {#operations} `GET /lmsp/v1/models/{model_id}` gibt ein Modellobjekt zurück. Eine unbekannte ID ergibt `404` mit `model_not_found`. Zwei optionale Endpunkte steuern das Laden explizit. Sie sind verfügbar, wenn die Fähigkeit `model_management` `true` ist, und erfordern den Scope `models:manage` ([Abschnitt 10.3](https://madeforagent.com/de/lmsp/1.0/security.md#scopes)): | Endpunkt | Verhalten | | --- | --- | | `POST /lmsp/v1/models/{model_id}/load` | Lädt das Modell vorab. Gibt das Modellobjekt mit `202 Accepted` zurück, wenn das Laden begonnen hat, oder mit `200`, wenn es bereits `ready` ist. | | `POST /lmsp/v1/models/{model_id}/unload` | Entlädt das Modell. Gibt das Modellobjekt zurück. Die Wiederholung der Anfrage ist harmlos. | Beide akzeptieren einen `Idempotency-Key` ([Abschnitt 9.2](https://madeforagent.com/de/lmsp/1.0/common-rules.md#idempotency)). --- # Antworten und Streaming > Die zentrale Konversationsschnittstelle von LMSP mit Responses-artigen Anfragen und Ausgabeelementen, synchroner und gestreamter Generierung, Server-Sent-Event-Typen, Ereignis-IDs, Wiederverbindung und Tool-Aufrufen. Source: https://madeforagent.com/de/lmsp/1.0/responses/ Language: de Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 6.1 Anfrage {#request} ```http POST /lmsp/v1/responses Authorization: Bearer Content-Type: application/json Idempotency-Key: 01J8M5T7Z2K4N6Q8S0V3X5B9DG LMSP-Version: 1.0 ``` ```json { "model": "qwen3:14b-q4_k_m", "input": [ { "type": "message", "role": "user", "content": [ { "type": "input_text", "text": "Describe a local model service in one sentence." } ] } ], "stream": false, "max_output_tokens": 512, "temperature": 0.7, "response_format": { "type": "text" }, "store": true } ``` Das Kernprotokoll verwendet eine Responses-artige `input`- und `output`-Struktur statt einer einfachen Liste von Nachrichtenzeichenfolgen, damit eine einzige Anfrageform Folgendes tragen kann: - mehrteilige Nachrichten über mehrere Gesprächsrunden; - Text, Bilder, Audio und Dateien; - Tool-Aufrufe und Tool-Ergebnisse; - strukturierte Ausgabe; - Zusammenfassungen des Schlussfolgerns; - multimodale Ausgabe. LMSP 1.0 definiert nur Textinhalt. Bild-, Audio- und Dateiinhaltstypen sind für spätere Versionen reserviert. | Feld | Erforderlich | Bedeutung | | --- | --- | --- | | `model` | Ja | ID des zu verwendenden Modells. | | `input` | Ja | Array von Eingabeelementen. Ein `message`-Element hat eine `role` (`system`, `user` oder `assistant`) und ein `content`-Array aus Teilen, etwa `input_text`. Die Nutzung von Tools fügt `function_call`- und `function_call_output`-Elemente hinzu ([Abschnitt 6.5](https://madeforagent.com/de/lmsp/1.0/responses.md#tools)). | | `stream` | Nein | `true`, um Server-Sent Events zu erhalten. Standardwert ist `false`. | | `max_output_tokens` | Nein | Obergrenze für die Anzahl der generierten Tokens. | | `temperature` | Nein | Sampling-Temperatur. | | `response_format` | Nein | `{"type": "text"}` (der Standard) oder `{"type": "json_schema", "json_schema": {"name": "...", "schema": {...}}}` für strukturierte Ausgabe. Erfordert die Fähigkeit `structured_output`. | | `tools`, `tool_choice` | Nein | Funktions-Tools, die das Modell aufrufen darf ([Abschnitt 6.5](https://madeforagent.com/de/lmsp/1.0/responses.md#tools)). Erfordert die Fähigkeit `tools`. | | `store` | Nein | Bittet den Dienst, die Antwort aufzubewahren, damit sie später abgerufen und als `previous_response_id` verwendet werden kann. Standardwert ist `false`. Wird von Diensten ohne die Fähigkeit `conversations` ignoriert. | | `previous_response_id` | Nein | Setzt eine gespeicherte Antwort fort. Erfordert die Fähigkeit `conversations`. | | `extensions` | Nein | Private Erweiterungen ([Abschnitt 9.1](https://madeforagent.com/de/lmsp/1.0/common-rules.md#versioning)). | Eine Anfrage, die eine Fähigkeit benötigt, die das Modell nicht hat, wird mit `400` und `unsupported_capability` abgelehnt. Eine Anfrage, die nicht in das Kontextfenster passt, wird mit `400` und `context_length_exceeded` abgelehnt. Ein Dienst, der Konversationen speichern kann, **KANN** auch `previous_response_id` unterstützen. Andernfalls **MUSS** jede Anfrage den vollständigen Kontext enthalten. Ein Dienst **DARF NICHT** darauf vertrauen, dass die HTTP-Verbindung den Konversationszustand hält. ## 6.2 Synchrone Antwort {#sync} Ist `stream` `false`, gibt der Dienst nach Abschluss der Generierung `200 OK` mit einem Antwortobjekt zurück. ```json { "id": "resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF", "object": "response", "created_at": 1794200000, "status": "completed", "model": "qwen3:14b-q4_k_m", "output": [ { "id": "msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE", "type": "message", "role": "assistant", "content": [ { "type": "output_text", "text": "A local model service is a resident interface layer that discovers, manages and calls models on the user's own device." } ] } ], "usage": { "input_tokens": 28, "output_tokens": 31, "total_tokens": 59 }, "error": null, "incomplete_details": null } ``` | Feld | Bedeutung | | --- | --- | | `id` | Antwortkennung, etwa `resp_...`. | | `object` | Immer `"response"`. | | `created_at` | Erstellungszeit in Sekunden seit der Unix-Epoche. | | `status` | `in_progress`, `completed`, `incomplete`, `failed` oder `cancelled`. Eine synchrone Antwort wird in einem Endstatus zurückgegeben. | | `model` | ID des Modells, das die Antwort erzeugt hat. | | `output` | Array von Ausgabeelementen. | | `usage` | Token-Zähler: `input_tokens`, `output_tokens` und `total_tokens`. | | `error` | `null` oder ein Problemobjekt ([Abschnitt 9.3](https://madeforagent.com/de/lmsp/1.0/common-rules.md#errors)), wenn `status` `failed` ist. | | `incomplete_details` | `null` oder ein Objekt mit einem `reason` wie `max_output_tokens`, wenn `status` `incomplete` ist. | Typen von Ausgabeelementen: | Elementtyp | Form | | --- | --- | | `message` | `id`, `role` (`assistant`) und `content`, ein Array aus `output_text`-Teilen, die jeweils einen `text` haben. | | `function_call` | `id`, `call_id`, `name` und `arguments`, eine JSON-codierte Zeichenfolge. | | `reasoning` | `id` und `summary`, ein Array aus `summary_text`-Teilen, die jeweils einen `text` haben. | Schlägt die Generierung fehl, wird eine synchrone Anfrage mit einem Fehlerstatus und einem Problemdokument ([Abschnitt 9.3](https://madeforagent.com/de/lmsp/1.0/common-rules.md#errors)) beantwortet, nicht mit einem Antwortobjekt. Der Status `failed` erscheint in Streams, Aufgaben und gespeicherten Antworten. `GET /lmsp/v1/responses/{response_id}` gibt eine Antwort zurück, die mit `store: true` gespeichert wurde. Er ist optional und erfordert die Fähigkeit `conversations`. Eine unbekannte ID ergibt `404` mit `response_not_found`. ## 6.3 Streaming {#streaming} Zum Streamen setzen Sie `stream` in der Anfrage: ```json { "stream": true } ``` Der Dienst antwortet mit `200 OK` und `Content-Type: text/event-stream` und sendet semantische Ereignisse. Jedes Ereignis hat eine `id`, einen `event`-Namen und ein JSON-`data`-Objekt: ```text id: 1 event: response.created data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","status":"in_progress"} id: 2 event: response.output_item.added data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","output_index":0,"item":{"id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","type":"message","role":"assistant","content":[]}} id: 3 event: response.output_text.delta data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","item_id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","delta":"A local model "} id: 4 event: response.output_text.delta data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","item_id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","delta":"service is a resident interface layer."} id: 5 event: response.output_item.done data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","output_index":0,"item":{"id":"msg_01J8M6Q4W5C8H2K9P3S7Y1A6ZE","type":"message","role":"assistant","content":[{"type":"output_text","text":"A local model service is a resident interface layer."}]}} id: 6 event: response.completed data: {"response_id":"resp_01J8M6Q4W2T7N5R3V9X1Z8B0DF","status":"completed","usage":{"input_tokens":28,"output_tokens":12,"total_tokens":40}} ``` Mindestens diese Ereignisse sind definiert: | Ereignis | Bedeutung | Datenfelder | | --- | --- | --- | | `response.created` | Die Antwort wurde erstellt. | `response_id`, `status` (`in_progress`) | | `response.output_item.added` | Ein neues Ausgabeelement hat begonnen. | `response_id`, `output_index`, `item` | | `response.output_text.delta` | An ein Nachrichtenelement wurde Text angehängt. | `response_id`, `item_id`, `delta` | | `response.output_item.done` | Ein Ausgabeelement ist vollständig. | `response_id`, `output_index`, `item` | | `response.completed` | Die Antwort ist abgeschlossen. Letztes Ereignis. | `response_id`, `status`, `usage` | | `response.incomplete` | Die Generierung wurde vorzeitig beendet, zum Beispiel am Token-Limit. Letztes Ereignis. | `response_id`, `status`, `incomplete_details`, `usage` | | `response.failed` | Die Generierung ist fehlgeschlagen. Letztes Ereignis. | `response_id`, `status`, `error` | | `response.cancelled` | Die Antwort wurde abgebrochen. Letztes Ereignis. | `response_id`, `status` | | `error` | Ein Problem, das nicht an eine einzelne Antwort gebunden ist und nach dem der Stream nicht fortgesetzt werden kann. | `error`, ein Problemobjekt | Ein Dienst schließt den Stream nach einem letzten Ereignis oder einem `error`-Ereignis. Dienste **KÖNNEN** zusätzliche Ereignisse senden, zum Beispiel für Argumente von Tool-Aufrufen, Bilder, Audio und strukturierte JSON-Deltas. Clients **MÜSSEN** Ereignistypen ignorieren, die sie nicht kennen. Schließt der Client die Verbindung einer Streaming-Anfrage, **SOLLTE** der Dienst die Generierung beenden. ## 6.4 Ereignis-IDs und Wiederverbindung {#reconnection} Die `id` eines Ereignisses **MUSS** eine ganzzahlige Sequenznummer sein, die innerhalb der Antwort streng ansteigt und bei 1 beginnt. Nach einer abgebrochenen Verbindung setzt ein Client fort, indem er die zuletzt erhaltene ID sendet. Das geschieht mit einem Header: ```http Last-Event-ID: 2 ``` oder mit einem Abfrageparameter: ```http GET /lmsp/v1/tasks/{task_id}/events?after=2 ``` Beides geht an den Ereignis-Endpunkt einer Aufgabe ([Abschnitt 7.4](https://madeforagent.com/de/lmsp/1.0/tasks.md#events)). Der Dienst spielt nur die Ereignisse erneut ab, deren Sequenznummer größer als 2 ist. Sind beide vorhanden, hat `after` Vorrang. Sind die angeforderten Ereignisse älter als die Aufbewahrungsdauer, antwortet der Dienst mit `410 Gone` und dem Fehler `event_history_expired`. Der Client ruft dann stattdessen das Endergebnis mit `GET /lmsp/v1/tasks/{task_id}` ab. Eine direkt von `POST /lmsp/v1/responses` gestreamte Antwort gehört zu dieser HTTP-Verbindung und kann nicht fortgesetzt werden. Ein Client, der fortsetzbare Ausgabe braucht, **SOLLTE** eine [Aufgabe](https://madeforagent.com/de/lmsp/1.0/tasks.md) erstellen und ihren Ereignissen folgen. ## 6.5 Tool-Aufrufe {#tools} LMSP 1.0 definiert Funktions-Tools, die der Client ausführt. Der Dienst führt Tools nicht selbst aus. Der Scope `tools:execute` ist für Erweiterungen reserviert, die das tun ([Abschnitt 10.3](https://madeforagent.com/de/lmsp/1.0/security.md#scopes)). Zuerst listet der Client die Tools auf. Jeder Eintrag hat `type` mit dem Wert `function`, einen `name`, eine `description` und `parameters`, ein JSON-Schema-Objekt. `tool_choice` ist `auto` (der Standard), `none`, `required` oder `{"type": "function", "name": "get_weather"}`. ```json { "model": "qwen3:14b-q4_k_m", "input": [ { "type": "message", "role": "user", "content": [ { "type": "input_text", "text": "What is the weather in Hangzhou?" } ] } ], "tools": [ { "type": "function", "name": "get_weather", "description": "Get the current weather for a city.", "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] } } ], "tool_choice": "auto" } ``` Entscheidet das Modell, ein Tool aufzurufen, enthält die Antwort ein `function_call`-Element. Seine `arguments` sind eine JSON-codierte Zeichenfolge. In einem Stream trifft das Element vollständig in `response.output_item.done` ein. ```json { "id": "resp_01J8M7B3N6Q9T2V5X8Z1C4D7FH", "object": "response", "created_at": 1794200050, "status": "completed", "model": "qwen3:14b-q4_k_m", "output": [ { "id": "fc_01J8M7B3N8R1S4W7Y0A3E6G9JK", "type": "function_call", "call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM", "name": "get_weather", "arguments": "{\"city\":\"Hangzhou\"}" } ], "usage": { "input_tokens": 74, "output_tokens": 18, "total_tokens": 92 }, "error": null, "incomplete_details": null } ``` Der Client führt das Tool aus und sendet dann eine neue Anfrage, die den vollständigen Kontext trägt: die früheren Eingabeelemente, das `function_call`-Element wie empfangen und ein `function_call_output`-Element mit derselben `call_id`. Sein `output` ist eine Zeichenfolge, meist JSON-codiert. ```json { "type": "function_call_output", "call_id": "call_01J8M7B3N9T2V5X8Z1C4D7F0HM", "output": "{\"temperature_c\":17,\"condition\":\"light rain\"}" } ``` --- # Asynchrone Aufgaben > Wie LMSP lange Generierungen als persistierte Aufgaben ausführt, mit Aufgabenerstellung, Zustandsautomat, idempotentem Abbruch, Ereignisströmen und Neustartrichtlinien für unfertige Aufgaben. Source: https://madeforagent.com/de/lmsp/1.0/tasks/ Language: de Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 7.1 Eine Aufgabe erstellen {#create} Ein Client erstellt eine Aufgabe, indem er die Antwortanfrage, die er ausführen möchte, in einen Aufgaben-Umschlag verpackt per POST sendet. Ein `Idempotency-Key`-Header wird empfohlen ([Abschnitt 9.2](https://madeforagent.com/de/lmsp/1.0/common-rules.md#idempotency)). ```http POST /lmsp/v1/tasks Authorization: Bearer Idempotency-Key: 01J8M7C4Y3N5P8R2T6V9X1Z4BH ``` ```json { "type": "response", "input": { "model": "qwen3:14b-q4_k_m", "input": [ { "type": "message", "role": "user", "content": [ { "type": "input_text", "text": "Write a long report." } ] } ] }, "on_restart": "fail" } ``` | Feld | Erforderlich | Bedeutung | | --- | --- | --- | | `type` | Ja | `response`, der einzige Aufgabentyp in 1.0. | | `input` | Ja | Eine Antwortanfrage, genau wie für `POST /lmsp/v1/responses`. Ihr Feld `stream` wird ignoriert. | | `on_restart` | Nein | `fail` (der Standard), `retry` oder `resume`. Siehe [Abschnitt 7.5](https://madeforagent.com/de/lmsp/1.0/tasks.md#restart). | Der Dienst **MUSS** die Aufgabe persistieren, bevor er antwortet. Danach gibt er zurück: ```http HTTP/1.1 202 Accepted ``` ```json { "id": "task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC", "object": "task", "type": "response", "status": "queued", "created_at": 1794200100, "updated_at": 1794200100, "response_id": "resp_01J8M8R5X4B9D2F6H1K3N7Q0ZW", "events_url": "/lmsp/v1/tasks/task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC/events", "on_restart": "fail", "response": null, "error": null } ``` | Aufgabenfeld | Bedeutung | | --- | --- | | `id` | Aufgabenkennung, etwa `task_...`. | | `object` | Immer `"task"`. | | `type` | `response`. | | `status` | Der aktuelle Zustand ([Abschnitt 7.2](https://madeforagent.com/de/lmsp/1.0/tasks.md#states)). | | `created_at`, `updated_at` | Zeiten in Sekunden seit der Unix-Epoche. | | `response_id` | ID der Antwort, die die Aufgabe erzeugt. Sie wird bei der Erstellung der Aufgabe vergeben. | | `events_url` | Pfad des Ereignisstroms. Vorhanden, wenn die Fähigkeit `event_resume` `true` ist. | | `on_restart` | Die Neustartrichtlinie der Aufgabe. | | `response` | Das Antwortobjekt, sobald `status` `succeeded` ist, sonst `null`. | | `error` | Ein Problemobjekt ([Abschnitt 9.3](https://madeforagent.com/de/lmsp/1.0/common-rules.md#errors)), wenn `status` `failed` ist, sonst `null`. | `GET /lmsp/v1/tasks/{task_id}` gibt das Aufgabenobjekt zurück. Clients, die keine Ereignisströme nutzen, fragen diesen Endpunkt regelmäßig ab. Eine unbekannte ID ergibt `404` mit `task_not_found`. Eine abgeschlossene Aufgabe sieht so aus: ```json { "id": "task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC", "object": "task", "type": "response", "status": "succeeded", "created_at": 1794200100, "updated_at": 1794200162, "response_id": "resp_01J8M8R5X4B9D2F6H1K3N7Q0ZW", "events_url": "/lmsp/v1/tasks/task_01J8M8R5X3V7B2N4Q9T1W6Y0ZC/events", "on_restart": "fail", "response": { "id": "resp_01J8M8R5X4B9D2F6H1K3N7Q0ZW", "object": "response", "created_at": 1794200100, "status": "completed", "model": "qwen3:14b-q4_k_m", "output": [ { "id": "msg_01J8M8R6A2C5E8G1J4M7P0S3VY", "type": "message", "role": "assistant", "content": [ { "type": "output_text", "text": "Local model services make on-device inference a shared, discoverable utility..." } ] } ], "usage": { "input_tokens": 12, "output_tokens": 1480, "total_tokens": 1492 }, "error": null, "incomplete_details": null }, "error": null } ``` ## 7.2 Zustandsautomat {#states} ```text queued --> loading --> running --> succeeded | | | | | +--> failed | | +--> cancelling --> cancelled | +--------------> failed +--------------------------> cancelled ``` | Zustand | Bedeutung | Folgezustände | | --- | --- | --- | | `queued` | Angenommen und persistiert, wartet auf den Start. | `loading`, `cancelled`, `failed` | | `loading` | Das Modell wird geladen. | `running`, `cancelling`, `failed` | | `running` | Das Modell generiert. | `succeeded`, `failed`, `cancelling` | | `cancelling` | Der Abbruch wurde angefordert, und das Backend hat noch nicht angehalten. | `cancelled` | | `succeeded` | Endzustand. Die Antwort ist vollständig. | keine | | `failed` | Endzustand. | keine | | `cancelled` | Endzustand. | keine | Die Endzustände sind `succeeded`, `failed` und `cancelled`. Eine Aufgabe in einem Endzustand **DARF NICHT** mehr wechseln. Eine Aufgabe, deren Antwort als `incomplete` endet, zum Beispiel am Token-Limit, ist `succeeded`. Jeder Übergang ist atomar, sodass eine Aufgabe nie zugleich abgebrochen und abgeschlossen ist. Es gewinnt der Übergang, der zuerst festgeschrieben wird. ## 7.3 Abbruch {#cancel} ```http POST /lmsp/v1/tasks/{task_id}/cancel ``` Der Dienst gibt `200 OK` und das aktuelle Aufgabenobjekt zurück. Eine `queued`-Aufgabe wird sofort `cancelled`. Eine `loading`- oder `running`-Aufgabe wird `cancelling`, bis das Backend angehalten hat, und danach `cancelled`. Der Abbruch **MUSS** idempotent sein. Der Abbruch einer Aufgabe, die bereits `cancelling` oder `cancelled` ist, gibt die aktuelle Aufgabe zurück und erzeugt keinen neuen Fehler. Der Abbruch einer Aufgabe, die bereits `succeeded` oder `failed` ist, wird mit `409` und `task_not_cancelable` beantwortet. Eine unbekannte ID ergibt `404` mit `task_not_found`. ## 7.4 Ereignisströme {#events} ```http GET /lmsp/v1/tasks/{task_id}/events Accept: text/event-stream ``` Dieser Endpunkt ist optional. Er ist verfügbar, wenn die Fähigkeit `event_resume` `true` ist. - Die Ereignisse sind die Antwortereignisse aus [Abschnitt 6.3](https://madeforagent.com/de/lmsp/1.0/responses.md#streaming), für die Antwort, die die Aufgabe erzeugt. Nummerierung und Fortsetzung folgen [Abschnitt 6.4](https://madeforagent.com/de/lmsp/1.0/responses.md#reconnection). - Der Stream beginnt mit `response.created`, das bei der Annahme der Aufgabe aufgezeichnet wird. Er endet mit genau einem letzten Ereignis, das zum Ergebnis passt: `response.completed`, `response.incomplete`, `response.failed` oder `response.cancelled`. - Ein Client, der sich spät verbindet, erhält zuerst die verpassten Ereignisse und danach Live-Ereignisse. Der Dienst schließt den Stream nach dem letzten Ereignis. - Ereignisse werden für eine Aufbewahrungsdauer vorgehalten ([Abschnitt 11.2](https://madeforagent.com/de/lmsp/1.0/persistence.md#rules)). Ältere Ereignisse ergeben `410 Gone` mit `event_history_expired`. ## 7.5 Neustartverhalten {#restart} `on_restart` legt fest, was mit einer unfertigen Aufgabe geschieht, wenn der Dienst neu startet: | Wert | Verhalten | | --- | --- | | `fail` | Der Standard. Der Dienst markiert die unfertige Aufgabe als `failed`, mit dem Fehlercode `server_restarted`. | | `retry` | Der Dienst führt die Aufgabe von vorn erneut aus. | | `resume` | Der Dienst setzt von einem Snapshot aus fort. Das ist nur erlaubt, wenn das Backend fortsetzbare Snapshots ausdrücklich unterstützt. Andernfalls wird die Erstellungsanfrage mit `400` und `unsupported_capability` abgelehnt. | Eine Aufgabe, die beim Neustart des Dienstes `cancelling` ist, schließt ihren Abbruch ab und wird `cancelled`, unabhängig von ihrer Richtlinie. `retry` wird als Standard nicht empfohlen, weil die Aufgabe möglicherweise schon Tools ausgeführt oder externe Nebeneffekte erzeugt hat. Ein Client, der `retry` wählt, **MUSS** es mit einem `Idempotency-Key` kombinieren und seine Tool-Aufrufe idempotent machen. --- # OpenAI- und Ollama-Kompatibilität > Wie ein LMSP-Dienst über eine dünne Datenkonvertierungsschicht auf einem einzigen Ausführungskern mit bestehenden OpenAI- und Ollama-Clients kompatibel bleibt und wo diese Kompatibilität endet. Source: https://madeforagent.com/de/lmsp/1.0/compatibility/ Language: de Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 8.1 OpenAI-kompatible Endpunkte {#openai} Ein Dienst **SOLLTE** neben der LMSP-Schnittstelle eine OpenAI-kompatible Schnittstelle anbieten und sie in `interfaces` mit `kind` gleich `openai` deklarieren. Um bestehende Clients abzudecken, **MUSS** ein Dienst, der das tut, mindestens diese Endpunkte unter dem Präfix `/v1` implementieren: | Endpunkt | Hinweise | | --- | --- | | `GET /v1/models` | Listet die Modelle des LMSP-Katalogs auf. Jede `id` ist die LMSP-Modell-ID. | | `POST /v1/chat/completions` | Chat Completions, mit und ohne Streaming. | | `POST /v1/responses` | Die OpenAI-Responses-Form. | | `POST /v1/embeddings` | Die LMSP-1.0-Kernschnittstelle hat keinen Embeddings-Endpunkt. Der Adapter stellt diesen Endpunkt direkt bereit, für Modelle, deren `capabilities.embeddings` `true` ist. | Diese Endpunkte akzeptieren dieselben Bearer-Tokens wie die LMSP-Schnittstelle. Ein Client, der das OpenAI-Protokoll spricht, setzt das LMSP-Token als seinen API-Schlüssel. Eine erste Implementierung kann mit `/v1/models` und `/v1/chat/completions` beginnen ([Seite 12](https://madeforagent.com/de/lmsp/1.0/mvp.md)). ## 8.2 Ollama-kompatible Endpunkte {#ollama} Ein Dienst **SOLLTE** auch diese Endpunkte bereitstellen, damit auch für Ollama geschriebene Clients funktionieren: | Endpunkt | Hinweise | | --- | --- | | `GET /api/tags` | Listet die Modelle des LMSP-Katalogs auf. | | `POST /api/chat` | Chat. | | `POST /api/generate` | Einfache Textgenerierung. | Ein Dienst, der sie bereitstellt, deklariert eine Schnittstelle mit `kind` gleich `ollama`. ## 8.3 Ein Ausführungskern {#core} Die Kompatibilitätsschicht **MUSS** nur Daten konvertieren. Sie **DARF NICHT** eine zweite Modellverwaltungslogik anlegen. Eine Anfrage an eine Kompatibilitätsschnittstelle wird auf eine LMSP-Antwort abgebildet, läuft auf demselben Kern und Adapter wie eine native Anfrage und nutzt denselben Modellkatalog und dieselbe Authentifizierung. ```text OpenAI Chat Completions | Abbildung der Anfrage v LMSP Response | Backend-Anpassung v llama.cpp / Ollama / vLLM / andere Laufzeitumgebungen ``` Auf den Endpunkten `/v1` und `/api` **SOLLTE** ein Dienst Fehler in dem Format melden, das die jeweilige API definiert, damit unveränderte Clients sie auswerten können. Die LMSP-Schnittstelle verwendet immer `application/problem+json`. ## 8.4 Grenzen {#boundaries} Die Kompatibilität hat Grenzen, und es lohnt sich, sie klar zu benennen: - Ein bestehender OpenAI-kompatibler Client braucht meist nur eine geänderte `base_url`. Er erhält die LMSP-Erkennung nicht automatisch. - Nur Clients, die LMSP unterstützen, können einen Dienst automatisch erkennen, seine detaillierten Fähigkeiten lesen, Ereignisströme fortsetzen und asynchrone Aufgaben verwalten. - Kein serverseitiges Protokoll kann einen Client zum Laufen bringen, der sich nicht konfigurieren lässt und nur offizielle Cloud-Adressen akzeptiert. --- # Allgemeine Regeln > Regeln, die für jeden LMSP-Endpunkt gelten, mit Versions-Headern und Erweiterungen, Idempotenzschlüsseln, dem Fehlerformat problem+json samt Fehlercodes und der Zustandsprüfung. Source: https://madeforagent.com/de/lmsp/1.0/common-rules/ Language: de Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 9.1 Versionen und Erweiterungen {#versioning} Jede LMSP-Anfrage **KANN** diese Header tragen: ```http LMSP-Version: 1.0 LMSP-Client: example-client/1.2.0 ``` `LMSP-Version` ist die Protokollversion, auf die der Client abzielt. `LMSP-Client` kennzeichnet die Client-Software für Diagnosezwecke als `name/version`. Das Protokollverhalten eines Dienstes **DARF NICHT** davon abhängen. Regeln: - Das `v1` im Pfad bezeichnet die Hauptversion. - Eine Anfrage, die eine unbekannte Hauptversion nennt, wird mit `426 Upgrade Required` und dem Fehlercode `unsupported_protocol_version` beantwortet. - Neue optionale Felder **DÜRFEN NICHT** die 1.x-Kompatibilität brechen. - Dienste und Clients **MÜSSEN** Felder ignorieren, die sie nicht kennen. - Private Erweiterungen kommen in ein `extensions`-Objekt und werden in umgekehrter Domain-Notation benannt: ```json { "extensions": { "com.example.cache": { "enabled": true } } } ``` ## 9.2 Idempotenz {#idempotency} Anfragen, die etwas erzeugen, etwa das Erstellen einer Antwort, das Erstellen einer Aufgabe oder das Laden eines Modells, akzeptieren einen Idempotenzschlüssel: ```http Idempotency-Key: ``` Der Dienst speichert den Schlüssel zusammen mit einem Digest des Anfrage-Bodys und dem Ergebnis: - Derselbe Schlüssel mit demselben Body liefert das ursprüngliche Ergebnis zurück. - Derselbe Schlüssel mit einem anderen Body wird mit `409 Conflict` und `idempotency_conflict` beantwortet. Ein Schlüssel gilt für den Client und den Endpunkt. Er **SOLLTE** ein eindeutiger Wert mit höchstens 255 Zeichen sein, etwa eine ULID oder eine UUID. Ein Dienst **SOLLTE** Schlüssel mindestens 24 Stunden aufbewahren. Ein Dienst **KANN** den Schlüssel bei Streaming-Anfragen ignorieren. Ein Client, der sichere Wiederholungen braucht, verwendet eine [Aufgabe](https://madeforagent.com/de/lmsp/1.0/tasks.md). ## 9.3 Fehler {#errors} Jeder Fehler der LMSP-Schnittstelle verwendet `application/problem+json` ([RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)): ```json { "type": "urn:lmsp:error:model-not-found", "title": "Model not found", "status": 404, "code": "model_not_found", "detail": "No local model with id 'qwen3:14b-q4_k_m'", "request_id": "req_01J8M9S6Y4W8C3P5R1V7Z2A0DH", "retryable": false } ``` | Feld | Erforderlich | Bedeutung | | --- | --- | --- | | `type` | Ja | URI, die die Art des Fehlers kennzeichnet. LMSP verwendet `urn:lmsp:error:` gefolgt vom Code mit Bindestrichen statt Unterstrichen. | | `title` | Ja | Kurze, menschenlesbare Zusammenfassung. | | `status` | Ja | Der HTTP-Statuscode. | | `code` | Ja | Maschinenlesbarer Fehlercode aus der folgenden Liste. | | `detail` | Nein | Menschenlesbare Erläuterung dieses Auftretens. Sie **DARF NICHT** Geheimnisse, Prompts oder generierte Inhalte enthalten. | | `request_id` | Nein | Kennung der Anfrage zur Zuordnung zu den Dienstprotokollen. | | `retryable` | Ja | Ob eine spätere Wiederholung der Anfrage erfolgreich sein kann. | Gängige Fehlercodes: | Code | HTTP-Status | Wiederholbar | Bedeutung | | --- | --- | --- | --- | | `invalid_request` | 400 | Nein | Die Anfrage ist fehlerhaft oder hat ungültige Parameter. | | `unauthorized` | 401 | Nein | Das Token fehlt, ist ungültig, abgelaufen oder widerrufen, oder ein Kopplungscode ist falsch. | | `forbidden` | 403 | Nein | Dem Token fehlt der erforderliche Scope, oder die Prüfung von `Origin` oder `Host` ist fehlgeschlagen. | | `model_not_found` | 404 | Nein | Kein lokales Modell hat diese ID. | | `model_not_ready` | 409 | Ja | Das Modell ist nicht geladen und wird nicht bei Bedarf geladen. | | `model_load_failed` | 500 | Ja | Das Laden des Modells ist fehlgeschlagen. | | `context_length_exceeded` | 400 | Nein | Die Eingabe passt nicht in das Kontextfenster des Modells. | | `unsupported_capability` | 400 oder 501 | Nein | Das Modell oder der Dienst unterstützt nicht, was die Anfrage braucht. Ein nicht implementierter optionaler Endpunkt antwortet mit 501. | | `unsupported_protocol_version` | 426 | Nein | Der Dienst unterstützt die angeforderte Hauptversion nicht. | | `response_not_found` | 404 | Nein | Keine gespeicherte Antwort hat diese ID. | | `task_not_found` | 404 | Nein | Keine Aufgabe hat diese ID. | | `task_not_cancelable` | 409 | Nein | Die Aufgabe ist bereits erfolgreich beendet oder fehlgeschlagen. | | `idempotency_conflict` | 409 | Nein | Der Idempotenzschlüssel wurde bereits mit einem anderen Anfrage-Body verwendet. | | `event_history_expired` | 410 | Nein | Die angeforderten Ereignisse sind älter als die Aufbewahrungsdauer. | | `rate_limited` | 429 | Ja | Zu viele Anfragen. | | `resource_exhausted` | 503 | Ja | Dem Gerät fehlen Arbeitsspeicher oder eine andere Ressource. | | `backend_unavailable` | 503 | Ja | Die Modell-Laufzeitumgebung ist nicht erreichbar. | | `server_restarted` | 503 | Ja | Der Dienst wurde neu gestartet, während die Aufgabe unfertig war. | | `internal_error` | 500 | Unterschiedlich | Ein unerwarteter Fehler im Dienst. | Das Feld `retryable` ist maßgeblich. Die Spalte oben zeigt den üblichen Wert. Ein Dienst **KANN** weitere Codes definieren. Ein Client **MUSS** einen Code, den er nicht kennt, anhand seines HTTP-Status und seines Feldes `retryable` behandeln. ## 9.4 Zustandsprüfung {#health} ```http GET /lmsp/v1/health ``` ```json { "status": "ready", "service_id": "svc_01J8M4Y8K6M5E6K6Z7Z0Y8W3M2", "uptime_seconds": 86420, "loaded_models": 1, "active_tasks": 2, "storage": "ok" } ``` | Feld | Bedeutung | | --- | --- | | `status` | `starting`, `ready`, `degraded` oder `stopping`. | | `service_id` | Die Dienst-ID aus der Dienstbeschreibung. | | `uptime_seconds` | Sekunden seit dem Start des Dienstes. | | `loaded_models` | Anzahl der Modelle im Zustand `ready`. | | `active_tasks` | Anzahl der Aufgaben, die `queued`, `loading`, `running` oder `cancelling` sind. | | `storage` | `ok` oder `error`. | Der Status ist `200 OK`, wenn `status` `ready` oder `degraded` ist, andernfalls `503 Service Unavailable`. Der Health-Endpunkt liefert nur den Betriebszustand. Er **DARF NICHT** Modellpfade, Prompts, Zugriffstokens oder andere sensible Informationen zurückgeben. --- # Lokale Sicherheit > Sicherheitsanforderungen an LMSP-Dienste, mit Loopback-Bindung, Kopplung und Bearer-Tokens, Scopes, Origin- und Host-Prüfungen gegen bösartige Webseiten, LAN-Modus und Protokollierungsregeln. Source: https://madeforagent.com/de/lmsp/1.0/security/ Language: de Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 10.1 Grundlage {#baseline} Das ausschließliche Lauschen auf localhost ist keine absolute Sicherheit: Eine bösartige Webseite kann trotzdem versuchen, lokale Ports zu erreichen. LMSP kombiniert deshalb mehrere Maßnahmen. - Ein Dienst **MUSS** sich standardmäßig an die Loopback-Adressen binden. Er **DARF NICHT** auf `0.0.0.0` oder einer anderen Nicht-Loopback-Adresse lauschen, solange der LAN-Modus nicht aktiviert ist ([Abschnitt 10.5](https://madeforagent.com/de/lmsp/1.0/security.md#lan)). - Beim ersten Start **SOLLTE** ein Dienst ein zufälliges Dienstgeheimnis mit hoher Entropie erzeugen und damit, statt mit einem eingebauten Standardwert, Tokens ausstellen und prüfen. - Jede Anfrage an die Kernschnittstelle **MUSS** ein gültiges Bearer-Token tragen, außer bei den in [Abschnitt 4.2](https://madeforagent.com/de/lmsp/1.0/endpoints.md#conventions) aufgeführten Bootstrap-Endpunkten. Von Loopback zu kommen genügt allein nie. ## 10.2 Kopplung und Tokens {#pairing} Ein Client erhält sein eigenes Bearer-Token mit einem lokalen Kopplungscode. Der Nutzer lässt sich vom Dienst auf dessen Weise einen Kopplungscode anzeigen, und der Client reicht ihn ein: ```http POST /lmsp/v1/pair Content-Type: application/json ``` ```json { "client_name": "example-client", "pairing_code": "K7QD-4M2X", "scopes": ["inference"] } ``` | Anfragefeld | Bedeutung | | --- | --- | | `client_name` | Anzeigename des Clients, dem Nutzer angezeigt. | | `pairing_code` | Der Code, den der Nutzer vom Dienst erhalten hat. | | `scopes` | Optionale Liste der angeforderten Scopes. Standardwert ist `["inference"]`. | Der Dienst antwortet mit einem Token. Der `token_type` ist immer `Bearer`: ```json { "client_id": "cli_01J8MAT3W6X9B2D5F8H1K4N7QZ", "access_token": "lmsp_example_3f9a1c52e7d84b60", "token_type": "Bearer", "scopes": ["inference"] } ``` Danach sendet der Client mit jeder Anfrage `Authorization: Bearer `. - Ein Kopplungscode **MUSS** nur einmal verwendbar sein und **SOLLTE** innerhalb von 5 Minuten ablaufen. Er **SOLLTE** mindestens 40 Bit Entropie enthalten. Ein Dienst **MUSS** fehlgeschlagene Versuche begrenzen. Ein falscher oder abgelaufener Code wird mit `401` und `unauthorized` beantwortet. - Tokens sind pro Client unabhängig, sodass der Nutzer einen Client widerrufen kann, ohne die anderen zu beeinträchtigen. Ein Dienst **SOLLTE** dem Nutzer erlauben, gekoppelte Clients aufzulisten und zu widerrufen. - Ein Client **SOLLTE** sein Token im Schlüsselbund oder in der Anmeldeinformationsverwaltung des Betriebssystems aufbewahren. Ein Dienst **SOLLTE** nur einen Hash jedes Tokens speichern. - Ein fehlendes, ungültiges oder widerrufenes Token wird mit `401`, `unauthorized` und einem `WWW-Authenticate: Bearer`-Header beantwortet. Ein gültiges Token, dem der von einem Endpunkt benötigte Scope fehlt, wird mit `403` und `forbidden` beantwortet. ## 10.3 Scopes {#scopes} Berechtigungen sind in getrennte Scopes aufgeteilt. Modelle herunterzuladen, Modelle zu löschen und Tools auszuführen läuft nie über den Inferenz-Scope mit. | Scope | Erlaubt | | --- | --- | | `inference` | Den Modellkatalog lesen, Antworten und Aufgaben erstellen sowie die eigenen Aufgaben des Clients lesen und abbrechen. | | `models:manage` | Modelle laden und entladen. | | `models:install` | Reserviert. Modelle herunterladen und löschen. | | `tools:execute` | Reserviert. Tools auf Dienstseite ausführen. | Aufgaben und gespeicherte Antworten gehören dem Client, der sie erstellt hat. Ein Dienst **SOLLTE** auf die Anfrage eines anderen Clients antworten, als gäbe es sie nicht (`task_not_found` oder `response_not_found`). ## 10.4 Schutz von Browser und Netzwerk {#browser} - Ein Dienst **MUSS** Cross-Origin-Browseranfragen standardmäßig ablehnen und nur ausdrücklich konfigurierte `Origin`-Werte zulassen. Eine Anfrage mit einer anderen `Origin` wird mit `403` und `forbidden` beantwortet. - Ist ein Origin erlaubt, beantwortet der Dienst dessen CORS-Preflight-Anfragen und sendet `Access-Control-Allow-Origin` mit genau diesem Origin, nie mit `*`. - Ein Dienst **MUSS** den `Host`-Header validieren, um DNS-Rebinding zu verhindern. Er akzeptiert nur Hostnamen, die er bedient: die Loopback-Namen und -Adressen sowie alle für den LAN-Modus konfigurierten Namen. Jeder andere Wert wird mit `403` und `forbidden` beantwortet. ## 10.5 LAN-Modus {#lan} LAN-Modus bedeutet, über die Loopback-Adressen hinaus zu lauschen. - Ein Dienst **DARF NICHT** den LAN-Modus aktivieren, es sei denn, der Nutzer schaltet ihn ausdrücklich ein. - Im LAN-Modus **MUSS** ein Dienst eine Authentifizierung verlangen und **SOLLTE** außerdem TLS aktivieren. Ein Client **SOLLTE NICHT** ein Token über unverschlüsseltes HTTP an eine Nicht-Loopback-Adresse senden, es sei denn, der Nutzer erlaubt es ausdrücklich. - Die mDNS-Ankündigung ist nur im LAN-Modus erlaubt, wenn der Nutzer außerdem die LAN-Erkennung eingeschaltet hat ([Abschnitt 3.2](https://madeforagent.com/de/lmsp/1.0/discovery.md#mdns)). ## 10.6 Protokollierung und Datenschutz {#logging} - Modellpfade, Logs, Prompts und generierte Inhalte **DÜRFEN NICHT** in mDNS-Ankündigungen erscheinen. - Standardmäßig **SOLLTE** ein Dienst nur Metadaten protokollieren (Zeiten, Endpunkte, Statuscodes, IDs, Token-Zahlen und Dauern). Er **SOLLTE NICHT** vollständige Prompts oder generierte Inhalte protokollieren. - Health-Antworten und Fehlerdetails **DÜRFEN NICHT** Modellpfade, Prompts, Zugriffstokens oder andere sensible Informationen enthalten. --- # Persistenz > Wie ein LMSP-Dienst seinen Zustand speichert, mit einer eingebetteten SQLite-Datenbank, den Tabellen, den Transaktionsregeln für Aufgaben und Ereignisse, der Aufbewahrung und der Wiederherstellung beim Start. Source: https://madeforagent.com/de/lmsp/1.0/persistence/ Language: de Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 11.1 Speicherung {#storage} Ein Dienst **SOLLTE** seinen Zustand in einer eingebetteten [SQLite](https://www.sqlite.org/)-Datenbank halten. Ein vorgeschlagener Satz von Tabellen: | Tabelle | Inhalt | | --- | --- | | `service_config` | Dienstidentität und Konfiguration. | | `clients` | Gekoppelte Clients, Token-Hashes und Scopes. | | `models` | Modellmetadaten und Inhalts-Digests. | | `responses` | Gespeicherte Antworten. | | `tasks` | Asynchrone Aufgaben. | | `task_events` | Das Ereignisprotokoll jeder Aufgabe, mit Sequenznummern. | | `idempotency_keys` | Idempotenzschlüssel, Anfrage-Digests und Ergebnisse. | Modelldateien **MÜSSEN** außerhalb der Datenbank bleiben. Die Datenbank enthält nur Metadaten und Inhalts-Digests. Tabellennamen und Aufbau sind eine Implementierungsentscheidung. Was Clients beobachten können und was interoperabel sein muss, ist das Verhalten in den nächsten beiden Abschnitten. ## 11.2 Regeln {#rules} Welchen Speicher ein Dienst auch verwendet, er: - **MUSS** eine Aufgabe persistieren, bevor er `202 Accepted` zurückgibt. - **MUSS** Ereignis-Sequenznummern und Aufgabenstatus in derselben Transaktion aktualisieren. - **MUSS** den Abbruchübergang atomar machen, um die Race Condition einer Aufgabe zu vermeiden, die abgebrochen und dann abgeschlossen wird. - **SOLLTE** beendete Aufgaben und Ereignisse für eine konfigurierbare Aufbewahrungsdauer vorhalten. - **DARF NICHT** unfertige Aufgaben bei der Protokollbereinigung löschen. - **MUSS** beim Start die übrig gebliebenen Aufgaben `queued`, `loading`, `running` und `cancelling` durchsehen und die Neustartrichtlinie jeder einzelnen anwenden ([Abschnitt 7.5](https://madeforagent.com/de/lmsp/1.0/tasks.md#restart)). ## 11.3 Wiederherstellung beim Start {#recovery} Die Tabelle zeigt den Zustand, in den eine übrig gebliebene Aufgabe gemäß ihrer `on_restart`-Richtlinie überführt wird: | Beim Start gefundener Zustand | `fail` | `retry` | `resume` | | --- | --- | --- | --- | | `queued` | `failed` | `queued` | `queued` | | `loading` | `failed` | `queued` | `queued` | | `running` | `failed` | `queued` | `running`, Fortsetzung vom Snapshot | | `cancelling` | `cancelled` | `cancelled` | `cancelled` | Eine Aufgabe, die nach `failed` überführt wird, erhält den Fehlercode `server_restarted` und ein `response.failed`-Ereignis. Eine Aufgabe, die nach `cancelled` überführt wird, erhält ein `response.cancelled`-Ereignis. Der neue Zustand und sein Ereignis werden in einer Transaktion geschrieben ([Abschnitt 11.2](https://madeforagent.com/de/lmsp/1.0/persistence.md#rules)). --- # Minimaler tragfähiger Umfang > Ein vorgeschlagener Umfang für eine erste LMSP-Implementierung, mit den zehn Bausteinen, die einen nutzbaren geschlossenen Kreislauf bilden, und den Teilen der Spezifikation, die auf spätere Versionen warten können. Source: https://madeforagent.com/de/lmsp/1.0/mvp/ Language: de Specification: LMSP 1.0 (draft) Updated: 2026-11-08 ## 12.1 Erste Version {#scope} Die erste Version muss nicht jede multimodale Funktion, jeden Modell-Download und keine Echtzeit-Sprache implementieren. Sie bildet einen nutzbaren geschlossenen Kreislauf, sobald sie Folgendes bietet: 1. Diensterkennung über `/.well-known/lmsp.json`. 2. Optionale LAN-Ankündigung von `_lmsp._tcp.local.`. 3. `GET /lmsp/v1/models`. 4. `POST /lmsp/v1/responses`, sowohl synchron als auch als SSE-Stream. 5. Asynchrone Aufgaben: erstellen, abfragen und abbrechen, mit SQLite-Persistenz. 6. Fortsetzen abgebrochener Streams mit `Last-Event-ID` oder `after`. 7. Bearer-Tokens, lokale Kopplung sowie `Origin`- und `Host`-Schutz. 8. Die OpenAI-kompatiblen Endpunkte `/v1/models` und `/v1/chat/completions`. 9. Eine OpenAPI-3.2-Vertragsdatei und sprachübergreifende Konformitätstests. 10. Mindestens ein echtes Backend und eine Prüfung, dass sich Aufgaben nach einem Neustart des Dienstes korrekt erholen. Der Kern dieses Entwurfs: LMSP liefert den vollständigen Funktionsumfang, die OpenAI-Schnittstelle liefert fertige Kompatibilität, mDNS und die Dienstbeschreibung liefern automatische Erkennung, und das SQLite-Aufgabenmodell liefert lokale Persistenz. ## 12.2 Was warten kann {#later} Alles, was die obige Liste nicht erwähnt, kann in späteren Versionen folgen. Dazu gehören die optionalen Endpunkte (gespeicherte Antworten sowie Laden und Entladen von Modellen), die OpenAI-Endpunkte `/v1/responses` und `/v1/embeddings`, die Ollama-kompatible API und jeder Inhaltstyp außer Text. Dieser Umfang ist ein Weg zu einer nutzbaren ersten Version, kein Konformitätsprofil. Ein Dienst, der LMSP 1.0 für sich beansprucht, implementiert weiterhin jeden erforderlichen Endpunkt von [Seite 4](https://madeforagent.com/de/lmsp/1.0/endpoints.md) und das erforderliche Verhalten, das auf den anderen Seiten beschrieben ist.