> Nível 1 de Agent Harness Patterns, uma trilha de padrões sobre como funcionam os agentes de IA. Versão web: https://harnesspatterns.dev/pt/patterns/what-is-an-agent · Todos os padrões (em inglês): https://harnesspatterns.dev/llms.txt

# O que é um agente?

"Agente" é usado para quase tudo que tenha um modelo de linguagem dentro. A definição útil é bem mais estreita, e se resume a uma pergunta: quem decide o próximo passo? Num agente, quem decide é o modelo.

## O problema

Um chatbot, um script que chama um modelo duas vezes e um sistema que corrige bugs sozinho: todos são chamados de agentes. Isso dificulta saber o que você está construindo, e mais ainda escolher a ferramenta certa para o trabalho.

A animação é um pequeno jogo de aventura. Um aldeão pergunta: "Perdi a chave do baú da vila. Onde ela está?". O jogo tem duas funções que podem ajudar: `ask_villager` pergunta a alguém o que viu, e `search_area` procura num ponto do mapa. Repare em quem decide qual delas roda, e quando.

## O que faz dele um agente

Um agente não é "um LLM com ferramentas" nem "um workflow esperto". É um sistema em que **o modelo escolhe o fluxo de controle**: qual ferramenta chamar, em que ordem e quando parar. O seu código nunca diz "pergunte ao pescador e depois procure no carvalho". O modelo lê cada resultado e decide o próximo passo.

O loop que torna isso possível é o próximo nível.

## Na animação

- **O aldeão** (seu app): A pergunta sai de uma casa da vila, e a resposta volta para lá.
- **Astor** (o loop): O loop do agente, com o bandoneón de mensagens nas costas. Ele vai aonde os bilhetes do Oráculo mandam, e a nenhum outro lugar.
- **O Oráculo** (LLM): O modelo, numa caverna entre duas fogueiras. Ele nunca sai: só sabe o que está no bandoneón. Sem ferramentas, só consegue falar, como Petrus, o Inerte.
- **O cais e a floresta** (ferramentas): `ask_villager` e `search_area`: as suas próprias funções. Uma tela fica no escuro até que um caminho leve até ela.
- **As telas acesas** (fluxo de controle): O padrão inteiro numa imagem, também no minimapa. Cada caminho só aparece quando o Oráculo pede aquela ferramenta, depois de ler o último resultado. Num workflow, o seu código teria desenhado todos eles antes de alguém perguntar. A montanha continua no escuro: o modelo nunca precisou dela.
- **Rupias e corações** (tokens, maxTurns): Cada visita ao Oráculo custa rupias, porque o bandoneón inteiro é lido de novo, e um coração do orçamento de turnos. Os números são ilustrativos.

## O código

**Com astorlm:** Embrulhe as suas próprias funções com `tool()` e entregue-as ao agente. O loop já vem embutido: o modelo escolhe quais ferramentas chamar, em que ordem e quando já tem o suficiente para responder.

**Do zero:** As funções do seu jogo, entregues ao modelo como ferramentas. O loop em si é o do nível 2; a única novidade é quais ferramentas ele recebe.

**Com astorlm**

```ts
import { OpenAIProvider, createLocalAgent, tool } from 'astorlm'
import { z } from 'zod'

// Any OpenAI-compatible endpoint: OpenAI, Ollama, LM Studio, vLLM, a proxy…
const provider = new OpenAIProvider({
  baseURL: 'http://localhost:11434/v1', // e.g. Ollama's default address
  model: 'your-model', // e.g. 'llama3.1', 'gpt-4o-mini'
  apiKey: 'YOUR_API_KEY', // local servers usually ignore it
})

// Your own game functions, wrapped as tools: a name, a description and an input schema.
const askVillager = tool({
  name: 'ask_villager',
  description: 'Ask someone in the village what they saw. Returns what they say.',
  schema: z.object({ name: z.string().describe('Who to ask, e.g. "fisher" or "baker"') }),
  execute: async ({ name }) => world.villager(name).say(),
})

const searchArea = tool({
  name: 'search_area',
  description: 'Search one spot on the map. Returns what is found there, if anything.',
  schema: z.object({ area: z.string().describe('A named spot, e.g. "old oak" or "bridge"') }),
  execute: async ({ area }) => world.search(area),
})

// The model decides which tools to call, in what order, and when to stop.
const agent = await createLocalAgent({
  provider,
  tools: [askVillager, searchArea],
  maxTurns: 5, // a cap on the laps, in case it never settles
})

await agent.run('I lost the key to the village chest. Where is it?') // "In the crow's nest on the old oak"
```

**TypeScript**

```ts
// An agent that finds a villager's lost key. Plain TypeScript, no SDK.

// Your game. In a real one these read the world state and the characters' dialogue.
async function askVillager(name: string) {
  const seen: Record<string, string> = {
    fisher: 'A crow flew off with something shiny, toward the old oak in the woods.',
  }
  return seen[name] ?? `The ${name} saw nothing.`
}
async function searchArea(area: string) {
  return area === 'old oak' ? "In the crow's nest: a small brass key." : `Nothing at the ${area}.`
}

// The same functions, as tools the model can ask for. Each one returns text.
const tools = {
  ask_villager: ({ name }: { name: string }) => askVillager(name),
  search_area: ({ area }: { area: string }) => searchArea(area),
}

// runAgent is the loop from level 2, with the tools passed in. Your code never says
// "ask the fisher, then search the oak": the model picks each step after reading the last result.
export async function agent(question: string): Promise<string> {
  return runAgent(question, tools)
}
```

**Python**

```python
# An agent that finds a villager's lost key. Standard library only, no SDK.

# Your game. In a real one these read the world state and the characters' dialogue.
def ask_villager(name):
    seen = {"fisher": "A crow flew off with something shiny, toward the old oak in the woods."}
    return seen.get(name, f"The {name} saw nothing.")

def search_area(area):
    return "In the crow's nest: a small brass key." if area == "old oak" else f"Nothing at the {area}."

# The same functions, as tools the model can ask for. Each one returns text.
TOOLS = {
    "ask_villager": lambda args: ask_villager(args["name"]),
    "search_area": lambda args: search_area(args["area"]),
}

# run_agent is the loop from level 2, with the tools passed in. Your code never says
# "ask the fisher, then search the oak": the model picks each step after reading the last result.
def agent(question):
    return run_agent(question, TOOLS)
```

## Quando usar um, e quanto custa

- **Use quando você não consegue escrever os passos de antemão.** A chave pode estar num ninho, debaixo de uma ponte ou já vendida na loja: em código, cada caso novo é mais um ramo. O agente resolve todos com o mesmo loop, desde que tenha as ferramentas.
- **Cada passo é uma chamada ao modelo.** Duas ferramentas significaram três chamadas aqui. Mais passos significam mais latência e mais tokens, então limite as voltas com `maxTurns`.
- **A mesma pergunta pode seguir outro caminho.** Registre o caminho que o modelo escolheu, para poder ver por que uma resposta saiu do jeito que saiu.
- **As ferramentas são o limite.** O modelo só pode fazer o que as suas ferramentas permitem. O que você entrega a ele é o que ele pode quebrar.

## Padrões relacionados

- [2 · O loop do agente](https://harnesspatterns.dev/pt/patterns/agent-loop.md)
- [3 · Projetando uma ferramenta](https://harnesspatterns.dev/pt/patterns/designing-a-tool.md)
- [12 · Planejar e refletir](https://harnesspatterns.dev/pt/patterns/plan-and-reflect.md)
