Spaces:
Running on Zero
fix: Wire up the GGUF deployment path and fix its tokenizer mismatch
Browse filesllama-cpp-python was never in requirements.txt, so on HF Spaces HAS_LLAMA_CPP
was always False and every request silently fell back to slow bf16 PyTorch
inference under ZeroGPU's 300s budget -- despite the app already containing a
full GGUF loading path for exactly this deployment. Added the dependency and
uploaded a quantized GGUF of the currently-best-benchmarked (sft_v2) fused
checkpoint to the atakankahya/ControlAI-Agent Hub repo.
Also fixed: passing an explicit .gguf/ollama model path loaded a hardcoded
"Qwen/Qwen2.5-3B-Instruct" tokenizer instead of this model's own tokenizer and
chat template -- wrong vocab and tool-call format entirely.
Quantization level was chosen empirically, not assumed: tested Q4_K_M, Q6_K,
Q8_0, and full f16 against this exact fine-tuned model on a step-response
prompt (3 runs each). Q4_K_M mis-routed tool calls in 3/3 runs and produced
wildly inconsistent hallucinated numbers; Q6_K/Q8_0/f16 all called the correct
tool with consistent, verified numbers in 3/3 runs. Q8_0 was fastest of the
three correct options and is near-lossless relative to f16 at roughly half
the size, so it's now the default.
Also corrected a stale "68,000+ chunks" README claim -- the actual local RAG
index has ~9,900.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- README.md +2 -2
- controlai_agent/orchestrator.py +26 -5
- requirements.txt +1 -0
|
@@ -50,7 +50,7 @@ Standard large language models (LLMs) operate probabilistically without determin
|
|
| 50 |
1. **Deterministic Scientific Sandbox:** Computes continuous/discrete algebraic Riccati equations (CARE/DARE), matrix exponentials, and Bode diagrams using LAPACK, SciPy, and CVXPY.
|
| 51 |
2. **4-Stage Mathematical Proof Standard:** Formulates system class, analytical theorems, closed-form derivations, and engineering breakdown limits.
|
| 52 |
3. **Dynamic Simulation & Plotting:** Solves nonlinear differential equations and renders verified trajectories directly in the interface.
|
| 53 |
-
4. **Offline RAG Knowledge Engine:** Grounded with
|
| 54 |
|
| 55 |
---
|
| 56 |
|
|
@@ -64,7 +64,7 @@ graph TD
|
|
| 64 |
subgraph Core Engine [Hybrid Verification Engine]
|
| 65 |
Brain[Foundation Model - Qwen3-4B]
|
| 66 |
LoRA[Theory & Tool Adapter - SFT]
|
| 67 |
-
RAG[Offline Knowledge Engine -
|
| 68 |
Tools[Deterministic Numerical Tool Suite]
|
| 69 |
end
|
| 70 |
|
|
|
|
| 50 |
1. **Deterministic Scientific Sandbox:** Computes continuous/discrete algebraic Riccati equations (CARE/DARE), matrix exponentials, and Bode diagrams using LAPACK, SciPy, and CVXPY.
|
| 51 |
2. **4-Stage Mathematical Proof Standard:** Formulates system class, analytical theorems, closed-form derivations, and engineering breakdown limits.
|
| 52 |
3. **Dynamic Simulation & Plotting:** Solves nonlinear differential equations and renders verified trajectories directly in the interface.
|
| 53 |
+
4. **Offline RAG Knowledge Engine:** Grounded with 9,900+ chunks indexed across classical and modern control engineering literature.
|
| 54 |
|
| 55 |
---
|
| 56 |
|
|
|
|
| 64 |
subgraph Core Engine [Hybrid Verification Engine]
|
| 65 |
Brain[Foundation Model - Qwen3-4B]
|
| 66 |
LoRA[Theory & Tool Adapter - SFT]
|
| 67 |
+
RAG[Offline Knowledge Engine - 9,900+ Chunks]
|
| 68 |
Tools[Deterministic Numerical Tool Suite]
|
| 69 |
end
|
| 70 |
|
|
@@ -239,6 +239,11 @@ REPETITION_PENALTY = 1.15
|
|
| 239 |
|
| 240 |
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
| 241 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 242 |
# How many times a single tool may be invoked within one user turn. Two allows
|
| 243 |
# a legitimate retry with corrected arguments after an error, while stopping
|
| 244 |
# the model from spending its whole step budget re-running the same lookup.
|
|
@@ -572,7 +577,7 @@ class ControlAIAgent:
|
|
| 572 |
|
| 573 |
if self.is_ollama:
|
| 574 |
self.ollama_model = model_path.split(":", 1)[1] if ":" in str(model_path) else "controlai"
|
| 575 |
-
self.hf_tokenizer = AutoTokenizer.from_pretrained(
|
| 576 |
elif self.is_gguf:
|
| 577 |
if not HAS_LLAMA_CPP:
|
| 578 |
raise ImportError("llama-cpp-python is required to run GGUF models. Install it with: pip install llama-cpp-python")
|
|
@@ -582,7 +587,12 @@ class ControlAIAgent:
|
|
| 582 |
n_ctx=16384,
|
| 583 |
verbose=False,
|
| 584 |
)
|
| 585 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 586 |
elif self.is_mlx:
|
| 587 |
if adapter_path:
|
| 588 |
self.model, self.mlx_tokenizer = mlx_load(model_path, adapter_path=adapter_path)
|
|
@@ -590,11 +600,22 @@ class ControlAIAgent:
|
|
| 590 |
self.model, self.mlx_tokenizer = mlx_load(model_path)
|
| 591 |
self.hf_tokenizer = AutoTokenizer.from_pretrained(model_path)
|
| 592 |
else:
|
| 593 |
-
# Universal Linux / Cloud / HuggingFace Spaces backend:
|
| 594 |
# of OUR OWN fine-tuned ControlAI model (never a generic base model).
|
| 595 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 596 |
gguf_repo = os.environ.get("CONTROLAI_GGUF_REPO", CONTROLAI_HF_REPO)
|
| 597 |
-
gguf_filename = os.environ.get("CONTROLAI_GGUF_FILENAME", "*controlai-
|
| 598 |
|
| 599 |
self.llama_model = None
|
| 600 |
if HAS_LLAMA_CPP:
|
|
|
|
| 239 |
|
| 240 |
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
| 241 |
|
| 242 |
+
# Our own fine-tuned model's repo -- every GGUF/Ollama/CUDA backend must load
|
| 243 |
+
# ITS tokenizer and chat template (never a generic base model's), since the
|
| 244 |
+
# tool-call format, special tokens, and vocab are specific to this fine-tune.
|
| 245 |
+
CONTROLAI_HF_REPO = "atakankahya/ControlAI-Agent"
|
| 246 |
+
|
| 247 |
# How many times a single tool may be invoked within one user turn. Two allows
|
| 248 |
# a legitimate retry with corrected arguments after an error, while stopping
|
| 249 |
# the model from spending its whole step budget re-running the same lookup.
|
|
|
|
| 577 |
|
| 578 |
if self.is_ollama:
|
| 579 |
self.ollama_model = model_path.split(":", 1)[1] if ":" in str(model_path) else "controlai"
|
| 580 |
+
self.hf_tokenizer = AutoTokenizer.from_pretrained(CONTROLAI_HF_REPO, trust_remote_code=True)
|
| 581 |
elif self.is_gguf:
|
| 582 |
if not HAS_LLAMA_CPP:
|
| 583 |
raise ImportError("llama-cpp-python is required to run GGUF models. Install it with: pip install llama-cpp-python")
|
|
|
|
| 587 |
n_ctx=16384,
|
| 588 |
verbose=False,
|
| 589 |
)
|
| 590 |
+
# A local .gguf path carries no tokenizer/chat-template of its own --
|
| 591 |
+
# always load ours (never a generic base model's), same as the
|
| 592 |
+
# auto-downloaded deployment path below.
|
| 593 |
+
local_fused = PROJECT_ROOT / "models" / "controlai_fused"
|
| 594 |
+
tokenizer_source = str(local_fused) if local_fused.exists() else CONTROLAI_HF_REPO
|
| 595 |
+
self.hf_tokenizer = AutoTokenizer.from_pretrained(tokenizer_source, trust_remote_code=True)
|
| 596 |
elif self.is_mlx:
|
| 597 |
if adapter_path:
|
| 598 |
self.model, self.mlx_tokenizer = mlx_load(model_path, adapter_path=adapter_path)
|
|
|
|
| 600 |
self.model, self.mlx_tokenizer = mlx_load(model_path)
|
| 601 |
self.hf_tokenizer = AutoTokenizer.from_pretrained(model_path)
|
| 602 |
else:
|
| 603 |
+
# Universal Linux / Cloud / HuggingFace Spaces backend: fast C++ GGUF
|
| 604 |
# of OUR OWN fine-tuned ControlAI model (never a generic base model).
|
| 605 |
+
#
|
| 606 |
+
# Q8_0, not Q4_K_M: measured directly against this exact model on the
|
| 607 |
+
# "simulate a step response" prompt (3 runs each). Q4_K_M mis-routed
|
| 608 |
+
# tool calls in 3/3 runs (reached for continuous_lqr/bode_analysis
|
| 609 |
+
# instead of simulate_step_response, then hallucinated inconsistent
|
| 610 |
+
# overshoot values -- 8.6%, 43.1%, 25.4%, none near the true ~9.5%).
|
| 611 |
+
# Q6_K, Q8_0, and full f16 all called the correct tool with
|
| 612 |
+
# consistent, tool-verified numbers in 3/3 runs apiece, matching
|
| 613 |
+
# local MLX behavior -- Q8_0 was picked among those three because it
|
| 614 |
+
# was both the fastest of the three in this test (8-19s vs Q6_K's
|
| 615 |
+
# 11-25s and f16's 11-22s) and, at 8.5 bits/weight, close enough to
|
| 616 |
+
# f16 to be considered near-lossless, at roughly half f16's size.
|
| 617 |
gguf_repo = os.environ.get("CONTROLAI_GGUF_REPO", CONTROLAI_HF_REPO)
|
| 618 |
+
gguf_filename = os.environ.get("CONTROLAI_GGUF_FILENAME", "*controlai-q8_0.gguf")
|
| 619 |
|
| 620 |
self.llama_model = None
|
| 621 |
if HAS_LLAMA_CPP:
|
|
@@ -13,6 +13,7 @@ control>=0.9.4
|
|
| 13 |
cvxpy>=1.4.0
|
| 14 |
rich>=13.7.0
|
| 15 |
rank-bm25>=0.2.2
|
|
|
|
| 16 |
pypdf>=3.17.0
|
| 17 |
pymupdf>=1.23.0
|
| 18 |
scikit-learn>=1.3.0
|
|
|
|
| 13 |
cvxpy>=1.4.0
|
| 14 |
rich>=13.7.0
|
| 15 |
rank-bm25>=0.2.2
|
| 16 |
+
llama-cpp-python>=0.3.0
|
| 17 |
pypdf>=3.17.0
|
| 18 |
pymupdf>=1.23.0
|
| 19 |
scikit-learn>=1.3.0
|