Ausgaben in LangChain streamen
Sie implementieren Token-Streaming durch LCEL-Chains, sodass Ihre Anwendung jedes Wort beim Eintreffen anzeigt, statt auf die vollständige Antwort zu warten, und dadurch die wahrgenommene Latenz verbessert.
Ausgaben in LangChain streamen ist eine kostenlose AI Engineering Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des AI Engineering Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.
Warum Streaming wichtig ist
Ohne Streaming sehen Benutzer auf einen leeren Bildschirm, während sie darauf warten, dass das LLM die Ausgabe fertig generiert – bei langen Antworten kann das 5–30 Sekunden dauern. Beim Streaming erscheinen Tokens, sobald sie generiert werden, und geben sofortiges Feedback. Dadurch verbessert sich die wahrgenommene Reaktionsfähigkeit deutlich. LangChains LCEL leitet Streaming automatisch durch die gesamte Kette weiter, wenn Sie .stream() aufrufen.
Grundlegendes Streaming mit .stream()
Jede LCEL-Kette stellt eine .stream()-Methode bereit, die einen Iterator aus Chunks zurückgibt. Bei einer Kette, die mit StrOutputParser endet, ist jeder Chunk ein Stringfragment. Sie iterieren über die Chunks und geben sie aus oder liefern sie zurück, sobald sie eintreffen. Das Streaming findet auf HTTP-Ebene statt: Jedes Token der OpenAI API wird sofort nach seinem Eintreffen durch den Parser weitergeleitet.
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
chain = (
ChatPromptTemplate.from_template('Explain {topic} in detail.')
| ChatOpenAI(model='gpt-4o-mini')
| StrOutputParser()
)
# Stream tokens to stdout
for chunk in chain.stream({'topic': 'quantum entanglement'}):
print(chunk, end='', flush=True)
print() # final newlineAsynchrones Streaming mit .astream()
.astream() ist die asynchrone Variante von .stream(). Sie gibt einen asynchronen Iterator zurück, den Sie mit async for verarbeiten. Das ist der richtige Ansatz in FastAPI, Starlette und anderen asynchronen Web-Frameworks, in denen der Request-Handler eine Coroutine ist. Die Verwendung von synchronem Streaming in einem asynchronen Handler würde die Ereignisschleife blockieren.
import asyncio
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
chain = (
ChatPromptTemplate.from_template('Write a poem about {subject}')
| ChatOpenAI(model='gpt-4o-mini')
| StrOutputParser()
)
async def stream_response():
async for chunk in chain.astream({'subject': 'the ocean'}):
print(chunk, end='', flush=True)
asyncio.run(stream_response())Streaming in FastAPI mit StreamingResponse
In FastAPI verpacken Sie einen asynchronen Generator in StreamingResponse mit media_type='text/plain', um Text-Tokens an den Browser zu streamen. Für Server-Sent Events (SSE) verwenden Sie media_type='text/event-stream' und formatieren jeden Chunk als data: ...\n\n. Der Browser empfängt die Tokens dann, sobald sie generiert werden, ohne auf die vollständige Antwort warten zu müssen.
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
async def generate_stream(topic: str):
async for chunk in chain.astream({'topic': topic}):
yield chunk
@app.get('/stream')
async def stream_endpoint(topic: str):
return StreamingResponse(
generate_stream(topic),
media_type='text/plain'
)
# SSE format for frontend EventSource
async def sse_stream(topic: str):
async for chunk in chain.astream({'topic': topic}):
yield f'data: {chunk}\n\n'Streaming durch Zwischenschritte
LCEL-Ketten leiten Streaming durch jeden Schritt weiter, der dies unterstützt. Der StrOutputParser ist streamingfähig und gibt Chunks sofort weiter. Einige Parser – etwa JsonOutputParser – müssen jedoch die vollständige Ausgabe puffern, bevor sie sie parsen können, wodurch das Streaming unterbrochen wird. LangChain macht dieses Verhalten transparent: Wenn ein Schritt nicht streamingkompatibel ist, sammelt er die Ausgabe, bevor er sie weiterleitet.
from langchain_core.output_parsers import JsonOutputParser
# This chain does NOT stream token by token
# JsonOutputParser must buffer the full response before parsing JSON
json_chain = (
ChatPromptTemplate.from_template('Return JSON: {task}')
| ChatOpenAI(model='gpt-4o-mini')
| JsonOutputParser() # buffers until complete
)
# But partial JSON streaming IS possible with streaming_json_parser
for partial in json_chain.stream({'task': 'list 3 colors'}):
print(partial) # prints partial dict as it fills inastream_events für detaillierte Kontrolle
.astream_events() stellt eine detailliertere Streaming-API bereit, die für jeden Schritt der Kette Ereignisse ausgibt, nicht nur für die endgültige Ausgabe. Jedes Ereignis enthält ein kind-Feld (on_chain_start, on_llm_stream, on_chain_end) und eine data-Nutzlast. Damit können Sie Tool-Aufrufergebnisse, Zwischenschritte der Verarbeitung und die endgültige Ausgabe getrennt an verschiedene Bereiche einer Benutzeroberfläche streamen.
async def stream_with_events(question: str):
async for event in chain.astream_events(
{'question': question},
version='v2'
):
kind = event['event']
if kind == 'on_llm_stream':
chunk = event['data']['chunk'].content
print(chunk, end='', flush=True)
elif kind == 'on_chain_end':
print('\n[Done]')
elif kind == 'on_tool_start':
print(f'\n[Tool: {event["name"]}]')Gestreamte Ausgabe puffern
Manchmal müssen Sie Tokens sowohl an den Benutzer streamen als auch die vollständige Antwort für Protokollierung oder weitere Verarbeitung erfassen. Verwenden Sie .astream() mit einem Listen-Akkumulator. Fügen Sie die Chunks nach der Schleife zusammen, um den vollständigen Text zu erhalten. So können Sie die Ausgabe in Echtzeit anzeigen und gleichzeitig die vollständige Antwort für Analysen, Caching oder Evaluierung speichern.
async def stream_and_capture(question: str) -> str:
full_response = []
async for chunk in chain.astream({'question': question}):
print(chunk, end='', flush=True) # stream to user
full_response.append(chunk) # also collect
print() # newline
complete = ''.join(full_response)
await log_response(question, complete) # log full text
return completeStreaming mit Tool-Aufrufen
Wenn ein Modell in einer gestreamten Antwort einen Tool-Aufruf erzeugt, treffen die Funktionsargumente als Tokenfragmente ein. Sie müssen den JSON-Argumentstring puffern, bis der Tool-Aufruf vollständig ist, bevor Sie ihn ausführen. LangChain übernimmt dies in seinen Agent-Executors automatisch. Wenn Sie jedoch eine eigene Streaming-Schleife erstellen, müssen Sie finish_reason prüfen und die Fragmente von tool_call.function.arguments sammeln.
from openai import AsyncOpenAI
client = AsyncOpenAI()
async def stream_with_tools(prompt: str):
tool_call_buffer = {}
async with client.chat.completions.stream(
model='gpt-4o-mini',
messages=[{'role': 'user', 'content': prompt}],
tools=[weather_tool_schema]
) as stream:
async for chunk in stream:
delta = chunk.choices[0].delta
if delta.tool_calls:
for tc in delta.tool_calls:
idx = tc.index
if idx not in tool_call_buffer:
tool_call_buffer[idx] = ''
if tc.function.arguments:
tool_call_buffer[idx] += tc.function.argumentsAbbruch und Timeout beim Streaming
Lange Streaming-Antworten benötigen eine Unterstützung für den Abbruch. In asynchronem Python können Sie eine asyncio.Task abbrechen, die den Stream kapselt. In FastAPI übernimmt das Framework den Abbruch bei einer Client-Trennung automatisch, wenn Sie StreamingResponse verwenden. Setzen Sie ein Timeout über den timeout-Parameter des OpenAI-Clients oder kapseln Sie den Stream mit asyncio.wait_for(), um ihn nach einer maximalen Dauer abzubrechen.
import asyncio
async def stream_with_timeout(question: str, timeout: float = 30.0):
async def _stream():
async for chunk in chain.astream({'question': question}):
yield chunk
try:
async for chunk in asyncio.timeout(_stream(), timeout):
print(chunk, end='', flush=True)
except asyncio.TimeoutError:
print('\n[Stream timed out after 30 seconds]')
except asyncio.CancelledError:
print('\n[Stream cancelled by client disconnect]')Clientseitiges SSE mit JavaScript
Im Frontend verarbeitet die native EventSource API des Browsers Server-Sent Events. Wenn der FastAPI-Endpunkt Chunks im Format data: token\n\n ausgibt, löst EventSource für jeden Chunk ein message-Ereignis aus. Hängen Sie jedes Token beim Eintreffen an das DOM an, um einen Schreibmaschineneffekt zu erzeugen. Für mehr Kontrolle bietet fetch() mit response.body.getReader() vollständigen Zugriff auf den Stream.
// Frontend JavaScript (not Python)
const source = new EventSource('/stream?topic=quantum+computing');
const outputDiv = document.getElementById('output');
source.onmessage = (event) => {
outputDiv.textContent += event.data;
};
source.onerror = () => {
source.close();
outputDiv.textContent += ' [done]';
};
// Alternative: fetch with ReadableStream
const response = await fetch('/stream?topic=ai');
const reader = response.body.getReader();
while (true) {
const {done, value} = await reader.read();
if (done) break;
outputDiv.textContent += new TextDecoder().decode(value);
}Bewährte Vorgehensweisen für Streaming
Beachten Sie bei der Implementierung von Streaming die folgenden bewährten Vorgehensweisen: Verwenden Sie beim Ausgeben nach stdout immer flush=True, um Pufferung zu verhindern. Setzen Sie stream_usage=True, wenn Sie während des Streamings genaue Token-Zählungen benötigen. Senden Sie am Ende von SSE-Streams ein data: [DONE]\n\n-Signal, damit der Client weiß, wann er die Verbindung schließen kann. Testen Sie Streaming-Endpunkte mit curl --no-buffer, um zu überprüfen, dass die Tokens schrittweise eintreffen.
# Complete SSE endpoint with DONE sentinel
async def sse_generator(question: str):
try:
async for chunk in chain.astream({'question': question}):
# Escape any newlines in the chunk
safe_chunk = chunk.replace('\n', ' ')
yield f'data: {safe_chunk}\n\n'
finally:
yield 'data: [DONE]\n\n'
@app.get('/chat/stream')
async def chat_stream(question: str):
return StreamingResponse(
sse_generator(question),
media_type='text/event-stream',
headers={'Cache-Control': 'no-cache', 'X-Accel-Buffering': 'no'}
)Kurze Überprüfung
Testen Sie Ihr Verständnis der gestreamten Ausgabe in LangChain.
Zusammenfassung der Lektion
In dieser Lektion haben Sie gelernt: Mit stream() und astream() können Sie über Token-Chunks iterieren, sobald sie generiert werden, und so die lange Wartezeit auf die vollständige Antwort vermeiden. StreamingResponse in FastAPI liefert Tokens im SSE-Format in Echtzeit an Browser-Clients. astream_events() stellt detaillierte Event-Hooks für jeden Schritt der Kette bereit, einschließlich Tool-Aufrufen und Zwischenausgaben. Als Nächstes beschäftigen wir uns mit der Speicherverwaltung für Gespräche mit mehreren Dialogrunden.
Häufig gestellte Fragen
Ist die Lektion „Ausgaben in LangChain streamen“ kostenlos?
Ja — der vollständige Text von „Ausgaben in LangChain streamen“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des AI Engineering Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der AI Engineering Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Ausgaben in LangChain streamen“?
Sie implementieren Token-Streaming durch LCEL-Chains, sodass Ihre Anwendung jedes Wort beim Eintreffen anzeigt, statt auf die vollständige Antwort zu warten, und dadurch die wahrgenommene Latenz verb… Du übst AI Engineering Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um AI Engineering Academy zu starten?
Keine Vorkenntnisse erforderlich. AI Engineering Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Ausgaben in LangChain streamen“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser AI Engineering Academy-Lektion Code schreiben und ausführen?
Ja. Jede AI Engineering Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- LangChain-Architektur und zentrale Abstraktionen
- Mit LCEL Chains erstellen
- Verzweigte und parallele Chains
- Ausgaben in LangChain streamen