• בלוג
  • יום 3 - דוגמה לתהליך עבודה של שני סוכנים

יום 3 - דוגמה לתהליך עבודה של שני סוכנים

02/10/2025

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

1. מה אנחנו בונים

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

  1. מודל שפה גדול מקבל משימה למצוא רעיונות לפוסטים. הוא מחזיר רשימה של 5 רעיונות.

  2. פונקציית פייתון בוחרת את אחד הרעיונות, במקרה שלנו זו פשוט בחירה באקראי אבל בעולם האמיתי אולי היא תסתכל ב DB להבין איזה פוסטים עדיין לא כתבתי או תחפש ברשת או כל מימוש אחר.

  3. אחרי שהחלטנו על נושא מודל שפה גדול (יכול להיות אותו מודל או מודל אחר) מקבל את המשימה לכתוב פוסט מפורט לבלוג על נושא זה.

  4. קוד פייתון מקבל את הפוסט ומפרסם אותו. בדוגמה שלנו ה"פרסום" זה בסך הכל הדפסה למסך, אבל נוכל לדמיין שאנחנו מעלים את הפוסט לבלוג.

נשים לב לסעיפים 1 ו-3 ברשימה שלי:

  1. שני הסעיפים מבצעים משימה באמצעות מודל שפה גדול, אבל הם לא חייבים להשתמש באותו מודל. למעשה הרבה פעמים בכתיבת תהליך עבודה נרצה לבחור לכל חלק בתהליך את המודל הטוב ביותר עבורו, וזה לא תמיד יהיה אותו מודל. אין מודל אחד הכי טוב שעושה הכל ובבניית מערכת אג'נטית אנחנו משחקים, מנסים ובוחרים ולפעמים גם מתחרטים.

  2. אחרי שמודל השפה הגדול החליט על רעיונות לפוסטים אני צריך לקבל את המידע שחזר ולעבוד איתו מתוך פייתון. יהיה לי נוח אם המידע הזה יגיע בתור מבנה נתונים פייתונאי רגיל.

וכבר אנחנו רואים את התפקיד של ספריית OpenAI Agents SDK במערכת שלנו. הספריה תאפשר לי להגדיר שני "סוכנים", לבחור לכל סוכן מודל שפה גדול שמתאים לו, לבחור לכל סוכן פרומפט מערכת שונה שמתאים לו והכי חשוב לקבל מהמודל מידע מובנה בפורמט של מחלקה בפייתון.

2. הגדרת טיפוס חזרה

ספריית OpenAI Agents SDK אבל גם ספריות רבות אחרות לעבודה עם מודלי שפה גדולים בפייתון משתמשת ב Pydantic כדי להגדיר מידע מובנה שאנחנו מצפים לקבל חזרה מהמודל. דוגמה ראשונה לקלאס פידנטיק עבור תהליך כתיבת הפוסט תהיה:

from pydantic import BaseModel, Field

class BlogPostIdea(BaseModel):
    title: str = Field(..., title="Title", description="The title of the blog post"),
    main_concepts: list[str] = Field(..., title="Main Concepts", description="Main concepts for the post")

פידנטיק היא ספריית פייתון לתיאור ואימות מבני נתונים. היא מאפשרת לי להגדיר מחלקה ולקבוע שיהיו בה שני שדות, title ו main_concepts, לתאר מה הסוג של כל שדה וגם מה תפקידו. כל התיאורים האלה עוזרים למודל השפה הגדול להבין איך "למלא" את מבני הנתונים. מודלי שפה גדולים מודרניים מאומנים ליצור מידע מובנה וספריות העבודה איתם עוטפות את ההתנהגות הזו כך שאנחנו צריכים רק "לבקש" לקבל חזרה מידע בתור מחלקת pydantic וזה מה שהמודל יחזיר.

בשביל להשתמש בטיפוס החזרה בתוך סוכן הרעיונות לפוסטים שלי אני כותב את הסוכן באופן הבא:

    market_research_agent = Agent(
        name="MarketResearcher",
        model=LitellmModel(model="github/gpt-4.1", api_key=os.environ["GITHUB_TOKEN"]),
        output_type=list[BlogPostIdea],
        instructions="""
        You are a market researcher and your job is to suggest cool ideas for blog posts.
        I will send you ideas and you will help me turn them into engaging posts,
        Or I will send you topics and you will help to focus me on the best viral ideas in these niches.
        """
    )

