9.2 KiB
ForgeLM
Inferência local de LLMs .gguf em Rust: API HTTP no estilo OpenAI, CLI e app
desktop Tauri com chat persistente e gerenciador de modelos — tudo rodando na sua máquina.
Início rápido · Recursos · Como funciona · Limitações · Documentação
Note
Estado do projeto: em desenvolvimento (último commit em abril/2026). Segundo
.planning/ROADMAP.md, as fases 1–4 (estado de rascunho do runtime, segurança dos comandos de ciclo de vida, workspace unificado e download de modelos do Hugging Face) estão concluídas e a fase 5 (validação de fontes de modelo) segue aberta. O histórico também registra os planos 06-01 a 06-03 (redesign do chat e da página de Configurações).
Important
A API sobe aberta por padrão. Sem
LOCALLLM_API_KEYnão há autenticação, o bind default é0.0.0.0:8080e o CORS libera*. Para uso fora de uma máquina confiável, defina a chave e restrinjaLOCALLLM_ADDReLOCALLLM_CORS_ORIGINS(vejadocs/api/configuration.md).
O que existe hoje
| Superfície | Onde | O que entrega |
|---|---|---|
| API HTTP local | crates/inference-server |
GET /health, GET /v1/models e POST /v1/chat/completions (com streaming SSE e stream_options.include_usage) |
CLI localllm |
crates/localllm-cli |
Comandos status, models, auth, config, bench, logs e doctor; flags globais --server, --api-key, --models-dir, --format text|json e --dry-run |
| App desktop | tauri-app |
Runtime manager (modo local ou remote), chat persistente e página de Configurações com gerenciador de modelos |
| Perfis de runtime | crates/inference-core |
Turbo4B (default), balanced_9b e cpu_fallback, ajustáveis por LOCALLLM_GPU_LAYERS, LOCALLLM_CTX, LOCALLLM_BATCH, etc. |
| Runtime llama.cpp gerenciado | crates/runtime-deps |
Baixa o llama.cpp b8358 (variantes CPU e CUDA 12.4), valida SHA-256 e guarda em cache local |
No app desktop:
- Runtime manager com estados
stopped,starting,ready,degraded,stoppingeerror; o modo local inicia/para o processo e usaGET /healthpara saber se está pronto. - Gerenciador de modelos: escaneia/importa
.gguf, busca modelos no Hugging Face, baixa em streaming com progresso e cancelamento (token do Hugging Face opcional), troca o modelo carregado com um clique (hot-swap: para, grava o novomodel_pathe reinicia), apaga arquivos e abre a pasta no explorador. - Chat: streaming, memória opcional de até 20 mensagens recentes, separação visual do raciocínio (
<think>…</think>) da resposta final, contagem de tokens (por mensagem e por chat) e tokens/s, edição, reenvio e exclusão de mensagens.
Início rápido
Warning
Na primeira execução o servidor baixa o runtime do llama.cpp. Se o runtime não for encontrado (
LLAMA_DLL_PATH, ao lado do binário ou vendor legado), oruntime-depsbaixa o pacote degithub.com/ggml-org/llama.cpp(b8358). A variante CUDA 12.4 são dois zips (≈ 227 MB + ≈ 391 MB conforme o manifesto); a CPU, um zip de ≈ 37 MB. O servidor escolhe CUDA quando as camadas em GPU são> 0e cai para CPU caso não exista variante de GPU para o alvo.
1. Subir a API local (Windows cmd; em bash use export):
set LOCALLLM_MODEL=D:\caminho\modelo.gguf
cargo run -p inference-server
curl http://127.0.0.1:8080/health
curl http://127.0.0.1:8080/v1/models
2. Usar a CLI:
cargo run -p localllm-cli -- status
cargo run -p localllm-cli -- models list
3. Abrir o app desktop:
cd tauri-app
npm install
npm run tauri dev
No app, abra o Runtime Manager, escolha modo local ou remote e depois use o chat.
Requisitos: toolchain Rust atual, Node.js/NPM (app Tauri) e um modelo .gguf local.
GPU NVIDIA é opcional — existe o perfil cpu_fallback.
Como funciona
flowchart LR
UI["App Tauri<br/>React + Rust"] -->|"HTTP /v1/chat/completions"| S
UI -->|"inicia / para / health"| S["inference-server<br/>Axum · binário localllm"]
CLI["localllm-cli"] -->|HTTP| S
S --> C["inference-core<br/>engine · sessão · sampler · perfis"]
C --> L["llama-sys<br/>carga dinâmica (libloading)"]
L --> R["llama.dll<br/>llama.cpp b8358"]
D["runtime-deps<br/>download + SHA-256"] --> R
S --> D
UI -->|"busca e download"| HF["Hugging Face"]
S -.-> M["metrics<br/>tokens e throughput"]
Crates e módulos
| Módulo | Responsabilidade |
|---|---|
crates/api-contracts |
Tipos compartilhados: chat completions, lista de modelos, health e erros |
crates/inference-core |
Engine de inferência local: carga do modelo, sessão, sampler e perfis de runtime |
crates/inference-server |
Camada HTTP em Axum: variáveis de ambiente, auth, CORS e aliases de modelo |
crates/localllm-cli |
CLI de operação e automação (clap) |
crates/metrics |
Contadores de uso de tokens e throughput |
crates/llama-sys |
Integração de baixo nível: carrega llama.dll dinamicamente via libloading |
crates/runtime-deps |
Resolve o runtime (override por env, binário adjacente, vendor legado ou cache gerenciado) e instala a partir de vendor/llama-runtime/manifest.json |
tauri-app/ |
App desktop: frontend React 18 + Vite + Tailwind, backend Tauri 2 em Rust |
Variáveis de ambiente do servidor (principais): LOCALLLM_MODEL, LOCALLLM_ADDR,
LOCALLLM_MODEL_ALIASES, LOCALLLM_PROFILE, LOCALLLM_API_KEY,
LOCALLLM_AUTH_HEADER, LOCALLLM_AUTH_SCHEME, LOCALLLM_CORS_ORIGINS,
LOCALLLM_SYSTEM_PROMPT e LOCALLLM_ENABLE_TOOL_CALLS. Detalhes em
docs/api/configuration.md.
Limitações conhecidas
- A API expõe só três endpoints; a compatibilidade com a OpenAI é parcial e focada no fluxo de chat (
nprecisa ser1,parallel_tool_callsnão é tratado como recurso suportado,contentem partes vira texto consolidado). - O raciocínio não aparece como campo separado na API; quem separa
<think>…</think>é o frontend do app. - Na CLI, a execução ao vivo está mais consolidada em
status,models listebench throughput; o restante da superfície é mais avançado no parser do que nas capacidades HTTP públicas. - O chat usa
sql.jscarregado por CDN e persiste o banco exportado emlocalStorage— não é um banco nativo do sistema. - No modo local o app precisa encontrar o binário
localllm; o runtime manager faz polling periódico do snapshot (sem fluxo de eventos push). - O manifesto do runtime (
vendor/llama-runtime/manifest.json) só lista varianteswindows-x64(CPU e CUDA 12.4). Em outros alvos o servidor só sobe com um runtime já presente (binário adjacente ouLLAMA_DLL_PATH). - Os scripts
scripts/build-dev.shescripts/build-prod.shcompilamvendor/llama.cppe exigem esse submódulo, que não está declarado no repositório (não há.gitmodules). inference-serverelocalllm-clideclaram ambos um binário chamadolocalllm; usecargo run -p <crate>para escolher qual executar.
Execução local
cargo run -p inference-server # API em 0.0.0.0:8080 (precisa de LOCALLLM_MODEL)
cargo run -p localllm-cli -- status # CLI
cd tauri-app
npm install
npm run dev # só o frontend (Vite, porta 1420)
npm run tauri dev # app desktop completo
npm run build # tsc + vite build
npm test # vitest run
Documentação
| Documento | Conteúdo |
|---|---|
docs/README.md |
Índice da documentação |
docs/api/overview.md · endpoints.md · configuration.md |
API: visão geral, referência HTTP e configuração |
docs/cli/overview.md · commands.md |
CLI: visão geral e referência de comandos |
docs/app/overview.md · user-guide.md · backend-commands.md |
App desktop: visão geral, guia de uso e comandos Tauri |
docs/developer/architecture.md |
Arquitetura do workspace e fluxos entre módulos |
Avisos
- Os binários de inferência vêm do llama.cpp (releases oficiais baixadas e verificadas por SHA-256); modelos são buscados no Hugging Face e seguem a licença de cada autor.
- Licença do workspace: MIT (declarada em
Cargo.toml; o repositório não inclui arquivoLICENSE).