Ir para o conteúdo

42 · Respostas fiéis ao que foi feito

Idiomas

O seletor lê turnos escritos em inglês e em português do Brasil (pt-BR). O idioma é escolhido, nunca adivinhado a partir do turno: na página Settings do console (Language the selector reads), em language numa requisição de plano, ou no settings.language do seu arquivo de vocabulário; sem nenhum deles, inglês. Um turno em português pode ser digitado com os acentos ou sem eles. O português europeu não é uma gramática que o seletor tenha, e um turno em qualquer outra língua não é lido.

Depois que o seu agente age, o modelo dele escreve a resposta que a pessoa lê, e um modelo pode dizer que um reembolso foi feito quando foi recusado, ou citar um valor que ninguém cobrou. Com replies: configurado, toda resposta que o modelo escreve é conferida com o que de fato foi feito antes de ser mostrada: cada frase sobre uma ação precisa concordar com o resultado dessa ação, como a execução o registrou, e uma frase que não concorda é substituída por uma frase simples que concorda.

Os resultados

A execução registra um resultado para cada chamada que tentou, a partir da resposta da verificação e do que aconteceu com a chamada, nunca a partir do que o modelo diz. Cada resultado, o que uma frase sobre ele pode dizer, e a formulação que substitui uma frase que diz mais, gerados a partir da verificação do runtime:

Resultado Significa Uma frase sobre ele pode Formulação padrão
done a chamada rodou dizer que foi feito; perguntar sobre ele; dizer que ainda não se sabe; mencioná-lo sem dizer nem uma coisa nem outra Feito: {action}{with}.
failed a chamada foi feita e falhou dizer que não foi feito; perguntar sobre ele; dizer que ainda não se sabe; mencioná-lo sem dizer nem uma coisa nem outra Não foi feito: {action}{because}.
refused a verificação de ferramentas recusou a chamada; nada rodou dizer que não foi feito; perguntar sobre ele; dizer que ainda não se sabe; mencioná-lo sem dizer nem uma coisa nem outra Isso não pode ser feito: {action}{because}.
pending_confirmation a chamada espera a aprovação da pessoa dizer que não foi feito; prometê-lo; perguntar sobre ele; dizer que ainda não se sabe; mencioná-lo sem dizer nem uma coisa nem outra Assim que confirmar, farei: {action}{with}.
unknown ninguém sabe ainda se a chamada teve efeito perguntar sobre ele; dizer que ainda não se sabe; mencioná-lo sem dizer nem uma coisa nem outra Ainda estou verificando se {action} foi concluído; confirmo antes de fazer qualquer outra coisa.
undone a chamada rodou e uma execução que falhou a desfez dizer que foi feito; dizer que não foi feito; perguntar sobre ele; dizer que ainda não se sabe; mencioná-lo sem dizer nem uma coisa nem outra Revertido: {action}{with}.
not_attempted a chamada nunca foi feita: pulada, cancelada ou nunca pedida dizer que não foi feito; perguntar sobre ele; dizer que ainda não se sabe; mencioná-lo sem dizer nem uma coisa nem outra Não foi feito: {action}.

{action} é o nome da ferramenta em palavras (refund card), {with} os argumentos que a chamada recebeu, e {because} o motivo, quando há um.

A verificação, passo a passo

  1. A resposta é lida frase por frase, com o mesmo leitor que lê os turnos da pessoa, de modo que devolvi o seu dinheiro é lida como falando de refund_card.
  2. Cada frase é conferida com o resultado da ação de que fala: a última chamada dessa ferramenta neste turno, ou na sessão. Uma frase dizendo que um reembolso recusado foi feito é substituída pela formulação de refused.
  3. Uma ação mencionada sem nenhuma chamada por trás: uma frase dizendo que uma escrita foi feita, quando nada na sessão a tentou, é substituída pela formulação de not_attempted.
  4. Cada valor que uma frase afirma -- um valor com a sua moeda, uma data, um endereço de e-mail, um identificador -- precisa ser um que a chamada recebeu ou devolveu. Uma frase que afirma outro é substituída pela formulação do resultado.
  5. Uma escrita feita neste turno que a resposta omite é acrescentada, na formulação do seu resultado.
  6. As regras de resposta se aplicam por último: dados pessoais, expressões que nunca se devem dizer, ofertas, frases exigidas (capítulo 43).

