Ir para o conteúdo

25 · O feedback e o vocabulário aprendido

O roteador lê um turno pelas palavras que as suas ferramentas declaram. Os seus usuários têm palavras próprias -- tire o pedido 4411 do cartão onde a sua ferramenta diz refund_card --, e os polegares deles ensinam essas palavras ao roteador. Este capítulo é o que um polegar registra, como o minerador hospedado transforma polegares num novo vocabulário e como um vocabulário é revertido.

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.

Um polegar

O polegar de uma pessoa, para cima ou para baixo, sobre o que o roteador escolheu é um registro de feedback. Numa sessão:

with Client() as client:
    chat = client.session("desk", catalogue=catalogue, rulebook=rulebook)
    plan = chat.read("mostre o pedido 4411")
    print(chat.thumbs(plan, up=True))                                   # o roteador escolheu bem
    plan = chat.read("tire o pedido 4411 do cartão")
    print(plan.steps[0].selection.tool, "->", chat.thumbs(plan, up=False, corrected="refund_card"))

O segundo turno chegou a get_order, e o polegar para baixo diz que a ferramenta certa era refund_card (corrected). O mesmo polegar repetido é um registro só no serviço. Um agente da Parte I faz o mesmo com agent.thumbs(reply, up=...), e o callback do LangChain com StalwartFeedbackCallback (capítulo 27).

Um polegar para baixo vale mais com o que se quis dizer. agent.meant_choices(reply) -- meant_choices(rated) ao lado do callback do LangChain -- lista o que oferecer à pessoa: primeiro as ferramentas que o roteador pesou -- as que ele perguntou entre si, ou as duas leituras de uma palavra que ele leu de dois jeitos --, depois todas as outras que o agente podia alcançar, e "" por último para "nenhuma delas". A resposta é o corrected.

O que um registro contém

desk = Agent.from_file("agent.yaml")
reply = desk.chat("mostre o pedido 4411", user="u-17")
print(json.dumps(desk.feedback_record(reply, up=True), indent=1, sort_keys=True))
{'accepted': 1}
get_order -> {'accepted': 1}
{
 "agent": "desk",
 "cited": [],
 "context": {
  "before": [],
  "history": "first",
  "previous": [],
  "readings": [],
  "step": 0,
  "steps": 1
 },
 "corrected": "",
 "decided_by": "tool: admission",
 "delegated": false,
 "language": "pt-BR",
 "outcomes": [
  "get_order:done"
 ],
 "reply_digest": "1bfd98bf2f6401b4e33432e2778566c3d8b4d5a315f0b10ca25d1706a6a2d733",
 "rewrites": [],
 "router_digest": "",
 "thumb": "up",
 "tool": "get_order",
 "turn": "mostre o pedido 4411",
 "verdict": "resolved",
 "visible": [
  "charge_card",
  "get_order",
  "hand_off",
  "read_inbox",
  "send_receipt"
 ],
 "vocabulary_digest": "bdd0a20dc1bccb3a79e549d99b44a40a1039f2ce18c76d95a2fdc41fc0f3715d"
}
ThumbRefused: personal data in the request, so nothing was sent: a telephone number at turn. Remove it, or put a placeholder in its place (an address at example.com, say), and send the request again

O registro é as palavras do turno avaliado com a leitura que o roteador fez delas: o turno, o agente, as ferramentas que ele podia ver (visible), a ferramenta que escolheu e a regra que a escolheu (decided_by), o desfecho (verdict), o vocabulário com que leu e o polegar. O que a resposta disse fica guardado só como o que foi feito -- o resultado de cada ação (outcomes) e os trechos que ela citou -- e um digest do seu texto: nunca as palavras da resposta, o valor de um argumento, o resultado de uma ferramenta ou um turno anterior.

Um registro também guarda o contexto em que o turno foi lido (context), porque o roteador lê pelo contexto e só acerta ou erra dentro dele: tag lists please pede as listas de tags onde as suas ferramentas só as listam, e marca listas onde uma ferramenta as marca. O contexto é o lugar da etapa avaliada no plano (step, steps) e as ferramentas das etapas antes dela (before), o que o turno anterior fez -- first, asked, answered ou declined (history) -- e as ferramentas que ele chamou ou entre as quais perguntou (previous), e, onde o roteador leu uma palavra de dois jeitos, as ferramentas que as duas leituras alcançaram (readings). Só nomes de ferramentas: nenhuma palavra de um turno anterior.

O minerador aprende com as palavras do turno, então o registro é examinado atrás de dados pessoais na sua máquina antes de ser enviado, e um polegar sobre um turno que os contém é recusado, sem nada enviado:

reply = desk.chat("mostre o pedido 4411, o meu telefone é (11) 91234-5678", user="u-17")
try:
    desk.thumbs(reply, up=True)
except ThumbRefused as refused:
    print("ThumbRefused:", refused)

