16. שילוח לפרודקשן
"סוכן דמו זה קל; סוכן אמין זו הנדסה"
חדש בנושא?
מה זה streaming?
במקום לחכות לתשובת ה-LLM השלמה בבת אחת, streaming מעביר טוקנים בזמן שהם נוצרים — כמו לצפות במישהו מקליד. זה גורם לסוכן להרגיש רספונסיבי גם בהפקות ארוכות.
מה זה model routing?
שימוש במודלים שונים למשימות שונות. מודלים מהירים וזולים (Haiku) להחלטות פשוטות. מודלים חזקים ויקרים (Opus) לחשיבה מורכבת. זה חותך עלויות 60-80% בלי לפגוע באיכות.
מה זה exponential backoff?
אסטרטגיית retry שבה ממתינים יותר זמן בין כל ניסיון: 1 שנייה, 2 שניות, 4 שניות, 8 שניות. זה מונע הפצצה של API כושל ונותן לו זמן להתאושש.
הבעיה
בניתם סוכן. הוא עובד על הלפטופ שלכם. אתם עושים דמו וזה נראה מדהים. אז אתם שולחים אותו.
המשתמש הראשון פוגע ב-rate limit ומקבל stack trace. המשתמש השני ממתין 45 שניות בוהה במסך ריק. המשתמש השלישי מריץ לולאה ששורפת $200 בטוקנים לפני שמישהו שם לב. הפער בין “עובד על הלפטופ שלי” ל”אמין בפרודקשן” הוא עצום.
הפתרון
שכבו דאגות פרודקשן על הרתמה הקיימת. אתם לא משכתבים את לולאת הסוכן — אתם עוטפים אותה עם התשתית שהיא צריכה כדי לשרוד תעבורה אמיתית:
Streaming → UX רספונסיבי, בלי מסכים ריקים
Retries → לשרוד rate limits וכשלים חולפים
ניתוב מודלים → לחתוך עלויות 60-80% בלי לאבד איכות
מעקב עלויות → לדעת מה מוציאים, לעצור לפני חריגה
ניטור בריאות → לראות בעיות לפני שמשתמשים מדווחים
Streaming תשובות
def stream_response(messages: list) -> anthropic.types.Message:
with client.messages.stream(
model="claude-sonnet-4-6-20250610",
messages=messages,
tools=TOOLS,
max_tokens=8000,
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print()
return stream.get_final_message()
Retry עם Exponential Backoff
def call_with_retry(messages: list, max_retries: int = 4):
for attempt in range(max_retries):
try:
return client.messages.create(
model=select_model(messages),
messages=messages,
tools=TOOLS,
max_tokens=8000,
)
except anthropic.RateLimitError:
wait = 2 ** attempt
print(f"Rate limited. Retrying in {wait}s...")
time.sleep(wait)
except anthropic.APITimeoutError:
if attempt == max_retries - 1:
raise
time.sleep(1)
raise RuntimeError("API unavailable after retries")
דפוס exponential backoff — המתנה של 1s, 2s, 4s, 8s — נותן ל-API זמן להתאושש.
ניתוב מודלים
def select_model(messages: list) -> str:
token_count = count_tokens(messages)
if token_count < 2000:
return "claude-haiku-4-5-20251001"
return "claude-sonnet-4-6-20250610"
חישוב עלות קונקרטי: ל-100 משימות סוכן, כל אחת 10k input + 2k output:
- הכל-Sonnet: $6.00
- 70% Haiku + 30% Sonnet: $2.92
חיסכון של 51% עם היוריסטיקת ניתוב נאיבית.
מה השתנה מתצפית
| רכיב | תצפית | פרודקשן |
|---|---|---|
| מיקוד | לראות מה הסוכן עושה | להפוך את הסוכן לאמין |
| כשלים | לתעד שגיאות ל-post-mortem | לנסות מחדש שגיאות חולפות אוטומטית |
| לאטנסי | למדוד זמני תגובה | להפחית לאטנסי נתפס עם streaming |
| עלות | לעקוב אחר הוצאה ב-traces | לאכוף תקציבים, לנתב למודלים זולים |
נקודה מרכזית
סוכן פרודקשן הוא לא סוכן שונה — הוא אותה לולאת הסוכן עטופה בהנדסה שהיא צריכה כדי לשרוד את העולם האמיתי. Streaming לרספונסיביות. Retries לעמידות. ניתוב מודלים לעלות. מעקב תקציב לבטיחות. ניטור בריאות לנראות. כל אחד שכבה קטנה ועצמאית. ביחד הם ההבדל בין דמו לשירות.
מדריך קוד אינטראקטיבי
1def agent_loop_production(messages: list, tracer: AgentTracer):2 while True:3 response = call_with_retry(messages)4 tracer.record("llm_call", {5 "tokens": response.usage.input_tokens + response.usage.output_tokens,6 "model": response.model,7 })8 messages.append({"role": "assistant", "content": response.content})9 if response.stop_reason != "tool_use":10 return11 12 for block in response.content:13 if block.type == "tool_use":14 verdict = guardrail.check(block.name, block.input)15 if verdict == "DENIED":16 result = "Error: Tool call denied by guardrail"17 elif verdict == "COST_CAP_EXCEEDED":18 result = "Error: Cost cap exceeded"19 elif verdict == "NEEDS_APPROVAL":20 result = human_approve(block)21 else:22 result = execute_tool(block)23 tracer.record("tool_exec", {"tool": block.name})24 messages.append(tool_result(block.id, result))25 26def call_with_retry(messages, max_retries=4):27 for attempt in range(max_retries):28 try:29 return client.messages.create(30 model=select_model(messages),31 messages=messages, tools=TOOLS, max_tokens=8000,32 )33 except anthropic.RateLimitError:34 wait = 2 ** attempt35 time.sleep(wait)36 raise RuntimeError("API unavailable after retries")37 38def select_model(messages) -> str:39 token_count = count_tokens(messages)40 if token_count < 2000:41 return "claude-haiku-4-5-20251001"42 return "claude-sonnet-4-6-20250610"43 חשבו את הפרש העלויות: הרצת 100 משימות סוכן שכל אחת משתמשת ב-10k input + 2k output טוקנים. השוו הכל-Sonnet מול ניתוב 70% ל-Haiku.
רמז
בדקו תמחור נוכחי ב-docs.anthropic.com. Haiku זול בערך פי 10-20 לטוקן.
הוסיפו streaming ללולאת הסוכן: השתמשו ב-client.messages.stream() והדפיסו טוקנים כשהם מגיעים. הציגו spinner בזמן ביצוע כלים.
רמז
השתמשו ב-with client.messages.stream(...) as stream: for text in stream.text_stream: print(text, end='', flush=True)
בנו דשבורד בריאות: endpoint HTTP פשוט שמדווח על סוכנים פעילים, סך טוקנים שנצרכו היום, שיעור שגיאות, וזמן תגובה ממוצע.
רמז
השתמשו ב-http.server או Flask. קראו מתיקיית .traces/ כדי לחשב מטריקות.