7 בניית מיומנויות

OpenAI Agents SDK — בניית סוכנים עם GPT

ה-SDK הרשמי של OpenAI לבניית סוכני AI. בפרק הזה תלמדו לבנות סוכנים ב-Python וב-TypeScript עם Agent, Runner, ו-@function_tool. תכירו את מודל ה-Handoffs הנקי ביותר בשוק, תבנו מערכות multi-agent עם triage, תגדירו Guardrails לקלט ופלט, תחברו MCP Servers, ותעקבו אחרי כל צעד עם Tracing מובנה. בסוף הפרק -- יהיו לכם סוכנים עובדים שמדברים זה עם זה, מוגנים מקלט בעייתי, ומתועדים מ-A עד Z.

מה יהיה לך בסוף הפרק הזה
מה תוכלו לעשות אחרי הפרק הזה
לפני שמתחילים
הפרויקט שלך -- קו אדום לאורך הקורס

בפרק 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.

מילון מונחים -- פרק 7
מונח (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 -- מאפשר לסוכן לקרוא לכלים חיצוניים דרך פרוטוקול סטנדרטי
מתחיל 10 דקות חינם

סקירה ופילוסופיה -- למה 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?

מתי לא להשתמש

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 לשינויים.

עלויות (מרץ 2026)
מודלInput/1M tokensOutput/1M tokensContext
GPT-5$1.25$101M
GPT-5.2$1.75$141M
GPT-5.2 Pro$21$1681M
GPT-5.4$2.50$151.05M

ה-SDK עצמו חינמי. התשלום הוא רק על קריאות API. כלים מובנים: Web Search ~$25-30/1K queries, File Search ~$2.50/1K queries, Code Interpreter ~$0.03/session.

מסגרת החלטה: OpenAI Agents SDK מול Assistants API
קריטריוןAgents SDK (חדש)Assistants API (ישן)ההמלצה
ארכיטקטורהקוד ב-client, אתה שולטState ב-server, OpenAI שולטSDK -- שליטה מלאה
Multi-agentHandoffs + agents-as-toolsאין תמיכה nativeSDK -- הרבה יותר חזק
Guardrailsמובנה (input + output)איןSDK
Tracingמובנה, חינםאיןSDK
Code Interpreterככלי של סוכןככלי של assistantשניהם זהים
בשלותחדש (מרץ 2025)ותיק (2023)SDK כבר יציב

שורה תחתונה: אם אתם מתחילים פרויקט חדש -- Agents SDK. אם יש לכם Assistants API קיים -- תכננו מיגרציה, אבל אין לחץ מיידי.

עשה עכשיו 3 דקות

התקינו את ה-SDK: פתחו טרמינל והריצו pip install openai-agents (Python) או npm install @openai/agents (TypeScript). ודאו ש-OPENAI_API_KEY מוגדר כ-environment variable. בדקו עם python -c "from agents import Agent; print('OK')".

מתחיל 15 דקות $0.05

הסוכן הראשון שלך -- Agent + Runner

בואו נבנה סוכן ב-3 שורות. זה לא פשטנות -- זו באמת הפילוסופיה של ה-SDK. כל סוכן הוא Agent (מי הוא ומה יש לו) ו-Runner (מה שמריץ אותו).

Python -- הסוכן הראשון שלך
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:

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

Python -- 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, וככה גם הסוכנים שלכם צריכים לעבוד.

Python -- Streaming עם run_streamed
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).

Python -- שיתוף context בין סוכנים
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)
עשה עכשיו 5 דקות

הריצו את הסוכן הראשון: צרו קובץ my_agent.py, העתיקו את הקוד למעלה, והריצו. שנו את ה-instructions לתפקיד אחר (למשל: "You are an Israeli tech startup advisor"). שלחו 3 שאלות שונות ובדקו את התשובות. רשמו: מה עבד, מה לא, ואיזה instructions עבדו הכי טוב.

בינוני 20 דקות $0.50

Function Tools -- כלים לסוכן

סוכן בלי כלים הוא סתם chatbot. Function Tools (כלי-פונקציות) הם מה שהופך LLM לסוכן -- היכולת לקרוא לפונקציות, לקבל תוצאות, ולהמשיך לחשוב.

ב-OpenAI Agents SDK, הגדרת כלי היא פשוטה במיוחד: כותבים פונקציית Python רגילה עם type hints ו-docstring, שמים עליה את ה-decorator @function_tool, וזהו. ה-SDK שולף אוטומטית את ה-JSON Schema מה-type hints.

