Executando verificação de segurança...
1

CLI com IA: Construindo Ferramentas de Linha de Comando em Python e JavaScript que Usam LLMs de Verdade

O problema real: CLIs que chamam IA e quebram no primeiro timeout

A maioria dos tutoriais de "CLI com IA" para no openai.chat.completions.create(). O resultado é uma ferramenta que funciona na demo, trava no primeiro rate limit e não oferece nenhuma experiência decente quando a API demora 8 segundos para responder.

Construir uma CLI que integra LLMs para uso real exige resolver três problemas que ninguém cobre: streaming de resposta para o terminal não parecer congelado, fallback entre provedores quando um cai, e cache local para não torrar créditos repetindo a mesma pergunta. Este post resolve os três, em Python e em JavaScript, com código que roda.

Anatomia de uma CLI com IA que funciona

Antes de código, a estrutura. Uma CLI inteligente tem quatro camadas:

  1. Parser de argumentos: recebe input do usuário (prompt, arquivo, flags).
  2. Camada de cache: verifica se já respondeu aquela pergunta antes.
  3. Client HTTP com retry e fallback: chama o provedor primário, cai para o secundário se necessário.
  4. Renderer de output: streaming para o terminal com formatação.

A tabela abaixo compara as escolhas de biblioteca em cada camada:

CamadaPythonJavaScript (Node.js)
Parser de argumentosargparse (stdlib) ou clickcommander ou yargs
Cache localdiskcache ou SQLite via sqlite3keyv com adapter SQLite
Client HTTPhttpx (async, streaming nativo)fetch nativo (Node 18+) com ReadableStream
Streaming no terminalsys.stdout.write + flushprocess.stdout.write
Formatação de Markdownrichmarked-terminal

Se você já trabalha com ferramentas de automação em JavaScript, a camada de parser e output vai parecer familiar. A diferença é que agora o "meio" da CLI faz uma chamada de rede lenta e imprevisível.

Python: CLI completa com streaming e cache

Começando pelo parser. O click é mais ergonômico que argparse para CLIs que crescem:

# cli.py
import click
import hashlib
import json
import sqlite3
import os

DB_PATH = os.path.expanduser("~/.cache/aicli/cache.db")

def get_cache_db() -> sqlite3.Connection:
    os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
    conn = sqlite3.connect(DB_PATH)
    conn.execute(
        "CREATE TABLE IF NOT EXISTS cache "
        "(key TEXT PRIMARY KEY, response TEXT, created_at REAL DEFAULT (unixepoch()))"
    )
    return conn

def cache_key(model: str, prompt: str) -> str:
    # SHA256 garante chave fixa independente do tamanho do prompt
    raw = f"{model}::{prompt}"
    return hashlib.sha256(raw.encode()).hexdigest()

@click.command()
@click.argument("prompt")
@click.option("--model", default="gpt-4o-mini", help="Modelo a usar")
@click.option("--no-cache", is_flag=True, help="Ignora cache local")
def ask(prompt: str, model: str, no_cache: bool):
    """Envia um prompt para o LLM e exibe a resposta com streaming."""
    db = get_cache_db()

    if not no_cache:
        key = cache_key(model, prompt)
        row = db.execute("SELECT response FROM cache WHERE key = ?", (key,)).fetchone()
        if row:
            click.echo(row[0])
            return

    response_text = stream_completion(model, prompt)

    if response_text and not no_cache:
        db.execute(
            "INSERT OR REPLACE INTO cache (key, response) VALUES (?, ?)",
            (cache_key(model, prompt), response_text),
        )
        db.commit()

Agora a parte que importa: o client HTTP com streaming. Usar httpx em modo async permite ler chunks conforme chegam, em vez de esperar a resposta inteira:

# client.py
import httpx
import sys
import os
import json

OPENAI_URL = "https://api.openai.com/v1/chat/completions"
ANTHROPIC_URL = "https://api.anthropic.com/v1/messages"

def stream_completion(model: str, prompt: str) -> str:
    """Tenta OpenAI primeiro. Se falhar com status >= 500 ou timeout, cai para Anthropic."""
 

---

Leia o artigo completo em [https://www.vivodecodigo.com.br/backend/cli-ia-python-javascript-llm-ferramentas-linha-comando](https://www.vivodecodigo.com.br/backend/cli-ia-python-javascript-llm-ferramentas-linha-comando)
Carregando publicação patrocinada...