17 בניית מיומנויות

Build: Marketing Automation Agent -- סוכן אוטומציה שיווקית

בפרק הזה תבנו מערכת סוכנים שמנהלת את כל מחזור השיווק הדיגיטלי: יצירת תוכן, ניתוח ביצועים, ניטור מתחרים, וניהול פרסום. תרכיבו צוות CrewAI שמתאם בין ארבעה סוכנים מתמחים -- Content Agent, Analytics Agent, Competitor Agent, ו-Ads Agent -- שפועלים יחד תחת Marketing Orchestrator. בסוף הפרק, יהיה לכם מערכת אוטומציה שיווקית עובדת שיכולה לייצר בלוגים, לנתח תנועה, לזהות שינויים אצל מתחרים, ולהמליץ על אופטימיזציה לקמפיינים.

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

בפרק 16 בניתם Research Agent שחוקר נושא, אוסף מידע ממקורות מרובים, ומייצר דו"ח מחקר מקיף -- למדתם parallel research, data fusion, ו-report generation. בפרק הזה תיקחו את אותם דפוסים -- חיפוש מידע, ניתוח, ויצירת תוכן -- ותיישמו אותם לdomain ספציפי: שיווק דיגיטלי. תבנו מערכת של 4 סוכנים מתמחים שעובדים כצוות תחת orchestrator מרכזי. בפרק 18 תבנו Code Review & DevOps Agent ותראו איך אותם דפוסים של multi-agent orchestration מתאימים גם ל-domain אחר לחלוטין.

מילון מונחים -- מושגים חדשים בפרק
מונח (English) תרגום הסבר
Marketing Orchestrator מתזמר שיווקי הסוכן המרכזי שמתאם בין כל סוכני השיווק -- מחליט מה לעשות, מתי, ובאיזה סדר. בפרויקט שלנו הוא CrewAI Crew שמפעיל את שאר הסוכנים
Brand Voice טון מותגי הסגנון הכתיבתי הייחודי של המותג -- כולל טון (רשמי/ידידותי), אוצר מילים, ערכים, ו-do/don't. הסוכן חייב לשמור על עקביות
Content Calendar לוח תוכן תוכנית פרסום מתוזמנת ל-30+ יום -- כוללת נושאים, פלטפורמות, תאריכי פרסום, ומילות מפתח. הסוכן מייצר אותו אוטומטית מנתוני SEO
SERP Tracking מעקב תוצאות חיפוש ניטור מיקומים בתוצאות החיפוש של Google לאורך זמן -- לך ולמתחרים. שינויים מהותיים מפעילים התראות
Anomaly Detection זיהוי חריגות מנגנון שמזהה שינויים לא רגילים במטריקות שיווקיות -- למשל ירידה של 30% בתנועה, עלייה חדה ב-CPC, או bounce rate חריג
Ad Copy נוסח פרסומי הטקסט שמופיע במודעות פרסום -- כותרות, תיאורים, CTA. הסוכן מייצר variants לבדיקות A/B
CrewAI Crew צוות CrewAI אובייקט ב-CrewAI שמאגד agents, tasks, ו-process type (sequential/hierarchical) למשימה מורכבת אחת
SEO Meta Tags תגיות SEO title tag, meta description, og:tags -- המטא-דאטא שמשפיעה על מיקום בגוגל ועל איך התוכן מוצג בשיתוף ברשתות
Content Brief תקציר תוכן מסמך מפורט שמנחה את כתיבת התוכן: keyword ראשי, keywords משניים, קהל יעד, מבנה, מתחרים, tone of voice
CPC (Cost Per Click) עלות לקליק הסכום שמשלמים על כל קליק במודעה. הסוכן מנתח CPC לפי קמפיין, מילת מפתח, ותקופה כדי למצוא אופטימיזציות
ROAS (Return on Ad Spend) החזר על הוצאה פרסומית כמה הכנסה מתקבלת על כל שקל שמושקע בפרסום. ROAS של 4 אומר: על כל 1 ש"ח, חזרו 4 ש"ח
Competitive Gap Analysis ניתוח פערים תחרותיים זיהוי נושאים שמתחרים כותבים עליהם ואתם לא, או מילות מפתח שהם מדורגים עליהן ואתם לא -- הזדמנויות לתוכן חדש
מתחיל 20 דקות מושג חינם

סקירת הפרויקט וארכיטקטורה

בואו נדמיין סטארטאפ ישראלי שמוכר SaaS לעסקים קטנים -- נקרא לו "ClickFlow". צוות השיווק שלהם מורכב מ-2 אנשים שמנסים לכסות הכל: כתיבת בלוגים, ניהול רשתות חברתיות, ניתוח Google Analytics, מעקב אחרי מתחרים, ואופטימיזציה של קמפיינים ב-Google Ads ו-Facebook. הם מבלים 15+ שעות בשבוע על משימות שחוזרות על עצמן -- שליפת דו"חות, בדיקת מיקומים בגוגל, כתיבת drafts ראשונים, ניתוח ביצועי מודעות.

מה אם סוכן AI היה מטפל ב-70% מהמשימות הטכניות האלה, ומשאיר לצוות האנושי את ההחלטות האסטרטגיות, הקשרים האישיים, והיצירתיות הגבוהה? זה בדיוק מה שנבנה בפרק הזה.

הארכיטקטורה של המערכת

המערכת בנויה כ-multi-agent system עם ארכיטקטורת orchestrator:

                    ┌──────────────────────┐
                    │  Marketing           │
                    │  Orchestrator        │
                    │  (CrewAI Crew)       │
                    └──────┬───────────────┘
                           │
            ┌──────────────┼──────────────┐──────────────┐
            │              │              │              │
    ┌───────▼──────┐ ┌─────▼──────┐ ┌─────▼──────┐ ┌────▼───────┐
    │  Content     │ │ Analytics  │ │ Competitor │ │ Ads        │
    │  Agent       │ │ Agent      │ │ Agent      │ │ Agent      │
    │              │ │            │ │            │ │            │
    │ - Blog posts │ │ - GA4      │ │ - SERP     │ │ - Campaign │
    │ - Social     │ │ - GSC      │ │ - Content  │ │   analysis │
    │ - Email      │ │ - Reports  │ │ - Pricing  │ │ - Budget   │
    │ - Ad copy    │ │ - Anomaly  │ │ - Alerts   │ │ - Ad copy  │
    └──────────────┘ └────────────┘ └────────────┘ └────────────┘

למה CrewAI? כי זה ה-SDK שנבנה בדיוק לזה -- הגדרת agents עם roles, goals, ו-tools, שילוב שלהם ב-crew עם process type (sequential או hierarchical), וביצוע tasks שמעבירים תוצאות מסוכן לסוכן. למדנו את CrewAI בפרק 9, ועכשיו נשתמש בו ב-scale אמיתי.

עקרונות עיצוב

עיקרון מימוש למה
READ-ONLY לפלטפורמות חיצוניות API access לקריאה בלבד, שום כתיבה ישירה בטיחות -- סוכן לא מוציא כסף ולא מפרסם בלי אישור אנושי
Recommendations, not actions הסוכן ממליץ, האדם מאשר Human-on-the-Loop -- שלמדנו בפרק 14
Brand voice consistency קובץ brand guidelines נטען לכל סוכן תוכן כל output חייב להישמע כמו המותג
Modular agents כל סוכן עצמאי, אפשר להשתמש בו בלבד גמישות -- אם צריכים רק content, מפעילים רק אותו
עשה עכשיו 3 דקות

צרו תיקייה חדשה לפרויקט:

mkdir marketing-agent && cd marketing-agent
mkdir -p agents tools config output
touch config/brand_guidelines.json
touch config/competitors.json
touch config/.env

ב-config/.env הוסיפו את המפתחות שלכם:

ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
# GOOGLE_ANALYTICS_PROPERTY_ID=properties/123456789
# GOOGLE_ADS_CUSTOMER_ID=123-456-7890
טעות נפוצה: לתת לסוכן גישת כתיבה לפלטפורמות פרסום

מפתה לתת לסוכן write access ל-Google Ads או Facebook Ads -- "שהוא ישנה bids אוטומטית." אל תעשו את זה בהתחלה. סוכן שמשנה bids בלי פיקוח יכול לשרוף תקציב של אלפי שקלים בכמה שעות. התחילו תמיד ב-read-only, בנו אמון בהמלצות הסוכן, ואז -- אולי, אחרי שבועות של validation -- שקלו automated actions עם budget caps ו-approval workflows.

בינוני 45 דקות תרגול חינם

Content Creation Agent -- יצירת תוכן

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

Brand Voice -- שמירה על טון עקבי

לפני שהסוכן כותב מילה, הוא חייב להבין את ה-brand voice. זה ההבדל בין תוכן שנראה כאילו AI כתב אותו לבין תוכן שנשמע כמו המותג. ניצור קובץ brand guidelines:

# config/brand_guidelines.json
{
  "company_name": "ClickFlow",
  "tagline": "שיווק דיגיטלי שעובד בשבילך",
  "tone": "ידידותי ומקצועי, לא פורמלי מדי, לא סלנגי",
  "audience": "בעלי עסקים קטנים ובינוניים בישראל, גילאי 30-55",
  "language_rules": {
    "primary": "עברית",
    "english_ok_for": ["מונחים טכניים", "שמות כלים", "ראשי תיבות"],
    "avoid": ["ז'רגון טכני מיותר", "משפטים ארוכים מ-25 מילים", "passive voice"],
    "prefer": ["דוגמאות מספריות", "שאלות רטוריות", "פסקאות קצרות"]
  },
  "content_rules": {
    "blog_length": "1200-2000 מילים",
    "cta_style": "רך -- 'רוצים ללמוד עוד?' ולא 'קנו עכשיו!'",
    "seo_required": true,
    "internal_links": "לפחות 2 לינקים לתוכן קיים"
  },
  "competitors_to_differentiate_from": ["monday.com", "Wix", "Elementor"],
  "unique_selling_points": [
    "מתאים לעסקים ישראליים",
    "תמיכה בעברית מלאה",
    "אינטגרציה עם חשבשבת ו-Priority"
  ]
}

מימוש ב-Python עם CrewAI

הנה ה-Content Agent המלא. שימו לב איך ה-brand guidelines נטענים ומוזרקים ל-system prompt:

# agents/content_agent.py
import json
from crewai import Agent, Task
from crewai.tools import tool
from pathlib import Path

# טוען brand guidelines
def load_brand_guidelines() -> dict:
    path = Path(__file__).parent.parent / "config" / "brand_guidelines.json"
    with open(path, "r", encoding="utf-8") as f:
        return json.load(f)

BRAND = load_brand_guidelines()

# --- Tools ---
@tool("web_search")
def web_search(query: str) -> str:
    """חיפוש באינטרנט למחקר תוכן. מחזיר תוצאות רלוונטיות."""
    # בפרודקשן: חיבור ל-Brave Search, Tavily, או SerpAPI
    import requests
    resp = requests.get(
        "https://api.search.brave.com/res/v1/web/search",
        headers={"X-Subscription-Token": os.environ["BRAVE_API_KEY"]},
        params={"q": query, "count": 5}
    )
    results = resp.json().get("web", {}).get("results", [])
    return "\n".join([
        f"- {r['title']}: {r['description']}" for r in results
    ])

@tool("seo_analyzer")
def seo_analyzer(keyword: str) -> str:
    """מנתח keyword: volume, difficulty, related keywords."""
    # בפרודקשן: חיבור ל-SEMrush, Ahrefs, או Google Keyword Planner
    return json.dumps({
        "keyword": keyword,
        "monthly_volume": 2400,
        "difficulty": "medium",
        "related_keywords": [
            f"{keyword} לעסקים קטנים",
            f"איך לעשות {keyword}",
            f"{keyword} 2026",
            f"{keyword} בישראל"
        ],
        "top_questions": [
            f"מה זה {keyword}?",
            f"כמה עולה {keyword}?",
            f"איך מתחילים עם {keyword}?"
        ]
    }, ensure_ascii=False)

@tool("brand_guidelines_reader")
def brand_guidelines_reader(aspect: str) -> str:
    """קורא את הנחיות המותג. aspect: tone, audience, content_rules, all."""
    if aspect == "all":
        return json.dumps(BRAND, ensure_ascii=False, indent=2)
    return json.dumps(BRAND.get(aspect, f"No guidelines for: {aspect}"),
                      ensure_ascii=False)

# --- Agent ---
content_agent = Agent(
    role="Content Marketing Specialist",
    goal="ליצור תוכן שיווקי איכותי שתואם את ה-brand voice, "
         "ממוקד SEO, ומניע את הקורא לפעולה",
    backstory=f"""אתה כותב תוכן שיווקי מנוסה שעובד עם {BRAND['company_name']}.
    אתה מכיר את קהל היעד: {BRAND['audience']}.
    הטון שלך: {BRAND['tone']}.
    אתה תמיד כותב בעברית, עם מונחים טכניים באנגלית כשצריך.
    כל תוכן שאתה כותב עובר אופטימיזציית SEO ומכוון לדירוג בגוגל.""",
    tools=[web_search, seo_analyzer, brand_guidelines_reader],
    verbose=True,
    llm="anthropic/claude-sonnet-4-20250514"
)

# --- Tasks ---
def create_blog_post_task(keyword: str) -> Task:
    return Task(
        description=f"""כתוב פוסט בלוג מלא על "{keyword}".

        שלבים:
        1. קרא את הנחיות המותג (brand_guidelines_reader, aspect="all")
        2. חקור את ה-keyword (seo_analyzer)
        3. חפש מידע עדכני (web_search)
        4. כתוב את הפוסט:
           - כותרת (H1) עם ה-keyword
           - מבוא מושך (2-3 משפטים)
           - 4-6 sections עם H2
           - דוגמאות מספריות ומהעולם הישראלי
           - סיכום עם CTA רך
           - אורך: {BRAND['content_rules']['blog_length']}

        5. הוסף SEO meta:
           - title tag (עד 60 תווים)
           - meta description (עד 155 תווים)
           - 3-5 internal link suggestions

        הפלט חייב להיות בעברית, בטון של {BRAND['tone']}.""",
        expected_output="פוסט בלוג מלא בעברית עם SEO meta tags",
        agent=content_agent
    )
עשה עכשיו 5 דקות

צרו את config/brand_guidelines.json עבור פרויקט אמיתי שלכם (או עסק ישראלי שאתם מכירים). מלאו לפחות: company_name, tone, audience, ו-content_rules. אם אין לכם עסק -- השתמשו בדוגמת ClickFlow מלמעלה.

מימוש ב-TypeScript עם Vercel AI SDK

אם אתם מעדיפים TypeScript, הנה אותו Content Agent עם Vercel AI SDK:

// agents/content-agent.ts
import { generateText, tool } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { z } from "zod";
import { readFileSync } from "fs";
import { join } from "path";

const brandGuidelines = JSON.parse(
  readFileSync(join(__dirname, "../config/brand_guidelines.json"), "utf-8")
);

const contentTools = {
  webSearch: tool({
    description: "Search the web for content research",
    parameters: z.object({ query: z.string() }),
    execute: async ({ query }) => {
      const resp = await fetch(
        `https://api.search.brave.com/res/v1/web/search?q=${encodeURIComponent(query)}&count=5`,
        { headers: { "X-Subscription-Token": process.env.BRAVE_API_KEY! } }
      );
      const data = await resp.json();
      return data.web?.results?.map(
        (r: any) => `- ${r.title}: ${r.description}`
      ).join("\n") ?? "No results found";
    },
  }),

  seoAnalyzer: tool({
    description: "Analyze keyword for SEO: volume, difficulty, related terms",
    parameters: z.object({ keyword: z.string() }),
    execute: async ({ keyword }) => {
      // Production: connect to SEMrush / Ahrefs API
      return JSON.stringify({
        keyword,
        monthly_volume: 2400,
        difficulty: "medium",
        related_keywords: [
          `${keyword} לעסקים קטנים`,
          `איך לעשות ${keyword}`,
          `${keyword} 2026`,
        ],
      });
    },
  }),

  readBrandGuidelines: tool({
    description: "Read brand voice and content guidelines",
    parameters: z.object({
      aspect: z.enum(["tone", "audience", "content_rules", "all"]),
    }),
    execute: async ({ aspect }) => {
      if (aspect === "all") return JSON.stringify(brandGuidelines);
      return JSON.stringify(brandGuidelines[aspect] ?? "Not found");
    },
  }),
};

export async function generateBlogPost(keyword: string) {
  const { text } = await generateText({
    model: anthropic("claude-sonnet-4-20250514"),
    tools: contentTools,
    maxSteps: 10,
    system: `אתה כותב תוכן שיווקי של ${brandGuidelines.company_name}.
טון: ${brandGuidelines.tone}. קהל: ${brandGuidelines.audience}.
כתוב תמיד בעברית. שלב מונחים טכניים באנגלית כשמתאים.`,
    prompt: `כתוב פוסט בלוג מלא על "${keyword}".
1. קרא את brand guidelines
2. נתח את ה-keyword ל-SEO
3. חפש מידע עדכני
4. כתוב פוסט: H1 + מבוא + 4-6 sections + סיכום + CTA
5. הוסף title tag (60 תווים), meta description (155 תווים)
אורך: ${brandGuidelines.content_rules.blog_length}`,
  });

  return text;
}
עשה עכשיו 2 דקות

בחרו keyword אמיתי שרלוונטי לעסק שלכם (למשל "אוטומציה שיווקית" או "CRM לעסקים קטנים"). רשמו אותו -- נשתמש בו בתרגיל המלא.

סוגי תוכן נוספים

Content Agent לא מסתכם בבלוגים. הנה איך מרחיבים אותו לסוגי תוכן נוספים:

סוג תוכן אורך פלטפורמה מאפיינים ייחודיים
בלוג פוסט 1,200-2,000 מילים אתר SEO, H2 structure, internal links, CTA
פוסט LinkedIn 150-300 מילים LinkedIn Hook בשורה ראשונה, שורות קצרות, emoji מינימלי, hashtags
פוסט Facebook 80-150 מילים Facebook שאלה פותחת, ויזואלי, CTA ברור, בעברית מדוברת
אימייל שיווקי 200-400 מילים Email Subject line (עד 50 תווים), preview text, כפתור CTA אחד
נוסח מודעה 30-90 תווים Google/Meta Ads 3 variants לכל מודעה, keyword בכותרת, USP ברור
מסגרת החלטה: איזה סוג תוכן ליצור קודם?
אם... אז צרו... למה
יש לכם keyword עם volume גבוה בלוג פוסט + פוסטים חברתיים בלוג מושך תנועה אורגנית, פוסטים מגבירים reach
יש לכם מוצר חדש / פיצ'ר אימייל + LinkedIn + מודעות הודעה ישירה לקהל קיים + acquisition
מתחרים פרסמו תוכן על הנושא בלוג פוסט שלם ומעמיק יותר "10x content" -- תוכן שעשרת מונים טוב מהמתחרה
יש לכם נתונים / case study בלוג + LinkedIn + email sequence נתונים מקוריים הם זהב שיווקי, לפזר על כל הערוצים
תרגיל 1: בנו את Content Agent המלא (30 דקות)

בנו Content Agent שלם שמייצר בלוג פוסט:

  1. צרו את config/brand_guidelines.json עם כל השדות (טון, קהל, חוקי תוכן)
  2. ממשו את agents/content_agent.py (או .ts) עם ה-3 tools: web_search, seo_analyzer, brand_guidelines_reader
  3. הריצו את הסוכן עם keyword אמיתי (למשל: "אוטומציה שיווקית לעסקים קטנים")
  4. בדקו את הפלט: האם הטון תואם? האם יש SEO meta? האם האורך בטווח?
  5. שמרו את הפלט ב-output/blog_draft_01.md ובדקו אם הייתם מפרסמים את זה
  6. שפרו את ה-prompt עד שהתוצאה מספקת -- תעדו מה שיניתם ולמה

תוצאה צפויה: פוסט בלוג של 1,200+ מילים בעברית, עם title tag, meta description, ו-3 הצעות ל-internal links.

טעות נפוצה: לסמוך על הסוכן בלי fact-checking

Content Agent יכול להמציא סטטיסטיקות. אם הוא כותב "72% מהעסקים בישראל משתמשים באוטומציה" -- הוא כנראה המציא את המספר. כל עובדה ונתון חייבים לעבור fact-check אנושי לפני פרסום. הוסיפו ל-prompt הנחיה: "אם אתה מציין סטטיסטיקה, ציין את המקור. אם אין לך מקור -- כתוב 'לפי הערכות' או השמט."

בינוני 40 דקות תרגול חינם

Analytics Agent -- ניתוח ביצועים

הסוכן השני הוא ה-Analytics Agent -- העיניים של המערכת. הוא מתחבר ל-Google Analytics 4 ו-Google Search Console, שולף נתונים, מזהה מגמות ואנומליות, ומייצר דו"חות שאפשר לפעול לפיהם.

הבעיה עם אנליטיקס היא לא חוסר נתונים -- הבעיה היא עודף נתונים. GA4 מחזיר מאות מטריקות, מימדים, ו-segments. בעל עסק קטן לא יודע מה לעשות עם bounce rate של 67.3%. ה-Analytics Agent הופך נתונים גולמיים ל-insights פעילים: "התנועה מגוגל ירדה ב-25% השבוע כי המאמר על CRM נדחף למקום 8 -- כדאי לעדכן אותו."

חיבור ל-Google Analytics 4

# agents/analytics_agent.py
import os
import json
from datetime import datetime, timedelta
from crewai import Agent, Task
from crewai.tools import tool

# --- Google Analytics Tool ---
@tool("ga4_report")
def ga4_report(metric: str, date_range: str = "last_7_days") -> str:
    """שולף דו"ח מ-GA4. metric: sessions, users, pageviews, bounce_rate, conversions.
    date_range: last_7_days, last_30_days, last_month, custom."""
    from google.analytics.data_v1beta import BetaAnalyticsDataClient
    from google.analytics.data_v1beta.types import (
        RunReportRequest, DateRange, Metric, Dimension
    )

    client = BetaAnalyticsDataClient()
    property_id = os.environ["GA4_PROPERTY_ID"]

    # חישוב טווח תאריכים
    end_date = datetime.now()
    if date_range == "last_7_days":
        start_date = end_date - timedelta(days=7)
    elif date_range == "last_30_days":
        start_date = end_date - timedelta(days=30)
    else:
        start_date = end_date - timedelta(days=7)

    # מפה מטריקות לשמות GA4
    metric_map = {
        "sessions": "sessions",
        "users": "totalUsers",
        "pageviews": "screenPageViews",
        "bounce_rate": "bounceRate",
        "conversions": "conversions",
    }

    request = RunReportRequest(
        property=f"properties/{property_id}",
        date_ranges=[DateRange(
            start_date=start_date.strftime("%Y-%m-%d"),
            end_date=end_date.strftime("%Y-%m-%d")
        )],
        metrics=[Metric(name=metric_map.get(metric, metric))],
        dimensions=[Dimension(name="date")],
    )

    response = client.run_report(request)
    rows = [
        {"date": row.dimension_values[0].value,
         metric: row.metric_values[0].value}
        for row in response.rows
    ]
    return json.dumps(rows, ensure_ascii=False)

@tool("search_console_report")
def search_console_report(days: int = 7) -> str:
    """שולף נתוני Search Console: queries, clicks, impressions, position."""
    from googleapiclient.discovery import build
    from google.oauth2 import service_account

    credentials = service_account.Credentials.from_service_account_file(
        "config/service_account.json",
        scopes=["https://www.googleapis.com/auth/webmasters.readonly"]
    )
    service = build("searchconsole", "v1", credentials=credentials)

    end_date = datetime.now()
    start_date = end_date - timedelta(days=days)

    response = service.searchanalytics().query(
        siteUrl=os.environ["SITE_URL"],
        body={
            "startDate": start_date.strftime("%Y-%m-%d"),
            "endDate": end_date.strftime("%Y-%m-%d"),
            "dimensions": ["query"],
            "rowLimit": 20
        }
    ).execute()

    return json.dumps(response.get("rows", []), ensure_ascii=False)

@tool("anomaly_detector")
def anomaly_detector(current_value: float, previous_value: float,
                     metric_name: str) -> str:
    """מזהה אם שינוי במטריקה הוא חריג. מחזיר alert אם השינוי > 20%."""
    if previous_value == 0:
        return json.dumps({"alert": False, "reason": "No previous data"})

    change_pct = ((current_value - previous_value) / previous_value) * 100

    alert = abs(change_pct) > 20
    direction = "עלייה" if change_pct > 0 else "ירידה"

    return json.dumps({
        "metric": metric_name,
        "current": current_value,
        "previous": previous_value,
        "change_percent": round(change_pct, 1),
        "direction": direction,
        "alert": alert,
        "severity": "critical" if abs(change_pct) > 50 else
                    "warning" if abs(change_pct) > 20 else "normal",
        "message": f"{direction} של {abs(round(change_pct, 1))}% ב-{metric_name}"
                   if alert else "ללא שינוי מהותי"
    }, ensure_ascii=False)

# --- Agent ---
analytics_agent = Agent(
    role="Marketing Analytics Specialist",
    goal="לשלוף נתוני שיווק, לזהות מגמות ואנומליות, "
         "ולייצר insights פעילים שמנהלים יכולים לפעול לפיהם",
    backstory="""אתה אנליסט שיווקי מנוסה שיודע להפוך נתונים גולמיים
    ל-insights ברורים. אתה לא רק מציג מספרים -- אתה מסביר למה הם
    חשובים ומה צריך לעשות. כשיש ירידה -- אתה מציע סיבות ופתרונות.
    כשיש עלייה -- אתה מזהה מה עבד ומציע להרחיב.
    הנתונים שלך תמיד בשקלים (ש"ח) ובהקשר ישראלי.""",
    tools=[ga4_report, search_console_report, anomaly_detector],
    verbose=True,
    llm="anthropic/claude-sonnet-4-20250514"
)

# --- Tasks ---
def create_weekly_report_task() -> Task:
    return Task(
        description="""ייצר דו"ח שבועי של ביצועי שיווק:

        1. שלוף מ-GA4: sessions, users, pageviews, bounce_rate, conversions (last_7_days)
        2. שלוף מ-Search Console: top 20 queries
        3. בדוק כל מטריקה מול השבוע הקודם עם anomaly_detector
        4. ייצר דו"ח מובנה:

        ## דו"ח שבועי -- [תאריך]
        ### מטריקות מרכזיות
        - Sessions: X (▲/▼ Y%)
        - Users: X (▲/▼ Y%)
        - Conversions: X (▲/▼ Y%)

        ### התראות
        - [כל anomaly שזוהתה]

        ### Top Performing Content
        - [דפים/queries עם הכי הרבה תנועה]

        ### המלצות
        - [3 פעולות ספציפיות]""",
        expected_output="דו"ח שבועי מובנה עם מטריקות, התראות, והמלצות",
        agent=analytics_agent
    )
