Conteúdo detalhado
⚙️ Preparação e Ambiente
Tudo que precisa estar no lugar antes de escrever a primeira linha do agente: bot do Telegram, chave do modelo, projeto Node, segredos protegidos e um teste fim-a-fim.
Um bot é uma conta automática no Telegram, criada conversando com o @BotFather. No fim, você recebe um token (uma string longa) que dá ao seu código permissão pra ler e enviar mensagens em nome do bot.
É a porta por onde você fala com o agente. Sem o bot, não tem canal — e fora isso o Telegram é grátis, multiplataforma e tem cliente em todo dispositivo que você já usa.
@BotFather, token, chat ID do seu usuário (pra restringir quem fala), polling vs webhook, biblioteca cliente (Telegraf).
A credencial que autoriza seu código a chamar o modelo de IA. Pode ser uma API key paga (Anthropic, OpenAI), uma agregadora barata (OpenRouter) ou um modelo rodando local de graça (Ollama).
Sem modelo o agente não pensa. E ter abstração desde o início deixa você trocar a quente — começa em DeepSeek por centavos, vai pra Claude quando precisa de qualidade, fallback pra Ollama se a internet caiu.
API key, custo por token (input vs output), context window, model name, OpenRouter como "uma chave pra todos", Ollama pra rodar local sem custo.
Inicializar um projeto Node.js com TypeScript: instalar Node 20+, rodar npm init, configurar tsconfig.json e ter um script "dev" que roda o código.
É o esqueleto. TypeScript te dá tipos pra evitar erros bobos, hot-reload pra iterar rápido e estrutura pro projeto crescer sem virar bagunça.
npm init, tsconfig.json (target ES2022, module Node16), tsx para rodar TS direto, scripts no package.json, gerenciamento de dependências.
Um arquivo .env guarda chaves e configs fora do código. O .gitignore garante que ele nunca vai pro repositório público — e o .env.example documenta quais variáveis existem sem expor valores.
É a diferença entre vazar suas chaves no GitHub e ter o agente seguro. É a primeira regra de segurança de qualquer projeto sério, e custa zero implementar.
dotenv, .env vs .env.example, .gitignore, separação dev/prod, nunca commitar segredo, gerenciador de segredos no deploy (Railway, Doppler).
Uma divisão clara: src/ pro código, scripts/ pra utilitários (migrations, seeds), data/ pra arquivos do agente em tempo real (SQLite, logs), tests/ pra testes.
Quando o projeto crescer pra 50 arquivos, ter convenção evita "onde eu coloco isso?" toda hora. Reduz fricção e ajuda IA a entender seu código quando você pedir ajuda.
Separação de responsabilidades, code vs data vs config, módulos por domínio (memory/, tools/, llm/), index.ts como ponto de entrada.
Um script único que: lê o token e a chave do .env, conecta no Telegram, chama o LLM com uma mensagem fixa e responde no chat. Só pra provar que tudo conversa.
É a vitória rápida. Se isso roda, você sabe que o Telegram, o LLM e seu código estão alinhados — qualquer feature daqui pra frente é construir em cima dessa base.
Smoke test, debugging em camadas (credenciais → rede → resposta), logs informativos, polling do Telegram, primeiro round-trip de tokens.
🧠 Identidade e Memória
Sem identidade o agente responde genérico. Sem memória ele esquece tudo. Aqui você dá voz, regras e três camadas de memória que fazem ele lembrar de você de verdade.
Um arquivo Markdown com o "system prompt" do agente: tom de voz, formato de resposta, o que ele faz, o que recusa, e fatos básicos sobre você.
É o que separa um chatbot genérico de um assistente que parece seu. Ajustar o soul depois de uma semana de uso é onde a magia acontece — você ensina o estilo dele.
System prompt, identidade vs comportamento, regras explícitas (o que NÃO fazer), Markdown como formato versionável, recarregar sem reiniciar o processo.
Um módulo único que lê o .env, valida tipos, expõe um objeto config tipado (modelo, tamanho do buffer, fuso, limites) pro resto do código importar.
Centralizar config evita process.env espalhado por toda parte. Quando você mudar o nome de uma variável, muda em um lugar só — e o TypeScript te avisa onde ainda usa o antigo.
Single source of truth, validação com Zod, config tipada, valores default, separação config vs código.
As últimas N mensagens da conversa (40, 100, o que couber no contexto), guardadas em SQLite e re-enviadas a cada chamada do LLM pra ele lembrar do que vocês acabaram de falar.
É o que dá continuidade — sem isso, cada mensagem sua é uma conversa nova do zero. Com isso, você diz "manda mais um igual o anterior" e ele entende.
Buffer FIFO, SQLite com better-sqlite3, contagem de tokens vs contagem de mensagens, summary quando o buffer estoura, role (user/assistant/system).
Uma tabela chave-valor em SQLite com fatos centrais sobre você: nome, fuso, profissão, metas atuais, pessoas importantes. Esses fatos vão em TODA chamada do LLM.
Faz o agente nunca esquecer o essencial. Você diz "minha esposa se chama Ana" uma vez e ele lembra pra sempre, sem precisar repetir nem buscar no histórico.
Key-value store, persistência indefinida, hot reload (mudou o fato, próxima resposta já usa), budget de tamanho (~2k chars), atualização via tool call.
Cada mensagem é convertida em um vetor (embedding) e indexada num banco vetorial (Pinecone, sqlite-vec). Quando você pergunta algo, busca os trechos mais parecidos em significado, não em palavras exatas.
É o que deixa o agente lembrar de coisas ditas há meses. Você diz "aquele cliente que reclamou de prazo" e ele recupera a conversa certa, mesmo sem usar palavra-chave.
Embedding (vetor de ~1500 dimensões), cosine similarity, top-k retrieval, chunking, modelos de embedding (text-embedding-3-small, voyage-2), opção local vs cloud.
A regra de bolso: fatos centrais sempre vão (camada 1), buffer recente sempre vai (camada 2), busca semântica é chamada por tool quando o agente percebe que precisa lembrar de algo antigo (camada 3).
Mandar tudo a cada mensagem queima tokens à toa. Mandar pouco demais e ele parece amnésico. A estratégia certa é o equilíbrio entre custo e memória — e muda o quanto você gasta por mês.
Custo por token, recall vs precision, when to retrieve (lazy vs eager), tool de busca como acesso à camada 3, hierarquia de memória.
🛠 Cérebro e Ferramentas
Onde o agente sai do "só conversa" pra "executa tarefa de verdade". Você aprende a abstração de LLM, anatomia de uma ferramenta, e o loop que junta tudo.
Uma interface chat({messages, tools}) que esconde se por baixo é Claude, GPT, DeepSeek ou Ollama. O resto do código nunca sabe qual modelo tá rodando.
Modelos novos saem todo mês. Quando o próximo for muito melhor, você troca uma string no .env em vez de reescrever metade do código. É a única abstração que se paga em meses.
Adapter pattern, formatos diferentes (Anthropic/OpenAI/Ollama), tradução de tool calls entre formatos, fallback chain, OpenRouter como facilitador.
Toda ferramenta tem 3 partes: nome (identificador), JSON Schema (descrição dos parâmetros pro LLM saber chamar), e handler (a função TS que executa de verdade).
Ferramentas são como o agente sai da caixa. Aprender o padrão uma vez te deixa adicionar 50 ferramentas novas seguindo a mesma receita — Notion, Gmail, banco, qualquer API.
Tool definition, JSON Schema (types, required, descriptions), handler como função pura, retorno como string ou JSON, validação de input.
As 5 primeiras ferramentas que todo agente precisa: ler arquivo, escrever arquivo, buscar na web, ler URL, e atualizar memória central. São o kit mínimo.
Com essas 5 já dá pra fazer 80% do que você quer: pesquisa, anotação, lembrete, follow-up. As outras 50 ferramentas que você vai querer depois seguem o mesmo padrão.
Allowlist de paths (segurança), descrição clara pro LLM saber quando chamar, retornos pequenos (truncar grandes), tratamento de erro como string legível.
O coração do sistema: pega mensagem do usuário → chama LLM → se ele pediu ferramenta, executa e devolve o resultado pra ele → repete até ele responder em texto puro.
É o que separa "chatbot" de "agente". Sem loop, ele só fala. Com loop, ele lê arquivos, busca dados, encadeia 5 ações pra responder uma pergunta complexa.
tool_calls no response, executar handler, append do tool_result, condição de parada (resposta final vs tool call), max iterations (15-20).
Cinto de segurança do loop: limite de N iterações pra ele não entrar em espiral infinita, allowlist de pastas onde ele pode mexer, timeout em chamadas de rede.
Loop sem limite + bug = fatura de $300 numa noite. Allowlist mal feita + agente confuso = arquivo importante apagado. São proteções que custam 5 minutos pra escrever.
MAX_ITER, fail-safe, allowlist (não denylist), absolute paths obrigatórios, timeouts de fetch, kill switch via env.
A última peça: o loop terminou, você tem o texto final. Agora envia pro Telegram com formatação Markdown (negrito, código), tratando mensagens longas (cortar em 4096 chars).
Detalhes que parecem simples e quebram tudo na prática: o Telegram não aceita Markdown padrão, tem limite de tamanho, e mensagem com erro de formato falha silenciosa.
parse_mode (MarkdownV2 vs HTML), escape de caracteres especiais, split de mensagem longa, retry em 429 (rate limit), salvar a mensagem no buffer.