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 as funções utilitárias que você precisar.

Ao escrever seu código, você pode usar a biblioteca do sistema de blocos 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 persistam dados. No entanto, é possível usar ferramentas para persistir dados e manter 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 gravar parâmetros de sessão, a menos que ocorra uma transição de fluxo.

Ações inline

As ações inline se comportam de maneira semelhante às ações de ferramenta. Eles 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."""
  if not isinstance(n, int) or n < 2:
    return False

  for i in range(2, int(n ** 0.5) + 1):
    if n % i == 0:
      return False

  return True

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

Para referenciar uma ação inline nas instruções do playbook, basta referenciar o nome da ação entre aspas simples e descrever como ela deve ser usada.

Exemplo de uma ação inline 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 Entrada e saída.

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

Funções de gatilho

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. É possível 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 Acionado sempre antes de o LLM prever a próxima ação.
@BeforeActionTrigger condition: str, em que a condição é opcional Acionado sempre antes de o LLM executar 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 decorador, além de como usar a função de biblioteca do sistema de blocos de código 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 ☕")

Como referenciar fluxos, playbooks e ferramentas

No bloco de código, é possível referenciar 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 referenciar fluxos e playbooks em um bloco de código, você também precisa referenciá-los nas instruções do playbook com a seguinte sintaxe:

${RESOURCE_TYPE: my_resource_name}

Por exemplo, se o bloco de código tiver flows.myflow e playbooks.myplaybook, as instruções do playbook precisam 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 vão ocorrer antes de qualquer outra ação determinada 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 estará disponível para o LLM. Quando a fila estiver vazia, a operação retornará ao LLM para seleção de ação e entrada, a menos que uma substituição encerre a vez com respond ou outra função que encerre a vez.

Argumentos de função:

  • action: a ação que vai ocorrer. 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"}.

Exemplos:

# 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

Semelhante às 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 um conteúdo específico.

Exemplo:

respond("Hello")

Ferramentas de chamada

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

Exemplos:

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

Intenção de correspondência

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

Ler parâmetros de sessão

Os blocos de código podem ler parâmetros disponíveis no momento da execução.

Exemplo:

state["$session.params.my-param"]
state["$request.session-id"]

Depuração

É possível 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 nossos detalhes conforme necessário.

Controle adicional

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.