עשה עכשיו 4 דקות

אם אין לכם Google Analytics property משלכם, השתמשו ב-GA4 Demo Account של Google: לכו ל-analytics.google.com/analytics/web/demoAccount וגשו ל-Google Merchandise Store. רשמו את ה-Property ID -- נשתמש בו בתרגילים.

TypeScript: Analytics Agent

// agents/analytics-agent.ts
import { generateText, tool } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { z } from "zod";

const analyticsTools = {
  ga4Report: tool({
    description: "Pull GA4 report for a specific metric and date range",
    parameters: z.object({
      metric: z.enum(["sessions", "users", "pageviews", "bounce_rate", "conversions"]),
      dateRange: z.enum(["last_7_days", "last_30_days"]).default("last_7_days"),
    }),
    execute: async ({ metric, dateRange }) => {
      // Production: use @google-analytics/data
      // Demo: return mock data
      const mockData = {
        sessions: [
          { date: "2026-03-18", value: 1250 },
          { date: "2026-03-19", value: 1180 },
          { date: "2026-03-20", value: 1340 },
          { date: "2026-03-21", value: 980 },
          { date: "2026-03-22", value: 870 },
          { date: "2026-03-23", value: 1410 },
          { date: "2026-03-24", value: 1290 },
        ],
      };
      return JSON.stringify(mockData[metric] ?? mockData.sessions);
    },
  }),

  anomalyDetector: tool({
    description: "Detect anomalies by comparing current vs previous values",
    parameters: z.object({
      currentValue: z.number(),
      previousValue: z.number(),
      metricName: z.string(),
    }),
    execute: async ({ currentValue, previousValue, metricName }) => {
      const changePct = previousValue === 0
        ? 0
        : ((currentValue - previousValue) / previousValue) * 100;
      const alert = Math.abs(changePct) > 20;
      return JSON.stringify({
        metric: metricName,
        change_percent: Math.round(changePct * 10) / 10,
        alert,
        severity: Math.abs(changePct) > 50 ? "critical" :
                  Math.abs(changePct) > 20 ? "warning" : "normal",
      });
    },
  }),
};

export async function generateWeeklyReport() {
  const { text } = await generateText({
    model: anthropic("claude-sonnet-4-20250514"),
    tools: analyticsTools,
    maxSteps: 15,
    system: `אתה אנליסט שיווקי. הפוך נתונים גולמיים ל-insights ברורים.
תמיד הסבר למה מספרים חשובים ומה לעשות בעקבותם.
הנתונים בש"ח, ההקשר ישראלי.`,
    prompt: `ייצר דו"ח שבועי: שלוף sessions, users, conversions מ-GA4,
בדוק אנומליות, וסכם עם 3 המלצות ספציפיות.`,
  });
  return text;
}
עלות ריצת Analytics Agent

Google APIs: חינם (GA4 Data API ו-Search Console API הם בחינם לשימוש סביר). LLM: ~$0.10-0.30 לכל דו"ח (תלוי בכמות הנתונים). סה"כ חודשי: אם מריצים דו"ח יומי -- כ-$3-9 בחודש. דו"ח שבועי -- כ-$0.50-1.50 בחודש. השוואה: אנליסט אנושי שמפיק דו"ח שבועי מקביל עולה ~1-2 שעות עבודה (~200-400 ש"ח).

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

רשמו 3 מטריקות שיווקיות שהכי חשובות לעסק שלכם (או לעסק שבניתם brand guidelines בשבילו). לכל מטריקה, הגדירו: מה נחשב "חריג" (threshold). למשל: sessions -- ירידה של מעל 25% שבוע-על-שבוע.

שימו לב: GA4 API Rate Limits

ל-Google Analytics Data API יש rate limits: 10 בקשות בו-זמנית ו-quota יומי שתלוי בסוג הנכס. אם הסוכן שולף נתונים בלולאה אגרסיבית, הוא יקבל שגיאת 429. פתרון: הוסיפו caching -- שמרו את תוצאות ה-API ל-file/Redis עם TTL של שעה, והסוכן ישתמש ב-cache במקום לקרוא ל-API שוב.

בינוני 40 דקות תרגול חינם

Competitor Monitoring Agent -- ניטור מתחרים

הסוכן השלישי הוא ה-Competitor Monitoring Agent -- המודיעין של המערכת. הוא עוקב אחרי מתחרים ומתריע כשמשהו משתנה: תוכן חדש, שינויים במיקומים בגוגל, שינויי מחירים, או פעילות חדשה ברשתות חברתיות.

בשוק הישראלי, ניטור מתחרים הוא קריטי במיוחד. השוק קטן, התחרות צפופה, ושינוי קטן אצל מתחרה יכול להשפיע עליכם מהר. ClickFlow (הסטארטאפ שלנו) מתחרה מול 3 חברות ישראליות -- ובעל העסק צריך לדעת מה הם עושים בלי לבזבז שעתיים ביום על מעקב ידני.

הגדרת מתחרים

# config/competitors.json
{
  "competitors": [
    {
      "name": "CompetitorA",
      "domain": "competitor-a.co.il",
      "blog_url": "https://competitor-a.co.il/blog",
      "social": {
        "linkedin": "https://linkedin.com/company/competitor-a",
        "facebook": "https://facebook.com/competitorA"
      },
      "tracked_keywords": [
        "CRM לעסקים קטנים",
        "אוטומציה שיווקית",
        "ניהול לידים"
      ],
      "pricing_page": "https://competitor-a.co.il/pricing"
    },
    {
      "name": "CompetitorB",
      "domain": "competitor-b.com",
      "blog_url": "https://competitor-b.com/blog",
      "social": {
        "linkedin": "https://linkedin.com/company/competitor-b"
      },
      "tracked_keywords": [
        "marketing automation",
        "email marketing ישראל",
        "דיוור אלקטרוני"
      ],
      "pricing_page": "https://competitor-b.com/pricing"
    },
    {
      "name": "CompetitorC",
      "domain": "competitor-c.co.il",
      "blog_url": "https://competitor-c.co.il/blog",
      "social": {
        "facebook": "https://facebook.com/competitorC"
      },
      "tracked_keywords": [
        "שיווק דיגיטלי לעסקים",
        "קמפיינים בגוגל",
        "פרסום ממומן"
      ],
      "pricing_page": "https://competitor-c.co.il/plans"
    }
  ],
  "monitoring_schedule": {
    "content_check": "daily",
    "serp_check": "daily",
    "pricing_check": "weekly",
    "social_check": "daily"
  }
}

מימוש ב-Python

# agents/competitor_agent.py
import json
import hashlib
from datetime import datetime
from pathlib import Path
from crewai import Agent, Task
from crewai.tools import tool

SNAPSHOT_DIR = Path("output/competitor_snapshots")
SNAPSHOT_DIR.mkdir(parents=True, exist_ok=True)

@tool("scrape_page")
def scrape_page(url: str) -> str:
    """סורק דף וב ומחזיר את הטקסט. לניטור שינויים אצל מתחרים."""
    import requests
    from bs4 import BeautifulSoup

    try:
        resp = requests.get(url, timeout=10, headers={
            "User-Agent": "Mozilla/5.0 (compatible; MarketingBot/1.0)"
        })
        soup = BeautifulSoup(resp.text, "html.parser")
        # הסר scripts ו-styles
        for tag in soup(["script", "style", "nav", "footer"]):
            tag.decompose()
        text = soup.get_text(separator="\n", strip=True)
        return text[:5000]  # חתוך ל-5000 תווים
    except Exception as e:
        return f"Error scraping {url}: {str(e)}"

@tool("check_serp_position")
def check_serp_position(keyword: str, domain: str) -> str:
    """בודק מיקום של domain בתוצאות גוגל עבור keyword."""
    # בפרודקשן: SerpAPI, DataForSEO, או Brightdata
    import requests
    resp = requests.get(
        "https://serpapi.com/search",
        params={
            "q": keyword,
            "location": "Israel",
            "hl": "he",
            "gl": "il",
            "api_key": os.environ.get("SERPAPI_KEY", "demo")
        }
    )
    results = resp.json().get("organic_results", [])
    for i, result in enumerate(results):
        if domain in result.get("link", ""):
            return json.dumps({
                "keyword": keyword,
                "domain": domain,
                "position": i + 1,
                "title": result.get("title", ""),
                "snippet": result.get("snippet", "")
            }, ensure_ascii=False)
    return json.dumps({
        "keyword": keyword,
        "domain": domain,
        "position": "not_found",
        "message": f"{domain} לא נמצא ב-top 100 עבור '{keyword}'"
    }, ensure_ascii=False)

