חזרה
// סדרת Wholesale Automation · חלק 1 מתוך 2← מעבר לחלק 2 בסדרה
// מערכות מבוזרות וטלפוניית ענן/20 דקות קריאה/פורסם: 2025-12-18

טלפוניית AI אוטונומית: ארכיטקטורה מבוזרת, תשתיות ענן ותכנון משאבים

מדריך הנדסי מקיף לבניית צינורות קול בשיהוי מינימלי, נתיב הליבה (Core Highway), מניעת מרוצי תהליכים וניתוח סמנטי באצוות.

  • AWS SAM
  • Twilio Voice
  • PostgreSQL
  • DynamoDB
  • Hume AI
  • DevOps
  • Python 3.11
אבירם יגנה
אבירם יגנה
ארכיטקט מערכות ראשי ומייסד שותף

הקשר המערכת ואתגר ההנדסה המרכזי

// מדוע ארכיטקטורות טלפוניה רגילות קורסות תחת עומסי חיוג מבוססי בינה מלאכותית

מערכות טלפוניה אוטומטיות בהיקפים גבוהים פועלות בסביבת רשת מורכבת ובלתי צפויה. בעת ביצוע אלפי שיחות קוליות מדי שעה, ספקי תקשורת, מרכזיות טלפוניה (Twilio, Telnyx) ומכשירי קצה אנושיים מייצרים גלי אירועים אסינכרוניים המגיעים לעיתים בסדר הפוך.

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

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

  • ▪מניעה מוחלטת של שיחות כפולות בעזרת נעילות שורה במסד PostgreSQL לצד נעילות מהירות במסד DynamoDB עם מנגנון מחיקה אוטומטי.
  • ▪מענה קולי מיידי הודות לפתיחת גשר האודיו במקביל לצליל החיוג, תוך אגירת פתיח השיחה עוד לפני שהלקוח עונה לקו.
  • ▪ויסות חיוג קבוע ויציב הנאכף באמצעות תור SQS מתמשך הפועל בקצב מדויק בהתאם לתקנות ספקי התקשורת.

נתיב הליבה המשותף (Core Service Highway): ניתוק תלויות הדדיות בין שירותי ענן

// מדוע הפניות ישירות בתבניות ענן מובילות לנעילות פריסה וכיצד תבנית נתיב הליבה פותרת זאת

בארכיטקטורות ענן מבוזרות מבוססות Serverless, אחת הטעויות הנפוצות בשלבי הפיתוח הראשונים היא לאפשר למיקרו-שירותים לתקשר באמצעות הפניות ישירות בין תבניות CloudFormation או ייצוא הדדי של משאבים (הוראות !GetAtt ו-!ImportValue). בגרסאות הראשונות, כאשר שירות קליטת המידע (Webhook Receiver) פנה ישירות למשאבים של שירות הוויסות (Pacing Metronome) או מנהל הנעילות (State Arbiter), ענן AWS יצר נעילת תלויות קשיחה שאינה ניתנת להפרדה.

צימוד זה הפך כל עדכון פריסה לסיוט תפעולי. בכל פעם שמהנדס נדרש לעדכן, לבצע rollback או להוריד מיקרו-שירות בודד, ענן AWS סירב לבצע את הפעולה בשל שגיאות export-in-use. הורדה או שדרוג של שירות בודד חייבה מחיקה או השבתה של מספר שירותים מקבילים בכל רחבי המערכת.

כדי לחסל את צוואר הבקבוק הזה לצמיתות, תכננו מחדש את המערכת סביב תבנית נתיב הליבה (Core Service Highway). שירות הליבה משמש כעורק התחבורה הראשי של המאגר כולו. הוא מרכז בתוכו את כלל החוזים המשותפים, סכמות הנתונים של Pydantic, מאגרי החיבורים למסד הנתונים (AWS RDS Proxy), רישום יומנים מובנה (JSON Logging) והגדרות אפיק האירועים.

