Image-Text-to-Text
Transformers
Safetensors
qwen3_5
decision-making
routing
mixture-of-experts
moqle
lora
agents
e2e-testing
games
multilingual
on-device
system-one
conversational
Instructions to use labqoat/squad-0.8b with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use labqoat/squad-0.8b with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="labqoat/squad-0.8b") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("labqoat/squad-0.8b") model = AutoModelForMultimodalLM.from_pretrained("labqoat/squad-0.8b", device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use labqoat/squad-0.8b with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "labqoat/squad-0.8b" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "labqoat/squad-0.8b", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/labqoat/squad-0.8b
- SGLang
How to use labqoat/squad-0.8b with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "labqoat/squad-0.8b" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "labqoat/squad-0.8b", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "labqoat/squad-0.8b" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "labqoat/squad-0.8b", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use labqoat/squad-0.8b with Docker Model Runner:
docker model run hf.co/labqoat/squad-0.8b
squad-0.8b 2026-10-26: retrained e2e expert (real web-app data, held-out tests 29/82 vs 17/82), prefix cache in the runtime
091795c verified Download qev_server.py from labqoat/squad-0.8b: direct link, hf CLI and curl.
- Browser
- Download file 17.8 kB
-
https://huggingface.co/labqoat/squad-0.8b/resolve/main/qev_server.py
- Command line
-
hf download hf://labqoat/squad-0.8b/qev_server.py
-
curl -L -o qev_server.py https://huggingface.co/labqoat/squad-0.8b/resolve/main/qev_server.py
17.8 kB
| """qev_server: an HTTP server for qev-0.8b that speaks the System One wire format (POST /v1/systemone). | |
| pip install -r requirements.txt # + requirements-cuda.txt on an NVIDIA GPU | |
| python qev_server.py # http://127.0.0.1:8017, labqoat/squad-0.8b | |
| python qev_server.py --host 0.0.0.0 --port 8000 --encoding per_question | |
| python qev_server.py --specialists # router + games / e2e-tester LoRA slots (fast CUDA backend) | |
| curl http://127.0.0.1:8017/v1/systemone -H 'Content-Type: application/json' -d '{ | |
| "model": "squad-0.8b", | |
| "state": "My card was charged twice for the same order, please refund one.", | |
| "questions": {"billing": {"type": "noul", "instructions": "Is this a billing problem?"}}}' | |
| -> {"model": "squad-0.8b", "answers": {"billing": {"type": "noul", "noul": 0.97}}, | |
| "usage": {"input_tokens": 51, "output_tokens": 0}} | |
| Endpoints: | |
| - POST /v1/systemone {"state": str | object | array, "questions": {id: question}, "model": optional, "encoding": | |
| optional "joint" | "per_question", "images": optional {name: base64 PNG / JPEG}, | |
| "image_detail": optional "low" | "default" | "high" (256², 448², 1024² pixels; or | |
| "max_pixels": int)} -> | |
| {"model", "answers", "usage"}. Code written for the System One API works unchanged; "model" in | |
| the request is accepted and ignored. Images (fast CUDA backend; pillow + torchvision): the | |
| state places one with "<image:name>", an image it does not mention goes at the end of the | |
| context; usage then also reports "image_tokens". | |
| With --specialists, usage also reports "route": the slot the router chose ("trunk", | |
| "games", "e2e-tester"; per_question: one per question when they differ). | |
| - GET /health readiness, backend, encoding, model files' SHA-256 (from SHA256SUMS when present). | |
| - GET /v1/models the served model. | |
| State cache and memo (fast backend, on by default): an agent asking one question at a time about the same page | |
| sends the same state again and again. Model states (Gated DeltaNet states and attention K / V at the end of each | |
| request's state, a few tokens before it and every 2048 tokens) are kept on the GPU, LRU within --prefix-cache-mb | |
| (default 2048; 0: off), and a request (calls of up to 4) continues from the deepest one its tokens share: the same | |
| state computes only its questions (L40S, e2e pages: ~7.5 ms instead of ~20 ms), a state that grew computes only what | |
| is new. A new state costs more than without the cache (~+40%, it builds the checkpoints) and is computed the plain | |
| way when the call has several rows or other calls wait. Answers equal the uncached ones up to bf16 round-off (the same | |
| argmax and route; on bf16-sensitive requests the probabilities move as much as between the engine's own CUDA-graph | |
| and eager paths). A request repeated whole (state, questions, encoding) is answered from a memo of the last --memo | |
| requests (default 1024; 0: off) without the model. | |
| Concurrent requests are micro-batched: the first request in an idle server runs at once; requests that arrive while | |
| a batch is running are answered together in the next one (up to --max-batch). Answers are the same as one at a time | |
| up to floating-point round-off. With QEV_API_KEY set, every call but /health needs "Authorization: Bearer <key>". | |
| Only the Python standard library is used on top of qev.py. | |
| """ | |
| import argparse | |
| import hmac | |
| import json | |
| import os | |
| import queue | |
| import sys | |
| import threading | |
| import time | |
| from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer | |
| sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) | |
| MAX_BODY = 32 * 1024 * 1024 | |
| ENCODINGS = ("joint", "per_question") | |
| class Batcher: | |
| """One worker thread owns the model; requests queue up and are answered in batches.""" | |
| def __init__(self, decide_batch, max_batch: int = 8): | |
| self.decide_batch, self.max_batch = decide_batch, max_batch | |
| self.q: queue.Queue = queue.Queue() | |
| threading.Thread(target=self._loop, daemon=True).start() | |
| def submit(self, state, questions: dict, per_question: bool, timeout: float = 300.0, images: dict | None = None, | |
| max_pixels: int | None = None): | |
| done, box = threading.Event(), {} | |
| self.q.put((state, questions, per_question, done, box, images, max_pixels)) | |
| if not done.wait(timeout): | |
| raise TimeoutError("the model did not answer in time") | |
| if "error" in box: | |
| raise box["error"] | |
| return box["answers"], box["tokens"], box.get("image_tokens", 0), box.get("route") | |
| def _loop(self): | |
| while True: | |
| jobs = [self.q.get()] | |
| while len(jobs) < self.max_batch: | |
| try: | |
| jobs.append(self.q.get_nowait()) | |
| except queue.Empty: | |
| break | |
| for key in dict.fromkeys((j[2], j[6]) for j in jobs): # one batch per (encoding, image budget) | |
| part = [j for j in jobs if (j[2], j[6]) == key] | |
| self._run(part, key[0]) | |
| def _run(self, jobs: list, per_question: bool): | |
| try: | |
| res = self.decide_batch([(j[0], j[1], j[5]) if j[5] else (j[0], j[1]) for j in jobs], per_question, | |
| jobs[0][6]) | |
| except Exception as e: # noqa: BLE001 - one bad request must not fail the others: answer each on its own | |
| if len(jobs) > 1: | |
| for j in jobs: | |
| self._run([j], per_question) | |
| else: | |
| jobs[0][4]["error"] = e | |
| jobs[0][3].set() | |
| return | |
| for j, r in zip(jobs, res, strict=True): | |
| j[4]["answers"], j[4]["tokens"] = r[0], r[1] | |
| j[4]["image_tokens"] = r[2] if len(r) > 2 else 0 | |
| j[4]["route"] = r[3] if len(r) > 3 else None | |
| j[3].set() | |
| def _validate(req) -> tuple: | |
| if not isinstance(req, dict): | |
| raise ValueError('the body must be a JSON object: {"state": ..., "questions": {id: question}}') | |
| if "state" not in req: | |
| raise ValueError('missing "state"') | |
| qs = req.get("questions") | |
| if not isinstance(qs, dict) or not qs: | |
| raise ValueError('"questions" must be a non-empty object {id: question}') | |
| for k, q in qs.items(): | |
| if not isinstance(q, dict) or q.get("type") not in ("noul", "choice", "score"): | |
| raise ValueError(f'question "{k}": "type" must be "noul", "choice" or "score"') | |
| if not isinstance(q.get("instructions", ""), str): | |
| raise ValueError(f'question "{k}": "instructions" must be a string') | |
| if q["type"] in ("choice", "score") and not q.get("criteria"): | |
| raise ValueError(f'question "{k}": a {q["type"]} question needs "criteria"') | |
| enc = req.get("encoding") | |
| if enc is not None and enc not in ENCODINGS: | |
| raise ValueError('"encoding" must be "joint" or "per_question"') | |
| return req["state"], qs, enc | |
| IMAGE_DETAIL = {"low": 256 * 256, "default": 448 * 448, "high": 1024 * 1024} | |
| def image_budget(req: dict) -> int | None: | |
| """The request's image budget: "max_pixels" (int, 1024 to 4194304) or "image_detail" ("low" 256x256, "default" | |
| 448x448, "high" 1024x1024); None: the server's --max-pixels.""" | |
| mp, det = req.get("max_pixels"), req.get("image_detail") | |
| if mp is not None: | |
| if isinstance(mp, bool) or not isinstance(mp, int) or not 1024 <= mp <= 2048 * 2048: | |
| raise ValueError('"max_pixels" must be an integer from 1024 to 4194304') | |
| return mp | |
| if det is not None: | |
| if det not in IMAGE_DETAIL: | |
| raise ValueError('"image_detail" must be "low", "default" or "high"') | |
| return IMAGE_DETAIL[det] | |
| return None | |
| def decode_images(raw) -> dict | None: | |
| """The "images" field: {name: base64 string (a data: URL prefix is accepted)} -> {name: PIL image}.""" | |
| import base64 | |
| import binascii | |
| import io | |
| if raw is None or raw == {}: | |
| return None | |
| if not isinstance(raw, dict): | |
| raise ValueError('"images" must be an object {name: base64 string}') | |
| try: | |
| from PIL import Image | |
| except ImportError: | |
| raise ValueError("images need pillow (pip install pillow torchvision)") from None | |
| out = {} | |
| for k, v in raw.items(): | |
| if not isinstance(v, str): | |
| raise ValueError(f'image "{k}": a base64 string') | |
| if v.startswith("data:"): | |
| v = v.split(",", 1)[-1] | |
| try: | |
| out[k] = Image.open(io.BytesIO(base64.b64decode(v, validate=True))).convert("RGB") | |
| except (binascii.Error, OSError) as e: | |
| raise ValueError(f'image "{k}": not a decodable base64 image ({e})') from None | |
| return out | |
| def _file_hashes(path: str | None) -> dict: | |
| if path and os.path.exists(os.path.join(path, "SHA256SUMS")): | |
| out = {} | |
| for line in open(os.path.join(path, "SHA256SUMS")): | |
| parts = line.split() | |
| if len(parts) == 2 and parts[1].endswith((".safetensors", "tokenizer.json")): | |
| out[parts[1]] = parts[0] | |
| return out | |
| return {} | |
| class Server(ThreadingHTTPServer): | |
| daemon_threads = True | |
| request_queue_size = 1024 # the listen backlog (the stdlib default of 5 resets bursts of concurrent clients) | |
| def make_handler(batcher: Batcher, info: dict, encoding: str, api_key: str | None): | |
| class H(BaseHTTPRequestHandler): | |
| protocol_version = "HTTP/1.1" | |
| def _send(self, code: int, body: dict): | |
| data = json.dumps(body, ensure_ascii=False).encode() | |
| self.send_response(code) | |
| self.send_header("Content-Type", "application/json") | |
| self.send_header("Content-Length", str(len(data))) | |
| self.end_headers() | |
| self.wfile.write(data) | |
| def log_message(self, fmt, *args): | |
| if info.get("verbose"): | |
| super().log_message(fmt, *args) | |
| def _authorized(self) -> bool: | |
| if not api_key: | |
| return True | |
| got = self.headers.get("Authorization", "") | |
| return hmac.compare_digest(got, f"Bearer {api_key}") | |
| def do_GET(self): | |
| path = self.path.split("?", 1)[0] | |
| if path == "/health": | |
| return self._send(200, {"status": "ok", **{k: v for k, v in info.items() if k != "verbose"}}) | |
| if not self._authorized(): | |
| return self._send(401, {"detail": "missing or wrong API key"}) | |
| if path == "/v1/models": | |
| return self._send(200, {"object": "list", "data": [{"id": info["model"], "object": "model", | |
| "owned_by": "labqoat"}]}) | |
| return self._send(404, {"detail": "not found"}) | |
| def do_POST(self): | |
| path = self.path.split("?", 1)[0] | |
| if path != "/v1/systemone": | |
| return self._send(404, {"detail": "not found"}) | |
| if not self._authorized(): | |
| return self._send(401, {"detail": "missing or wrong API key"}) | |
| try: | |
| n = int(self.headers.get("Content-Length", 0)) | |
| if n > MAX_BODY: | |
| return self._send(413, {"detail": f"the body is larger than {MAX_BODY} bytes"}) | |
| body = json.loads(self.rfile.read(n) or b"{}") | |
| state, qs, enc = _validate(body) | |
| imgs = decode_images(body.get("images")) | |
| budget = image_budget(body) | |
| if imgs and not info.get("images"): | |
| raise ValueError("this server does not read images (the fast CUDA backend is needed)") | |
| except (ValueError, json.JSONDecodeError) as e: | |
| return self._send(422, {"detail": str(e)}) | |
| t = time.perf_counter() | |
| try: | |
| ans, toks, itoks, route = batcher.submit(state, qs, (enc or encoding) == "per_question", images=imgs, | |
| max_pixels=budget if imgs else None) | |
| except (ValueError, KeyError, TypeError, AssertionError) as e: | |
| return self._send(422, {"detail": str(e) or type(e).__name__}) | |
| except TimeoutError as e: | |
| return self._send(503, {"detail": str(e)}) | |
| except Exception as e: # noqa: BLE001 | |
| return self._send(500, {"detail": f"{type(e).__name__}: {e}"}) | |
| usage = {"input_tokens": toks, "output_tokens": 0} | |
| if imgs: | |
| usage["image_tokens"] = itoks | |
| if route is not None: | |
| usage["route"] = route | |
| return self._send(200, {"model": info["model"], "answers": ans, "usage": usage, | |
| "latency_ms": round((time.perf_counter() - t) * 1000, 2)}) | |
| return H | |
| def main(): | |
| ap = argparse.ArgumentParser(description="qev-0.8b System One HTTP server (POST /v1/systemone)") | |
| ap.add_argument("--model", default="labqoat/squad-0.8b", help="local directory or Hugging Face repo id") | |
| ap.add_argument("--host", default="127.0.0.1") | |
| ap.add_argument("--port", type=int, default=8017) | |
| ap.add_argument("--backend", default="auto", choices=["auto", "fast", "transformers"]) | |
| ap.add_argument("--device", default=None) | |
| ap.add_argument("--encoding", default="joint", choices=ENCODINGS, | |
| help="default for requests without \"encoding\": joint (every question behind one copy of the " | |
| "state) or per_question (one row per question; often more coherent answers)") | |
| ap.add_argument("--max-batch", type=int, default=8, | |
| help="most requests answered in one batch (8 measured best on an L40S: ~120 req/s)") | |
| ap.add_argument("--fast-start", action="store_true", | |
| help="fast backend: listen once the common CUDA graphs are captured and capture the rest in the " | |
| "background (requests during that time can be slow); default: capture all before listening") | |
| ap.add_argument("--no-images", action="store_true", | |
| help="do not load the vision tower (requests with \"images\" then get HTTP 422)") | |
| ap.add_argument("--max-pixels", type=int, default=448 * 448, help="images are resized to at most this many pixels") | |
| ap.add_argument("--prefix-cache-mb", type=int, default=2048, | |
| help="fast backend: the cross-request state cache, MB of GPU memory (LRU): a request whose state " | |
| "shares tokens with an earlier one continues from its cached model state; 0: off") | |
| ap.add_argument("--memo", type=int, default=1024, | |
| help="fast backend: whole requests remembered (the same request again: the same answer, no model " | |
| "call); 0: off") | |
| ap.add_argument("--specialists", action="store_true", | |
| help="router + LoRA slots from the model's specialists/ directory (fast CUDA backend)") | |
| ap.add_argument("--verbose", action="store_true", help="log every request") | |
| a = ap.parse_args() | |
| from qev import QEV | |
| t0 = time.perf_counter() | |
| m = QEV.from_pretrained(a.model, device=a.device, backend=a.backend, precapture=False, max_pixels=a.max_pixels, | |
| specialists=a.specialists, prefix_cache_mb=a.prefix_cache_mb, memo=a.memo) | |
| images = False | |
| if m.fast is not None and not a.no_images: | |
| try: | |
| m.fast.enable_images(a.max_pixels) | |
| images = True | |
| except Exception as e: # noqa: BLE001 - no pillow / torchvision / processor config: a text-only server | |
| print(f"qev_server: images off ({type(e).__name__}: {e})", flush=True) | |
| if m.fast is not None: # CUDA graphs for every batch shape, so no live request waits for a capture | |
| print("qev_server: capturing CUDA graphs (about 2 min the first time, faster with a warm kernel cache)", | |
| flush=True) | |
| m.fast.precapture(background=a.fast_start, per_question=a.encoding == "per_question", images=images) | |
| m.decide("warm-up", {"q": {"type": "noul", "instructions": "Is this a warm-up?"}}) | |
| local = a.model if os.path.isdir(a.model) else None | |
| if local is None: | |
| try: | |
| from huggingface_hub import snapshot_download | |
| local = snapshot_download(a.model, allow_patterns=["SHA256SUMS"]) | |
| except Exception: # noqa: BLE001 | |
| local = None | |
| info = {"model": "squad-0.8b", "source": a.model, "backend": m.backend, "device": str(m.device), | |
| "encoding": a.encoding, "images": images, "specialists": m.fast.slots.b.describe() if ( | |
| m.fast is not None and m.fast.slots is not None) else None, "load_s": round(time.perf_counter() - t0, 1), "sha256": _file_hashes(local), | |
| "verbose": a.verbose} | |
| def run(reqs, pq, max_pixels=None): | |
| res = m.decide_batch(reqs, pq, usage=True, max_pixels=max_pixels) | |
| routes = m.last_routes if len(m.last_routes) == len(res) else [None] * len(res) | |
| return [(a_, t_, k_, r_) for (a_, t_), k_, r_ in zip(res, m.last_image_tokens, routes, strict=True)] | |
| batcher = Batcher(run, max_batch=a.max_batch) | |
| key = os.environ.get("QEV_API_KEY") or None | |
| httpd = Server((a.host, a.port), make_handler(batcher, info, a.encoding, key)) | |
| print(f"qev_server: {info['backend']} backend on {info['device']}, ready in {info['load_s']} s; " | |
| f"POST http://{a.host}:{a.port}/v1/systemone" + (" (API key required)" if key else ""), flush=True) | |
| try: | |
| httpd.serve_forever() | |
| except KeyboardInterrupt: | |
| pass | |
| if __name__ == "__main__": | |
| main() | |