Skip to content
This page has been auto-translated and may contain errors.View in English

Agentes

docs.scrimba.com

Um agente é um modelo rodando em um loop, escolhendo a próxima ferramenta a chamar até que uma tarefa seja concluída. O resto deste capítulo é o que isso significa, onde ele vale a pena, e onde isso custa silenciosamente.

O loop de agente

Em uso de ferramentas o modelo chamou uma função e você enviou o resultado de volta. Mas algumas tarefas levam vários passos, e você não sabe os passos com antecedência. "Encontre o voo mais barato e reserve-o" pode significar pesquisar, comparar, verificar um calendário, depois reservar, e o modelo tem que descobrir essa sequência conforme avança.

Então, em vez de lidar com uma única chamada de ferramenta, você coloca tudo em um loop. Este ciclo repetido é o loop de agente, uma volta repetida até que a tarefa seja concluída:

  1. Envie a conversa e as ferramentas disponíveis para o modelo.
  2. O modelo chama uma ferramenta ou fornece uma resposta final.
  3. Se chamou uma ferramenta, execute-a, adicione o resultado à conversa, e volte ao passo 1.
  4. Se deu uma resposta final, pare.

A cada volta o modelo vê tudo o que aconteceu até agora, incluindo resultados anteriores de ferramentas, e decide o próximo movimento. Essa é a única diferença em relação ao uso de ferramentas: você continua em loop até que o modelo esteja satisfeito de ter terminado.

A mudança real é quem está dirigindo. Em todos os capítulos até agora, seu código decidiu o fluxo de controle: você escolheu quando chamar o modelo, quando executar uma ferramenta, o que viria depois. Um agente entrega essa decisão ao modelo. O loop continua perguntando "o que deveria acontecer a seguir?" e a previsão do modelo é a resposta a cada vez. Você troca controle por flexibilidade, e essa troca é a fonte tanto do alcance quanto do risco.

Por baixo, nada novo está acontecendo. É a mesma previsão em um contexto crescente, o round-trip de uso de ferramentas repetido. O modelo não elabora um plano e o segue. A cada volta ele prevê o melhor próximo passo a partir do que pode ver agora, então o loop executa novamente.

Quando isso funciona, parece um raciocínio em direção a um objetivo. Quando não funciona, o agente fica em loop ou segue uma rota sem saída, porque nenhuma parte do sistema está mantendo o plano geral.

JunoO loop de agente Um agente é o loop de uso de ferramentas repetido: envie a conversa e ferramentas, o modelo chama uma ferramenta ou fornece uma resposta final, você executa qualquer ferramenta e realimenta o resultado, e faz isso novamente até que responda. A cada volta o modelo vê todos os resultados anteriores e escolhe o próximo passo. A única ideia nova sobre o uso simples de ferramentas é fazer loop em vez de lidar com uma única chamada.

Em uso de ferramentas você tratou uma chamada e retornou o resultado. Um agente é aquele round-trip envolvido em um loop, executado até que o modelo decida que terminou. Aquele loop é o loop de agente. Aqui está o movimento: pare de codificar a sequência de passos e deixe o modelo escolher o próximo a cada volta.

O ciclo é quatro passos:

  1. Envie a conversa mais a lista de ferramentas para o modelo.
  2. O modelo responde com chamadas de ferramentas ou uma resposta final em texto.
  3. Se pediu ferramentas, execute-as, anexe cada resultado à conversa, e faça um loop.
  4. Se respondeu, pare e retorne.

O mecanismo que torna isso funcionar é que o modelo vê a conversa completa crescente a cada volta: seu pedido original, cada chamada de ferramenta que fez, e cada resultado que voltou. Esse contexto acumulado é a única memória do agente. Cada previsão é condicionada ao histórico completo até agora, que é por que ele pode encadear passos que dependem de resultados anteriores.

Um detalhe digno de nota no início: o passo 2 pode retornar várias chamadas de ferramenta de uma vez, não uma. Quando as chamadas não dependem uma da outra, como verificar o clima em três cidades, o modelo pode solicitar todas as três em uma única volta e você as executa juntas. Quando uma chamada precisa do resultado de uma anterior, o modelo tem que esperar por esse resultado antes de poder pedir a próxima, então essas chegam em voltas separadas. O loop trata ambas: execute as chamadas que chegaram nesta volta, realimente todos os resultados, e preveja novamente.