A última linha da saída. Um polegar sobre um turno inteiro de várias instruções, sobre uma resposta que a conversa decidiu ou sobre a resposta depois de uma confirmação também é recusado, nomeando o que avaliar no lugar: essas não são leituras das palavras da pessoa.

Os registros são guardados pela retenção do seu plano (capítulo 16), lidos por mais ninguém e nunca usados para treinamento. GET /v1/feedback/summary conta os polegares dos últimos trinta dias pelo que avaliaram -- uma ferramenta que o roteador escolheu, um turno que o modelo assumiu, uma pergunta que o roteador fez, uma resposta a partir das suas fontes --, e GET /v1/feedback/export dá cada registro guardado como uma linha de JSON, que é o que uma equipe que roda o seu próprio minerador lê.

O minerador hospedado

POST /v1/vocabulary/mine (ou client.mine(model)) enfileira uma execução de aprendizado sobre o seu feedback guardado e o seu vocabulário em vigor, num idioma só (abaixo). Ela propõe palavras que os seus usuários usaram para as suas ferramentas, e só as aplica quando cada uma das suas cinco barreiras se mantém e o vocabulário em vigor ainda é a versão sobre a qual ela minerou. As barreiras: nenhuma escrita é alcançada por engano, no seu corpus de avaliação ou em qualquer caso de feedback; o feedback deixado de fora do aprendizado não é respondido pior do que antes; a linha de base do seu corpus e as dos seus diálogos, onde você as tem, continuam valendo; e o novo arquivo passa limpo nas verificações. A execução é respondida na hora com um id; GET /v1/vocabulary/mine/{run_id} (client.ledger(run_id)) lê o seu estado -- queued, running, finished, failed ou cancelled --, se ela aplicou, a versão que pôs em vigor ou a barreira que a segurou. O seu registro nomeia cada caso por digest, nunca pelas suas palavras. DELETE /v1/vocabulary/mine/{run_id} retira uma execução na fila; uma que já está rodando termina.

A página Miner do console mostra as mesmas execuções, e a página Vocabulary cada versão e o que o seu registro diz (GET /v1/vocabulary/history).

Um vocabulário, com versões

O vocabulário em vigor (GET /v1/vocabulary, client.vocabulary()) é um arquivo com as suas palavras e as ferramentas que elas querem dizer. Uma versão fica guardada quando a próxima entra em vigor, então POST /v1/vocabulary/revert -- ou client.revert_vocabulary(), ou a página Vocabulary -- põe em vigor de novo a anterior, uma versão por chamada. PUT /v1/vocabulary publica uma versão que você mesmo escreveu. Todo plano nomeia o vocabulário com que leu (vocabulary_digest), então um plano que mudou pode ser rastreado até a versão que o mudou.

Uma versão fica em vigor para cada idioma que o roteador lê: um arquivo é do idioma que o seu settings.language nomeia -- en ou pt-BR -- e do inglês quando não nomeia nenhum. GET /v1/vocabulary e POST /v1/vocabulary/revert aceitam ?language= -- ou senão o idioma da sua página Settings -- um registro de feedback traz o idioma em que o seu turno foi lido, e uma execução de aprendizado minera um idioma -- o language que o seu corpo nomeia, ou senão o da sua página Settings -- só para o arquivo desse idioma. Um polegar em português nunca ensina uma palavra ao arquivo em inglês.

O runtime na sua máquina recebe a versão em vigor na próxima renovação da sua licença, então uma versão posta em vigor, ou revertida, chega aos seus agentes nesse prazo.

A forma de uma frase que o roteador não conseguiu ler de jeito nenhum -- não uma palavra, mas como a frase é construída -- é guardada por uma execução de mineração só como forma, no próprio alfabeto do roteador e nunca com uma palavra sua. GET /v1/grammar-reports/shipped lista as suas formas que uma versão do roteador agora lê. Uma forma vai com a forma do seu contexto, nunca com o contexto: o que o turno anterior fez, onde a etapa estava no plano, quantas ferramentas uma palavra lida de dois jeitos alcançou, e cada ferramenta antes dela como as classes de palavra do seu nome (ACTION OBJECT), nunca o nome. Uma forma só é guardada onde cinco turnos distintos a compartilham num mesmo contexto. Enviar uma você mesmo é opcional: um relatório sem consentimento é recusado (grammar_report_not_consented), e também um num alfabeto que nenhuma versão trouxe (grammar_report_alphabet_unknown).

Os limites

Os limites do capítulo 20 valem aqui, e mais estes:

  • Um vocabulário ensina palavras ao roteador, não discernimento: uma palavra aplicada a uma ferramenta lê essa ferramenta onde quer que seja dita.
  • O minerador só aplica o que as suas barreiras sustentam, e as barreiras leem os casos que você tem. Uma palavra que ninguém avaliou não é aprendida.