DEV Community

Cover image for Crie um assistente de terminal com Python, IA e memória em SQLite

Crie um assistente de terminal com Python, IA e memória em SQLite

🎯 O que vamos construir

Neste tutorial, você criará um assistente que recebe perguntas pelo terminal, consulta um modelo de IA e salva as conversas em SQLite. Ao reiniciar o programa, ele recuperará as mensagens recentes para continuar a conversa.

Você também adicionará comandos para limpar a conversa e encerrar o programa.

Tempo estimado de leitura: 8 minutos. A execução das etapas pode levar mais tempo.

🧠 A teoria mínima necessária

Nosso projeto terá três peças:

  • Python: coordena a entrada do usuário, a consulta à IA e o armazenamento.
  • API de IA: recebe mensagens e devolve uma resposta. Pense nela como um serviço acessado por um balcão de atendimento.
  • SQLite: guarda o histórico em um arquivo local, sem exigir um servidor de banco de dados.

Para a IA acompanhar a conversa, enviaremos algumas mensagens anteriores junto com cada pergunta. É como entregar um resumo do atendimento antes de fazer uma nova solicitação.

Isso não treina o modelo: apenas fornece contexto naquela chamada.

📌 Nota / Dica: Este assistente responde perguntas. Ele não executa comandos do sistema nem modifica arquivos por solicitação da IA.

🧱 Passo 1: prepare o ambiente

Você precisará de Python 3.10 ou superior e de uma chave de API da OpenAI com acesso a um modelo compatível.

Crie a pasta e o ambiente virtual:

mkdir assistente-terminal
cd assistente-terminal
python -m venv .venv
Enter fullscreen mode Exit fullscreen mode
  • mkdir cria a pasta do projeto.
  • cd entra nessa pasta.
  • python -m venv cria um ambiente isolado para instalar as dependências.

Ative o ambiente no Linux ou macOS:

source .venv/bin/activate
Enter fullscreen mode Exit fullscreen mode
  • source aplica a configuração do ambiente ao terminal atual.

No Windows, usando PowerShell:

.\.venv\Scripts\Activate.ps1
Enter fullscreen mode Exit fullscreen mode
  • O script Activate.ps1 ativa o mesmo ambiente no PowerShell.

Instale o SDK, a biblioteca oficial usada para conversar com a API:

python -m pip install openai
Enter fullscreen mode Exit fullscreen mode
  • python -m pip instala o pacote no Python do ambiente ativo.
  • sqlite3 já acompanha as distribuições usuais do Python.

Configure a chave no Linux ou macOS:

export OPENAI_API_KEY="sua-chave"
Enter fullscreen mode Exit fullscreen mode
  • export disponibiliza a chave para os programas iniciados nesse terminal.

No PowerShell:

$env:OPENAI_API_KEY="sua-chave"
Enter fullscreen mode Exit fullscreen mode
  • $env: define uma variável de ambiente na sessão atual.

⚠️ Atenção / Erro Comum: A API pode gerar cobranças por uso. Uma assinatura do ChatGPT não substitui o acesso à API. Não coloque sua chave no código nem publique o histórico de comandos que a contenha.

🧱 Passo 2: crie a memória em SQLite

Crie um arquivo chamado assistente.py. Adicione os blocos seguintes, na ordem apresentada.

Comece pelas importações e configurações:

import os
import sqlite3
from contextlib import closing

from openai import OpenAI, OpenAIError

BANCO = "conversas.db"
MODELO = os.getenv("OPENAI_MODEL", "gpt-4.1-mini")
LIMITE_HISTORICO = 12
Enter fullscreen mode Exit fullscreen mode
  • os lê configurações do ambiente.
  • sqlite3 acessa o banco.
  • closing garante o fechamento da conexão ao sair de um bloco.
  • OpenAI é o cliente da API; OpenAIError representa erros dessa biblioteca.
  • BANCO define o arquivo local.
  • MODELO aceita uma configuração externa e usa um valor padrão.
  • LIMITE_HISTORICO limita quantas mensagens anteriores serão enviadas.

Se o modelo padrão não estiver disponível na sua conta, configure OPENAI_MODEL com outro modelo compatível com Chat Completions.

Agora crie a estrutura do banco:

def preparar_banco():
    with closing(sqlite3.connect(BANCO)) as conexao:
        with conexao:
            conexao.execute("""
                CREATE TABLE IF NOT EXISTS mensagens (
                    id INTEGER PRIMARY KEY,
                    papel TEXT NOT NULL,
                    conteudo TEXT NOT NULL
                )
            """)
Enter fullscreen mode Exit fullscreen mode
  • connect abre o arquivo ou o cria, caso ainda não exista.
  • with conexao confirma a operação quando ela termina com sucesso.
  • CREATE TABLE IF NOT EXISTS cria a tabela somente quando necessário.
  • id identifica e ordena as mensagens.
  • papel registra quem escreveu; conteudo guarda o texto.

SQLite funciona como um caderno organizado: cada linha representa uma mensagem.

🧱 Passo 3: salve e recupere conversas

Vamos salvar a pergunta e a resposta juntas:

def salvar_turno(pergunta, resposta):
    with closing(sqlite3.connect(BANCO)) as conexao:
        with conexao:
            conexao.executemany(
                "INSERT INTO mensagens (papel, conteudo) VALUES (?, ?)",
                [("user", pergunta), ("assistant", resposta)],
            )
Enter fullscreen mode Exit fullscreen mode
  • salvar_turno recebe os dois lados de uma interação.
  • executemany executa a inserção para cada par de valores.
  • user identifica o usuário; assistant, a IA.
  • Os marcadores ? passam os valores separadamente do SQL.
  • A transação mantém as duas mensagens juntas: se a gravação falhar, nenhuma delas é confirmada.

⚠️ Atenção / Erro Comum: Não monte consultas SQL concatenando texto digitado pelo usuário. Use parâmetros como ?, inclusive quando a entrada parecer inofensiva.

Em seguida, recupere as mensagens recentes:

def carregar_historico():
    with closing(sqlite3.connect(BANCO)) as conexao:
        linhas = conexao.execute(
            """
            SELECT papel, conteudo
            FROM mensagens
            ORDER BY id DESC
            LIMIT ?
            """,
            (LIMITE_HISTORICO,),
        ).fetchall()

    return [
        {"role": papel, "content": conteudo}
        for papel, conteudo in reversed(linhas)
    ]
Enter fullscreen mode Exit fullscreen mode
  • ORDER BY id DESC busca primeiro as mensagens mais novas.
  • LIMIT ? restringe a quantidade recuperada.
  • A vírgula em (LIMITE_HISTORICO,) cria uma tupla com um elemento.
  • fetchall reúne os resultados.
  • reversed restaura a ordem cronológica.
  • role e content são os campos esperados pela API.

O banco manterá todo o histórico, mas enviaremos apenas as últimas 12 mensagens. Esse limite reduz o contexto e ajuda a controlar custos, embora não limite o tamanho de cada mensagem.

🧱 Passo 4: conecte o assistente à IA

Adicione a função responsável pela resposta:

def perguntar_ia(cliente, pergunta):
    mensagens = [
        {
            "role": "system",
            "content": (
                "Você é um assistente de terminal. "
                "Responda em português, com clareza e objetividade."
            ),
        },
        *carregar_historico(),
        {"role": "user", "content": pergunta},
    ]

    resultado = cliente.chat.completions.create(
        model=MODELO,
        messages=mensagens,
    )

    resposta = resultado.choices[0].message.content
    if not resposta:
        raise ValueError("A API não retornou uma resposta de texto.")

    return resposta
Enter fullscreen mode Exit fullscreen mode
  • A mensagem system orienta o comportamento do assistente.
  • *carregar_historico() inclui as mensagens anteriores na lista.
  • A última mensagem contém a pergunta atual.
  • create envia a solicitação ao modelo.
  • choices[0] acessa a primeira alternativa retornada.
  • A verificação evita salvar uma resposta vazia.

📌 Nota / Dica: As mensagens recuperadas do SQLite serão enviadas ao provedor da API. Evite inserir senhas, chaves ou informações confidenciais.

🧱 Passo 5: adicione os comandos do terminal

Primeiro, implemente a limpeza do histórico:

def limpar_historico():
    with closing(sqlite3.connect(BANCO)) as conexao:
        with conexao:
            conexao.execute("DELETE FROM mensagens")