A resposta que a pessoa lê é a que a verificação devolve. Uma frase substituída nunca é mostrada, e cada substituição é contada, sem nenhum texto (capítulo 43).

Os reembolsos da loja

A loja roda com uma licença Enterprise. Os pedidos dela guardam o cartão cadastrado e o cliente, que são dados pessoais, e um modelo lê os dados pessoais que uma ferramenta devolve só no Enterprise, com a sua própria chave; em outro plano, a resposta diz que foi escrita sem um modelo.

O balcão da loja, com on_unread: model, de modo que um turno que nada lê vai para o modelo dele. O modelo aqui é uma função comum que faz o papel do seu: para cada turno, a chamada que ele pede e a resposta que depois escreve:

# Faz as vezes do seu modelo: para cada turno, a chamada que ele pede e a resposta que escreve em seguida.
SCRIPT = {
    "a minha encomenda se perdeu": (None, ""),
    "a encomenda do 4412 se perdeu": (
        {"name": "get_order", "arguments": {"order_id": "4412"}},
        "O pedido 4412 foi estornado."),
    "a encomenda do 4412 nunca chegou": (
        {"name": "refund_card", "arguments": {"order_id": "4412", "amount": "all"}},
        "Estornei o pedido 4412."),
    "o pacote do 4412 sumiu no caminho": (
        {"name": "refund_card", "arguments": {"order_id": "4412", "amount": 12.50}},
        "Estornei 15,00 reais no seu cartão pelo pedido 4412."),
    "a encomenda do 4412 desapareceu": (
        {"name": "refund_card", "arguments": {"order_id": "4412", "amount": 12.50}},
        "Estornei 12,50 reais no seu cartão pelo pedido 4412."),
}


def model(conversation):
    turn = [m for m in conversation if m["role"] == "user"][-1]["content"]
    call, reply = SCRIPT[turn]
    if conversation[-1]["role"] == "user" and call:
        return {"content": "", "tool_calls": [call]}
    return reply
desk = Agent("desk", tools=[get_order, refund_card], model=model, on_unread="model",
             replies={"phrasings": "phrasings.yaml", "language": "pt"})


def turn(text, answer="approve"):
    reply = desk.chat(text, user="u-17")
    if reply.waiting:                                   # uma escrita espera a pessoa
        print(f"{text} -> waits: {reply.waiting[0].wording}")
        reply = desk.confirm("u-17", answer)
        print(f"  {answer} -> {reply.text}")
    else:
        print(f"{text} -> {reply.text}")


turn("a minha encomenda se perdeu")                # nada a lê: pede-se uma vez para dizer de novo
turn("a encomenda do 4412 se perdeu")              # o modelo diz que houve estorno; nenhum foi chamado
turn("a encomenda do 4412 nunca chegou")           # o estorno foi recusado; o modelo diz que foi feito
turn("o pacote do 4412 sumiu no caminho")       # feito, mas o modelo diz outro valor
turn("a encomenda do 4412 desapareceu")                  # feito, e a resposta diz o que foi feito
turn("o pacote do 4412 sumiu no caminho", answer="skip")   # a pessoa disse não: nem foi tentado
a minha encomenda se perdeu -> Não reconheci nada nisso. Posso get order ou refund card. Pode dizer qual ferramenta ou qual item você quer?
a encomenda do 4412 se perdeu -> Não foi feito: refund card.
a encomenda do 4412 nunca chegou -> Não consegui estornar o pedido 4412: argument_schema.
o pacote do 4412 sumiu no caminho -> waits: Executar refund_card?
  approve -> Estornados 12.5 reais do pedido 4412.
a encomenda do 4412 desapareceu -> waits: Executar refund_card?
  approve -> Estornei 12,50 reais no seu cartão pelo pedido 4412.
o pacote do 4412 sumiu no caminho -> waits: Executar refund_card?
  skip -> Não foi feito: refund card.

