הגדרת סטרימינג לתשובות של מודלים גדולים של שפה (LLM) ולתעבורה אחרת
במאמר הזה מוסבר איך להגדיר סטרימינג ב-API Gateway.
API Gateway תומך בסטרימינג. סטרימינג מאפשר לשערי גישה להפעיל חיבורים ארוכי טווח ולהעביר נתונים במנות קטנות גם בסטרימינג של בקשות וגם בסטרימינג של תגובות.
אחד מהשימושים הנפוצים בסטרימינג הוא הפעלת מודל שפה גדול (LLM). המודל שולח את התשובה שלו טוקן אחד בכל פעם, כך שהלקוח יכול להציג את הטקסט בזמן שהמודל עדיין יוצר אותו. דוגמה מלאה להזרמת תגובות ממודל Gemma שמוגש על ידי vLLM ב-Cloud Run זמינה במאמר הזרמת תגובות מ-LLM.
פרוטוקולים נתמכים לסטרימינג
כשההגדרה מופעלת, API Gateway תומך בשיטות הסטרימינג הבאות:
- העברת תגובה מצטברת: מסגרות נתונים של HTTP/2 או קידוד העברה בחלקים של HTTP/1.1, בהתאם למה שהלקוח מסכים עליו.
- אירועים שנשלחים מהשרת (SSE): סטרימינג חד-כיווני מהשרת ללקוח.
- WebSockets: ערוצי תקשורת דו-כיווניים מלאים על גבי חיבור TCP יחיד.
- סטרימינג דו-כיווני ב-gRPC: סטרימינג דו-כיווני באמצעות gRPC.
דרישות מוקדמות
לפני שמשתמשים בסטרימינג, צריך לוודא ששירות לקצה העורפי תומך בפרוטוקול הנדרש (לדוגמה, HTTP/2 או WebSockets) ושהגדרות ה-API מוגדרות בצורה נכונה.
הגדרת פרוטוקול הקצה העורפי
כדי לתמוך בתנועת סטרימינג, צריך להגדיר את הפרוטוקול עבור ה-Backend בהתאם לסוג הסטרימינג:
- gRPC: צריך להגדיר את ה-backend לשימוש ב-HTTP/2 (
h2). - WebSockets: צריך להשתמש ב-
http/1.1. פרוטוקול WebSockets מחייב לחיצת יד של HTTP/1.1Connection: Upgrade. - אירועים שנשלחים מהשרת (SSE) ומסירה מצטברת של תגובות: הקצה העורפי יכול להשתמש ב-HTTP/1.1 או ב-HTTP/2 (
h2). מומלץ להשתמש ב-HTTP/2 (h2) כדי לשפר את הביצועים.
במפרט OpenAPI, מגדירים את פרוטוקול הבק-אנד באופן הבא:
דוגמה (OpenAPI 3.x)
מגדירים את השדה protocol בהגדרת ה-backend שנקראת באובייקט x-google-api-management.backends. צריך גם להפנות אל ה-Backend הזה באמצעות x-google-backend ברמת השורש או ברמת הפעולה.
x-google-api-management:
backends:
gemma:
address: https://my-gemma-service.run.app
protocol: h2 # Use 'http/1.1' for WebSockets
x-google-backend: gemma
דוגמה (OpenAPI 2.0)
מגדירים את השדה protocol בתוסף x-google-backend.
x-google-backend:
address: https://my-gemma-service.run.app
protocol: h2 # Use 'http/1.1' for WebSockets
הגדרת הדדליין של השידור
השדה deadline קובע כמה זמן בקשה (unary או streaming) יכולה לפעול.
בטבלה הבאה אפשר לראות איך פסק הזמן חל על כל סוג של בקשה:
| Method | זמן קצוב לתפוגה במצב סרק (המרווח המקסימלי בין הודעות) |
הזמן הקצוב לתפוגת הבקשה הסתיים (משך הזמן הכולל המקסימלי של הבקשה) |
|---|---|---|
| לא סטרימינג | לא רלוונטי: הזמן הקצוב לתפוגה כשאין פעילות רלוונטי רק לסטרימינג | ברירת המחדל היא 15 שניות. אפשר להגדיר את deadline כדי לשנות את משך הזמן, עד 3,600 שניות עבור שערים עם הפעלת סטרימינג |
| סטרימינג באמצעות HTTP (SSE, העברה בחלקים) |
לא רלוונטי: למעשה אינסופי; רק הזמן הקצוב לתפוגה של הבקשה מסיים את הסטרימינג | ברירת המחדל היא 15 שניות. אפשר להגדיר את deadline כדי לשנות את ברירת המחדל, עד 3,600 שניות עבור שערים עם הפעלת סטרימינג |
| סטרימינג באמצעות gRPC או WebSockets | ברירת המחדל היא 300 שניות. אפשר להגדיר את deadline כדי לשנות את ההגדרה, עד 3,600 שניות עבור שערים עם הפעלת סטרימינג. ב-WebSockets, המערכת מתעלמת מ-deadline של פחות מ-300 שניות, וחל מינימום של 300 שניות |
תמיד 3,600 שניות בשערי גישה עם הפעלת סטרימינג, אי אפשר להגדיר |
דוגמה (OpenAPI 3.x)
מגדירים את השדה deadline בהגדרת ה-backend שצוין.
x-google-api-management:
backends:
gemma:
address: https://my-gemma-service.run.app
protocol: h2
deadline: 3600.0
x-google-backend: gemma
דוגמה (OpenAPI 2.0)
מגדירים את השדה deadline בתוסף x-google-backend.
x-google-backend:
address: https://my-gemma-service.run.app
protocol: h2
deadline: 3600.0
מידע על מגבלות אחרות שחלות על חיבורי סטרימינג זמין במאמר בנושא מגבלות.
הפעלת סטרימינג בשער
ההגדרה של הסטרימינג נקבעת בזמן יצירת השער. חשוב לשים לב להתנהגות הבאה:
- אין השבתה מפורשת: אין דגל להשבתה מפורשת של סטרימינג. אם לא מציינים את הדגל
--enable-streaming, API Gateway יקבע את המצב בזמן היצירה מתוך הגדרת ה-API ומברירת המחדל של הפלטפורמה: הגדרת API שמגדירה נתב מודלים תמיד תיצור שער סטרימינג. כדי לראות את המצב שבו נוצר השער, קוראים את השדהeffectiveStreamingModeשל השער שהוא פלט בלבד. - אי אפשר לשנות את ההגדרה: מצב הסטרימינג קבוע מרגע היצירה, ואי אפשר לשנות אותו בהמשך.
כדי לציין סטרימינג בשער, משתמשים בדגל --enable-streaming עם הפקודה gcloud api-gateway gateways create:
gcloud api-gateway gateways create GATEWAY_ID \
--api=API_ID \
--api-config=CONFIG_ID \
--location=GCP_REGION \
--enable-streamingמידע נוסף על אפשרויות הפריסה של שערים זמין במאמר פריסת API בשער.
מאפייני סטרימינג של שער
השדות הבאים במשאב Gateway שולטים בהתנהגות הסטרימינג:
| שדה | מאפיינים | ערכים |
|---|---|---|
streamingMode |
מחרוזת (לא ניתן לשינוי, אופציונלי) |
|
effectiveStreamingMode |
מחרוזת (פלט בלבד) |
|
כשמשתמשים ב-API בארכיטקטורת REST כדי ליצור שער, אפשר לציין סטרימינג בגוף הבקשה:
{
"apiConfig": "projects/...",
"streamingMode": "STREAMING_MODE_ENABLED"
}
איך מוודאים שהסטרימינג מופעל
כדי לוודא שהסטרימינג פעיל בשער, מתארים את השער באמצעות ה-CLI של gcloud:
gcloud api-gateway gateways describe GATEWAY_ID \
--location=GCP_REGIONמחפשים את השדה effectiveStreamingMode בפלט. אם הסטרימינג מופעל, הפלט כולל:
effectiveStreamingMode: EFFECTIVE_STREAMING_MODE_ENABLED
הצגת התשובות באופן שוטף ממודל שפה גדול (LLM)
בדוגמה הזו, שער סטרימינג מוצב לפני מודל Gemma שמקבל בקשות מ-vLLM ב-Cloud Run, ומבצע סטרימינג של השלמת צ'אט דרך השער. vLLM משרת API שתואם ל-OpenAI ומבצע סטרימינג של תשובות כאירועים שנשלחים מהשרת (SSE).
לפני שמתחילים, צריך לבצע את השלבים שמפורטים במאמר הגדרת סביבת הפיתוח, כולל הגדרת חשבון השירות שמשמש ליצירת הגדרות API. השער משתמש בחשבון השירות הזה כדי לקרוא לשירות Cloud Run.
פריסת המודל
פורסים מודל Gemma באמצעות ההוראות שבמאמר פריסת מודל Gemma 4 באמצעות קונטיינר vLLM. שימו לב לשם השירות, לכתובת ה-URL של השירות, לאזור ולשם המודל שאתם פורסים, כמו google/gemma-4-E4B-it.
הענקת גישה לשער לשירות
במדריך מוסבר איך פורסים את השירות באמצעות --no-allow-unauthenticated. השער קורא לשירות עם טוקן של מזהה של חשבון השירות שלו, שמועבר כ---backend-auth-service-account כשיוצרים את הגדרת ה-API. מקצים לחשבון השירות את התפקיד Cloud Run Invoker (roles/run.invoker) בשירות:
gcloud run services add-iam-policy-binding SERVICE_NAME \
--region=REGION \
--member=serviceAccount:SERVICE_ACCOUNT_EMAIL \
--role=roles/run.invokerמחליפים את מה שכתוב בשדות הבאים:
-
SERVICE_NAME: השם של שירות Cloud Run -
REGION: האזור שבו פרסתם את השירות -
SERVICE_ACCOUNT_EMAIL: כתובת האימייל של חשבון השירות של השער
יצירת הגדרות ה-API
שומרים את מפרט OpenAPI הבא בשם gemma-api.yaml, ומחליפים את https://my-gemma-service.run.app בכתובת ה-URL של השירות:
openapi: 3.0.3
info:
title: Gemma API
version: 1.0.0
x-google-api-management:
backends:
gemma:
address: https://my-gemma-service.run.app
protocol: h2
deadline: 570.0
x-google-backend: gemma
components:
securitySchemes:
google_id_token:
type: oauth2
flows:
implicit:
authorizationUrl: ""
scopes: {}
x-google-auth:
issuer: https://accounts.google.com
jwksUri: https://www.googleapis.com/oauth2/v3/certs
audiences:
- gemma-api
security:
- google_id_token: []
paths:
/v1/chat/completions:
post:
operationId: createChatCompletion
responses:
'200':
description: A chat completion, streamed as SSE when the request sets "stream" to true.
הערך deadline של 570 שניות קצר ב-30 שניות מהערך --timeout 600 שמוגדר במדריך Gemma בשירות. כתוצאה מכך, אם הסטרימינג נמשך יותר מדי זמן, הוא מסתיים בגלל הזמן הקצוב לתפוגה של השער deadline, ולא בגלל הזמן הקצוב לתפוגה של השירות. ערך ברירת המחדל של x-google-backend ברמה העליונה הוא pathTranslation: APPEND_PATH_TO_ADDRESS. אפליקציית השער מוסיפה את נתיב הבקשה לכתובת הקצה העורפי, כך שבקשה ל-/v1/chat/completions מגיעה לנקודת הקצה של השלמות הצ'אט של vLLM.
הדרישה security גורמת לשער לדחות כל בקשה שלא כוללת טוקן של מזהה חתום על ידי Google עם קהל היעד gemma-api. אתם יכולים לבחור מחרוזת קהל אחרת, כל עוד המתקשרים מבקשים את אותה מחרוזת כשהם יוצרים אסימון. למידע נוסף, ראו שימוש באסימוני מזהה של Google לאימות משתמשים.
יוצרים את הגדרת ה-API:
gcloud api-gateway api-configs create CONFIG_ID \
--api=API_ID \
--openapi-spec=gemma-api.yaml \
--backend-auth-service-account=SERVICE_ACCOUNT_EMAILמחליפים את מה שכתוב בשדות הבאים:
-
CONFIG_ID: מזהה של הגדרת ה-API -
API_ID: מזהה ה-API. אם ה-API לא קיים, הפקודה יוצרת אותו.
יצירת השער
יצירת שער סטרימינג מהגדרת ה-API:
gcloud api-gateway gateways create GATEWAY_ID \
--api=API_ID \
--api-config=CONFIG_ID \
--location=GCP_REGION \
--enable-streamingמחליפים את מה שכתוב בשדות הבאים:
-
GATEWAY_ID: מזהה לשער -
GCP_REGION: האזור של השער, שיכול להיות שונה מ-REGION. ערכים מותרים מפורטים במאמר פריסת API בשער.
כשהשער מוכן, מאתרים את שם המארח שלו:
gcloud api-gateway gateways describe GATEWAY_ID \
--location=GCP_REGION \
--format="value(defaultHostname)"קבלת טוקן של מזהה עבור המתקשר
חשבון משתמש לא יכול לבחור את קהל היעד של אסימון המזהה שלו, ולכן בדוגמה הזו נוצר אסימון עבור חשבון שירות שמתחזים אליו. למבצע הקריאה החוזרת, משתמשים בחשבון שירות קיים או יוצרים חשבון שירות. מידע נוסף מופיע במאמר יצירת חשבונות שירות. מקצים לעצמכם את התפקיד 'יצירת אסימונים בחשבון שירות' (roles/iam.serviceAccountTokenCreator) בחשבון השירות, שנדרש ל-ה-CLI של gcloud כדי להתחזות לחשבון השירות:
gcloud iam service-accounts add-iam-policy-binding CALLER_SERVICE_ACCOUNT_EMAIL \
--member=user:USER_EMAIL \
--role=roles/iam.serviceAccountTokenCreatorמחליפים את מה שכתוב בשדות הבאים:
CALLER_SERVICE_ACCOUNT_EMAIL: כתובת האימייל של חשבון השירות שמבצע את הקריאה לשערUSER_EMAIL: כתובת האימייל שלכם
שליחת בקשה להזרמת תוכן
שולחים בקשה להשלמת צ'אט עם הערך "stream": true, עם טוקן של מזהה של חשבון השירות של המתקשר בכותרת Authorization. הדגל -N משבית את מאגר הפלט הזמני ב-curl, כך שכל אירוע מודפס כשהוא מגיע:
curl -N https://DEFAULT_HOSTNAME/v1/chat/completions \
-H "Authorization: Bearer $(gcloud auth print-identity-token \
--impersonate-service-account=CALLER_SERVICE_ACCOUNT_EMAIL \
--audiences=gemma-api)" \
-H "Content-Type: application/json" \
-d '{
"model": "MODEL_NAME",
"messages": [{"role": "user", "content": "Why is the sky blue?"}],
"stream": true
}'מחליפים את מה שכתוב בשדות הבאים:
-
DEFAULT_HOSTNAME: שם המארח של השער CALLER_SERVICE_ACCOUNT_EMAIL: חשבון השירות מהשלב הקודם-
MODEL_NAME: המודל שפרסתם, למשלgoogle/gemma-4-E4B-it
התגובה היא סטרימינג SSE. האירוע הראשון נושא את התפקיד assistant, כל אירוע מאוחר יותר נושא את החלק הבא של התשובה, והאירוע האחרון לפני data: [DONE] מגדיר את finish_reason. הפלט אמור להיראות כך:
data: {"id":"chatcmpl-7bcd57ad-1c3c-4779-91be-2973b875e517","object":"chat.completion.chunk","created":1790099706,"model":"google/gemma-4-E4B-it","choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}],"prompt_token_ids":null}
data: {"id":"chatcmpl-7bcd57ad-1c3c-4779-91be-2973b875e517","object":"chat.completion.chunk","created":1790099706,"model":"google/gemma-4-E4B-it","choices":[{"index":0,"delta":{"content":"The"},"logprobs":null,"finish_reason":null,"token_ids":null}]}
...
data: {"id":"chatcmpl-7bcd57ad-1c3c-4779-91be-2973b875e517","object":"chat.completion.chunk","created":1790099706,"model":"google/gemma-4-E4B-it","choices":[{"index":0,"delta":{"content":""},"logprobs":null,"finish_reason":"stop","stop_reason":106,"token_ids":null}]}
data: [DONE]
הסרת המשאבים
כדי לא לצבור חיובים לחשבון Google Cloud על המשאבים שבהם השתמשתם בדוגמה הזו, מוחקים את השער ואת הגדרות ה-API:
gcloud api-gateway gateways delete GATEWAY_ID \
--location=GCP_REGIONgcloud api-gateway api-configs delete CONFIG_ID \
--api=API_IDאם יצרתם את ה-API בדוגמה הזו, מחקו אותו:
gcloud api-gateway apis delete API_ID
מוחקים את שירות Cloud Run:
gcloud run services delete SERVICE_NAME \
--region=REGIONתמחור
במהלך גרסת הטרום-השקה הציבורית של הסטרימינג, הלקוחות לא מחויבים על תעבורת נתונים יוצאת (egress) מהרשת בשערי כניסה שמופעל בהם סטרימינג. עם זאת, החיוב ב-Service Control API עדיין חל ברמת ה-API, ללא קשר לשלב ההשקה.
מגבלות
המגבלות הבאות חלות על סטרימינג ב-API Gateway במהלך גרסת הטרום-השקה הציבורית:
אי אפשרות שינוי: אי אפשר לעדכן שער קיים כדי להפעיל או להשבית סטרימינג. תצטרכו ליצור שער חדש. שימו לב: שער עם תמיכה בסטרימינג מקבל צורה שונה של שם מארח, ולכן צריך לעדכן את הלקוחות או את רשומות ה-DNS. אם אתם רוצים שנעדכן את רשומת שער התשלומים שלכם לפורמט החדש, פנו לתמיכה. API Gateway משתמש בדפוסי שמות המארחים הבאים:
- ללא סטרימינג:
{gateway_id}-{base36_project_number}.{shard_hash}.gateway.dev, לדוגמהtest-gateway-4jcaz8x.uc.gateway.dev - סטרימינג:
{gateway_id}-{project_number}.{region}.gateway.dev, לדוגמהtest-gateway-9876654321.us-central1.gateway.dev - סטרימינג (גרסה קודמת):
{service}-{tenant_project_number}.{region}.run.app, לדוגמהtest-gateway-834512064953.us-central1.run.app. שערי כניסה שנוצרו לפני שהיו זמינים שמות מארחים אזוריים*.gateway.devישמרו את שם המארח הזה באופן קבוע ולא יועברו לדפוס החדש.
שער חדש עם תמיכה בהזרמת נתונים מקבל את התבנית Streaming. שתי הדוגמאות הראשונות הן של אותו שער באותו פרויקט: בתבנית Streaming מספר הפרויקט מופיע בפורמט עשרוני ולא בפורמט base36, ולכן התווית הראשונה קצרה יותר מאשר בשער שאינו Streaming. התווית הראשונה היא מחרוזת משולבת
{gateway_id}-{project_number}, שצריכה להתאים למגבלת התווים של תווית DNS (עד 63 תווים). הגבלת מזהה השער ל-49 תווים מאפשרת להשתמש במספר פרויקט של עד 13 ספרות. אם מספר הפרויקט ארוך יותר, צריך להשתמש במזהה שער קצר יותר.- ללא סטרימינג:
Terraform: הפעלת סטרימינג באמצעות Terraform לא אפשרית (התמיכה הזו מתוכננת לגרסה עתידית).
איזון עומסים ודומיינים מותאמים אישית: שערים עם
effectiveStreamingModeשלEFFECTIVE_STREAMING_MODE_ENABLEDלא תואמים לאיזון עומסים ב-HTTP(S) עבור API Gateway או NEGs ללא שרת. אי אפשר להציב שער כזה מאחורי Serverless NEG או מאזן עומסים חיצוני של אפליקציות (ALB). לכן, אין תמיכה בדומיינים מותאמים אישית (שמסתמכים על איזון עומסים) בשערים האלה במהלך תקופת ה-Public Preview.אופן הפעולה של הגדרת זמן קצוב לתפוגה: הפעלת סטרימינג בשער לא משנה את אופן הפעולה של השדה
deadlineבנתיב SSE או בנתיב העברה בחלקים. המועד האחרון נשאר מועד מחייב לגבי התגובה המלאה, ולכן הסטרימינג נפסק כשהמועד האחרון חלף, בלי קשר לכמות הנתונים שנשלחת. ברירת המחדל היא 15 שניות והערך המקסימלי הוא 3,600 שניות. ב-WebSocket, deadlineמגביל את הפער בין ההודעות, והחיבור מסתיים אחרי 3,600 שניות. מידע נוסף מופיע במאמר בנושא הגדרת מועד סיום השידור.Model Context Protocol (MCP): יצירת השער באמצעות
--enable-streamingלא יוצרת סטרימינג של נקודת קצה של MCP. התשובות של MCP נשארות בגוףapplication/jsonאחד, ללא קשר למצב הסטרימינג של השער. פרטים נוספים זמינים במאמר בנושא מגבלות של MCP.