Skip to content

Akış Protokolü ve Gerçek Zamanlı Çıktı

NDJSON akış olayları, kısmi mesajlar ve akış işleme

13 dk okuma

Agent arayüzünüz 45 saniye boyunca hiçbir şey göstermiyor, sonra tüm yanıtı bir seferde aktarıyor. Kullanıcılar donmuş olduğunu düşünüyor. Çözüm tek bir bayrak — --output-format stream-json — ve birkaç satır NDJSON ayrıştırma.

NDJSON stream protocol: system, assistant, tool_use, tool_result, result event flowsystemassistanttool_usetool_resultresultinittextReadstdout$0.04turn cycle

stream-json protokolü, Claude CLI’ı gerçek zamanlı bir olay yayıcıya dönüştürür. Tüm yanıtı beklemek yerine, olaylar gerçekleşirken NDJSON olayları alırsınız — init meta verileri, token token metin, araç çağrıları, araç sonuçları, hız sınırları ve nihai özet. NDJSON (Newline Delimited JSON), satır başına bir JSON nesnesi anlamına gelir. Her olay, \n ile ayrılmış eksiksiz bir JSON nesnesidir. --input-format stream-json ile birleştirildiğinde, gerçek zamanlı arayüzler, agent zincirleri ve izleme panoları oluşturmak için çift yönlü iletişim sağlar.

Bu bölüme ihtiyacınız var eğer: özel arayüzler oluşturuyorsanız, gerçek zamanlı ilerleme çubukları uyguluyorsanız, panolar oluşturuyorsanız veya akış davranışını hata ayıklıyorsanız. Temel otomasyon için JSON modu daha basittir.

Akışı Etkinleştirme

Akış protokolünü etkinleştirmek için iki bayrak gerekir: --output-format stream-json çıktı modunu ayarlar ve --verbose tam oturum meta verilerini içeren init olayının yayılmasını sağlar. --verbose olmadan init olayı eksik olabilir — her zaman ikisini birlikte kullanın.

Basit bir prompt'u akışla gönderme
$ claude -p "Explain recursion" --output-format stream-json --verbose
{"type": "system","subtype": "init","model": "claude-opus-4-6","session_id": "380bd0cd-...","tools":["Bash","Read","Edit","..."]}
{"type": "assistant","message":{"content":[{"type": "text","text": "Recursion is a technique where..."}]}}
{"type": "rate_limit_event","rate_limit_info":{"status": "allowed","resetsAt": 1773810000}}
{"type": "result","subtype": "success","duration_ms": 3216,"total_cost_usd": 0.01590}

Çıktıdaki her satır eksiksiz, bağımsız bir JSON nesnesidir. Araç kullanımı olmayan basit bir prompt tam olarak dört olay üretir: system (init), assistant (yanıt), rate_limit_event (API durumu) ve result (nihai zarf).

Olay Türleri

Her olayın ne temsil ettiğini söyleyen bir type alanı vardır. Çoğu oturum 5 temel olay üretir: session_started -> input_sent -> started_working -> output_message -> completed. Diğerleri (tool_use, tool_result vb.) araç kullanımı, yeniden denemeler ve kısmi mesaj akışına bağlı olarak koşullu görünür.

İşte tam katalog:

Akış Olay Türleri

Olay TürüAlt Tür / TetikleyiciNe Zaman TetiklenirTemel Alanlar
systeminitHer akıştaki ilk olaytools, mcp_servers, model, session_id, permissionMode
systemapi_retryYeniden denenebilir API hatasında (hız sınırı, sunucu hatası)attempt, max_retries, retry_delay_ms, error
assistantModel bir yanıt ürettikten sonramessage.content[], message.usage
userBir araç çalıştırılıp sonuçları döndükten sonraAraç sonuç içeriği
rate_limit_eventHer API çağrısından sonra (izin verildiğinde bile her zaman tetiklenir)rate_limit_info.status, resetsAt
resultsuccess veya error_*Akıştaki son olay—output-format json zarfıyla aynı alanlar
stream_eventmessage_start, content_block_delta, message_stop, …Yalnızca —include-partial-messages ileevent.delta.text — artımlı token parçaları

Claude araç kullandığında, olaylar serpişir: bir assistant olayı araç çağrısını içerir (content[].type === "tool_use"), ardından araç sonucunu içeren bir user olayı gelir. Bu döngü, nihai assistant yanıtından önce her araç çağrısı için tekrarlanır.