בתוך אוביקט האיתחול אני מעביר בפרמטר output_type את טיפוס הנתונים שאני רוצה לקבל חזרה. זה מספיק. עכשיו כשאני אקרא ל Runner.run אני אקבל בחזרה משהו שמתאים לטיפוס שהגדרתי.

3. קוד התוכנית

אנחנו מוכנים עכשיו לראות את קוד התוכנית המלא:

import asyncio
from agents import Agent, Runner
from agents.extensions.models.litellm_model import LitellmModel
import os
from pydantic import BaseModel, Field
import random
class BlogPostIdea(BaseModel):
    title: str = Field(..., title="Title", description="The title of the blog post"),
    main_concepts: list[str] = Field(..., title="Main Concepts", description="Main concepts for the post")

class BlogPost(BaseModel):
    title: str = Field(..., title="Title", description="The title of the blog post"),
    content: str = Field(..., title="Content", description="Actual blog post content in markdown format")

async def main(general_topic: str):
    market_research_agent = Agent(
        name="MarketResearcher",
        model=LitellmModel(model="github/gpt-4.1", api_key=os.environ["GITHUB_TOKEN"]),
        output_type=list[BlogPostIdea],
        instructions="""
        You are a market researcher and your job is to suggest cool ideas for blog posts.
        I will send you ideas and you will help me turn them into engaging posts,
        Or I will send you topics and you will help to focus me on the best viral ideas in these niches.        
        """
    )

    result = await Runner.run(market_research_agent, f"Create 5 blog posts subject lines and main concept for: {general_topic}")
    selected_idea = random.sample(result.final_output, 1)[0]

    writer = Agent(
        name="Writer",
        model=LitellmModel(model="github/gpt-4.1", api_key=os.environ["GITHUB_TOKEN"]),
        instructions="""
        You are a copywriter creating engaging and viral blog posts.
        """,
    )
    post = await Runner.run(writer, f"Create a blog post from the following data: {selected_idea.model_dump()}")
    print(post.final_output)

if __name__ == "__main__":
     asyncio.run(main("dogs"))

בשביל להריץ אותו אתם צריכים להגדיר את GITHUB_TOKEN כמו שראינו אתמול או לבחור מודל אחר מ LitellmModel עם מפתח API אחר לבחירתכם.

אלה הדברים החשובים בתוכנית:

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

  2. המידע שחוזר מכל סוכן הוא מידע מובנה ולכן אני יכול לבחור פריט אחד באקראי מתוך רשימת פוסטים ולא צריך לפענח את הטקסט שה LLM החזיר. ספריית Agents SDK עושה את הפיענוח עבורי.

  3. לסוכן אין זיכרון או מצב פנימי. כל פעם שאני מפעיל Runner.run הוא פונה מחדש למודל השפה הגדול עם הפרומפט שכתבתי ועם פרומפט המערכת ומקבל תשובה. כל בקשה עומדת בפני עצמה.

  4. ספריית OpenAI Agents SDK עדיין לא תומכת בהעברת מידע מובנה בתור קלט לפרומפט - זו הסיבה שהשתמשתי ב selected_idea.model_dump() בתוך מחרוזת הפרומפט. פקודה זו הופכת את האוביקט למילון רגיל בפייתון. הפרומפט שמודל השפה הגדול יקבל יכול להיות לכן:

Create a blog post from the following data: {'title': '10 Surprising Ways Dogs Make Our Lives Better', 'main_concepts': ['Emotional and physical benefits of owning a dog', 'How dogs improve mental health', "Lesser-known facts about dogs' positive influence"]}

4. עכשיו אתם

רוצים לשחק עם הדוגמה? מצוין! זו אחלה דרך ללמוד. הוסיפו סוכן "עורך" שישפר את הטקסט ויהפוך אותו ליותר מעניין וגם סוכן "מדרג" שמקבל את הרעיונות ומדרג אותם כדי לבחור את הפוסט המעניין ביותר.