Enter fullscreen mode Exit fullscreen mode
  • DELETE FROM mensagens remove todas as linhas da tabela.
  • A tabela continua disponível para novas conversas.
  • Esse comando limpa o histórico usado pelo aplicativo; não representa apagamento seguro do arquivo em disco.

Agora adicione o fluxo principal:

def main():
    if not os.getenv("OPENAI_API_KEY"):
        print("Configure a variável OPENAI_API_KEY antes de iniciar.")
        return

    preparar_banco()
    cliente = OpenAI(timeout=30.0, max_retries=1)
    print("Assistente pronto! Comandos: /limpar e /sair")

    while True:
        pergunta = input("\nVocê: ").strip()

        if not pergunta:
            continue
        if pergunta == "/sair":
            break
        if pergunta == "/limpar":
            limpar_historico()
            print("Histórico limpo.")
            continue

        try:
            resposta = perguntar_ia(cliente, pergunta)
            salvar_turno(pergunta, resposta)
        except (OpenAIError, ValueError) as erro:
            print(f"Não foi possível obter a resposta: {erro}")
            continue

        print(f"\nAssistente: {resposta}")
Enter fullscreen mode Exit fullscreen mode
  • A verificação inicial detecta a ausência da chave.
  • timeout limita a espera de cada tentativa; max_retries permite uma nova tentativa em falhas elegíveis.
  • while True mantém a conversa funcionando.
  • strip remove espaços nas extremidades.
  • continue inicia a próxima interação; break encerra o laço.
  • try e except tratam falhas da API e respostas vazias.
  • O histórico só é salvo após uma resposta válida.

Finalize o arquivo:

if __name__ == "__main__":
    try:
        main()
    except (KeyboardInterrupt, EOFError):
        print("\nAté mais!")
    except sqlite3.Error as erro:
        print(f"Erro no banco de dados: {erro}")
Enter fullscreen mode Exit fullscreen mode
  • A condição executa main quando o arquivo é iniciado diretamente.
  • KeyboardInterrupt permite sair com Ctrl+C.
  • EOFError trata o encerramento da entrada.
  • sqlite3.Error apresenta falhas de armazenamento.

🔍 Passo 6: teste a memória

Execute na pasta do projeto:

python assistente.py
Enter fullscreen mode Exit fullscreen mode
  • O comando inicia o programa e cria conversas.db nessa pasta.

Faça este teste:

  1. Digite: “Estou aprendendo Python e quero criar uma lista de tarefas”.
  2. Encerre com /sair.
  3. Execute novamente e pergunte: “Qual projeto eu quero criar?”.
  4. Use /limpar e repita a pergunta.

Antes da limpeza, o assistente deve conseguir usar a conversa anterior. Depois, aquela informação deixa de integrar o contexto enviado.

⚠️ Atenção / Erro Comum: O caminho do banco é relativo à pasta de execução. Iniciar o programa em outra pasta pode criar outro arquivo e dar a impressão de que a memória desapareceu.

🛠️ Tabela de Sintaxe

Comando/Propriedade O que faz Exemplo
sqlite3.connect Abre o banco sqlite3.connect(BANCO)
execute Executa SQL conexao.execute(sql, valores)
LIMIT Restringe resultados LIMIT 12
/limpar Apaga a conversa salva /limpar
/sair Encerra o programa /sair

💪 Faça você mesmo

  1. Personalize o assistente: altere a mensagem system para criar um tutor de Python. Teste como a orientação muda as respostas.
  2. Crie o comando /historico: mostre as mensagens retornadas por carregar_historico() sem consultar a API.
  3. Separe conversas: adicione um identificador de sessão à tabela e filtre as consultas por ele. Assim, cada projeto poderá ter seu próprio histórico.

🚀 Novidades, Desafios e Dicas

Quer sair da teoria e construir um portfólio real com validação automática e apoio da comunidade?

Acesse nossos canais oficiais:

Comunidade HDEV | Desenvolvimento de Casa + DevsFree


Notas do Editor

  • A construção foi dividida em etapas pequenas, com explicação das instruções-chave após cada bloco.
  • Foram explicitados os limites da memória, os cuidados com credenciais e um roteiro para verificar a persistência entre execuções.


https://mercadolivre.com/sec/1EroZqV

Top comments (0)