יצירת שער AI עם ניתוב, הגנה מוגברת על המודל ומטמון סמנטי

הדף הזה רלוונטי ל-Apigee ול-Apigee Hybrid.

לצפייה במסמכי התיעוד של Apigee Edge

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

כל שלב במדריך מתבסס על ההגדרות הקודמות ומוסיף יכולת ספציפית באמצעות קובצי Apigee Feature Template‏ (AFT) לשימוש חוזר:

  • שלב 1: פריסת שרת proxy מינימלי של API שמקשר לספק יחיד של מודל שפה גדול (LLM).
  • שלב 2: מוסיפים את Model Armor להסרת תוכן זדוני או רגיש מההנחיות ומהתשובות, כדי לסנן קלט זדוני ולמנוע זליגת מידע אישי רגיש.
  • שלב 3: הוספת ניתוב משימות למודלים בין ספקים ומטמון סמנטי שמגובה על ידי חיפוש וקטורי בפלטפורמת הסוכנים.
  • שלב 4: מגדירים חלופה בין ספקים כדי לנסות שוב באופן אוטומטי לשלוח בקשות לספק משני אם היעד הראשי מחזיר קוד סטטוס HTTP מסוג 4xx או 5xx.

כדי להוסיף יכולת, מוסיפים שורה אחת לבלוק features בתבנית. כדי לראות או להוריד את כל קבצי הדוגמה, כולל קובצי ה-AFT וסקריפטים של כלי עזר, אפשר לעיין במאגר התבניות של Apigee ב-GitHub.

לפני שמתחילים

לפני שמתחילים, חשוב לוודא שהתנאים הבאים מתקיימים:

  • פרויקט פעיל Google Cloud שהחיוב בו מופעל.
  • סביבת Comprehensive שזמינה במופע Apigee שלכם. אפשר לפרוס את כללי המדיניות של Model Armor,‏ SemanticCacheLookup ו-SemanticCachePopulate רק בסביבות Comprehensive.
  • ‫Google Cloud CLI ‏ (gcloud) מותקן ומוגדר עם Application Default Credentials ‏ (ADC). כדי ליצור פרטי כניסה, מריצים את הפקודה gcloud auth application-default login.
  • חשבון שירות של סביבת זמן ריצה עם התפקידים הבאים ב-IAM:
    • roles/aiplatform.user
    • roles/modelarmor.user
    חשבון השירות צריך גם גישה לפרטי כניסה ספציפיים לספק.
  • בשלבים 2, 3 ו-4, מציינים את נתיב המשאב של תבנית Model Armor. לדוגמה, projects/YOUR_PROJECT/locations/us-central1/templates/apigee-aft-demo-ma.
  • לשלבים 3 ו-4: מפת מפתח-ערך (KVM) של Apigee בשם openai-credentials בסביבה שלכם, שמכילה רשומת api-key עם מפתח OpenAI API תקין.
  • לשלבים 3 ו-4: נקודת קצה של אינדקס חיפוש וקטורי ב-Vertex AI שנפרסה עבור מטמון סמנטי. להוראות מפורטות להגדרת אינדקס, קראו את קובץ ה-README של מאגר התבניות של Apigee ב-GitHub.

סקירה כללית

