This guide covers setting up local LLM (Large Language Model) infrastructure on the workstation for AI-assisted development.
Primary solution: vLLM — a Docker container serving unsloth/Qwen3.8-27B-NVFP4 on port 8080. It replaces the earlier LM Studio, Ollama, and llama.cpp setups.
Estimated setup time: 30-45 minutes (vLLM is pre-configured in the repository)
This guide covers:
vLLM is the primary local LLM server. It runs in a Docker container and serves the unsloth/Qwen3.8-27B-NVFP4 model via an OpenAI-compatible API on port 8080. It replaces the earlier LM Studio, Ollama, and llama.cpp setups.
--hf-overrides possible, but currently not active — see 1.5/1.6)scripts/local-llm/)scripts/local-llm/.env.vllm.\scripts\local-llm\start_vllm_server.ps1
The script:
llama-server is still running (port 8080 + VRAM conflict)vllm-qwen38-27b container.env.vllm)API endpoint: http://localhost:8080/v1
docker rm -f vllm-qwen38-27b
The server is configured in scripts/local-llm/docker-compose.vllm.yml. Key parameters:
Current configuration (2026-09-15):
| Parameter | Value | Purpose |
|---|---|---|
--max-model-len |
auto |
Auto-fit to available KV memory (→ 262k native on 96 GB @ 0.9) |
--max-num-seqs |
8 |
Max parallel sequences (recipe value for rtx_pro_6000) |
--tensor-parallel-size |
1 |
Single GPU |
--gpu-memory-utilization |
0.9 |
VRAM budget for weights + KV cache + CUDA graphs |
--mm-encoder-tp-mode |
data |
Data-parallel vision encoder (recipe default) |
--speculative-config |
mtp, 5 tokens |
MTP speculative decoding (recipe-verified for rtx_pro_6000 / dgx_spark_gb10) |
--enable-auto-tool-choice |
— | Tool-choice routing (active with the current VLLM_USE_RUST_FRONTEND=0) |
--reasoning-parser |
qwen3 |
Parse thinking blocks |
--tool-call-parser |
qwen3_coder |
Tool calling (official recipe parser) |
--chat-template |
/opt/chat_templates/qwen3.8-froggeric-v22.3.jinja |
froggeric v22.3 fixed chat template (JSON-string tool args, empty-think poisoning) |
--default-chat-template-kwargs |
enable_thinking: true, preserve_thinking: true, reasoning_effort: medium |
Server-wide thinking level (medium = model default; override per request) |
--async-scheduling |
— | Overlap request scheduling with GPU execution (recipe-verified for this GPU) |
V1 defaults (not in compose): enable_prefix_caching and enable_chunked_prefill are on by default in vLLM V1. kv_cache_dtype resolves to fp8 (torch.float8_e4m3fn) automatically for this mixed-precision NVFP4 checkpoint (confirmed in the startup log). max_num_batched_tokens defaults to 8192 (matches the recipe value for this GPU).
Environment (compose environment): VLLM_USE_RUST_FRONTEND=0 — the experimental Rust frontend is disabled (since 2026-09-16): while it was enabled it produced weird/mangled model responses, so it was switched off for output quality. While enabled it had improved decode throughput but also lacked --hf-overrides support (see 1.6 long-context note); with =0, --hf-overrides is supported again. VLLM_WSL2_ENABLE_PIN_MEMORY=1 avoids the WSL2 pinned-memory issue.
The model is multimodal (text + image + video, vision_config in the checkpoint); audio is not supported. Image tokens count against the context length (~2.3k tokens per 1920×1200 image).
Per-request thinking override: pass chat_template_kwargs (e.g. {"reasoning_effort":"low"} or {"enable_thinking":false}).
Current setup (measured 2026-09-15) — 262k native / 8 seqs / MTP=5 / async-scheduling / reasoning_effort: xhigh; warm server, short prompts, RTX PRO 6000 Blackwell (96 GB VRAM). Measured with the Rust frontend enabled; it was disabled again on 2026-09-16 (see findings)
| Change | Result (short prompt, no thinking, ~300 tokens) |
|---|---|
| MTP=3, no async-scheduling (cold) | ~109 tok/s |
| MTP=3 (warm) | ~148–153 tok/s |
| MTP=5 (recipe-verified value for this GPU) | ~200 tok/s |
MTP=5 + --async-scheduling (current) |
~230 tok/s |
num_speculative_tokens > 1 “may result in lower acceptance rate” — here the recipe-verified 5 outperformed the conservative default with higher acceptance.xhigh thinking (server default): ~155–175 tok/s on short prompts; thinking increases output length, so the tok/s is lower than the no-thinking number.Earlier tuning (2026-08-19/21) — RTX PRO 6000 Blackwell (96 GB VRAM), 50k–225k-token prompts, 1–8 parallel requests:
| Config | KV Pool | Generation Throughput | MTP Acceptance |
|---|---|---|---|
| 1M / 16 seqs (original) | very small | 0.2–0.5 tokens/s | 0–75% (volatile, long 0% stretches) |
| 512k / 8 seqs | 1.89M tokens | 125–161 tokens/s | 41–58% |
| 262k native / 8 seqs | 1.82M tokens | ~127 tokens/s | 43–53% |
| 1M / 6 seqs | 1.92M tokens | 85–120 tokens/s | 65–66% |
| 512k / 4 seqs (then) | 1.89M tokens | 30–76 tokens/s (long contexts) | 60–95% (content-dependent) |
Findings:
max-num-seqs (16 → 4–6), not the context length.seqs × max_len); max-num-seqs mainly caps concurrency and CUDA-graph batch sizes.mtp_num_hidden_layers: 3). num_speculative_tokens: 5 per the official recipe’s rtx_pro_6000 / dgx_spark_gb10 overrides now replaces the earlier depth-1 default (which showed 75–97% acceptance): depth 5 with async-scheduling gives ~230 tok/s vs ~150 at depth 3, with ~91% acceptance. vLLM’s speculative-decoding warning (“may result in lower acceptance rate”) did not materialize. Acceptance is a property of the generated text, not the config — measure over varied prompts.unsloth (mixed-precision NVFP4) leaves ~2× the KV cache of the uniform-W4A4 Inferact build, which drafts slightly better. For long-context single-GPU serving, unsloth is the right choice (per the official vLLM recipe).vllm/vllm-openai:latest (v0.29.0 as of 2026-09-15; 0.27.1 on 2026-08-20) is newer than the :nightly tag (0.26.1rc1.dev994 at the time) — use :latest.VLLM_USE_RUST_FRONTEND=0. While it was enabled (=1, 2026-09-15) it served the API via a Rust router and improved decode throughput (together with --async-scheduling), but it was disabled again because it produced weird responses — output quality over raw throughput. Secondary gap while enabled: --hf-overrides not supported (tracked in vllm#56931, feature-parity: vllm#44280) — with =0 this is no longer a blocker for the context extension below.tokenizer.json with truncation: max_length 2048, silently truncating all prompts. Unsloth re-uploaded a fixed revision (truncation: null); the HF cache picked it up automatically. Verify with: grep -o 'truncation.: null' .../tokenizer.json.--max-model-len + --hf-overrides '{"text_config":{"max_position_embeddings": N}}' (nested under text_config). The model’s native limit is 262k (rope_type: default); 512k/1M are supported extensions (YaRN RoPE scaling). Currently NOT active: the server runs with --max-model-len auto → 262k native. To enable 512k/1M, add the --hf-overrides argument to docker-compose.vllm.yml (supported again with VLLM_USE_RUST_FRONTEND=0).# Live engine metrics (throughput, KV-cache usage, MTP acceptance)
docker logs vllm-qwen38-27b 2>&1 | Select-Object -Last 10
# Prometheus metrics
curl -s http://localhost:8080/metrics
Key metrics to watch:
Avg generation throughput (tokens/s)GPU KV cache usage (%)Avg Draft acceptance rate (MTP)Running / Waiting request countsStartup and runtime logs are written to logs/vllm/vllm_start_YYYYMMDD_HHMMSS.log.
✓ Checkpoint: vLLM server is running at http://localhost:8080/v1
The following LM Studio instructions are kept for reference only. vLLM (above) is the current primary local LLM server.
C:\Users\<YourUsername>\AppData\Local\Programs\LM StudioLM Studio has a built-in model browser to download LLMs:
Q4_K_M - Good balance (recommended for most users)Q5_K_M - Higher quality, more memoryQ8_0 - Highest quality, requires significant memoryNote: Models are stored in: C:\Users\<YourUsername>\.cache\lm-studio\models
Configure Model Parameters:
Click the ⚙️ Settings icon (top-right of chat window) to adjust:
Context Length:
2048 tokens4096 - 8192 tokensTemperature:
0.0 (deterministic) to 2.0 (creative)0.1 - 0.3 (more precise)0.7 - 1.0 (more varied)0.7Top P (Nucleus Sampling):
0.0 to 1.00.95Repeat Penalty:
1.0 (no penalty) to 1.5 (high penalty)1.1GPU Layers:
Auto (recommended)System Prompt (Optional):
Configure the model’s behavior with a system prompt:
You are an expert Python and geospatial data scientist. You help with
code for analyzing urban tree drought risk using GeoPandas, PostGIS,
and related libraries. Provide clear, well-documented code examples.
Click “Save Preset” to reuse this configuration.
LM Studio includes an OpenAI-compatible API server:
1234 (do not change unless needed)http://127.0.0.1:1234/v1Test the Server:
Open PowerShell and test with curl:
curl http://127.0.0.1:1234/v1/models
You should see a JSON response with your loaded model.
✓ Checkpoint: LM Studio server is running at http://127.0.0.1:1234/v1
Official Documentation:
Community Resources:
Understanding Model Parameters:
Connect GitHub Copilot in VSCode to use your local vLLM model instead of OpenAI.
Prerequisites:
Workstation_Remote_Development.md)Ctrl+, (or Cmd+, on macOS)github.copilot.chat.localhostChatModelsAdd Local Model Configuration:
Click “Edit in settings.json” and add:
{
"github.copilot.advanced": {
"debug.overrideEngine": "local"
},
"github.copilot.chat.localhostChatModels": [
{
"model": "vllm",
"endpoint": "http://127.0.0.1:8080/v1/chat/completions",
"name": "vLLM Qwen3.8-27B (Local)"
}
]
}
/v1 endpoint:
http://127.0.0.1:8080/v1/chat/completionshttp://127.0.0.1:8080/chat/completions/v1 is required for OpenAI API compatibilityCtrl+Shift+P (or Cmd+Shift+P on macOS)Ctrl+Shift+I (Windows/Linux) or Cmd+Shift+I (macOS)Test the Integration:
Try a simple prompt:
Explain how to read a GeoPackage with GeoPandas
The response should come from your local vLLM model.
Current Limitations:
Performance Tips:
Troubleshooting:
docker ps)/v1 and uses port 8080Note: llama.cpp is superseded by vLLM (Part 1). The llama.cpp autostart task is kept for reference only. The vLLM container is managed via
start_vllm_server.ps1and does not require a Windows Scheduled Task.
For the shared workstation, the repository also supports a local llama.cpp server that starts automatically during Windows boot, even before a user signs in.
Why this setup exists:
SYSTEM in Session 0, so it is independent of interactive VS Code or RDP sessions.Managed scripts in this repository:
scripts/local-llm/start_llama_server.ps1 starts llama-server.exe as a detached process.scripts/local-llm/register_llama_server_startup.ps1 registers the Windows Scheduled Task.scripts/local-llm/unregister_llama_server_startup.ps1 removes the Scheduled Task again.Registration command:
pwsh -NoProfile -File scripts/local-llm/register_llama_server_startup.ps1
This creates the task BlueGreenCity-KI llama.cpp server with these properties:
SYSTEMpowershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/start_llama_server.ps1VS Code tasks:
Register llama.cpp startup taskUnregister llama.cpp startup taskOperational details:
logs/llama-cpp/llama_server_YYYYMMDD_HHMMSS.logC:\ProgramData\llama-cpp\huggingfaceLLAMA_CPP_CACHE_ROOT if neededVerify registration:
Get-ScheduledTask -TaskName 'BlueGreenCity-KI llama.cpp server'
Manual test run:
Start-ScheduledTask -TaskName 'BlueGreenCity-KI llama.cpp server'
Get-ScheduledTaskInfo -TaskName 'BlueGreenCity-KI llama.cpp server'
Verification target:
NT-AUTORITÄT\SYSTEMLastTaskResult = 0Removal command:
pwsh -NoProfile -File scripts/local-llm/unregister_llama_server_startup.ps1
✓ Checkpoint: GitHub Copilot Chat uses the local vLLM model
KiloCode is an alternative AI coding assistant that works with local LLM servers.
Ctrl+Shift+X)Ctrl+, and search for kilocodeSet OpenAI-Compatible Endpoint:
In VSCode settings.json:
{
"kilocode.apiEndpoint": "http://127.0.0.1:8080/v1",
"kilocode.model": "unsloth/Qwen3.8-27B-NVFP4",
"kilocode.apiKey": "not-needed"
}
Configure Model Parameters (Optional):
{
"kilocode.temperature": 0.2,
"kilocode.maxTokens": 2048
}
Ctrl+Shift+P → “KiloCode: Open”✓ Checkpoint: KiloCode is configured and working with local LLM
Model Context Protocol (MCP) allows LLMs to access external tools like databases.
What is MCP?
Architecture:
vLLM (LLM) ←→ MCP Client ←→ MCP Server ←→ Database/Tools
Docker MCP Hub provides pre-configured MCP servers in containers.
Install Docker MCP Hub:
Open PowerShell and run:
# Clone the Docker MCP Hub repository
git clone https://github.com/docker/mcp-hub.git
cd mcp-hub
# Start the hub
docker-compose up -d
Verify Installation:
docker ps
You should see MCP Hub containers running.
Configure MCP to access the PostGIS database:
Configure Database Connection:
Create mcp-config.json in the MCP Hub directory:
{
"mcpServers": {
"postgres": {
"command": "docker",
"args": [
"run",
"--rm",
"-e", "POSTGRES_CONNECTION_STRING=postgresql://postgres:your_password@host.docker.internal:5432/bgcki",
"mcp/postgres"
]
}
}
}
Replace your_password with the actual database password from .env
Test Database Connection:
# From the mcp-hub directory
docker run --rm `
-e "POSTGRES_CONNECTION_STRING=postgresql://postgres:your_password@host.docker.internal:5432/bgcki" `
mcp/postgres test
Available Database Operations:
Note: vLLM exposes an OpenAI-compatible API but does not include a native MCP client. Use an MCP-capable front end (Claude Desktop, Open WebUI, or AnythingLLM) to connect the LLM to MCP servers.
Option A: Use Claude Desktop with MCP (Recommended)
claude_desktop_config.json:{
"mcpServers": {
"postgres": {
"command": "docker",
"args": [
"run", "--rm",
"-e", "POSTGRES_CONNECTION_STRING=postgresql://postgres:password@host.docker.internal:5432/bgcki",
"mcp/postgres"
]
}
}
}
Option B: Use AnythingLLM with MCP Bridge
✓ Checkpoint: MCP Server is running and accessible
Web interfaces for interacting with local LLMs.
AnythingLLM is a full-featured AI document chat and assistant application.
http://127.0.0.1:8080/v1unsloth/Qwen3.8-27B-NVFP4Open WebUI (formerly Ollama WebUI) is a self-hosted ChatGPT-style interface.
Install with Docker:
docker run -d -p 3000:3000 `
--name open-webui `
-v open-webui:/app/backend/data `
ghcr.io/open-webui/open-webui:main
Note: Open WebUI’s internal port is
8080, which conflicts with the vLLM host port. Map it to host port3000instead.
http://host.docker.internal:8080/v1unsloth/Qwen3.8-27B-NVFP4| Feature | AnythingLLM | Open WebUI |
|---|---|---|
| Installation | Desktop app | Docker container |
| Document Chat | ✅ Excellent | ✅ Good |
| UI/UX | Clean, modern | ChatGPT-like |
| Multi-model | ✅ Yes | ✅ Yes |
| Customization | High | Very High |
| Plugins | Growing | Extensive |
| Best for | Document Q&A | General chat |
Recommendation: Use both!
✓ Checkpoint: Web UI is running and connected to the vLLM server
.\scripts\local-llm\start_vllm_server.ps1)Example Prompts:
Example:
Example:
For Code:
For Chat/Docs:
Hardware:
Configuration:
Local LLMs:
API Security:
0.0.0.0:8080 (Docker port mapping)Database Access:
Issue: vLLM API not responding
docker ps --filter name=vllm-qwen38-27bdocker logs vllm-qwen38-27b 2>&1 | Select-Object -Last 30curl http://127.0.0.1:8080/v1/models.\scripts\local-llm\start_vllm_server.ps1Issue: VSCode can’t connect to local model
/v1 and uses port 8080Issue: Slow inference
reasoning_effort per request (low or enable_thinking: false)Issue: Out of memory / KV-cache exhaustion
--max-num-seqs (biggest lever for KV-pool size)--gpu-memory-utilization (currently 0.9) to shrink the weights+KV budgetGPU KV cache usage in the logs (should stay below ~80%)vLLM:
Qwen3.8-27B (Unsloth NVFP4):
Model Context Protocol (MCP):
AnythingLLM:
Open WebUI:
Forums and Communities:
Model Leaderboards:
Learning Resources:
Code Generation:
General Chat:
Document Q&A:
Small/Fast (< 7B):
Experimental:
http://127.0.0.1:8080/v1http://127.0.0.1:8080/metricsscripts/local-llm/docker-compose.vllm.ymlscripts/local-llm/start_vllm_server.ps1scripts/local-llm/.env.vllmlogs/vllm/vllm_start_YYYYMMDD_HHMMSS.logunsloth/Qwen3.8-27B-NVFP4{
"github.copilot.chat.localhostChatModels": [
{
"model": "vllm",
"endpoint": "http://127.0.0.1:8080/v1/chat/completions",
"name": "vLLM Qwen3.8-27B (Local)"
}
]
}
# Start vLLM
.\scripts\local-llm\start_vllm_server.ps1
# Stop vLLM
docker rm -f vllm-qwen38-27b
# View vLLM logs
docker logs -f vllm-qwen38-27b
# Start Open WebUI (host port 3000 to avoid vLLM's 8080)
docker run -d -p 3000:3000 --name open-webui ghcr.io/open-webui/open-webui:main
808030005432123411434Note: Ollama is superseded by vLLM (Part 1). This appendix is kept for reference only.
For a more lightweight, CLI-focused approach, consider Ollama:
# Windows (native)
winget install Ollama.Ollama
# Or download from: https://ollama.com/download
# Run a model
ollama run codellama
# List models
ollama list
# Pull a model
ollama pull mistral
# Serve API
ollama serve # Runs on port 11434
{
"github.copilot.chat.localhostChatModels": [
{
"model": "ollama",
"endpoint": "http://127.0.0.1:11434/v1/chat/completions",
"name": "Ollama (Local)"
}
]
}
When to use Ollama:
For questions or issues:
Workstation_Remote_Development.md for SSH setup issuesLast updated: August 2026