Blocchi di codice

Quando definisci un playbook, puoi fornire facoltativamente blocchi di codice, ovvero codice Python incorporato che può essere utilizzato per controllare meglio il comportamento dell'agente. Questo codice è composto da funzioni con decoratori speciali e da tutte le funzioni di utilità necessarie.

Quando scrivi il codice, puoi utilizzare la libreria di sistema dei blocchi di codice per controllare il comportamento dell'agente.

Problemi noti

Si applicano i seguenti problemi noti:

  • I progetti nei perimetri VPC-SC che limitano l'accesso ad Artifact Registry rifiuteranno anche i deployment di Code Block.

Limitazioni

Si applicano le seguenti limitazioni:

  • I blocchi di codice non possono contenere oggetti che persistono i dati. Tuttavia, puoi utilizzare strumenti per rendere persistenti i dati e mantenere lo stato.
  • I blocchi di codice non possono effettuare chiamate remote direttamente. Ad esempio, non puoi utilizzare la libreria requests di Python. Tuttavia, puoi utilizzare strumenti per effettuare chiamate da remoto indirettamente.
  • I nomi delle risorse convertiti in nomi Python devono essere nomi Python legali.
  • I blocchi di codice non possono leggere o scrivere i parametri di sessione, a meno che non avvenga una transizione del flusso.

Azioni in linea

Le azioni in linea si comportano in modo simile alle azioni dei tool. Hanno uno schema di input e output definito, che è determinato dalla firma della funzione Python, incluse le annotazioni di tipo e la docstring. Analogamente alle chiamate di strumenti, l'LLM non è a conoscenza del codice che implementa l'azione.

Esempio:

@Action
def is_prime(n: int): bool
  """Returns true if n is prime."""
  import math
  return (all([False for i in range(2, math.sqrt(n)
               if n % i == 0 ]) and not n < 2)

Per questa funzione, al LLM verranno fornite informazioni sull'azione, sul suo input e sul suo output.

Per fare riferimento a un'azione in linea nelle istruzioni del playbook, basta fare riferimento al nome dell'azione tra apici inversi e descrivere come deve essere utilizzata.

Esempio per un'azione in linea place_order:

Take the customer's order, then call the `place_order` action when the order is ready.

Per creare esempi che utilizzano azioni in linea, utilizza il tipo di strumento inline-action nella sezione Input e output.

Per saperne di più, consulta la documentazione di riferimento di@Action.

Funzioni di attivazione

Le funzioni di attivazione vengono utilizzate per definire azioni condizionali nel codice.

Le funzioni di trigger vengono dichiarate utilizzando i decoratori. Puoi utilizzare i seguenti decoratori di funzioni di trigger:

Decoratore Parametri del decoratore Descrizione
@EventTrigger event: str, condition: str, dove la condizione è facoltativa Attivato da un evento
@BeforeModelTrigger condition: str, dove la condizione è facoltativa Attivato ogni volta prima che l'LLM preveda l'azione successiva.
@BeforeActionTrigger condition: str, dove la condizione è facoltativa Attivato ogni volta prima che l'LLM esegua un'azione.
@BeforePlaybookTrigger condition: str, dove la condizione è facoltativa Attivato al primo avvio di un playbook.

Ad esempio, queste funzioni mostrano come utilizzare questi decoratori e i parametri dei decoratori, nonché come utilizzare la funzione di libreria di sistema del blocco di codice respond.

# No decorator parameter
@PlaybookStartTrigger
def my_playbook_conditional_action():
  respond("How can I help?")

# With a condition decorator parameter
@BeforeActionTrigger('$next-action.name = "search"')
def my_before_action_conditional_action():
  respond("One moment please")

# Event
@EventTrigger(event="welcome")
def my_welcome_event():
  respond("hi")

# Event with a condition:
@EventTrigger(event="welcome",
              condition="$sys.func.NOW().hours < 10")
def my_good_morning_event():
  respond("Good morning ☕")

Riferimenti a flussi, playbook e strumenti

Nel blocco di codice, puoi fare riferimento a flussi, playbook e strumenti specifici utilizzando le variabili globali flows, playbooks e tools.

Ognuno di questi oggetti ha membri che corrispondono ai nomi delle risorse corrispondenti. Questi nomi devono essere nomi Python legali.

Esempio:

  add_override(playbooks.troubleshooting, {})
  add_override(flows.billing)
  add_override(tools.weather_api.get_weather, {"location": "San Francisco"})

Quando fai riferimento a flussi e playbook in un blocco di codice, devi farvi riferimento anche nelle istruzioni del playbook con la seguente sintassi:

${RESOURCE_TYPE: my_resource_name}

Ad esempio, se il blocco di codice contiene flows.myflow e playbooks.myplaybook, le istruzioni del playbook devono includere:

${FLOW: myflow}
${PLAYBOOK: myplaybook}

Override delle azioni

Puoi utilizzare i blocchi di codice per creare una coda di azioni che verranno eseguite prima di qualsiasi altra azione determinata dal LLM e potenzialmente sostituirle. Crea override delle azioni utilizzando la funzione globale add_override.

Tutte le azioni di override in coda verranno eseguite in sequenza e l'output dell'azione sarà disponibile per il LLM. Una volta vuota, la coda torna all'LLM per l'azione e la selezione dell'input, a meno che un override non termini il turno con respond o un'altra funzione che completa il turno.

Argomenti della funzione:

  • azione: l'azione da eseguire. Per un'azione in linea, utilizza my_function_name. Per un'azione dello strumento, utilizza tools.my_tool_name.my_tool_action. Per un'azione di flusso, utilizza flows.my_flow_name.
  • input: input facoltativi per l'azione. Ad esempio: {"location": "Omaha"}.

Esempi:

# Assuming remote tool named "dmv" with operationId "search_offices"
# remote tool with only requestBody
add_override(tools.dmv.search_offices,{"address": "95030"})

# remote tool with only parameters
add_override(tools.pets.get_pet, {"id": "123"})

# remote tool with requestBody + parameters:
add_override(tools.pets.create_pet, {"requestBody": {"arg1":"foo"}, "param1": "bar"})

# datastore. Assumes existing datastore tool named "Menu".
add_override(tools.menu.Menu, {"query": "what is the menu"})

# code block action. Assumes another code block @Action my_action.
add_override(my_action)

Override della risposta

Simile agli override delle azioni, ma specificamente per le risposte dell'agente, puoi utilizzare la funzione globale respond per forzare l'agente a rispondere all'utente con contenuti specifici.

Esempio:

respond("Hello")

Strumenti di chiamata

Nelle funzioni del blocco di codice, puoi chiamare gli strumenti definiti per l'agente. A differenza di quando esegui l'override di un'azione dello strumento, quando chiami direttamente uno strumento, i risultati dell'esecuzione dello strumento non sono disponibili per l'LLM.

Esempi:

# Assumes existing tool named "DMV" with operationId "search_offices"
# remote tool with only request body.
offices = tools.dmv.search_offices({"address": "95030"})

# remote tool with parameters and request body
offices = tools.dmv.search_offices({"requestBody": {"address":"95030"}, "param1":"foo"})

# datastore actions. Assumes existing datastore tool named "Menu".
data = tools.menu.Menu({"query": "get the menu"})["snippets"]

Intenzione di corrispondenza

I blocchi di codice possono corrispondere in modo programmatico a un intent per un determinato flusso utilizzando la funzione Flow.match_intent.

Esempio:

matches = flows.flow1.match_intent(history.last_user_utterance).matches
if matches and matches[0].intent == "some_intent":
  to_country = matches[0].parameters.get("to_country")
  if to_country:
    respond(f"To confirm, you're going to {to_country}, right?")

Debug

Puoi utilizzare il simulatore per eseguire il debug delle funzioni del blocco di codice. Queste funzioni verranno mostrate come azioni nel simulatore e forniranno i nostri dettagli in base alle necessità.

Controllo aggiuntivo

Questa guida illustra alcuni utilizzi comuni della libreria di sistema dei blocchi di codice. Per altri tipi di controllo, consulta la documentazione della libreria.