Aşağıdaki etkileşimli görselleştirici gerçek bir akış oturumunu oynatır. Olayların nasıl sırayla geldiğini ve yanıtı nasıl oluşturduğunu izleyin.

Stream VisualizerNDJSON REPLAY
Event 0 of 4
Press Play to start the stream
Try This

Akış olaylarını kendiniz görün:

claude -p “Say hello” —output-format stream-json 2>/dev/null | head -5

İlk olayın session_id içeren init olduğuna ve sonraki olayların metin parçalarını içeren assistant olduğuna dikkat edin. Yalnızca metni çıkarmak için jq -r ‘select(.type==“assistant”) | .content’ ile pipe edin.

Init Olayı

Her akıştaki ilk olay, oturum meta verilerini içeren bir system/init yüküdür. Bu, protokoldeki en zengin olaydır ve herhangi bir arayüz veya izleme sistemini başlatmanın anahtarıdır.

Sistem Init Olayıartifacts/16/stream_basic.jsonl
1{
2 "type": "system",
3 "subtype": "init",
4 "cwd": "/Users/tunaozmen/claude-cli-mastery",A
5 "session_id": "380bd0cd-2017-414d-b3c3-2101041c4d3b",B
6 "tools": [C
7 "Task",
8 "Bash",
9 "Glob",
10 "Grep",
11 "Read",D
12 "Edit",
13 "Write",E
14 "..."
15 ],
16 "mcp_servers": [
17 {
18 "name": "chrome-devtools",
19 "status": "connected"
20 },
21 {
22 "name": "claude.ai Notion",
23 "status": "connected"
24 },
25 {
26 "name": "claude.ai Gmail",
27 "status": "needs-auth"
28 }
29 ],
30 "model": "claude-opus-4-6",
31 "permissionMode": "default",
32 "claude_code_version": "2.1.74",
33 "agents": [
34 "general-purpose",
35 "Explore",
36 "Plan",
37 "claude-code-guide"
38 ],
39 "skills": [
40 "debug",
41 "simplify",
42 "batch",
43 "loop",
44 "claude-api"
45 ],
46 "plugins": [
47 {
48 "name": "rust-analyzer-lsp"
49 }
50 ],
51 "fast_mode_state": "off"
52}
ABu konuşma icin UUID — daha sonra devam etmek icin --resume'a gecirin
BTum mevcut araclar — --allowedTools kisitlamalarinin etkili oldugunu dogrulayin
CMCP sunucu sagligi — 'connected' ile 'needs-auth' durumunu kontrol edin
DHangi model calisiyor — surum sabitleme icin kullanisli
ECLI surumu — CI ardisik duzenlerinde uyumluluk kontrolu

Init olayını sağlık kontrolleri (MCP sunucu bağlantılarını doğrulama), araç denetimleri (izin listelerini onaylama), sürüm sabitleme (claude_code_version kontrolü) ve arayüz başlatma (araç listeleri ve model adlarını doldurma) için kullanın.

Kısmi Mesajlar

Varsayılan olarak, yanıtın tamamını tek bir assistant olayında alırsınız. --include-partial-messages eklemek, her token parçası için stream_event girdileri ekleyerek metin üretildikçe render eden daktilo tarzı arayüzleri mümkün kılar.

Kısmi mesajlarla daktilo efekti
$ claude -p "Say hello" --output-format stream-json --verbose --include-partial-messages | \
$ jq -rj 'select(.type == "stream_event" and .event.delta.type? == "text_delta") | .event.delta.text'
# token token cikti:
Hello! How can I help you today?

stream_event girdilerinin sırası katı bir düzeni izler:

  1. message_start — model kimliği, boş içerik
  2. content_block_start — yeni metin bloğu başlar (indeks 0)
  3. content_block_delta — artımlı token’lar: "\n\nHello", sonra "! How", sonra " can I help you today?"
  4. content_block_stop — blok tamamlandı
  5. message_deltastop_reason: "end_turn", nihai kullanım istatistikleri
  6. message_stop — akış tamamlandı

Tam assistant olayı (birleştirilmiş tam mesajla) tüm delta’lardan sonra görünür. Daktilo arayüzü için content_block_delta olaylarını gerçek zamanlı tüketin — assistant olayını beklemeyin.

