הקשר המערכת ואתגר ההנדסה המרכזי
// מדוע ארכיטקטורות טלפוניה רגילות קורסות תחת עומסי חיוג מבוססי בינה מלאכותית
מערכות טלפוניה אוטומטיות בהיקפים גבוהים פועלות בסביבת רשת מורכבת ובלתי צפויה. בעת ביצוע אלפי שיחות קוליות מדי שעה, ספקי תקשורת, מרכזיות טלפוניה (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 מהטלפוניה:
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כיול משאבים: המתמטיקה של זיכרון, מעבד ושיהוי
// מדוע הקצאת 1769 MB ב-Lambda היא סוד ההצלחה לקול רציף ללא קטיעות
טעות שכיחה בארכיטקטורות Serverless היא הגדרת הזיכרון למינימום האפשרי (128 MB או 256 MB) מתוך כוונה לחסוך בעלויות. במערכות שמע בזמן אמת ובסביבות עתירות מקביליות, החלטה זו מובילה לפגיעה ביצועית קשה.
ב-AWS Lambda, עוצמת המעבד (CPU) ורוחב הפס של הרשת מוקצים ביחס ישר לכמות הזיכרון. בדיוק ברף של 1769 MB, המערכת מקצה ליבת מעבד מלאה וייעודית (1.0 dedicated vCPU). מתחת לרף זה, הפונקציה מקבלת מקטעי זמן חלקיים של מעבד, מה שגורם להשהיות תקופתיות של עשרות מילי-שניות בעת ניקוי זיכרון או פעולות GIL בפייתון. עבור ממשק REST רגיל השהיה כזו אינה מורגשת; אך בערוץ שמע דיגיטלי חי של 8kHz, השהיה של 40 מילי-שניות נשמעת כגמגום קולי רובוטי צורם.
זוהי טבלת כיול המשאבים המדויקת שנבחרה עבור רכיבי המערכת השונים:
Audio Bridge Worker
מונע האטה של המעבד והשהיות ניקוי זיכרון בזמן עיבוד חוצצי שמע חיים וזיהוי פעילות קולית.
Twilio Webhook Receiver
פענוח בקשות קל-משקל. נדרש להחזיר תשובת 200 תוך פחות מ-300 מילי-שניות כדי למנוע ניסיונות חוזרים מרשת Twilio.
Pacing Metronome Dispatcher
שרת יחיד הפועל בקצב קבוע ומדויק לאכיפת תקנות חיוג ללא סטיות שעון.
State Arbiter & Lock Release
נדרש למאגר חיבורים קבוע למסד PostgreSQL (דרך RDS Proxy) לסגירת טרנזקציות ללא מיצוי חיבורים.
Batch Analytics Worker
מעבד 25 תמלילי שיחות בכל אצווה; זיכרון גבוה יותר מאפשר פענוח JSON מהיר וטיפול בנפחי טוקנים גדולים.
Lead Ingestion & Normalizer
מעבד מקבצים גדולים של נתוני נכסים, מבצע סינון כפילויות ואימות מספרי טלפון על פני 10,000 רשומות.
מקביליות מבוזרת: תבנית הנעילה במסד הנתונים
// כיצד פתרנו את בעיית ההודעות האסינכרוניות באמצעות נעילות PostgreSQL ייעודיות
כאשר מבוצעת שיחה יוצאת, עשויים להגיע במקביל עד 5 אירועים שונים: עדכון סטטוס מהספק ("חיוג"), פתיחת ערוץ השמע של Twilio ("מדיה מוכנה"), ניתוק על ידי הלקוח ותפוגת זמן פנימית. עדכון רגיל במסד בסגנון UPDATE leads SET status = ... גורם לשאילתה שהגיעה אחרונה לדרוס את האמת העסקית.
כדי לפתור זאת, יישמנו אסטרטגיית נעילה כפולה: מסד DynamoDB עם מנגנון מחיקה אוטומטי (TTL) משמש כמחסום מהיר, בעוד נעילות ברמת טרנזקציה במסד PostgreSQL (מסוג Advisory Locks) מבטיחות סדר כרונולוגי ודאי.
זהו קוד השאילתה המרכזי שמריץ שירות ה-State Arbiter לפני כל שינוי מצב:
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מודיעין שיחה: ניתוח סמנטי מבוסס אצוות (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, בעוד פניות רגילות מנותבות לקמפיינים מתוזמנים.
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)אוטומציית פיתוח, CI/CD ובדיקות אוטומטיות
// אינטגרציה רציפה עם שרתי בדיקה מדומים ובדיקות שיהוי קוליות
פריסת עדכונים למערכת טלפוניה חיה דורשת זהירות קפדנית. באג קטן בקוד עלול להוביל לחסימת קווי טלפון או להפרעה בשיחות עם לקוחות בזמן אמת.
צינור הפריסה האוטומטי שלנו פועל בסביבת GitHub Actions בחמישה שלבי אימות:
1. בדיקת סגנון קוד ותקינות טיפוסים קפדנית באמצעות Ruff ו-Mypy.
2. בדיקות יחידה מול שירותי ענן מדומים באמצעות חבילת moto.
3. בדיקות אינטגרציה מלאות מול שרת מקומי מדומה (mock_twilio_server.py) הפותח ערוצי תקשורת ומזרים שמע דיגיטלי לבדיקת גשר האודיו.
4. פריסה אוטומטית לסביבת בדיקות באמצעות AWS SAM, כולל שיחת בדיקה ממוחשבת למספר מאומת.
5. שחרור מבוקר לסביבת הייצור עם ביטול פריסה אוטומטי במקרה של חריגה משגיאות שרת.
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תובנות מפתח לארכיטקטורת מערכות קול
// עקרונות מעשיים לתכנון מערכות ענן מבוזרות בזמן אמת
בעת תכנון מערכות טלפוניה מבוזרות או עוזרי קול אינטראקטיביים בענן, מומלץ להקפיד על ארבעה עקרונות יסוד:
- ▪נתקו מיקרו-שירותים באמצעות נתיב ליבה משותף (Core Service Highway): לעולם אל תאפשרו לתבניות CloudFormation להפנות הדדית באמצעות ייצוא משאבים, אחרת השבתת שירות בודד תנעל את המאגר כולו.
- ▪הקצו לפחות 1769 MB לשרתי עיבוד שמע ב-Lambda: התוספת השולית בעלות זניחה לחלוטין לעומת אובדן לקוחות הנגרם מגמגום שמע בעת ניקוי זיכרון של המעבד.
- ▪לעולם אל תריצו ניתוח סמנטי כבד על שיחות קוליות חיות: אגרו תמלילים ועבדו אותם באצוות אסינכרוניות כדי לחסוך 70% בעלויות טוקנים ולשמור על שיהוי שיחה מיידי.
- ▪אכפו מבנה בדיקות מראה מדויק של 1:1: הפרידו לחלוטין מתאמי קלט (Parser) מלוגיקה עסקית (Executor), ושקפו כל קובץ מקור עם קובץ בדיקה מבודד למניעת זליגת מצב בבדיקות.
חלק 2: צינורות קליטת לידים, ויסות גיאוגרפי ומנגנון שרידות מדורג
צריכים לתכנן או לייצב מערכת טלפוניה מבוזרת בהיקף גבוה?
אנו מתמחים בתכנון ארכיטקטורות ענן עמידות, ביטול שיהוי קולי בסוכני AI ואכיפת סנכרון מצב בזמן אמת בסביבות ענן מורכבות.