כל מיקרו-שירות עצמאי מתחבר ישירות אל נתיב הליבה, אך שירותי הקצה לעולם אינם מייבאים קוד, מפנים או מכירים זה את זה ישירות. היתרון התפעולי עצום: ניתן לפרוס, לשדרג או להוריד לחלוטין את שירות ה-Webhook Receiver או את שירות ה-Audio Bridge תוך שניות בודדות מבלי להשפיע או לגעת בשום שירות שכן. הפשרה הארכיטקטונית היחידה היא ששינוי בשירות הליבה עצמו הוא אירוע תשתיתי הדורש בדיקה מקיפה, אך מכיוון שהלוגיקה העסקית חיה כולה בשירותי הקצה, 99% מהפריסות מתבצעות באופן עצמאי לחלוטין.

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

טופולוגיית הקוד, תבנית Parser-Executor ובדיקות במבנה מראה (Mirrored Tests)

// הפרדה מוחלטת של תחומי אחריות: מתאמי קלט נפרדים, מנועי ביצוע טהורים ובדיקות מבודדות לחלוטין

מבנה התיקיות משקף את עקרונות נתיב הליבה ובידוד השירותים. במקום ספרייה לא מובנית של קבצי סקריפט, כל מיקרו-שירות פועל לפי תבנית פנימית קשיחה של Parser-Executor-Handler המפרידה בין התאמת פרוטוקולי רשת לבין לוגיקה עסקית טהורה.

בתוך כל מיקרו-שירות: קובץ parser.py קולט נתוני רשת גולמיים (דוגמת בקשות HTTP מספקי תקשורת, הודעות תור SQS או מקטעי שמע ב-WebSocket) ומאמת אותם מול סכמות הליבה; קובץ executor.py מכיל את חוקי העסק וניהול המצבים ללא כל תלות בסביבת AWS Lambda או בפרוטוקול התעבורה; וקובץ handler.py הוא קוד מקשר דק של עד 25 שורות המחבר ביניהם.

יתרה מכך, מערך הבדיקות בנוי בתבנית מראה מדויקת של 1:1. בתוך כל מיקרו-שירות, תיקיית הבדיקות tests/ משקפת במדויק את מבנה התיקייה הראשית (למעט תיקיית הבדיקות עצמה). לכל קובץ מקור יש קובץ בדיקה ייעודי ומבודד (test_parser.py, test_executor.py, test_handler.py). מבנה זה מונע זליגת תלויות בין בדיקות ומצביע מיידית ב-CI על הקובץ המדויק שדורש התייחסות.

