Benchmark: Which Flow Format Do Local AI Models Write Best?
Date: 2026-10-12. Kinenix 0.2.0b3 (development branch). Scripts and every generated flow: benchmarks/flow_format/.
Summary
Kinenix flows are written by AI assistants from a requirement. We compared two formats for that file, Kinenix's flow.md and a YAML equivalent, by asking five small local models, from two model families and on two machines, to write the same flow in both formats.
flow.mdwas better for every model of 3B or more, on both machines. For example,qwen2.5-coder:7bparsed 5 of 5flow.mdflows (9.2 of the 11 needed actions on average) against 2 of 5 in YAML, andphi4-miniparsed 9 of 10 against 3 of 10.- Code-trained models write flows much better than general models of the same size:
qwen2.5-coder:3bused 9.0 of the 11 actions,qwen2.5:3b6.2. - YAML broke on syntax, not on understanding: Kinenix's
${...}expressions inside[ ], unquoted:in selectors, and#at the start of a value. flow.mdfailures were silent before this test (a step heading without its action produced an empty flow with no warning). Kinenix now reports them.
Decision: Kinenix keeps flow.md as its only flow format, and drops flow.json.
For a small machine, phi4-mini (MIT license) is the best candidate found so far; qwen2.5-coder:3b scored higher but its license allows research use only (see Models and licenses).
Setup
| Machine | Hardware | Runtime | Models |
|---|---|---|---|
laptop-rtx3050ti | Laptop, Intel Core i5-12500H, 16 GB RAM, NVIDIA RTX 3050 Ti Laptop GPU (4 GB VRAM), Windows 11 | Ollama 0.40.3 (CUDA) | qwen2.5:1.5b, qwen2.5:3b, qwen2.5-coder:7b |
ubuntu-rx550 | Desktop, Intel Core i5-3570 (2012, no AVX2), 7.7 GB RAM, AMD Radeon 540/550 (Lexa, about 4 GB VRAM), Ubuntu 24.04 | Ollama 0.34.2 (Vulkan) | qwen2.5-coder:3b, phi4-mini |
All models are Ollama's default Q4_K_M quantization of the instruct (chat) variant. Settings: temperature 0.7, context 8192 tokens, up to 3000 output tokens. Runs: 10 per format, except 5 per format for qwen2.5-coder:7b, which does not fit in 4 GB of VRAM and took about 115 seconds per flow.
Generation speed depends on the machine and on whether the model fits in GPU memory; accuracy does not. phi4-mini with an 8192-token context needed 3.7 GB and ran 14% on the CPU (ollama ps), so its time per flow is slower than the model itself.
Models and licenses
| Model | Family | Parameters | License |
|---|---|---|---|
qwen2.5:1.5b | Qwen (Alibaba) | 1.5B | Apache 2.0 |
qwen2.5:3b | Qwen (Alibaba) | 3.1B | Qwen Research License (non-commercial) |
qwen2.5-coder:3b | Qwen (Alibaba) | 3.1B | Qwen Research License (non-commercial) |
phi4-mini | Phi (Microsoft) | 3.8B | MIT |
qwen2.5-coder:7b | Qwen (Alibaba) | 7.6B | Apache 2.0 |
Licenses differ by size within one family; check the model card before using a model in production.
Task
The flow is bot_fx_rate: open the Bank of Thailand exchange rate page, pick currencies and a date range in a date picker, read one table per currency, write a CSV, and email it. It needs 11 different actions, two loops, and retries.
Each prompt contained, in this order:
- The requirement, including the selectors to use and the config keys.
- The list of Kinenix actions and their parameters (
kinenix actions). - The same rules (use only listed actions,
output_var, loops, error handling). - The format: a short description and the same example flow written in that format.
Only part 4 differed between the two formats. The YAML format puts action parameters under with: (as in GitHub Actions), because some parameter names (name, condition) would otherwise clash with step keys.
Scoring
| Measure | Meaning |
|---|---|
| Parsed | The file was read without a syntax error and produced at least one step |
| Clean | Parsed, and kinenix validate (plus, for flow.md, the ignored-line check) reported no problem |
| Loop with sub-steps | At least one logic.loop has its sub-steps attached |
| Actions | How many of the 11 needed actions appear (average over all runs) |
These measure whether the file is usable as a starting point, not whether the flow would succeed against the live site. The saved flows can be scored again with a newer Kinenix (--rescore); the table below was rescored with the checks added after this test (step headings without an action, flows without steps) and did not change.
Equivalence check
Before asking any model, bot_fx_rate was written by hand in YAML and read with a 40-line prototype reader. Both files produced the same 22 steps, and the YAML version ran against the live site: 42 executed steps, 110 rows for September 2026, 13.5 seconds. Both formats can express the flow; the question is which one models write correctly.
Results
| Machine | Model | Format | Runs | Parsed | Clean | Loop with sub-steps | Actions (of 11) | Seconds per flow |
|---|---|---|---|---|---|---|---|---|
| laptop | qwen2.5 1.5B | flow.md | 10 | 5 | 0 | 0 | 3.2 | 17 |
| laptop | qwen2.5 1.5B | YAML | 10 | 7 | 2 | 1 | 2.4 | 14 |
| laptop | qwen2.5 3B | flow.md | 10 | 10 | 1 | 2 | 6.2 | 23 |
| laptop | qwen2.5 3B | YAML | 10 | 6 | 3 | 4 | 5.3 | 21 |
| ubuntu | qwen2.5-coder 3B | flow.md | 10 | 10 | 2 | 9 | 9.0 | 63 |
| ubuntu | qwen2.5-coder 3B | YAML | 10 | 2 | 2 | 2 | 1.9 | 57 |
| ubuntu | phi4-mini (3.8B) | flow.md | 10 | 9 | 4 | 9 | 7.3 | 110 |
| ubuntu | phi4-mini (3.8B) | YAML | 10 | 3 | 2 | 3 | 2.5 | 85 |
| laptop | qwen2.5-coder 7B | flow.md | 5 | 5 | 2 | 4 | 9.2 | 117 |
| laptop | qwen2.5-coder 7B | YAML | 5 | 2 | 2 | 2 | 3.8 | 112 |
The better format for each model and measure is in bold. Raw flows and per-run scores: benchmarks/flow_format/results/<machine>/<model>/.
What went wrong
flow.md
- Step heading without its action (1.5B, 5 of 10 runs):
### 1. Open ${config_url}followed by a- **web.open**bullet. The parser found no steps and, at the time, said nothing. - Sub-steps not indented as sub-steps (3B, most runs): bullets under
- **Sub-steps:**written as parameters or plain text. - Parameters an action does not accept (7B): for example
timeoutonweb.type.kinenix validatenames each one and suggests the closest valid name.
YAML
${...}inside a list:attachments: [${config.output_path}]is a YAML syntax error, because{starts a mapping inside[ ](7B, 2 of 5 runs).- Unquoted
:in a value:selector: button: Accept recommended cookies. - Indentation of nested lists, and error-handling keys placed under
with:. - When written by hand,
selector: #dropdownCurrencysilently became an empty value, because#starts a comment. Selectors have to be quoted.
Every model also invented things the requirement did not say (URLs, config values inside variables, subflows that do not exist). That is a model-size problem, not a format problem, and it shrank with the larger model.
Conclusions
- From 3B up,
flow.mdis the better format for AI authoring, for both model families and on both machines. YAML's advantage on the smallest model came fromflow.mdfailing silently, which is now fixed. - Kinenix's
${...}syntax and YAML conflict. Moving to YAML would also mean changing the expression syntax. - Clear errors matter more than the format. The 7B model's
flow.mdproblems were all of a kind thatkinenix validatereports with a fix, so an assistant can correct them in one more round. - Code-trained models matter more than size. At the same 3B size, the coder model used 9.0 of the 11 actions and attached loop sub-steps in 9 of 10 runs; the general model used 6.2 and did so in 2 of 10.
qwen2.5-coder:3bcame close toqwen2.5-coder:7b(9.2). - Model size: 1.5B is too small to write flows in either format; a code-trained 3-4B model is usable as a first draft that
kinenix validatethen corrects; 7B is better when the machine allows it. - License: the best small model in this test,
qwen2.5-coder:3b, is licensed for research only.phi4-mini(MIT) had the most clean flows (4 of 10) and is the first candidate for a default model on small machines.
Changes made in Kinenix
flow.mdis the only flow file;flow.jsonis no longer written or read (kinenix compileprints the compiled form for inspection,kinenix export-mdconverts old JSON flows).- A step heading without an action, and a flow without steps, are reported by
kinenix validateandkinenix run. - The sub-step indentation message shows the correct form.
- The
AGENTS.mdof every new project lists the three most common mistakes from this test.
Limitations
- One task, two model families, and small samples (5 to 10 runs per format). The results show a direction, not exact rates.
- The two machines ran different Ollama versions (0.40.3 and 0.34.2); generation speed is not comparable across machines.
- Scores check the file, not a successful run against the site.
- The prompt was written by the Kinenix authors, who know
flow.mdwell; a different prompt could change the numbers.
Reproduce
cd benchmarks/flow_format
pip install requests pyyaml # only for this benchmark
ollama pull qwen2.5-coder:7b
kinenix actions > actions.txt
python experiment.py qwen2.5-coder:7b 5 --machine my-pc # writes results/my-pc/<model>/runN.md, runN.yaml, scores.jsonl
python experiment.py --rescore # score every saved flow again and print the table
Next benchmarks
Planned, to cover what this one did not:
| Benchmark | Question |
|---|---|
| More tasks | Do the results hold for hello, rpachallenge, and a long real requirement (insurance quotes with subflows)? |
| Run success | Does the generated flow actually run, against the example sites and the test sites listed in roadmap.md? |
| Repair rounds | Given the kinenix validate output, how many rounds does each model need to reach a clean flow? |
| More models | qwen3:4b, Gemma, Granite (IBM), Llama, Typhoon for Thai requirements, and larger models on a GPU machine; Apache 2.0 and MIT models first |
| Thai requirements | The same tasks with the requirement written in Thai |
| Error explanation | For the Phase 2 run records: does a local model explain a recorded failure correctly the next morning? |