Não há plano global dentro de nada disso. O modelo prevê o melhor próximo passo a partir do que pode ver agora, não a partir de um mapa de toda a tarefa. Essa é a diferença entre um agente e os pipelines fixos que você escreveu antes, e é por que o mesmo loop que encadeia passos de pesquisa também pode perseguir seu próprio rabo.

JunoO loop de agente Um agente é o round-trip de uso de ferramentas em um loop: envie conversa mais ferramentas, o modelo chama ferramentas ou responde, você executa as ferramentas e realimenta resultados, repita até que responda. A conversa crescente é a única memória do agente, então cada passo é condicionado a cada resultado anterior. Uma volta pode retornar várias chamadas de ferramenta independentes de uma vez, ou uma por uma quando cada uma depende da anterior. Nenhum plano global existe em lugar nenhum: cada passo é uma adivinhação fresca do próximo passo.

Um agente é o round-trip de uso de ferramentas colocado em um loop e passando o controle, o loop de agente: o modelo escolhe a próxima ferramenta a cada volta, você a executa, realimenta o resultado, e faz isso novamente até que emita uma resposta final em vez de uma chamada. O loop é quatro passos e não é a parte interessante. A parte interessante é o que a arquitetura faz e não faz por você.

O ciclo:

  1. Envie a conversa em execução mais os esquemas de ferramentas.
  2. O modelo retorna chamadas de ferramentas ou uma resposta final.
  3. Execute qualquer chamada, anexe resultados, faça um loop.
  4. Em uma resposta final, retorne.

Uma única volta pode retornar múltiplas chamadas de ferramentas. O modelo emite chamadas paralelas quando as julga independentes (três consultas sem dependência de dados entre elas), e chamadas seriais em voltas quando uma precisa da saída de outra primeiro. Você não pode forçar isso de fora: se o trabalho se paraleliza é a decisão do modelo baseada na tarefa que inferiu, então uma tarefa que você pensa ser paralela pode voltar serializada e mais lenta, e uma que você pensa ser serial pode voltar como um lote que você precisa estar pronto para executar junto.

Aqui está o fato que carrega a carga, o que cada modo de falha rastreia de volta. Não há plano global. O modelo não mantém um mapa da tarefa e não executa contra ele. A cada volta ele prevê o próximo passo a partir da conversa atual, e essa conversa é o estado inteiro do sistema, seu prompt mais cada chamada e resultado até agora, acumulado.

Cada passo confia no passo anterior, sem nada verificando o todo. É por isso que um agente que parece estar raciocinando em direção a um objetivo está na verdade fazendo uma sequência de adivinhações localmente plausíveis que, quando funciona, se somam.

A consequência a internalizar agora, porque a seção de guardrail a compensa: porque o estado é apenas a transcrição crescente e cada passo é condicionado a ela, um resultado de ferramenta errado no início não é corrigido, é construído sobre. O erro se propaga para frente e se agrava, e nenhuma parte do loop está posicionada para notar. O trabalho de confiabilidade em agentes é principalmente lutar contra essa propriedade.

JunoO loop de agente Um agente é o round-trip de uso de ferramentas em um loop com o modelo dirigindo: ele escolhe a próxima ferramenta, você a executa, realimenta o resultado, repita até que responda. Todo o estado é a transcrição crescente, e não há plano global em lugar nenhum, apenas uma cadeia de adivinhações do próximo passo cada uma condicionada à anterior. Uma volta pode retornar chamadas paralelas quando o modelo as julga independentes ou chamadas seriais quando dependem uma da outra, e você não controla qual. Segure-se em uma coisa: cada passo confia no passo anterior, então um resultado errado no início se compõe para frente sem nada verificando o todo.

Um agente mínimo

Aqui está o loop em código. Ele reutiliza as definições de ferramentas e implementações do uso de ferramentas e as envolve em um loop que executa até que o modelo pare de pedir ferramentas.

python
import json