עץ קבצים ומבנה שירותים
  • 📁 wholesale-automation/# תיקיית הבסיס של הפרויקט
    • 📁 core/# נתיב הליבה (Core Highway): חוזים משותפים, מאגרי מסד וסכמות אירועים
      • 📁 contracts/
        • 📄 events.py# סכמות נתונים ב-Pydantic עבור אפיקי הודעות
        • 📄 telephony.py# מודלי סטטוס שיחה ומדרג עדיפויות
      • 📁 database/
        • 📄 connection.py# ניהול מאגר חיבורים ב-PostgreSQL RDS Proxy
        • 📄 advisory.py# עזרי נעילות שורה ונעילות טרנזקציה
      • 📁 telemetry/
        • 📄 logger.py# רישום יומנים מובנה בפורמט JSON
      • 📁 tests/# בדיקות מראה מבודדות עבור רכיבי הליבה
        • 📄 test_events.py
        • 📄 test_connection.py
        • 📄 test_advisory.py
    • 📁 services/# מיקרו-שירותים עצמאיים (כל שירות נפרס כפונקציית Lambda עצמאית)
      • 📁 webhook_receiver/# נקודת קצה מהירה במיוחד לקבלת עדכוני סטטוס מרשת Twilio
        • 📄 handler.py# קוד כניסה רזה (פחות מ-25 שורות)
        • 📄 parser.py# טיוב כותרי רשת ואימות חתימות ספק
        • 📄 executor.py# הזנת הודעות גולמיות לנתיב ה-SQS
        • 📄 requirements.txt
        • 📁 tests/# בדיקות מראה מבודדות 1:1
          • 📄 test_parser.py
          • 📄 test_executor.py
          • 📄 test_handler.py
      • 📁 pacing_metronome/# מנוע ויסות המשחרר שיחות במרווחי זמן מדויקים לפי מגבלות קווי התקשורת
        • 📄 handler.py
        • 📄 parser.py
        • 📄 executor.py
        • 📁 tests/
          • 📄 test_parser.py
          • 📄 test_executor.py
      • 📁 audio_bridge/# שרת תקשורת בזמן אמת המחבר בין ערוצי Twilio למנוע הקולי של Hume AI
        • 📄 handler.py
        • 📄 bridge.py
        • 📄 audio_buffer.py
        • 📄 vad.py# מזהה פעילות קולית בזמן אמת
        • 📁 tests/
          • 📄 test_bridge.py
          • 📄 test_audio_buffer.py
          • 📄 test_vad.py
      • 📁 state_arbiter/# ניהול נעילות שורה במסד PostgreSQL ועדכון סטטוס הפנייה
        • 📄 handler.py
        • 📄 parser.py
        • 📄 executor.py
        • 📁 tests/
          • 📄 test_parser.py
          • 📄 test_executor.py
      • 📁 batch_analytics/# ניתוח סמנטי של תמלילים באצוות וחילוץ מדדי מוטיבציה של מוכרים
        • 📄 handler.py# מופעל לפי גודל אצווה או תזמון קבוע
        • 📄 parser.py# חילוץ מקטעי תמליל ומטא-דאטה
        • 📄 semantic_analyzer.py# חילוץ פרמטרים מובנים באמצעות LLM
        • 📁 tests/
          • 📄 test_parser.py
          • 📄 test_semantic_analyzer.py
    • 📁 infrastructure/# תבניות תשתית כקוד והגדרות סביבה
      • 📄 template.yaml# תבנית AWS SAM המגדירה את כלל משאבי הענן
      • 📄 samconfig.toml# פרמטרי פריסה עבור סביבות staging ו-production
    • 📁 tests/# בדיקות אינטגרציה מקצה לקצה ושרת סימולציית טלפוניה
      • 📄 e2e_call_lifecycle.py
      • 📄 mock_twilio_server.py# שרת מקומי המדמה ערוצי Twilio Media Streams

תשתיות כקוד: תבנית ה-AWS SAM המלאה

// הגדרה הצהרתית של משאבי ענן עם תורי הודעות שגיאה (DLQ), אפיקי אירועים ורשת מנוהלת

כל משאבי הענן מוגדרים בצורה הצהרתית באמצעות AWS Serverless Application Model (SAM). אנו נמנעים לחלוטין משינויים ידניים בממשק הניהול של AWS כדי להבטיח התאמה מלאה בין סביבת הבדיקות לסביבת הייצור.

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

להלן קטע מתבנית ה-SAM המגדיר את אפיק המצבים, תור הוויסות ומקבל הודעות ה-Webhook מהטלפוניה:

infrastructure/template.yaml
yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Wholesale Automation Telephony and Distributed State Engine

Globals:
  Function:
    Runtime: python3.11
    Architectures:
      - arm64 # Graviton2: 20% lower cost, 15% lower compute latency
    Timeout: 10
    MemorySize: 512
    Environment:
      Variables:
        STAGE: !Ref Stage
        LOG_LEVEL: INFO
        DB_SECRET_ARN: !Ref DatabaseSecretArn

Parameters:
  Stage:
    Type: String
    Default: staging
    AllowedValues: [staging, production]
  DatabaseSecretArn:
    Type: String
    Description: AWS Secrets Manager ARN containing PostgreSQL credentials

