Files
ai-agent-book/book-tr/gen_ch9_figs.py
T
liqiang b119135836
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
2026-08-20 13:12:50 +00:00

1053 lines
50 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""[DEPRECATED] Old Chapter 9 (multi-Agent) figure generator.
⚠️ DO NOT RUN: After the 2026-03-12 refactoring, chapter numbers changed (original Ch 9 → Ch 10).
The figures generated by this file actually correspond to the current [Chapter 10] content (multi-Agent collaboration), but are still saved as fig9-*.svg.
Running it would overwrite the current correct [Chapter 9] (multimodal & real-time interaction) figures, causing content misalignment.
The current correct Chapter 9 SVGs (multimodal/voice/Computer Use/VLA/Sim2Real) were
renamed from original fig8-*.svg in commit a33c88f on 2026-03-12; the current correct Chapter 10 SVGs
(multi-Agent collaboration) were **manually migrated** from the content originally generated by this file to fig10-*.svg.
To regenerate figures from this file, you should instead generate fig10-*.svg and reference them according to chapter10.md.
Original (now Ch 10) figure list:
fig10-1: Shared context vs independent context (concrete context windows)
fig10-2: Phase-based role switching (prompt/tool-set changes per phase)
fig10-3: Proposer-Reviewer loop (Slidev PPT iterative feedback)
fig10-4: Manager sequential coordination (sequential sub-agent delegation)
fig10-5: Book translation Agent architecture (NEW — Exp 10.4)
fig10-6: Manager parallel coordination (concurrent agents + message bus)
fig10-7: Phone + Computer dual Agent (NEW — Exp 10.5/10.6)
fig10-8: Parallel web scraping (NEW — Exp 10.7)
fig10-9: Handoff chain pattern (peer control passing)
fig10-10: MetaGPT SOP pipeline (PM→Arch→Eng→QA with artifacts)
fig10-11: AI town architecture (memory stream + reflection + planning)
fig10-12: Voice Werewolf Agent system (NEW — Exp 10.9)
"""
import sys
print(
"ERROR: gen_ch9_figs.py is DEPRECATED. Running it would overwrite the\n"
"correct Chapter 9 (multimodal) figures with old Chapter 10 (multi-agent) content.\n"
"See module docstring at the top of this file for the rename history.",
file=sys.stderr,
)
sys.exit(2)
import sys, os
sys.path.insert(0, os.path.dirname(__file__))
from svg_lib import (
SVG, COLORS, FONT, MONO,
FS_TITLE, FS_BODY, FS_SMALL, FS_TINY, FS_LABEL, STROKE_W, CORNER_R,
_escape,
)
OUT = os.path.join(os.path.dirname(__file__), 'images')
# ════════════════════════════════════════════════════════════════════
# fig9-1: Shared context vs independent context
# ════════════════════════════════════════════════════════════════════
def fig9_1():
W, H = 780, 560
s = SVG(W, H)
s.text(W // 2, 30, 'Paylaşılan bağlam ile bağımsız bağlam karşılaştırması', size=FS_TITLE, bold=True)
col_w = 350
lx, rx = 20, W - col_w - 20
# ── Left: shared context ──
s.group_box(lx, 55, col_w, 480, 'Paylaşılan bağlam (tek Ajan, birden çok aşama)')
ctx_x, ctx_w = lx + 15, col_w - 30
phases = [
('Aşama 1: Gereksinim Analisti', 'medium', [
'sys: "Sorumluluğun gereksinimleri tam anlamak..."',
'tools: [ask_question, save_req]',
'user: "CSV analiz betiği yaz"',
'agent: "Hangi dosya türleri işlenmeli?"',
]),
('Aşama 2: Yazılım Mühendisi', 'light', [
'sys: "Onaylanan gereksinimlere göre kod yaz..."',
'tools: [write_file, execute_code]',
'agent: write_file("analyze.py", ...)',
'agent: execute_code("python test.py")',
]),
('Aşama 3: Kod İnceleyici', 'light', [
'sys: "Kod kalitesini ve güvenliğini incele..."',
'tools: [run_linter, run_tests]',
'agent: run_linter → 2 uyarı',
'agent: approve_code()',
]),
]
cy = 82
for title, fill, lines in phases:
ph = 18 + len(lines) * 18 + 10
s.rect(ctx_x, cy, ctx_w, ph, fill=fill, rx=4)
s.text(ctx_x + 8, cy + 14, title, size=FS_SMALL, bold=True, anchor='start')
for i, ln in enumerate(lines):
s.mono(ctx_x + 12, cy + 32 + i * 18, ln, size=12)
cy += ph + 2
s.rect(ctx_x, cy, ctx_w, 28, fill='code_bg', rx=3)
s.text(ctx_x + ctx_w // 2, cy + 14, '↑ Tüm aşamalar aynı konuşma geçmişini paylaşır', size=FS_TINY, bold=True)
cy += 36
s.text(lx + col_w // 2, cy + 10, '✓ Tam yürütme izi', size=FS_SMALL, fill='text_light')
s.text(lx + col_w // 2, cy + 32, '✗ Bağlam hızla genişler', size=FS_SMALL, fill='text_light')
# ── Right: independent context ──
s.group_box(rx, 55, col_w, 480, 'Bağımsız bağlam (gerçek çoklu Ajan)')
agents_data = [
('Sözlük Ajanı', [
'sys: "Terimleri belirle ve çevir..."',
'tools: [search_dict, write_file]',
'→ glossary.json',
]),
('Çeviri Ajanı', [
'sys: "Bu bölümü çevir..."',
'tools: [read_file, write_file]',
'→ chapter3_zh.md',
]),
('Redaksiyon Ajanı', [
'sys: "Terim tutarlılığını kontrol et..."',
'tools: [read_file, write_file]',
'→ review_report.md',
]),
]
ay = 82
for name, lines in agents_data:
ah = 18 + len(lines) * 18 + 8
s.rect(rx + 15, ay, ctx_w, ah, fill='light', rx=4)
s.text(rx + 23, ay + 14, name, size=FS_SMALL, bold=True, anchor='start')
for i, ln in enumerate(lines):
s.mono(rx + 27, ay + 32 + i * 18, ln, size=12)
ay += ah + 8
fs_y = ay + 5
s.rect(rx + 15, fs_y, ctx_w, 65, fill='medium', rx=4)
s.text(rx + 15 + ctx_w // 2, fs_y + 16, 'Paylaşılan dosya sistemi', size=FS_SMALL, bold=True)
files = ['glossary.json', 'chapter3_zh.md', 'review_report.md']
s.mono(rx + 27, fs_y + 38, ' '.join(files), size=11)
s.text(rx + 15 + ctx_w // 2, fs_y + 55, '+ Araç çağrısı parametreleri yapılandırılmış veri taşır', size=FS_TINY, fill='text_light')
s.text(rx + col_w // 2, fs_y + 82, '✓ Modüler · Genişletilebilir · Paralel', size=FS_SMALL, fill='text_light')
s.text(rx + col_w // 2, fs_y + 104, '✗ Bilgi senkronizasyonu karmaşık', size=FS_SMALL, fill='text_light')
s.save(os.path.join(OUT, 'fig9-1.svg'))
# ════════════════════════════════════════════════════════════════════
# fig9-2: Phase-based role switching
# ════════════════════════════════════════════════════════════════════
def fig9_2():
W, H = 780, 520
s = SVG(W, H)
s.text(W // 2, 28, 'Aşama bazlı rol değişimi: Coding Agent üç aşama', size=FS_TITLE, bold=True)
phases = [
('Gereksinim Analisti', 'medium',
'"Sorumluluğun gereksinimleri tam anlamak.\nHemen uygulamaya geçme; bu aşamada\ngörevin soru sormak ve onaylamak."',
['ask_clarifying_question(q)', 'save_requirement(k, v)', 'complete_requirements_analysis()'],
'complete_requirements_analysis()'),
('Yazılım Mühendisi', 'light',
'"Onaylanan gereksinimlere göre yüksek kaliteli Python kodu yaz.\nModüler tasarım ve hata işleme en iyi uygulamalarını izle."',
['write_file(path, content)', 'read_file(path)', 'execute_code(code)'],
'submit_for_review()'),
('Kod İnceleyici', '#e8e8e8',
'"Kod kalitesini birden çok boyutta değerlendir: \nişlevsel doğruluk, kodlama standartları, \nve güvenlik. Eleştirel düşün."',
['run_linter(file)', 'run_tests(file)', 'analyze_complexity(file)'],
None),
]
s.rect(30, 55, W - 60, 28, fill='code_bg', rx=3)
s.text(W // 2, 69, '▼ Aynı bağlam içinde sürekli akış — konuşma geçmişi aşamalar boyunca tam korunur ▼', size=FS_SMALL, bold=True)
pw = 225
gap = 18
px_start = (W - 3 * pw - 2 * gap) // 2
py = 100
for i, (role, fill, prompt, tools, trigger) in enumerate(phases):
x = px_start + i * (pw + gap)
s.rect(x, py, pw, 380, fill=fill, rx=6)
s.text(x + pw // 2, py + 22, f'Aşama {i + 1}', size=FS_TINY, fill='text_light')
s.text(x + pw // 2, py + 42, role, size=FS_BODY, bold=True)
s.rect(x + 8, py + 60, pw - 16, 88, fill='code_bg', rx=3)
s.text(x + 14, py + 75, 'Sistem İstemi', size=FS_TINY, fill='text_light', anchor='start')
for j, ln in enumerate(prompt.split('\n')):
s.text(x + 14, py + 92 + j * 16, ln, size=12, anchor='start', fill='text_light')
s.rect(x + 8, py + 158, pw - 16, 18 + len(tools) * 20, fill='white', rx=3)
s.text(x + 14, py + 172, 'Araç Kümesi', size=FS_TINY, fill='text_light', anchor='start')
for j, tool in enumerate(tools):
s.mono(x + 14, py + 190 + j * 20, tool, size=11)
if trigger:
ty = py + 290
s.rect(x + 8, ty, pw - 16, 48, fill='dark', rx=12)
s.text(x + pw // 2, ty + 16, 'Geçişi Tetikle', size=FS_TINY, fill='white')
s.mono(x + pw // 2, ty + 34, trigger, size=10, anchor='middle', fill='white')
if i < 2:
ax1 = x + pw + 2
ax2 = x + pw + gap - 2
ay = py + 310
s.arrow(ax1, ay, ax2, ay)
s.text(W // 2, H - 10, 'Rol Geçişi: Sistem istemini + araç kümesini güncelle, konuşma geçmişi ve durum kesintisiz korunur',
size=FS_SMALL, fill='text_light')
s.save(os.path.join(OUT, 'fig9-2.svg'))
# ════════════════════════════════════════════════════════════════════
# fig9-3: Proposer-Reviewer Loop (Slidev PPT Generation)
# ════════════════════════════════════════════════════════════════════
def fig9_3():
W, H = 780, 520
s = SVG(W, H)
s.text(W // 2, 28, 'Proposer-Reviewer Döngüsü: Slidev PPT Üretimi', size=FS_TITLE, bold=True)
# Editor (Proposer)
ex, ey, ew, eh = 30, 65, 300, 200
s.rect(ex, ey, ew, eh, fill='light')
s.text(ex + ew // 2, ey + 22, 'Proposer Agent', size=FS_BODY, bold=True)
s.text(ex + 12, ey + 48, 'Girdi: Genişletilmiş makale özeti (2000 karakter)', size=FS_TINY, anchor='start', fill='text_light')
editor_lines = [
'---',
'theme: academic',
'---',
'# Transformer Dikkat Mekanizması',
'',
'## Temel Fikir',
'- Self-attention Q·K^T/√d hesaplar',
'- Çok başlı dikkat paralel işler',
]
ch = s.code_block(ex + 10, ey + 62, ew - 20, editor_lines, font_size=11, line_h=14)
s.text(ex + ew // 2, ey + eh - 10, 'İçerik yapısını anla → Slaytlara ayrıştır', size=FS_TINY, fill='text_light')
# Critic (Reviewer)
cx, cy, cw, ch_h = 450, 65, 300, 200
s.rect(cx, cy, cw, ch_h, fill='medium')
s.text(cx + cw // 2, cy + 22, 'Reviewer Agent', size=FS_BODY, bold=True)
s.rect(cx + 10, cy + 42, cw - 20, 38, fill='code_bg', rx=3)
s.text(cx + 18, cy + 55, '① Slidev render → PDF/PNG', size=FS_TINY, anchor='start')
s.text(cx + 18, cy + 70, '② Görsel LLM çok boyutlu değerlendirme', size=FS_TINY, anchor='start')
feedback_items = [
'Sayfa Sorun Türü Önem',
'P3 İçerik çok yoğun Yüksek',
'P7 Yazı çok küçük Orta',
'P11 Renk uyumsuzluğu Düşük',
]
s.rect(cx + 10, cy + 86, cw - 20, 75, fill='code_bg', rx=3)
s.text(cx + 18, cy + 100, 'Yapılandırılmış Geri Bildirim:', size=FS_TINY, anchor='start', bold=True)
for i, fb in enumerate(feedback_items):
s.mono(cx + 18, cy + 118 + i * 15, fb, size=11)
s.text(cx + cw // 2, cy + ch_h - 10, 'Render + görsel analiz → uygulanabilir iyileştirme önerileri', size=FS_TINY, fill='text_light')
# Arrows between Editor and Critic
mid_y1 = ey + 70
mid_y2 = ey + eh - 50
s.arrow(ex + ew + 2, mid_y1, cx - 2, mid_y1)
s.text((ex + ew + cx) / 2, mid_y1 - 12, 'Slidev Kodu', size=FS_SMALL, bold=True)
s.arrow(cx - 2, mid_y2, ex + ew + 2, mid_y2)
s.text((ex + ew + cx) / 2, mid_y2 + 16, 'Yapılandırılmış Geri Bildirim', size=FS_SMALL, bold=True)
# Iteration timeline
iy = 290
s.rect(30, iy, W - 60, 100, fill='code_bg', rx=4)
s.text(W // 2, iy + 18, 'Yinelemeli İyileştirme Süreci', size=FS_BODY, bold=True)
rounds = [
('Tur 1', '12 sayfalık taslak\n5 sorun', 'light'),
('Tur 2', '14 sayfa (yoğun sayfalar bölündü)\n2 sorun', 'light'),
('Tur 3', '14 sayfa (yazı boyutu düzeltildi)\n0 sorun ✓', 'medium'),
]
rw = 190
rx_start = (W - 3 * rw - 2 * 30) // 2
for i, (name, desc, fill) in enumerate(rounds):
rx = rx_start + i * (rw + 30)
ry = iy + 35
s.rect(rx, ry, rw, 52, fill=fill, rx=3)
s.text(rx + 10, ry + 16, name, size=FS_SMALL, bold=True, anchor='start')
for j, ln in enumerate(desc.split('\n')):
s.text(rx + 10, ry + 34 + j * 16, ln, size=FS_TINY, anchor='start', fill='text_light')
if i < 2:
s.arrow(rx + rw + 4, ry + 26, rx + rw + 26, ry + 26, color='dark')
# Why not single agent
wy = 405
s.rect(30, wy, W - 60, 90, fill='light', rx=4)
s.text(W // 2, wy + 20, 'Neden tekli ajan kullanılmıyor?', size=FS_BODY, bold=True)
single_x = 60
dual_x = W // 2 + 20
s.text(single_x, wy + 45, 'Tekli Ajan: Render çıktıları × N tur → bağlam patlaması', size=FS_TINY, anchor='start', fill='text_light')
s.text(single_x, wy + 63, '(1080p ekran görüntüsü = binlerce token × 14 sayfa × 5 tur)', size=FS_TINY, anchor='start', fill='text_light')
s.text(dual_x, wy + 45, 'İkili Ajan: Critic yalnızca mevcut sürümü görür', size=FS_TINY, anchor='start')
s.text(dual_x, wy + 63, 'Editor yalnızca metin geri bildirimini biriktirir → temiz bağlam', size=FS_TINY, anchor='start')
s.save(os.path.join(OUT, 'fig9-3.svg'))
# ════════════════════════════════════════════════════════════════════
# fig9-4: Manager sequential coordination
# ════════════════════════════════════════════════════════════════════
def fig9_4():
W, H = 780, 480
s = SVG(W, H)
s.text(W // 2, 28, 'Manager sıralı koordinasyon: Alt Ajan araç olarak', size=FS_TITLE, bold=True)
# Manager
mx, my, mw, mh = 240, 60, 300, 100
s.rect(mx, my, mw, mh, fill='medium')
s.text(mx + mw // 2, my + 22, 'Manager Agent', size=FS_BODY, bold=True)
s.text(mx + mw // 2, my + 46, 'Görev anlama → ayrıştırma → zamanlama → sentezleme', size=FS_TINY, fill='text_light')
s.text(mx + mw // 2, my + 66, 'Araç kümesi: [call_agent_A, call_agent_B,', size=FS_TINY, fill='text_light')
s.text(mx + mw // 2, my + 82, 'call_agent_C, search, write_file]', size=FS_TINY, fill='text_light')
# Sub-agents in sequence
agents = [
('Alt Ajan A', 'Veri toplama', 'Teknik dokümantasyonu ara\nAnahtar bilgiyi çıkar', 'light'),
('Alt Ajan B', 'Analiz ve işleme', 'Veriyi karşılaştır ve analiz et\nİstatistik raporu üret', 'light'),
('Alt Ajan C', 'Rapor üretimi', 'Nihai raporu yaz\nÇıktıyı biçimlendir', 'light'),
]
aw = 210
ax_start = (W - 3 * aw - 2 * 25) // 2
ay = 240
for i, (name, role, desc, fill) in enumerate(agents):
x = ax_start + i * (aw + 25)
s.rect(x, ay, aw, 120, fill=fill, rx=6)
s.text(x + aw // 2, ay + 20, name, size=FS_SMALL, bold=True)
s.text(x + aw // 2, ay + 40, f'Rol: {role}', size=FS_TINY, fill='text_light')
for j, ln in enumerate(desc.split('\n')):
s.text(x + aw // 2, ay + 62 + j * 18, ln, size=FS_TINY, fill='text_light')
badge_labels = [f'Adım {i + 1}']
s.badge(x + aw - 55, ay + 95, 50, 20, badge_labels[0], fill='dark', font_size=FS_TINY)
# Arrow from Manager to sub-agent
s.arrow(mx + mw // 2 - 100 + i * 100, my + mh + 2,
x + aw // 2, ay - 2, color='dark')
# Sequential arrow between sub-agents
if i < 2:
s.arrow(x + aw + 2, ay + 60, x + aw + 23, ay + 60)
# Data flow
dy = 380
s.rect(30, dy, W - 60, 80, fill='code_bg', rx=4)
s.text(W // 2, dy + 18, 'Sıralı yürütme akışı', size=FS_BODY, bold=True)
flow_items = [
'Manager Ajan A\'yı çağırır',
'→ A veri döndürür',
'→ Manager B\'ye aktarır',
'→ B analiz döndürür',
'→ Manager C\'ye aktarır',
'→ C rapor döndürür',
]
fx_start = 55
for i, item in enumerate(flow_items):
s.text(fx_start + i * 118, dy + 42, item, size=FS_TINY, anchor='start',
fill='text' if 'Call' in item or 'Return' in item else 'text_light')
s.text(W // 2, dy + 65, 'Manager perspektifi: Ajan çağırmak = araç çağırmak (istek gönder → yanıt al)',
size=FS_SMALL, fill='text_light')
s.save(os.path.join(OUT, 'fig9-4.svg'))
# ════════════════════════════════════════════════════════════════════
# fig9-5: Book translation Agent architecture (Exp 9.4)
# ════════════════════════════════════════════════════════════════════
def fig9_5():
W, H = 780, 540
s = SVG(W, H)
s.text(W // 2, 28, 'Deney 9.4: Kitap çeviri Ajanı — Manager modu', size=FS_TITLE, bold=True)
# Manager at top
mx, my, mw, mh = 240, 55, 300, 70
s.rect(mx, my, mw, mh, fill='medium')
s.text(mx + mw // 2, my + 22, 'Manager Agent', size=FS_BODY, bold=True)
s.text(mx + mw // 2, my + 48, 'Görev planlama · İlerleme izleme · İstisna yönetimi · Sonuç sentezi', size=FS_TINY, fill='text_light')
# Three sub-agents
sub_agents = [
(30, 'Sözlük Ajanı', 'Terim sözlüğü',
['Tüm kitabı al → Uzmanlık terimlerini belirle', 'Uzman sözlükleri + çeviri geleneklerini ara', 'Çıktı: glossary.json'],
['{"attention": "dikkat",', ' "transformer": "Transformer",', ' "backprop": "geri yayılım"}']),
(270, 'Çeviri Ajanı ×N', 'Bölüm çevirisi',
['Girdi: bölüm + sözlük + rehber', 'Terimleri sözlüğe göre sıkı çevir', 'Çıktı: chapter{n}_zh.md'],
['"...dikkat mekanizması Query·Key^T\'nin', ' benzerliğini hesaplar..."']),
(520, 'Redaksiyon Ajanı', 'Tam metin incelemesi',
['Terim tutarlılığını tara ve doğrula', 'Akıcılık ve okunabilirliği kontrol et', 'Çıktı: review_report.md'],
['P3: "attention"→"odak" tutarsızlığı', 'P8: Uzun cümle bölünmesi önerildi']),
]
aw = 230
ay = 170
for x, name, role, desc, output in sub_agents:
s.rect(x, ay, aw, 185, fill='light', rx=6)
s.text(x + aw // 2, ay + 20, name, size=FS_SMALL, bold=True)
s.text(x + aw // 2, ay + 38, role, size=FS_TINY, fill='text_light')
for i, ln in enumerate(desc):
s.text(x + 12, ay + 60 + i * 18, ln, size=FS_TINY, anchor='start', fill='text_light')
s.rect(x + 8, ay + 115, aw - 16, 10 + len(output) * 15, fill='code_bg', rx=3)
for i, ln in enumerate(output):
s.mono(x + 14, ay + 128 + i * 15, ln, size=10)
# Arrow from Manager
s.arrow(mx + mw // 2, my + mh + 2, x + aw // 2, ay - 2, color='dark')
# Sequential arrows between sub-agents
s.arrow(30 + aw + 4, ay + 90, 270 - 4, ay + 90, label='Sözlük')
s.arrow(270 + aw + 4, ay + 90, 520 - 4, ay + 90, label='Çeviri')
# Shared file system
fy = 375
s.rect(30, fy, W - 60, 70, fill='medium', rx=6)
s.text(W // 2, fy + 18, 'Paylaşılan dosya sistemi', size=FS_BODY, bold=True)
files = [
('glossary.json', 'Terim sözlüğü'),
('chapter{1..10}_zh.md', 'Bölüm çevirisi'),
('review_report.md', 'İnceleme raporu'),
('translation_guide.md', 'Çeviri rehberi'),
]
fw = (W - 80) // len(files)
for i, (fname, desc) in enumerate(files):
cx = 50 + i * fw + fw // 2
s.mono(cx, fy + 40, fname, size=11, anchor='middle')
s.text(cx, fy + 58, desc, size=FS_TINY, fill='text_light')
# Key insight
ky = 460
s.rect(30, ky, W - 60, 60, fill='code_bg', rx=4)
s.text(W // 2, ky + 18, 'Bağlam izolasyonu avantajları', size=FS_BODY, bold=True)
s.text(W // 2, ky + 42,
'Sözlük: yalnızca terimleri görür | Çeviri: yalnızca mevcut bölüm + sözlüğü görür | Manager: yalnızca dosya indeksini tutar',
size=FS_TINY, fill='text_light')
s.save(os.path.join(OUT, 'fig9-5.svg'))
# ════════════════════════════════════════════════════════════════════
# fig9-6: Manager parallel coordination
# ════════════════════════════════════════════════════════════════════
def fig9_6():
W, H = 780, 500
s = SVG(W, H)
s.text(W // 2, 28, 'Manager paralel koordinasyon: mesaj veri yolu mimarisi', size=FS_TITLE, bold=True)
# Orchestration Agent
ox, oy, ow, oh = 240, 55, 300, 70
s.rect(ox, oy, ow, oh, fill='medium')
s.text(ox + ow // 2, oy + 22, 'Orkestrasyon Ajanı', size=FS_BODY, bold=True)
s.text(ox + ow // 2, oy + 48, 'Paralel zamanlama · Gerçek zamanlı izleme · Sonuç toplama', size=FS_TINY, fill='text_light')
# Message bus
bus_y = 155
s.rect(50, bus_y, W - 100, 36, fill='dark', rx=4)
s.text(W // 2, bus_y + 18, 'Mesaj Veri Yolu', size=FS_SMALL, fill='white', bold=True)
s.arrow(ox + ow // 2, oy + oh + 2, ox + ow // 2, bus_y - 2)
# Parallel agents
agents = [
('Ajan 1', 'Veri toplama', 'Çalışıyor ◎', 'light'),
('Ajan 2', 'İçerik analizi', 'Çalışıyor ◎', 'light'),
('Ajan 3', 'Grafik Üretimi', 'Tamamlandı ✓', 'medium'),
('Ajan 4', 'Biçim Doğrulama', 'Bekliyor ○', 'code_bg'),
]
aw = 160
gap = 14
total = len(agents) * aw + (len(agents) - 1) * gap
ax_start = (W - total) // 2
ay = 225
for i, (name, role, status, fill) in enumerate(agents):
x = ax_start + i * (aw + gap)
s.rect(x, ay, aw, 100, fill=fill, rx=6)
s.text(x + aw // 2, ay + 20, name, size=FS_SMALL, bold=True)
s.text(x + aw // 2, ay + 40, role, size=FS_TINY, fill='text_light')
s.text(x + aw // 2, ay + 65, status, size=FS_TINY,
fill='text_light' if 'Bekliyor' in status else 'text')
s.text(x + aw // 2, ay + 82, 'Bağımsız Bağlam', size=FS_TINY, fill='text_light')
s.arrow(x + aw // 2, bus_y + 38, x + aw // 2, ay - 2, color='dark')
# Message examples
my = 350
s.rect(30, my, W - 60, 125, fill='code_bg', rx=4)
s.text(W // 2, my + 18, 'Mesaj Veri Yolu İletişim Örneği', size=FS_BODY, bold=True)
messages = [
('Orch → Ajan 1', '{"type":"start","task":"arxiv makalelerini topla","params":{"query":"LLM agent"}}'),
('Ajan 3 → Orch', '{"type":"completed","agent_id":"3","result":"charts/fig1.svg üretildi"}'),
('Ajan 1 → Ajan 2', '{"type":"data_ready","source":"agent_1","file":"raw_data.json"}'),
('Orch → Ajan 4', '{"type":"start","depends_on":["agent_2","agent_3"]}'),
]
for i, (sender, msg) in enumerate(messages):
y = my + 40 + i * 22
s.text(40, y, sender, size=FS_TINY, bold=True, anchor='start')
s.mono(200, y, msg, size=10, anchor='start')
s.save(os.path.join(OUT, 'fig9-6.svg'))
# ════════════════════════════════════════════════════════════════════
# fig9-7: Phone + Computer Dual Agent (Exp 9.5/9.6)
# ════════════════════════════════════════════════════════════════════
def fig9_7():
W, H = 780, 560
s = SVG(W, H)
s.text(W // 2, 28, 'Deney 9.5/9.6: Telefon + Bilgisayar İkili Ajan', size=FS_TITLE, bold=True)
# Phone Agent (left)
px, py, pw, ph = 30, 65, 310, 240
s.rect(px, py, pw, ph, fill='light', rx=6)
s.text(px + pw // 2, py + 22, 'Telefon Ajanı', size=FS_BODY, bold=True)
s.text(px + pw // 2, py + 42, 'Node.js · Gerçek Zamanlı Sesli Arama', size=FS_TINY, fill='text_light')
phone_pipeline = [
('Kullanıcı Sesi', 'Mikrofon Girdisi', 'medium'),
('VAD + ASR', 'Silero VAD → STT Metne Dökme', 'light'),
('LLM Çıkarımı', 'Niyeti Anla + Bilgi Çıkar', 'light'),
('TTS Sentezi', 'Ses Yanıtı Üret → Çal', 'medium'),
]
for i, (label, desc, fill) in enumerate(phone_pipeline):
y = py + 60 + i * 42
s.rect(px + 10, y, pw - 20, 36, fill=fill, rx=3)
s.text(px + 20, y + 14, label, size=FS_TINY, bold=True, anchor='start')
s.text(px + 20, y + 28, desc, size=11, anchor='start', fill='text_light')
if i < len(phone_pipeline) - 1:
s.arrow(px + pw // 2, y + 38, px + pw // 2, y + 42, color='dark')
# Computer Agent (right)
cx, cy, cw, ch_h = 440, 65, 310, 240
s.rect(cx, cy, cw, ch_h, fill='light', rx=6)
s.text(cx + cw // 2, cy + 22, 'Bilgisayar Ajanı', size=FS_BODY, bold=True)
s.text(cx + cw // 2, cy + 42, 'Python · Tarayıcı Otomasyonu', size=FS_TINY, fill='text_light')
comp_pipeline = [
('Ekran Görüntüsü', 'Mevcut Tarayıcı Sayfası', 'medium'),
('Görsel LLM', 'Sayfa Yapısını + Form Alanlarını Anla', 'light'),
('Eylem Planlama', 'Alanları Bul → Girdi Sırasını Planla', 'light'),
('Eylemleri Yürüt', 'Tıkla / Girdi / Gönder', 'medium'),
]
for i, (label, desc, fill) in enumerate(comp_pipeline):
y = cy + 60 + i * 42
s.rect(cx + 10, y, cw - 20, 36, fill=fill, rx=3)
s.text(cx + 20, y + 14, label, size=FS_TINY, bold=True, anchor='start')
s.text(cx + 20, y + 28, desc, size=11, anchor='start', fill='text_light')
if i < len(comp_pipeline) - 1:
s.arrow(cx + cw // 2, y + 38, cx + cw // 2, y + 42, color='dark')
# WebSocket connection between agents
ws_y = py + ph + 15
s.rect(30, ws_y, W - 60, 36, fill='dark', rx=4)
s.text(W // 2, ws_y + 18, 'WebSocket Çift Yönlü İletişim (ws://localhost:8849)', size=FS_SMALL, fill='white', bold=True)
s.arrow(px + pw // 2, py + ph + 2, px + pw // 2, ws_y - 2, color='dark')
s.arrow(cx + cw // 2, cy + ch_h + 2, cx + cw // 2, ws_y - 2, color='dark')
# Message examples
my = ws_y + 50
s.rect(30, my, W - 60, 150, fill='code_bg', rx=4)
s.text(W // 2, my + 18, 'Gerçek zamanlı çift yönlü mesaj akışı (telefon ve bilgisayar eşzamanlı kullanılır)', size=FS_BODY, bold=True)
msgs = [
('Telefon → Bilgisayar', '[FROM_PHONE_AGENT] Kullanıcı adının Zhang San olduğunu söylüyor', '→'),
('Bilgisayar → Telefon', '[FROM_COMPUTER_AGENT] Ad dolduruldu, kimlik numarası gerekiyor', '←'),
('Telefon → Bilgisayar', '[FROM_PHONE_AGENT] Kimlik numarası 310101199001011234', '→'),
('Bilgisayar → Telefon', '[FROM_COMPUTER_AGENT] Form gönderildi, kayıt başarılı', '←'),
]
for i, (sender, content, direction) in enumerate(msgs):
y = my + 42 + i * 26
s.text(42, y, sender, size=FS_TINY, bold=True, anchor='start',
fill='text' if '→' == direction else 'text_light')
s.mono(210, y, content, size=10, anchor='start')
# Key point
s.text(W // 2, my + 140,
'Anahtar: İki ajan birbirini bloklamadan bağımsız ReAct döngülerini paralel çalıştırır',
size=FS_SMALL, fill='text_light')
s.save(os.path.join(OUT, 'fig9-7.svg'))
# ════════════════════════════════════════════════════════════════════
# fig9-8: Parallel Web Scraping Agent (Exp 9.7)
# ════════════════════════════════════════════════════════════════════
def fig9_8():
W, H = 780, 530
s = SVG(W, H)
s.text(W // 2, 28, 'Deney 9.7: Paralel Web Kazıma — Basamaklı Sonlandırma', size=FS_TITLE, bold=True)
# Orchestration Agent
ox, oy, ow, oh = 230, 55, 320, 65
s.rect(ox, oy, ow, oh, fill='medium')
s.text(ox + ow // 2, oy + 20, 'Orkestrasyon Ajanı', size=FS_BODY, bold=True)
s.text(ox + ow // 2, oy + 44, 'Dinamik oluşturma · Gerçek zamanlı izleme · Basamaklı sonlandırma', size=FS_TINY, fill='text_light')
# Parallel Computer Use Agents
agents = [
('Ajan 1', 'cs.edu.cn', 'Aranıyor... ◎', 'light'),
('Ajan 2', 'math.edu.cn', 'Bulunamadı ✗', '#e8e8e8'),
('Ajan 3', 'phys.edu.cn', 'Bulundu! ✓', 'medium'),
('Ajan 4', 'chem.edu.cn', 'Sonlandırıldı ⊘', 'code_bg'),
('Ajan 5', 'bio.edu.cn', 'Sonlandırıldı ⊘', 'code_bg'),
]
aw = 130
gap = 12
total_w = len(agents) * aw + (len(agents) - 1) * gap
ax_start = (W - total_w) // 2
ay = 160
for i, (name, url, status, fill) in enumerate(agents):
x = ax_start + i * (aw + gap)
s.rect(x, ay, aw, 95, fill=fill, rx=4)
s.text(x + aw // 2, ay + 16, name, size=FS_SMALL, bold=True)
s.mono(x + aw // 2, ay + 35, url, size=10, anchor='middle')
s.text(x + aw // 2, ay + 55, 'Akademik Kadro Araması', size=FS_TINY, fill='text_light')
s.text(x + aw // 2, ay + 75, status, size=FS_TINY,
bold=('Bulundu' in status), fill='text' if 'Bulundu' in status else 'text_light')
s.arrow(ox + ow // 2, oy + oh + 2, x + aw // 2, ay - 2, color='dark')
# Cascade termination flow
ty = 280
s.rect(30, ty, W - 60, 120, fill='code_bg', rx=4)
s.text(W // 2, ty + 18, 'Basamaklı Sonlandırma Zaman Çizelgesi', size=FS_BODY, bold=True)
timeline = [
('t=0sn', '5 ajan başlat\n"Zhang Wei" öğretmeni paralel ara'),
('t=12sn', 'Ajan 2 tamamlandı\nBulunamadı → Normal çıkış'),
('t=18sn', 'Ajan 3 hedefi buldu!\ntarget_found gönder'),
('t=18.1sn', 'Orch, 1,4,5 nolu Ajanlara\nterminate yayınlıyor'),
('t=19sn', 'Tümü sonlandırmayı onayladı\nSonuçları topla ve döndür'),
]
tw = 130
tx_start = (W - len(timeline) * tw) // 2
for i, (time, desc) in enumerate(timeline):
x = tx_start + i * tw
s.text(x + tw // 2, ty + 42, time, size=FS_SMALL, bold=True)
for j, ln in enumerate(desc.split('\n')):
s.text(x + tw // 2, ty + 60 + j * 16, ln, size=FS_TINY, fill='text_light')
if i < len(timeline) - 1:
s.arrow(x + tw - 2, ty + 55, x + tw + 4, ty + 55, color='dark')
# Result and comparison
ry = 420
s.rect(30, ry, 340, 85, fill='light', rx=4)
s.text(200, ry + 18, 'Bulunan sonuç', size=FS_BODY, bold=True)
result_lines = [
'Ad: Zhang Wei Fakülte: Fizik Fakültesi',
'Unvan: Profesör Alan: Kuantum Hesaplama',
'E-posta: zhangwei@phys.edu.cn',
]
for i, ln in enumerate(result_lines):
s.mono(50, ry + 40 + i * 16, ln, size=11)
s.rect(400, ry, 350, 85, fill='medium', rx=4)
s.text(575, ry + 18, 'Performans Karşılaştırması', size=FS_BODY, bold=True)
s.text(420, ry + 42, 'Seri: 10 site × 30sn = ~5 dakika', size=FS_TINY, anchor='start', fill='text_light')
s.text(420, ry + 60, 'Paralel: bulmak için 18sn + sonlandırmak için 1sn = 19sn', size=FS_TINY, anchor='start', bold=True)
s.text(420, ry + 78, 'Hızlanma: ~15× (basamaklı sonlandırma optimizasyonuyla)', size=FS_TINY, anchor='start', fill='text_light')
s.save(os.path.join(OUT, 'fig9-8.svg'))
# ════════════════════════════════════════════════════════════════════
# fig9-9: Handoff Chain Pattern
# ════════════════════════════════════════════════════════════════════
def fig9_9():
W, H = 780, 440
s = SVG(W, H)
s.text(W // 2, 28, 'Handoff Zincir Deseni: Eşler arası devir + Sözleşme tabanlı işbirliği', size=FS_TITLE, bold=True)
nodes = [
('Ajan A', 'Gereksinim Analizi', 'Çıktı: yapılandırılmış gereksinim belgesi \nspec.json', 'medium'),
('Ajan B', 'Mimari Tasarım', 'Çıktı: teknik tasarım belgesi \ndesign.md', 'light'),
('Ajan C', 'Kod Uygulaması', 'Çıktı: kaynak kod \nsrc/*.py', 'light'),
('Ajan D', 'Test Doğrulaması', 'Çıktı: test raporu \ntest_report.md', 'medium'),
]
nw, nh = 160, 130
gap = 22
total_w = len(nodes) * nw + (len(nodes) - 1) * gap
nx_start = (W - total_w) // 2
ny = 60
for i, (name, role, output, fill) in enumerate(nodes):
x = nx_start + i * (nw + gap)
s.rect(x, ny, nw, nh, fill=fill, rx=6)
s.text(x + nw // 2, ny + 20, name, size=FS_SMALL, bold=True)
s.text(x + nw // 2, ny + 40, role, size=FS_TINY, fill='text_light')
s.rect(x + 8, ny + 55, nw - 16, 50, fill='code_bg', rx=3)
for j, ln in enumerate(output.split('\n')):
s.text(x + nw // 2, ny + 72 + j * 16, ln, size=FS_TINY, fill='text_light')
s.text(x + nw // 2, ny + nh - 8, 'Tamamlanınca devret →', size=FS_TINY, fill='text_light')
if i < len(nodes) - 1:
s.arrow(x + nw + 4, ny + nh // 2, x + nw + gap - 4, ny + nh // 2)
# Handoff data detail
hy = 215
s.rect(30, hy, W - 60, 90, fill='code_bg', rx=4)
s.text(W // 2, hy + 18, 'Devir İçeriği (Ajan A → Ajan B Örneği)', size=FS_BODY, bold=True)
handoff_fields = [
('Tetikleme Koşulu', 'A gereksinim belgesini tamamlar → is_complete=True'),
('Hedef Ajan', 'target="architect" (Ajan B)'),
('Devir İçeriği', 'files=["spec.json"] + summary="E-ticaret sistemi: 3 mikroservis, REST API"'),
('Devir Sonrası Durum', 'status="exit" (kaynakları serbest bırak, bekleme durumunda kalma)'),
]
for i, (field, value) in enumerate(handoff_fields):
y = hy + 38 + i * 16
s.text(42, y, field + ':', size=FS_TINY, bold=True, anchor='start')
s.text(150, y, value, size=FS_TINY, anchor='start', fill='text_light')
# Comparison with Manager mode
cy = 320
s.rect(30, cy, 340, 100, fill='light', rx=4)
s.text(200, cy + 18, 'Merkezsizleşmenin Avantajları', size=FS_SMALL, bold=True)
advantages = [
'✓ Tüm rolleri anlayan merkezi Manager gerekmez',
'✓ Net sorumluluk sınırları, arayüz ayrıştırması',
'✓ Engineer birden çok paralel örneğe sahip olabilir',
]
for i, adv in enumerate(advantages):
s.text(48, cy + 42 + i * 20, adv, size=FS_TINY, anchor='start', fill='text_light')
s.rect(400, cy, 350, 100, fill='light', rx=4)
s.text(575, cy + 18, 'Merkezsizleşmenin Sınırlamaları', size=FS_SMALL, bold=True)
limits = [
'✗ Küresel optimizasyon perspektifi eksik',
'✗ İstisna yönetimi zor (merkezi koordinasyon yok)',
'✗ Süreç sabit, dinamik ayarlamak zor',
]
for i, lim in enumerate(limits):
s.text(418, cy + 42 + i * 20, lim, size=FS_TINY, anchor='start', fill='text_light')
s.save(os.path.join(OUT, 'fig9-9.svg'))
# ════════════════════════════════════════════════════════════════════
# fig9-10: MetaGPT SOP Pipeline
# ════════════════════════════════════════════════════════════════════
def fig9_10():
W, H = 780, 530
s = SVG(W, H)
s.text(W // 2, 28, 'MetaGPT SOP Boru Hattı: Standartlaştırılmış Belge Odaklı', size=FS_TITLE, bold=True)
roles = [
('Ürün Yöneticisi', 'medium',
'Girdi: Kullanıcı Gereksinim Açıklaması',
['Özellik Listesi + Öncelik', 'Kullanıcı Hikayeleri (5 adet)', 'Kabul Kriterleri'],
'docs/PRD.md'),
('Mimar', 'light',
'Girdi: PRD.md',
['Teknoloji Yığını: FastAPI+React', 'API Spesifikasyonu (OpenAPI)', 'Veritabanı Şeması'],
'docs/design.md'),
('Mühendis ×3', 'light',
'Girdi: design.md + modül spesifikasyonu',
['Modül A: Kullanıcı Servisi', 'Modül B: Sipariş Servisi', 'Modül C: Ödeme Servisi'],
'src/*.py'),
('QA Mühendisi', 'medium',
'Girdi: src/ + PRD.md',
['Birim Testleri (pytest)', 'Entegrasyon Testleri (API)', 'Hata Raporu → Mühendis'],
'docs/test_report.md'),
]
rw = 170
gap = 16
total_w = len(roles) * rw + (len(roles) - 1) * gap
rx_start = (W - total_w) // 2
ry = 55
for i, (name, fill, input_desc, outputs, artifact) in enumerate(roles):
x = rx_start + i * (rw + gap)
s.rect(x, ry, rw, 230, fill=fill, rx=6)
s.text(x + rw // 2, ry + 20, name, size=FS_SMALL, bold=True)
s.text(x + 8, ry + 42, input_desc, size=11, anchor='start', fill='text_light')
s.rect(x + 8, ry + 58, rw - 16, 20 + len(outputs) * 16, fill='code_bg', rx=3)
s.text(x + 14, ry + 72, 'Çıktı:', size=FS_TINY, bold=True, anchor='start')
for j, out in enumerate(outputs):
s.text(x + 14, ry + 88 + j * 16, out, size=11, anchor='start', fill='text_light')
s.rect(x + 8, ry + 168, rw - 16, 30, fill='dark', rx=12)
s.mono(x + rw // 2, ry + 183, artifact, size=11, anchor='middle', fill='white')
if i < len(roles) - 1:
ax1 = x + rw + 2
ax2 = x + rw + gap - 2
s.arrow(ax1, ry + 115, ax2, ry + 115)
# QA → Engineer feedback loop
qa_x = rx_start + 3 * (rw + gap) + rw // 2
eng_x = rx_start + 2 * (rw + gap) + rw // 2
s.arrow_curved(qa_x, ry + 230 + 5, eng_x, ry + 230 + 5, curve=-30, label='Hata Düzeltme', dash=True)
# Shared file system
fy = 310
s.rect(30, fy, W - 60, 50, fill='medium', rx=4)
s.text(W // 2, fy + 16, 'Paylaşılan Proje Dizini', size=FS_SMALL, bold=True)
s.mono(W // 2, fy + 36, 'docs/PRD.md docs/design.md src/*.py docs/test_report.md',
size=11, anchor='middle')
# Key insight
ky = 375
s.rect(30, ky, W - 60, 130, fill='code_bg', rx=4)
s.text(W // 2, ky + 18, 'MetaGPT Temel Tasarımı', size=FS_BODY, bold=True)
insights = [
('Standartlaştırılmış Belgeler', 'Her rol net biçimde çıktı üretir — alt akış yalnızca biçimi anlamalı, üst akışın düşünce sürecini değil'),
('Arayüz Ayrıştırması', 'PM\'i iyileştir (daha güçlü modele geç) — çıktı PRD biçimine uyduğu sürece alt akış sıfır değişiklik gerektirir'),
('Manager Yok', 'Kontrol DAG boyunca doğal akar: PM→Arch→Eng→QA, merkezi zamanlama ek yükü yok'),
('İstisna Kanalı', 'QA test başarısız → Hata raporu modüle göre Mühendis\'e yönlendirilir → yinelemeli düzeltme'),
]
for i, (title, desc) in enumerate(insights):
y = ky + 42 + i * 24
s.text(42, y, '▸ ' + title, size=FS_SMALL, bold=True, anchor='start')
s.text(180, y, desc, size=FS_TINY, anchor='start', fill='text_light')
s.save(os.path.join(OUT, 'fig9-10.svg'))
# ════════════════════════════════════════════════════════════════════
# Fig9-11: VLA Architecture (Vision-Language-Action) — Comparison of Three Technical Paths
# ════════════════════════════════════════════════════════════════════
def fig9_11():
W, H = 900, 620
s = SVG(W, H)
# Common Input
in_x, in_y, in_w, in_h = 230, 55, 440, 64
s.rect(in_x, in_y, in_w, in_h, fill='medium', rx=6)
s.text(in_x + in_w / 2, in_y + 22, 'Ortak Girdi: kamera görüntüsü + dil talimatı', size=FS_SMALL, bold=True)
s.text(in_x + in_w / 2, in_y + 44, '"Kırmızı bloğu mavi kutuya koy"', size=FS_TINY, fill='text_light')
# Arrows leading to three branches
s.arrow(in_x + 70, in_y + in_h + 2, 145, 165) # → OpenVLA
s.arrow(W / 2, in_y + in_h + 2, W / 2, 165) # → π₀
s.arrow(in_x + in_w - 70, in_y + in_h + 2, 755, 165) # → RT-2
# Three-Column Architecture
col_w, col_gap = 270, 30
cols_total = 3 * col_w + 2 * col_gap
sx0 = (W - cols_total) / 2 # = 30
columns = [
('OpenVLA', 'Açık kaynak · ayrık eylem tokenleri', 'light', [
('Görsel kodlayıcı', 'DINOv2 + SigLIP', 'Piksel özelliklerini çıkar'),
('LLM omurgası', 'Llama 2 (7B)', 'Talimatları ve sahneleri anla'),
('Kod çözme yöntemi', 'Otoregresif · metin tokenleri', 'Eylemleri seçeneklere ayrıklaştır'),
('Eylem çıktısı', '"a=[3,2,5,...]" tokenleri', 'Adım adım 7-DOF kontrol değeri üret'),
]),
('π₀(Pi-Zero', 'Difüzyon politikası · yumuşak yörünge', 'medium', [
('Görsel kodlayıcı', 'ViT çoklu görünüm füzyonu', 'Piksel özelliklerini çıkar'),
('Mixture-of-Transformers', 'Hızlı-yavaş ayrık omurga', 'Dil yavaş düşünme + kontrol hızlı düşünme'),
('Kod çözme yöntemi', 'Difüzyon gürültü giderme yinelemesi', 'Tüm yörüngeyi kabadan inceye iyileştirme'),
('Eylem çıktısı', 'Sürekli eylem dizisi (50 adım/parti)', 'Yüksek frekanslı yumuşak kontrol sinyali'),
]),
('RT-2', 'Eylem modeli olarak dil modeli', 'light', [
('Görsel-dil omurgası', 'PaLI-X / PaLM-E', 'VLM uçtan uca anlama'),
('Eylem gösterimi', 'Eylem → doğal dil tokenleri', '"kolu 5cm sağa hareket ettir"'),
('Kod çözme yöntemi', 'VLM otoregresyonunu yeniden kullan', 'Metin üretimiyle paylaşılan ağırlıklar'),
('Eylem çıktısı', 'Metin açıklaması → denetleyici ayrıştırması', 'VLM\'in anlamsal genelleme yeteneğini miras al'),
]),
]
top_y = 165
title_h = 50
row_h = 80
for i, (name, tag, fill, rows) in enumerate(columns):
cx = sx0 + i * (col_w + col_gap)
#Column container
col_total_h = title_h + len(rows) * row_h + 14
s.rect(cx, top_y, col_w, col_total_h, fill='white', stroke='border')
#Title bar
s.rect(cx, top_y, col_w, title_h, fill=fill)
s.text(cx + col_w / 2, top_y + 18, name, size=FS_BODY, bold=True)
s.text(cx + col_w / 2, top_y + 38, tag, size=FS_TINY, fill='text_light')
#Rows
for j, (label, value, hint) in enumerate(rows):
ry = top_y + title_h + 8 + j * row_h
s.rect(cx + 10, ry, col_w - 20, row_h - 8, fill='code_bg', rx=4)
s.text(cx + col_w / 2, ry + 18, label, size=FS_TINY, bold=True)
s.text(cx + col_w / 2, ry + 38, value, size=FS_TINY)
s.text(cx + col_w / 2, ry + 56, hint, size=FS_TINY, fill='text_light')
# Bottom: unified output layer
out_y = top_y + title_h + 4 * row_h + 14 + 24
s.rect(30, out_y, W - 60, 50, fill='darker', rx=6)
s.text(W / 2, out_y + 18,
'Robot kontrol sinyalleri: 7-DOF eklem açıları / uç efektör pozu',
size=FS_SMALL, bold=True, fill='white')
s.text(W / 2, out_y + 36,
'Fark, "robota bir sonraki adımı nasıl söyleyeceğinde" yatar, ancak sonuçta ikisi de birleşik bir kontrol arayüzüne iner',
size=FS_TINY, fill='white')
s.save(os.path.join(OUT, 'fig9-11.svg'))
# ════════════════════════════════════════════════════════════════════
# Fig 9-12: Voice Werewolf Agent System (Exp 9.9)
# ════════════════════════════════════════════════════════════════════
def fig9_12():
W, H = 780, 550
s = SVG(W, H)
s.text(W // 2, 28, 'Deney 9.9: Sesli Kurt Adam — Bilgi İzin Kontrolü', size=FS_TITLE, bold=True)
# Judge (code-driven)
jx, jy, jw, jh = 260, 55, 260, 75
s.rect(jx, jy, jw, jh, fill='dark', rx=6)
s.text(jx + jw // 2, jy + 20, 'Hakem (kod güdümlü)', size=FS_BODY, bold=True, fill='white')
s.text(jx + jw // 2, jy + 42, 'Oyun durumu · Aşama kontrolü · Bilgi dağıtımı', size=FS_TINY, fill='white')
s.text(jx + jw // 2, jy + 58, 'Gece → Gündüz → Oylama → Sonuçlandır', size=FS_TINY, fill='white')
# Role agents
roles = [
(40, 'Kurt Adam 1', '🐺', 'medium',
['Görünür: Takım arkadaşı kimlikleri', 'Strateji: Köylü gibi davran', 'Gece: Hedef seç']),
(185, 'Kurt Adam 2', '🐺', 'medium',
['Görünür: Takım arkadaşı kimlikleri', 'Strateji: Oylamayı takip ederek koru', 'Gece: Hedefte anlaş']),
(330, 'Görücü', '🔮', 'light',
['Görünür: Araştırma sonuçları', 'Strateji: Açıklama zamanını seç', 'Gece: 1 kişiyi kontrol et']),
(475, 'Cadı', '🧪', 'light',
['Görünür: Ölüm/iyileştirme', 'Strateji: İksir/panzehiri sakla', 'Gece: 1 kişiyi kurtar/zehirle']),
(620, 'Köylü ×2', '👤', '#e8e8e8',
['Görünür: Yalnızca kamuya açık bilgi', 'Strateji: Mantıksal muhakeme', 'Gündüz: Konuşmayı analiz et']),
]
aw, ay = 135, 180
for x, name, icon, fill, info in roles:
s.rect(x, ay, aw, 140, fill=fill, rx=6)
s.text(x + aw // 2, ay + 18, f'{icon} {name}', size=FS_SMALL, bold=True)
for i, ln in enumerate(info):
s.text(x + aw // 2, ay + 42 + i * 20, ln, size=11, fill='text_light')
# Arrow from Judge
s.arrow(jx + jw // 2, jy + jh + 2, x + aw // 2, ay - 2, color='dark')
# Permission badge
if 'Kurt Adam' in name:
s.badge(x + aw - 45, ay + aw - 15, 40, 18, 'Karşılıklı bilgi', fill='darker', font_size=11)
elif 'Görücü' in name:
s.badge(x + aw - 55, ay + aw - 15, 50, 18, 'Araştırma sonuçları', fill='darker', font_size=10)
# Info permission control
iy = 340
s.rect(30, iy, W - 60, 90, fill='code_bg', rx=4)
s.text(W // 2, iy + 18, 'Bilgi izin kontrolü: hakem role göre bağlamı filtreler', size=FS_BODY, bold=True)
perms = [
('Kurt Adam', 'Tüm kurt adam kimlikleri + gece tartışması + herkese açık konuşma'),
('Görücü', 'Araştırma sonuçları (yalnızca kendi araştırdığı) + herkese açık konuşma'),
('Cadı', 'Gecenin ölümleri + panzehir/zehir durumu + herkese açık konuşma'),
('Köylü', 'Yalnızca herkese açık konuşma + oylama kayıtları (sıfır özel bilgi)'),
]
pw = (W - 80) // 2
for i, (role, perm) in enumerate(perms):
row, col = i // 2, i % 2
x = 50 + col * pw
y = iy + 40 + row * 22
s.text(x, y, role + ':', size=FS_TINY, bold=True, anchor='start')
s.text(x + 55, y, perm, size=FS_TINY, anchor='start', fill='text_light')
# Voice interaction
vy = 445
s.rect(30, vy, W - 60, 85, fill='light', rx=4)
s.text(W // 2, vy + 18, 'Gerçek zamanlı sesli etkileşim (ASR + LLM + TTS)', size=FS_BODY, bold=True)
voice_flow = [
('Gündüz tartışması', 'Hakem konuşma sırasını yönetir\nkoltuk sırasına göre konuşma'),
('Oylama aşaması', 'Tüm oyuncuların oyunu topla\noyları say ve sonucu duyur'),
('Gece aşaması', 'Hakem rolleri sırayla uyandırır\nözel ses kanalı'),
('İnsan oyuncu', 'Rastgele rol ataması\nses tabanlı oylama/konuşma'),
]
vw = (W - 80) // len(voice_flow)
for i, (title, desc) in enumerate(voice_flow):
cx = 50 + i * vw + vw // 2
s.text(cx, vy + 42, title, size=FS_SMALL, bold=True)
for j, ln in enumerate(desc.split('\n')):
s.text(cx, vy + 60 + j * 16, ln, size=FS_TINY, fill='text_light')
s.save(os.path.join(OUT, 'fig9-12.svg'))
# ════════════════════════════════════════════════════════════════════
# Main
# ════════════════════════════════════════════════════════════════════
def main():
os.makedirs(OUT, exist_ok=True)
figs = [
('fig9-1', fig9_1),
('fig9-2', fig9_2),
('fig9-3', fig9_3),
('fig9-4', fig9_4),
('fig9-5', fig9_5),
('fig9-6', fig9_6),
('fig9-7', fig9_7),
('fig9-8', fig9_8),
('fig9-9', fig9_9),
('fig9-10', fig9_10),
('fig9-11', fig9_11),
('fig9-12', fig9_12),
]
for name, func in figs:
func()
print(f' ✓ {name}')
print(f'\nGenerated {len(figs)} figures in {OUT}/')
if __name__ == '__main__':
main()