כל ארבעת השלבים מקבלים את צורת הבקשה של OpenAI Chat Completions בכתובת /v1/chat/completions[-stageN], כך שאותן ערכות SDK של לקוחות פועלות בכל שלב. קידומת השדה model קובעת את החלטת הניתוב: בקשות למודלים של google/* מנותבות אל Gemini ב-Agent Platform, וכל הבקשות האחרות מנותבות אל OpenAI. ההגדרה ההפוכה הזו כברירת מחדל מוודאת שמשפחות חדשות של מודלים של OpenAI, כמו o1-*, o3-* ו-chatgpt-*, מנותבות בצורה נכונה במקום לפספס התאמה של קידומת gpt-* בלי להציג הודעה.

שלב היכולת נוספה נתיב בסיסי
1 ‫Hello LLM (בקשה בפורמט OpenAI ל-Gemini ב-Agent Platform) /v1/chat/completions
2 הגנה מוגברת על המודל (החדרת פרומפטים, אתיקה של בינה מלאכותית ומסננים של Sensitive Data Protection) /v1/chat/completions-stage2
3 ניתוב בין ספקים ומטמון סמנטי של Agent Platform חיפוש וקטורי /v1/chat/completions-stage3
4 חלופה בין ספקים (שער AI מלא) /v1/chat/completions-stage4

שלב 1: Hello LLM

הפרוקסי המינימלי פועל מול יעד Gemini יחיד דרך נקודת הקצה (endpoint) שלו שתואמת ל-OpenAI. שני קובצי תכונות קטנים מספקים את שלד ה-proxy הבסיסי ומחלץ JSON. החילוץ מעתיק את $.model ואת $.messages[-1].content למשתני הזרימה llm.model ו-llm.prompt, כדי שבשלבים הבאים יהיו קלטים עקביים.

‫llm-base.yaml מגדיר את שלד ה-proxy הבסיסי:

gateway: apigee
schemaVersion: 1.0.0
name: llm-base
type: feature
parameters:
  - name: BASE_PATH
    default: /v1/chat/completions
endpoints:
  - name: default
    basePath: "{BASE_PATH}"
    routes:
      - name: primary
        target: gemini-target

‫llm-openai-format.yaml מחלץ את שדות הבקשה בפורמט OpenAI:

gateway: apigee
schemaVersion: 1.0.0
name: llm-openai-format
type: feature
defaultEndpoint:
  name: default
  flows:
    - name: PreFlow
      mode: Request
      steps:
        - name: EV-ExtractOpenAIRequest
policies:
  - name: EV-ExtractOpenAIRequest
    type: ExtractVariables
    content:
      ExtractVariables:
        metadata:
          name: EV-ExtractOpenAIRequest
          continueOnError: "true"
        Source:
          _text: request
        JSONPayload:
          Variable:
            - metadata:
                name: model
              JSONPath:
                _text: "$.model"
            - metadata:
                name: prompt
              JSONPath:
                _text: "$.messages[-1].content"
        VariablePrefix:
          _text: llm

‫target-vertex-gemini.yaml מגדיר יעד של Agent Platform שמשתמש בנקודת הקצה שתואמת ל-OpenAI:

gateway: apigee
schemaVersion: 1.0.0
name: target-vertex-gemini
type: feature
targets:
  - name: gemini-target
    httpTargetConnection:
      URL: https://aiplatform.googleapis.com/v1/projects/{organization.name}/locations/global/endpoints/openapi/chat/completions
      Authentication:
        GoogleAccessToken:
          Scopes:
            Scope: https://www.googleapis.com/auth/cloud-platform

יוצרים את קובצי התכונות בתבנית של שלב 1, 01-hello-llm.yaml:

gateway: apigee
schemaVersion: 1.0.0
name: aft-demo-01-hello-llm
features:
  - llm-base.yaml
  - llm-openai-format.yaml
  - target-vertex-gemini.yaml

פורסים את התבנית:

gcloud beta apigee apis import aft-demo-01-hello-llm \
  --from-template=01-hello-llm.yaml \
  --organization=APIGEE_ORG

בודקים את שרת ה-proxy:

curl -X POST https://APIGEE_HOSTNAME/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"google/gemini-2.5-flash",
       "messages":[{"role":"user","content":"Explain how AI works in a few words"}]}'

מחליפים את מה שכתוב בשדות הבאים:

  • ‫APIGEE_ORG: שם הארגון ב-Apigee.
  • ‫APIGEE_HOSTNAME: שם המארח של קבוצת הסביבות ב-Apigee, בדרך כלל מאזן עומסים (LB) של Google Cloud .

שלב 2: הוספת Model Armor

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

מוסיפים לתבנית קובץ תכונות אחד, llm-model-armor.yaml:

gateway: apigee
schemaVersion: 1.0.0
name: llm-model-armor
type: feature
parameters:
  - name: MA_TEMPLATE_PATH
    default: projects/{organization.name}/locations/us-central1/templates/apigee-aft-demo-ma
defaultEndpoint:
  name: default
  flows:
    - name: PreFlow
      mode: Request
      steps:
        - name: MA-SanitizeUserPrompt
    - name: PostFlow
      mode: Response
      steps:
        - name: MA-SanitizeModelResponse
policies:
  - name: MA-SanitizeUserPrompt
    type: SanitizeUserPrompt
    content:
      SanitizeUserPrompt:
        metadata:
          name: MA-SanitizeUserPrompt
        ModelArmor:
          TemplateName:
            _text: "{MA_TEMPLATE_PATH}"
        UserPromptSource:
          _text: "{llm.prompt}"
  - name: MA-SanitizeModelResponse
    type: SanitizeModelResponse
    content:
      SanitizeModelResponse:
        metadata:
          name: MA-SanitizeModelResponse
        ModelArmor:
          TemplateName:
            _text: "{MA_TEMPLATE_PATH}"
        UserPromptSource:
          _text: "{llm.prompt}"
        LLMResponseSource:
          _text: "{jsonPath('$.choices[-1].message.content',response.content,true)}"

התבנית של שלב 2, 02-add-model-armor.yaml, מוסיפה שורה אחת:

gateway: apigee
schemaVersion: 1.0.0
name: aft-demo-02-add-model-armor
features:
  - llm-base.yaml
  - llm-openai-format.yaml
  - target-vertex-gemini.yaml
  - llm-model-armor.yaml           # <-- the change from Stage 1
parameters:
  - name: BASE_PATH
    default: /v1/chat/completions-stage2

פרמטר MA_TEMPLATE_PATH מוגדר כברירת מחדל לתבנית בשם apigee-aft-demo-ma ב-us-central1. כדי להשתמש בתבנית Model Armor משלכם, צריך לבטל את הפרמטר בבלוק parameters של התבנית.

שלב 3: הוספת ניתוב בין ספקים ומטמון סמנטי

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

כדי להגדיר את שלב 3, מוסיפים שלושה קובצי תכונות לבלוק features בתבנית:

  • ‫target-openai-gpt.yaml: הוספת OpenAI כנקודת קצה משנית.
  • ‫llm-routing.yaml: ניתוב בקשות באופן דינמי על סמך שם המודל המבוקש.
  • ‫llm-semantic-cache.yaml: מוסיף מטמון סמנטי לפני שני הספקים.

בדוגמה הבאה אפשר לראות איך קובץ התכונות llm-routing.yaml מגדיר את לוגיקת הניתוב:

gateway: apigee
schemaVersion: 1.0.0
name: llm-routing
type: feature
parameters:
  - name: BASE_PATH
    default: /v1/chat/completions
endpoints:
  - name: default
    basePath: "{BASE_PATH}"
    routes:
      - name: gemini
        condition: llm.model StartsWith "google/"
        target: gemini-target
      - name: openai
        target: openai-target      # default when the condition is false

המטמון הסמנטי פועל SemanticCacheLookup ב-PreFlow של הבקשה ו-SemanticCachePopulate ב-PostFlow של התגובה, רק במקרים של אי מציאה במטמון. שתי כללי המדיניות משתמשים בנקודת קצה של אינדקס חיפוש וקטורי של Agent Platform שאתם מקצים בנפרד. הקטע הבא מציג את החלקים העיקריים של הגדרות המדיניות:

policies:
  - name: SCLLookup
    type: SemanticCacheLookup
    content:
      SemanticCacheLookup:
        UserPromptSource:
          _text: "{llm.prompt}"
        Embeddings:
          VertexAI:
            URL:
              _text: "https://{EMBEDDINGS_LOCATION}-aiplatform.googleapis.com/v1/projects/{organization.name}/locations/{EMBEDDINGS_LOCATION}/publishers/google/models/{EMBEDDINGS_MODEL}:predict"
        SimilaritySearch:
          VertexAI:
            URL:
              _text: "https://{VECTOR_INDEX_ENDPOINT_SUBDOMAIN}.{EMBEDDINGS_LOCATION}-{PROJECT_NUMBER}.vdb.vertexai.goog/v1/projects/{organization.name}/locations/{EMBEDDINGS_LOCATION}/indexEndpoints/{VECTOR_INDEX_ENDPOINT_ID}:findNeighbors"
            DeployedIndexID:
              _text: "{DEPLOYED_INDEX_ID}"
            Threshold:
              _text: "{THRESHOLD}"
  - name: SCPPopulate
    type: SemanticCachePopulate
    # ... (see the GitHub repository for the full definition)

בשלב 3, התבנית מרכיבה את כל קובצי התכונות:

gateway: apigee
schemaVersion: 1.0.0
name: aft-demo-03-add-routing-and-cache
features:
  - llm-base.yaml
  - llm-openai-format.yaml
  - target-vertex-gemini.yaml
  - llm-model-armor.yaml
  - target-openai-gpt.yaml         # <-- add OpenAI target
  - llm-routing.yaml               # <-- add model-name routing
  - llm-semantic-cache.yaml        # <-- add semantic cache
parameters:
  - name: BASE_PATH
    default: /v1/chat/completions-stage3
  - name: VECTOR_INDEX_ENDPOINT_ID
    default: "YOUR_INDEX_ENDPOINT_ID"
  - name: VECTOR_INDEX_ID
    default: "YOUR_INDEX_ID"
  - name: VECTOR_INDEX_ENDPOINT_SUBDOMAIN
    default: "YOUR_SUBDOMAIN"
  - name: PROJECT_NUMBER
    default: "YOUR_PROJECT_NUMBER"
  - name: DEPLOYED_INDEX_ID
    default: "YOUR_DEPLOYED_INDEX_ID"

מפעילים את התבנית באמצעות אותה פקודה gcloud beta apigee apis import עם הדגל --from-template שבה השתמשתם בשלב 1.

שלב 4: הוספת חלופה בין ספקים

בשלב 4, מצורף DefaultFaultRule לשני היעדים. כשהיעד הראשי מחזיר סטטוס 4xx או 5xx, כלל השגיאה שולח ServiceCallout עם אותה הנחיה לספק השני ומחזיר את התשובה הזו ללקוח. הלקוח מקבל תגובת 200 תקינה עם השלמה רגילה, ואין צורך בלוגיקה משלו לניסיון חוזר או לטיפול בשגיאות.

קובץ התכונה llm-fallback.yaml מוסיף את ההתנהגות הזו. הדוגמה הבאה מקוצרת. הקובץ המלא זמין במאגר GitHub.

gateway: apigee
schemaVersion: 1.0.0
name: llm-fallback
type: feature
targets:
  # Vertex primary; on 4xx/5xx, fall back to OpenAI.
  - name: gemini-target
    httpTargetConnection:
      Properties:
        Property:
          metadata:
            name: success.codes
          _text: "2XX"
      URL: https://aiplatform.googleapis.com/v1/projects/{organization.name}/locations/global/endpoints/openapi/chat/completions
      Authentication:
        GoogleAccessToken:
          Scopes:
            Scope: https://www.googleapis.com/auth/cloud-platform
    flows:
      - name: PostFlow
        mode: Response
        steps:
          - name: RF-TargetErrorToFault
            condition: response.status.code >= 400
    defaultFaultRule:
      name: FallbackToOpenAI
      steps:
        - name: KVM-GetOpenAIKey
        - name: AM-BuildOpenAIFallbackRequest
        - name: SC-FallbackToOpenAI
        - name: AM-CopyOpenAIFallbackResponse
  # OpenAI primary; on 4xx/5xx, fall back to Vertex.
  - name: openai-target
    httpTargetConnection:
      Properties:
        Property:
          metadata:
            name: success.codes
          _text: "2XX"
      URL: https://api.openai.com/v1/chat/completions
    flows:
      - name: PreFlow
        mode: Request
        steps:
          - name: JS-StripOpenAIModelPrefix
          - name: KVM-GetOpenAIKey
          - name: AM-SetOpenAIAuth
      - name: PostFlow
        mode: Response
        steps:
          - name: RF-TargetErrorToFault
            condition: response.status.code >= 400
    defaultFaultRule:
      name: FallbackToVertex
      steps:
        - name: AM-BuildVertexFallbackRequest
        - name: SC-FallbackToVertex
        - name: AM-CopyVertexFallbackResponse
policies:
  # RaiseFault converts a target 4xx/5xx into a fault so DefaultFaultRule fires.
  - name: RF-TargetErrorToFault
    type: RaiseFault
    content:
      RaiseFault:
        IgnoreUnresolvedVariables: "true"
        # empty FaultResponse -- DefaultFaultRule builds the real response
  # ... AM-Build*, SC-Fallback*, AM-Copy* policies -- see GitHub repository

המעבר לגיבוי מסתמך על שתי הגדרות:

  • ‫success.codes: 2XX בשני הבלוקים של httpTargetConnection. מערכת Apigee מתייחסת לכל תגובה של יעד שאינה 2xx כאל כשל ביעד, ועוברת ישירות לזרימת השגיאות.
  • מדיניות RaiseFault ב-PostFlow של התגובה של כל יעד, שמוגבלת על ידי response.status.code >= 400. המדיניות הזו מבטיחה שהמדיניות DefaultFaultRule תפעל בכל תגובת שגיאה.

יוצרים את התבנית של שלב 4, שמוסיפה שורה אחת לתבנית של שלב 3:

gateway: apigee
schemaVersion: 1.0.0
name: aft-demo-04-add-fallback
features:
  - llm-base.yaml
  - llm-openai-format.yaml
  - target-vertex-gemini.yaml
  - llm-model-armor.yaml
  - target-openai-gpt.yaml
  - llm-routing.yaml
  - llm-semantic-cache.yaml
  - llm-fallback.yaml              # <-- the change from Stage 3
parameters:
  - name: BASE_PATH
    default: /v1/chat/completions-stage4
  # ... Model Armor and Vector Search parameters as in Stage 3

פורסים את התבנית:

gcloud beta apigee apis import aft-demo-04-add-fallback \
  --from-template=04-add-fallback.yaml \
  --organization=APIGEE_ORG

אימות ההתנהגות מקצה לקצה

המאגר ב-GitHub כולל סקריפט routing-diagnostic.sh שמפעיל את כל נתיבי הניתוב והגיבוי עם הנחיות בנושאים שונים. מכיוון שהמטמון הסמנטי מקצר את הדרך להנחיות דומות, כל הנחיה לבדיקה צריכה להיות מנוסחת בצורה שונה.

STAGE=4 ./routing-diagnostic.sh

הסקריפט שולח חמש בקשות דרך שרת ה-proxy של שלב 4:

  • מודל קנוני של OpenAI
  • מודל Gemini עם הקידומת google/
  • שם של מודל Gemini בלי קידומת, שמופנה ל-OpenAI לפי ברירת המחדל ההפוכה
  • מודל חשיבה רציונלית של OpenAI
  • שם מודל עם הקידומת openai/

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

כדי לראות כל שלב במדיניות, קריאת יעד ומעבר של כלל שגיאה לבקשה אחת, יוצרים סשן ניפוי באגים ב-Apigee מול הגרסה שנפרסה:

DEBUG_URL="https://apigee.googleapis.com/v1/organizations/APIGEE_ORG/environments/APIGEE_ENV/apis/aft-demo-04-add-fallback/revisions/REVISION/debugsessions"
curl -X POST -H "Authorization: Bearer $(gcloud auth application-default print-access-token)" \
  -H "Content-Type: application/json" \
  -d '{"filter":"","count":10,"timeout":"600","validity":600}' \
  "$DEBUG_URL"

מחליפים את מה שכתוב בשדות הבאים:

  • ‫APIGEE_ORG: שם הארגון ב-Apigee.
  • ‫APIGEE_ENV: הסביבה שבה פרסתם את שרת ה-proxy.
  • ‫REVISION: מספר הגרסה שנפרסה של שרת ה-proxy של aft-demo-04-add-fallback.

לאחר מכן, שולחים בקשה שמפעילה את החלופה:

curl -X POST https://APIGEE_HOSTNAME/v1/chat/completions-stage4 \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-4o-mini",
       "messages":[{"role":"user","content":"Describe nuclear fusion in stars in two sentences."}]}'

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

  1. חילוץ משתני בקשה: Apigee מחלץ את המשתנים llm.model ו-llm.prompt מהמטען הייעודי (payload) הנכנס.
  2. הערכת מדיניות הבטיחות: הבקשה עוברת את סינון האבטחה של Model Armor.
  3. בדיקה של המטמון הסמנטי: החיפוש לא מוצא את המטמון הסמנטי, ולכן הבקשה ממשיכה ליעד.
  4. הערכת תנאי הניתוב: התנאי llm.model StartsWith "google/" מקבל את הערך false.
  5. ניתוב ליעד הראשי: Apigee מעבירה את הבקשה אל openai-target.
  6. טיפול בשגיאת היעד: היעד של OpenAI מחזיר קוד סטטוס של HTTP שהוא לא 2xx, וזה גורם ל-Apigee להציג שגיאת יעד.
  7. הפעלת כלל השגיאה: רכיב DefaultFaultRule מפעיל את רצף הגיבוי על ידי הפעלת רכיבים AM-BuildVertexFallbackRequest, SC-FallbackToVertex ו-AM-CopyVertexFallbackResponse.
  8. החזרת התשובה: הלקוח מקבל תגובת HTTP‏ 200 שמכילה מטען ייעודי (payload) שנוצר על ידי Gemini ב-Agent Platform.

המאמרים הבאים

  • הגדרת אימות: מטמיעים מפתחות API של Apigee,‏ OpenID Connect (‏OIDC) או JWT מאוחד לפני שרת ה-proxy כדי לאכוף מכסות אסימונים ספציפיות לדייר ואמצעי בקרת גישה של הספק.
  • מעקב אחרי העלות וזמן האחזור: מחברים את מרכזי הבקרה של Apigee Analytics לשרת ה-proxy ל-API כדי לעקוב אחרי זמן האחזור והעלויות התפעוליות לכל מודל.
  • החלת מדיניות בטיחות ספציפית לדייר: מגדירים תבניות של Model Armor לכל דייר באמצעות הפרמטר MA_TEMPLATE_PATH כדי להחיל כללי הסרת תוכן זדוני או רגיש מותאמים אישית על תנועה ארגונית, תנועה של מפתחים ותנועה ציבורית.
  • הגדרות לדוגמה: כדי להוריד את קבוצת הדוגמאות המלאה, כולל התבנית llm-fallback.yaml, שמונה קובצי תכונות, הסקריפט routing-diagnostic.sh וסקריפטים להקצאת משאבים ל-KVM, ל-Model Armor ול-Agent Platform חיפוש וקטורי, עיינו במאגר של Apigee progressive AI gateway ב-GitHub.