def run_agent(user_text, tools, tool_impls, max_steps=6):
    messages = [{"role": "user", "content": user_text}]
    step = 0

    while step < max_steps:
        response = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
        message = response.choices[0].message
        messages.append(message)

        calls = message.tool_calls
        if not calls:
            return message.content  # nenhuma ferramenta desejada: esta é a resposta final

        # execute cada ferramenta solicitada e realimente os resultados
        for call in calls:
            args = json.loads(call.function.arguments)
            result = tool_impls[call.function.name](args)
            messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})

        step += 1

    return "Stopped: the agent reached its step limit."  # rede de segurança

Leia de cima para baixo: chame o modelo, coloque sua mensagem na conversa, e se pediu ferramentas, execute todas e anexe os resultados, então faça um loop novamente. Quando o modelo retorna texto em vez de uma chamada de ferramenta, esse texto é a resposta final e você o retorna.

O valor max_steps define um limite de passos, a rede de segurança que mantém o loop de sair do controle, que a próxima seção trata. A forma aqui combina com o SDK de um provedor; os nomes dos campos diferem entre provedores, mas o loop é o mesmo em todos os lugares.

JunoUm agente mínimo Um agente mínimo é um loop em torno de uma chamada de modelo: execute o modelo, execute as ferramentas que pede, realimente os resultados, repita. Quando o modelo retorna texto em vez de uma chamada de ferramenta, esse texto é a resposta final. O limite de passos é uma rede de segurança necessária, não um extra que você adiciona depois.

Aqui está o loop em código, reutilizando as definições de ferramentas e implementações do uso de ferramentas. Ele executa até que o modelo pare de pedir ferramentas ou atinja o limite de passos.

python
import json

def run_agent(user_text, tools, tool_impls, max_steps=6):
    messages = [{"role": "user", "content": user_text}]
    step = 0

    while step < max_steps:
        response = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
        message = response.choices[0].message
        messages.append(message)

        calls = message.tool_calls
        if not calls:
            return message.content  # resposta final

        for call in calls:
            args = json.loads(call.function.arguments)
            try:
                result = tool_impls[call.function.name](args)
            except Exception as err:
                result = {"error": str(err)}  # expor a falha, não travar
            messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})

        step += 1

    return "Stopped: the agent reached its step limit."

A forma é o SDK de um provedor e os nomes dos campos variam, mas cada loop tem essas partes: anexe a mensagem do modelo, ramifique se pediu ferramentas, execute as solicitadas, realimente cada resultado de volta como uma mensagem tool vinculada ao seu id de chamada.

A única mudança digna de fazer sobre a versão básica é o try/except em torno da ferramenta. Quando uma ferramenta falha, não deixe a exceção matar o loop. Capture-a e realimente o erro de volta ao modelo como o resultado da ferramenta. O modelo pode então ler "aquela consulta falhou" em sua próxima volta e se adaptar: tentar novamente com argumentos diferentes, tentar outra ferramenta, ou dizer ao usuário que não conseguiu completar a tarefa. Um travamento não dá ao modelo chance de se recuperar; esse padrão erro-como-resultado mantém no loop com informações para agir.

Duas coisas para acompanhar conforme isso executa. Primeiro, a conversa só cresce. A cada volta anexa a mensagem do modelo e cada resultado de ferramenta, então no quinto passo o modelo está lendo tudo dos passos um a quatro novamente. Essa é a memória do agente e também sua conta: cada passo realimenta o contexto acumulado todo, então o custo de token por passo sobe conforme a tarefa avança. Um agente de dez passos não é dez chamadas baratas, é dez chamadas sobre uma transcrição cada vez maior.

Segundo, esse crescimento é por que max_steps importa além de parar loops infinitos. Escolha-o contra a tarefa. Uma pergunta sobre o tempo precisa de dois ou três passos; uma tarefa de pesquisa pode querer dez. Defina o limite um pouco acima do que uma execução saudável leva, então uma tarefa legitimamente mais longa pode terminar mas uma presa ainda fica cortada antes de drenar seu orçamento.

JunoUm agente mínimo O loop é: anexe a mensagem do modelo, ramifique se pediu ferramentas, execute-as, realimente cada resultado de volta como uma mensagem tool. Envolva a chamada da ferramenta em try/except e realimente erros de volta em vez de travar, para que o modelo possa tentar novamente ou se recuperar. Observe que a conversa só cresce: cada passo realimenta a transcrição toda, então o custo de token por passo sobe conforme a tarefa executa. Defina max_steps contra a tarefa, um pouco acima de uma execução saudável.

