A fine-tuned
Qwen2.5-Coder-7B-Instruct model specialized for
Rhino3D Python scripting — generating correct
rhinoscriptsyntax and
RhinoCommon code from natural language instructions.
This is the
fused model (LoRA weights merged into base). For the standalone LoRA adapter, see
rhino-coder-7b-lora.
The base Qwen2.5-Coder-7B is a strong general code model, but it doesn't know Rhino's APIs. On 10 held-out Rhino scripting tasks:
1# BASE MODEL — wrong (averages control points, not area centroid)
2def find_centroid(curve_id):
3 points = rs.CurvePoints(curve_id)
4 centroid = [0, 0, 0]
5 for point in points:
6 centroid[0] += point[0]
7 centroid[1] += point[1]
8 centroid[2] += point[2]
9 centroid[0] /= len(points)
10 return centroid
11
12# FINE-TUNED — correct, concise
13crv = rs.GetObject('Select closed curve', 4)
14if crv and rs.IsCurveClosed(crv):
15 centroid = rs.CurveAreaCentroid(crv)
16 if centroid:
17 rs.AddPoint(centroid[0])
1from mlx_lm import load, generate
2
3model, tokenizer = load("quocvibui/rhino-coder-7b")
4
5messages = [
6 {"role": "system", "content": "You are an expert Rhino3D Python programmer. Write clean, working scripts using rhinoscriptsyntax and RhinoCommon. Include all necessary imports. Only output code, no explanations unless asked."},
7 {"role": "user", "content": "Create a 10x10 grid of spheres with radius 0.5"},
8]
9
10prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
11output = generate(model, tokenizer, prompt=prompt, max_tokens=1024)
12print(output)
1import requests
2
3response = requests.post("http://localhost:8080/v1/chat/completions", json={
4 "model": "default",
5 "messages": [
6 {"role": "system", "content": "You are an expert Rhino3D Python programmer. Write clean, working scripts using rhinoscriptsyntax and RhinoCommon. Include all necessary imports. Only output code, no explanations unless asked."},
7 {"role": "user", "content": "Draw a spiral staircase with 20 steps"}
8 ],
9 "max_tokens": 1024,
10 "temperature": 0.1
11})
12print(response.json()["choices"][0]["message"]["content"])
LoRA (Low-Rank Adaptation) fine-tuning via
MLX-LM, then fused into the base model.
5,060 instruction-code pairs for Rhino3D Python scripting (90/10 train/val split):
Data was cleaned aggressively — 10,252 entries excluded from 12,814 total raw entries. Filters removed trivial getters, boilerplate, placeholder code, C#-only types, and duplicates.
1{
2 "messages": [
3 {"role": "system", "content": "You are an expert Rhino3D Python programmer..."},
4 {"role": "user", "content": "<instruction>"},
5 {"role": "assistant", "content": "<python code>"}
6 ]
7}