@tool("detect_content_changes")
def detect_content_changes(url: str, competitor_name: str) -> str:
    """משווה תוכן נוכחי מול snapshot קודם ומזהה שינויים."""
    current_content = scrape_page.run(url)
    current_hash = hashlib.md5(current_content.encode()).hexdigest()

    snapshot_file = SNAPSHOT_DIR / f"{competitor_name}_{url_to_filename(url)}.json"

    if snapshot_file.exists():
        with open(snapshot_file, "r") as f:
            previous = json.load(f)
        changed = previous["hash"] != current_hash
        result = {
            "url": url,
            "competitor": competitor_name,
            "changed": changed,
            "previous_check": previous["timestamp"],
            "current_check": datetime.now().isoformat()
        }
    else:
        result = {
            "url": url,
            "competitor": competitor_name,
            "changed": False,
            "message": "First check -- snapshot saved",
            "current_check": datetime.now().isoformat()
        }

    # שמור snapshot
    with open(snapshot_file, "w") as f:
        json.dump({
            "hash": current_hash,
            "timestamp": datetime.now().isoformat(),
            "content_preview": current_content[:500]
        }, f, ensure_ascii=False)

    return json.dumps(result, ensure_ascii=False)

def url_to_filename(url: str) -> str:
    return hashlib.md5(url.encode()).hexdigest()[:12]

# --- Agent ---
competitor_agent = Agent(
    role="Competitive Intelligence Analyst",
    goal="לעקוב אחרי מתחרים, לזהות שינויים, "
         "ולייצר התראות ודו"חות תחרותיים",
    backstory="""אתה מנתח מודיעין תחרותי שעוקב אחרי מתחרים בשוק הישראלי.
    אתה סורק אתרים, בודק מיקומים בגוגל, ומזהה שינויים בתוכן ובמחירים.
    כשיש שינוי מהותי -- אתה מתריע מיד עם ניתוח: מה השתנה, למה זה חשוב,
    ומה אנחנו צריכים לעשות בתגובה. אתה מכיר היטב את השוק הישראלי כולל
    פלטפורמות מקומיות כמו Walla, Ynet, וCalcalist.""",
    tools=[scrape_page, check_serp_position, detect_content_changes],
    verbose=True,
    llm="anthropic/claude-sonnet-4-20250514"
)
עשה עכשיו 4 דקות

מלאו את config/competitors.json עם 3 מתחרים אמיתיים שלכם. לכל מתחרה רשמו: domain, כתובת בלוג (אם יש), ו-3 מילות מפתח שאתם מתחרים עליהן.

ניטור תוכן עברי

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

תרגיל 2: בנו את Competitor Agent (30 דקות)
  1. ממשו את agents/competitor_agent.py עם 3 tools: scrape_page, check_serp_position, detect_content_changes
  2. הגדירו 3 מתחרים ב-config/competitors.json
  3. הריצו סריקה ראשונית -- היא תיצור snapshots בסיסיים
  4. חכו יום (או שנו ידנית snapshot) והריצו שוב -- ודאו שמזהה שינויים
  5. בדקו מיקומי SERP ל-3 מילות מפתח
  6. ייצרו "דו"ח תחרותי יומי" עם כל הממצאים

תוצאה צפויה: דו"ח שמציג: שינויי תוכן (אם יש), מיקומי SERP, והמלצות פעולה.

בינוני 35 דקות תרגול חינם

Ad Management Agent -- ניהול פרסום

הסוכן הרביעי הוא ה-Ad Management Agent -- המנתח הפיננסי של המערכת. הוא מנתח ביצועי קמפיינים ב-Google Ads ו-Meta Ads, מזהה מודעות שמבזבזות תקציב, ומייצר המלצות אופטימיזציה. חשוב: הוא פועל בREAD-ONLY -- ממליץ בלבד, לא מבצע שינויים.

למה READ-ONLY? כי שינוי bid של 50 אגורות על מילת מפתח פופולרית יכול לעלות אלפי שקלים ביום. עד שבונים אמון מלא ביכולת הסוכן, הגישה הבטוחה היא: הסוכן מנתח ← הסוכן ממליץ ← אדם מאשר ← אדם מבצע.

מימוש ב-Python

# agents/ads_agent.py
import json
from crewai import Agent, Task
from crewai.tools import tool

@tool("google_ads_report")
def google_ads_report(report_type: str = "campaign_performance") -> str:
    """שולף דו"ח ביצועים מ-Google Ads.
    report_type: campaign_performance, keyword_performance, ad_copy_performance."""
    from google.ads.googleads.client import GoogleAdsClient

    client = GoogleAdsClient.load_from_env()
    ga_service = client.get_service("GoogleAdsService")

    queries = {
        "campaign_performance": """
            SELECT campaign.name, campaign.status,
                   metrics.impressions, metrics.clicks,
                   metrics.cost_micros, metrics.conversions,
                   metrics.cost_per_conversion
            FROM campaign
            WHERE segments.date DURING LAST_7_DAYS
            AND campaign.status = 'ENABLED'
            ORDER BY metrics.cost_micros DESC
            LIMIT 20
        """,
        "keyword_performance": """
            SELECT ad_group_criterion.keyword.text,
                   ad_group_criterion.keyword.match_type,
                   metrics.impressions, metrics.clicks,
                   metrics.cost_micros, metrics.conversions,
                   metrics.average_cpc
            FROM keyword_view
            WHERE segments.date DURING LAST_7_DAYS
            ORDER BY metrics.cost_micros DESC
            LIMIT 30
        """,
        "ad_copy_performance": """
            SELECT ad_group_ad.ad.responsive_search_ad.headlines,
                   ad_group_ad.ad.responsive_search_ad.descriptions,
                   metrics.impressions, metrics.clicks,
                   metrics.ctr, metrics.conversions
            FROM ad_group_ad
            WHERE segments.date DURING LAST_7_DAYS
            ORDER BY metrics.impressions DESC
            LIMIT 15
        """
    }

    query = queries.get(report_type, queries["campaign_performance"])
    customer_id = os.environ["GOOGLE_ADS_CUSTOMER_ID"].replace("-", "")

    response = ga_service.search(customer_id=customer_id, query=query)
    results = []
    for row in response:
        results.append({
            "campaign": row.campaign.name if hasattr(row, 'campaign') else "N/A",
            "impressions": row.metrics.impressions,
            "clicks": row.metrics.clicks,
            "cost_ils": round(row.metrics.cost_micros / 1_000_000, 2),
            "conversions": round(row.metrics.conversions, 1),
            "cpc_ils": round(row.metrics.average_cpc / 1_000_000, 2)
                       if hasattr(row.metrics, 'average_cpc') else None
        })
    return json.dumps(results, ensure_ascii=False)

@tool("budget_analyzer")
def budget_analyzer(campaigns_data: str) -> str:
    """מנתח הקצאת תקציב ומזהה בזבוז. מחזיר המלצות."""
    campaigns = json.loads(campaigns_data)

    total_spend = sum(c["cost_ils"] for c in campaigns)
    total_conversions = sum(c["conversions"] for c in campaigns)

    analysis = {
        "total_spend_ils": total_spend,
        "total_conversions": total_conversions,
        "avg_cpa_ils": round(total_spend / max(total_conversions, 1), 2),
        "recommendations": []
    }

    for c in campaigns:
        cpa = c["cost_ils"] / max(c["conversions"], 0.1)
        if c["conversions"] < 1 and c["cost_ils"] > 100:
            analysis["recommendations"].append({
                "campaign": c["campaign"],
                "action": "pause_or_reduce",
                "reason": f"הוציא {c['cost_ils']} ש\"ח ללא המרות. שקלו להשהות.",
                "potential_saving_ils": c["cost_ils"]
            })
        elif cpa < analysis["avg_cpa_ils"] * 0.5:
            analysis["recommendations"].append({
                "campaign": c["campaign"],
                "action": "increase_budget",
                "reason": f"CPA של {round(cpa, 2)} ש\"ח -- מתחת לממוצע. הגדילו תקציב.",
                "potential_impact": "more conversions at good CPA"
            })

    return json.dumps(analysis, ensure_ascii=False)

@tool("generate_ad_variants")
def generate_ad_variants(product: str, target_audience: str,
                         usp: str) -> str:
    """מייצר 3 וריאנטים של נוסחי מודעה לבדיקות A/B."""
    return json.dumps({
        "product": product,
        "variants": [
            {
                "headline_1": f"{product} -- הפתרון שחיכיתם לו",
                "headline_2": f"חיסכון של 50% על {product}",
                "description": f"{usp}. מתאים ל{target_audience}. נסו בחינם!",
                "style": "benefit-focused"
            },
            {
                "headline_1": f"עדיין מבזבזים זמן על {product}?",
                "headline_2": f"אוטומציה של {product} ב-5 דקות",
                "description": f"אלפי עסקים בישראל כבר עברו. {usp}. התחילו היום.",
                "style": "pain-point"
            },
            {
                "headline_1": f"{product} לעסקים בישראל",
                "headline_2": f"תמיכה מלאה בעברית",
                "description": f"{usp}. תוצאות תוך 30 יום או כסף חזרה.",
                "style": "trust-focused"
            }
        ]
    }, ensure_ascii=False)