Python -- הגדרת כלים עם @function_tool
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 -- אותו דבר, סינטקס שונה

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"המודל לא יקרא לשום כליכשרוצים רק תשובה טקסטואלית
טעות נפוצה: חוסר docstring בכלים

מה קורה: מפתח כותב @function_tool על פונקציה בלי docstring. ה-SDK לא משליך שגיאה, אבל הסוכן לא יודע מתי לקרוא לכלי.

למה זה מזיק: ה-description של הכלי נגזר מה-docstring. בלי תיאור -- המודל מנחש, ולעתים קרובות מנחש לא נכון.

הפתרון: תמיד כתבו docstring ברור שמסביר: מה הכלי עושה, מתי להשתמש בו, ומה כל פרמטר. כתבו כאילו אתם מסבירים לעובד חדש.

עשה עכשיו 5 דקות

כתבו כלי משלכם: בחרו פונקציה מהתחום שלכם (חיפוש לקוח, בדיקת מלאי, המרת מטבע, חישוב מע"מ). הגדירו אותה עם @function_tool, type hints, ו-docstring. חברו אותה לסוכן ובדקו שהוא קורא לה נכון. טיפ: התחילו עם return של string קבוע -- אפשר לחבר API אמיתי אחר כך.

בינוני 15 דקות $0.30

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 מבטיח שהפלט תמיד עומד בסכמה.

Python -- סוכן עם structured output
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:

TypeScript -- structured output עם Zod
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 יכולים להיות מקוננים -- מודל בתוך מודל. זה חזק במיוחד כשהפלט מורכב:

Python -- Nested 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}")
עשה עכשיו 5 דקות

צרו Pydantic model לתחום שלכם: אם אתם ב-e-commerce -- ProductReview. אם אתם ב-HR -- CandidateProfile. אם אתם ב-marketing -- CampaignBrief. הגדירו 5-8 שדות, כולל רשימות ו-enums. חברו ל-Agent עם output_type ובדקו שהפלט מובנה.

בינוני 20 דקות $1

Handoffs -- העברת שליטה בין סוכנים

Handoffs הם ה-killer feature של OpenAI Agents SDK. הרעיון פשוט: סוכן אחד יכול להעביר את השליטה לסוכן אחר, ביחד עם כל ההקשר של השיחה. זה כמו שעובד תמיכה מעביר אותך למומחה -- בלי שתצטרכו לחזור על עצמכם.

Python -- Handoff פשוט: Triage Agent
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 עונה על השאלה!

מה קורה מאחורי הקלעים?

  1. ה-Triage Agent מקבל את השאלה
  2. הוא מזהה שזו שאלת תכנות
  3. הוא מבצע handoff ל-Code Tutor
  4. Code Tutor מקבל את כל ההקשר של השיחה ועונה
  5. result.final_output מכיל את תשובת Code Tutor

Handoffs vs Agents-as-Tools

יש שתי דרכים לחבר סוכנים ב-OpenAI SDK. ההבדל קריטי:

מאפייןHandoffAgent-as-Tool
שליטהעוברת לסוכן החדש (הוא עונה)נשארת בסוכן המקורי
הקשרכל השיחה עוברתרק ה-prompt הספציפי
מתאים ל-ניתוב לפי תחום (triage)קריאה לתוצאה (orchestration)
אנלוגיההעברה למומחה (אתה נפגש איתו)שליחת שליח (הוא חוזר עם תשובה)
Python -- agents-as-tools pattern
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, הסוכן הראשון מוותר על השליטה.

טעות נפוצה: שימוש ב-Handoff במקום agents-as-tools

מה קורה: מפתח משתמש ב-handoffs כשצריך orchestration. התוצאה: סוכן אחד עונה במקום הסוכן הראשי, ומאבדים שליטה על הפורמט.

כלל האצבע: אם הסוכן הראשי צריך לאסוף תוצאות מסוכנים אחרים ולחבר אותן -- as_tool(). אם הוא צריך להעביר את השיחה למומחה -- handoffs.

הפתרון: שאלו את עצמכם: "מי צריך לענות למשתמש -- הסוכן הראשי או המומחה?" ראשי = as_tool. מומחה = handoff.

עשה עכשיו 5 דקות

בנו Triage Agent פשוט: הגדירו 2 סוכנים מומחים מהתחום שלכם (למשל: "Sales Agent" ו-"Support Agent"). צרו Triage Agent עם handoffs=[sales_agent, support_agent]. שלחו 4 שאלות -- 2 של מכירות, 2 של תמיכה -- ובדקו שהניתוב נכון.

