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

ב-APC וב-APX, בחרנו בנתיב אחר. קול אינו ערוץ. הוא מצב (mode). הוא יושב מעל ממשק קיים במקום להחליף אותו. הבנת ההבחנה הזו היא מה שמונעת מהמערכת להתפרק.

ההפשטה השגויה

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

כאן מתחיל הכאוס. שינוי קטן בהתנהגות של סוכן מחייב כעת העתקה של השינוי לאורך מספר עצי פרומפטים. אם הצוות שוכח ממשק אחד, החוויה מתפרקת. המשתמשים מקבלים טון אחד בטקסט ואישיות מעט שונה בדיבור. עם הזמן, חוסר העקביות הקטן הזה מצטבר לסטייה של המערכת (system drift). שכבת הקונטקסט הניידת מפסיקה להיות ניידת, כי היא חייבת להתחשב בהגשה קולית בענף אחד ובטקסט שקט בענף אחר. ההפשטה "דולפת" (leaks), והגדרת הפרויקט שהייתה פעם מאוחדת מתפוררת לאוסף של פתרונות קצה (hacks) ספציפיים לכל ערוץ.

הפרדת קונטקסט מזמן ריצה (Runtime)

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

APC מחזיקה את הקונטקסט של הפרויקט. היא מגדירה את הסוכנים, הכללים והכישורים (skills) המרכיבים את הפרויקט. חשבו על זה כעל המשמעות היציבה של המערכת. היא עונה על השאלות המבניות: מה הסוכן הזה יודע? מה מותר לו לעשות? אילו כלים הוא יכול להפעיל? APC צריכה להישאר אגנוסטית לחלוטין לגבי השאלה האם התשובה מוצגת על מסך, נשלחת דרך API של צ'אט או מופעלת דרך רמקול.

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

הפרדה זו פירושה שפרויקט המוגדר ב-APC נשאר שלם ללא קשר למספר הממשקים ש-APX חושפת. החוזה (contract) אינו משתנה. רק שכבת התצוגה משתנה.

איך מצבים (Modes) עובדים בפועל

במימוש שלנו, ממשקים כמו טלגרם, CLI ואפליקציית ווב הם ערוצים. ערוץ אומר לך איפה התרחשה האינטראקציה. קול מתווסף דרך מטא-דאטה של הערוץ כמצב (mode). מצב אומר לך כיצד התגובה צריכה להתנהג.

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

התוצאה היא עץ פרומפטים יחיד לכל ממשק. אין ענף נפרד של voice-desktop. אין וריאנט של whisper-web. המודולטור (modifier) מוחל רק כאשר זמן הריצה מבקש זאת, ורק ברגע האחרון והרלוונטי ביותר. הפרומפט הליבתי נשאר קבוע.

מה אתם מרוויחים

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

עלויות תחזוקה נמוכות יותר. לו הקול היה ערוץ בפני עצמו, לכל ממשק היה צורך בתאום. הייתם צריכים לתחזק ערוץ CLI וערוץ voice-CLI, ערוץ טלגרם וערוץ voice-telegram, וכן הלאה. בכל פעם שתתאימו פרומפט מערכת, תתקנו באג בפורמט או תלטשו תיאור של כישור (skill), תצטרכו להפיץ את השינוי לאורך שני העצים. אם תפספסו אחד, המשתמשים יבחינו בפער. על ידי שימוש במצב (mode), אתם שומרים על עץ פרומפטים יחיד לכל ממשק. הקול הופך לשכבת על מותנית (conditional overlay) במקום לנקודת פיצול בדרך, כך שעומס העבודה שלכם נשאר ליניארי גם כשאתם מוסיפים דרכים חדשות לאינטראקציה.

רישום לוגים מדויק. ערוצים מתעדים היכן התרחשה אינטראקציה. מצבים (Modes) מתעדים כיצד התגובה נמסרה. אינטראקציית שולחן עבודה נשארת אינטראקציית שולחן עבודה, בין אם המשתמש קרא אותה ובין אם שמע אותה. כאשר הצוות שלכם עוקב אחר באג או סוקר אנליטיקה, הם לא צריכים להשוות בין "desktop-voice" ל-"desktop-text" כאילו מדובר במשטחי מוצר שונים. מזהה הערוץ נשאר נקי, ודגל המצב (mode flag) ממוקם בצורה מסודרת לצדו במטא-דאטה. הלוגים שלכם נשארים אמינים, והדיבאגינג נשאר פשוט מכיוון שהמיקום וההתנהגות אינם מעורבבים זה בזה.

הקשר פרויקט נקי. APC מגדיר את החוזה. הוא לא אמור להיות אכפת לו אם התגובה נאמרת בקול, מוצפנת בלחישה, או מוצגת בגופן monospace. אלו הן סוגיות של זמן ריצה (runtime). על ידי שמירת עיצוב הקול בתוך APX, אנו שומרים על הניידות של APC. ניתן לקחת הגדרת פרויקט APC ולהטמיע אותה בסביבת זמן ריצה חדשה לחלוטין, מבלי לגרור איתה הנחות עיצוב ספציפיות לקול או שאריות (cruft) של אופטימיזציית דיבור. הגבול נשמר, ומשמעות הפרויקט נותרת יציבה.

הוכחה בשולחן העבודה

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

השורה התחתונה

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