# --- Agent ---
ads_agent = Agent(
    role="Digital Advertising Analyst",
    goal="לנתח ביצועי קמפיינים פרסומיים, לזהות בזבוז תקציב, "
         "ולהמליץ על אופטימיזציות שמשפרות ROAS",
    backstory="""אתה מומחה פרסום דיגיטלי שמנתח קמפיינים ב-Google Ads
    ו-Meta Ads. אתה מזהה מודעות שמבזבזות תקציב, מילות מפתח שלא ממירות,
    ומצליח למצוא הזדמנויות לאופטימיזציה. אתה תמיד מדבר בשקלים (ש"ח),
    מכיר את השוק הישראלי, ומדגיש ROI בכל המלצה.
    חשוב: אתה ממליץ בלבד -- לעולם לא מבצע שינויים ישירות.""",
    tools=[google_ads_report, budget_analyzer, generate_ad_variants],
    verbose=True,
    llm="anthropic/claude-sonnet-4-20250514"
)
מסגרת החלטה: מתי להקשיב להמלצות הסוכן ומתי לא
סוג המלצה רמת אמון פעולה
"קמפיין X הוציא 500 ש"ח ללא המרות" גבוהה (נתונים עובדתיים) בדקו ופעלו -- עובדה חד-משמעית
"הגדילו bid ב-20% על keyword Y" בינונית (ניתוח טוב, אבל market dynamics מורכבים) בחנו עם שינוי קטן (10%) ועקבו
"שנו את ה-landing page" נמוכה (הסוכן לא רואה את ה-UX) קחו כהשראה, לא כהנחיה ישירה
"הוסיפו קהל יעד חדש" בינונית-נמוכה (תלוי במורכבות השוק) בדקו עם תקציב קטן, A/B test
עשה עכשיו 3 דקות

אם יש לכם Google Ads account, היכנסו ורשמו: מהו הקמפיין הכי יקר שלכם? מהו ה-CPA שלו? ומהו הקמפיין עם ה-ROAS הכי טוב? אם אין לכם -- השתמשו בנתונים הבאים לתרגול: קמפיין "Brand" -- 200 ש"ח, 15 המרות. קמפיין "Generic" -- 800 ש"ח, 3 המרות.

טעות נפוצה: לתת לסוכן לייצר ad copy בלי לבדוק policies

ל-Google Ads ו-Meta Ads יש מדיניות פרסום מחמירה. מודעה שמבטיחה "תוצאות מובטחות" או "הכי טוב בישראל" עלולה להידחות. בשוק הישראלי, חובת סימון מודעות (חוק הגנת הצרכן) מוסיפה שכבה נוספת. כל ad copy שהסוכן מייצר חייב לעבור בדיקת compliance -- ידנית או עם guardrail אוטומטי שבודק claims מוגזמים.

מתקדם 45 דקות תרגול חינם

Marketing Orchestrator -- תזמור המערכת

עכשיו מגיע החלק המרכזי: חיבור כל הסוכנים למערכת אחת מתואמת. ה-Marketing Orchestrator הוא CrewAI Crew שמנהל את ארבעת הסוכנים לפי שגרה מוגדרת.

CrewAI Crew -- המימוש המלא

# orchestrator.py
from crewai import Crew, Process
from agents.content_agent import content_agent, create_blog_post_task
from agents.analytics_agent import analytics_agent, create_weekly_report_task
from agents.competitor_agent import competitor_agent
from agents.ads_agent import ads_agent
from crewai import Task
import json
from datetime import datetime

# --- Orchestrator Tasks ---
def daily_tasks() -> list[Task]:
    """משימות יומיות: analytics + competitor check."""
    return [
        Task(
            description="""בדוק את המטריקות היומיות:
            1. שלוף sessions ו-conversions מאתמול מ-GA4
            2. השווה מול הממוצע של 7 ימים אחרונים
            3. אם יש anomaly -- דווח מיד""",
            expected_output="סיכום יומי: מטריקות + התראות (אם יש)",
            agent=analytics_agent
        ),
        Task(
            description="""בדוק מתחרים:
            1. סרוק את דפי הבלוג של כל 3 המתחרים
            2. בדוק אם יש תוכן חדש
            3. בדוק מיקומי SERP ל-3 מילות מפתח עיקריות
            4. דווח על כל שינוי מהותי""",
            expected_output="דו"ח מתחרים יומי: שינויים + התראות",
            agent=competitor_agent
        ),
    ]

def weekly_tasks() -> list[Task]:
    """משימות שבועיות: full report + content suggestions."""
    return [
        create_weekly_report_task(),
        Task(
            description="""בהתבסס על דו"ח האנליטיקס השבועי ודו"ח המתחרים:
            1. זהה 3 נושאים לתוכן חדש
            2. לכל נושא -- הסבר למה הוא רלוונטי עכשיו
            3. תעדף: מה הכי דחוף ומה יכול לחכות""",
            expected_output="רשימת 3 נושאים מתועדפים לתוכן חדש",
            agent=content_agent
        ),
        Task(
            description="""נתח את ביצועי הקמפיינים של השבוע:
            1. שלוף דו"ח campaign_performance
            2. זהה קמפיינים שמבזבזים תקציב
            3. זהה קמפיינים שמביאים ROI טוב
            4. ייצר 3 המלצות אופטימיזציה ספציפיות""",
            expected_output="דו"ח קמפיינים שבועי + 3 המלצות",
            agent=ads_agent
        ),
    ]

def monthly_tasks(keyword: str) -> list[Task]:
    """משימות חודשיות: content calendar + strategy review."""
    return [
        Task(
            description=f"""ייצר לוח תוכן ל-30 הימים הקרובים:
            1. שלוף top keywords מ-Search Console
            2. זהה פערים תחרותיים (נושאים שמתחרים כתבו ואנחנו לא)
            3. שלב עם calendar events (חגים, אירועים עסקיים)
            4. ייצר brief לכל פריט תוכן

            פורמט הפלט:
            | שבוע | נושא | סוג | פלטפורמה | keyword | סטטוס |
            חגים רלוונטיים: פסח, יום העצמאות, שבועות (בהתאם לתאריך)""",
            expected_output="לוח תוכן ל-30 יום עם briefs",
            agent=content_agent
        ),
        create_blog_post_task(keyword),
    ]

# --- The Crew ---
def run_daily():
    """הפעלת שגרה יומית."""
    crew = Crew(
        agents=[analytics_agent, competitor_agent],
        tasks=daily_tasks(),
        process=Process.sequential,
        verbose=True
    )
    result = crew.kickoff()
    save_report(result, "daily")
    return result

def run_weekly():
    """הפעלת שגרה שבועית."""
    crew = Crew(
        agents=[analytics_agent, content_agent, competitor_agent, ads_agent],
        tasks=weekly_tasks(),
        process=Process.sequential,
        verbose=True
    )
    result = crew.kickoff()
    save_report(result, "weekly")
    return result

def run_monthly(keyword: str):
    """הפעלת שגרה חודשית."""
    crew = Crew(
        agents=[content_agent, analytics_agent, competitor_agent],
        tasks=monthly_tasks(keyword),
        process=Process.hierarchical,
        manager_llm="anthropic/claude-sonnet-4-20250514",
        verbose=True
    )
    result = crew.kickoff()
    save_report(result, "monthly")
    return result

def save_report(result, report_type: str):
    """שומר דו"ח לקובץ."""
    timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M")
    filename = f"output/{report_type}_report_{timestamp}.md"
    with open(filename, "w", encoding="utf-8") as f:
        f.write(f"# דו\"ח {report_type} -- {timestamp}\n\n")
        f.write(str(result))
    print(f"Report saved: {filename}")

if __name__ == "__main__":
    import sys
    mode = sys.argv[1] if len(sys.argv) > 1 else "daily"
    if mode == "daily":
        run_daily()
    elif mode == "weekly":
        run_weekly()
    elif mode == "monthly":
        keyword = sys.argv[2] if len(sys.argv) > 2 else "אוטומציה שיווקית"
        run_monthly(keyword)

TypeScript Orchestrator

// orchestrator.ts
import { generateBlogPost } from "./agents/content-agent";
import { generateWeeklyReport } from "./agents/analytics-agent";
import { generateText } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
import { writeFileSync } from "fs";

interface OrchestratorResult {
  type: "daily" | "weekly" | "monthly";
  timestamp: string;
  reports: Record<string, string>;
}

async function runDaily(): Promise<OrchestratorResult> {
  console.log("Running daily marketing check...");

  const analyticsReport = await generateWeeklyReport(); // daily subset
  // const competitorReport = await checkCompetitors();

  const result: OrchestratorResult = {
    type: "daily",
    timestamp: new Date().toISOString(),
    reports: {
      analytics: analyticsReport,
      // competitors: competitorReport,
    },
  };

  saveReport(result);
  return result;
}