Resources:
  # 1. Pacing SQS Queue with Dead-Letter Queue
  MetronomeDLQ:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: !Sub "${Stage}-wholesale-metronome-dlq"
      MessageRetentionPeriod: 1209600 # 14 days

  MetronomeQueue:
    Type: AWS::SQS::Queue
    Properties:
      QueueName: !Sub "${Stage}-wholesale-metronome"
      VisibilityTimeout: 60 # 6x the Lambda timeout of 10s
      RedrivePolicy:
        deadLetterTargetArn: !GetAtt MetronomeDLQ.Arn
        maxReceiveCount: 3

  # 2. Ultra-Fast Webhook Receiver (Twilio Status Callbacks)
  TwilioWebhookFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: services/webhook_receiver/
      Handler: handler.lambda_handler
      MemorySize: 256 # Lightweight string validation and queuing
      Timeout: 5     # Fast return to avoid Twilio callback timeout
      Events:
        TwilioHttp:
          Type: HttpApi
          Properties:
            Path: /webhooks/twilio
            Method: post

  # 3. Audio Bridge Worker (Real-time WebSockets & VAD)
  AudioBridgeFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: services/audio_bridge/
      Handler: handler.lambda_handler
      MemorySize: 1769 # Allocated exactly 1 full dedicated vCPU
      Timeout: 300     # 5-minute maximum call duration
      Policies:
        - AWSLambdaBasicExecutionRole
        - SecretsManagerReadWrite
הסבר תכנוני: שימו לב להגדרת VisibilityTimeout של 60 שניות בתור ה-SQS: בדיוק פי 6 ממשך הריצה של הפונקציה (10 שניות), בהתאם להנחיות הרשמיות של AWS למניעת עיבוד כפול של אותה פנייה.

כיול משאבים: המתמטיקה של זיכרון, מעבד ושיהוי

// מדוע הקצאת 1769 MB ב-Lambda היא סוד ההצלחה לקול רציף ללא קטיעות

טעות שכיחה בארכיטקטורות Serverless היא הגדרת הזיכרון למינימום האפשרי (128 MB או 256 MB) מתוך כוונה לחסוך בעלויות. במערכות שמע בזמן אמת ובסביבות עתירות מקביליות, החלטה זו מובילה לפגיעה ביצועית קשה.

ב-AWS Lambda, עוצמת המעבד (CPU) ורוחב הפס של הרשת מוקצים ביחס ישר לכמות הזיכרון. בדיוק ברף של 1769 MB, המערכת מקצה ליבת מעבד מלאה וייעודית (1.0 dedicated vCPU). מתחת לרף זה, הפונקציה מקבלת מקטעי זמן חלקיים של מעבד, מה שגורם להשהיות תקופתיות של עשרות מילי-שניות בעת ניקוי זיכרון או פעולות GIL בפייתון. עבור ממשק REST רגיל השהיה כזו אינה מורגשת; אך בערוץ שמע דיגיטלי חי של 8kHz, השהיה של 40 מילי-שניות נשמעת כגמגום קולי רובוטי צורם.

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

Audio Bridge Worker

זיכרון:1769 MB
עוצמת מעבד (vCPU)1.0 dedicated vCPU
זמן תפוגה300s (5 דקות)
מקביליות100 reserved
נימוק תכנוני:

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

Twilio Webhook Receiver

זיכרון:256 MB
עוצמת מעבד (vCPU)0.14 fractional vCPU
זמן תפוגה5s
מקביליות500 unreserved
נימוק תכנוני:

פענוח בקשות קל-משקל. נדרש להחזיר תשובת 200 תוך פחות מ-300 מילי-שניות כדי למנוע ניסיונות חוזרים מרשת Twilio.

Pacing Metronome Dispatcher

זיכרון:512 MB
עוצמת מעבד (vCPU)0.29 fractional vCPU
זמן תפוגה10s
מקביליות1 (נעילת FIFO)
נימוק תכנוני:

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

State Arbiter & Lock Release

זיכרון:512 MB
עוצמת מעבד (vCPU)0.29 fractional vCPU
זמן תפוגה15s
מקביליות50 reserved
נימוק תכנוני:

נדרש למאגר חיבורים קבוע למסד PostgreSQL (דרך RDS Proxy) לסגירת טרנזקציות ללא מיצוי חיבורים.