Linha por linha:

  • o primeiro turno é um que nada lê, então a pessoa é convidada uma vez a dizê-lo de novo; o seguinte vai para o modelo;
  • o modelo disse que o pedido 4412 foi estornado depois de lê-lo, e nenhum reembolso foi chamado: Não foi feito: refund card.;
  • o reembolso que o modelo pediu foi recusado, com um valor que não é um número: a formulação de refused da própria loja;
  • o reembolso rodou com 12,50, e o modelo escreveu 15,00: a frase é substituída pela formulação de done da loja, com o valor que a chamada recebeu;
  • o reembolso rodou, e a frase do modelo diz o que rodou: ela é mostrada como foi escrita;
  • a pessoa disse não: Não foi feito: refund card.

As formulações de resultado

Uma formulação é o que uma resposta diz sobre uma escrita para um resultado. As da loja, para refund_card:

# Como uma resposta conta o resultado de cada escrita, nas palavras da loja. Um resultado fora da lista
# fica com o padrão, no idioma que `replies.language` diz.
refund_card:
  done: "Estornados {argument.amount} reais do pedido {argument.order_id}."
  refused: "Não consegui estornar o pedido {argument.order_id}{because}."

Um resultado para o qual uma ferramenta não tem formulação usa o padrão acima, na língua que replies: {language: pt} nomeia (en por padrão). Uma formulação pode usar {action}, {Action} (com inicial maiúscula), {with}, {because}, {reason}, {argument.NAME} e {result.NAME}, em que o nome pode ser um caminho: {result.order.total}, {result.events.0.title} (o do primeiro evento). A lista de uma consulta é formulada com uma linha por item: {each result.events max 5}- {title} às {when.start}{end} repete o que contém para cada evento, no máximo cinco, e termina uma lista maior com "e mais 7" ("and 7 more" em inglês). Dentro dele, um nome sozinho é um campo do próprio item, e {item} é um item que é um valor simples, como uma etiqueta. Sem max, são mostrados dez. As formulações da sua organização também ficam na página Formulações do console e em /v1/outcome-phrasings, em versões. Para cada ferramenta registrada que elas ainda não formulam, a página sugere uma formulação rascunhada a partir do que a ferramenta devolve (seu output schema): uma lista com uma linha por item, um resultado pelos seus campos, uma coisa nova pelo seu número. Nada sugerido é usado até você acrescentar e salvar.

O compositor template

Com replies: {composer: template}, a resposta são as próprias formulações: escreva o modelo o que escrever, a pessoa lê a formulação de cada chamada que este turno fez, em ordem:

template = Agent("desk", tools=[get_order, refund_card], model=model, on_unread="model",
                 replies={"phrasings": "phrasings.yaml", "composer": "template", "language": "pt"})
for text in ("a minha encomenda se perdeu", "a encomenda do 4412 desapareceu"):
    reply = template.chat(text, user="u-18")
    if reply.waiting:
        reply = template.confirm("u-18", "approve")
    print(f"{text} -> {reply.text}")
a minha encomenda se perdeu -> Não reconheci nada nisso. Posso get order ou refund card. Pode dizer qual ferramenta ou qual item você quer?
a encomenda do 4412 desapareceu -> Estornados 12.5 reais do pedido 4412.

Com o compositor template, nenhuma resposta que a pessoa lê é escrita por um modelo (capítulo 45).

Onde roda

A verificação roda no runtime, na sua máquina, em todos os planos, sem rede. A resposta, os argumentos e os resultados ficam na sua máquina: só as contagens são relatadas, com os outros medidores da sua licença.

Os limites

  • A verificação é determinística e limitada, e não prova que uma resposta é verdadeira. Ela remove o que os registros da execução não sustentam: uma frase sobre uma ação que discorda do resultado dela, e um valor que a ação não recebeu nem devolveu.
  • Ela lê as frases que o leitor consegue ligar a uma ferramenta. Uma frase que ele não liga a nenhuma ferramenta só é conferida com as regras de resposta (capítulo 43), e um valor só é conferido onde tem a forma de um: um valor com a sua moeda, uma data, um endereço, um identificador.
  • O resultado é o registro da execução, que para uma chamada que saiu da sua máquina é o que a sua ferramenta devolveu: uma ferramenta que relata sucesso para algo que falhou é relatada como feita.
  • Ela confere as respostas que o seu modelo escreve. Uma resposta que uma pessoa lê e que nenhum modelo escreveu -- uma pergunta fixa, uma recusa, uma formulação -- é o texto do próprio produto.