LangChain'de Akışlı Çıktı
Uygulamanızın tam yanıtı beklemek yerine gelen her sözcüğü göstermesi için LCEL zincirleri üzerinden token akışını uygulayın; böylece algılanan gecikmeyi azaltın.
LangChain'de Akışlı Çıktı, CoddyKit'te ücretsiz bir AI Engineering Academy dersidir. Bu, 4 dersinin 4. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, AI Engineering Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. AI Engineering Academy kursu toplamda 4 dersten oluşur.
Akış Neden Önemlidir
Akış olmadan kullanıcılar, LLM'nin üretmeyi bitirmesini beklerken boş bir ekrana bakar; uzun yanıtlar için bu süre 5–30 saniye sürebilir. Akış ile belirteçler üretildikleri anda görünür ve anında geri bildirim sağlanır. Bu, algılanan yanıt verme hızını büyük ölçüde iyileştirir. LangChain'in LCEL yapısı, .stream() çağrıldığında akışı tüm zincir boyunca otomatik olarak aktarır.
.stream() ile Temel Akış
Her LCEL zinciri, parçalar üzerinde bir yineleyici döndüren .stream() yöntemini sunar. StrOutputParser ile biten bir zincirde her parça bir dize bölümüdür. Parçalar üzerinde yineleme yaparak geldikleri anda yazdırabilir veya dışarı verebilirsiniz. Akış HTTP düzeyinde gerçekleşir; OpenAI API'sinden gelen her belirteç ulaşır ulaşmaz ayrıştırıcı üzerinden iletilir.
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 newline.astream() ile Eşzamansız Akış
.astream(), .stream() yönteminin eşzamansız sürümüdür. Eşzamansız bir yineleyici döndürür ve bu yineleyiciyi async for ile tüketirsiniz. İstek işleyicisinin bir eş yordam olduğu FastAPI, Starlette ve diğer eşzamansız web çerçevelerinde doğru yaklaşım budur. Eşzamansız bir işleyicide eşzamanlı akış kullanmak olay döngüsünü engeller.
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())StreamingResponse ile FastAPI'de Akış
FastAPI'de metin belirteçlerini tarayıcıya aktarmak için eşzamansız bir oluşturucuyu StreamingResponse içinde media_type='text/plain' ile sarın. Sunucu tarafından gönderilen olaylar (SSE) için media_type='text/event-stream' kullanın ve her parçayı data: ...\n\n biçiminde düzenleyin. Böylece tarayıcı, yanıtın tamamını beklemeden belirteçleri üretildikleri anda alır.
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'Ara Adımlar Üzerinden Akış
LCEL zincirleri, akışı bunu destekleyen her adım üzerinden aktarır. StrOutputParser akışın farkındadır ve parçaları hemen iletir. Ancak JsonOutputParser gibi bazı ayrıştırıcıların ayrıştırma işleminden önce çıktının tamamını arabelleğe alması gerekir; bu da akışı keser. LangChain bunu açıkça ortaya koyar: Bir adım akışla uyumlu değilse çıktıyı sonraki adıma aktarmadan önce biriktirir.
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 inAyrıntılı Denetim için astream_events
.astream_events(), yalnızca son çıktı için değil, zincirdeki her adım için olaylar oluşturan daha ayrıntılı bir akış API'si sunar. Her olayda bir kind alanı (on_chain_start, on_llm_stream, on_chain_end) ve bir data yükü bulunur. Bu sayede araç çağrısı sonuçlarını, ara akıl yürütmeyi ve son çıktıyı bir kullanıcı arayüzünün farklı bölümlerine ayrı ayrı aktarabilirsiniz.
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"]}]')Akış Çıktısını Arabelleğe Alma
Bazen belirteçleri kullanıcıya hem aktarmanız hem de eksiksiz yanıtı günlük kaydı veya başka işlemler için yakalamanız gerekir. .astream() yöntemini bir liste biriktiriciyle kullanın. Döngüden sonra parçaları birleştirerek tam metni elde edin. Bu yaklaşım, akış çıktısını gerçek zamanlı göstermenize ve aynı zamanda eksiksiz yanıtı analiz, önbelleğe alma veya değerlendirme amacıyla saklamanıza olanak tanır.
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 completeAraç Çağrılarıyla Akış
Bir model, akış halindeki bir yanıtta araç çağrısı oluşturduğunda işlev bağımsız değişkenleri belirteç parçaları olarak gelir. Aracı çalıştırmadan önce JSON bağımsız değişken dizesini araç çağrısı tamamlanana kadar arabelleğe almanız gerekir. LangChain bunu aracı yürütücülerinde otomatik olarak ele alır; ancak özel bir akış döngüsü oluşturuyorsanız finish_reason değerini denetlemeli ve tool_call.function.arguments parçalarını biriktirmelisiniz.
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.argumentsAkışta İptal ve Zaman Aşımı
Uzun akış yanıtları iptal desteği gerektirir. Eşzamansız Python'da akışı saran bir asyncio.Task öğesini iptal edebilirsiniz. FastAPI'de StreamingResponse kullanılırken çerçeve, istemci bağlantısının kesilmesi durumundaki iptali otomatik olarak yönetir. OpenAI istemcisinin timeout parametresiyle bir zaman aşımı belirleyin veya en uzun sürenin ardından akışı durdurmak için asyncio.wait_for() ile sarın.
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]')JavaScript ile İstemci Tarafında SSE
Ön uçta, tarayıcının yerleşik EventSource API'si sunucu tarafından gönderilen olayları tüketir. FastAPI uç noktası data: token\n\n parçalarını gönderdiğinde EventSource her biri için bir message olayı tetikler. Daktilo efekti oluşturmak için her belirteci geldiği anda DOM'a ekleyin. Daha fazla denetim için fetch() ile response.body.getReader() kullanmak, akışa tam erişim sağlar.
// 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);
}Akış için En İyi Uygulamalar
Akış uygularken şu en iyi uygulamaları izleyin: arabelleğe almayı önlemek için stdout'a yazdırırken her zaman flush=True kullanın. Akış sırasında doğru belirteç sayılarına ihtiyacınız varsa stream_usage=True ayarını yapın. İstemcinin bağlantıyı ne zaman kapatacağını anlayabilmesi için SSE akışlarının sonunda data: [DONE]\n\n sonlandırıcısını gönderin. Belirteçlerin artımlı olarak ulaştığını doğrulamak için akış uç noktalarını curl --no-buffer ile test edin.
# 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'}
)Kısa Kontrol
LangChain'de akış çıktısını ne kadar anladığınızı test edin.
Ders Özeti
Bu derste şunları öğrendiniz: stream() ve astream(), belirteç parçaları üretilirken bunlar üzerinde yineleme yapmanızı sağlayarak yanıtın tamamı için gereken uzun beklemeyi ortadan kaldırır; SSE biçimli FastAPI içindeki StreamingResponse, belirteçleri tarayıcı istemcilerine gerçek zamanlı olarak iletir; astream_events() ise araç çağrıları ve ara çıktılar da dahil olmak üzere zincirdeki her adım için ayrıntılı olay kancaları sunar. Sırada çok turlu konuşmalar için bellek yönetimini inceleyeceğiz.
Sıkça Sorulan Sorular
“LangChain'de Akışlı Çıktı” dersi ücretsiz mi?
Evet — “LangChain'de Akışlı Çıktı” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve AI Engineering Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. AI Engineering Academy kursu toplamda 4 dersten oluşur.
“LangChain'de Akışlı Çıktı” dersinde ne öğreneceğim?
Uygulamanızın tam yanıtı beklemek yerine gelen her sözcüğü göstermesi için LCEL zincirleri üzerinden token akışını uygulayın; böylece algılanan gecikmeyi azaltın. AI Engineering Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
AI Engineering Academy öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te AI Engineering Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 4. dersidir.
“LangChain'de Akışlı Çıktı” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu AI Engineering Academy dersinde kod yazıp çalıştırabilir miyim?
Evet. Her AI Engineering Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- LangChain Mimarisi ve Temel Soyutlamalar
- LCEL ile Zincirler Oluşturma
- Dallanma ve Paralel Zincirler
- LangChain'de Akışlı Çıktı