Batch Analytics Worker

זיכרון:1024 MB
עוצמת מעבד (vCPU)0.58 fractional vCPU
זמן תפוגה60s
מקביליות10 reserved
נימוק תכנוני:

מעבד 25 תמלילי שיחות בכל אצווה; זיכרון גבוה יותר מאפשר פענוח JSON מהיר וטיפול בנפחי טוקנים גדולים.

Lead Ingestion & Normalizer

זיכרון:1024 MB
עוצמת מעבד (vCPU)0.58 fractional vCPU
זמן תפוגה60s
מקביליות10 reserved
נימוק תכנוני:

מעבד מקבצים גדולים של נתוני נכסים, מבצע סינון כפילויות ואימות מספרי טלפון על פני 10,000 רשומות.

מקביליות מבוזרת: תבנית הנעילה במסד הנתונים

// כיצד פתרנו את בעיית ההודעות האסינכרוניות באמצעות נעילות PostgreSQL ייעודיות

כאשר מבוצעת שיחה יוצאת, עשויים להגיע במקביל עד 5 אירועים שונים: עדכון סטטוס מהספק ("חיוג"), פתיחת ערוץ השמע של Twilio ("מדיה מוכנה"), ניתוק על ידי הלקוח ותפוגת זמן פנימית. עדכון רגיל במסד בסגנון UPDATE leads SET status = ... גורם לשאילתה שהגיעה אחרונה לדרוס את האמת העסקית.

כדי לפתור זאת, יישמנו אסטרטגיית נעילה כפולה: מסד DynamoDB עם מנגנון מחיקה אוטומטי (TTL) משמש כמחסום מהיר, בעוד נעילות ברמת טרנזקציה במסד PostgreSQL (מסוג Advisory Locks) מבטיחות סדר כרונולוגי ודאי.

זהו קוד השאילתה המרכזי שמריץ שירות ה-State Arbiter לפני כל שינוי מצב:

services/state_arbiter/executor.py
python
import psycopg2
from contextlib import contextmanager

@contextmanager
def acquire_lead_lock(cursor, lead_id: int):
    """
    Acquires an application-level transactional advisory lock on a lead ID.
    If another worker is currently mutating this lead, the query will wait
    until the transaction completes, guaranteeing serialized state transitions.
    """
    try:
        # pg_advisory_xact_lock automatically releases when the transaction commits or rolls back
        cursor.execute("SELECT pg_advisory_xact_lock(%s);", (lead_id,))
        yield
    finally:
        pass

def update_call_outcome(conn, lead_id: int, new_status: str, call_duration_sec: int):
    STATUS_PRIORITY = {
        'PENDING': 0,
        'DISPATCHED': 1,
        'RINGING': 2,
        'CONNECTED': 3,
        'QUALIFIED': 4,
        'COMPLETED': 4,
        'FAILED': 4
    }

    with conn.cursor() as cursor:
        with acquire_lead_lock(cursor, lead_id):
            cursor.execute("SELECT status FROM leads WHERE id = %s FOR UPDATE;", (lead_id,))
            current = cursor.fetchone()
            if not current:
                return False

            current_status = current[0]
            # Prevent out-of-order carrier packets from downgrading final states
            if STATUS_PRIORITY.get(new_status, 0) < STATUS_PRIORITY.get(current_status, 0):
                # Log stale event and discard safely
                return False

            cursor.execute("""
                UPDATE leads
                SET status = %s,
                    duration = duration + %s,
                    updated_at = NOW()
                WHERE id = %s;
            """, (new_status, call_duration_sec, lead_id))
            conn.commit()
            return True
הסבר תכנוני: הפונקציה pg_advisory_xact_lock מוודאת שגם אם שני שרתים מקבלים אותות שונים בהפרש של שתי מילי-שניות, השרת השני ימתין עד לסיום הפעולה הראשונה ויקרא את הסטטוס המעודכן לפני ביצוע שינוי כלשהו.