בינוני 20 דקות $2

Multi-Agent Orchestration -- תזמור מערכות מרובות סוכנים

עכשיו שמבינים handoffs ו-agents-as-tools, אפשר לבנות מערכות מורכבות. ב-OpenAI Agents SDK יש שלושה דפוסים עיקריים:

דפוס 1: Triage (ניתוב)

סוכן מנתב שמפנה לפי הנושא. כבר ראינו את זה.

דפוס 2: Pipeline (שרשרת)

סוכנים ברצף -- כל אחד מעביר את השליטה הלאה.

Python -- Pipeline: Researcher → Writer → Editor
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 (תזמורן)

סוכן מרכזי שמשתמש בסוכנים אחרים ככלים, אוסף תוצאות, ומסנתז.

Python -- Orchestrator שאוסף מידע מ-3 מקורות
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.

תרגיל 1: מערכת Triage עם 3 סוכנים 25 דקות

מטרה: בניית מערכת שירות לקוחות עם ניתוב חכם.

  1. צרו 3 סוכנים מומחים: BillingAgent (שאלות על חיובים ותשלומים), TechSupportAgent (בעיות טכניות), SalesAgent (שדרוגים ומוצרים חדשים)
  2. צרו TriageAgent שמנתב לסוכן הנכון לפי תוכן השאלה
  3. תנו לכל סוכן handoff_description ברור
  4. שלחו 6 שאלות (2 לכל קטגוריה) ובדקו שהניתוב מדויק
  5. הוסיפו כלי check_account_status ל-BillingAgent

Success criteria: 5 מתוך 6 שאלות מנותבות לסוכן הנכון. BillingAgent משתמש בכלי.

עלות: ~$0.50

עשה עכשיו 3 דקות

ציירו דיאגרמה: קחו נייר ועט וציירו את המערכת מתרגיל 1 -- חיצים מ-Triage Agent ל-3 סוכנים, כלים ליד כל סוכן. זה יעזור לכם לחשוב על הארכיטקטורה לפני הקוד.

בינוני 20 דקות $0.50

Guardrails -- מעקות בטיחות לקלט ופלט

Guardrails (מעקות בטיחות) הם בדיקות שרצות בנוסף לסוכן עצמו. הם שומרים על איכות ובטיחות מ-2 כיוונים:

הרעיון המרכזי: guardrails רצים במקביל לסוכן (input guardrails) או מיד אחריו (output guardrails). הם משתמשים ב-LLM נפרד (יכול להיות מודל זול!) כדי לבדוק את התוכן.

Python -- Input Guardrail שבודק רלוונטיות
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

Python -- 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),
    ],
)
טעות נפוצה: Guardrails יקרים מדי

מה קורה: מפתח מגדיר 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 עובדים באותו עיקרון אבל עם סינטקס שונה:

TypeScript -- Input Guardrail
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 (נקודת היציאה). ככה מכסים את שני הכיוונים.

עשה עכשיו 5 דקות

הוסיפו Input Guardrail לסוכן שלכם: חשבו על סוג קלט שאתם רוצים לחסום (spam, off-topic, שפה לא הולמת). הגדירו Pydantic model עם is_allowed: bool ו-reason: str. חברו ל-Agent עם input_guardrails. בדקו עם 2 קלטים: אחד שעובר ואחד שנחסם.

בינוני 15 דקות חינם

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, אבל אפשר גם לשלוח ל-מערכות חיצוניות:

Python -- שליחת traces ל-Langfuse
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 לכל ריצה:

Python -- Tracing עם 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
עשה עכשיו 5 דקות

בדקו Trace אמיתי: הריצו את אחד הסוכנים שבניתם. היכנסו ל-platform.openai.com/traces. מצאו את ה-trace האחרון. לחצו ובדקו: (1) כמה LLM calls היו, (2) כמה tokens נצרכו, (3) כמה זמן הריצה לקחה. רשמו את המספרים -- תשתמשו בהם בתרגיל 2.

בינוני 15 דקות $0.50

אינטגרציית MCP

OpenAI Agents SDK תומך ב-MCP (Model Context Protocol) -- הפרוטוקול הסטנדרטי שלמדנו בפרק 3. זה אומר שאפשר לחבר את הסוכנים שלכם ל-אלפי כלים קיימים דרך MCP Servers, בלי לכתוב את הכלים מחדש.

