Python-Code-Tools

Sie können Inline-Python-Code als Tool für Ihren Agenten bereitstellen, um die Funktionen Ihres Agenten zu erweitern. Dieser Code kann vom Agent bereitgestellte Eingaben akzeptieren und ein Ergebnis zurückgeben, das vom Agent in der Unterhaltung verwendet wird. Sie können benutzerdefinierte Logik implementieren, eine Verbindung zu proprietären APIs oder Datenbanken herstellen und deterministische Ergebnisse für Aufgaben erzielen, die Präzision erfordern.

Name und Beschreibung

Beim Erstellen des Tools sollten der Name des Tools und der Name der aufzurufenden Hauptfunktion identisch sein und im Snake Case-Format vorliegen.

Docstrings sind ein wichtiger Bestandteil der Definition eines Python-Tools. Der Docstring der Funktion wird als Tool-Beschreibung verwendet, die für Agents bereitgestellt wird, die das Tool nutzen. Sie sollten sich Docstrings als Erweiterung von Prompts vorstellen. Ein klarer, beschreibender und gut strukturierter Docstring wirkt sich direkt darauf aus, wie gut das Modell versteht, was Ihr Tool macht, wann es verwendet werden soll und welche Argumente angegeben werden müssen. Das ist der Schlüssel zu einer zuverlässigen und genauen Auswahl von Tools.

Umgebung

In Ihrem Python-Toolcode haben Sie Zugriff auf bestimmte Klassen und Funktionen, die Ihnen beim Schreiben des Codes helfen. Weitere Informationen finden Sie in der Python-Laufzeitreferenz.

Das context-Objekt ist beispielsweise eine global verfügbare Variable, die einen Snapshot des aktuellen Konversationsstatus enthält. Sie müssen sie nicht importieren oder als Parameter definieren, sondern können direkt darauf zugreifen. Sie enthält wertvolle Informationen für die Ausführung komplexer Logik.

Im Folgenden finden Sie eine Aufschlüsselung der verfügbaren Schlüssel im Kontextobjekt:

  • function_call_id: Eine eindeutige ID für den ausgeführten Tool-Aufruf.
  • user_content: Ein Dictionary mit der letzten Nachricht des Nutzers, einschließlich des Texts und der Rolle. Dies ist eines der am häufigsten verwendeten Attribute.
  • state: Ein Dictionary, das den Sitzungsstatus darstellt. Damit können Sie Variablen speichern und abrufen, die über mehrere Konversationsrunden hinweg bestehen bleiben müssen (z. B. Nutzerprofil oder Einkaufswageninhalte).
  • events: Eine Liste aller Ereignisse im Unterhaltungsverlauf bis zu diesem Punkt. So können Sie Tools mit komplexerem Kontextbewusstsein erstellen.
  • session_id: Die eindeutige Kennung für die gesamte Unterhaltungssitzung.
  • invocation_id: Eine eindeutige Kennung für den aktuellen Zug der Unterhaltung.
  • agent_name: Der Name des Agenten, der das Tool ausführt.

Python-Tools, die andere Tools aufrufen

Wenn Sie Python-Code-Tools definieren, können Sie explizit andere Tools aufrufen, die in der Agent-Anwendung definiert sind. Wenn Sie beispielsweise ein OpenAPI-Tool mit dem Namen crm_service_get_cart_information haben, können Sie es mit dem folgenden Code aufrufen:

# Deterministically call another tool from this tool.
# This syntax for OpenAPI spec tool is:
# tools.<tool_name>_<endpoint_name>({tool_args})
res = tools.crm_service_get_cart_information({})

Codebeispiele

In den folgenden Abschnitten finden Sie Beispiele.

Letzte Nutzereingabe abrufen

In diesem Beispiel wird eine grundlegende Funktion demonstriert: der Zugriff auf die letzte Nachricht des Nutzers. Das Tool untersucht das context.user_content-Objekt und extrahiert den Text aus der letzten Äußerung des Nutzers. Dieses Muster ist für alle Tools unerlässlich, die eine Aktion direkt auf Grundlage der letzten Äußerung des Nutzers ausführen müssen.

from typing import Optional

