- סוכן AI עובד ב-Python עם
Agent+Runner-- כולל instructions, model, ו-tools - סוכן מקבילי ב-TypeScript עם
@openai/agents-- אותה ארכיטקטורה, שפה אחרת - 3 Function Tools מותאמים אישית -- עם
@function_tooldecorator ו-type hints - מערכת multi-agent עובדת עם Handoffs -- Triage Agent שמנתב ל-2 סוכנים מומחים
- Guardrails מוגדרים -- Input Guardrail שבודק תוכן + Output Guardrail שמוודא פורמט
- Tracing מופעל עם OpenAI Dashboard -- מעקב אחרי כל צעד, כל tool call, כל handoff
- טבלת השוואה מתועדת -- OpenAI SDK vs Claude Agent SDK vs Vercel AI SDK, עם יתרונות וחסרונות
- תוכלו לבנות סוכן AI מלא עם OpenAI Agents SDK ב-Python וב-TypeScript -- כולל כלים, handoffs, ו-guardrails
- תוכלו לתכנן מערכת multi-agent עם דפוס Triage -- סוכן מנתב שמעביר שליטה לסוכנים מתמחים
- תוכלו להגדיר guardrails שמגנים על הסוכן מקלט בעייתי ופלט לא תקין
- תוכלו לנתח traces של ריצות סוכנים לצורך דיבוג ואופטימיזציה
- תוכלו להשוות בין שלוש הגישות ל-SDK (OpenAI, Claude, Vercel AI SDK) ולבחור את הנכונה למשימה
- פרקים קודמים: פרק 1 (מה זה סוכן AI, לולאת ReAct), פרק 2 (ארכיטקטורות), פרק 3 (MCP ו-Function Calling), פרק 6 (Vercel AI SDK -- להשוואה)
- מה תצטרכו: Python 3.10+ או Node.js 18+, מפתח OpenAI API, עורך קוד (VS Code מומלץ), pip או npm
- ידע נדרש: Python בסיסי (type hints, async/await, decorators) או TypeScript בסיסי, הכרת Function Calling מפרק 3
- זמן משוער: 4-5 שעות (כולל תרגילים)
- עלות API משוערת: $5-15 (GPT-5: $1.25/$10 per 1M tokens)
בפרק 6 בניתם סוכן AI עם Vercel AI SDK -- TypeScript-first, multi-provider, עם ToolLoopAgent ו-useChat ל-UI מלא. בפרק הזה תבנו סוכן מקביל עם OpenAI Agents SDK -- ותגלו את הגישה השונה: Python-first, handoffs נקיים, guardrails מובנים, ו-tracing חינמי. בפרק 8 תעברו ל-LangGraph -- ותלמדו לבנות סוכנים עם state machines, checkpoints ו-human-in-the-loop.
| מונח (English) | עברית | הסבר |
|---|---|---|
| Agent | סוכן | המחלקה המרכזית ב-OpenAI SDK. מוגדר עם name, instructions, model, tools, ו-handoffs |
| Runner | מריץ | המנוע שמריץ סוכנים. שלוש גרסאות: run_sync() (סינכרוני), run() (async), run_streamed() (streaming) |
| @function_tool | כלי-פונקציה | Decorator שהופך פונקציית Python רגילה לכלי שסוכן יכול לקרוא לו. עובד אוטומטית עם type hints |
| Handoff | העברת שליטה | מנגנון שמעביר את השליטה מסוכן אחד לאחר. הסוכן המקבל ממשיך את השיחה מאותה נקודה |
| InputGuardrail | מעקה קלט | בדיקה שרצה על הקלט של המשתמש לפני שהסוכן מתחיל לעבוד. יכולה לחסום קלט בעייתי |
| OutputGuardrail | מעקה פלט | בדיקה שרצה על התשובה של הסוכן אחרי שסיים. מוודאת שהפלט עומד בסטנדרטים |
| Tracing | מעקב | מערכת לוגים מובנית שמתעדת כל צעד של הסוכן: קריאות LLM, tool calls, handoffs. חינמית ב-OpenAI Dashboard |
| output_type | סוג פלט | פרמטר ב-Agent שמגדיר structured output עם Pydantic model. מבטיח שהסוכן מחזיר JSON מוגדר |
| Responses API | API תגובות | ה-API החדש של OpenAI (מרץ 2025) שמחליף את Chat Completions לשימושים אגנטיים. תומך ב-tool orchestration, web search, file search |
| as_tool() | סוכן-ככלי | מתודה שהופכת סוכן לכלי של סוכן אחר. מאפשרת agents-as-tools pattern -- חלופה ל-handoffs |
| Tripwire | חוט מתח | מנגנון ב-guardrails שמפעיל חסימה כשתנאי מסוים מתקיים. כמו מערכת אזעקה |
| MCPServer | שרת MCP | חיבור לשרת Model Context Protocol -- מאפשר לסוכן לקרוא לכלים חיצוניים דרך פרוטוקול סטנדרטי |
סקירה ופילוסופיה -- למה OpenAI Agents SDK
במרץ 2025, OpenAI שחררו את ה-Agents SDK (OpenAI Agents SDK) -- הפריימוורק הרשמי שלהם לבניית סוכני AI. הוא מחליף את ה-Assistants API הישן ואת ה-Swarm הניסיוני, ומביא גישה חדשה: קלה, פשוטה, ועם הכל בפנים.
ה-SDK הוא open source (רישיון MIT), זמין ב-Python (החבילה openai-agents, גרסה 0.13.0+) וב-TypeScript/Node.js (@openai/agents). הפילוסופיה: lightweight primitives -- מספר קטן של אבני בניין חזקות שמתחברות ביחד.
ארבע אבני הבניין
| אבן בניין | מה היא עושה | אנלוגיה |
|---|---|---|
| Agent | LLM עם instructions, tools, ו-handoffs | עובד מומחה עם תיאור תפקיד וכלי עבודה |
| Handoff | העברת שליטה מסוכן לסוכן | מנהל שמפנה אותך למומחה אחר |
| Guardrail | בדיקות אבטחה על קלט ופלט | שומר בכניסה שבודק תעודת זהות |
| Tracing | מעקב אחרי כל צעד של הסוכן | מצלמת אבטחה שמתעדת הכל |
למה להשתמש ב-OpenAI Agents SDK?
- Handoffs הכי נקיים בשוק -- העברת שליטה בין סוכנים בשורה אחת, עם שימור הקשר מלא
- Guardrails מובנים -- לא צריך ספרייה חיצונית לוולידציה
- Tracing חינמי -- כל ריצה מתועדת אוטומטית ב-OpenAI Dashboard, ללא עלות נוספת
- Code Interpreter ו-File Search מובנים -- סוכנים שכותבים ומריצים קוד Python, או מחפשים במסמכים
- Sessions לזיכרון -- שימור שיחות בין ריצות, אוטומטי
- הכי מהיר להתחלה -- 3 שורות קוד לסוכן עובד
מתי לא להשתמש
- צריכים multi-provider -- ה-SDK עובד רק עם מודלים של OpenAI (GPT-5, GPT-5.2, GPT-5.4). אם אתם צריכים Claude או Gemini -- Vercel AI SDK (פרק 6)
- צריכים graph-based orchestration -- לזרימות מורכבות עם תנאים, loops, ו-checkpoints -- LangGraph (פרק 9)
- מעדיפים TypeScript-first -- ה-SDK של OpenAI הוא Python-first. גרסת ה-TypeScript חדשה יותר ופחות בשלה
Swarm → Agents SDK: הרקע ההיסטורי
ה-Agents SDK לא צמח מאפס. ב-2024 OpenAI שחררו Swarm -- פרויקט ניסיוני (experimental) שהדגים את רעיון ה-handoffs. Swarm היה מינימליסטי מדי לפרודקשן (אין guardrails, אין tracing, אין Sessions), אבל הוכיח שהגישה עובדת. במרץ 2025, OpenAI לקחו את הלקחים מ-Swarm ובנו את ה-Agents SDK -- גרסת production עם כל מה שחסר.
במקביל, OpenAI הכריזו על Responses API -- API חדש שמחליף את Chat Completions לשימושים אגנטיים. ה-Agents SDK בנוי מעל Responses API, אבל מסתיר את הפרטים. אתם עובדים עם Agent ו-Runner, לא עם HTTP requests ישירות.
נכון למרץ 2026, ה-SDK עדיין מסומן כ-0.x (pre-1.0), מה שאומר ש-breaking changes אפשריים. בפועל, ה-API יציב מספיק לפרודקשן -- עשרות חברות (כולל סטארטאפים ישראליים כמו חברות מ-Tel Aviv ו-Herzliya) כבר משתמשות בו. אבל כדאי לעקוב אחרי ה-release notes לשינויים.
| מודל | Input/1M tokens | Output/1M tokens | Context |
|---|---|---|---|
| GPT-5 | $1.25 | $10 | 1M |
| GPT-5.2 | $1.75 | $14 | 1M |
| GPT-5.2 Pro | $21 | $168 | 1M |
| GPT-5.4 | $2.50 | $15 | 1.05M |
ה-SDK עצמו חינמי. התשלום הוא רק על קריאות API. כלים מובנים: Web Search ~$25-30/1K queries, File Search ~$2.50/1K queries, Code Interpreter ~$0.03/session.
| קריטריון | Agents SDK (חדש) | Assistants API (ישן) | ההמלצה |
|---|---|---|---|
| ארכיטקטורה | קוד ב-client, אתה שולט | State ב-server, OpenAI שולט | SDK -- שליטה מלאה |
| Multi-agent | Handoffs + agents-as-tools | אין תמיכה native | SDK -- הרבה יותר חזק |
| Guardrails | מובנה (input + output) | אין | SDK |
| Tracing | מובנה, חינם | אין | SDK |
| Code Interpreter | ככלי של סוכן | ככלי של assistant | שניהם זהים |
| בשלות | חדש (מרץ 2025) | ותיק (2023) | SDK כבר יציב |
שורה תחתונה: אם אתם מתחילים פרויקט חדש -- Agents SDK. אם יש לכם Assistants API קיים -- תכננו מיגרציה, אבל אין לחץ מיידי.
התקינו את ה-SDK: פתחו טרמינל והריצו pip install openai-agents (Python) או npm install @openai/agents (TypeScript). ודאו ש-OPENAI_API_KEY מוגדר כ-environment variable. בדקו עם python -c "from agents import Agent; print('OK')".
הסוכן הראשון שלך -- Agent + Runner
בואו נבנה סוכן ב-3 שורות. זה לא פשטנות -- זו באמת הפילוסופיה של ה-SDK. כל סוכן הוא Agent (מי הוא ומה יש לו) ו-Runner (מה שמריץ אותו).
from agents import Agent, Runner
agent = Agent(
name="assistant",
instructions="You are a helpful assistant. Answer in Hebrew when asked in Hebrew.",
model="gpt-5",
)
result = Runner.run_sync(agent, "מה זה סוכן AI? הסבר בקצרה.")
print(result.final_output)
# סוכן AI הוא תוכנת בינה מלאכותית שיכולה לקבל החלטות
# ולבצע פעולות באופן עצמאי כדי להשיג מטרה מוגדרת...
זה הכל. Agent מגדיר את הסוכן, Runner.run_sync מריץ אותו. התוצאה ב-result.final_output.
עכשיו אותו דבר ב-TypeScript:
import { Agent, run } from '@openai/agents';
const agent = new Agent({
name: 'assistant',
instructions: 'You are a helpful assistant. Answer in Hebrew when asked in Hebrew.',
model: 'gpt-5',
});
const result = await run(agent, 'מה זה סוכן AI? הסבר בקצרה.');
console.log(result.finalOutput);
שימו לב לדמיון: אותם concepts (Agent, run), סינטקס שונה. Python משתמש ב-Runner.run_sync() או await Runner.run() (async). TypeScript משתמש ב-await run().
שלוש דרכים להרצה
| מתודה | סוג | מתי להשתמש |
|---|---|---|
Runner.run_sync(agent, input) |
סינכרוני | סקריפטים פשוטים, prototyping, CLI tools |
await Runner.run(agent, input) |
Async | Web servers, production, כשצריך concurrency |
Runner.run_streamed(agent, input) |
Streaming | Chat UI, כשצריך להציג תשובות בזמן אמת |
פרמטרים של Agent
from agents import Agent
agent = Agent(
name="research_analyst", # שם הסוכן
instructions="You are a senior research analyst...", # הוראות (system prompt)
model="gpt-5", # מודל (ברירת מחדל: gpt-5)
tools=[search_tool, calc_tool], # כלים שהסוכן יכול לקרוא
handoffs=[editor_agent], # סוכנים שהוא יכול להעביר אליהם
output_type=ResearchReport, # Pydantic model לפלט מובנה
handoff_description="Expert at deep research and analysis", # תיאור להעברות
)
Streaming -- תשובות בזמן אמת
ב-production, כמעט תמיד תרצו streaming -- המשתמש רואה את התשובה נכתבת בזמן אמת, במקום לחכות 10-30 שניות עד שהכל מוכן. ככה עובד ChatGPT, וככה גם הסוכנים שלכם צריכים לעבוד.
from agents import Agent, Runner
agent = Agent(
name="storyteller",
instructions="You tell short stories about Israeli tech culture. Be vivid and engaging.",
)
async def stream_example():
result = Runner.run_streamed(agent, "ספר לי סיפור על סטארטאפ בתל אביב")
async for event in result.stream_events():
# כל event הוא חלק מהתשובה
if event.type == "raw_response_event":
# הדפסת טקסט בזמן אמת
if hasattr(event.data, 'delta'):
print(event.data.delta, end="", flush=True)
# בסוף -- התוצאה המלאה
final = await result.final_output
print(f"\n\nTotal tokens: {result.usage.total_tokens}")
ה-streaming events כוללים לא רק טקסט, אלא גם tool calls, handoffs, ו-guardrail results. ב-Chat UI, אפשר להשתמש באירועים האלה כדי להציג למשתמש מה הסוכן עושה ברגע זה -- "מחפש מידע...", "מעביר למומחה...", וכו'.
context -- שיתוף מידע בין סוכנים
כל ריצה של Runner יכולה לקבל context -- אובייקט Python שעובר בין כל הסוכנים בשרשרת. זה שימושי כשצריך להעביר מידע שלא חלק מהשיחה (למשל: user ID, session data, configuration).
from dataclasses import dataclass
from agents import Agent, Runner, RunContextWrapper
@dataclass
class AppContext:
user_id: str
is_premium: bool
language: str = "he"
# כלי שמשתמש ב-context
@function_tool
def get_user_orders(ctx: RunContextWrapper[AppContext]) -> str:
"""Get recent orders for the current user."""
user_id = ctx.context.user_id
is_premium = ctx.context.is_premium
# בפרודקשן: query ל-database
return f"User {user_id} has 3 recent orders (premium: {is_premium})"
agent = Agent(
name="support",
instructions="Help users with their orders. Check their order history first.",
tools=[get_user_orders],
)
# context עובר לכל הכלים והסוכנים
ctx = AppContext(user_id="user_123", is_premium=True)
result = Runner.run_sync(agent, "מה הסטטוס של ההזמנה האחרונה שלי?", context=ctx)
הריצו את הסוכן הראשון: צרו קובץ my_agent.py, העתיקו את הקוד למעלה, והריצו. שנו את ה-instructions לתפקיד אחר (למשל: "You are an Israeli tech startup advisor"). שלחו 3 שאלות שונות ובדקו את התשובות. רשמו: מה עבד, מה לא, ואיזה instructions עבדו הכי טוב.
Function Tools -- כלים לסוכן
סוכן בלי כלים הוא סתם chatbot. Function Tools (כלי-פונקציות) הם מה שהופך LLM לסוכן -- היכולת לקרוא לפונקציות, לקבל תוצאות, ולהמשיך לחשוב.
ב-OpenAI Agents SDK, הגדרת כלי היא פשוטה במיוחד: כותבים פונקציית Python רגילה עם type hints ו-docstring, שמים עליה את ה-decorator @function_tool, וזהו. ה-SDK שולף אוטומטית את ה-JSON Schema מה-type hints.
from agents import Agent, Runner, function_tool
@function_tool
def get_weather(city: str, unit: str = "celsius") -> str:
"""Get the current weather for a city.
Args:
city: The city name (e.g., "Tel Aviv", "Jerusalem")
unit: Temperature unit - "celsius" or "fahrenheit"
"""
# בפרודקשן: קריאת API אמיתית
return f"The weather in {city} is 28 degrees {unit}, sunny."
@function_tool
def calculate_shipping(
weight_kg: float,
destination: str,
express: bool = False
) -> str:
"""Calculate shipping cost for a package to Israel.
Args:
weight_kg: Package weight in kilograms
destination: City in Israel
express: Whether to use express shipping
"""
base = weight_kg * 15 # ש"ח לק"ג
if express:
base *= 2
return f"Shipping to {destination}: {base:.0f} ILS"
@function_tool
def search_products(query: str, max_results: int = 5) -> str:
"""Search for products in the catalog.
Args:
query: Search query string
max_results: Maximum number of results to return
"""
# סימולציה
return f"Found {max_results} products matching '{query}'"
# סוכן עם 3 כלים
agent = Agent(
name="shop_assistant",
instructions="""You are a helpful shopping assistant for an Israeli e-commerce store.
Use tools to help customers. Always respond in the customer's language.
Prices are in ILS (שקלים).""",
tools=[get_weather, calculate_shipping, search_products],
)
result = Runner.run_sync(agent, "כמה יעלה לשלוח חבילה של 3 קילו לחיפה?")
print(result.final_output)
# משלוח חבילה של 3 קילו לחיפה יעלה 45 ₪ (משלוח רגיל)
# או 90 ₪ (משלוח מהיר).
שימו לב: הסוכן לא צריך שתגידו לו לקרוא לכלי. הוא מבין מההקשר שהשאלה "כמה עולה משלוח" דורשת את calculate_shipping, ומחלץ את הפרמטרים (weight_kg=3, destination="חיפה") מהטקסט החופשי.
TypeScript -- אותו דבר, סינטקס שונה
import { Agent, run, tool } from '@openai/agents';
import { z } from 'zod';
const getWeather = tool({
name: 'get_weather',
description: 'Get the current weather for a city',
parameters: z.object({
city: z.string().describe('The city name'),
unit: z.enum(['celsius', 'fahrenheit']).default('celsius'),
}),
execute: async ({ city, unit }) => {
return `The weather in ${city} is 28 degrees ${unit}, sunny.`;
},
});
const agent = new Agent({
name: 'assistant',
instructions: 'You are a helpful assistant.',
tools: [getWeather],
});
const result = await run(agent, "What's the weather in Tel Aviv?");
console.log(result.finalOutput);
Parallel Tool Calling
GPT-5 יכול לקרוא ל-מספר כלים במקביל בסיבוב אחד. למשל, אם המשתמש שואל "מזג האוויר בתל אביב וירושלים", הסוכן יקרא ל-get_weather("Tel Aviv") ו-get_weather("Jerusalem") בו-זמנית, לא אחד אחרי השני. זה חוסך latency וגם tokens.
Tool Choice
| ערך | התנהגות | מתי להשתמש |
|---|---|---|
"auto" | המודל מחליט אם לקרוא לכלי | ברירת מחדל -- נכון ב-90% מהמקרים |
"required" | המודל חייב לקרוא לכלי אחד לפחות | כשתמיד צריך פעולה (search, lookup) |
"none" | המודל לא יקרא לשום כלי | כשרוצים רק תשובה טקסטואלית |
מה קורה: מפתח כותב @function_tool על פונקציה בלי docstring. ה-SDK לא משליך שגיאה, אבל הסוכן לא יודע מתי לקרוא לכלי.
למה זה מזיק: ה-description של הכלי נגזר מה-docstring. בלי תיאור -- המודל מנחש, ולעתים קרובות מנחש לא נכון.
הפתרון: תמיד כתבו docstring ברור שמסביר: מה הכלי עושה, מתי להשתמש בו, ומה כל פרמטר. כתבו כאילו אתם מסבירים לעובד חדש.
כתבו כלי משלכם: בחרו פונקציה מהתחום שלכם (חיפוש לקוח, בדיקת מלאי, המרת מטבע, חישוב מע"מ). הגדירו אותה עם @function_tool, type hints, ו-docstring. חברו אותה לסוכן ובדקו שהוא קורא לה נכון. טיפ: התחילו עם return של string קבוע -- אפשר לחבר API אמיתי אחר כך.
Structured Output -- פלט מובנה עם output_type
סוכן שמחזיר טקסט חופשי הוא בסדר לשיחה, אבל לא מספיק לפרודקשן. כשצריך לשמור תוצאות ב-database, לשלוח ל-API, או להציג ב-UI -- צריך structured output: JSON מוגדר מראש.
ב-OpenAI Agents SDK, structured output מוגדר עם Pydantic models (Python) או Zod schemas (TypeScript). מגדירים output_type על ה-Agent, וה-SDK מבטיח שהפלט תמיד עומד בסכמה.
from agents import Agent, Runner
from pydantic import BaseModel
class CompanyAnalysis(BaseModel):
"""Analysis result for an Israeli tech company."""
company_name: str
sector: str
founded_year: int
employee_count_estimate: int
funding_total_usd: float
strengths: list[str]
risks: list[str]
recommendation: str # "invest", "watch", "pass"
agent = Agent(
name="analyst",
instructions="""You are a senior tech analyst specializing in Israeli startups.
Analyze the given company and provide structured output.
Be specific with numbers and cite sources when possible.""",
output_type=CompanyAnalysis, # הפלט חייב להיות CompanyAnalysis
)
result = Runner.run_sync(agent, "Analyze Wiz (Israeli cybersecurity company)")
analysis = result.final_output_as(CompanyAnalysis)
print(f"Company: {analysis.company_name}")
print(f"Sector: {analysis.sector}")
print(f"Recommendation: {analysis.recommendation}")
print(f"Strengths: {', '.join(analysis.strengths)}")
הנקודה המרכזית: result.final_output_as(CompanyAnalysis) מחזיר אובייקט Python מובנה -- לא string, לא dict, אלא Pydantic model עם type safety. IDE נותן autocomplete, ויש ולידציה אוטומטית.
Structured Output ב-TypeScript
ב-TypeScript, structured output עובד עם Zod (כמו ב-Vercel AI SDK) ולא עם Pydantic:
import { Agent, run } from '@openai/agents';
import { z } from 'zod';
const CompanyAnalysisSchema = z.object({
company_name: z.string(),
sector: z.string(),
founded_year: z.number(),
strengths: z.array(z.string()),
risks: z.array(z.string()),
recommendation: z.enum(['invest', 'watch', 'pass']),
});
const agent = new Agent({
name: 'analyst',
instructions: 'Analyze Israeli tech companies. Be data-driven.',
outputType: CompanyAnalysisSchema,
});
const result = await run(agent, 'Analyze Monday.com');
console.log(result.finalOutput.recommendation); // "invest"
console.log(result.finalOutput.strengths); // ["Strong PLG motion", ...]
Nested Models ו-Enums
Pydantic models יכולים להיות מקוננים -- מודל בתוך מודל. זה חזק במיוחד כשהפלט מורכב:
from pydantic import BaseModel
from enum import Enum
class Priority(str, Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
class ActionItem(BaseModel):
description: str
assignee: str
priority: Priority
due_date: str
class MeetingSummary(BaseModel):
title: str
date: str
participants: list[str]
key_decisions: list[str]
action_items: list[ActionItem] # מודל מקונן!
next_meeting_date: str | None
meeting_agent = Agent(
name="Meeting Summarizer",
instructions="Summarize meeting transcripts into structured notes.",
output_type=MeetingSummary,
)
result = Runner.run_sync(meeting_agent, """
Meeting transcript: Yossi and Dana discussed the Q2 roadmap.
Decided to launch the AI feature by June 15. Dana will prepare
the design specs by May 20. Yossi to set up the staging environment
by May 25. Next sync: May 18.
""")
summary = result.final_output_as(MeetingSummary)
for item in summary.action_items:
print(f"[{item.priority.value}] {item.description} -> {item.assignee}")
צרו Pydantic model לתחום שלכם: אם אתם ב-e-commerce -- ProductReview. אם אתם ב-HR -- CandidateProfile. אם אתם ב-marketing -- CampaignBrief. הגדירו 5-8 שדות, כולל רשימות ו-enums. חברו ל-Agent עם output_type ובדקו שהפלט מובנה.
Handoffs -- העברת שליטה בין סוכנים
Handoffs הם ה-killer feature של OpenAI Agents SDK. הרעיון פשוט: סוכן אחד יכול להעביר את השליטה לסוכן אחר, ביחד עם כל ההקשר של השיחה. זה כמו שעובד תמיכה מעביר אותך למומחה -- בלי שתצטרכו לחזור על עצמכם.
from agents import Agent, Runner
# סוכנים מומחים
math_agent = Agent(
name="Math Tutor",
handoff_description="Specialist for math problems and calculations",
instructions="""You are a math tutor. Explain step by step.
Use examples with Israeli context (prices in ILS, distances in km).""",
)
history_agent = Agent(
name="History Tutor",
handoff_description="Specialist for historical questions",
instructions="""You are a history tutor. Focus on context and cause-effect.
Include Israeli and Middle Eastern history when relevant.""",
)
code_agent = Agent(
name="Code Tutor",
handoff_description="Specialist for programming questions",
instructions="""You are a programming tutor. Show code examples.
Support Python and TypeScript.""",
)
# סוכן מנתב
triage_agent = Agent(
name="Triage Agent",
instructions="""You are a study assistant router.
Based on the student's question, hand off to the right specialist:
- Math questions -> Math Tutor
- History questions -> History Tutor
- Programming questions -> Code Tutor
For general questions, answer directly.""",
handoffs=[math_agent, history_agent, code_agent],
)
# הרצה
result = Runner.run_sync(triage_agent, "איך כותבים לולאת for ב-Python?")
print(result.final_output)
# Code Tutor עונה על השאלה!
מה קורה מאחורי הקלעים?
- ה-Triage Agent מקבל את השאלה
- הוא מזהה שזו שאלת תכנות
- הוא מבצע handoff ל-Code Tutor
- Code Tutor מקבל את כל ההקשר של השיחה ועונה
result.final_outputמכיל את תשובת Code Tutor
Handoffs vs Agents-as-Tools
יש שתי דרכים לחבר סוכנים ב-OpenAI SDK. ההבדל קריטי:
| מאפיין | Handoff | Agent-as-Tool |
|---|---|---|
| שליטה | עוברת לסוכן החדש (הוא עונה) | נשארת בסוכן המקורי |
| הקשר | כל השיחה עוברת | רק ה-prompt הספציפי |
| מתאים ל- | ניתוב לפי תחום (triage) | קריאה לתוצאה (orchestration) |
| אנלוגיה | העברה למומחה (אתה נפגש איתו) | שליחת שליח (הוא חוזר עם תשובה) |
from agents import Agent, Runner
translator_es = Agent(
name="Spanish Translator",
instructions="Translate the user's message to Spanish.",
)
translator_fr = Agent(
name="French Translator",
instructions="Translate the user's message to French.",
)
orchestrator = Agent(
name="Translation Orchestrator",
instructions="You translate messages to multiple languages using your tools.",
tools=[
translator_es.as_tool(
tool_name="translate_to_spanish",
tool_description="Translate text to Spanish",
),
translator_fr.as_tool(
tool_name="translate_to_french",
tool_description="Translate text to French",
),
],
)
result = Runner.run_sync(orchestrator, "Say 'Hello' in Spanish and French")
print(result.final_output)
# Spanish: "Hola"
# French: "Bonjour"
בדוגמה הזו, ה-Orchestrator נשאר בשליטה. הוא שולח את הטקסט למתרגמים, מקבל חזרה תוצאות, ומחבר אותן בתשובה. ב-handoff, הסוכן הראשון מוותר על השליטה.
מה קורה: מפתח משתמש ב-handoffs כשצריך orchestration. התוצאה: סוכן אחד עונה במקום הסוכן הראשי, ומאבדים שליטה על הפורמט.
כלל האצבע: אם הסוכן הראשי צריך לאסוף תוצאות מסוכנים אחרים ולחבר אותן -- as_tool(). אם הוא צריך להעביר את השיחה למומחה -- handoffs.
הפתרון: שאלו את עצמכם: "מי צריך לענות למשתמש -- הסוכן הראשי או המומחה?" ראשי = as_tool. מומחה = handoff.
בנו Triage Agent פשוט: הגדירו 2 סוכנים מומחים מהתחום שלכם (למשל: "Sales Agent" ו-"Support Agent"). צרו Triage Agent עם handoffs=[sales_agent, support_agent]. שלחו 4 שאלות -- 2 של מכירות, 2 של תמיכה -- ובדקו שהניתוב נכון.
Multi-Agent Orchestration -- תזמור מערכות מרובות סוכנים
עכשיו שמבינים handoffs ו-agents-as-tools, אפשר לבנות מערכות מורכבות. ב-OpenAI Agents SDK יש שלושה דפוסים עיקריים:
דפוס 1: Triage (ניתוב)
סוכן מנתב שמפנה לפי הנושא. כבר ראינו את זה.
דפוס 2: Pipeline (שרשרת)
סוכנים ברצף -- כל אחד מעביר את השליטה הלאה.
from agents import Agent, Runner
editor = Agent(
name="Editor",
instructions="""You are a senior editor. Polish the article you receive:
- Fix grammar and clarity
- Ensure engaging opening paragraph
- Add a compelling headline
- Keep the content accurate""",
)
writer = Agent(
name="Writer",
instructions="""You are a content writer. Take the research notes you receive and write
a 500-word article. When done, hand off to the Editor for polishing.""",
handoffs=[editor],
)
researcher = Agent(
name="Researcher",
instructions="""You are a research specialist. When given a topic:
1. List 5 key facts
2. Note 2-3 statistics
3. Identify the main narrative angle
Then hand off to the Writer with your findings.""",
handoffs=[writer],
)
result = Runner.run_sync(researcher, "Write about AI adoption in Israeli startups")
print(result.final_output) # מאמר ערוך ומלוטש
דפוס 3: Orchestrator (תזמורן)
סוכן מרכזי שמשתמש בסוכנים אחרים ככלים, אוסף תוצאות, ומסנתז.
from agents import Agent, Runner
market_analyst = Agent(
name="Market Analyst",
instructions="Analyze the market size and trends for the given topic. Include Israeli market data.",
)
competitor_analyst = Agent(
name="Competitor Analyst",
instructions="Identify top 5 competitors and their strengths/weaknesses.",
)
financial_analyst = Agent(
name="Financial Analyst",
instructions="Estimate revenue potential, costs, and break-even timeline.",
)
ceo_agent = Agent(
name="CEO Advisor",
instructions="""You are a startup CEO advisor. Use your analyst tools to gather data,
then synthesize into a clear go/no-go recommendation with supporting evidence.""",
tools=[
market_analyst.as_tool("analyze_market", "Get market analysis"),
competitor_analyst.as_tool("analyze_competitors", "Get competitor analysis"),
financial_analyst.as_tool("analyze_financials", "Get financial projections"),
],
)
result = Runner.run_sync(ceo_agent, "Should we launch an AI writing tool for Hebrew content?")
print(result.final_output)
בחירת דפוס -- מתי מה
| דפוס | מתי להשתמש | דוגמה | סיבוכיות |
|---|---|---|---|
| Triage | שאלות מתחומים שונים, צריך מומחה לכל תחום | שירות לקוחות (billing / tech / sales) | נמוכה |
| Pipeline | תהליך רצף שכל שלב מוסיף ערך | מחקר → כתיבה → עריכה | בינונית |
| Orchestrator | צריך לאסוף מידע ממקורות שונים ולסנתז | ניתוח עסקי (שוק + מתחרים + פיננסים) | גבוהה |
כלל אצבע: התחילו תמיד ב-Triage (הכי פשוט). עברו ל-Pipeline רק כשיש תהליך ברור עם שלבים. Orchestrator -- רק כשצריך לאסוף ולסנתז מידע ממקורות מקבילים.
מה קורה: מפתח יוצר 10 סוכנים כשמספיקים 3.
למה זה בעיה: כל סוכן = LLM call = tokens = עלויות + latency. מערכת עם 10 סוכנים תהיה איטית, יקרה, וקשה לדיבוג. גם ה-Triage Agent מתקשה לנתב נכון כשיש 10 אפשרויות.
הפתרון: 2-4 סוכנים בשלב הראשון. הוסיפו סוכנים רק כשיש הוכחה שסוכן אחד לא מצליח לטפל במשימה. מדדו עם traces.
מטרה: בניית מערכת שירות לקוחות עם ניתוב חכם.
- צרו 3 סוכנים מומחים:
BillingAgent(שאלות על חיובים ותשלומים),TechSupportAgent(בעיות טכניות),SalesAgent(שדרוגים ומוצרים חדשים) - צרו
TriageAgentשמנתב לסוכן הנכון לפי תוכן השאלה - תנו לכל סוכן
handoff_descriptionברור - שלחו 6 שאלות (2 לכל קטגוריה) ובדקו שהניתוב מדויק
- הוסיפו כלי
check_account_statusל-BillingAgent
Success criteria: 5 מתוך 6 שאלות מנותבות לסוכן הנכון. BillingAgent משתמש בכלי.
עלות: ~$0.50
ציירו דיאגרמה: קחו נייר ועט וציירו את המערכת מתרגיל 1 -- חיצים מ-Triage Agent ל-3 סוכנים, כלים ליד כל סוכן. זה יעזור לכם לחשוב על הארכיטקטורה לפני הקוד.
Guardrails -- מעקות בטיחות לקלט ופלט
Guardrails (מעקות בטיחות) הם בדיקות שרצות בנוסף לסוכן עצמו. הם שומרים על איכות ובטיחות מ-2 כיוונים:
- Input Guardrails -- רצים על הקלט של המשתמש לפני שהסוכן מתחיל. חוסמים תוכן בעייתי, off-topic, או מזיק
- Output Guardrails -- רצים על הפלט של הסוכן אחרי שסיים. מוודאים שהתשובה עומדת בסטנדרטים
הרעיון המרכזי: guardrails רצים במקביל לסוכן (input guardrails) או מיד אחריו (output guardrails). הם משתמשים ב-LLM נפרד (יכול להיות מודל זול!) כדי לבדוק את התוכן.
from agents import (
Agent, Runner,
InputGuardrail, GuardrailFunctionOutput,
)
from agents.exceptions import InputGuardrailTripwireTriggered
from pydantic import BaseModel
# מודל פלט ל-guardrail
class RelevanceCheck(BaseModel):
is_relevant: bool
reasoning: str
# סוכן guardrail (יכול להשתמש במודל זול)
guardrail_agent = Agent(
name="Relevance Checker",
instructions="""Check if the user's message is about technology or business.
If it's about something completely unrelated (recipes, sports scores, gossip),
mark as not relevant.""",
output_type=RelevanceCheck,
model="gpt-5", # מודל זול מספיק לבדיקה
)
# פונקציית guardrail
async def check_relevance(ctx, agent, input_data):
result = await Runner.run(guardrail_agent, input_data, context=ctx.context)
check = result.final_output_as(RelevanceCheck)
return GuardrailFunctionOutput(
output_info=check,
tripwire_triggered=not check.is_relevant,
)
# הסוכן הראשי עם guardrail
main_agent = Agent(
name="Tech Advisor",
instructions="You are a tech advisor for Israeli businesses.",
input_guardrails=[
InputGuardrail(guardrail_function=check_relevance),
],
)
# שימוש
import asyncio
async def main():
# שאלה רלוונטית -- עוברת
try:
result = await Runner.run(main_agent, "What cloud provider should I use?")
print(result.final_output)
except InputGuardrailTripwireTriggered:
print("Blocked: not relevant!")
# שאלה לא רלוונטית -- נחסמת
try:
result = await Runner.run(main_agent, "What's the best hummus in Tel Aviv?")
print(result.final_output)
except InputGuardrailTripwireTriggered:
print("Blocked: not relevant!") # זה מה שיודפס
asyncio.run(main())
Output Guardrail
from agents import Agent, Runner, OutputGuardrail, GuardrailFunctionOutput
from agents.exceptions import OutputGuardrailTripwireTriggered
from pydantic import BaseModel
class SensitivityCheck(BaseModel):
contains_pii: bool
pii_types: list[str]
sensitivity_agent = Agent(
name="PII Detector",
instructions="""Check if the text contains PII (Personally Identifiable Information):
- Israeli ID numbers (teudat zehut)
- Credit card numbers
- Phone numbers
- Full addresses
List any PII types found.""",
output_type=SensitivityCheck,
)
async def check_pii(ctx, agent, output):
result = await Runner.run(sensitivity_agent, output, context=ctx.context)
check = result.final_output_as(SensitivityCheck)
return GuardrailFunctionOutput(
output_info=check,
tripwire_triggered=check.contains_pii,
)
safe_agent = Agent(
name="Customer Agent",
instructions="Help customers with their accounts.",
output_guardrails=[
OutputGuardrail(guardrail_function=check_pii),
],
)
מה קורה: מפתח מגדיר guardrail עם GPT-5.2 Pro ($21/$168 per 1M tokens) ל-כל קלט.
למה זה בעיה: guardrails רצים על כל הודעה. אם הסוכן שלכם מקבל 1,000 הודעות ביום, ה-guardrail יכול לעלות יותר מהסוכן עצמו.
הפתרון: השתמשו ב-מודל זול ל-guardrails (GPT-5 או אפילו GPT-4o-mini). הבדיקה היא פשוטה (סיווג binary) -- לא צריך את המודל החכם ביותר. גם model="gpt-5" מספיק ב-99% מהמקרים.
Guardrails ב-TypeScript
ב-TypeScript, guardrails עובדים באותו עיקרון אבל עם סינטקס שונה:
import { Agent, run } from '@openai/agents';
import { z } from 'zod';
const RelevanceSchema = z.object({
is_relevant: z.boolean(),
reasoning: z.string(),
});
const guardrailAgent = new Agent({
name: 'Relevance Check',
instructions: 'Check if the input is about technology. Return is_relevant: false if off-topic.',
outputType: RelevanceSchema,
});
const mainAgent = new Agent({
name: 'Tech Advisor',
instructions: 'You advise on tech topics.',
inputGuardrails: [
{
name: 'relevance_check',
execute: async (ctx, input) => {
const result = await run(guardrailAgent, input);
const check = result.finalOutput;
return {
tripwireTriggered: !check.is_relevant,
outputInfo: check,
};
},
},
],
});
שילוב Guardrails עם Handoffs
נקודה חשובה: Guardrails רצים רק על הסוכן הראשון בשרשרת. אם Triage Agent עם Input Guardrail מעביר שליטה ל-Specialist Agent -- ה-guardrail של ה-Triage רץ, אבל ה-Specialist לא מפעיל guardrails נוספים (אלא אם הגדרתם לו guardrails משלו).
המלצה: שימו Input Guardrail על ה-Triage Agent (נקודת הכניסה) ו-Output Guardrail על כל Specialist (נקודת היציאה). ככה מכסים את שני הכיוונים.
הוסיפו Input Guardrail לסוכן שלכם: חשבו על סוג קלט שאתם רוצים לחסום (spam, off-topic, שפה לא הולמת). הגדירו Pydantic model עם is_allowed: bool ו-reason: str. חברו ל-Agent עם input_guardrails. בדקו עם 2 קלטים: אחד שעובר ואחד שנחסם.
Tracing -- מעקב ודיבוג
אחד הדברים הכי frustrating בעבודה עם סוכנים: "למה הוא עשה את זה?" הסוכן קרא לכלי לא נכון, או עשה handoff מוזר, או נתן תשובה מוזרה -- ואתה לא יודע למה.
OpenAI Agents SDK פותר את זה עם Tracing מובנה -- כל ריצה של סוכן מתועדת אוטומטית. בלי קוד נוסף. בלי תשלום נוסף. פשוט נכנסים ל-OpenAI Dashboard ורואים הכל.
מה Trace מכיל?
| רכיב | מה הוא מציג | למה חשוב |
|---|---|---|
| Agent Spans | אילו סוכנים רצו ובאיזה סדר | לדבג handoffs ו-routing |
| LLM Calls | כל קריאה למודל: prompt, response, tokens | לראות מה הסוכן "חשב" |
| Tool Calls | אילו כלים נקראו, עם מה, ומה חזר | לדבג כלים שמחזירים תוצאות לא נכונות |
| Guardrails | אילו guardrails רצו ומה התוצאה | לראות אם guardrail חוסם בטעות |
| Timing | כמה זמן כל שלב לקח | למצוא צווארי בקבוק |
| Token Usage | כמה tokens נצרכו בכל שלב | אופטימיזציית עלויות |
Custom Trace Processors
ה-tracing המובנה שולח ל-OpenAI Dashboard, אבל אפשר גם לשלוח ל-מערכות חיצוניות:
from agents import set_trace_processors
from agents.tracing.processors import LangfuseTraceProcessor
# שולח traces גם ל-OpenAI Dashboard וגם ל-Langfuse
set_trace_processors([
LangfuseTraceProcessor(), # מעקב חיצוני
])
אפשר גם לכתוב Custom Processor שכותב ל-database שלכם, שולח ל-Datadog, או מתעד עלויות ב-Google Sheets.
Tracing עם שמות מותאמים
כשמריצים הרבה סוכנים, חשוב לזהות כל ריצה. אפשר להוסיף trace name ו-metadata לכל ריצה:
from agents import Agent, Runner
from agents.tracing import trace
# עוטפים את הריצה ב-trace מותאם
with trace("customer_support_flow", metadata={"user_id": "user_123", "channel": "web"}):
result = await Runner.run(
triage_agent,
"I want to cancel my subscription",
)
# ב-Dashboard: Trace שם "customer_support_flow" עם metadata
# מאפשר חיפוש לפי user_id, channel, וכו'
מה לחפש ב-Trace כשדברים לא עובדים
| בעיה | מה לחפש ב-Trace | פתרון אפשרי |
|---|---|---|
| סוכן לא קורא לכלי | בדקו את ה-system prompt -- האם הכלים מופיעים? | שפרו docstring, הוסיפו דוגמאות ב-instructions |
| Handoff לסוכן לא נכון | בדקו את ה-handoff_description של כל סוכן | עשו את ה-descriptions ספציפיים יותר |
| תשובה איטית (>10 שניות) | בדקו timing של כל span -- מי הצוואר בקבוק? | מודל זול יותר, prompt קצר יותר, פחות tools |
| עלויות גבוהות מהצפוי | בדקו token usage per span | הקטינו conversation history, השתמשו ב-GPT-5 במקום 5.2 |
| Guardrail חוסם בטעות | בדקו את ה-guardrail span -- מה ה-output_info? | שפרו את ה-instructions של ה-guardrail agent |
בדקו Trace אמיתי: הריצו את אחד הסוכנים שבניתם. היכנסו ל-platform.openai.com/traces. מצאו את ה-trace האחרון. לחצו ובדקו: (1) כמה LLM calls היו, (2) כמה tokens נצרכו, (3) כמה זמן הריצה לקחה. רשמו את המספרים -- תשתמשו בהם בתרגיל 2.
אינטגרציית MCP
OpenAI Agents SDK תומך ב-MCP (Model Context Protocol) -- הפרוטוקול הסטנדרטי שלמדנו בפרק 3. זה אומר שאפשר לחבר את הסוכנים שלכם ל-אלפי כלים קיימים דרך MCP Servers, בלי לכתוב את הכלים מחדש.
from agents import Agent, Runner
from agents.mcp import MCPServerStdio
# חיבור ל-MCP Server (filesystem server כדוגמה)
async with MCPServerStdio(
command="npx",
args=["-y", "@modelcontextprotocol/server-filesystem", "/tmp/data"],
) as mcp_server:
agent = Agent(
name="File Assistant",
instructions="You help users manage files. Use the filesystem tools.",
mcp_servers=[mcp_server], # הכלים נטענים אוטומטית
)
result = await Runner.run(agent, "List all files in the data directory")
print(result.final_output)
הסוכן מקבל את כל הכלים מה-MCP Server אוטומטית -- לא צריך להגדיר אותם ידנית. אפשר לחבר מספר MCP Servers לסוכן אחד, ולשלב אותם עם @function_tool רגילים.
MCP + Function Tools ביחד
אפשר לשלב MCP Servers עם @function_tool רגילים באותו סוכן. הכלים מ-MCP נטענים דינמית, והכלים ה-custom שלכם מוגדרים סטטית:
from agents import Agent, Runner, function_tool
from agents.mcp import MCPServerStdio
@function_tool
def calculate_vat(amount: float, rate: float = 17.0) -> str:
"""Calculate VAT (מע"מ) for Israeli transactions.
Args:
amount: The base amount in ILS
rate: VAT rate (default 17% for Israel)
"""
vat = amount * (rate / 100)
total = amount + vat
return f"Base: {amount:.2f} ILS, VAT ({rate}%): {vat:.2f} ILS, Total: {total:.2f} ILS"
async with MCPServerStdio(
command="npx",
args=["-y", "@modelcontextprotocol/server-filesystem", "/tmp/invoices"],
) as fs_server:
# סוכן עם כלים מ-2 מקורות: custom + MCP
accountant = Agent(
name="Accountant",
instructions="""You are an Israeli accountant assistant.
Use filesystem tools to read invoice files.
Use calculate_vat to compute VAT on amounts.""",
tools=[calculate_vat], # כלי custom
mcp_servers=[fs_server], # כלים מ-MCP
)
result = await Runner.run(accountant, "Read invoice.txt and calculate VAT on the total")
print(result.final_output)
SSE Transport ל-MCP Servers מרוחקים
בנוסף ל-MCPServerStdio (תהליכים מקומיים), ה-SDK תומך ב-MCPServerSse לשרתים מרוחקים שרצים כ-HTTP services:
from agents.mcp import MCPServerSse
async with MCPServerSse(
url="https://my-mcp-server.example.com/sse",
headers={"Authorization": "Bearer my-token"},
) as remote_server:
agent = Agent(
name="Remote Tool User",
instructions="Use the remote tools to complete tasks.",
mcp_servers=[remote_server],
)
מה קורה: MCP Server שלא מתנהל נכון נשאר פתוח ותופס משאבים.
הפתרון: השתמשו תמיד ב-async with (context manager) שמנהל connect/cleanup אוטומטית. לחלופין, השתמשו ב-MCPServerManager לניהול מרוכז של מספר servers.
תרשמו 3 MCP Servers שיעזרו לפרויקט שלכם: היכנסו ל-MCP Servers Repository ובחרו 3 servers רלוונטיים. כתבו את השמות שלהם ואיך הם יעזרו לסוכן שלכם. בפרק 3 למדנו על MCP בפירוט -- עכשיו אתם רואים את האינטגרציה בפועל.
מטרה: בניית סוכן מוגן עם guardrails ומעקב traces.
- צרו סוכן "Customer Support Agent" עם 2 כלים:
check_order_statusו-request_refund - הגדירו Input Guardrail שבודק ש-הקלט קשור לשירות לקוחות (לא פוליטיקה, לא בדיחות)
- הגדירו Output Guardrail שבודק ש-אין מספרי כרטיס אשראי או ת.ז. בתשובה
- הריצו 5 שיחות: 3 לגיטימיות, 1 off-topic (שייחסם ב-input), 1 שמנסה לגרום לסוכן לחשוף מידע רגיש
- היכנסו ל-OpenAI Dashboard → Traces. צלמו מסך של trace אחד ונתחו: כמה קריאות LLM, כמה tokens, איפה הזמן הכי ארוך
Success criteria: Input Guardrail חוסם off-topic. Output Guardrail חוסם PII. Traces נראים ב-Dashboard.
עלות: ~$1
Responses API מול Chat Completions
ברקע של Agents SDK עובד Responses API -- ה-API החדש של OpenAI (מרץ 2025) שמחליף את Chat Completions לשימושים אגנטיים. לא חייבים להכיר אותו כדי להשתמש ב-SDK, אבל כדאי להבין את ההבדל.
| מאפיין | Chat Completions (ישן) | Responses API (חדש) |
|---|---|---|
| עיצוב | שיחה פשוטה: messages in, message out | אגנטי: input, tools, handoffs, tracing |
| Tool orchestration | ידני -- אתה מנהל את הלולאה | מובנה -- ה-API מנהל tool loops |
| Web Search | לא מובנה (צריך כלי חיצוני) | מובנה כ-tool |
| File Search | לא מובנה | מובנה כ-tool |
| Code Interpreter | לא זמין | מובנה כ-tool |
| Conversation history | אתה שולח את כל ה-messages כל פעם | ה-API שומר state עם previous_response_id |
| Streaming | SSE פשוט | SSE מתקדם עם events לכל שלב |
מתי Chat Completions: שימוש פשוט, צריכים backward compatibility, לא צריכים tools מובנים.
מתי Responses API: בניית סוכנים, צריכים Code Interpreter / Web Search / File Search, רוצים state management אוטומטי.
ה-Agents SDK משתמש ב-Responses API מאחורי הקלעים. כשאתם כותבים Runner.run(), הוא שולח את הכל דרך Responses API -- כולל tools, handoffs, ו-tracing. אתם לא צריכים לעבוד ישירות עם ה-API, אלא אם אתם צריכים שליטה low-level.
Built-in Tools דרך Responses API
from agents import Agent, Runner
from agents.tools import CodeInterpreterTool, WebSearchTool, FileSearchTool
# סוכן עם Code Interpreter -- יכול לכתוב ולהריץ Python
data_agent = Agent(
name="Data Analyst",
instructions="""You are a data analyst. When asked to analyze data:
1. Write Python code to process the data
2. Execute it with Code Interpreter
3. Present findings clearly""",
tools=[CodeInterpreterTool()],
)
# סוכן עם Web Search -- יכול לחפש באינטרנט
research_agent = Agent(
name="Researcher",
instructions="You research topics using web search. Cite sources.",
tools=[WebSearchTool()],
)
# סוכן עם File Search -- יכול לחפש במסמכים
knowledge_agent = Agent(
name="Knowledge Base",
instructions="You answer questions based on uploaded documents.",
tools=[FileSearchTool(vector_store_ids=["vs_abc123"])],
)
נסו Code Interpreter: צרו סוכן עם CodeInterpreterTool() ושלחו לו "Calculate the first 20 Fibonacci numbers and plot them as a chart". בדקו ש-Code Interpreter כותב קוד Python, מריץ אותו, ומחזיר תוצאה. שימו לב לעלות: ~$0.03 per session.
Sessions -- זיכרון בין שיחות
אחד הפיצ'רים החדשים ב-Agents SDK (דרך Responses API) הוא Sessions -- ניהול אוטומטי של היסטוריית שיחה. במקום לשלוח את כל ה-messages כל פעם (כמו ב-Chat Completions), ה-API שומר את ההקשר בצד השרת.
from agents import Agent, Runner
agent = Agent(
name="advisor",
instructions="You are a financial advisor. Remember previous context.",
)
# שיחה ראשונה
result1 = Runner.run_sync(agent, "I have 500K ILS to invest.")
# ה-SDK מחזיר previous_response_id
# שיחה שנייה -- ממשיכה את ההקשר!
result2 = Runner.run_sync(
agent,
"What about real estate in Tel Aviv?",
previous_response_id=result1.last_response_id,
)
# הסוכן זוכר שיש 500K ILS
היתרון: לא שולחים את כל ההיסטוריה (חוסך tokens). החיסרון: ה-state נמצא בשרתי OpenAI (פחות שליטה). לפרויקטים עם דרישות privacy -- שקלו לנהל את ההיסטוריה בעצמכם.
מה קורה: Sessions שומרים conversation history בשרתי OpenAI. לעסקים ישראליים שמטפלים במידע אישי של לקוחות אירופיים (GDPR) או ישראליים (חוק הגנת הפרטיות) -- זה יכול להיות בעייתי.
הפתרון: (1) בדקו את OpenAI Data Processing Addendum, (2) אל תשמרו PII ב-sessions, (3) לדרישות מחמירות -- נהלו היסטוריה בעצמכם עם previous_response_id=None ושלחו context ידנית.
OpenAI SDK מול Claude Agent SDK מול Vercel AI SDK
עכשיו שהכרתם 3 SDKs (Claude בפרק 5, Vercel AI SDK בפרק 6, ו-OpenAI בפרק זה), בואו נשווה אותם head-to-head. ההשוואה הזו היא אחד הדברים הכי חשובים בקורס -- כי בחירת ה-SDK הנכון חוסכת חודשים של עבודה.
| קריטריון | OpenAI Agents SDK | Claude Agent SDK | Vercel AI SDK |
|---|---|---|---|
| שפה ראשית | Python (+ TypeScript) | Python (+ TypeScript) | TypeScript (בלבד) |
| מודלים | OpenAI בלבד | Claude בלבד | 20+ providers |
| Multi-agent | Handoffs + agents-as-tools | Handoffs + sub-agents | Manual (אתה מחבר) |
| Guardrails | מובנה (Input + Output) | חלקי | אין מובנה |
| Tracing | מובנה + Dashboard חינם | מובנה | OpenTelemetry (צריך setup) |
| Code Interpreter | מובנה | אין | אין |
| Extended Thinking | אין | מובנה (Claude Opus) | דרך provider |
| Computer Use | אין | מובנה | אין |
| UI Components | אין מובנה | אין מובנה | useChat, RSC, generative UI |
| MCP Support | כן (mcp_servers) | כן (native) | כן (createMCPClient) |
| Voice/Realtime | RealtimeAgent + SIP | אין | אין מובנה |
| רישיון | MIT | MIT | Apache 2.0 |
אותו סוכן בשלוש SDKs -- השוואת קוד
בואו נראה את אותו סוכן פשוט (עם כלי מזג אוויר) בשלוש ה-SDKs. שימו לב להבדלים בסינטקס:
from agents import Agent, Runner, function_tool
@function_tool
def get_weather(city: str) -> str:
"""Get weather for a city."""
return f"Sunny, 28C in {city}"
agent = Agent(name="assistant", instructions="Help with weather.", tools=[get_weather])
result = Runner.run_sync(agent, "Weather in Tel Aviv?")
print(result.final_output)
import { ToolLoopAgent, tool } from 'ai';
import { z } from 'zod';
const getWeather = tool({
description: 'Get weather for a city',
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => `Sunny, 28C in ${city}`,
});
const agent = new ToolLoopAgent({
model: 'openai/gpt-5',
tools: { getWeather },
instructions: 'Help with weather.',
});
const { text } = await agent.generate('Weather in Tel Aviv?');
console.log(text);
שלושת הקטעים עושים אותו דבר בדיוק. ההבדלים: OpenAI SDK משתמש ב-@function_tool decorator (הכי נקי ב-Python), Vercel AI SDK משתמש ב-tool() עם Zod (הכי נקי ב-TypeScript). Claude Agent SDK (פרק 5) דומה מאוד ל-OpenAI SDK בסינטקס -- כי שניהם למדו אחד מהשני.
עלויות -- השוואה מעשית
| משימה | OpenAI (GPT-5) | Claude (Sonnet 4.5) | Google (Gemini Flash) |
|---|---|---|---|
| שיחת Chat פשוטה (500 tokens) | ~$0.006 | ~$0.009 | ~$0.001 |
| Agent עם 3 tool calls | ~$0.05 | ~$0.07 | ~$0.01 |
| Multi-agent pipeline (5 agents) | ~$0.30 | ~$0.45 | ~$0.06 |
| 1,000 שיחות יומיות | ~$50/יום | ~$70/יום | ~$10/יום |
שימו לב: המחירים משוערים למרץ 2026 ומשתנים לעתים קרובות. הנקודה החשובה היא היחס: Gemini Flash זול פי 5-7 מ-GPT-5, ו-GPT-5 זול מ-Claude Sonnet. אבל מחיר =/= איכות -- כל מודל מצטיין במשהו אחר.
עקבו אחרי עץ ההחלטה:
- צריכים multi-provider? (Claude + GPT + Gemini) → Vercel AI SDK
- צריכים Code Interpreter או Voice agents? → OpenAI Agents SDK
- צריכים extended thinking או computer use? → Claude Agent SDK
- צריכים handoffs נקיים עם guardrails? → OpenAI Agents SDK
- בונים Next.js app עם Chat UI? → Vercel AI SDK
- הפרויקט הוא Python-first? → OpenAI SDK או Claude SDK
- לא בטוחים? → התחילו עם Vercel AI SDK (הכי גמיש), מעברו אח"כ אם צריך
מטרה: בניית אותו סוכן גם ב-OpenAI SDK וגם ב-Vercel AI SDK (מפרק 6), להשוואה ישירה.
- הגדירו סוכן "Travel Advisor" עם 2 כלים:
search_flights(from, to, date)ו-get_hotel_prices(city, check_in, nights) - ב-OpenAI SDK:
Agent+@function_tool+Runner.run_sync() - ב-Vercel AI SDK:
ToolLoopAgent+tool()עם Zod +generate() - שלחו את אותן 3 שאילתות לשניהם: (a) "Find flights from TLV to NYC next month", (b) "Hotel prices in Rome for 5 nights", (c) "Plan a trip to Berlin -- flights + hotel"
- השוו: syntax, token usage, latency, output quality. תעדו בטבלה
Success criteria: שני הסוכנים עובדים עם אותם כלים. יש לכם טבלת השוואה עם לפחות 5 קריטריונים.
עלות: ~$2
Voice Agents -- RealtimeAgent
OpenAI Agents SDK כולל תמיכה ב-Voice Agents (סוכני קול) דרך RealtimeAgent ו-RealtimeSession. זה מאפשר לבנות סוכנים שמדברים -- קול-לקול, ב-latency נמוך. הטכנולוגיה מבוססת על OpenAI Realtime API עם תמיכה ב-SIP (Session Initiation Protocol) ו-WebSocket.
from agents.realtime import RealtimeAgent, RealtimeSession
# הגדרת סוכן קולי
voice_agent = RealtimeAgent(
name="Phone Support",
instructions="""You are a phone support agent for an Israeli tech company.
Speak naturally in Hebrew. Be concise -- phone conversations should be short.
If you can't help, offer to transfer to a human agent.""",
tools=[check_order_status, create_ticket],
handoffs=[human_agent],
)
# הפעלת session (WebSocket)
async with RealtimeSession(agent=voice_agent) as session:
# session מטפל ב-audio input/output אוטומטית
await session.run()
Use cases ישראליים: שירות לקוחות טלפוני (מוקד) עם סוכן AI שעונה בעברית, IVR חכם שמבין שאלות חופשיות במקום "הקש 1 לשירות", ו-appointment scheduling בקליניקות ומספרות. הטכנולוגיה עדיין מתפתחת, אבל כבר ניתנת לשימוש ב-POC.
מה קורה: Voice agents צורכים audio tokens (input ו-output) בנוסף ל-text tokens. שיחה של 5 דקות יכולה לעלות $0.50-$2.
הפתרון: התחילו עם text agents ותעברו ל-voice רק כש-ROI ברור. בשיחות קצרות (1-2 דקות) העלות סבירה. לשיחות ארוכות -- שקלו hybrid (voice לניתוב, text לטיפול).
Israeli Context -- דוגמאות מהשטח
כמה דפוסים ספציפיים לשוק הישראלי:
| תחום | דפוס מומלץ | סוכנים | כלים |
|---|---|---|---|
| חנות אונליין | Triage | מכירות / תמיכה / החזרות | חיפוש מוצרים, חישוב משלוח+מע"מ, בדיקת סטטוס הזמנה |
| סטארטאפ SaaS | Orchestrator | Onboarding / Technical / Billing | API status check, documentation search, Stripe integration |
| סוכנות שיווק | Pipeline | מחקר → קופי → עריכה | Google Trends, competitor analysis, Hebrew spellcheck |
| משרד עורכי דין | Triage + Guardrails | intake → מומחה לפי תחום | File Search (פסיקות), חיפוש חקיקה, calendar |
שימו לב: בכל הדוגמאות, guardrails הם חובה. סוכן שירות לקוחות שמחשוף מידע רגיש, סוכן משפטי שנותן ייעוץ שגוי, סוכן מכירות שמבטיח דברים שלא ניתן לקיים -- כל אלה סיכונים עסקיים. Guardrails = ביטוח.
טעויות נפוצות -- ואיך להימנע מהן
מה קורה: מפתח מתחיל פרויקט חדש עם Assistants API כי מצא טוטוריאל מ-2024.
למה זה בעיה: Assistants API הוא הגישה הישנה של OpenAI. Agents SDK מחליף אותו עם ארכיטקטורה טובה יותר: multi-agent, guardrails, tracing, ושליטה מלאה בקוד (לא state בשרת).
הפתרון: לפרויקטים חדשים -- תמיד Agents SDK. מיגרציה מ-Assistants API: החליפו client.beta.assistants ב-Agent, client.beta.threads ב-Runner.
מה קורה: Agent A → Agent B → Agent C → Agent D → Agent E. שרשרת של 5+ handoffs.
למה זה בעיה: כל handoff = קריאת LLM נוספת + כל ה-conversation history. שרשרת ארוכה = עלויות גבוהות, latency ארוך, ו-context window שמתמלא.
הפתרון: מקסימום 3 handoffs ברצף. אם צריכים יותר -- השתמשו ב-agents-as-tools (orchestrator pattern) במקום handoffs. כך ה-orchestrator שולט ולא כל ההיסטוריה עוברת.
מה קורה: מפתח משתמש ב-Runner.run() (async) בלי await, או ב-Runner.run_sync() בתוך async function.
למה זה בעיה: Runner.run() בלי await מחזיר coroutine, לא תוצאה. run_sync() בתוך async function חוסם את ה-event loop.
הפתרון: כלל פשוט: סקריפט פשוט = Runner.run_sync(). Web server / async code = await Runner.run(). לעולם אל תערבבו.
מה קורה: import openai; openai.api_key = "sk-proj-abc123..." ישירות בקוד.
למה זה בעיה: Git push = ה-key חשוף. בוטים סורקים GitHub ומשתמשים במפתחות תוך דקות. עלויות של מאות ואלפי דולרים.
הפתרון: ה-SDK קורא אוטומטית את OPENAI_API_KEY מ-environment variables. הגדירו: export OPENAI_API_KEY=sk-proj-... ב-terminal, או .env + python-dotenv. ודאו ש-.env ב-.gitignore.
מה קורה: סוכן עם tools שנכנס ללולאה אינסופית -- קורא לכלי, לא מרוצה מהתוצאה, קורא שוב, וחוזר חלילה.
למה זה בעיה: כל לולאה = API call = tokens = כסף. סוכן בלולאה יכול לשרוף $50+ תוך שעה.
הפתרון: הגדירו max_turns ב-Runner.run(): Runner.run_sync(agent, input, max_turns=10). זה מגביל את מספר הצעדים. לפרודקשן -- הוסיפו גם timeout ו-cost budget.
מטרה: בניית מערכת multi-agent שלמה עם כל מה שלמדנו.
- צרו Research Agent עם WebSearchTool שחוקר נושא
- צרו Writer Agent שכותב מאמר על סמך המחקר (structured output:
Articleעםtitle,body,key_takeaways) - צרו Quality Agent שבודק את המאמר (structured output:
QualityReportעםscore,issues,pass) - חברו את שלושתם ב-pipeline: Research → Writer → Quality (handoffs)
- הוסיפו Input Guardrail ל-Research Agent שבודק שהנושא לגיטימי
- הריצו על 3 נושאים שונים ובדקו traces ב-Dashboard
Success criteria: Pipeline עובד end-to-end. Guardrail חוסם נושא לא הולם. Traces מראים את כל הצעדים.
עלות: ~$3-5
| תדירות | משימה | זמן |
|---|---|---|
| יומי | בדקו traces ב-OpenAI Dashboard -- שגיאות, tool failures, guardrail blocks | 5 דק' |
| יומי | בדקו token usage ועלויות -- ודאו שאין סוכנים ב-loop | 3 דק' |
| שבועי | סקרו guardrail logs -- האם יש false positives (חסימות מיותרות)? | 10 דק' |
| שבועי | בדקו אם יש עדכון ל-openai-agents: pip install --upgrade openai-agents | 5 דק' |
| חודשי | A/B test -- בדקו אם GPT-5 (זול) מספיק במקום GPT-5.2 לסוכנים ספציפיים | 20 דק' |
| חודשי | סקרו handoff accuracy -- האם ה-triage agent מנתב נכון? בדקו ב-traces | 15 דק' |
בנו Triage Agent עם 2 סוכנים מומחים ו-handoffs. 15 שורות קוד: Agent ראשון, Agent שני, Triage Agent עם handoffs=[agent1, agent2], ו-Runner.run_sync(). שלחו 4 שאלות ובדקו שהניתוב עובד. ברגע שתראו סוכן אחד מעביר שליטה לסוכן אחר בצורה טבעית -- תבינו למה handoffs הם game changer.
- מה ההבדל בין Handoff ל-agents-as-tools? תנו דוגמה של מצב שבו כל אחד מתאים. (רמז: מי עונה למשתמש?)
- למה guardrails צריכים לרוץ על מודל זול ולא על אותו מודל כמו הסוכן? מה הסיכון? (רמז: עלויות, volume)
- מה ההבדל בין
Runner.run_sync(),Runner.run(), ו-Runner.run_streamed()? מתי תשתמשו בכל אחד? (רמז: sync vs async vs UX) - הסבירו מה Trace מכיל ואיך הוא עוזר לדבג סוכן שנותן תשובות לא נכונות. (רמז: agent spans, tool calls, token usage)
- תנו 3 סיבות לבחור OpenAI Agents SDK ו-3 סיבות לבחור Vercel AI SDK. (רמז: handoffs, guardrails, multi-provider, UI)
עברתם 4 מתוך 5? מצוין -- אתם מוכנים לפרק 8.
בפרק הזה בניתם סוכנים מלאים עם OpenAI Agents SDK -- מ-Agent פשוט בן 3 שורות ועד מערכת multi-agent עם handoffs, guardrails, ו-tracing. הכרתם את ארבע אבני הבניין (Agent, Handoff, Guardrail, Tracing) ולמדתם מתי להשתמש בכל אחת. בניתם כלים עם @function_tool, ראיתם structured output עם Pydantic, והבנתם את ההבדל הקריטי בין handoffs (העברת שליטה) ל-agents-as-tools (שליחת שליח).
התובנה המרכזית: OpenAI Agents SDK מצטיין ב-multi-agent orchestration. מודל ה-handoffs שלו הוא הנקי ביותר בשוק, ה-guardrails מובנים (לא צריך ספרייה חיצונית), וה-tracing חינמי ומיידי. המחיר: תלות ב-OpenAI בלבד, אין multi-provider, ואין UI components.
בפרק הבא (פרק 8) נעבור ל-LangGraph -- ונלמד לבנות סוכנים כ-state machines עם checkpoints, branching ו-human-in-the-loop שרצים לאורך זמן.
צ'קליסט -- סיום פרק 7
- ☐ התקנתי
openai-agents(Python) או@openai/agents(TypeScript) והגדרתי API key - ☐ בניתי Agent בסיסי עם
name,instructions, ו-model-- והרצתי עםRunner.run_sync() - ☐ הגדרתי לפחות 2 כלים עם
@function_toolכולל type hints ו-docstring - ☐ בניתי סוכן עם
output_type(Pydantic model) שמחזיר structured output - ☐ בניתי מערכת Triage Agent עם
handoffsל-2 סוכנים מומחים לפחות - ☐ מבין/ה את ההבדל בין Handoff ל-agents-as-tools ויודע/ת מתי להשתמש בכל אחד
- ☐ הגדרתי Input Guardrail שחוסם קלט לא רלוונטי
- ☐ הגדרתי Output Guardrail שבודק פלט (PII, פורמט, וכו')
- ☐ נכנסתי ל-OpenAI Dashboard → Traces ובדקתי trace של ריצת סוכן
- ☐ מכיר/ה את Built-in Tools: Code Interpreter, Web Search, File Search
- ☐ מבין/ה את ההבדל בין Responses API ל-Chat Completions
- ☐ חיברתי MCP Server לסוכן עם
mcp_servers(או מבין/ה איך לעשות) - ☐ עבדתי על לפחות 3 מתוך 4 תרגילים
- ☐ מכיר/ה את טבלת ההשוואה: OpenAI SDK vs Claude SDK vs Vercel AI SDK
- ☐ עניתי על 4 מתוך 5 שאלות ב"בדוק את עצמך"