Image-Text-to-Text
MLX
Safetensors
English
qwen3_5
apple-silicon
mac
quantized
4-bit precision
arex-2
qwen3.8
vision
agent
reasoning
tool-use
deep-research
long-context
conversational
Instructions to use mlx-community/AREX-2-4bit with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use mlx-community/AREX-2-4bit with MLX:
# Make sure mlx-vlm is installed # pip install --upgrade mlx-vlm from mlx_vlm import load, generate from mlx_vlm.prompt_utils import apply_chat_template from mlx_vlm.utils import load_config # Load the model model, processor = load("mlx-community/AREX-2-4bit") config = load_config("mlx-community/AREX-2-4bit") # Prepare input image = ["http://images.cocodataset.org/val2017/000000039769.jpg"] prompt = "Describe this image." # Apply chat template formatted_prompt = apply_chat_template( processor, config, prompt, num_images=1 ) # Generate output output = generate(model, processor, formatted_prompt, image) print(output) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Pi
How to use mlx-community/AREX-2-4bit with Pi:
Start the MLX server
# Install MLX LM: uv tool install mlx-lm # Start a local OpenAI-compatible server: mlx_lm.server --model "mlx-community/AREX-2-4bit"
Configure the model in Pi
# Install Pi: npm install -g @earendil-works/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "mlx-lm": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "mlx-community/AREX-2-4bit" } ] } } }Run Pi
# Start Pi in your project directory: pi
- Hermes Agent
How to use mlx-community/AREX-2-4bit with Hermes Agent:
Start the MLX server
# Install MLX LM: uv tool install mlx-lm # Start a local OpenAI-compatible server: mlx_lm.server --model "mlx-community/AREX-2-4bit"
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 mlx-community/AREX-2-4bit
Run Hermes
hermes
- Atomic Chat
- OpenClaw
How to use mlx-community/AREX-2-4bit with OpenClaw:
Start the MLX server
# Install MLX LM: uv tool install mlx-lm # Start a local OpenAI-compatible server: mlx_lm.server --model "mlx-community/AREX-2-4bit"
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 "mlx-community/AREX-2-4bit" \ --custom-provider-id mlx-lm \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
File size: 7,445 Bytes
9d75279 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | """Extra checks for one AREX-2 MLX build: long-prompt recall and a multi-step tool loop.
Usage:
venv/bin/python extra_tests.py long builds/AREX-2-5bit [--tokens 32000]
venv/bin/python extra_tests.py agent builds/AREX-2-5bit [--label NAME]
Results go to results/long-<name>.json and results/agent-<name>.json.
"""
import json
import random
import re
import sys
import time
from pathlib import Path
import mlx.core as mx
from mlx_vlm import generate, load
ROOT = Path(__file__).parent
RES = ROOT / "results"
SAMPLING = dict(temperature=1.0, top_p=0.95, top_k=20)
def arg(flag, default=None):
return sys.argv[sys.argv.index(flag) + 1] if flag in sys.argv else default
def long_prompt(build, name, target):
"""Three facts planted at 15%, 50% and 85% of a long filler prompt; the model must return all three."""
model, processor = load(str(build))
tok = processor.tokenizer
random.seed(21)
words = "ledger harbor window copper meadow signal paper orbit timber candle river anchor".split()
para = lambda: " ".join(random.choice(words) for _ in range(90)) + "."
n = max(10, target // 101) # one filler paragraph is about 101 tokens
paras = [para() for _ in range(n)]
facts = {"Lisbon": "7341", "Osaka": "2086", "Tulsa": "9517"}
for (city, code), frac in zip(facts.items(), (0.15, 0.50, 0.85)):
paras.insert(int(n * frac), f"Note for staff: the storeroom access code for the {city} office is {code}.")
q = ("\n\nList the storeroom access codes for the Lisbon, Osaka and Tulsa offices, "
"in that order, as three numbers separated by commas. Reply with the numbers only.")
prompt = tok.apply_chat_template([{"role": "user", "content": "\n\n".join(paras) + q}],
tokenize=False, add_generation_prompt=True, enable_thinking=False)
t0 = time.time()
r = generate(model, processor, prompt, max_tokens=40, temperature=0.0)
out = {"build": name, "prompt_tokens": r.prompt_tokens, "prompt_tps": round(r.prompt_tps, 1),
"seconds": round(time.time() - t0, 1), "peak_memory_gb": round(mx.get_peak_memory() / 1e9, 1),
"found": {c: (code in r.text) for c, code in facts.items()}, "output": r.text[:200]}
out["pass"] = all(out["found"].values())
(RES / f"long-{name}-{target}.json").write_text(json.dumps(out, indent=2))
print(f"{'PASS' if out['pass'] else 'FAIL'} long prompt {name}: {out['prompt_tokens']} tokens, "
f"{out['prompt_tps']} tok/s, {out['seconds']}s, peak {out['peak_memory_gb']} GB, found {out['found']}", flush=True)
TOOLS = [
{"type": "function", "function": {"name": "find_customer", "description": "Look up a customer by full name.",
"parameters": {"type": "object", "properties": {"name": {"type": "string"}}, "required": ["name"]}}},
{"type": "function", "function": {"name": "list_orders", "description": "List a customer's orders with totals.",
"parameters": {"type": "object", "properties": {"customer_id": {"type": "string"}}, "required": ["customer_id"]}}},
{"type": "function", "function": {"name": "get_order", "description": "Get one order's items and tracking number.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}}, "required": ["order_id"]}}},
{"type": "function", "function": {"name": "track_shipment", "description": "Get shipment status by tracking number.",
"parameters": {"type": "object", "properties": {"tracking_number": {"type": "string"}}, "required": ["tracking_number"]}}},
]
ORDERS = [{"order_id": "A-1009", "date": "2026-08-02", "total": 129.50},
{"order_id": "A-1042", "date": "2026-09-17", "total": 342.00},
{"order_id": "A-1077", "date": "2026-09-29", "total": 58.25}]
TRACKING = {"A-1009": "TRK-70312", "A-1042": "TRK-88213", "A-1077": "TRK-90455"}
def run_tool(name, a):
if name == "find_customer":
return {"customer_id": "C-4471"} if "whitfield" in str(a.get("name", "")).lower() else {"error": "no such customer"}
if name == "list_orders":
return {"orders": ORDERS} if a.get("customer_id") == "C-4471" else {"error": "unknown customer_id"}
if name == "get_order":
oid = a.get("order_id")
return {"order_id": oid, "items": 3, "tracking_number": TRACKING[oid]} if oid in TRACKING else {"error": "unknown order_id"}
if name == "track_shipment":
t = a.get("tracking_number")
if t == "TRK-88213":
return {"status": "delayed", "location": "Memphis", "eta": "2026-10-09"}
return {"status": "delivered"} if t in TRACKING.values() else {"error": "unknown tracking_number"}
return {"error": f"unknown tool {name}"}
def agent(build, name):
"""Four chained tool calls plus a sum. Pass needs the right shipment tracked and all three facts in the answer."""
model, processor = load(str(build))
tok = processor.tokenizer
runs = []
for seed in (31, 32, 33):
msgs = [{"role": "user", "content": "Dana Whitfield wants to know where her most expensive order is and "
"when it will arrive. Also tell her the total she has spent across all her orders. Use the tools."}]
calls, final, t0, toks = [], "", time.time(), 0
for turn in range(8):
prompt = tok.apply_chat_template(msgs, tools=TOOLS, tokenize=False, add_generation_prompt=True)
r = generate(model, processor, prompt, max_tokens=1500, seed=seed + turn, **SAMPLING)
toks += r.generation_tokens
text = r.text.split("</think>")[-1]
found = re.findall(r"<tool_call>\s*<function=([\w.-]+)>(.*?)</function>\s*</tool_call>", text, re.S)
if not found:
final = text.strip()
break
tcs = []
for fn, body in found:
a = {k: v.strip() for k, v in re.findall(r"<parameter=([\w.-]+)>(.*?)</parameter>", body, re.S)}
calls.append((fn, a))
tcs.append({"type": "function", "function": {"name": fn, "arguments": a}})
msgs.append({"role": "assistant", "content": text.split("<tool_call>")[0].strip(), "tool_calls": tcs})
for tc in tcs:
msgs.append({"role": "tool", "content": json.dumps(run_tool(tc["function"]["name"], tc["function"]["arguments"]))})
low = final.lower()
ok = (("track_shipment", {"tracking_number": "TRK-88213"}) in calls and "memphis" in low and "529.75" in final
and any(d in low for d in ("2026-10-09", "october 9", "oct 9", "oct. 9", "9 october", "10/09", "10/9")))
runs.append({"seed": seed, "pass": ok, "tool_calls": [c[0] for c in calls], "turns": turn + 1, "tokens": toks,
"seconds": round(time.time() - t0, 1), "final": final[-500:]})
print(f"{'PASS' if ok else 'FAIL'} agent {name} seed {seed}: {len(calls)} calls, {toks} tok, {time.time() - t0:.0f}s", flush=True)
out = {"build": name, "passed": sum(x["pass"] for x in runs), "runs": runs}
(RES / f"agent-{name}.json").write_text(json.dumps(out, indent=2))
print(f"agent {name}: {out['passed']} of {len(runs)} runs passed", flush=True)
if __name__ == "__main__":
mode, build = sys.argv[1], Path(sys.argv[2])
name = arg("--label", build.name)
RES.mkdir(exist_ok=True)
if mode == "long":
long_prompt(build, name, int(arg("--tokens", "32000")))
else:
agent(build, name)
|