# Docstrings in tools are important because they are directly
# sent to the model as the description for the tool. You should
# think of docstrings as an extension of prompting. Clear and
# descriptive docstrings will yield higher quality tool
# selection from the model.
def get_last_user_utterance() -> Optional[str]:
  """
  Retrieves the most recent message sent by the user from the conversation history.

  Returns:
    The text of the last user message, or None if no user messages are found.
  """
  # The 'context.user_content' contains the last input data
  # provided by the user.
  # We can filter it to find only the text input from the user.
  user_messages = [
    part["text"] for part in context.user_content["parts"]
    if context.user_content["role"] == "user"
  ]

  if user_messages:
    # The most recent message is the first one in the list.
    return user_messages[0]

  return None

Variablen abrufen und aktualisieren

Sprachmodelle können den Sitzungsstatus nicht direkt ändern. Das ist so gewollt, da so sichergestellt wird, dass Statusänderungen kontrolliert und vorhersehbar erfolgen. Der Status kann nur über zwei Mechanismen geändert werden: Python-Tools oder Callbacks.

In diesem Beispiel wird gezeigt, wie ein Python-Tool den Status verwalten kann. Das Tool liest zuerst die aktuelle customer_profile aus context.state. Anschließend wird die Geschäftslogik ausgeführt (Punkte werden hinzugefügt) und das aktualisierte Profil wird in „context.state“ zurückgeschrieben. Dieser neue Status ist dann für den Agent und andere Tools für den Rest der Sitzung verfügbar.

from pydantic import BaseModel, Field
from typing import Optional, Dict, Any

# Using Pydantic defines the expected structure of your state variables. This makes your code more reliable and easier to
# debug.
class CustomerProfile(BaseModel):
  email: Optional[str] = None
  loyalty_points: int = Field(default=0, ge=0) # Must be >= 0
  plan: str = "Standard"

# Docstrings in tools are important because they are directly
# sent to the model as the description for the tool. You should
# think of docstrings as an extension of prompting. Clear and
# descriptive docstrings will yield higher quality tool
# selection from the model.
def update_customer_loyalty_points(points_to_add: int) -> Dict[str, Any]:
  """
  Adds loyalty points to the customer's profile and returns the updated profile.

  Args:
    points_to_add: The number of loyalty points to add to the existing total.

  Returns:
    A dictionary containing the customer's updated profile information.
  """
  # 1. Get the current profile data from the session state.
  # The .get() method safely returns an empty dict if
  # 'customer_profile' doesn't exist.
  current_profile_data = context.state.get("customer_profile", {})

  # 2. Load the data into a Pydantic model for validation and easy access.
  profile = CustomerProfile(**current_profile_data)

  # 3. Perform the business logic.
  # Print statements can be used for debugging and will show
  # up in the tracing details.
  profile.loyalty_points += points_to_add
  print(f"Updated loyalty points to: {profile.loyalty_points}")

  # 4. Save the updated data back into the session state.
  # .model_dump() converts the Pydantic model back to a
  # dictionary.
  context.state["customer_profile"] = profile.model_dump()

  return context.state["customer_profile"]

Externe Netzwerkanfragen

Python-Tools können externe Netzwerkanfragen stellen. Das ist nützlich, um Echtzeitdaten abzurufen oder Drittanbieterdienste einzubinden, für die keine OpenAPI-Spezifikation vorhanden ist. Dies ist eine flexible Alternative zur Verwendung von OpenAPI-basierten Tools. Im Beispiel wird die Standardbibliothek „requests“ (in der Umgebung verfügbar) verwendet, um eine öffentliche API aufzurufen und einen zufälligen Fakt abzurufen.

from typing import Optional

# Docstrings in tools are important because they are directly sent to the model as the
# description for the tool. You should think of docstrings as an extension of prompting.
# Clear and descriptive docstrings will yield higher quality tool selection from the model.

def get_random_fact() -> Optional[str]:
  """
  Fetches a random fact from a public API.

  Returns:
      A string containing the fact on success, or None if an error occurs.
  """
  # The 'ces_requests' library is inspired by 'requests', a  standard and powerful way in Python
  # to make HTTP network calls to any external API, just like you would with `curl` or a web browser.
  url = "https://uselessfacts.jsph.pl/api/v2/facts/random"

  try:
      # This example calls a public API that is completely open and requires no authentication
      # (like an API key). Many other APIs for services like weather or e-commerce require you
      # to send credentials, often as an API key in the request headers or parameters.
      res = ces_requests.get(url=url, json=request_body, headers=headers)

      # Example POST request
      #res = ces_requests.post(url=url, json=request_body, headers=headers)

      # This is a standard practice with 'ces_requests' to check if the call was successful. It will
      # raise an error for statuses like 404 or 500.
      res.raise_for_status()

      fact_data = res.json()
      return fact_data.get("text")

  except:
      return None