O loop, reutilizando a camada de ferramentas do uso de ferramentas. Forma de SDK de um provedor, nomes dos campos variam, estrutura não.

python
import json

def run_agent(user_text, tools, tool_impls, max_steps=6):
    messages = [{"role": "user", "content": user_text}]
    step = 0

    while step < max_steps:
        response = client.chat.completions.create(model=MODEL, messages=messages, tools=tools)
        message = response.choices[0].message
        messages.append(message)

        calls = message.tool_calls
        if not calls:
            return message.content

        for call in calls:
            args = json.loads(call.function.arguments)
            try:
                result = tool_impls[call.function.name](args)
            except Exception as err:
                result = {"error": str(err)}  # o modelo lê isso e pode se adaptar na próxima volta
            messages.append({"role": "tool", "tool_call_id": call.id, "content": json.dumps(result)})

        step += 1

    return "Stopped: the agent reached its step limit."

O loop básico está correto e não pode ser enviado para produção, e a lacuna entre os dois é onde esta seção vive. Três propriedades deste código mordem em produção.

Exponha erros, nunca trabe. O try/except realimenta uma ferramenta falha de volta ao modelo como um resultado que pode ler. Isso está certo, mas entenda o que você está fazendo: você está passando uma string de erro ao modelo e confiando que se recupere sensatamente. Pode tentar a mesma chamada ruim novamente, ou inventar uma abordagem diferente, ou se desculpar e parar.

Realimentar erros mantém o agente vivo; não torna a recuperação confiável. Para qualquer coisa crítica, coloque um limite de tentativas por ferramenta e trate falha repetida como um estado terminal que você trata, não um loop que você deixa o modelo resolver por intuição.

A transcrição só cresce, e isso é dois custos compostos. O custo de token por passo sobe porque cada chamada realimenta o histórico acumulado completo, então uma execução longa paga uma conta crescente a cada volta, não uma fixa. E quanto mais longa a transcrição, mais o modelo está lendo saída de ferramenta antiga para decidir o próximo movimento, que é exatamente onde o efeito perdido-no-meio do capítulo janela de contexto começa a morder, onde um modelo atende menos à informação enterrada no meio de um contexto longo: as instruções iniciais que deveriam restringir o agente afundam sob resultados acumulados e são atendidas menos. Agentes longos não falham alto, eles derivam.

max_steps é um orçamento, não uma guarda de bug. Existe porque o modelo decide quando parar e pode decidir errado: fazer loop em um passo, fazer ping-pong entre duas ferramentas, perseguir uma rota sem saída.

O número é um limite de custo real. O pior caso de gasto é grosseiramente max_steps multiplicado pelo custo de uma chamada de contexto completo perto do final da execução, então um limite generoso em uma tarefa pesada em contexto é uma conta generosa. Defina-o a partir da execução mais longa legítima mais uma margem, alarme quando as execuções rotineiramente o atingem (isso é um sinal de que o agente está preso, não que o limite é muito baixo), e resista em aumentá-lo para esconder um agente que não consegue terminar.

JunoUm agente mínimo O loop básico está correto e não pode ser enviado para produção. Realimente erros de ferramenta para que o modelo possa se adaptar, mas coloque um limite em tentativas e trate falha repetida como terminal, porque expor um erro não torna a recuperação confiável. A transcrição só cresce, então o custo de token por passo sobe e suas instruções iniciais ficam enterradas sob resultados antigos até o agente derivar. max_steps é um limite de custo, não uma guarda de bug: dimensione-o para a execução mais longa e real mais margem, e quando as execuções continuam o atingindo, o agente está preso, então não aumente reflexivamente o número.

Parando e guardrails

Um loop que deixa um modelo decidir quando parar pode falhar em parar. Pode chamar ferramentas para sempre, repetir a si mesmo, ou perseguir uma rota sem saída. Porque cada passo é uma chamada de modelo cobrada por tokens, um agente descontrolado queima dinheiro e tempo rápido.

