Blocos de código

Ao definir um playbook, você pode fornecer blocos de código, que são códigos Python inline que podem ser usados para controlar melhor o comportamento do agente. Esse código é composto por funções com decoradores especiais e quaisquer funções de utilitário necessárias.

Ao escrever seu código, use a biblioteca do sistema de bloco de código para controlar o comportamento do agente.

Limitações

Considere as seguintes limitações:

  • Os blocos de código não podem conter objetos que persistem dados. No entanto, é possível usar ferramentas para manter os dados e o estado.
  • Os blocos de código não podem fazer chamadas remotas diretamente. Por exemplo, não é possível usar a biblioteca de solicitações do Python. No entanto, é possível usar ferramentas para fazer chamadas remotas indiretamente.
  • Os nomes de recursos convertidos em nomes do Python precisam ser nomes válidos do Python.
  • Os blocos de código não podem ler nem gravar parâmetros de sessão, a menos que uma transição de fluxo ocorra.
  • Quando um bloco de código usa uma ferramenta OpenAPI e recebe um código de status HTTP diferente de 200, ele falha, e não há como detectar o erro.

Ações inline

As ações inline se comportam de maneira semelhante às ações de ferramenta. Elas têm um esquema de entrada e saída definido, que é determinado pela assinatura da função Python, incluindo anotações de tipo e docstring. Assim como nas chamadas de ferramentas, o LLM não conhece o código que implementa a ação.

Exemplo:

@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)

Para essa função, o LLM vai receber informações sobre a ação, a entrada e a saída dela.

Para fazer referência a uma ação inline nas instruções do playbook, basta referenciar o nome da ação entre chaves angulares e descrever como ela deve ser usada.

Exemplo de uma ação in-line place_order:

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

Para criar exemplos que usam ações inline, use o tipo de ferramenta inline-action na seção Input & Output.

Para mais informações, consulte a documentação de referência do @Action.

Funções de acionamento

As funções de acionamento são usadas para definir ações condicionais no código.

As funções de gatilho são declaradas usando decoradores. Você pode usar os seguintes decoradores de função de gatilho:

Decorador Parâmetros do decorador Descrição
@EventTrigger event: str, condition: str, em que a condição é opcional Acionada por um evento
@BeforeModelTrigger condition: str, em que a condição é opcional Acionada sempre que o LLM prevê a próxima ação.
@BeforeActionTrigger condition: str, em que a condição é opcional Acionado sempre que o LLM executa uma ação.
@BeforePlaybookTrigger condition: str, em que a condição é opcional Acionado na primeira vez que um playbook é iniciado.

Por exemplo, essas funções mostram como usar esses decoradores e parâmetros de decorator, além de como usar a função respond da biblioteca de sistema de bloco de código.

# 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 ☕")

Como fazer referência a fluxos, playbooks e ferramentas

No bloco de código, é possível fazer referência a fluxos, playbooks e ferramentas específicos usando as variáveis globais flows, playbooks e tools.

Cada um desses objetos tem membros que correspondem aos nomes dos recursos correspondentes. Esses nomes precisam ser nomes válidos do Python.

Exemplo:

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

Ao fazer referência a fluxos e playbooks em um bloco de código, também é necessário fazer referência a eles nas instruções do playbook com a seguinte sintaxe:

${RESOURCE_TYPE: my_resource_name}

Por exemplo, se o bloco de código contiver flows.myflow e playbooks.myplaybook, as instruções do playbook precisarão incluir:

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

Substituições de ação

É possível usar blocos de código para criar uma fila de ações que vai ocorrer antes de outras ações determinadas pelo LLM e, possivelmente, substituí-las. Para criar substituições de ação, use a função global add_override.

Todas as ações de substituição em fila serão executadas sequencialmente, e a saída da ação vai estar disponível para o LLM. Quando a fila fica vazia, a operação retorna ao LLM para ação e seleção de entrada, a menos que uma substituição termine a vez com responder ou outra função que conclua a vez.

Argumentos de função:

  • action: a ação a ser realizada. Para uma ação inline, use my_function_name. Para uma ação de ferramenta, use tools.my_tool_name.my_tool_action. Para uma ação de fluxo, use flows.my_flow_name.
  • inputs: entradas opcionais para a ação. Por exemplo, {"location": "Omaha"}.

Amostras:

# 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)

Substituições de resposta

Assim como as substituições de ação, mas especificamente para respostas do agente, é possível usar a função global respond para forçar o agente a responder ao usuário com conteúdo específico.

Exemplo:

respond("Hello")

Ferramentas de ligação

Nas funções do bloco de código, é possível chamar as ferramentas definidas para o agente. Ao contrário de quando você substitui uma ação de ferramenta, ao chamar uma ferramenta diretamente, os resultados da execução da ferramenta não estão disponíveis para o LLM.

Amostras:

# 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"]

Corresponder à intenção

Os blocos de código podem corresponder de forma programática a uma intent para um determinado fluxo usando a função Flow.match_intent.

Exemplo:

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?")

Depuração

Você pode usar o simulador para depurar as funções do bloco de código. Essas funções vão aparecer como ações no simulador e fornecerão os detalhes conforme necessário.

Controle extra

Este guia aborda alguns usos comuns da biblioteca do sistema de blocos de código. Para outros tipos de controle, consulte a documentação da biblioteca.