הדף הזה רלוונטי ל-Apigee ול-Apigee Hybrid.
לעיון במסמכי התיעוד של
Apigee Edge.
Apigee תומכת בסטרימינג רציף של תגובות מנקודות קצה של אירועים שנשלחים מהשרת (SSE) ללקוחות בזמן אמת. התכונה Apigee SSE שימושית לטיפול בממשקי API של מודל שפה גדול (LLM) שפועלים בצורה היעילה ביותר על ידי העברת התשובות שלהם בסטרימינג בחזרה ללקוח. סטרימינג של SSE מפחית את זמן האחזור, והלקוחות יכולים לקבל נתוני תגובה ברגע שהם נוצרים על ידי LLM. התכונה הזו תומכת בשימוש בסוכני AI שפועלים בסביבות בזמן אמת, כמו בוטים של שירות לקוחות או מתזמני תהליכי עבודה.
כדי להשתמש ב-SSE עם Apigee, פשוט מפנים proxy ל-API ליעד או לנקודת קצה של proxy שתומכים ב-SSE. כדי לשלוט בצורה מדויקת יותר בתגובת ה-SSE, Apigee מספקת תהליך מיוחד של נקודת קצה שנקרא EventFlow. בהקשר של EventFlow, אתם יכולים להוסיף קבוצה מוגבלת של כללי מדיניות כדי לבצע פעולות בתגובת ה-SSE, כמו סינון, שינוי או טיפול בשגיאות. מידע נוסף על תהליכים של שרתי proxy זמין במאמר שליטה בשרתי proxy ל-API באמצעות תהליכים.
יצירת שרת proxy ל-API בשביל SSE
בממשק המשתמש של Apigee יש תבנית ליצירת שרת proxy חדש שכולל EventFlow.
כדי ליצור שרת proxy ל-API עם התבנית EventFlow באמצעות ממשק המשתמש של Apigee:
במסוף Google Cloud , נכנסים לדף Apigee > Proxy Development > proxy ל-API.
- בחלונית proxy ל-API, לוחצים על + Create.
- בחלונית Create a proxy, בקטע Proxy template, בוחרים באפשרות Proxy with Server-Sent Events (SSE).
- בקטע פרטי שרת ה-proxy, מזינים את הפרטים הבאים:
- שם שרת ה-proxy: מזינים שם לשרת ה-proxy, למשל
myproxy. - Base Path: מוגדר אוטומטית לערך שמזינים בשדה Proxy name. נתיב הבסיס הוא חלק מכתובת ה-URL שמשמשת לשליחת בקשות ל-API. Apigee משתמשת בכתובת ה-URL כדי להתאים ולנתב בקשות נכנסות לשרת ה-proxy המתאים ל-API.
- Description (Optional): מזינים תיאור ל-proxy החדש ל-API, למשל "Testing Apigee with a simple proxy".
- Target (Existing API): מזינים את כתובת ה-URL של היעד של ה-SSE בשביל ה-proxy ל-API. לדוגמה:
https://mocktarget.apigee.net/sse-events/5 - לוחצים על הבא.
- שם שרת ה-proxy: מזינים שם לשרת ה-proxy, למשל
- פריסה (אופציונלי):
- סביבות פריסה: אופציונלי. מסמנים את התיבות כדי לבחור סביבה אחת או יותר לפריסת שרת ה-proxy. אם אתם מעדיפים לא לפרוס את שרת ה-proxy בשלב הזה, השאירו את השדה Deployment environments ריק. תמיד אפשר לפרוס את שרת ה-proxy מאוחר יותר.
- חשבון שירות: אופציונלי. חשבון שירות לשרת ה-proxy. חשבון השירות מייצג את הזהות של שרת ה-proxy שנפרס, וקובע אילו הרשאות יש לו. זו תכונה מתקדמת, ואפשר להתעלם ממנה לצורך המדריך הזה.
שרתי proxy ל-API שנפרסו עם הגדרת
EventFlowיחויבו כ-Extensible. - לוחצים על יצירה.
אפשר גם לקרוא את המאמר יצירת proxy ל-API פשוט.
הגדרת EventFlow
כדי לשלוט בצורה מדויקת יותר בתגובת ה-SSE, Apigee מספקת תהליך מיוחד של נקודת קצה שנקרא EventFlow. בהקשר של EventFlow, אתם יכולים להוסיף קבוצה מוגבלת של כללי מדיניות, שמפורטים בהמשך, כדי לשנות את התגובה של SSE לפני שהיא מועברת בסטרימינג בחזרה ללקוח. למידע נוסף על תהליכי proxy, קראו את המאמר שליטה בשרתי proxy ל-API באמצעות תהליכים.
מיקום של EventFlow
ל-EventFlow יש שני מאפיינים:
-
name: שם לזיהוי התהליך. -
content-type: הערך של המאפיין הזה צריך להיותtext/event-stream.
אפשר לעיין גם בחומר עזר בנושא הגדרת תהליכים.
אפשר למקם EventFlow בתוך הגדרה של TargetEndpoint או ProxyEndpoint, כמו בדוגמאות הקוד הבאות:
<ProxyEndpoint>
<ProxyEndpoint name="default">
<Description/>
<FaultRules/>
<PreFlow name="PreFlow">
<Request/>
<Response/>
</PreFlow>
<PostFlow name="PostFlow">
<Request/>
<Response/>
</PostFlow>
<Flows/>
<EventFlow name="EventFlow" content-type="text/event-stream">
<Response/>
</EventFlow>
<HTTPProxyConnection>
<Properties/>
<URL>https://httpbin.org/sse</URL>
</HTTPProxyConnection>
</ProxyEndpoint><TargetEndpoint>
<TargetEndpoint name="default">
<Description/>
<FaultRules/>
<PreFlow name="PreFlow">
<Request/>
<Response/>
</PreFlow>
<PostFlow name="PostFlow">
<Request/>
<Response/>
</PostFlow>
<Flows/>
<EventFlow name="EventFlow" content-type="text/event-stream">
<Response/>
</EventFlow>
<HTTPTargetConnection>
<Properties/>
<URL>https://httpbin.org/sse</URL>
</HTTPTargetConnection>
</TargetEndpoint>חשוב גם לציין שלמרות שאפשר להוסיף EventFlow ל-TargetEndpoint, ל-ProxyEndpoint או לשניהם, רק EventFlow אחד מופעל.
בטבלה הבאה מוצג הביצוע של בתי EventFlow על סמך מיקום נקודת הקצה:
| ProxyEndpoint | TargetEndpoint | שימוש ב-EventFlow |
|---|---|---|
EventFlow ב-ProxyEndpoint |
EventFlow ב-TargetEndpoint |
EventFlow ב-TargetEndpoint |
לא EventFlow |
EventFlow ב-TargetEndpoint |
EventFlow ב-TargetEndpoint |
EventFlow ב-ProxyEndpoint |
לא EventFlow |
EventFlow ב-ProxyEndpoint |
הוספת כללי מדיניות ל-EventFlow
אפשר להוסיף עד ארבעה כללי מדיניות לרכיב Response של EventFlow. כמו בכל התהליכים, כללי המדיניות מופעלים לפי הסדר שבו הם נוספו, ואפשר להוסיף שלבים מותנים כדי לשלוט בהפעלה שלהם.
חשוב לציין שסוגי המדיניות שאפשר להוסיף ל-EventFlow מוגבלים לסוגים הבאים.
אסור להשתמש בסוגים אחרים של כללי מדיניות ב-EventFlow:
אפשר גם לעיין במאמרים צירוף והגדרה של כללי מדיניות בממשק המשתמש וצירוף והגדרה של כללי מדיניות בקובצי XML.
בדוגמאות הבאות מוצג EventFlow עם שלב מדיניות RaiseFault מותנה שנוסף:
<ProxyEndpoint>
<ProxyEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>Raise-Fault-Cred-Invalid</Name> <Condition>fault.name equals "invalid_access_token"</Condition> </Step> </Response> </EventFlow> <HTTPProxyConnection> </ProxyEndpoint></pre>
<TargetEndpoint>
<TargetEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>Raise-Fault-Cred-Invalid</Name> <Condition>fault.name equals "invalid_access_token"</Condition> </Step> </Response> </EventFlow> <HTTPTargetConnection> </TargetEndpoint></pre>
דוגמאות נוספות לקוד ב-EventFlow מופיעות בקטע תרחישים לדוגמה ודוגמאות ל-EventFlow.
משתני זרימה
EventFlow מאכלס שלושה משתני זרימה של תגובה. שימו לב שאפשר להשתמש במשתנים האלה רק במסגרת האירוע הנוכחי שעובר עיבוד ב-EventFlow.
גישה למשתנים האלה או הגדרה שלהם מחוץ להיקף של EventFlow לא משפיעה. הם רלוונטיים רק בהקשר של EventFlow.
-
response.event.current.content: מחרוזת שמכילה את כל התגובה של האירוע הנוכחי. Apigee לא מנתח את המחרוזת בשום צורה. הוא מכיל את כל התשובה ללא שינוי, כולל כל שדות הנתונים. -
response.event.current.data: מחרוזת שמכילה את המטען הייעודי (payload) של הנתונים באירוע הנוכחי. אפשר לשנות את המשתנה הזה ב-EventFlowכדי לשנות את המטען הייעודי (payload) של הנתונים שנשלח ללקוח. response.event.current.count: ספירה מצטברת של מספר אירועי התגובה שנשלחו. הערך הזה מתעדכן בכל אירוע שמתקבל. הספירה תהיה 1 לאירוע הראשון, והיא תגדל לאירועים הבאים.
אפשר לקרוא גם על הפניה למשתנה זרימה.
תרחישים לדוגמה ודוגמאות לשימוש ב-EventFlow
הדוגמאות הבאות מראות איך להטמיע תרחישים נפוצים לשימוש בשרתי פרוקסי של SSE:
- שינוי של תגובת SSE
- סינון תגובת SSE
- שליחת אירוע SSE למערכת חיצונית
- שימוש במדיניות של Apigee Model Armor ב-EventFlow
- טיפול בשגיאות ב-EventFlow
- הפצת הודעות שגיאה ב-EventFlow
- שימוש ב-DataCapture כדי לאסוף ספירות של טוקנים ב-Analytics
- שימוש במדיניות LLMTokenQuota כדי לאכוף מכסות טוקנים ב-EventFlow
שינוי תשובה של SSE
בדוגמה הזו מוסבר איך להסיר נתונים מתגובת SSE EventFlow לפני שהיא מוחזרת ללקוח.
התוכן של תגובת ה-SSE מאוחסן במשתנה זרימה שנקרא response.event.current.content.
במקרה הזה, אנחנו משתמשים במדיניות JavaScript כדי לאחזר את הערך של משתנה הזרימה, לנתח אותו ולשנות אותו. אפשר לעיין גם במאמר משתני זרימה.
- יוצרים שרת proxy חדש באמצעות התבנית של שרת ה-proxy ל-SSE. מידע נוסף זמין במאמר יצירת שרת proxy ל-API עם אירועים שנשלחים מהשרת (SSE).
- פותחים את שרת ה-proxy בכלי לעריכת שרתי proxy של Apigee ולוחצים על הכרטיסייה Develop.
- יוצרים מדיניות JavaScript חדשה עם ההגדרה הבאה. בדוגמה הזו, קוד ה-JavaScript נכלל ישירות במדיניות.
אפשרות נוספת להגדרת המדיניות היא להכניס את קוד ה-JavaScript לקובץ משאבים.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Javascript continueOnError="false" enabled="true" timeLimit="200" name="js-update-resp"> <DisplayName>js-update-resp</DisplayName> <Properties/> <Source> var event = JSON.parse(context.getVariable("response.event.current.content")); event.modelVersion = null; context.setVariable("response.event.current.content",JSON.stringify(event)); </Source> </Javascript>
- מוסיפים את מדיניות ה-JavaScript ל-
EventFlowשל שרת ה-proxy. ה-EventFlowמצורף ל-TargetEndpointאו ל-ProxyEndpointשמוגדרים כברירת מחדל. בדוגמה הזו, התוכן נוצר באמצעות Gemini API ב-Vertex AI.<ProxyEndpoint>
<ProxyEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>js-update-resp</Name> </Step> </Response> </EventFlow> <HTTPProxyConnection> <URL>https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?key=GEMINI_API_KEY&alt=sse</URL> </HTTPProxyConnection> </ProxyEndpoint><TargetEndpoint>
<TargetEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>js-update-resp</Name> </Step> </Response> </EventFlow> <HTTPTargetConnection> <URL>https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?key=GEMINI_API_KEY&alt=sse</URL> </HTTPTargetConnection> </TargetEndpoint> - שומרים את שרת ה-proxy ופורסים אותו.
- שולחים קריאה לשרת ה-proxy שנפרס:
curl -X POST -H 'Content-Type: application/json' \ "https://YOUR_APIGEE_ENVIRONMENT_GROUP_HOSTNAME/YOUR_API_PATH" \ -d '{ "contents":[{"parts":[{"text": "Write a story about a magic pen."}]}]}'הצגת דוגמה לתשובה
זוהי דוגמה לתשובה בלי סינון. שימו לב שהתשובה כוללת מאפיין
modelVersion": "gemini-2.5-flash".data: { "candidates": [ { "content": { "parts": [ { "text": "ara found the pen tucked away in a dusty antique shop, nestled amongst chipped tea" } ], "role": "model" } } ], "usageMetadata": { "promptTokenCount": 8, "totalTokenCount": 8 }, "modelVersion": "gemini-2.5-flash" }זוהי תגובה לדוגמה נוספת עם מדיניות JavaScript שהוחלה. המאפיין
modelVersionהוסר.data: { "candidates": [ { "content": { "parts": [ { "text": " the fantastical creatures of her imagination. The quiet beauty of a simple life was a magic all its own.\n" } ], "role": "model" }, "finishReason": "STOP" } ], "usageMetadata": { "promptTokenCount": 8, "candidatesTokenCount": 601, "totalTokenCount": 609, "promptTokensDetails": [ { "modality": "TEXT", "tokenCount": 8 } ], "candidatesTokensDetails": [ { "modality": "TEXT", "tokenCount": 601 } ] } }
סינון של תגובת SSE
בדוגמה הזו אפשר לראות איך לסנן נתונים מתגובת SSE לפני שהם מוחזרים ללקוח. במקרה הזה, אנחנו מסננים את נתוני האירועים מהתגובה באמצעות מדיניות JavaScript. המדיניות מנתחת את התגובה לאירוע וממירה אותה ל-JSON, משנה את ה-JSON כדי להסיר את נתוני האירוע, ואז שולחת את נתוני התגובה ששונו בחזרה ללקוח.
כמו בדוגמה הקודמת, בדוגמה הזו מאחזרים את הערך של משתנה הזרימה response.event.current.content ומנתחים אותו ל-JSON, ואז מיישמים לוגיקה כדי להטמיע את הסינון הרצוי.
- יוצרים שרת proxy חדש באמצעות התבנית של שרת ה-proxy ל-SSE. מידע נוסף זמין במאמר יצירת שרת proxy ל-API עם אירועים שנשלחים מהשרת (SSE).
- פותחים את שרת ה-proxy בכלי לעריכת שרתי proxy של Apigee ולוחצים על הכרטיסייה Develop.
- יוצרים מדיניות JavaScript חדשה עם ההגדרה הבאה. בדוגמה הזו, קוד ה-JavaScript נכלל ישירות במדיניות.
אפשרות נוספת להגדרת המדיניות היא להכניס את קוד ה-JavaScript לקובץ משאבים.
<Javascript continueOnError="false" enabled="true" timeLimit="200" name="js-filter-resp"> <DisplayName>js-filter-resp</DisplayName> <Properties/> <Source> var event = JSON.parse(context.getVariable("response.event.current.content")); if("error" in event){ // Do not send event to customer context.setVariable("response.event.current.content", ""); } </Source> </Javascript>
- מוסיפים את מדיניות ה-JavaScript ל-
EventFlowשל שרת ה-proxy. ה-EventFlowמצורף ל-TargetEndpointאו ל-ProxyEndpointשמוגדרים כברירת מחדל. בדוגמה הזו נעשה שימוש ב-Gemini API ב-Vertex AI כדי ליצור תוכן.<ProxyEndpoint>
<ProxyEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>js-filter-resp</Name> </Step> </Response> </EventFlow> <HTTPProxyConnection> <URL>https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?key=GEMINI_API_KEY&alt=sse </URL> </HTTPProxyConnection> </ProxyEndpoint><TargetEndpoint>
<TargetEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>js-filter-resp</Name> </Step> </Response> </EventFlow> <HTTPTargetConnection> <URL>https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?key=GEMINI_API_KEY&alt=sse </URL> </HTTPTargetConnection> </TargetEndpoint> - שומרים את שרת ה-proxy ופורסים אותו.
- שולחים קריאה לשרת ה-proxy שנפרס:
curl -X POST -H 'Content-Type: application/json' \ "https://YOUR_APIGEE_ENVIRONMENT_GROUP_HOSTNAME/YOUR_API_PATH" \ -d '{ "contents":[{"parts":[{"text": "Write a story about a magic pen."}]}]}'הצגת דוגמה לתשובה
ככה נראית דוגמה לתגובה בלי סינון. שימו לב שהיא כוללת נתוני שגיאה:
data: { "candidates": [ { "content": { "parts": [ { "text": "El" } ], "role": "model" } } ], "usageMetadata": { "promptTokenCount": 8, "totalTokenCount": 8 }, "modelVersion": "gemini-2.5-flash" } data: { "error": "Service temporarily unavailable. We are experiencing high traffic.", "modelVersion": "gemini-2.5-flash" }הנה עוד דוגמה לתגובה אחרי שהופעל סינון והודעת השגיאה הוסרה.
data: { "candidates": [ { "content": { "parts": [ { "text": "El" } ], "role": "model" } } ], "usageMetadata": { "promptTokenCount": 8, "totalTokenCount": 8 }, "modelVersion": "gemini-2.5-flash" } data: { "candidates": [ { "content": { "parts": [ { "text": "ara found the pen tucked away in a dusty antique shop, nestled amongst chipped tea" } ], "role": "model" } } ], "usageMetadata": { "promptTokenCount": 8, "totalTokenCount": 8 }, "modelVersion": "gemini-2.5-flash" }
שליחת אירוע SSE למערכת חיצונית
בדוגמה הזו, אנחנו מצרפים את מדיניות PublishMessage של Apigee אל EventFlow כדי לשלוח אירוע SSE אל נושא Pub/Sub.
- יוצרים שרת proxy חדש באמצעות התבנית של שרת ה-proxy ל-SSE. מידע נוסף זמין במאמר יצירת שרת proxy ל-API עם אירועים שנשלחים מהשרת (SSE).
- פותחים את שרת ה-proxy בכלי לעריכת שרתי proxy של Apigee ולוחצים על הכרטיסייה Develop.
- יוצרים מדיניות PublishMessage חדשה עם ההגדרה הבאה:
<PublishMessage continueOnError="false" enabled="true" name="PM-record-event"> <DisplayName>PM-record-event</DisplayName> <Source>{response.event.current.content}</Source> <CloudPubSub> <Topic>projects/<customer_project>/topics/<topic_name></Topic> </CloudPubSub> </PublishMessage> - מוסיפים את המדיניות PublishMessage כשלב ב-
EventFlowשל ה-proxy ל-API.<ProxyEndpoint>
<ProxyEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>PM-record-event</Name> </Step> </Response> </EventFlow> <HTTPProxyConnection> </ProxyEndpoint>
<TargetEndpoint>
<TargetEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>PM-record-event</Name> </Step> </Response> </EventFlow> <HTTPTargetConnection> </TargetEndpoint>
- פורסים ובודקים את ה-proxy ל-API.
- אחרי שמוסיפים את התוכן שנוצר לנושא Pub/Sub, אפשר, למשל, ליצור פונקציית Cloud Run כדי לעבד הודעות מהנושא.
שימוש במדיניות של Apigee Model Armor ב-EventFlow
אתם יכולים להשתמש במדיניות SanitizeModelResponse כדי להסיר תוכן זדוני או רגיש מאירועים שנשלחו מהשרת ב-EventFlow. מגדירים את <ContinuousScan> לערך true כדי לבדוק את כל הסטרימינג, כמו בשלבים הבאים, או משאירים את הערך false (ברירת המחדל) כדי לבדוק כל אירוע בנפרד. במצב true, המדיניות מעכבת כל אירוע עד שההגנה המוגברת על המודל מאשרת שהטקסט שלו נקי, ואז משחררת אותו בשלמותו, ללא שינוי, ובסדר הנכון לשלבים הבאים וללקוח.
מידע נוסף על האופן שבו המדיניות מטפלת בהתאמות, בשגיאות ובמכסות זמין במאמר הסרת תוכן זדוני או רגיש מתגובות של אירועים שנשלחו מהשרת (SSE) בסטרימינג. למידע נוסף על Model Armor, קראו את הסקירה הכללית על Model Armor.
כדי להגדיר את המדיניות:
- יוצרים שרת proxy חדש באמצעות התבנית של שרת ה-proxy ל-SSE. מידע נוסף זמין במאמר יצירת שרת proxy ל-API עם אירועים שנשלחים מהשרת (SSE).
- פותחים את שרת ה-proxy בכלי לעריכת שרתי proxy של Apigee ולוחצים על הכרטיסייה Develop.
- יוצרים מדיניות SanitizeModelResponse עם
<ContinuousScan>true</ContinuousScan>ו-<LLMResponseSource>שמוגדרים לחלץ את השינוי בטקסט מ-response.event.current.data. הדוגמה הבאה היא לסטרימינג של Gemini SSE:<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <SanitizeModelResponse async="false" continueOnError="false" enabled="true" name="SMR-modelresponse"> <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> <DisplayName>SMR-modelresponse</DisplayName> <ModelArmor> <TemplateName>projects/{project}/locations/{location}/templates/{template-name}</TemplateName> </ModelArmor> <LLMResponseSource>{jsonPath('$.candidates[-1].content.parts[-1].text',response.event.current.data,true)}</LLMResponseSource> <ContinuousScan>true</ContinuousScan> </SanitizeModelResponse>
בסטרימינג של SSE שתואם ל-OpenAI, מגדירים את
<LLMResponseSource>לערך{jsonPath('$.choices[-1].delta.content',response.event.current.data,true)}. בזרמי SSE של Anthropic Claude, מגדירים את<LLMResponseSource>לערך{jsonPath('$.delta.text',response.event.current.data,true)}. - מצרפים את המדיניות
SanitizeModelResponseלרכיב<Response>שלEventFlowבשרת ה-proxy. אם משתמשים גם ב-LLMTokenQuotaאו ב-DataCaptureב-EventFlow, צריך להציב אתSanitizeModelResponseקודם כדי שהמדיניות הזו תקבל רק אירועים שנבדקו:<EventFlow name="EventFlow" content-type="text/event-stream"> <Request/> <Response> <Step> <Name>SMR-modelresponse</Name> </Step> </Response> </EventFlow>
- פורסים ובודקים את ה-proxy ל-API.
טיפול בשגיאות ב-EventFlow
כברירת מחדל, זרם האירועים מסתיים כשמתרחשת תקלה. עם זאת, אם אתם רוצים לבצע ניפוי באגים נוסף, אתם יכולים לשלוח מידע על התקלה ל-Cloud Logging, כמו שמוצג בדוגמה הזו.
- יוצרים שרת proxy חדש באמצעות התבנית של שרת ה-proxy ל-SSE. מידע נוסף זמין במאמר יצירת שרת proxy ל-API עם אירועים שנשלחים מהשרת (SSE).
- פותחים את שרת ה-proxy בכלי לעריכת שרתי proxy של Apigee ולוחצים על הכרטיסייה Develop.
- יוצרים מדיניות RaiseFault חדשה עם ההגדרה הבאה:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <RaiseFault continueOnError="false" enabled="true" name="RF-Empty-Event"> <DisplayName>RF-Empty-Event</DisplayName> <Properties/> <FaultResponse> <AssignVariable> <Name>faultReason</Name> <Value>empty-event</Value> </AssignVariable> </FaultResponse> <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables> </RaiseFault> - מצרפים את מדיניות RaiseFault ל-
EventFlowשל שרת ה-proxy של SSE:<EventFlow content-type="text/event-stream"> <Response> <Step> <Name>RF-Empty-Event</Name> <Condition>response.event.current.content ~ "data: "</Condition> </Step> </Response> </EventFlow>
- יוצרים מדיניות MessageLogging כדי לתעד שגיאות ביומן. לדוגמה:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <MessageLogging continueOnError="false" enabled="true" name="ML-log-error"> <DisplayName>ML-log-error</DisplayName> <CloudLogging> <LogName>projects/{organization.name}/logs/apigee_errors</LogName> <Message contentType="text/plain">Request failed due to {faultReason}.</Message> <ResourceType>api</ResourceType> </CloudLogging> <logLevel>ALERT</logLevel> </MessageLogging> - מוסיפים את המדיניות MessageLogging ל-FaultRules של נקודת הקצה של היעד או של שרת ה-proxy:
<TargetEndpoint>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <TargetEndpoint name="TargetEndpoint-1"> <Description/> <FaultRules> <FaultRule name="default-fault"> <Step> <Name>ML-log-error</Name> </Step> </FaultRule> </FaultRules> ... </TargetEndpoint><ProxyEndpoint>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ProxyEndpoint name="ProxyEndpoint-1"> <Description/> <FaultRules> <FaultRule name="default-fault"> <Step> <Name>ML-log-error</Name> </Step> </FaultRule> </FaultRules> ... </ProxyEndpoint> - פורסים ובודקים את ה-proxy ל-API.
הפצת שגיאות ב-EventFlow
בדוגמה הזו אנחנו מראים איך להשתמש ב-EventFlow כדי להפיץ שגיאות ללקוח.
התהליך פועל כדי להודיע ללקוח על שגיאות באופן מיידי במהלך ביצוע המדיניות.
- יוצרים שרת proxy חדש באמצעות התבנית של שרת ה-proxy ל-SSE. מידע נוסף זמין במאמר יצירת שרת proxy ל-API עם אירועים שנשלחים מהשרת (SSE).
- פותחים את שרת ה-proxy בכלי לעריכת שרתי proxy של Apigee ולוחצים על הכרטיסייה Develop.
- יוצרים מדיניות JavaScript חדשה עם ההגדרה הבאה:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Javascript continueOnError="false" enabled="true" timeLimit="200" name="js-error"> <DisplayName>js-error</DisplayName> <Properties/> <Source> if(context.getVariable("response.event.current.count")=="2") { throw new Error("Internal Error"); } context.setVariable("response.event.current.content", context.getVariable("response.event.current.content")); </Source> </Javascript>המדיניות הזו נועדה להציג שגיאה כשמתקיים תנאי ספציפי.
- מצרפים את מדיניות ה-JavaScript ל-
EventFlowשל שרת ה-proxy של SSE בתוך ההגדרות שלTargetEndpointאוProxyEndpoint. השלב הזה מבטיח ש-EventFlow יעבד את המדיניות במהלך הטיפול בתגובה:<TargetEndpoint>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <TargetEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>js-error</Name> </Step> </Response> </EventFlow> <HTTPTargetConnection> <URL>https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent</URL> </HTTPTargetConnection> </TargetEndpoint>
<ProxyEndpoint>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ProxyEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>js-error</Name> </Step> </Response> </EventFlow> <HTTPProxyConnection> <URL>https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent</URL> </HTTPProxyConnection> </ProxyEndpoint>
- פורסים את ה-proxy ל-API.
- כדי לבדוק את ההתנהגות של שרת ה-proxy, משתמשים בפקודה
curl:curl -X POST -H 'Content-Type: application/json' "https://ENVIRONMENT_GROUP_NAME/llm-api" -d '{ "contents":[{"parts":[{"text": "Write a story about a magic pen."}]}]}'
מחליפים את ENVIRONMENT_GROUP_NAME בשם של קבוצת הסביבות.
הפלט אמור להיראות כך:
data: {"candidates": [{"content": {"parts": [{"text": "El"}],"role": "model"}}],"usageMetadata": {"promptTokenCount": 8,"totalTokenCount": 8},"modelVersion": "gemini-2.5-flash"} data: {"fault":{"faultstring":"Execution of JS-error failed with error: Exception thrown from JavaScript : Error: Internal Error (Resource_1_js#2)","detail":{"errorcode":"steps.javascript.ScriptExecutionFailed"}}}בפלט מוצג זרם הנתונים הראשוני ואחריו הודעת
fault. אם מתרחשת שגיאה, Apigee מתעדת את פרטי התקלה ושולחת אותם ללקוח כאירוע.
מידע נוסף על טיפול בשגיאות ב-Apigee זמין במאמר טיפול בשגיאות.
שימוש ב-DataCapture כדי לאסוף ספירות של טוקנים בניתוח הנתונים
בדוגמה הזו מוסבר איך להשתמש במדיניות DataCapture בתוך EventFlow כדי לאסוף ספירות של טוקנים מאירועי SSE לשימוש בניתוח הנתונים של Apigee.
- ליצור אוספי נתונים לספירת אסימונים. מריצים את הפקודות הבאות כדי ליצור את אוספי הנתונים הנדרשים בארגון:
curl -X POST "https://apigee.googleapis.com/v1/organizations/ORG_NAME/datacollectors" \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: application/json" \ -d '{ "name": "dc_tokenCount", "description": "Collects token count", "type": "INTEGER" }'
curl -X POST "https://apigee.googleapis.com/v1/organizations/ORG_NAME/datacollectors" \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: application/json" \ -d '{ "name": "dc_thoughtsTokenCount", "description": "Collects thought token count", "type": "INTEGER" }'
- יוצרים שרת proxy חדש באמצעות התבנית של שרת ה-proxy ל-SSE. מידע נוסף זמין במאמר יצירת שרת proxy ל-API עם אירועים שנשלחים מהשרת (SSE).
- פותחים את שרת ה-proxy בכלי לעריכת שרתי proxy של Apigee ולוחצים על הכרטיסייה Develop.
- יוצרים מדיניות JavaScript חדשה כדי לנתח את ספירת הטוקנים מנתוני האירוע של ה-SSE. בעורך שרתי ה-proxy של Apigee, לוחצים על + לצד Policies, בוחרים באפשרות JavaScript כסוג המדיניות ומזינים שם למדיניות (לדוגמה,
JS-parse-token). קובץ ה-XML של המדיניות שנוצר אמור להיראות כך:<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Javascript continueOnError="false" enabled="true" timeLimit="200" name="JS-parse-token"> <DisplayName>JS-parse-token</DisplayName> <Properties/> <Source> const event=context.getVariable('response.event.current.content') try { const jsonString = event.replace(/^data:\s*/, '').trim(); const parsed = JSON.parse(jsonString); const usage = parsed.usageMetadata || {}; context.setVariable("thoughtsToken", usage.thoughtsTokenCount); context.setVariable("totalToken", usage.totalTokenCount); } catch (e) { context.setVariable("js_error_occurred", true); } </Source> </Javascript>
- יוצרים מדיניות DataCapture חדשה כדי לתעד את מספר הטוקנים. בעורך שרתי ה-proxy של Apigee, לוחצים על + לצד Policies, בוחרים ב-DataCapture כסוג המדיניות ומזינים שם למדיניות (לדוגמה,
DC-capture-tokencount). קובץ ה-XML של המדיניות שנוצר אמור להיראות כך:<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <DataCapture name="DC-capture-tokencount" continueOnError="false" enabled="true"> <DisplayName>DC-capture-tokencount</DisplayName> <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables> <Capture> <Collect ref="thoughtsToken" default="-1"/> <DataCollector>dc_thoughtsTokenCount</DataCollector> </Capture> <Capture> <Collect ref="totalToken" default="-1"/> <DataCollector>dc_tokenCount</DataCollector> </Capture> </DataCapture> - מצרפים קודם את מדיניות ה-JavaScript ואז את מדיניות DataCapture, בתוך
EventFlowשל שרת ה-proxy של SSE בהגדרות שלTargetEndpointאוProxyEndpoint. השלב הזה מבטיח ש-EventFlowיעבד את כללי המדיניות במהלך הטיפול בתגובה. קובץ ה-XML שנוצר אמור להיראות כך:<TargetEndpoint>
<TargetEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>JS-parse-token</Name> </Step> <Step> <Name>DC-capture-tokencount</Name> </Step> </Response> </EventFlow> <HTTPTargetConnection> <URL>https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?key=GEMINI_API_KEY&alt=sse</URL> </HTTPTargetConnection> </TargetEndpoint>
<ProxyEndpoint>
<ProxyEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>JS-parse-token</Name> </Step> <Step> <Name>DC-capture-tokencount</Name> </Step> </Response> </EventFlow> <HTTPProxyConnection> <URL>https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?key=GEMINI_API_KEY&alt=sse</URL> </HTTPProxyConnection> </ProxyEndpoint>
- שומרים ופורסים את שרת ה-proxy. מידע נוסף מופיע במאמר פריסת שרתי proxy ל-API.
- שולחים בקשות בדיקה לשרת ה-proxy. אחרי ששרת ה-proxy מעבד את התגובות של ה-SSE, מספר האסימונים שנלכדו זמין בניתוח הנתונים של Apigee דרך אוספי הנתונים
dc_tokenCountו-dc_thoughtsTokenCount.
שימוש במדיניות LLMTokenQuota כדי לאכוף מכסות של אסימונים ב-EventFlow
בדוגמה הזו מוסבר איך להשתמש במדיניות LLMTokenQuota בתוך EventFlow כדי לספור ולאכוף מכסות של אסימונים בסטרימינג של SSE. במהלך העיבוד של זרם האירועים, ספירת הטוקנים מתבצעת רק כשהמטא-נתונים של השימוש בטוקנים מהתגובה של ה-LLM נמצאים באירוע. כשהמטא-נתונים של השימוש בטוקן מתגלים, הם נשלפים והמדיניות מופעלת.
בכל שאר האירועים, המדיניות לא מבצעת שום פעולה.
- יוצרים שרת proxy חדש באמצעות התבנית של שרת ה-proxy ל-SSE. מידע נוסף זמין במאמר יצירת שרת proxy ל-API עם אירועים שנשלחים מהשרת (SSE).
- פותחים את שרת ה-proxy בכלי לעריכת שרתי proxy של Apigee ולוחצים על הכרטיסייה Develop.
- יוצרים מדיניות LLMTokenQuota חדשה כדי לספור את האסימונים שנצרכו על ידי זרם ה-SSE. בעורך שרתי ה-proxy של Apigee, לוחצים על + ליד Policies, בוחרים באפשרות LLMTokenQuota כסוג המדיניות ומזינים שם למדיניות (לדוגמה,
LTQ-Count-Only). קובץ ה-XML של המדיניות שנוצר אמור להיראות כך:<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <LLMTokenQuota name="LTQ-Count-Only" type="rollingwindow"> <SharedName>common-counter</SharedName> <CountOnly>true</CountOnly> <Allow count="15000"/> <Interval>30</Interval> <TimeUnit>minute</TimeUnit> <Distributed>true</Distributed> <LLMTokenUsageSource>{jsonPath('$.usageMetadata.candidatesTokenCount',response.event.current.data,false)}</LLMTokenUsageSource> <LLMModelSource>{jsonPath('$.modelVersion',response.event.current.data,false)}</LLMModelSource> </LLMTokenQuota>
- יוצרים מדיניות LLMTokenQuota שנייה כדי לאכוף את מכסת הטוקנים על בקשות נכנסות. בעורך שרתי ה-proxy של Apigee, לוחצים על + לצד Policies, בוחרים באפשרות LLMTokenQuota כסוג המדיניות ומזינים שם למדיניות (לדוגמה,
LTQ-Enforce-Only). המדיניות הזו משתמשת באותו<SharedName>כמו מדיניות הספירה, כך ששתי כללי המדיניות חולקים את אותו מונה מכסות. קובץ ה-XML של המדיניות שנוצר אמור להיראות כך:<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <LLMTokenQuota name="LTQ-Enforce-Only" type="rollingwindow"> <SharedName>common-counter</SharedName> <EnforceOnly>true</EnforceOnly> <Allow count="15000"/> <Interval>30</Interval> <TimeUnit>minute</TimeUnit> <Distributed>true</Distributed> </LLMTokenQuota>
- מוסיפים את המדיניות
LTQ-Enforce-Onlyכשלב ב-Requestשל ה-PreFlowשל ה-ProxyEndpoint. השלב הזה מבטיח שהמכסה תיבדק בכל בקשה נכנסת. קובץ ה-XML שנוצר אמור להיראות כך:<ProxyEndpoint name="default"> <PreFlow name="PreFlow"> <Request> <Step> <Name>LTQ-Enforce-Only</Name> </Step> </Request> <Response/> </PreFlow> </ProxyEndpoint> - מוסיפים את המדיניות
LTQ-Count-Onlyכשלב בתוךEventFlowשל שרת ה-proxy של SSE, בהגדרות שלTargetEndpointאוProxyEndpoint. השלב הזה מבטיח ש-EventFlowיעבד את המדיניות במהלך הטיפול בתגובה ויגדיל את מונה המכסות המשותפות. קובץ ה-XML שנוצר אמור להיראות כך:<TargetEndpoint>
<TargetEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>LTQ-Count-Only</Name> </Step> </Response> </EventFlow> <HTTPTargetConnection> <URL>https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?key=GEMINI_API_KEY&alt=sse</URL> </HTTPTargetConnection> </TargetEndpoint>
<ProxyEndpoint>
<ProxyEndpoint name="default"> <EventFlow content-type="text/event-stream"> <Response> <Step> <Name>LTQ-Count-Only</Name> </Step> </Response> </EventFlow> <HTTPProxyConnection> <URL>https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?key=GEMINI_API_KEY&alt=sse</URL> </HTTPProxyConnection> </ProxyEndpoint>
- שומרים ופורסים את שרת ה-proxy. מידע נוסף מופיע במאמר פריסת שרתי proxy ל-API.
- שולחים בקשות בדיקה לשרת ה-proxy. בכל בקשה נכנסת, המדיניות
LTQ-Enforce-Onlyבודקת את מונה המכסות המשותפות ודוחה את הבקשה אם כבר הגעתם למגבלה שהוגדרה. כשהשרת proxy מעבד את התגובות של ה-SSE, המדיניותLTQ-Count-Onlyסופרת את האסימונים שמדווחים במטא-נתונים של השימוש באסימונים בכל אירוע, ומגדילה את אותו מונה מכסות משותף. כשהמונה מגיע למגבלה שהוגדרה, בקשות נוספות לצריכת אסימונים נדחות עד שהמונה מתאפס.
מידע נוסף על המדיניות LLMTokenQuota, כולל איך להשתמש בה עם תגובות SSE ואיך להגדיר מוני מכסות משותפים, זמין במאמר המדיניות LLMTokenQuota.
הצגת נתוני SSE בניתוח הנתונים של Apigee
הנתונים של שרתי proxy ל-SSE מופיעים בניתוח הנתונים של Apigee, כמו בכל שרת proxy ל-API. במסוף Cloud, נכנסים לדף Analytics > API metrics.
ניפוי באגים בשרתי פרוקסי של SSE
כדי לנפות באגים בשרתי proxy של SSE, אפשר להשתמש בכלי לניפוי באגים של Apigee.
נתוני ניפוי הבאגים מתועדים ב-EventFlow בדיוק כמו בסוגי התהליכים האחרים.
פתרון בעיות
כדי לזהות את הגורם לבעיות בתנועה בזמן אמת, בודקים את יומני הגישה של Apigee.
מגבלות
המגבלות הבאות חלות על שרתי proxy של SSE:
- אם המדיניות DataCapture מופעלת בכל אירוע, רק הערך האחרון יתועד.
- אפשר להשאיר חיבור SSE פתוח ללא הגבלת זמן, אבל משך הזמן שלו מוגבל בסופו של דבר על ידי הגדרת הזמן הקצוב לתפוגה של מאזן העומסים במורד הזרם של Apigee. כברירת מחדל, הזמן הקצוב לתפוגה של מאזן העומסים ב-Apigee מוגדר ל-
30שניות. בחיבורים ארוכים יותר, מומלץ להגדיל את זמן הקצוב לתפוגה או ליצור שירות קצה עורפי נפרד עם ערך זמן קצוב לתפוגה גבוה יותר כדי לטפל בתעבורת ה-SSE. - נתוני Analytics מתועדים אחרי שסשן ה-SSE נסגר, לכן יכול להיות שיהיה עיכוב מסוים בדיווח על נתוני Analytics.
- תקלות בתוך EventFlow גורמות ליציאה מיידית מהסטרימינג ולהצגת שגיאה. במאמר תרחישים לדוגמה ודוגמאות של EventFlow מוסבר איך לתעד באופן ידני שגיאות מהסוג הזה או לשלוח אותן ללקוח.
- לקוח שמקבל תגובות SSE בסטרימינג יקבל את הכותרות של
HTTP, כולל קודי סטטוס, בתחילת הסטרימינג של האירוע. כתוצאה מכך, אם זרם האירועים נכנס למצב שגיאה, קוד הסטטוס שהתקבל בהתחלה לא ישקף את מצב השגיאה.אפשר לראות את המגבלה הזו כשמציגים סשן ניפוי באגים. בסשן, יכול להיות שתבחינו שקוד הסטטוס
HTTPשל סטרימינג שנכנס למצב שגיאה שונה מקודי הסטטוס שנשלחים ללקוח. זה יכול לקרות כי הרשומה של סשן ניפוי הבאגים נוצרת אחרי שכל הבקשה עובדה, ולא בתחילת זרם האירועים. יכול להיות שסשן ניפוי הבאגים ישקף את קוד השגיאה שנוצר, אבל הלקוח יראה רק את סטטוס ה-2xx שהתקבל בהתחלה בכותרות.