Então guardrails, os limites que você coloca em torno do loop, são parte do design, não um passo de polimento que você adiciona depois:

  • Um limite de passos. Coloque um teto no número de loops, do jeito que max_steps faz. Quando atingido, pare e retorne.
  • Valide entradas de ferramentas. O modelo escolhe os argumentos, então verifique-os antes de executar qualquer coisa com consequências reais.
  • Limite o que as ferramentas podem fazer. Dê ao agente o mínimo de poder que precisa. Uma ferramenta que lê é mais segura que uma que deleta.
  • Acompanhe o custo. Várias chamadas de modelo por tarefa se multiplicam rapidamente, então acompanhe tokens e defina um orçamento.

O fio que une esses: o modelo está improvisando o caminho, então você coloca os limites no lugar que não vai. Assuma que o agente fará a coisa errada pelo menos uma vez, e torne isso sobrevivível.

JunoParando e guardrails Um agente decide seu próprio ponto de parada, então pode ficar em loop para sempre, e cada loop custa tokens. Sempre defina um limite de passos, valide os argumentos que o modelo escolhe, e dê às ferramentas o mínimo de poder que precisam. Acompanhe o custo, porque várias chamadas de modelo por tarefa se somam rapidamente.

Um loop onde o modelo decide quando parar pode falhar em parar, e porque cada passo é uma chamada de modelo cobrada em tokens, um agente preso queima orçamento rápido. Guardrails são parte do design. Os quatro para conectar:

  • Um limite de passos. Coloque um teto nos loops com max_steps e retorne limpo quando atingido. Este é seu parada dura contra loops descontrolados.
  • Valide entradas de ferramentas. O modelo escolhe os argumentos, e pode escolher errado ou ser desviado errado. Verifique-os antes de qualquer ferramenta com consequências reais ser executada: um delete sem id, uma transferência com uma quantidade negativa, um caminho fora do diretório permitido.
  • Mínimo poder. Dê a cada ferramenta a capacidade mais estreita que a tarefa precisa. Somente leitura vence ler-escrever, uma consulta com escopo vence acesso bruto a banco de dados, uma lista fixa de destinatários vence envio arbitrário.
  • Teto de custo. Acompanhe tokens em toda a execução, não por chamada, e pare quando uma execução cruza um orçamento.

O ponto que une esses é que os argumentos para suas ferramentas vêm do modelo, o que significa que vêm, indiretamente, de qualquer texto que o modelo tenha lido. Se uma ferramenta buscou uma página web e essa página continha instruções, essas instruções estão agora no contexto do modelo e podem desviar a próxima chamada de ferramenta. Isso é injeção de prompt: texto não confiável no contexto influenciando o que o agente faz. A defesa não está no prompt. Está em validar cada entrada de ferramenta e escopar o poder de cada ferramenta para que mesmo um argumento completamente sequestrado não possa fazer dano real.

JunoParando e guardrails Quatro guardrails, por design não polimento: uma parada dura max_steps, validação de entrada em cada ferramenta consequente, escopo de mínimo poder, e um orçamento de tokens em toda a execução. A razão pela qual a validação de entrada importa: os argumentos de ferramenta vêm do modelo, o que significa de qualquer texto que leu, então uma página buscada carregando instruções é injeção de prompt que pode desviar a próxima chamada. Valide entradas e escope poder para que um argumento sequestrado ainda não possa fazer dano.

Um loop onde o modelo decide quando parar pode falhar em parar, e cada passo é uma chamada cobrada em tokens, então o modo de falha é caro por padrão. Os quatro guardrails (limite de passos, validação de entrada, mínimo poder, teto de custo) são aposta certa. A parte digna de sua atenção é por que a validação de entrada é um controle de segurança, não uma verificação de sanidade.

Os argumentos de ferramentas são saída de modelo, e saída de modelo é condicionada a tudo no contexto, incluindo texto que o agente buscou de fora. No momento em que um agente lê uma página web, um documento, um email, ou um resultado de ferramenta que você não controla, texto não confiável está em seu contexto e pode carregar instruções. Isso é injeção de prompt: conteúdo adversarial na entrada desviando o modelo em ações que você não pretendia. Em um prompt único é uma chatice. Em um agente é um exploit ativo, porque o próximo movimento do modelo é uma chamada de ferramenta com efeito no mundo real, e o texto injetado fica para influenciar aquela chamada.

