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¶
- 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. - 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. - 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. - 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.
- Uma escrita feita neste turno que a resposta omite é acrescentada, na formulação do seu resultado.
- 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
refusedda própria loja; - o reembolso rodou com 12,50, e o modelo escreveu 15,00: a frase é substituída pela formulação de
doneda 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.