Pular para o conteúdo
astorlm
Idioma: Português
← Mapa

Nível 12

Planejar e refletir

Escreva o plano antes de mexer em qualquer coisa, e confira o trabalho antes de aceitar a resposta. O plano mantém o agente no rumo; a revisão pega o que ele diz que fez, mas não fez.
1/52 Dobras do bandoneón:
  • user
  • assistant
  • tool_result
Uma entrega de jornais na rua Tango. A banca é onde o modelo fica, com a folha de rota pregada ao lado: o plano. O editor é o seu código.

EventBus

O problema

Dê a um agente um trabalho com várias partes e ele começa pelo que estiver na frente dele. No meio do caminho, os primeiros passos ficaram lá atrás no histórico, e ele esquece um. No fim, responde “pronto!” com total confiança, porque nada o obriga a olhar.

Esse é o Scatterbrain. Duas falhas numa só: sem plano, os passos se perdem; sem checagem, um passo que deu errado é relatado como feito. Na rua Tango, a ferramenta disse com todas as letras que o jornal caiu nos arbustos. O modelo leu e marcou a caixa mesmo assim.

A solução

Primeiro, planeje. Antes da primeira ação de verdade, o agente escreve o trabalho como uma lista de tarefas, e marca cada uma conforme avança. O truque que faz isso funcionar: o plano inteiro é adicionado a toda requisição, então o modelo sempre vê o que está feito e o que falta, por mais longo que fique o histórico. No astorlm, isso é pattern: 'PLAN_EXECUTE': duas ferramentas, add_plan_item e update_plan_item, e o plano no system prompt a cada turno.

Reflita antes de aceitar. Uma caixa marcada é só o que o modelo diz. Quando o run() retorna, o seu código revisa o resultado antes de aceitá-lo. Se algo estiver faltando, a constatação volta como uma nova mensagem na mesma sessão: o agente mantém o histórico e o plano, e corrige só o que está errado. Limite o número de rodadas. Há três jeitos de revisar, do mais forte ao mais fraco:

  • Conferir o mundo

    O seu código olha o resultado em si: as varandas, as linhas do banco de dados, a suíte de testes, o arquivo no disco.

    O melhor revisor quando você pode tê-lo: barato, exato, e ninguém consegue convencê-lo de nada. Exige que o trabalho possa ser conferido por código.

  • Um modelo crítico

    Uma segunda chamada lê a tarefa, a resposta e uma checklist, e lista o que está errado ou faltando.

    Para trabalho que nenhum código consegue conferir: um resumo, um e-mail, um plano. Custa uma chamada, também pode deixar coisas passarem, e precisa de critérios concretos, não de “isto está bom?”.

  • Perguntar ao agente

    O system prompt manda o agente reler o trabalho antes de responder.

    De graça e, às vezes, suficiente. Mas é o mesmo modelo dando nota a si mesmo, com os mesmos pontos cegos: ele já marcou o #14 uma vez.

É a mesma ideia de uma avaliação do nível 11, usada em tempo de execução: uma avaliação dá nota a execuções depois do fato, para melhorar o agente; uma revisão dá nota a esta execução antes que o usuário a veja.

O elenco

O mesmo elenco de sempre, desta vez numa entrega de jornais.

A banca o modelo
O Oráculo, atrás do balcão. Ele decide cada passo, e nunca pedala.
A folha de rota o plano
As tarefas e suas caixas. Ela brilha em dourado a cada turno: vai em toda requisição.
A bike do Astor o loop
Leva cada chamada de ferramenta, ida e volta, com o histórico no bandoneón.
Um arremesso deliver
Uma ferramenta comum. Ela diz onde o jornal caiu.
O editor o seu código
Passa o trabalho, e revisa as varandas antes de aceitar a resposta. A lupa dele é o review().

O código

Com astorlm: pattern: 'PLAN_EXECUTE' adiciona as ferramentas do plano e coloca o plano em toda requisição; getPlan() o lê de volta. A revisão é código comum depois do run(), e um segundo run() no mesmo agente continua a mesma sessão.

Do zero: Uma lista, duas ferramentas que a editam, e um system prompt reconstruído com a lista a cada turno. O histórico vive fora do run(), então a correção continua a mesma conversa.

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

// Any OpenAI-compatible endpoint: OpenAI, Ollama, LM Studio, vLLM, a proxy…
const LLM = { baseURL: 'http://localhost:11434/v1', apiKey: 'YOUR_API_KEY' } // local servers usually ignore the key

const SUBSCRIBERS = [12, 14, 18]
const porches = new Set<number>() // the real world: which porches have a paper

const deliver = tool({
  name: 'deliver',
  description: 'Ride to a house and throw today’s paper onto its porch. Says where the paper landed.',
  schema: z.object({ house: z.number() }),
  execute: async ({ house }) => {
    const landed = throwPaper(house) // your code: 'porch' or 'bushes'
    if (landed === 'porch') porches.add(house)
    return landed === 'porch' ? `Paper on the porch at #${house}.` : `Paper landed in the bushes at #${house}.`
  },
})

// PLAN: the agent gets add_plan_item and update_plan_item,
// and the current plan is added to the system prompt on every turn.
const agent = await createLocalAgent({
  provider: new OpenAIProvider({ ...LLM, model: 'your-model' }), // e.g. 'llama3.1', 'gpt-4o-mini'
  pattern: 'PLAN_EXECUTE',
  systemPrompt: 'You deliver newspapers. Plan every stop before you start, and tick each task as you go.',
  tools: [deliver],
  maxTurns: 20,
})

// REFLECT: check the work itself before accepting the answer. Deterministic when you can;
// a second model with a rubric when you can't.
const review = (): string[] => SUBSCRIBERS.filter((house) => !porches.has(house)).map((house) => `#${house} has no paper on the porch`)

let answer = await agent.run(`Deliver today’s paper to every subscriber on Tango Street: ${SUBSCRIBERS.join(', ')}.`)
for (let round = 1; round <= 2; round++) {
  const problems = review()
  if (problems.length === 0) break
  // Same agent, same session: it keeps its history and its plan, and fixes what's missing.
  answer = await agent.run(`Review found: ${problems.join('; ')}. Fix it.`)
}

console.log(agent.getPlan()) // [{ id: '1', description: 'Deliver to #12', status: 'completed' }, …]
console.log(answer.content)

O que observar

  • Mantenha as tarefas pequenas e verificáveis. “Entregar no #14” dá para verificar; “cuidar da rua”, não. Uma tarefa que você consegue conferir é uma tarefa que a revisão consegue pegar.
  • Deixe o plano mudar. Planos esbarram na realidade: uma rua está fechada, um cliente cancela. O agente deve poder adicionar, remover ou reordenar tarefas, e não seguir uma lista desatualizada.
  • Revise o mundo, não o plano. A folha dizia três marcações. Conferir a folha teria passado. A revisão precisa olhar o resultado em si.
  • Limite as rodadas. Uma revisão que nunca pode passar, ou um agente que não consegue corrigir o que encontra, fica em loop para sempre. Duas ou três rodadas, e depois passe para uma pessoa (nível 13).
  • Não planeje um trabalho de uma linha. Planejar custa turnos e tokens. Para uma única consulta, pule. Compensa quando o trabalho tem vários passos fáceis de perder.