התקשרות חזרה

פונקציות Callback הן תכונה מתקדמת שמספקת מנגנון יעיל לחיבור לתהליך ההפעלה של סוכן ספציפי באמצעות קוד Python. הן מאפשרות לכם לצפות בהתנהגות של הסוכן, להתאים אותה אישית ואפילו לשלוט בה בנקודות ספציפיות ומוגדרות מראש.

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

‫Python runtime ושיעורים

בקוד הקריאה החוזרת של Python, יש לכם גישה לפונקציות ולמחלקות מסוימות שיעזרו לכם לכתוב את הקוד. מידע נוסף זמין במאמר בנושא זמן הריצה של Python.

מגבלות של ארגז חול ורשת

קוד Python של פונקציית Callback מופעל בסביבת ארגז חול. יש בסביבה הזו את המגבלות הבאות:

  • אין גישה לרשת פרטית (PNA): קריאות חוזרות לא יכולות לגשת ישירות לכתובות IP פרטיות או לפתור דומייני DNS פרטיים, גם אם Service Directory מוגדר. אם אתם צריכים לגשת למשאבים ברשת פרטית, אתם צריכים להשתמש בכלי שתומך בגישה לרשת פרטית (כמו כלי OpenAPI או MCP).
  • גישה לאינטרנט הציבורי: קריאות חוזרות יכולות לגשת רק לנקודות קצה שזמינות לכולם באינטרנט.

סוגי שיחות חוזרות

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

כל סוג של callback מופעל בשלב ספציפי בתור לשיחה:

תהליך הקריאה החוזרת

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

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

X X
שם שם פונקציית הקריאה החוזרת הנדרשת
הרצה נקודת הביצוע בתוך תור השיחה.
מטרה תרחישים שימושיים לשימוש בקריאה החוזרת.
ארגומנטים ארגומנטים של קלט לפונקציה.
חזור הערך שהפונקציה מחזירה.
קריאה חוזרת (callback) של ADK קישור למסמכי התיעוד של הקריאה החוזרת (callback) המתאימה ב-ADK.

לפני שהסוכן מתחיל (before_agent_callback)

X X
שם before_agent_callback
הרצה הפעולה נקראת לפני הפעלת הסוכן.
מטרה האפשרות הזו שימושית להגדרת משאבים או מצב שנדרשים לסוכן, לביצוע בדיקות אימות של מצב הסשן או למניעת הפעלה של הסוכן.
ארגומנטים CallbackContext
חזור תוכן(אופציונלי): אם ההגדרה הזו מוגדרת, הסוכן לא מופעל והתגובה שסופקה משמשת.
קריאה חוזרת (callback) של ADK לפני שהנציג/ה יחזרו אליך

קוד לדוגמה:

import random

def before_agent_callback(
  callback_context: CallbackContext
) -> Optional[Content]:
  username = callback_context.variables.get("username", None)
  if not username:
    # default user
    final_name = "Default Name"
  else:
    # add a random integer to the username
    final_name = f"{username} {random.randint(1,10)}"
  # update the username variable
  callback_context.variables["username"] = final_name

אחרי שהסוכן מסיים (after_agent_callback)

X X
שם after_agent_callback
הרצה הפונקציה נקראת אחרי שהסוכן משלים את הפעולה.
מטרה התכונה הזו שימושית למשימות ניקוי, לאימות אחרי ההפעלה, לשינוי המצב הסופי או לעדכון התגובה של הסוכן.
ארגומנטים CallbackContext
חזור תוכן(אופציונלי): אם מציינים תוכן, הפלט של הסוכן יוחלף בפלט שצוין.
קריאה חוזרת (callback) של ADK אחרי שהסוכן יחזור ללקוח

קוד לדוגמה:

def after_agent_callback(
  callback_context: CallbackContext
) -> Optional[Content]:
  if callback_context.agent_name == "Routing Agent":
    counter = callback_context.variables.get("counter", 0)
    counter += 1
    # increment the invoked counter for this agent
    callback_context.variables["counter"] = int(counter)

לפני קריאה למודל שפה גדול (before_model_callback)

X X
שם before_model_callback
הרצה הפונקציה מופעלת לפני בקשת המודל.
מטרה האפשרות הזו שימושית לבדיקה או לשינוי של בקשת המודל, או כדי להימנע משימוש במודל.
ארגומנטים CallbackContext, ‏ LlmRequest
חזור ‫LlmResponse: אם הערך מוגדר, המערכת מדלגת על קריאת המודל ומשתמשת בתשובה כאילו היא הגיעה מהמודל.
קריאה חוזרת (callback) של ADK before model callback

קוד לדוגמה:

def before_model_callback(
  callback_context: CallbackContext,
  llm_request: LlmRequest
) -> Optional[LlmResponse]:
  """
  This callback executes *before* a request is sent to the LLM.

  By returning an `LlmResponse` object, we are intercepting the call to the
  LLM. The LLM will *not* be called, and the framework will instead use the
  `LlmResponse` we provide as if it came from the model.

  This is the core mechanism for implementing input guardrails, prompt
  validation, or serving responses from a cache. Here, we force the agent to
  call a function instead of thinking with the LLM.
  """
  # Modify the shared session state.
  callback_context.variables['foo'] = 'baz'

  # Skip the LLM call and return a custom response telling the agent to
  # execute a specific function.
  return LlmResponse(
    content=Content(parts=[Part(
      function_call=FunctionCall(
        name="function_name", args={"arg_name": "arg_value"}))],
      role="model"))

אחרי שיחה עם LLM‏ (after_model_callback)

X X
שם after_model_callback
הרצה הפונקציה מופעלת אחרי קבלת תשובה מהמודל.
מטרה הכלי הזה שימושי לשינוי הפורמט של תשובות המודל, לצנזור מידע רגיש שנוצר על ידי המודל, לניתוח נתונים מובְנים מהמודל לשימוש במשתנים ולטיפול בשגיאות במודל.
ארגומנטים CallbackContext, ‏ LlmResponse
חזור ‫LlmResponse: אם ההגדרה הזו מוגדרת, התשובה של המודל מוחלפת בתשובה שצוינה.
קריאה חוזרת (callback) של ADK אחרי קריאה חוזרת (callback) של המודל

קוד לדוגמה:

def after_model_callback(
  callback_context: CallbackContext,
  llm_response: LlmResponse
) -> Optional[LlmResponse]:
  """
  This callback executes *after* a response has been received from the LLM,
  but before the agent processes it.

  The `llm_response` parameter contains the actual data from the LLM.
  By returning `None`, we are approving this response and allowing the agent
  to use it as-is.

  If we returned a new `LlmResponse` object, it would *replace* the original,
  which is useful for redacting sensitive information, enforcing output
  formatting, or adding disclaimers.
  """
  # Returning None allows the LLM's actual response to be used.
  return None

לפני קריאה לכלי (before_tool_callback)

X X
שם before_tool_callback
הרצה הקריאה מתבצעת לפני קריאות לכלי.
מטרה האפשרות הזו שימושית לבדיקה ולשינוי של ארגומנטים של כלים, לבדיקות הרשאה לפני הפעלת כלי או להטמעה של שמירת נתונים במטמון ברמת הכלי.
ארגומנטים ‫Tool, ‏ Dict[str,Any]: קלט של כלי, CallbackContext
חזור ‫Dict[str,Any] : אם מוגדר, דילוג על הפעלת הכלי והפלט הזה מסופק למודל.
קריאה חוזרת (callback) של ADK לפני הקריאה החוזרת של הכלי

קוד לדוגמה:

def before_tool_callback(
  tool: Tool,
  input: dict[str, Any],
  callback_context: CallbackContext
) -> Optional[dict[str, Any]]:
  """
  This callback executes *before* a specific tool is called by the agent.

  Here, we modify the input arguments intended for the tool and then return
  a dictionary. By returning a dictionary instead of `None`, we are
  overriding the default behavior. The actual tool function will *not* be
  executed. Instead, the dictionary we return will be treated as the
  llm.tool's result and passed back to the LLM for the next step.

  This is ideal for validating tool inputs, applying policies, or returning
  mocked/cached data for testing.
  """
  # Modify the shared session state.
  callback_context.variables['foo'] = 'baz'

  # Modify the arguments for the tool call in-place.
  input['input_arg'] = 'updated_val1'
  input['additional_arg'] = 'updated_val2'

  # Override the tool call and return a mocked result.
  return {"result": "ok"}

אחרי קריאה לכלי (after_tool_callback)

X X
שם after_tool_callback
הרצה הפונקציה נקראת אחרי שהכלי מסיים את הפעולה.
מטרה הכלי הזה שימושי לבדיקה ולשינוי של תשובת הכלי לפני ששולחים אותה בחזרה למודל, לעיבוד שלאחר קבלת תוצאות הכלי או לשמירה של חלקים ספציפיים בתשובת הכלי במשתנים.
ארגומנטים ‫Tool, ‏ Dict[str,Any]: קלט של כלי, CallbackContext, ‏ Dict[str,Any]: תגובה של כלי
חזור Dict[str,Any]: אם מוגדר, מחליף את התשובה של הכלי שמועברת למודל.
קריאה חוזרת (callback) של ADK אחרי קריאה חוזרת לכלי

קוד לדוגמה:

# Previous tool was named `get_user_info`
# Previous tool returned the payload:
# {"username": "Patrick", "fave_food": ["pizza"]}