Design para isso como adversarial, porque é. Três regras sustentam:

  • Valide cada argumento de ferramenta contra uma lista de permissões, não lista de bloqueio. Defina como um argumento válido se parece (esse formato de id, esse conjunto de destinatários, esse diretório) e rejeite tudo mais. Você não pode enumerar cada entrada ruim que um invasor vai criar; você pode enumerar as boas.
  • Escope poder de ferramenta para que uma chamada completamente sequestrada seja sobrevivível. Assuma que o argumento é controlado pelo invasor e pergunte o que a ferramenta poderia então fazer. Se a resposta real é "enviar email para qualquer um" ou "deletar qualquer linha", a ferramenta é muito ampla independentemente de quão cuidado o prompt é. Mínimo poder é o controle que sustenta quando o modelo é comprometido, e o prompt não é um controle em absoluto.
  • Coloque um humano no loop em ações irreversíveis. Enviar dinheiro, deletar dados, enviar email para clientes: gate esses em confirmação. O agente propõe, uma pessoa ou uma verificação mais rigorosa dispõe.

A razão mais profunda pela qual nada disso vive no prompt: instruções no prompt do sistema e instruções injetadas em conteúdo buscado chegam como o mesmo tipo de coisa, texto no contexto, e o modelo não tem forma confiável de classificar uma acima da outra. Então você não pode fazer sua forma de segurança através do prompt. A fronteira que sustenta é fora do modelo: entradas validadas e ferramentas com escopo. Isso se conecta ao tratamento mais amplo em segurança e limites.

JunoParando e guardrails Os quatro guardrails são aposta certa; o que merece pensamento é a validação de entrada, porque é um controle de segurança. Os argumentos de ferramenta são saída de modelo condicionada a tudo que leu, então qualquer página buscada ou email pode carregar instruções injetadas que desviam a próxima chamada, e em um agente aquela chamada tem efeito no mundo real. Valide contra uma lista de permissões, escope cada ferramenta para que um argumento sequestrado ainda seja sobrevivível, e gate ações irreversíveis em um humano. Você não pode fazer sua forma de segurança através do prompt: instruções injetadas e do sistema são o mesmo tipo de texto para o modelo, então a fronteira tem que viver fora dele.

Quando um fluxo de trabalho vence um agente

Agentes são empolgantes, o que torna tentador chegar a um quando você não precisa. A regra simples: se você já conhece os passos, não use um agente. Escreva-os como código simples, um fluxo de trabalho, onde cada passo executa em ordem fixa.

Um fluxo de trabalho é mais confiável, mais barato, e muito mais fácil de debugar, porque você controla o caminho em vez de esperar o modelo encontrá-lo. Reserve agentes para tarefas abertas onde os passos dependem do que é descoberto ao longo do caminho.

Muitos recursos que parecem precisar de um agente são melhores como uma chamada de saída estruturada ou uma consulta RAG conectada manualmente. Chegue a um agente apenas quando não conseguir escrever os passos com antecedência.

JunoQuando um fluxo de trabalho vence um agente Se você já conhece os passos, codifique-os como um fluxo de trabalho em vez de usar um agente: é mais barato, mais confiável, e mais fácil de debugar. Reserve agentes para tarefas abertas onde os passos dependem do que é encontrado ao longo do caminho. Muitos recursos de "agente" são realmente uma chamada de saída estruturada ou RAG conectada manualmente.

Agentes são a ferramenta empolgante, que é exatamente por que são buscados quando estão errados. A regra de decisão é uma pergunta: consegue escrever os passos com antecedência? Se sim, você quer um fluxo de trabalho, os passos como código simples em ordem fixa, não um agente.

Um fluxo de trabalho vence em tudo em que um agente luta. É mais barato, porque você faz uma ou duas chamadas de modelo em vez de um loop delas. É mais confiável, porque o caminho é fixo em vez de ser redecidido a cada volta. E é muito mais fácil debugar, porque uma falha acontece em um passo conhecido que você pode inspecionar, não em algum lugar em uma cadeia de movimentos escolhidos pelo modelo.

Aqui está o teste na prática. "Resuma este ticket de suporte, classifique sua urgência, e roteie-o para uma fila" tem passos conhecidos em ordem conhecida, então é um fluxo de trabalho: uma chamada de saída estruturada para obter o resumo, categoria, e urgência, então código simples para rotear no resultado. "Investigue por que os últimos três pedidos deste cliente falharam" não tem passos conhecidos, o caminho depende do que cada consulta revela, então é um agente.