מודיעין שיחה: ניתוח סמנטי מבוסס אצוות (Batch Semantic Analytics)

// כיצד אנו מעבדים הקלטות ותמלילי שיחות באצוות אסינכרוניות לחילוץ כוונות מכירה וחיסכון בעלויות

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

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

תור SQS אסינכרוני צובר את האירועים ומפעיל את שירות הניתוח באצוות (Batch Analytics Worker). השירות מעבד מקבצים של עד 25 תמלילים במקביל, ומזין אותם למודל חילוץ נתונים מובנה המוגדר בסכמת Pydantic קשיחה. אסטרטגיה זו מצמצמת את קריאות ה-API ביותר מ-70% ומשיגה חיסכון עצום בעלויות טוקנים לעומת חילוץ בזמן אמת.

מנוע הניתוח מחלץ חמישה ממדים חיוניים: ציון מוטיבציה בין 1 ל-10, סיווג אותות מצוקה (דוגמת עיקולי מס, ירושות או מעבר דירה דחוף), רמת שיפוץ נדרשת בנכס, התנגדויות עיקריות והמלצה אוטומטית לשלב הטיפול ב-CRM. לאחר אימות, נתונים אלו נרשמים ישירות למסד PostgreSQL, מפעילים הודעות SMS אוטומטיות או מתריעים למנהלי רכישות בזמן אמת.

  • ▪אפס שיהוי בשיחה החיה: שרתי הזרמת הקול פועלים באופן בלעדי להעברת מקטעי אודיו בפחות משנייה ללא הרצת מודלים כבדים.
  • ▪חיסכון של 70% בעלויות עיבוד: קיבוץ תמלילים מרובים לקריאת חילוץ מרוכזת מצמצם דרמטית את תקורת הוראות המערכת (System Prompts).
  • ▪אימות נתונים קפדני ב-Pydantic: המידע המופק תואם במדויק את טיפוסי הנתונים הנדרשים לפני שמירה במסד או הפעלת מערכות CRM.
  • ▪ניתוב אוטומטי של עסקאות חמות: פניות בעלות ציון דחיפות גבוה (8 ומעלה) מתריעות מיידית לצוותי הרכישות ב-Slack וב-SMS, בעוד פניות רגילות מנותבות לקמפיינים מתוזמנים.
services/batch_analytics/semantic_analyzer.py
python
from typing import List, Optional
from pydantic import BaseModel, Field

class CallSellerInsights(BaseModel):
    call_sid: str
    motivation_score: int = Field(ge=1, le=10, description="Urgency rating: 1 is passive, 10 is immediate distress")
    distress_category: Optional[str] = Field(None, description="E.g., tax_lien, probate, code_violation, divorce, relocation")
    property_condition: str = Field(description="turnkey, cosmetic_only, heavy_rehab, teardown")
    asking_price: Optional[float] = None
    tax_assessment_delta_pct: Optional[float] = None
    primary_objections: List[str] = Field(default_factory=list)
    crm_action: str = Field(description="escalate_to_buyer, nurture_60_days, dead_lead")

def analyze_call_batch(transcripts: List[dict]) -> List[CallSellerInsights]:
    """
    Executes asynchronous batch semantic analysis on completed call transcripts.
    Separates heavy cognitive evaluation from the sub-second live audio bridge,
    reducing token overhead and eliminating runtime latency.
    """
    sanitized_inputs = [
        {"sid": t["call_sid"], "conversation": t["transcript_text"]}
        for t in transcripts
    ]
    # In production, invokes structured LLM extraction with JSON schema constraints
    # and returns validated CallSellerInsights models ready for database insertion
    return run_structured_llm_extraction(sanitized_inputs, schema=CallSellerInsights)
הסבר תכנוני: עיבוד אצוות של 25 שיחות במקביל חוסך מעל 70% בעלויות טוקנים, מכיוון שהוראות הפרומפט הראשי מוערכות פעם אחת לכל אצווה במקום להישלח מחדש עבור כל שיחה בודדת.

