E1 · Um fato que fica
10 minDiga ao agente um fato seu ("lembre que meu time é o Grêmio") e abra o memoria.json.
Pronto quando: o memoria.json tem o seu fato e continua lá depois de fechar e abrir o terminal.
Aula 4 · 15 min
Cada conversa começa do zero, a não ser que o harness entregue duas coisas antes do pedido: as instruções (quem o agente é e como age) e a memória (o que ele já sabe de você). As duas ficam em arquivos de texto que você abre e edita.
Começar a aula
Objetivo: pôr as instruções em instrucoes.md e a memória em memoria.json, e ver um fato sobreviver de uma conversa para a outra.
Clique em cada peça.
Rode dentro de agente-do-zero/. O cp traz o agente.py da aula 4 e o instrucoes.md.
Você é o assistente pessoal do dono. Responda em português, em no máximo 3 frases. Use as ferramentas quando o pedido for sobre arquivos ou sobre algo para guardar. Quando o dono disser "lembre que...", chame a ferramenta lembrar com o fato. Se uma ferramenta responder "recusado", diga ao dono o motivo e não tente de outro jeito. Nunca invente o conteúdo de um arquivo: leia antes de responder.
#!/usr/bin/env python3
"""Agente do zero (aula 4): + instruções num arquivo e memória que fica entre uma conversa e outra."""
import json, os, sys, urllib.request
MODELO = os.environ.get("MODELO", "llama3.2")
URL = os.environ.get("OLLAMA_URL", "http://localhost:11434") + "/api/chat"
PASTA = os.path.realpath("trabalho")
MEMORIA = "memoria.json"
MAX_RODADAS = 5
def cerebro(mensagens, ferramentas):
corpo = {"model": MODELO, "messages": mensagens, "tools": ferramentas, "stream": False, "think": False,
"options": {"temperature": 0, "seed": 1}}
pedido = urllib.request.Request(URL, json.dumps(corpo).encode(), {"Content-Type": "application/json"})
with urllib.request.urlopen(pedido, timeout=600) as r:
return json.loads(r.read())["message"]
def memorias():
return json.load(open(MEMORIA)) if os.path.exists(MEMORIA) else []
def ler_arquivo(nome):
with open(os.path.join(PASTA, nome)) as f: # ainda sem trava: ela entra na aula 5
return f.read()
def lembrar(fato):
json.dump(memorias() + [fato], open(MEMORIA, "w"), ensure_ascii=False)
return f"guardado: {fato}"
FERRAMENTAS = {"ler_arquivo": ler_arquivo, "lembrar": lembrar}
DESCRICOES = [
{"type": "function", "function": {"name": "ler_arquivo", "description": "Lê um arquivo da pasta de trabalho.",
"parameters": {"type": "object", "properties": {"nome": {"type": "string"}}, "required": ["nome"]}}},
{"type": "function", "function": {"name": "lembrar", "description": "Guarda um fato sobre o dono para sempre.",
"parameters": {"type": "object", "properties": {"fato": {"type": "string"}}, "required": ["fato"]}}},
]
def responder(pedido, mostrar=print):
instrucoes = open("instrucoes.md").read()
lembrancas = "\n".join(f"- {m}" for m in memorias()) or "(nada ainda)"
mensagens = [{"role": "system", "content": f"{instrucoes}\n\nO que você sabe do dono:\n{lembrancas}"},
{"role": "user", "content": pedido}]
for rodada in range(MAX_RODADAS):
msg = cerebro(mensagens, DESCRICOES)
mensagens.append(msg)
if not msg.get("tool_calls"):
return msg.get("content", ""), rodada + 1
for chamada in msg["tool_calls"]:
nome, args = chamada["function"]["name"], chamada["function"].get("arguments") or {}
try:
saida = FERRAMENTAS[nome](**args)
except Exception as erro:
saida = f"recusado: {erro}"
mostrar(f"[ferramenta] {nome} {json.dumps(args, ensure_ascii=False)} -> {saida[:80]}")
mensagens.append({"role": "tool", "content": saida})
return "Parei: cheguei ao limite de rodadas.", MAX_RODADAS
if __name__ == "__main__":
os.makedirs(PASTA, exist_ok=True)
resposta, rodadas = responder(" ".join(sys.argv[1:]))
print(f"{resposta}\n({rodadas} rodada(s))")cd ~/agente-do-zero cp ~/agentes-do-zero-v72/kit/aula4/agente.py ~/agentes-do-zero-v72/kit/instrucoes.md . python3 agente.py "lembre que meu cachorro se chama Thor" cat memoria.json; echo python3 agente.py "qual o nome do meu cachorro?"
[ferramenta] lembrar {"fato": "Seu cachorro se chama Thor"} -> guardado: Seu cachorro se chama Thor
Você tem um cachorro chamado Thor. Posso ajudar com algo mais relacionado a ele?
(2 rodada(s))
["Seu cachorro se chama Thor"]
[ferramenta] ler_arquivo {"nome": "Thor"} -> recusado: [Errno 2] No such file or directory: '~/agente-do-zero/t
Desculpe, não consegui encontrar o nome do seu cachorro no arquivo. Você pode me dizer o nome do seu cachorro, Thor?
(2 rodada(s))O fato foi guardado (está no memoria.json) e foi entregue ao modelo na segunda conversa. Mesmo assim o llama3.2 foi procurar um arquivo chamado "Thor" e disse que não achou. Guardar funcionou; usar, não. Você vai medir isso na aula 6 e tentar consertar na aula 7.
Faça na ordem.
Diga ao agente um fato seu ("lembre que meu time é o Grêmio") e abra o memoria.json.
Pronto quando: o memoria.json tem o seu fato e continua lá depois de fechar e abrir o terminal.
Edite a primeira linha do instrucoes.md com nano instrucoes.md (por exemplo, "responda em uma frase só") e repita python3 agente.py "leia notas.txt e diga a hora da reunião".
Pronto quando: a resposta mudou de forma (mais curta, por exemplo) sem você alterar o agente.py. Se o modelo pequeno não obedecer de primeira, tudo bem: é isso que a aula 6 vai medir.
A explicação aparece depois da sua resposta.
Pergunta 1 de 3
Onde ficam as instruções do agente nesta versão?
Pergunta 2 de 3
Na saída capturada, o que deu errado na segunda conversa?
Pergunta 3 de 3
Por que a memória fica num arquivo e não só na conversa?
Escolha uma alternativa. A explicação aparece depois da sua tentativa.