# 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 <token>
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\"}"
}
```
