Blocos de código

Ao definir um playbook, é possível fornecer blocos de código, que são códigos Python inline usados para controlar melhor o comportamento do agente. Esse código é composto por funções com decoradores especiais e todas as funções utilitárias necessárias.

Ao escrever seu código, você pode usar a biblioteca do sistema de blocos de código para controlar o comportamento do agente.

Problemas conhecidos

Os seguintes problemas conhecidos se aplicam:

  • Projetos em perímetros do VPC-SC que restringem o acesso ao Artifact Registry também vão rejeitar implantações de blocos de código.

Limitações

Considere as seguintes limitações:

  • Os blocos de código não podem conter objetos que mantêm dados. No entanto, é possível usar ferramentas para manter dados e estados.
  • 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 para nomes do Python precisam ser válidos.
  • Os blocos de código não podem ler nem gravar parâmetros de sessão, a menos que ocorra uma transição de fluxo.

Ações in-line

As ações inline funcionam de maneira semelhante às ações de ferramentas. 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."""
  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 mencionar o nome da ação entre crases 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 Entrada e saída.

Para mais informações, consulte a documentação de referência @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 acionamento são declaradas usando decoradores. Você pode usar os seguintes decoradores de função de acionamento:

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 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 da biblioteca do sistema de bloco 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 fazer referência a fluxos, playbooks e ferramentas

No bloco de código, você pode 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 legais 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, você também precisa 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 serão realizadas 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 na fila serão executadas em sequência, e a saída da ação vai estar disponível para o LLM. Quando a fila está vazia, a operação retorna ao LLM para ação e seleção de entrada, a menos que uma substituição termine o turno com respond ou outra função que conclua o turno.

Argumentos de função:

  • action: a ação a ser realizada. Para uma ação in-line, 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

Semelhante às substituições de ação, mas especificamente para respostas do agente, você pode 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 chamada

Nas funções do bloco de código, você pode chamar as ferramentas definidas para seu 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.

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

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

Depuração

Você pode usar o simulador para depurar as funções de bloco de código. Essas funções vão aparecer como ações no simulador, e elas vão 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.