O Agente
Um agente é uma entidade que interage com um ambiente em qualquer nível significativo. Uma pessoa em seu dia a dia é um agente nesse sentido, assim como um termostato que mantém a temperatura de uma sala ou um carro autônomo que se desloca pelo trânsito.
Todos eles percebem o ambiente por meio de sensores e agem sobre ele por meio de atuadores. Como cada ação alimenta a observação seguinte, percepção e ação formam um ciclo contínuo, o ciclo perceber, raciocinar e agir, que dura enquanto o agente interage. Todos os agentes construídos no curso seguem esse ciclo. O que muda é quanto conseguem perceber e até onde suas ações alcançam.
As três partes do ciclo
Cada iteração passa por três etapas, com nomes simples e funções distintas.
A percepção reúne o que o agente pode saber, o raciocínio escolhe o que fazer e a ação altera o ambiente. A percepção e a ação costumam vir de um modelo de interação existente, seja ele usado para controlar um aspirador, automação web, uma entidade de jogo ou um humanoide. O raciocínio pode mudar sem alterar essa fronteira, o que separa capacidade de alcance.
Explorar o ciclo e as arquiteturas clássicas?
Abra esta seção para ver exemplos concretos e uma taxonomia mais completa de arquiteturas.
- A percepção fornece tudo o que o agente sabe sobre o ambiente. Um termostato lê um único número: a temperatura atual. Um carro autônomo combina câmeras, radar e um mapa em um modelo da via. O agente trabalha somente com o que a percepção captura, pois as etapas seguintes não acessam o mundo diretamente. Uma lacuna na percepção permanece invisível para o restante do agente.
- O raciocínio transforma uma percepção em uma decisão, e isso varia muito entre agentes. Um termostato compara a temperatura com um alvo e para por aí, enquanto um motor de xadrez busca milhões de jogadas e um carro autônomo executa uma política aprendida. Os agentes que você constrói aqui raciocinam chamando um modelo de linguagem, e quase tudo o que o curso acrescenta depois (ferramentas/memória/planejamento) se apoia nesse único passo.
- A ação altera o ambiente para o próprio agente e para outros participantes. Pode ser tão pequena quanto acionar um relé ou tão complexa quanto conduzir um carro. Nas páginas seguintes, o código exposto ao modelo recebe o nome de ferramenta, pois, para o modelo, ele representa outra ação disponível. Chamar uma ferramenta significa solicitar que esse código seja executado como ação. O conjunto de ações também define o alcance máximo do agente: por melhor que seja o raciocínio, ele só afeta o mundo por meio das ações permitidas.
Os projetos clássicos de agentes diferem na etapa de decisão. O livro Artificial Intelligence: A Modern Approach, de Russell e Norvig, organiza esses projetos em um espectro que vai do agente reflexo a um agente de aprendizagem capaz de melhorar as próprias regras. O curso começa com lógica rígida e depois acrescenta um modelo de linguagem e contexto projetado, aproximando o ciclo de um agente orientado a objetivos e baseado em modelo. Nos módulos seguintes, o ciclo continua sobre um estado que muda, padrão que serve de base para agentes de aprendizagem.
Executar o menor ciclo de agente baseado em regras?
Um agente sem modelo de linguagem
A menor função de decisão é uma única instrução if. Aqui ela conduz uma pista
unidimensional limitada por paredes nas posições 0 e 9. Pressione Run e observe a posição
alternar entre as paredes enquanto o ciclo é executado.
Duas coisas que vale a pena examinar no código acima:
- O ambiente (posições das paredes, posição atual) vive em
state.env, enquanto as características intrínsecas do agente (sua direção) vivem emstate.agent. Mantê-los separados significa que um agente diferente, com estado intrínseco diferente, pode operar no mesmo ambiente sem atrito. - O passo de raciocínio é uma única instrução
if. Substituí-lo por algo mais poderoso, seja uma árvore de decisão, uma rede neural ou um modelo de linguagem, exige apenas mudar o que está entre a percepção e a ação. A estrutura do laço, a organização do estado e o passo de ação permanecem idênticos.
O que muda quando o raciocínio chama um LLM
Você chama a interface de chat-completions como qualquer outra função: entregue a ela uma lista de mensagens e um nome de modelo, e ela devolve uma mensagem do assistente mais metadados.
chat(). É o wrapper fornecido pelo curso que você executa ao vivo um pouco mais adiante nesta página. O trecho abaixo prevê o formato de chamada e os campos que ele retorna, para que os nomes já sejam familiares quando você chegar à célula executável.
const reply = await chat({
model: "nvidia/nemotron-3.5-lightning-30b-a3b",
messages: [{ role: "user", content: "Hi" }],
});
// reply.choices[0].message → { content, reasoning_content }
// reply.choices[0].finish_reason → "stop" | "tool_calls" | "length"
Três fatos sobre essa função moldam como os agentes construídos sobre ela precisam funcionar:
- As chamadas não compartilham estado. Entre requisições o servidor não guarda nada para você. Se quiser que o modelo lembre do turno anterior, você envia esse turno de novo. A "memória" de uma conversa é uma lista de mensagens que seu código mantém e reenvia a cada vez.
- A saída de raciocínio é opcional. Alguns modelos e modos retornam texto de raciocínio em
reasoning_content; outros retornam apenas a resposta ou solicitações de ferramentas. Examine os campos realmente retornados. O loop lêcontent, o motivo de término e as solicitações de ferramentas antes de escolher o próximo passo. - finish_reason é a condição de saída do laço.
"stop"significa que o modelo escreveu sua resposta final."tool_calls"significa que ele quer que seu código execute uma função nomeada e reporte o resultado de volta."length"significa que o orçamento de tokens acabou antes de o modelo terminar. Leia esse campo junto com o conteúdo retornado e as solicitações de ferramentas antes de decidir o próximo passo.
Comparar onde as APIs mantêm o estado da conversa?
Este curso usa a
Chat Completions API
o tempo todo: você mantém a conversa como um array messages[] no seu próprio código e reenvia o array completo a cada turno. A mais recente
Responses API
pode, em vez disso, manter a thread no servidor, de modo que você envia apenas a nova entrada e uma referência ao turno anterior. De qualquer forma, o modelo permanece sem estado e inalterado entre as chamadas. A conversa vive fora dele, em um estado que seu código ou o servidor guarda.
Uma chamada de verdade, no seu navegador
Pressione Run para enviar uma única requisição. Ela se sustenta inteiramente sozinha, sem nenhum laço em volta e sem carregar nada de um turno anterior.
Inspecionar a solicitação e a resposta HTTP brutas?
O que o chat() realmente envia
chat() é um wrapper de conveniência em torno de um único
POST HTTP comum no formato de transmissão compatível com a OpenAI. Essa requisição carrega três coisas:
- o endpoint para onde enviar,
- os cabeçalhos da solicitação; um endpoint personalizado pode exigir um cabeçalho
Authorization, - e um corpo JSON com
modelemessages.
A célula abaixo monta essa chamada manualmente. Abra request para examinar a URL, os cabeçalhos e o corpo, com qualquer valor de autorização oculto. Abra raw response para examinar o objeto completo retornado por chat().
O endpoint do modelo usa esse formato. O gateway do OpenClaw do módulo 3 expõe um protocolo separado para turnos do agente, sessões e operações do ambiente de execução.
Configure um endpoint compatível no painel do modelo antes de executar a célula. Os endpoints hospedados pela NVIDIA exigem uma chave de API da NVIDIA. Confira o acesso e a cota do serviço selecionado. O painel mostra o endpoint ativo e as configurações de credenciais; examine a solicitação abaixo, com os dados sensíveis ocultos, antes de enviá-la.
A rota selecionada determina qual serviço recebe a solicitação e sua credencial. Uma chamada pelo navegador exige que o endpoint permita a origem do curso. O curso pode usar seu serviço de retransmissão configurado quando o provedor não permite essa solicitação direta pelo navegador. Examine a rota ativa e os cabeçalhos da solicitação no painel do modelo.
Examine o helper de streaming.chatStream() processa o texto da resposta, qualquer texto de raciocínio retornado, os metadados de uso e o sinal de fim da transmissão. Ele conecta a resposta ao painel da lição e ao botão Stop. Abra o código-fonte do helper pelo menu da célula para examinar a solicitação e o tratamento de eventos.
Comparar formas de raciocinar sobre o labirinto dentro de um ciclo fixo?
Trocar a função de decisão sem alterar o ciclo
Os próximos exemplos mantêm o ciclo de perceber, raciocinar e agir e variam sua função de decisão. Compare regras fixas e algoritmos de busca antes de usar chat() para escolher um movimento.
Execute os nós em ordem. Cada um aplica uma regra de decisão diferente ao mesmo ciclo que resolve o labirinto:
- A regra constante "sempre leste" alcança o objetivo em um corredor reto, depois trava na primeira parede do labirinto, já que um rumo fixo não consegue virar.
- A busca em profundidade (DFS) segue um ramo até o fim antes de voltar.
- A busca em largura (BFS) explora a fronteira por níveis e encontra o caminho mais curto em uma grade sem pesos.
- O A* usa uma heurística de distância para priorizar caminhos promissores sem perder a garantia de menor caminho.
Como usar um modelo de linguagem para escolher movimentos
O controlador registra as células visitadas e um caminho de volta, filtra os ramos visitados e percorre os corredores. Nas bifurcações, o modelo lê o mapa e escolhe a ordem dos ramos com choose_direction. O controlador gerencia a exploração em profundidade; ele não fornece ao modelo uma rota resolvida.
Execute as células nesta ordem e depois altere um controle por vez:
- Comece pelo nó do mecanismo. Ele exporta os utilitários e o resolvedor compartilhado
state.runMaze, que percorre corredores automaticamente e chama o modelo somente nas bifurcações. - Execute o nó editável do agente de labirinto abaixo.
DIRECTIVEé a instrução central do sistema; o objeto de opções controla o modelo, o tamanho do labirinto, o mapa textual, o histórico de movimentos, a trilha de coordenadas e a repetição do schema da ferramenta. - Comece com os padrões funcionais. Depois, altere
modelpara comparar rotas com capacidades verificadas, remova o histórico ou definaadvancedpara ampliar o labirinto quando o caso simples funcionar.
choose_direction declara os valores de direção permitidos. O modelo solicita uma direção, e o controlador verifica o nome da ferramenta e os argumentos antes de mover. Examine a solicitação e a resposta para distinguir o esquema declarado da validação feita pelo seu código.O ciclo em detalhe
No exemplo do labirinto, o controlador monta uma solicitação para chat() e valida o movimento retornado antes de aplicá-lo. As etapas abaixo mostram essa troca.
- Amostrar localmente. Seu código lê uma parte do ambiente. Aqui ele lê a célula atual do labirinto e seus movimentos válidos. A solicitação também pode incluir o mapa completo e os turnos anteriores, dependendo dos controles selecionados.
- Perceber localmente. Essa parte é incorporada a um contexto completo e preparado: o prompt de sistema, o histórico acumulado de
messages[], os resultados anteriores de ferramentas e a parte que você acabou de amostrar. Neste exemplo, o labirinto é representado como texto nas mensagens enviadas ao modelo. - Agir localmente. O modelo mapeia esse texto em mais texto: um
sinal de intenção, idealmente uma chamada de ferramenta tipada como
{ "move": "east" }em vez de prosa livre. A intenção apenas solicita uma ação, e nunca executa uma. Seu código a lê e aplica uma atualização limitada ao ambiente (doMove(...)), validando-a primeiro. - Impactar localmente. A atualização muda o mundo. Nada permanece dentro do modelo. O estado durável está no ambiente e no contexto que o código reconstruirá. No turno seguinte, a amostragem local lê o mundo alterado e o ciclo recomeça.
Neste exemplo, chat() recebe texto que descreve o labirinto e retorna uma solicitação de movimento. O controlador fornece as observações, valida a solicitação e altera o estado do labirinto. A chamada ao modelo não executa o movimento.
Examine os dois limites: o contexto fornecido ao modelo e a validação que seu código realiza antes de aplicar uma ação solicitada.
Antes de continuar
Cada pergunta pode ser respondida ajustando um controle na célula do labirinto-LLM acima e rodando de novo.
- Compare o histórico de conversa. Defina
includeHistory:falsee execute novamente com o mesmo perfil e labirinto. Compare a ordem dos ramos, as decisões nas bifurcações e o tempo decorrido com o histórico ativado. O controlador mantém as células visitadas e o caminho de volta nas duas execuções. - Remova a dica de estratégia de DIRECTIVE. Apague a linha que recomenda preferir ramos não explorados a células visitadas e execute novamente com o mesmo perfil e labirinto. Compare a ordem dos ramos, as decisões nas bifurcações e o tempo decorrido. O controlador continua filtrando os ramos visitados; repita as execuções para verificar se alguma diferença persiste.
- Compare perfis de modelo. Comece com
model:"direct"e depois comparemodel:"reasoning"emodel:"omni"no mesmo labirinto. Examine o modelo, o orçamento de tokens, a temperatura e as configurações de raciocínio de cada solicitação. Esses perfis alteram várias configurações; compare a ordem dos ramos e a latência sem atribuir toda diferença apenas à identidade do modelo.
Experimente · compare o histórico de conversa
Este chat começa com o histórico de conversa ativado. Diga seu nome e depois pergunte qual é o seu nome. Desative o controle de memória e pergunte novamente. Cada chamada a chat() recebe as mensagens montadas pela interface; com a memória desativada, os turnos anteriores são omitidos. Compare as respostas e examine como o código monta a solicitação.