Backend (inference-server/compat.rs): - PreparedPrompt now carries extra_stop_sequences injected by template - Generic template injects User:/System:/Assistant:/Human: stop sequences to prevent the model from continuing the transcript after its reply - Increased repeat_penalty 1.15→1.3 and repeat_last_n 256→512 to break repetition loops more aggressively Backend (inference-server/routes.rs): - Merge template extra_stop_sequences into sampler before inference Frontend (chat.ts): - Added 'System:' and 'Human:' to CHAT_TRANSCRIPT_STOP_SEQUENCES - Extended TRANSCRIPT_LEAKAGE_PATTERN to include 'Human:' Frontend (ChatView.tsx): - buildApiMessages now strips leaked transcript from assistant messages before sending history back to the model - Reduced history window to 20 messages to limit context pollution
943 lines
30 KiB
Markdown
943 lines
30 KiB
Markdown
# Documentação Completa do Backend - ForgeLM
|
|
|
|
## Sumário Executivo
|
|
|
|
O ForgeLM é um sistema de inferência de LLMs locais composto por dois componentes principais:
|
|
|
|
1. **HTTP API Server** (`inference-server`) - Servidor Axum que expõe endpoints compatíveis com OpenAI
|
|
2. **Tauri Desktop Backend** - Backend do aplicativo desktop que gerencia o ciclo de vida do servidor
|
|
|
|
---
|
|
|
|
## Arquitetura Geral
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
│ ForgeLM Backend │
|
|
├─────────────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌──────────────────────┐ ┌─────────────────────────────────────────┐ │
|
|
│ │ Tauri App (Frontend)│ │ HTTP API Server (Axum) │ │
|
|
│ │ - React + TypeScript│ │ - Port: 8080 (default) │ │
|
|
│ │ - sql.js + localStorage│ │ - OpenAI-compatible API │ │
|
|
│ └──────────┬───────────┘ └──────────────┬──────────────────────────┘ │
|
|
│ │ │ │
|
|
│ │ Tauri Commands │ │
|
|
│ ▼ │ │
|
|
│ ┌──────────────────────┐ │ │
|
|
│ │ Tauri Backend │◄────────────────────┘ │
|
|
│ │ - Runtime lifecycle │ HTTP requests │
|
|
│ │ - Model management │ │
|
|
│ │ - GPU detection │ │
|
|
│ └──────────┬───────────┘ │
|
|
│ │ │
|
|
│ │ Spawns Process │
|
|
│ ▼ │
|
|
│ ┌──────────────────────┐ ┌─────────────────────────────────────────┐ │
|
|
│ │ inference-server │ │ inference-core │ │
|
|
│ │ (Binary Executable) │──────► - Engine │ │
|
|
│ │ │ │ - GenerationSession │ │
|
|
│ └──────────────────────┘ └──────────────┬──────────────────────────┘ │
|
|
│ │ │
|
|
│ │ FFI │
|
|
│ ▼ │
|
|
│ ┌─────────────────┐ │
|
|
│ │ llama-sys │ │
|
|
│ │ (llama.dll) │ │
|
|
│ └─────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 1. Crates e Estrutura do Workspace
|
|
|
|
### Estrutura do Workspace
|
|
|
|
```
|
|
Cargo.toml (workspace root)
|
|
├── crates/
|
|
│ ├── llama-sys/ # FFI bindings para llama.cpp
|
|
│ ├── runtime-deps/ # Gerenciamento de dependências do runtime
|
|
│ ├── inference-core/ # Lógica de inferência (Engine, Session, Sampler)
|
|
│ ├── inference-server/ # Servidor HTTP Axum
|
|
│ ├── api-contracts/ # Schemas de request/response
|
|
│ ├── metrics/ # Contadores de performance e TPS
|
|
│ └── localllm-cli/ # CLI para gerenciamento
|
|
│
|
|
└── tauri-app/
|
|
└── src-tauri/
|
|
└── src/
|
|
├── lib.rs # Entry point Tauri
|
|
├── runtime/ # Gerenciamento do ciclo de vida
|
|
├── model_library/ # Biblioteca de modelos HuggingFace
|
|
├── model_files.rs # Operações com arquivos .gguf
|
|
├── model_alias.rs # Resolução de aliases
|
|
└── gpu.rs # Detecção de GPU
|
|
```
|
|
|
|
### Dependências do Workspace
|
|
|
|
| Categoria | Crates |
|
|
|-----------|--------|
|
|
| Async Runtime | `tokio`, `axum`, `hyper`, `tower`, `tower-http` |
|
|
| Serialization | `serde`, `serde_json` |
|
|
| Error Handling | `anyhow`, `thiserror` |
|
|
| Logging | `tracing`, `tracing-subscriber` |
|
|
| FFI | `libloading`, `once_cell` |
|
|
| Utilities | `uuid`, `chrono`, `futures`, `tokio-stream` |
|
|
|
|
---
|
|
|
|
## 2. HTTP API Server (inference-server)
|
|
|
|
### Entry Point - `main.rs`
|
|
|
|
O servidor é iniciado em `crates/inference-server/src/main.rs`.
|
|
|
|
#### Configuração via Environment Variables
|
|
|
|
| Variável | Descrição | Padrão |
|
|
|----------|-----------|--------|
|
|
| `LOCALLLM_MODEL` | Caminho para arquivo GGUF | (obrigatório) |
|
|
| `LOCALLLM_PROFILE` | Perfil de performance (`turbo_4b`, `balanced_9b`, `cpu_fallback`) | `turbo_4b` |
|
|
| `LOCALLLM_CTX` | Tamanho do contexto (tokens) | depende do perfil |
|
|
| `LOCALLLM_BATCH` | Tamanho do batch | 4096 (max) |
|
|
| `LOCALLLM_GPU_LAYERS` | Camadas GPU (-1 = auto) | depende do perfil |
|
|
| `LOCALLLM_THREADS` | Threads CPU | depende do perfil |
|
|
| `LOCALLLM_ADDR` | Endereço de bind | `0.0.0.0:8080` |
|
|
| `LOCALLLM_API_KEY` | Chave API para autenticação | (opcional) |
|
|
| `LOCALLLM_LOG_FORMAT` | Formato de log (`json`, `pretty`) | `pretty` |
|
|
| `LOCALLLM_MODEL_ALIASES` | Aliases para modelos (CSV) | (opcional) |
|
|
| `LOCALLLM_ENABLE_TOOL_CALLS` | Habilitar tool calls | `true` |
|
|
|
|
### Rotas HTTP - `routes.rs`
|
|
|
|
O roteador é construído em `crates/inference-server/src/routes.rs`.
|
|
|
|
```rust
|
|
pub fn build_router(state: AppState) -> Router {
|
|
Router::new()
|
|
.route("/health", get(health_handler))
|
|
.route("/v1/models", get(models_handler))
|
|
.route("/v1/chat/completions", post(chat_completions_handler))
|
|
.layer(ServiceBuilder::new().layer(trace_layer).layer(cors))
|
|
.with_state(state)
|
|
}
|
|
```
|
|
|
|
#### Endpoints
|
|
|
|
| Método | Endpoint | Descrição |
|
|
|--------|----------|-----------|
|
|
| `GET` | `/health` | Health check do servidor |
|
|
| `GET` | `/v1/models` | Lista modelos disponíveis |
|
|
| `POST` | `/v1/chat/completions` | Chat completions (OpenAI-compatible) |
|
|
|
|
#### AppState
|
|
|
|
```rust
|
|
#[derive(Clone)]
|
|
pub struct AppState {
|
|
pub engine: Arc<Mutex<InferenceEngine>>, // Motor de inferência
|
|
pub counters: Arc<PerfCounters>, // Contadores de performance
|
|
pub model_name: Arc<String>, // Nome do modelo atual
|
|
pub server_config: Arc<ServerConfig>, // Configurações do servidor
|
|
pub start_time: std::time::Instant, // Timestamp de início
|
|
}
|
|
```
|
|
|
|
### Compatibilidade OpenAI - `compat.rs`
|
|
|
|
Arquivo: `crates/inference-server/src/compat.rs`
|
|
|
|
#### ServerConfig
|
|
|
|
Gerencia configurações de autenticação, CORS, e catálogo de modelos:
|
|
|
|
```rust
|
|
#[derive(Debug, Clone)]
|
|
pub struct ServerConfig {
|
|
pub api_key: Option<String>,
|
|
pub auth_header: String,
|
|
pub auth_scheme: Option<String>,
|
|
pub cors_origins: Vec<String>,
|
|
pub default_system_prompt: String,
|
|
pub enable_tool_calls: bool,
|
|
pub model_catalog: ModelCatalog,
|
|
}
|
|
```
|
|
|
|
#### ModelCatalog
|
|
|
|
Resolve aliases de modelos (case-insensitive):
|
|
|
|
```rust
|
|
pub struct ModelCatalog {
|
|
models: Vec<ModelDescriptor>,
|
|
aliases: HashMap<String, usize>,
|
|
}
|
|
|
|
pub struct ModelDescriptor {
|
|
pub id: String,
|
|
pub root: String,
|
|
pub parent: Option<String>,
|
|
}
|
|
```
|
|
|
|
**Aliases padrão:** `local-model`, `default`
|
|
|
|
#### Chat Templates Suportados
|
|
|
|
O sistema detecta automaticamente o template baseado no nome do modelo:
|
|
|
|
| Modelo | Template | Formatos |
|
|
|--------|----------|----------|
|
|
| Qwen | `<\|im_start\|>`, `<\|im_end\|>` | `system`, `user`, `assistant`, `tool` |
|
|
| Gemma | `<start_of_turn>`, `<end_of_turn>` | `model`, `user` |
|
|
| Llama | `[INST]`, `[/INST]` | com `<<SYS>>` para system |
|
|
| Kimi/Moonshot | `<\|im_system\|>`, `<\|im_user\|>`, `<\|im_assistant\|>` | - |
|
|
| Genérico | `Role: content` | Padrão |
|
|
|
|
#### Autorização
|
|
|
|
Suporta múltiplos headers de autenticação:
|
|
- Header configurado (`LOCALLLM_AUTH_HEADER`)
|
|
- `Authorization: Bearer <key>`
|
|
- `X-API-Key: <key>`
|
|
|
|
#### Validação de Requests
|
|
|
|
Validações implementadas:
|
|
- Modelo existe no catálogo
|
|
- Lista de mensagens não está vazia
|
|
- `n=1` (apenas uma completion por request)
|
|
- Tool calls habilitado se tools presentes
|
|
|
|
---
|
|
|
|
## 3. inference-core
|
|
|
|
### Engine - `engine.rs`
|
|
|
|
Local: `crates/inference-core/src/engine.rs`
|
|
|
|
O `InferenceEngine` é o núcleo de inferência que gerencia:
|
|
- Carregamento do modelo GGUF via llama-sys FFI
|
|
- Inicialização do contexto llama.cpp
|
|
- Criação de sessões de geração
|
|
|
|
#### EngineConfig
|
|
|
|
```rust
|
|
pub struct EngineConfig {
|
|
pub model_path: PathBuf, // Caminho para arquivo GGUF
|
|
pub profile: RuntimeProfile, // Perfil de performance
|
|
pub n_gpu_layers: i32, // Camadas GPU (-1 = todas)
|
|
pub n_ctx: u32, // Contexto (tokens)
|
|
pub n_batch: u32, // Batch size (prefill)
|
|
pub n_ubatch: u32, // Micro-batch (geração)
|
|
pub n_threads: i32, // Threads CPU
|
|
pub n_threads_batch: i32, // Threads para batch
|
|
pub flash_attn: bool, // Flash Attention
|
|
pub use_mmap: bool, // Usar memory mapping
|
|
pub seed: u32, // Seed RNG
|
|
}
|
|
```
|
|
|
|
#### Runtime Profiles
|
|
|
|
| Perfil | n_ctx | n_gpu_layers | Descrição |
|
|
|--------|-------|--------------|-----------|
|
|
| `Turbo4B` | 8192 | 999 | GPU total, otimizado para modelos até 4B |
|
|
| `Balanced9B` | 16384 | 999 | Equilibrado para modelos até 9B |
|
|
| `CpuFallback` | 4096 | 0 | CPU-only fallback |
|
|
|
|
#### Ciclo de Vida do Engine
|
|
|
|
```rust
|
|
// 1. Carregar engine
|
|
let mut engine = InferenceEngine::load(config)?;
|
|
|
|
// 2. Warmup (aloca buffers CUDA)
|
|
engine.warmup()?;
|
|
|
|
// 3. Criar sessão de geração
|
|
let session = engine.new_session(prompt, sampler_cfg)?;
|
|
|
|
// 4. Gerar tokens
|
|
while let Some(token) = session.next_token() {
|
|
print!("{}", token);
|
|
}
|
|
```
|
|
|
|
**Nota sobre segurança:** O engine é `Send` mas NÃO é `Sync`. Acesso deve ser coordenado (o servidor usa `tokio::sync::Mutex`).
|
|
|
|
### Session - `session.rs`
|
|
|
|
```rust
|
|
pub struct GenerationSession {
|
|
// ...
|
|
}
|
|
|
|
impl GenerationSession {
|
|
pub fn next_token(&mut self) -> Option<String>;
|
|
pub fn prompt_tokens(&self) -> u32;
|
|
}
|
|
```
|
|
|
|
### Sampler - `sampler.rs`
|
|
|
|
Configurações de sampling:
|
|
|
|
```rust
|
|
pub struct SamplerConfig {
|
|
pub temperature: f32, // 0.0 - 2.0
|
|
pub top_p: f32, // 0.0 - 1.0
|
|
pub max_tokens: u32,
|
|
pub stop_sequences: Vec<String>,
|
|
pub repeat_penalty: f32, // 1.15 (normal), 1.0 (tools)
|
|
pub repeat_last_n: usize, // 256 tokens
|
|
pub seed: u32,
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 4. API Contracts
|
|
|
|
Local: `crates/api-contracts/src/`
|
|
|
|
### Chat Completion Request (`chat.rs`)
|
|
|
|
```rust
|
|
pub struct ChatCompletionRequest {
|
|
pub model: String,
|
|
pub messages: Vec<ChatMessage>,
|
|
pub max_tokens: u32, // default: 1024
|
|
pub temperature: f32, // default: 0.15
|
|
pub top_p: f32, // default: 0.95
|
|
pub stream: bool, // default: false
|
|
pub stop: Vec<String>,
|
|
pub n: u32, // default: 1 (apenas 1 suportado)
|
|
pub seed: Option<u32>,
|
|
pub user: Option<String>,
|
|
pub response_format: Option<ResponseFormat>,
|
|
pub tools: Vec<ToolDefinition>,
|
|
pub tool_choice: Option<ToolChoice>,
|
|
pub stream_options: Option<StreamOptions>,
|
|
}
|
|
```
|
|
|
|
### ChatMessage
|
|
|
|
```rust
|
|
pub struct ChatMessage {
|
|
pub role: Role, // System, Developer, User, Assistant, Tool
|
|
pub content: Option<String>,
|
|
pub name: Option<String>,
|
|
pub tool_calls: Option<Vec<ToolCall>>,
|
|
pub tool_call_id: Option<String>,
|
|
}
|
|
```
|
|
|
|
### ResponseFormat
|
|
|
|
```rust
|
|
pub struct ResponseFormat {
|
|
pub format_type: String, // "json_object", "json_schema", "text"
|
|
pub json_schema: Option<Value>,
|
|
}
|
|
```
|
|
|
|
### ToolCalling
|
|
|
|
```rust
|
|
pub struct ToolDefinition {
|
|
pub tool_type: ToolType,
|
|
pub function: FunctionDefinition,
|
|
}
|
|
|
|
pub struct FunctionDefinition {
|
|
pub name: String,
|
|
pub description: Option<String>,
|
|
pub parameters: Value, // JSON Schema
|
|
}
|
|
|
|
pub struct ToolCall {
|
|
pub id: String,
|
|
pub tool_type: ToolType,
|
|
pub function: ToolFunctionCall,
|
|
}
|
|
|
|
pub struct ToolFunctionCall {
|
|
pub name: String,
|
|
pub arguments: String, // JSON string
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Tauri Desktop Backend
|
|
|
|
### Entry Point - `lib.rs`
|
|
|
|
Local: `tauri-app/src-tauri/src/lib.rs`
|
|
|
|
O backend Tauri gerencia:
|
|
- Ciclo de vida do runtime (start/stop)
|
|
- Gerenciamento de modelos locais
|
|
- Downloads do HuggingFace
|
|
- Detecção de GPU
|
|
- Sistema ForgeAgent (multi-agente)
|
|
|
|
### Commands Tauri
|
|
|
|
```rust
|
|
.invoke_handler(tauri::generate_handler![
|
|
query_gpu, // Detectar GPU NVIDIA
|
|
scan_models, // Escanear arquivos .gguf
|
|
pick_models_dir, // Selecionar diretório
|
|
pick_model_files, // Selecionar arquivos
|
|
import_model, // Importar modelo
|
|
search_hugging_face_models_command, // Buscar no HF
|
|
start_hugging_face_download_command, // Download do HF
|
|
cancel_hugging_face_download_command,// Cancelar download
|
|
swap_model_command, // Trocar modelo
|
|
delete_model_file, // Deletar arquivo
|
|
open_model_folder_command, // Abrir pasta
|
|
list_model_library_entries_command, // Listar biblioteca
|
|
get_model_library_state_command, // Estado da biblioteca
|
|
bootstrap_runtime_command, // Bootstrap runtime
|
|
get_runtime_snapshot_command, // Snapshot do runtime
|
|
save_runtime_config_command_handler, // Salvar config
|
|
start_runtime_command, // Iniciar runtime
|
|
stop_runtime_command, // Parar runtime
|
|
resolve_startup_model_command, // Resolver modelo inicial
|
|
get_app_data_dir, // Diretório de dados
|
|
find_server_binary, // Localizar binário
|
|
start_forgeagent_session_command, // Iniciar ForgeAgent
|
|
])
|
|
```
|
|
|
|
### Runtime Types - `runtime/types.rs`
|
|
|
|
#### ConnectionMode
|
|
|
|
```rust
|
|
pub enum ConnectionMode {
|
|
Local, // Servidor local spawnado
|
|
Remote, // Conectar a servidor externo
|
|
}
|
|
```
|
|
|
|
#### RuntimeStatus
|
|
|
|
```rust
|
|
pub enum RuntimeStatus {
|
|
Stopped,
|
|
Starting,
|
|
Loading,
|
|
Ready,
|
|
Degraded,
|
|
Stopping,
|
|
Error,
|
|
}
|
|
```
|
|
|
|
#### RuntimeConfig
|
|
|
|
```rust
|
|
pub struct RuntimeConfig {
|
|
pub connection_mode: ConnectionMode,
|
|
pub start_policy: StartPolicy, // Manual, OnAppLaunch
|
|
pub server_url: String, // Para Remote mode
|
|
pub api_key: String,
|
|
pub model_path: Option<String>,
|
|
pub models_dir: Option<String>,
|
|
pub addr: String, // "127.0.0.1:8080"
|
|
pub gpu_layers: i32,
|
|
pub ctx_size: u32, // default: 4096
|
|
pub extra_model_paths: Vec<String>,
|
|
pub selected_model_id: Option<String>,
|
|
pub remote_presets: Vec<RemotePreset>,
|
|
pub hugging_face_token: String,
|
|
pub preferred_startup_model_alias: Option<String>,
|
|
}
|
|
```
|
|
|
|
#### RuntimeSnapshot
|
|
|
|
```rust
|
|
pub struct RuntimeSnapshot {
|
|
pub status: RuntimeStatus,
|
|
pub ready: bool,
|
|
pub process_running: bool,
|
|
pub resolved_url: String,
|
|
pub binary_path: Option<String>,
|
|
pub last_error: Option<RuntimeErrorInfo>,
|
|
pub active_command: RuntimeLifecycleCommand,
|
|
pub last_command_result: RuntimeLifecycleResult,
|
|
pub config: RuntimeConfig,
|
|
}
|
|
```
|
|
|
|
### Model Library - `model_library/`
|
|
|
|
#### Tipos
|
|
|
|
```rust
|
|
pub struct ModelLibraryEntry {
|
|
pub id: String,
|
|
pub name: String,
|
|
pub repo_id: String,
|
|
pub description: String,
|
|
pub tags: Vec<String>,
|
|
pub size_gb: f64,
|
|
pub default_file: String,
|
|
pub installed: bool,
|
|
pub installed_path: Option<String>,
|
|
}
|
|
|
|
pub struct HuggingFaceModelResult {
|
|
pub id: String,
|
|
pub model_id: String,
|
|
pub downloads: i64,
|
|
pub likes: i32,
|
|
pub tags: Vec<String>,
|
|
pub gguf_files: Vec<GgufFileInfo>,
|
|
}
|
|
```
|
|
|
|
### Model Files - `model_files.rs`
|
|
|
|
```rust
|
|
#[derive(Serialize)]
|
|
pub struct ModelFileInfo {
|
|
pub path: String,
|
|
pub file_name: String,
|
|
pub size_bytes: u64,
|
|
pub modified: Option<String>,
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Fluxo de Dados
|
|
|
|
### 1. Requisição Chat Completion
|
|
|
|
```
|
|
┌──────────┐ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐
|
|
│ Client │───►│ Axum Router │───►│ compat.rs │───►│ routes.rs │
|
|
└──────────┘ └─────────────┘ └──────────────┘ └──────┬──────┘
|
|
│
|
|
▼
|
|
┌──────────┐ ┌─────────────┐ ┌──────────────┐ ┌─────────────┐
|
|
│ Client │◄───│ JSON │◄───│ Generation │◄───│ Engine │
|
|
│ │ │ Response │ │ Session │ │ (Mutex) │
|
|
└──────────┘ └─────────────┘ └──────────────┘ └──────┬──────┘
|
|
│
|
|
▼
|
|
┌─────────────────┐
|
|
│ llama-sys │
|
|
│ (llama.dll) │
|
|
└─────────────────┘
|
|
```
|
|
|
|
### 2. Streaming vs Blocking
|
|
|
|
**Streaming Mode:**
|
|
1. Cria stream SSE
|
|
2. Gera tokens em `spawn_blocking`
|
|
3. Envia chunks via channel
|
|
4. Client recebe tokens em tempo real
|
|
|
|
**Blocking Mode:**
|
|
1. Gera completion completa
|
|
2. Retorna JSON único
|
|
|
|
### 3. Ciclo de Vida do Modelo
|
|
|
|
```
|
|
┌─────────────┐
|
|
│ Stopped │
|
|
└──────┬──────┘
|
|
│ start_runtime_command()
|
|
▼
|
|
┌─────────────┐
|
|
│ Starting │
|
|
└──────┬──────┘
|
|
│ Processo spawnado
|
|
▼
|
|
┌─────────────┐
|
|
│ Loading │
|
|
└──────┬──────┘
|
|
│ Modelo carregado
|
|
▼
|
|
┌─────────────┐
|
|
│ Ready │◄──────────┐
|
|
└──────┬──────┘ │
|
|
│ stop_runtime() │ swap_model_command()
|
|
▼ │
|
|
┌─────────────┐ │
|
|
│ Stopping │ │
|
|
└─────────────┘ │
|
|
│
|
|
├─────────────────────────┤
|
|
│ swap │
|
|
│ ┌─────┐ ┌─────┐ │
|
|
│ │Stop │──►│Start│ │
|
|
│ └─────┘ └─────┘ │
|
|
└─────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 7. ForgeAgent - Sistema Multi-Agente
|
|
|
|
### Especialistas
|
|
|
|
| ID | Nome | Emoji | Função |
|
|
|----|------|-------|--------|
|
|
| `analyst` | Analista | 🔍 | Análise técnica e decomposição |
|
|
| `architect` | Arquiteto | 🏗️ | Arquitetura de software e padrões |
|
|
| `developer` | Desenvolvedor | 💻 | Implementação pragmática |
|
|
| `critic` | Crítico | ⚖️ | Revisão e identificação de riscos |
|
|
|
|
### Fluxo de Eventos
|
|
|
|
```
|
|
start_forgeagent_session_command()
|
|
│
|
|
▼
|
|
┌─────────────────────────┐
|
|
│ forgeagent:start │──► Envia plano estruturado
|
|
└─────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────┐
|
|
│ forgeagent:step-started │──► Início de cada passo
|
|
└─────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────┐
|
|
│ forgeagent:step-completed│──► Passo concluído
|
|
└─────────────────────────┘
|
|
│
|
|
▼
|
|
┌───────────────────────────────┐
|
|
│ forgeagent:specialist-thought │──► Pensamento do especialista
|
|
└───────────────────────────────┘
|
|
│
|
|
▼
|
|
┌──────────────────────────────────┐
|
|
│ forgeagent:specialist-response │──► Resposta do especialista
|
|
└──────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────┐
|
|
│ forgeagent:plan-completed│──► Resumo final
|
|
└─────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 8. API HTTP - Exemplos
|
|
|
|
### Health Check
|
|
|
|
```bash
|
|
curl http://localhost:8080/health
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"status": "ok",
|
|
"model_loaded": true,
|
|
"model_id": "qwen2.5-7b-instruct",
|
|
"uptime_secs": 3600
|
|
}
|
|
```
|
|
|
|
### Listar Modelos
|
|
|
|
```bash
|
|
curl http://localhost:8080/v1/models \
|
|
-H "Authorization: Bearer sua-chave"
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"object": "list",
|
|
"data": [
|
|
{
|
|
"id": "local-model",
|
|
"object": "model",
|
|
"created": 1234567890,
|
|
"owned_by": "local",
|
|
"root": "qwen2.5-7b-instruct",
|
|
"parent": "qwen2.5-7b-instruct",
|
|
"permission": []
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Chat Completion (Non-streaming)
|
|
|
|
```bash
|
|
curl http://localhost:8080/v1/chat/completions \
|
|
-H "Content-Type: application/json" \
|
|
-H "Authorization: Bearer sua-chave" \
|
|
-d '{
|
|
"model": "local-model",
|
|
"messages": [
|
|
{"role": "user", "content": "Olá!"}
|
|
],
|
|
"max_tokens": 1024,
|
|
"temperature": 0.7
|
|
}'
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": "uuid-123",
|
|
"object": "chat.completion",
|
|
"created": 1234567890,
|
|
"model": "qwen2.5-7b-instruct",
|
|
"choices": [
|
|
{
|
|
"index": 0,
|
|
"message": {
|
|
"role": "assistant",
|
|
"content": "Olá! Como posso ajudar?"
|
|
},
|
|
"finish_reason": "stop"
|
|
}
|
|
],
|
|
"usage": {
|
|
"prompt_tokens": 10,
|
|
"completion_tokens": 20,
|
|
"total_tokens": 30,
|
|
"tokens_per_second": 45.5
|
|
}
|
|
}
|
|
```
|
|
|
|
### Chat Completion (Streaming)
|
|
|
|
```bash
|
|
curl http://localhost:8080/v1/chat/completions \
|
|
-H "Content-Type: application/json" \
|
|
-H "Authorization: Bearer sua-chave" \
|
|
-d '{
|
|
"model": "local-model",
|
|
"messages": [
|
|
{"role": "user", "content": "Conte uma piada"}
|
|
],
|
|
"stream": true
|
|
}'
|
|
```
|
|
|
|
**Response (SSE):**
|
|
```
|
|
data: {"id":"...","object":"chat.completion.chunk","choices":[{"delta":{"role":"assistant"}}]}
|
|
|
|
data: {"id":"...","object":"chat.completion.chunk","choices":[{"delta":{"content":"Por"}}]}
|
|
|
|
data: {"id":"...","object":"chat.completion.chunk","choices":[{"delta":{"content":" que"}}]}
|
|
...
|
|
data: {"id":"...","object":"chat.completion.chunk","choices":[{"finish_reason":"stop"}]}
|
|
|
|
data: [DONE]
|
|
```
|
|
|
|
### Tool Calling
|
|
|
|
```bash
|
|
curl http://localhost:8080/v1/chat/completions \
|
|
-H "Content-Type: application/json" \
|
|
-H "Authorization: Bearer sua-chave" \
|
|
-d '{
|
|
"model": "local-model",
|
|
"messages": [
|
|
{"role": "user", "content": "Liste os arquivos"}
|
|
],
|
|
"tools": [
|
|
{
|
|
"type": "function",
|
|
"function": {
|
|
"name": "list_files",
|
|
"description": "Lista arquivos do projeto",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"path": {"type": "string"}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"tool_choice": "auto"
|
|
}'
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Configuração e Deploy
|
|
|
|
### Compilação
|
|
|
|
```bash
|
|
# Servidor
|
|
$env:LOCALLLM_LOG_FORMAT="json"
|
|
cargo build --release -p inference-server
|
|
|
|
# CLI
|
|
cargo build --release -p localllm-cli
|
|
|
|
# Tauri App
|
|
cd tauri-app
|
|
cargo tauri build
|
|
```
|
|
|
|
### Execução
|
|
|
|
```bash
|
|
# Com variáveis de ambiente
|
|
$env:LOCALLLM_MODEL="D:\models\model.gguf"
|
|
$env:LOCALLLM_PROFILE="balanced_9b"
|
|
$env:LOCALLLM_API_KEY="minha-chave-secreta"
|
|
$env:LOCALLLM_ADDR="0.0.0.0:8080"
|
|
|
|
.\target\release\inference-server.exe
|
|
```
|
|
|
|
### Docker (se aplicável)
|
|
|
|
```bash
|
|
docker run -p 8080:8080 \
|
|
-v /path/to/models:/models \
|
|
-e LOCALLLM_MODEL=/models/model.gguf \
|
|
-e LOCALLLM_API_KEY=secret \
|
|
forgelm/inference-server:latest
|
|
```
|
|
|
|
---
|
|
|
|
## 10. Estrutura de Arquivos
|
|
|
|
### Diretórios Importantes
|
|
|
|
```
|
|
%LOCALAPPDATA%/ForgeLM/ # Windows
|
|
~/.local/share/ForgeLM/ # Linux
|
|
~/Library/Application Support/ForgeLM/ # macOS
|
|
├── models/ # Modelos baixados
|
|
├── runtime/ # Binários do runtime
|
|
└── config.json # Configuração do runtime
|
|
```
|
|
|
|
### Frontend (Tauri App)
|
|
|
|
```
|
|
tauri-app/
|
|
├── src/
|
|
│ ├── lib/
|
|
│ │ ├── db.ts # Persistência local (sql.js)
|
|
│ │ └── types.ts # Tipos TypeScript
|
|
│ ├── main.tsx # Entry React
|
|
│ └── App.tsx # App shell
|
|
└── src-tauri/
|
|
├── src/
|
|
│ ├── lib.rs # Entry Tauri
|
|
│ ├── runtime/ # Gerenciamento runtime
|
|
│ ├── model_library/ # HuggingFace integration
|
|
│ ├── model_files.rs # Arquivos locais
|
|
│ ├── model_alias.rs # Resolução aliases
|
|
│ └── gpu.rs # Detecção GPU
|
|
└── taury.conf.json # Config Tauri
|
|
```
|
|
|
|
---
|
|
|
|
## 11. Glossário
|
|
|
|
| Termo | Descrição |
|
|
|-------|-----------|
|
|
| **GGUF** | Format binary for LLMs (GPT-Generated Unified Format) |
|
|
| **KV Cache** | Key-Value cache for attention mechanism |
|
|
| **Prefill** | Initial prompt processing phase |
|
|
| **Decode** | Token generation phase |
|
|
| **Context Window** | Maximum tokens the model can process |
|
|
| **Batch** | Number of tokens processed together |
|
|
| **GPU Layers** | Number of model layers offloaded to GPU |
|
|
| **Flash Attention** | Optimized attention implementation |
|
|
| **Tool Calling** | Function calling capability for LLMs |
|
|
| **SSE** | Server-Sent Events for streaming |
|
|
|
|
---
|
|
|
|
## 12. Referências Rápidas
|
|
|
|
### Arquivos Principais
|
|
|
|
| Função | Arquivo |
|
|
|--------|---------|
|
|
| Entry Server | `crates/inference-server/src/main.rs` |
|
|
| Rotas HTTP | `crates/inference-server/src/routes.rs` |
|
|
| Compat OpenAI | `crates/inference-server/src/compat.rs` |
|
|
| Engine | `crates/inference-core/src/engine.rs` |
|
|
| Session | `crates/inference-core/src/session.rs` |
|
|
| Sampler | `crates/inference-core/src/sampler.rs` |
|
|
| Schemas | `crates/api-contracts/src/chat.rs` |
|
|
| Entry Tauri | `tauri-app/src-tauri/src/lib.rs` |
|
|
| Runtime Types | `tauri-app/src-tauri/src/runtime/types.rs` |
|
|
|
|
### Env Vars Completas
|
|
|
|
```bash
|
|
# Modelo e Performance
|
|
LOCALLLM_MODEL="/path/to/model.gguf"
|
|
LOCALLLM_PROFILE="turbo_4b" # turbo_4b, balanced_9b, cpu_fallback
|
|
LOCALLLM_CTX=8192
|
|
LOCALLLM_BATCH=4096
|
|
LOCALLLM_GPU_LAYERS=-1
|
|
LOCALLLM_THREADS=4
|
|
LOCALLLM_THREADS_BATCH=4
|
|
|
|
# Servidor
|
|
LOCALLLM_ADDR="0.0.0.0:8080"
|
|
LOCALLLM_API_KEY="secret"
|
|
LOCALLLM_AUTH_HEADER="authorization"
|
|
LOCALLLM_AUTH_SCHEME="Bearer"
|
|
LOCALLLM_CORS_ORIGINS="*,https://example.com"
|
|
|
|
# Features
|
|
LOCALLLM_ENABLE_TOOL_CALLS="true"
|
|
LOCALLLM_MODEL_ALIASES="alias1,alias2"
|
|
LOCALLLM_SYSTEM_PROMPT="Você é um assistente..."
|
|
|
|
# Logging
|
|
LOCALLLM_LOG_FORMAT="json" # ou pretty
|
|
RUST_LOG="info"
|
|
```
|
|
|
|
---
|
|
|
|
## Conclusão
|
|
|
|
Este documento cobre a arquitetura completa do backend ForgeLM, incluindo:
|
|
|
|
1. **HTTP Server** - API compatível com OpenAI usando Axum
|
|
2. **Inference Core** - Motor de inferência via llama.cpp
|
|
3. **Tauri Backend** - Gerenciamento desktop do ciclo de vida
|
|
4. **API Contracts** - Schemas de request/response
|
|
5. **Fluxos de Dados** - Como as requisições fluem pelo sistema
|
|
|
|
Para mais detalhes, consulte os arquivos de código fonte mencionados nas referências.
|