Tek Bir Token Delta Olayı
1{
2 "type": "stream_event",
3 "event": {
4 "type": "content_block_delta",A
5 "index": 0,
6 "delta": {
7 "type": "text_delta",B
8 "text": "! How"
9 }
10 },
11 "session_id": "c5d6f705-4fab-46a5-97af-49ad226a5593"
12}
Acontent_block_delta her token parcasini tasir
BTam yaniti olusturmak icin her delta.text'i birlestirin
Note

—include-partial-messages yüksek hacimlidir. 500 kelimelik bir yanıt yüzlerce stream_event satırı üretebilir. Bunu yalnızca daktilo arayüzleri için etkinleştirin, yalnızca nihai sonuca ihtiyaç duyduğunuz veri ardışık düzenleri için değil.

Çift Yönlü İletişim

Akış protokolü yalnızca çıktı değildir. --input-format stream-json eklemek, stdout’ta olaylar alırken stdin aracılığıyla Claude’a mesaj göndermenizi sağlar — gerçek zamanlı arayüzler, agent orkestrasyon sistemleri ve özel IDE entegrasyonları oluşturmayı mümkün kılar.

Terminal window
# Tam çift yönlü mod
claude -p --input-format stream-json --output-format stream-json --verbose

Bu bayraklar için katı eşleşme kuralları vardır:

Giriş/Çıkış Bayrak Gereksinimleri

BayrakGerektirirAmaç
—input-format stream-json—output-format stream-jsonTakip mesajları için stdin’de stream-json kabul et
—replay-user-messagesHem —input-format hem de —output-format stream-json olarak ayarlıOnay için kullanıcı mesajlarını stdout’a geri yansıt

Birinin stream-json çıktısını diğerine pipe ederek Claude örneklerini de zincirleyebilirsiniz:

Terminal window
# İlk Claude analiz eder, ikinci Claude özetler
claude -p "Analyze auth.py" --output-format stream-json --verbose | \
claude -p "Summarize the analysis" --input-format stream-json --output-format stream-json --verbose

İkinci örnek, birinciden gelen tüm olayları — araç sonuçları ve nihai yanıt dahil — kendi görevi için bağlam olarak alır.

Gerçek Akış Yükü

İşte gerçek bir CLI çağrısından tam dört olaylık akış. Bu, araç kullanımı olmayan basit bir prompt için --output-format stream-json --verbose’un tam olarak ürettiği şeydir.

Tam 4 Olaylık Akışartifacts/16/stream_basic.jsonl
1{
2 "event_1_init": {1
3 "type": "system",
4 "subtype": "init",
5 "session_id": "380bd0cd-2017-414d-b3c3-2101041c4d3b",
6 "model": "claude-opus-4-6",
7 "tools": [
8 "Task",
9 "Bash",
10 "Glob",
11 "Grep",
12 "Read",
13 "Edit",
14 "Write"2
15 ],
16 "mcp_servers": [
17 {
18 "name": "chrome-devtools",
19 "status": "connected"
20 },
21 {
22 "name": "claude.ai Notion",
23 "status": "connected"
24 }
25 ],
26 "permissionMode": "default",
27 "claude_code_version": "2.1.74"3
28 },
29 "event_2_assistant": {
30 "type": "assistant",
31 "message": {
32 "model": "claude-opus-4-6",
33 "role": "assistant",
34 "content": [
35 {4
36 "type": "text",
37 "text": "test stream"
38 }
39 ],
40 "usage": {
41 "input_tokens": 3,
42 "cache_creation_input_tokens": 1381,
43 "cache_read_input_tokens": 14253,
44 "output_tokens": 1
45 }
46 }
47 },
48 "event_3_rate_limit": {
49 "type": "rate_limit_event",
50 "rate_limit_info": {
51 "status": "allowed",
52 "resetsAt": 1773810000,
53 "rateLimitType": "five_hour",
54 "overageStatus": "rejected"
55 }
56 },
57 "event_4_result": {
58 "type": "result",
59 "subtype": "success",
60 "duration_ms": 3216,
61 "num_turns": 1,
62 "result": "test stream",
63 "total_cost_usd": 0.0159,
64 "session_id": "380bd0cd-2017-414d-b3c3-2101041c4d3b",
65 "usage": {
66 "input_tokens": 3,
67 "cache_creation_input_tokens": 0,
68 "cache_read_input_tokens": 14253,
69 "output_tokens": 8
70 }
71 }
72}
1Init olayi — her zaman ilk, oturum meta verilerini icerir
2Assistant olayi — modelin tam yaniti
3Hiz siniri olayi — her zaman tetiklenir, status alanini kontrol edin
4Sonuc olayi — her zaman son, --output-format json ile ayni