def after_tool_callback(
  tool: Tool,
  input: dict[str, Any],
  callback_context: CallbackContext,
  tool_response: dict
) -> Optional[dict]:

  if tool.name == "get_user_info":
    tool_response["username"] = "Gary"
    tool_response["pet"] = "dog"

    # Override tool response
    return tool_response

פעולות ספציפיות לערוץ ולסוג המדיה

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

יצירת בקשה לחזרה לשיחה

כדי ליצור קריאה חוזרת:

  1. פותחים את הגדרות הסוכן.
  2. לוחצים על הוספת קוד.
  3. בוחרים סוג של בקשה להחזרת שיחה.
  4. תספק קוד Python.
  5. לוחצים על Save.

מטענים ייעודיים (payloads) בהתאמה אישית (custom_payloads)

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

ערך המטען הייעודי (payload) לא גלוי למודל השפה הגדול (LLM), הוא משמש רק ליצירת התשובה הסופית. מטענים ייעודיים (payloads) מותאמים אישית נוצרים ומוגדרים באמצעות קריאות חוזרות (callbacks), ובאופן ספציפי באמצעות before_model_callback או after_model_callback.

אפשר להשתמש במטען הייעודי (payload) למגוון מטרות, בדרך כלל כדי לאפשר אינטראקציות עשירות ומובנות:

  • העברה לטיפול של נציג/העברה: העברה של אינטראקציה לנציג אנושי באמצעות מתן הוראות ניתוב (לדוגמה, התור הספציפי לניתוב).
  • תוכן עשיר ופעולות בצד הלקוח: הוא תומך בהטמעה של ווידג'טים עשירים ותוכן עשיר אחר ישירות בצ'אטים, מה שימושי במיוחד לשילובים מותאמים אישית של צ'אטים.
    • דוגמאות כוללות הצגת כתובות URL של תמונות או אפשרויות ותגי תשובה מהירה ללקוח באמצעות ממשק כמו call companion.
  • Response Composition (הרכב התגובה): אפשר להגדיר החזרות של מטען ייעודי (payload) מותאם אישית במגוון דרכים:
    • החזרת מטען ייעודי (payload) מפורש בלבד באופן דטרמיניסטי.
    • החזרת מטען ייעודי (payload) יחד עם תשובת טקסט שנוצרה על ידי LLM.
    • החזרת המטען הייעודי (payload) עם תשובה בטקסט סטטי

הגדרת הסוכן

אפשר ליצור ולהגדיר מטען ייעודי (payload) בהתאמה אישית רק באמצעות קריאות חוזרות (callback). המטען הייעודי מוגדר כ-Blob עם mime_type של application/json.

Part.from_json(data=payload_string)

דוגמה ל-after_model_callback

זוהי דוגמה ל-after_model_callback שמחזירה את תגובת המודל יחד עם תגובת מטען ייעודי (payload) נוסף בהתאמה אישית.

import json

def after_model_callback(callback_context: CallbackContext, llm_response: LlmResponse) -> Optional[LlmResponse]:
 """
 Adds a custom payload to every model response which is a text
 """
 if (llm_response.content.parts[0].text is not None):
   # construct payload
   payload_dict = { "custom_payload_key": "custom_payload_value"}
   payload_json_string = json.dumps(payload_dict)

   new_parts = []
   # Keep the origial agent response part, as model only sees text in the historical context.
   new_parts.append(Part(text=llm_response.content.parts[0].text))

   # Append custom payload
   new_parts.append(Part.from_json(data=payload_json_string))

   return LlmResponse(content=Content(parts=new_parts))

דוגמה ל-before_model_callback

זוהי דוגמה ל-before_model_callback שמחזירה מטען ייעודי (payload) מותאם אישית נוסף אחרי הפעלה של כלי מסוים.

import json

def has_escalate(llm_request: LlmRequest) -> bool:
  for content in llm_request.contents:
    for part in content.parts:
      if part.function_call and part.function_call.name == 'escalate':
        return True
  return False

def before_model_callback(callback_context: CallbackContext, llm_request: LlmRequest) -> Optional[LlmResponse]:
  # checks if `escalate` tool is being called
  if not has_escalate(llm_request):
    return None
  payload_dict = { "escalate": "user ask for escalation"}
  payload_json_string = json.dumps(payload_dict)

  return LlmResponse(content=Content(parts=[Part(text="ESCALATE!!!"), Part.from_json(data=payload_json_string)]))

אימות מטען ייעודי (payload) בתגובה בזמן ריצה

המטען הייעודי (payload) מאוכלס כ-Struct בשדה payload גם ב-RunSession וגם ב-BidiRunSession.

ערך המטען הייעודי (payload) לא גלוי ל-LLM.