async function runWeekly(): Promise<OrchestratorResult> {
  console.log("Running weekly marketing report...");

  const [analyticsReport, blogPost] = await Promise.all([
    generateWeeklyReport(),
    generateBlogPost("אוטומציה שיווקית"),
  ]);

  const result: OrchestratorResult = {
    type: "weekly",
    timestamp: new Date().toISOString(),
    reports: {
      analytics: analyticsReport,
      content_draft: blogPost,
    },
  };

  saveReport(result);
  return result;
}

function saveReport(result: OrchestratorResult) {
  const filename = `output/${result.type}_report_${
    new Date().toISOString().split("T")[0]
  }.json`;
  writeFileSync(filename, JSON.stringify(result, null, 2), "utf-8");
  console.log(`Report saved: ${filename}`);
}

// CLI
const mode = process.argv[2] ?? "daily";
if (mode === "daily") runDaily();
else if (mode === "weekly") runWeekly();

תזמון אוטומטי

מערכת שיווק אוטומטית צריכה לרוץ בלי שמישהו מפעיל אותה ידנית. הנה שלוש אפשרויות:

שיטה מתאים ל... הגדרה
Cron Job שרת Linux / Mac 0 8 * * * cd /app && python orchestrator.py daily (כל יום ב-8:00)
GitHub Actions פרויקטים ב-GitHub Schedule trigger עם cron expression
Cloudflare Workers + Cron Triggers serverless Worker שמפעיל את הסוכן, trigger כל X שעות
# .github/workflows/marketing-daily.yml
name: Daily Marketing Check
on:
  schedule:
    - cron: '0 6 * * *'  # כל יום ב-6:00 UTC (8:00 ישראל)
  workflow_dispatch:       # גם ידנית

jobs:
  daily-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - run: pip install -r requirements.txt
      - run: python orchestrator.py daily
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          GA4_PROPERTY_ID: ${{ secrets.GA4_PROPERTY_ID }}
      - uses: actions/upload-artifact@v4
        with:
          name: daily-report
          path: output/daily_report_*.md
תרגיל 3: הרכיבו את ה-Orchestrator המלא (45 דקות)
  1. חברו את כל 4 הסוכנים (content, analytics, competitor, ads) ל-Crew אחד
  2. הגדירו שלוש שגרות: daily (analytics + competitors), weekly (+ content + ads), monthly (+ calendar)
  3. הריצו את השגרה היומית ובדקו: האם כל סוכן הפיק output? האם הסדר הגיוני?
  4. הגדירו cron job או GitHub Action שמריץ את השגרה היומית אוטומטית
  5. בדקו שהדו"חות נשמרים ב-output/ עם timestamps

תוצאה צפויה: orchestrator שמריץ שגרה יומית מלאה, שומר דו"ח, ומדווח על anomalies.

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

רשמו את לוח הזמנים האידיאלי שלכם: באיזו שעה הייתם רוצים שהסוכן יריץ את הבדיקה היומית? באיזה יום השגרה השבועית? ובאיזה תאריך בחודש השגרה החודשית? רשמו -- תשתמשו בזה ב-cron expression.

בינוני 30 דקות תרגול חינם

Content Calendar Automation -- לוח תוכן אוטומטי

אחת המשימות הכי מתישות בשיווק היא תכנון לוח תוכן חודשי. צריך לשלב: נתוני SEO (אילו keywords כדאי לכתוב עליהם), פערים תחרותיים (מה המתחרים כתבו ואנחנו לא), חגים ואירועים (פסח, יום העצמאות, Black Friday), ומטרות עסקיות (השקת מוצר, קמפיין חדש).

הסוכן עושה את הכל אוטומטית. הוא שולף נתונים מ-Search Console, בודק מה המתחרים פרסמו לאחרונה, מצליב עם לוח שנה ישראלי, ומייצר content calendar מלא עם briefs.

# tools/calendar_generator.py
import json
from datetime import datetime, timedelta

# לוח חגים ואירועים ישראליים 2026
ISRAELI_EVENTS = {
    "2026-04-02": "ערב פסח",
    "2026-04-03": "פסח -- חג ראשון",
    "2026-04-09": "פסח -- חג שביעי",
    "2026-04-15": "יום השואה",
    "2026-04-22": "יום הזיכרון",
    "2026-04-23": "יום העצמאות",
    "2026-05-13": "ל\"ג בעומר",
    "2026-05-22": "שבועות",
    "2026-06-14": "אירוע eCommerce Israel",
    "2026-09-12": "ראש השנה",
    "2026-09-21": "יום כיפור",
    "2026-11-27": "Black Friday",
    "2026-12-06": "חנוכה",
}

CONTENT_TYPES = {
    "blog": {"frequency": "2/week", "lead_time_days": 5},
    "social_linkedin": {"frequency": "3/week", "lead_time_days": 2},
    "social_facebook": {"frequency": "4/week", "lead_time_days": 1},
    "email": {"frequency": "1/week", "lead_time_days": 3},
    "ad_copy": {"frequency": "as_needed", "lead_time_days": 2},
}

def generate_calendar(
    start_date: datetime,
    keywords: list[str],
    competitor_gaps: list[str],
    business_goals: list[str],
    days: int = 30
) -> list[dict]:
    """מייצר לוח תוכן ל-N ימים."""
    calendar = []
    current = start_date

    for day in range(days):
        date = current + timedelta(days=day)
        date_str = date.strftime("%Y-%m-%d")
        day_of_week = date.strftime("%A")

        entry = {
            "date": date_str,
            "day": day_of_week,
            "content": [],
            "event": ISRAELI_EVENTS.get(date_str, None),
        }

        # Blog: Sunday + Wednesday
        if day_of_week in ["Sunday", "Wednesday"]:
            keyword = keywords[day % len(keywords)]
            entry["content"].append({
                "type": "blog",
                "keyword": keyword,
                "status": "draft_needed",
                "deadline": (date - timedelta(days=5)).strftime("%Y-%m-%d"),
                "brief": f"פוסט על {keyword}. אורך: 1200-2000 מילים."
            })

        # LinkedIn: Sunday + Tuesday + Thursday
        if day_of_week in ["Sunday", "Tuesday", "Thursday"]:
            entry["content"].append({
                "type": "linkedin",
                "topic": keywords[(day + 1) % len(keywords)],
                "status": "draft_needed"
            })

        # Event-based content
        if entry["event"]:
            entry["content"].append({
                "type": "event_post",
                "event": entry["event"],
                "platforms": ["facebook", "linkedin", "email"],
                "brief": f"תוכן ל{entry['event']}. קשרו למוצר."
            })

        calendar.append(entry)

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

הריצו את generate_calendar() עם 5 keywords שלכם ובדקו את הפלט. ספרו: כמה פריטי תוכן יש בחודש? האם יש "ימים עמוסים מדי"? שנו את הפרמטרים עד שהלוח ריאלי לצוות שלכם.

Content Brief אוטומטי

לוח תוכן בלי content briefs הוא רשימת קניות בלי מתכון. ה-brief מפרט לכותב (אנושי או AI) בדיוק מה לכתוב:

# דוגמת content brief שהסוכן מייצר
content_brief = {
    "title_suggestion": "אוטומציה שיווקית לעסקים קטנים: המדריך המלא 2026",
    "primary_keyword": "אוטומציה שיווקית",
    "secondary_keywords": [
        "אוטומציה שיווקית לעסקים קטנים",
        "כלי אוטומציה שיווקית",
        "אוטומציה שיווקית בישראל"
    ],
    "target_audience": "בעלי עסקים קטנים, 30-55, ישראל",
    "content_angle": "practical_guide",
    "word_count": "1,500-2,000",
    "structure": [
        "H2: מה זה אוטומציה שיווקית? (הגדרה + דוגמאות)",
        "H2: למה עסקים קטנים צריכים אוטומציה (5 סיבות עם נתונים)",
        "H2: 5 הכלים הכי טובים לעסקים בישראל",
        "H2: איך מתחילים -- מדריך צעד אחר צעד",
        "H2: כמה זה עולה? השוואת מחירים בש\"ח",
        "H2: טעויות נפוצות (ואיך להימנע מהן)",
    ],
    "competitor_content": [
        "CompetitorA כתב על זה לפני 8 חודשים -- 1,200 מילים, ללא נתונים",
        "CompetitorB לא כתב על הנושא כלל"
    ],
    "our_angle": "יותר מעמיק + נתונים ישראליים + השוואת מחירים בש\"ח",
    "internal_links": [
        "/blog/crm-for-small-business",
        "/blog/email-marketing-guide"
    ],
    "cta": "הירשמו לניסיון חינם של ClickFlow"
}
מסגרת החלטה: מתי להשתמש ב-AI לכתיבת תוכן ומתי באדם
סוג התוכן AI אדם שילוב (הכי טוב)
בלוג -- draft ראשון מצוין. מהיר, עקבי, SEO איטי אבל מקורי AI כותב draft, אדם עורך
פוסט LinkedIn אישי חסר אותנטיות אישי ואמיתי AI מציע מבנה, אדם ממלא סיפור אישי
אימייל שיווקי טוב ל-templates טוב ל-VIP / אישי AI יוצר sequence, אדם מתאים אישית
Ad copy מצוין ל-variants טוב ל-creative direction AI מייצר 10 variants, אדם בוחר 3
Case study / עדות לא מתאים הכרחי -- צריך אותנטיות אדם אוסף, AI מעצב ועורך
בינוני 25 דקות ניתוח חינם