A armadilha é que muitos recursos parecem abertos e não são. Puxar campos de um documento, responder de seus docs, classificar correio de entrada: esses parecem trabalho de agente mas se resolvem em uma chamada de saída estruturada ou uma consulta RAG com código em torno. Padrão do fluxo de trabalho e deixe uma tarefa ganhar o agente sendo imprevisível de uma forma que você não consegue escrever.

JunoQuando um fluxo de trabalho vence um agente A decisão é uma pergunta: consegue escrever os passos com antecedência? Se sim, construa um fluxo de trabalho, os passos como código simples, porque é mais barato, mais confiável, e debugável em um ponto conhecido. "Resuma, classifique, roteie um ticket" é um fluxo de trabalho: uma chamada de saída estruturada mais código de roteamento. "Investigue por que esses pedidos falharam" é um agente, porque o caminho depende do que cada passo encontra. Padrão do fluxo de trabalho e deixe a tarefa ganhar o agente.

O agente é a ferramenta que as pessoas querem usar, que é por isso que é usado onde não pertence. A regra de decisão é curta: se conseguir escrever os passos com antecedência, escreva-os. Isso é um fluxo de trabalho, os passos como código em ordem fixa, e vence um agente em custo, confiabilidade, e debugabilidade para qualquer tarefa cuja forma você conhece.

A razão rastreia diretamente para a arquitetura. Um agente não tem plano global e compõe erros para frente, então sua confiabilidade é o produto de cada passo sair certo com nada verificando o todo. Um fluxo de trabalho que você escreveu tem um plano, por definição, e você pode inspecionar, testar, e validar cada passo isoladamente. Quando algo quebra em um fluxo de trabalho, quebra em uma linha. Quando algo quebra em um agente, quebra em algum lugar em uma transcrição de movimentos escolhidos pelo modelo, e você reconstrói o que estava pensando do rastro.

Agora o caso mais difícil, porque "consigo conhecer os passos" é a metade direta. Um agente pode ser a ferramenta errada mesmo quando a tarefa é aberta, quando o custo de um passo errado é muito alto para deixar um próximo-passo adivinhador levá-lo. Um agente que reserva viagens, move dinheiro, ou modifica dados de produção é aberto e também um lugar onde você não quer um loop não planejado, injetável, que compõe erros mantendo os controles. O design certo lá é frequentemente um híbrido: o modelo planeja ou propõe, mas um fluxo de trabalho fixo e gates humanos executam, então a parte imprevisível nunca toca a parte irreversível diretamente.

Então a pergunta é duas perguntas. Consigo conhecer os passos, e o que um passo errado custa?

Passos conhecidos vão para um fluxo de trabalho. Passos desconhecidos com ações baratas, reversíveis são onde um agente ganha seu lugar. Passos desconhecidos com ações caras, irreversíveis querem um design constrangido, não um loop livre.

Um agente se encaixa bem em trabalho aberto com passos baratos e reversíveis, e pouco mais. Uma parte surpreendente de recursos de "agente" são uma chamada de saída estruturada ou uma consulta RAG com código em torno, e eles ficam melhor assim.

JunoQuando um fluxo de trabalho vence um agente Duas perguntas, não uma: consigo conhecer os passos, e o que um passo errado custa? Passos conhecidos vão para um fluxo de trabalho, que vence um agente em custo, confiabilidade, e debug porque tem um plano e o agente nunca tem. Passos desconhecidos com ações baratas reversíveis é onde um agente ganha seu lugar. Passos desconhecidos com ações caras irreversíveis querem um híbrido: o modelo propõe, um fluxo de trabalho fixo e gates humanos executam, para que o loop que compõe erros nunca toque a parte que você não consegue desfazer.

Na prática

A função run_agent acima é tudo. Dê a ela uma pergunta, um conjunto de ferramentas, e suas implementações, e ela faz loop até terminar ou até atingir o limite de passos. Uma pequena tarefa mostra o loop valendo a pena:

python
answer = run_agent(
    "Qual é o tempo em São Paulo e devo trazer um guarda-chuva?",
    tools,        # inclui get_weather do capítulo de uso de ferramentas
    tool_impls,   # {"get_weather": ...}
)
# O agente chama get_weather, lê "nublado", então responde em uma única volta final:
# "Está nublado em São Paulo a 25 graus, então um guarda-chuva é uma ideia sensata."

Uma ferramenta, um loop, uma resposta. A mesma estrutura escala para várias ferramentas e vários passos sem mudar de forma. Uma vez que consegue construir coisas tão capazes, a próxima pergunta é como você sabe que realmente funcionam, que é o que evals trata.

JunoNa prática O loop run_agent é todo o padrão: dê a ele uma pergunta, ferramentas, e suas implementações, e ele faz loop até o modelo parar de pedir ferramentas ou atingir o limite de passos. Uma ferramenta e um loop escalam para muitas sem mudar de forma. A próxima pergunta é como você sabe que realmente funciona, que é evals.

A função run_agent é todo o padrão. Dê a ela uma pergunta, ferramentas, e suas implementações, e ela faz loop até o modelo parar de pedir ou atingir o limite.

python
answer = run_agent(
    "Qual é o tempo em São Paulo e devo trazer um guarda-chuva?",
    tools,        # inclui get_weather do capítulo de uso de ferramentas
    tool_impls,   # {"get_weather": ...}
)
# O agente chama get_weather, lê "nublado", então responde em uma única volta final.

Uma ferramenta, um loop, uma resposta, e a mesma forma escala para várias ferramentas e vários passos. O que não escala de graça é sua confiança de que funciona. Um fluxo de trabalho você consegue testar passo a passo; um agente leva um caminho diferente em entradas diferentes, então uma execução que funcionou ontem diz pouco sobre a execução que falha hoje.

É por isso que a próxima coisa a construir junto com um agente é uma forma de medi-lo: execute-o em um conjunto de tarefas representativas e verifique os resultados, em vez de confiar em uma boa demonstração. Transformar "funcionou quando tentei" em um número que você consegue acompanhar é exatamente o que evals cobre.

JunoNa prática O loop run_agent é todo o padrão, e uma ferramenta e um loop escalam para muitas sem mudar de forma. O problema é confiança: um agente leva um caminho diferente por entrada, então uma boa demonstração prova pouco sobre a próxima execução. Construa uma forma de medi-lo em tarefas representativas em vez de confiar em um sucesso, que é o que evals é para.

A função run_agent é todo o padrão, e o exemplo abaixo é o mínimo: uma ferramenta, um loop, uma resposta.

python
answer = run_agent(
    "Qual é o tempo em São Paulo e devo trazer um guarda-chuva?",
    tools,        # inclui get_weather do capítulo de uso de ferramentas
    tool_impls,   # {"get_weather": ...}
)
# get_weather retorna "nublado", o modelo responde em uma única volta final.

A forma escala para muitas ferramentas e muitos passos sem mudar, e essa é a armadilha, porque os modos de falha escalam com ela enquanto o código fica ainda. Um agente é dependente do caminho: entradas diferentes conduzem sequências diferentes de passos escolhidos pelo modelo, então testes por entrada dizem quase nada sobre a entrada que não viu. A não determinismo da amostragem significa que até a mesma entrada pode levar um caminho diferente duas vezes.

Então a coisa que você constrói a seguir para um agente é medição, e é um tipo diferente de medição do que um fluxo de trabalho precisa. Você não está afirmando uma saída esperada; você está amostrando muitas tarefas representativas e lendo a distribuição de resultados: com que frequência termina no orçamento, com que frequência atinge a resposta certa, onde faz loop, o que custa na cauda. Essa é a versão do agente de evals, e é a única forma as preocupações de confiabilidade, custo, e segurança das seções acima se tornarem números que você consegue defender em vez de uma demonstração que sorte.

JunoNa práticarun_agent é todo o padrão e escala em forma enquanto os modos de falha escalam com ele. Um agente é dependente do caminho e amostragem adiciona não determinismo, então testes por entrada dizem pouco e uma boa demonstração prova menos. Meça-o do jeito agente: amostre muitas tarefas representativas e leia a distribuição, com que frequência termina no orçamento, onde faz loop, o que custa na cauda. Isso é o que evals é para, e é como as preocupações de confiabilidade e custo acima se tornam números que você consegue defender.