Python -- חיבור MCP Server לסוכן
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 שלכם מוגדרים סטטית:

Python -- שילוב MCP + custom tools
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:

Python -- חיבור ל-MCP Server מרוחק
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],
    )
שימו לב: lifecycle של MCP Servers

מה קורה: MCP Server שלא מתנהל נכון נשאר פתוח ותופס משאבים.

הפתרון: השתמשו תמיד ב-async with (context manager) שמנהל connect/cleanup אוטומטית. לחלופין, השתמשו ב-MCPServerManager לניהול מרוכז של מספר servers.

עשה עכשיו 3 דקות

תרשמו 3 MCP Servers שיעזרו לפרויקט שלכם: היכנסו ל-MCP Servers Repository ובחרו 3 servers רלוונטיים. כתבו את השמות שלהם ואיך הם יעזרו לסוכן שלכם. בפרק 3 למדנו על MCP בפירוט -- עכשיו אתם רואים את האינטגרציה בפועל.

תרגיל 2: סוכן עם Guardrails + Tracing 30 דקות

מטרה: בניית סוכן מוגן עם guardrails ומעקב traces.

  1. צרו סוכן "Customer Support Agent" עם 2 כלים: check_order_status ו-request_refund
  2. הגדירו Input Guardrail שבודק ש-הקלט קשור לשירות לקוחות (לא פוליטיקה, לא בדיחות)
  3. הגדירו Output Guardrail שבודק ש-אין מספרי כרטיס אשראי או ת.ז. בתשובה
  4. הריצו 5 שיחות: 3 לגיטימיות, 1 off-topic (שייחסם ב-input), 1 שמנסה לגרום לסוכן לחשוף מידע רגיש
  5. היכנסו ל-OpenAI Dashboard → Traces. צלמו מסך של trace אחד ונתחו: כמה קריאות LLM, כמה tokens, איפה הזמן הכי ארוך

Success criteria: Input Guardrail חוסם off-topic. Output Guardrail חוסם PII. Traces נראים ב-Dashboard.

עלות: ~$1

בינוני 10 דקות חינם

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
StreamingSSE פשוט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

Python -- Code Interpreter ו-Web Search כ-tools מובנים
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"])],
)
עשה עכשיו 5 דקות

נסו 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 שומר את ההקשר בצד השרת.

Python -- Sessions לשיחות ארוכות
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 ו-GDPR/privacy

מה קורה: Sessions שומרים conversation history בשרתי OpenAI. לעסקים ישראליים שמטפלים במידע אישי של לקוחות אירופיים (GDPR) או ישראליים (חוק הגנת הפרטיות) -- זה יכול להיות בעייתי.

הפתרון: (1) בדקו את OpenAI Data Processing Addendum, (2) אל תשמרו PII ב-sessions, (3) לדרישות מחמירות -- נהלו היסטוריה בעצמכם עם previous_response_id=None ושלחו context ידנית.

בינוני 15 דקות חינם

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. שימו לב להבדלים בסינטקס:

Python -- OpenAI Agents SDK
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)
TypeScript -- Vercel AI SDK (פרק 6)
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. אבל מחיר =/= איכות -- כל מודל מצטיין במשהו אחר.

מסגרת החלטה: איזה SDK לבחור?

עקבו אחרי עץ ההחלטה:

  1. צריכים multi-provider? (Claude + GPT + Gemini) → Vercel AI SDK
  2. צריכים Code Interpreter או Voice agents?OpenAI Agents SDK
  3. צריכים extended thinking או computer use?Claude Agent SDK
  4. צריכים handoffs נקיים עם guardrails?OpenAI Agents SDK
  5. בונים Next.js app עם Chat UI?Vercel AI SDK
  6. הפרויקט הוא Python-first? → OpenAI SDK או Claude SDK
  7. לא בטוחים? → התחילו עם Vercel AI SDK (הכי גמיש), מעברו אח"כ אם צריך
תרגיל 3: אותו סוכן ב-2 SDKs 30 דקות

מטרה: בניית אותו סוכן גם ב-OpenAI SDK וגם ב-Vercel AI SDK (מפרק 6), להשוואה ישירה.

  1. הגדירו סוכן "Travel Advisor" עם 2 כלים: search_flights(from, to, date) ו-get_hotel_prices(city, check_in, nights)
  2. ב-OpenAI SDK: Agent + @function_tool + Runner.run_sync()
  3. ב-Vercel AI SDK: ToolLoopAgent + tool() עם Zod + generate()
  4. שלחו את אותן 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"
  5. השוו: 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.

