Instructions to use impacte/ullr-2.6B-GGUF with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use impacte/ullr-2.6B-GGUF with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf impacte/ullr-2.6B-GGUF:F16 # Run inference directly in the terminal: llama cli -hf impacte/ullr-2.6B-GGUF:F16
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf impacte/ullr-2.6B-GGUF:F16 # Run inference directly in the terminal: llama cli -hf impacte/ullr-2.6B-GGUF:F16
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf impacte/ullr-2.6B-GGUF:F16 # Run inference directly in the terminal: ./llama-cli -hf impacte/ullr-2.6B-GGUF:F16
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf impacte/ullr-2.6B-GGUF:F16 # Run inference directly in the terminal: ./build/bin/llama-cli -hf impacte/ullr-2.6B-GGUF:F16
Use Docker
docker model run hf.co/impacte/ullr-2.6B-GGUF:F16
- LM Studio
- Jan
- Ollama
How to use impacte/ullr-2.6B-GGUF with Ollama:
ollama run hf.co/impacte/ullr-2.6B-GGUF:F16
- Unsloth Desktop
- Pi
How to use impacte/ullr-2.6B-GGUF with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf impacte/ullr-2.6B-GGUF:F16
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "impacte/ullr-2.6B-GGUF:F16" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Docker Model Runner
How to use impacte/ullr-2.6B-GGUF with Docker Model Runner:
docker model run hf.co/impacte/ullr-2.6B-GGUF:F16
- Lemonade
How to use impacte/ullr-2.6B-GGUF with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull impacte/ullr-2.6B-GGUF:F16
Run and chat with the model
lemonade run user.ullr-2.6B-GGUF-F16
List all available models
lemonade list
- Hermes Agent
How to use impacte/ullr-2.6B-GGUF with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf impacte/ullr-2.6B-GGUF:F16
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default impacte/ullr-2.6B-GGUF:F16
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use impacte/ullr-2.6B-GGUF with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf impacte/ullr-2.6B-GGUF:F16
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "impacte/ullr-2.6B-GGUF:F16" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
ULLR โ Search-First, Execute-Verified Tool-Calling Model
ULLR (the Norse god of archery โ precision, focus) is a 2.6B tool-calling model fine-tuned from LiquidAI/LFM2.5-2.6B for the nolock coding assistant. It is trained to follow a strict policy: search the web before answering, execute code before claiming it works, and always work with tool feedback. When served inside an agent harness (such as nolock), this policy makes the system a precise, verified coding agent โ ULLR is the model that powers it.
Results
BFCL v4 AST accuracy โ full model ladder
All models evaluated with the identical harness (official bfcl_eval AST checker, greedy decoding, native tool-call parsing). The Qwen models went through the same pipeline as ULLR: SFT on the same 296-example dataset (Qwen-native format + no-tool chat mix), merge, GGUF, and โ for the 0.8B variants โ KTO rounds with harvested negatives.
| Model | Params | Training | simple | multiple | parallel | parallel_multi | Overall |
|---|---|---|---|---|---|---|---|
| LFM2-1.2B-Tool + SFT + KTO | 1.2B | SFT+KTO | 0.492 | 0.375 | 0.425 | 0.113 | 0.351 |
| Qwen3.5-0.8B (base) | 0.8B | โ | 0.667 | 0.500 | 0.438 | 0.263 | 0.489 |
| Qwen3.5-0.8B + SFT | 0.8B | SFT | 0.667 | 0.500 | 0.438 | 0.263 | 0.489 |
| Qwen3.5-0.8B + SFT + KTO | 0.8B | SFT+KTO | 0.667 | 0.500 | 0.438 | 0.263 | 0.489 |
| Qwen3.5-2B (base) | 2B | โ | โ | โ | โ | โ | โ |
| Qwen3.5-2B + SFT (QLoRA) | 2B | SFT | 0.783 | 0.575 | 0.688 | 0.338 | 0.617 |
| Qwen3.5-2B + SFT + KTO | 2B | SFT+KTO | 0.783 | 0.575 | 0.688 | 0.338 | 0.617 |
| LFM2.5-2.6B (base) | 2.6B | โ | 0.883 | 0.812 | 0.738 | 0.637 | 0.781 |
| ULLR (LFM2.5-2.6B + KTO) | 2.6B | KTO | 0.875 | 0.925 | 0.825 | 0.650 | 0.825 |
| ULLR Q4_K_M (quantized) | 2.6B | KTO + Q4 | 0.908 | 0.838 | 0.775 | 0.537 | 0.781 |
Key takeaways:
- ULLR (KTO) beats every Qwen variant at every size โ +33.6pp over the fine-tuned Qwen3.5-2B, +46.6pp over the fine-tuned Qwen3.5-0.8B
- The KTO gain (+4.4pp) concentrated in multi-call categories:
multiple+11.3pp,parallel+8.7pp over base - Even the 1.7GB Q4 quantization (0.781) matches the unquantized base โ the KTO gains survive quantization
- Notably, KTO only improved the strongest base: on the Qwen models, identical KTO pipelines were neutral-to-harmful (see training details)
Multi-turn & in-domain
| Benchmark | Base LFM2.5-2.6B | ULLR (KTO) |
|---|---|---|
| ฯ-bench call validity (16 episodes) | 100% | 100% |
| ฯ-bench env errors | 0 | 0 |
| In-domain validation (10 prompts) | 5/10 | 6/10 |
In-domain failures are concentrated in multi-step completion (long verify loops exceeding the 8-step budget), not tool selection โ the model picks the right tools in the right order but doesn't always converge to a final answer.
How it was built
1. The policy (defined by the product, not the benchmark)
ULLR is trained to almost never answer from parametric knowledge:
User asks anything factual? โ web_search โ (web_fetch) โ cited summary
Answer contains math or code? โ rust_repl executes it FIRST โ verified result
Search/fetch fails? โ refine query / different URL โ retry
Local project question? โ grep / read_file / list_directory / edit
User gives a task? โ engage with tools immediately, never deflect
This is deliberately not the classic "don't over-call tools" alignment โ the model is supposed to search even when it probably knows the answer, and to run code before reporting results, accepting slower answers in exchange for verified ones.
2. GLM-5.3-Flash as the trajectory teacher
The policy training data was authored by GLM-5.3-Flash (Z.ai) acting as the teacher, rather than generated by a local model. This mattered for three behaviors that had zero coverage in the existing data:
- Search-and-summarize loops:
web_search โ web_fetch โ cited summarytrajectories with real queries and real documentation URLs (Rust Book, MDN, React blog, Tokio docs), each answer citing its source and noting why verification mattered - Code-execution: math/code questions where
rust_replruns before answering โ prime sums, Fibonacci, JSON/serde parsing, even a deliberate compile-error check (E0308) โ with answers reporting the executed result - Tool-feedback recovery: search โ fetch official docs โ synthesize setup steps across sources
The teacher also authored the engagement pairs: chat-deflection responses (the model's measured failure mode) as rejected completions, paired with acknowledge-and-call chosen completions reconstructed from ฯ-bench ground-truth action lists.
3. Nemotron-Nano-9B as the local cross-validation judge
Every row was cross-validated by a locally-running Nemotron-Nano-9B acting as a policy judge before training. The judge was first validated itself on 4 crafted cases (4/4 discrimination, including a borderline math-without-REPL case).
Judging all 115 rows flagged 44 as mislabeled. Human categorization of the flags showed:
| Flag reason | Count | Verdict |
|---|---|---|
| Judge expected full task/summary in a single completion | 23 | Judge wrong โ KTO completions are deliberately first-turn calls |
| Judge misapplied policy (ฯ-bench tools โ "local tools") | 10 | Judge wrong |
list_directory used on a file path |
7 | Real error โ fixed (read_file substituted) |
| Ambiguous STOP-acknowledgment negatives | 2 | Dropped |
The cross-validation caught 7 genuine tool-selection errors that would have taught the model to list directories instead of reading files โ while the 35 over-strict flags were overridden with documented reasoning. Automated judging + human categorization was the combination that worked.
4. nolock's KTO/DPO framework
Training used nolock's in-house preference framework โ the same .rlhf collection schema (thumbs-up/thumbs-down with user_correction metadata) that powers the editor's feedback loop. Human-labeled rows (including KTO-schema rows rescued from a mislabeled dpo/good/ directory, and LFM2-dialect tool calls converted to native format) were merged with on-policy negatives harvested from benchmark failures, then cross-validated. The framework's schema (TRL-compatible {prompt, completion, label}) fed directly into TRL's KTOTrainer.
Why KTO worked here (and failed on smaller models)
Three earlier KTO attempts (Qwen3.5-0.8B ร2, Qwen3.5-2B) failed to improve their bases. This one succeeded (+4.4pp BFCL, validation 5โ6/10) because:
- Strong base: LFM2.5-2.6B's agentic RL gave it capability to calibrate, not capability to create
- On-policy negatives: the 11 ฯ-bench non-engagement failures were the model's own outputs, not synthetic approximations
- Low KL drift (6.5): the training nudged engagement calibration without damaging the underlying agentic competence โ margins stayed positive (+0.59 โ +0.88) throughout
The policy (what this model is trained to do)
User asks anything factual? โ web_search โ (web_fetch) โ cited summary
Answer contains math or code? โ rust_repl executes it FIRST โ verified result
Search/fetch fails? โ refine query / different URL โ retry
Local project question? โ grep / read_file / list_directory / edit
User gives a task? โ engage with tools immediately, never deflect
Files
| File | Size | Use |
|---|---|---|
ullr-f16.gguf |
5.4 GB | Full precision โ local use with GPU headroom |
ullr-q4_k_m.gguf |
1.7 GB | Edge/Railway deployment (BFCL 0.781, โ4.4pp vs f16) |
Usage
llama.cpp (recommended serving path)
llama-server -m ullr-q4_k_m.gguf --jinja -c 8192 --port 8081
# OpenAI-compatible endpoint with native tool_calls:
curl http://localhost:8081/v1/chat/completions -d '{
"model": "ullr",
"messages": [{"role": "user", "content": "What is 17 * 23?"}],
"tools": [...],
"tool_choice": "auto"
}'
Ollama
ollama create ullr -f Modelfile # FROM ./ullr-q4_k_m.gguf
ollama run ullr "Find the official docs for the Tauri window-state plugin"
Note: serve via llama.cpp
--jinjaor Ollama โฅ 0.33. Earlier Ollama chat templates mishandle thereasoning_contentfield and can swallow tool calls after the thinking block.
Recommended sampling
temperature 0.1, top_k 50, top_p 0.9, repeat_penalty 1.1 (Liquid AI's official agentic settings).
Training details
| Base | LiquidAI/LFM2.5-2.6B (Lfm2ForCausalLM, hybrid 22 conv + 8 GQA) |
| Method | KTO (TRL KTOTrainer), LoRA r=32 / ฮฑ=64, dropout 0.05 |
| Targets | q/k/v/o_proj + gate/up/down_proj |
| Data | 106 rows (92 chosen / 14 rejected, 6.6:1) โ authored policy trajectories + on-policy harvested negatives + human preference rows |
| Hyperparams | lr 1e-5, ฮฒ 0.1, undesirable_weight 1.5, 3 epochs, batch 2ร4 accum, bf16, paged_adamw_8bit |
| Result | KL 6.5 (anchored), rewards/margins +0.59 โ +0.88, BFCL 0.781 โ 0.825 |
Limitations
- Multi-step completion: long verify loops (edit โ build โ test โ fix) can exceed practical step budgets; the model selects correctly but doesn't always converge within ~8 rounds.
- Reasoning overhead: always thinks before answering (
reasoning_content); latency per turn is higher than non-reasoning models of the same size. - License: LFM Open License v1.0 โ royalty-free for non-commercial/research and businesses <$10M annual revenue.
- Web dependency: per policy, factual answers require web access; offline use degrades to local-tools-only behavior.
Acknowledgments
- Liquid AI โ LFM2.5-2.6B base and the hybrid LIV+GQA architecture
- NVIDIA โ Nemotron-Nano-9B as the local cross-validation judge
- Z.ai โ GLM-5.3-Flash as the trajectory teacher
- Berkeley Function-Calling Leaderboard โ the evaluation harness
- Sierra Research โ ฯ-bench multi-turn evaluation
- llama.cpp โ inference runtime
Citation
@software{ullr2026,
author = {Gabriel Amazonas},
title = {ULLR: A Search-First, Execute-Verified Tool-Calling Model fine-tuned from LFM2.5-2.6B},
year = {2026},
url = {https://huggingface.co/impacte/ullr-2.6B-GGUF}
}
- Downloads last month
- -
4-bit
16-bit