הערכת ביצועים ו-ROI

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

עלות הסוכן

רכיב עלות חודשית הערות
LLM API (Anthropic/OpenAI) $15-60 תלוי בתדירות ובאורך outputs
Google APIs (GA4, GSC) $0 חינם לשימוש סביר
Search API (SerpAPI/Brave) $5-20 תלוי במספר חיפושים
Hosting (GitHub Actions / Cloudflare) $0-10 GitHub Actions: 2,000 דק/חודש חינם
סה"כ $20-90 (~75-330 ש"ח)

עלות אנושית מקבילה

משימה זמן אנושי / שבוע עלות חודשית (150 ש"ח/שעה)
כתיבת 2 בלוגים 4-6 שעות 2,400-3,600 ש"ח
דו"ח אנליטיקס שבועי 1-2 שעות 600-1,200 ש"ח
מעקב מתחרים 2-3 שעות 1,200-1,800 ש"ח
ניתוח קמפיינים 2-3 שעות 1,200-1,800 ש"ח
לוח תוכן חודשי 3-4 שעות (חודשי) 450-600 ש"ח
סה"כ 12-18 שעות/שבוע 5,850-9,000 ש"ח
ROI של Marketing Automation Agent

חיסכון חודשי: 5,850-9,000 ש"ח (עבודה אנושית) פחות 75-330 ש"ח (עלות סוכן) = 5,520-8,670 ש"ח חיסכון נטו. ROI: 2,600%-7,260%. חשוב: הסוכן לא מחליף משווק -- הוא מפנה לו 12-18 שעות לשבוע לעבודה אסטרטגית, יצירתית, וניהול קשרים אישיים. ה-draft של הבלוג עדיין צריך עריכה אנושית (30-60 דק במקום 3-4 שעות כתיבה מאפס).

מדדי איכות

ROI הוא לא רק כסף. צריך לבדוק איכות:

מדד איך מודדים יעד
Content usability rate % drafts שפורסמו (אחרי עריכה) מתוך כלל הdrafts 70%+
Edit ratio % שינויים שאדם עושה ב-draft של הסוכן מתחת ל-30%
Alert accuracy % התראות שבאמת היו רלוונטיות (לא false positives) 80%+
Recommendation adoption % המלצות אופטימיזציה שנאמצו ע"י הצוות 50%+
Time to insight כמה זמן עובר עד שהצוות מקבל insight פעיל תוך שעה מריצה
תרגיל 4: חשבו ROI לעסק שלכם (20 דקות)
  1. רשמו את 5 המשימות השיווקיות הכי חוזרות שלכם
  2. לכל משימה, העריכו: כמה שעות בשבוע? מה עלות השעה?
  3. העריכו כמה מכל משימה סוכן AI יכול לעשות (אחוז)
  4. חשבו: עלות סוכן חודשית vs. חיסכון חודשי
  5. רשמו: באילו משימות ה-ROI הכי גבוה? (שם תתחילו)
  6. הוסיפו מדד איכות אחד שתעקבו אחריו

תוצאה צפויה: טבלת ROI מותאמת אישית עם תעדוף -- מאילו משימות להתחיל עם אוטומציה.

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

חשבו תשובה אחת: מהי המשימה השיווקית היחידה שאם תאטמטו אותה, תחסכו הכי הרבה זמן? רשמו אותה.

מתחיל 10 דקות אסטרטגיה חינם

שגרת עבודה שיווקית עם סוכן

בנוסף לשגרת הסוכנים מפרקים קודמים (monitoring מפרק 14, research workflow מפרק 16), הנה השגרה הספציפית לניהול מערכת השיווק האוטומטית:

שגרת עבודה -- Marketing Automation Agent
תדירות משימה זמן
יומי בדקו את הדו"ח היומי של הסוכן: יש anomalies? שינויים אצל מתחרים? 5 דק
יומי אם יש draft תוכן -- סקרו ואשרו או בקשו שינויים 10-15 דק
יומי בדקו alert accuracy: האם ההתראות האחרונות היו מוצדקות? 2 דק
שבועי סקרו את הדו"ח השבועי: מטריקות, המלצות תוכן, ניתוח מתחרים 20 דק
שבועי פעלו על המלצות אופטימיזציה -- בחנו, אשרו, או דחו 15 דק
שבועי עדכנו brand guidelines אם השתנה משהו (מוצר חדש, טון, תחרות) 5 דק
חודשי סקרו את לוח התוכן שהסוכן ייצר -- אשרו, שנו, או הוסיפו 30 דק
חודשי בדקו ROI: עלות סוכן מול חיסכון. עדכנו את ה-ROI calculator 15 דק
חודשי שפרו prompts -- בהתבסס על drafts שדרשו הרבה עריכה 20 דק
עשה עכשיו 3 דקות

קבעו תזכורת בלוח השנה: "בדיקת דו"ח סוכן שיווקי" -- כל בוקר ב-8:30. גם אם עדיין לא הפעלתם את המערכת, ההרגל חשוב יותר מהכלי.

אם אתם עושים רק דבר אחד מהפרק הזה

בנו את Content Agent -- הסוכן שמקבל keyword ומייצר draft של בלוג פוסט עם SEO meta tags. זה הסוכן עם ה-ROI הכי גבוה (חוסך 3-4 שעות כתיבה, עולה $0.10-0.30 לריצה), ותוכלו לראות תוצאות ביום הראשון. אחרי שזה עובד -- הוסיפו analytics, ואז competitor monitoring. צעד אחד בכל פעם.

בדוק את עצמך -- 5 שאלות
  1. למה ה-Ads Agent צריך לפעול ב-READ-ONLY? מה הסיכונים של write access, ובאילו תנאים הייתם שוקלים לתת גישת כתיבה? (רמז: budget, bids, approval workflows)
  2. מה ההבדל בין Content Calendar ל-Content Brief? למה צריך את שניהם? (רמז: planning vs. execution guidance)
  3. תארו את 3 סוגי השגרות (יומית, שבועית, חודשית) של ה-Orchestrator. מה כל שגרה בודקת, ולמה הסדר הזה הגיוני? (רמז: urgency, scope, strategy)
  4. איך מודדים alert accuracy של Competitor Agent? למה false positives מסוכנים לא פחות מ-false negatives? (רמז: alert fatigue, trust)
  5. חשבו ROI: סוכן שיווקי עולה 200 ש"ח/חודש ומייצר drafts שדורשים 30 דקות עריכה במקום 3 שעות כתיבה. אם מייצרים 8 בלוגים בחודש, מהו ה-ROI? (רמז: (savings - cost) / cost, שעת משווק = 150 ש"ח)

עברתם 4 מתוך 5? מצוין -- אתם מוכנים לפרק 18.

סיכום הפרק

בפרק הזה בניתם מערכת שיווק אוטומטית מלאה -- ממשימה בודדת ועד orchestrator שמנהל צוות של ארבעה סוכנים מתמחים. התחלתם עם Content Agent שיודע לייצר בלוג פוסט מ-keyword עם brand voice עקבי ו-SEO מובנה. הוספתם Analytics Agent שמתחבר ל-GA4 ו-Search Console, שולף נתונים, ומזהה anomalies -- במקום שתבלו שעה-שעתיים בשליפת דו"חות ידנית. בניתם Competitor Agent שעוקב אחרי מתחרים ישראליים -- תוכן חדש, מיקומים בגוגל, שינויי מחירים -- עם snapshots שמאפשרים השוואה לאורך זמן. הוספתם Ads Agent שמנתח קמפיינים ב-Google Ads בREAD-ONLY ומייצר המלצות אופטימיזציה שחוסכות אלפי שקלים. חיברתם הכל עם Marketing Orchestrator -- CrewAI Crew עם שגרות יומיות, שבועיות, וחודשיות שרצות אוטומטית. ייצרתם Content Calendar אוטומטי שמבוסס על SEO data, פערים תחרותיים, ולוח חגים ישראלי. ולבסוף, חישבתם ROI -- ומצאתם שהסוכן חוסך 5,500-8,700 ש"ח בחודש בעלות של 75-330 ש"ח.

הנקודה המרכזית: סוכן שיווקי לא מחליף משווק -- הוא מעצים אותו. הוא עושה את העבודה הטכנית (שליפת דו"חות, drafts ראשונים, ניטור מתחרים), ומשאיר לאדם את מה שרק אדם יודע לעשות: אסטרטגיה, יצירתיות, קשרים אישיים, והחלטות עסקיות.

בפרק הבא (פרק 18) תבנו Code Review & DevOps Agent -- סוכן שעושה review לPull Requests, עוזר עם deployments, ומנטר production. תראו איך אותם דפוסים של multi-agent orchestration מתאימים לdomain אחר לחלוטין.

צ'קליסט -- סיום פרק 17