Python -- RealtimeAgent בסיסי (pseudocode)
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

מה קורה: 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 = ביטוח.

מתחיל 8 דקות חינם

טעויות נפוצות -- ואיך להימנע מהן

טעות 1: שימוש ב-Assistants API במקום Agents SDK

מה קורה: מפתח מתחיל פרויקט חדש עם 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.

טעות 2: Handoff chains ארוכים מדי

מה קורה: 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 שולט ולא כל ההיסטוריה עוברת.

טעות 3: שכחת async/await

מה קורה: מפתח משתמש ב-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(). לעולם אל תערבבו.

טעות 4: API Key ב-code

מה קורה: 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.

טעות 5: חוסר הגבלת loops

מה קורה: סוכן עם tools שנכנס ללולאה אינסופית -- קורא לכלי, לא מרוצה מהתוצאה, קורא שוב, וחוזר חלילה.

למה זה בעיה: כל לולאה = API call = tokens = כסף. סוכן בלולאה יכול לשרוף $50+ תוך שעה.

הפתרון: הגדירו max_turns ב-Runner.run(): Runner.run_sync(agent, input, max_turns=10). זה מגביל את מספר הצעדים. לפרודקשן -- הוסיפו גם timeout ו-cost budget.

תרגיל 4 (מתקדם): מערכת Multi-Agent מלאה 45 דקות

מטרה: בניית מערכת multi-agent שלמה עם כל מה שלמדנו.

  1. צרו Research Agent עם WebSearchTool שחוקר נושא
  2. צרו Writer Agent שכותב מאמר על סמך המחקר (structured output: Article עם title, body, key_takeaways)
  3. צרו Quality Agent שבודק את המאמר (structured output: QualityReport עם score, issues, pass)
  4. חברו את שלושתם ב-pipeline: Research → Writer → Quality (handoffs)
  5. הוסיפו Input Guardrail ל-Research Agent שבודק שהנושא לגיטימי
  6. הריצו על 3 נושאים שונים ובדקו traces ב-Dashboard

Success criteria: Pipeline עובד end-to-end. Guardrail חוסם נושא לא הולם. Traces מראים את כל הצעדים.

עלות: ~$3-5

שגרת עבודה -- פרק 7 (בנוסף לשגרה מפרקים 3 ו-6)
תדירותמשימהזמן
יומיבדקו traces ב-OpenAI Dashboard -- שגיאות, tool failures, guardrail blocks5 דק'
יומיבדקו token usage ועלויות -- ודאו שאין סוכנים ב-loop3 דק'
שבועיסקרו guardrail logs -- האם יש false positives (חסימות מיותרות)?10 דק'
שבועיבדקו אם יש עדכון ל-openai-agents: pip install --upgrade openai-agents5 דק'
חודשיA/B test -- בדקו אם GPT-5 (זול) מספיק במקום GPT-5.2 לסוכנים ספציפיים20 דק'
חודשיסקרו handoff accuracy -- האם ה-triage agent מנתב נכון? בדקו ב-traces15 דק'
אם אתם עושים רק דבר אחד מהפרק הזה 15 דקות

בנו Triage Agent עם 2 סוכנים מומחים ו-handoffs. 15 שורות קוד: Agent ראשון, Agent שני, Triage Agent עם handoffs=[agent1, agent2], ו-Runner.run_sync(). שלחו 4 שאלות ובדקו שהניתוב עובד. ברגע שתראו סוכן אחד מעביר שליטה לסוכן אחר בצורה טבעית -- תבינו למה handoffs הם game changer.

בדוק את עצמך -- 5 שאלות
  1. מה ההבדל בין Handoff ל-agents-as-tools? תנו דוגמה של מצב שבו כל אחד מתאים. (רמז: מי עונה למשתמש?)
  2. למה guardrails צריכים לרוץ על מודל זול ולא על אותו מודל כמו הסוכן? מה הסיכון? (רמז: עלויות, volume)
  3. מה ההבדל בין Runner.run_sync(), Runner.run(), ו-Runner.run_streamed()? מתי תשתמשו בכל אחד? (רמז: sync vs async vs UX)
  4. הסבירו מה Trace מכיל ואיך הוא עוזר לדבג סוכן שנותן תשובות לא נכונות. (רמז: agent spans, tool calls, token usage)
  5. תנו 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