Gerçek bir akışta, bu dört nesnenin her biri aralarında virgül veya köşeli parantez olmadan kendi satırında olurdu. Yukarıda gösterilen iç içe yapı, okunabilirlik için gruplandırılmıştır — gerçek NDJSON çıktısı satır başına bir JSON nesnesidir.

Akış Olaylarını Ayrıştırma

İşte bir Claude süreci başlatan ve ayrıştırılmış olayları geldikçe veren bir Node.js üreteci:

import { spawn } from 'child_process';
import { createInterface } from 'readline';
async function* streamClaude(prompt, { partial = false } = {}) {
const args = ['-p', prompt, '--output-format', 'stream-json', '--verbose'];
if (partial) args.push('--include-partial-messages');
const proc = spawn('claude', args);
const rl = createInterface({ input: proc.stdout });
for await (const line of rl) {
if (!line.trim()) continue; // bos satirlari atla
try {
yield JSON.parse(line);
} catch (err) {
console.warn(`Hatali JSON atlaniyor: ${line}`, err);
}
}
}
// Olay turune gore dagit
for await (const event of streamClaude('Explain recursion')) {
switch (event.type) {
case 'system':
if (event.subtype === 'init') {
console.log(`Model: ${event.model}, Tools: ${event.tools.length}`);
}
break;
case 'assistant':
console.log(`Response: ${event.message.content[0].text}`);
break;
case 'result':
console.log(`Cost: $${event.total_cost_usd.toFixed(4)}`);
break;
}
}

Üretim ayrıştırıcıları şunları yönetmelidir: eksik satırlar (\n’ye kadar tamponla), hatalı JSON (günlükle ve atla), beklenmeyen olay türleri (uyar ama devam et). Yukarıdaki örnek temel hata yönetimini gösterir — stdin’i parçalar halinde işliyorsanız tamponlama mantığı ekleyin.

Daktilo efekti için kısmi mesajları etkinleştirin ve metin delta’larını filtreleyin:

process.stdout.write('Claude says: ');
for await (const event of streamClaude('Write a haiku', { partial: true })) {
if (event.type === 'stream_event') {
const delta = event.event?.delta;
if (delta?.type === 'text_delta') {
process.stdout.write(delta.text);
}
}
}
console.log();

Yeniden Deneme Olayları

API yeniden denenebilir bir hata döndürdüğünde (hız sınırı veya sunucu hatası), yeniden deneme girişiminden önce bir system/api_retry olayı görünür. Bunu, arayüzünüzde yeniden deneme ilerlemesini göstermek veya özel geri çekilme mantığı uygulamak için kullanın.

{
"type": "system",
"subtype": "api_retry",
"attempt": 1,
"max_retries": 5,
"retry_delay_ms": 2000,
"error_status": 529,
"error": "server_error"
}
Gotcha

—verbose, —output-format stream-json ile birlikte gereklidir. Onsuz, oturum meta verilerini içeren init olayı yayılmayabilir. Her zaman iki bayrağı birlikte kullanın: —output-format stream-json —verbose.

Gotcha

Her satır bağımsız JSON’dur — bu NDJSON’dur, JSON dizisi değil. Nesneler arasında virgül yoktur ve sarmalayan köşeli parantez yoktur. Satır satır JSON.parse(line) ile ayrıştırın. Tam akışta JSON.parse(entireOutput) çağırmak başarısız olur.

Tip

result olayı her zaman sondadır ve —output-format json ile aynı verileri içerir. Tek bir akışta hem gerçek zamanlı akış olaylarını hem de nihai özet zarfını alırsınız — sonuç meta verilerini almak için ikinci bir çağrı yapmanıza gerek yoktur.

Bunu Uygulamada Görün

Üretim kodunun NDJSON akışlarını nasıl ayrıştırdığını ve gerçek zamanlı arayüz için SSE’ye nasıl köprülediğini MR Reviewer Oluşturma, Bölüm 2: Akıştan SSE’ye bölümünde görün.

Now Do This

İlk NDJSON olaylarınızı görmek için claude -p “Explain sessions in one paragraph” —output-format stream-json 2>/dev/null | head -5 çalıştırın. init olayının herhangi bir metin gelmeden önce session_id’yi içerdiğine dikkat edin — Claude yanıt vermeye başlamadan önce bile oturumu izlemeye başlayabilirsiniz.