אוטומציית פיתוח, CI/CD ובדיקות אוטומטיות

// אינטגרציה רציפה עם שרתי בדיקה מדומים ובדיקות שיהוי קוליות

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

צינור הפריסה האוטומטי שלנו פועל בסביבת GitHub Actions בחמישה שלבי אימות:

1. בדיקת סגנון קוד ותקינות טיפוסים קפדנית באמצעות Ruff ו-Mypy.

2. בדיקות יחידה מול שירותי ענן מדומים באמצעות חבילת moto.

3. בדיקות אינטגרציה מלאות מול שרת מקומי מדומה (mock_twilio_server.py) הפותח ערוצי תקשורת ומזרים שמע דיגיטלי לבדיקת גשר האודיו.

4. פריסה אוטומטית לסביבת בדיקות באמצעות AWS SAM, כולל שיחת בדיקה ממוחשבת למספר מאומת.

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

.github/workflows/deploy.yaml
yaml
name: Telephony Pipeline CI/CD

on:
  push:
    branches: [main, staging]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
          cache: 'pip'

      - name: Install dependencies
        run: pip install -r requirements-dev.txt

      - name: Run Ruff Linter & Mypy
        run: |
          ruff check .
          mypy core/ services/

      - name: Run Unit & Integration Tests
        env:
          AWS_DEFAULT_REGION: us-east-1
        run: pytest services/ core/ tests/ -v --cov=services

  deploy:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/setup-sam@v2
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1

      - name: SAM Build
        run: sam build --use-container

      - name: SAM Deploy to Staging
        if: github.ref == 'refs/heads/staging'
        run: |
          sam deploy --config-env staging --no-confirm-changeset --no-fail-on-empty-changeset

      - name: SAM Deploy to Production
        if: github.ref == 'refs/heads/main'
        run: |
          sam deploy --config-env production --no-confirm-changeset --no-fail-on-empty-changeset
הסבר תכנוני: הבנייה בתוך מכולה ייעודית (use-container) מבטיחה קימפול תואם לחלוטין עבור ספריות פייתון מהירות הפועלות על גבי מעבדי Graviton בסביבת הייצור.

תובנות מפתח לארכיטקטורת מערכות קול

// עקרונות מעשיים לתכנון מערכות ענן מבוזרות בזמן אמת

בעת תכנון מערכות טלפוניה מבוזרות או עוזרי קול אינטראקטיביים בענן, מומלץ להקפיד על ארבעה עקרונות יסוד:

  • ▪נתקו מיקרו-שירותים באמצעות נתיב ליבה משותף (Core Service Highway): לעולם אל תאפשרו לתבניות CloudFormation להפנות הדדית באמצעות ייצוא משאבים, אחרת השבתת שירות בודד תנעל את המאגר כולו.
  • ▪הקצו לפחות 1769 MB לשרתי עיבוד שמע ב-Lambda: התוספת השולית בעלות זניחה לחלוטין לעומת אובדן לקוחות הנגרם מגמגום שמע בעת ניקוי זיכרון של המעבד.
  • ▪לעולם אל תריצו ניתוח סמנטי כבד על שיחות קוליות חיות: אגרו תמלילים ועבדו אותם באצוות אסינכרוניות כדי לחסוך 70% בעלויות טוקנים ולשמור על שיהוי שיחה מיידי.
  • ▪אכפו מבנה בדיקות מראה מדויק של 1:1: הפרידו לחלוטין מתאמי קלט (Parser) מלוגיקה עסקית (Executor), ושקפו כל קובץ מקור עם קובץ בדיקה מבודד למניעת זליגת מצב בבדיקות.
המשך הקריאה בסדרה // Part 2 of 2

חלק 2: צינורות קליטת לידים, ויסות גיאוגרפי ומנגנון שרידות מדורג

צריכים לתכנן או לייצב מערכת טלפוניה מבוזרת בהיקף גבוה?

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

השלב הבא שלכם

בואו נגדיר מה נכון לבנות.

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

בואו נדבר על הפרויקט שלכם