Files
xgrammar-gemma4-test/README.md
T
wanhae.lee 9484167719 init
2026-07-05 00:33:50 +09:00

66 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# gemma-4 × xgrammar constrained decoding test
A collection of scripts that verify the modified xgrammar (`~/git/xgrammar`,
`style="gemma"` / `gemma_4` builtin structural tag) works correctly for tool
calling with `google/gemma-4-E2B-it`, and generate a report comparing
constrained vs unconstrained behavior.
## Usage (Makefile)
```bash
make setup # create uv venv + install deps + local xgrammar editable install (once)
make run # run all scenarios → generate report.md + print output ← for PR reports
make smoke # single-tool smoke test (greedy, fast)
make xgrammar # reinstall after modifying ~/git/xgrammar
make clean # remove venv/report
```
Options: `make run SAMPLES=8`, `XGRAMMAR_DIR=/path/to/xgrammar make setup`
The output of `make run`, **`report.md`**, is the artifact to show reviewers —
it contains the model/sampling configuration, a per-scenario table of
constrained vs unconstrained metrics, and the raw text of failure cases.
## Scenarios (`test_gemma4_scenarios.py`)
| | Setup | What it targets |
|---|---|---|
| **A. complex-schema** | Nested objects + array of objects + enum + boolean schema, titles containing quotes | Argument serialization mistakes |
| **B. multiturn-thinking** | Two prior rounds of tool call/response already in context and thinking is required, the next call takes a number-typed argument | Skipped/unterminated thinking, type errors |
| **C. adversarial-payload** | A string argument whose body must contain JSON/braces/an error log verbatim, an out-of-enum word ("critical") lure, two similarly named distractor tools, temp 1.5 + top_p 1.0 | String quoting collapse, enum violations |
Metrics (pass/fail per sample):
| metric | meaning |
|---|---|
| `well_formed` | Every `<\|tool_call>call:name{...}<tool_call\|>` block is complete and parseable |
| `valid_name` | Only calls tools that actually exist |
| `schema_valid` | Parsed arguments pass the JSON schema (parsed via a port of the sglang parser) |
| `stops_at_boundary` | Generation doesn't run past `<tool_call\|>` into `<\|tool_response>` |
| `thought_ok` | (thinking scenario) Opens the thought channel and closes it before the tool call |
## Key findings
- gemma-4-E2B-it's format training is very robust, so the tool call argument
format itself rarely breaks even at temp 1.5 + top_p 1.0.
- Per the [Gemma 4 prompt-formatting spec](https://ai.google.dev/gemma/docs/core/prompt-formatting-gemma4),
the model is only responsible for generating up to `<tool_call\|>`;
`<\|tool_response>` is appended by the application with the real tool
result, and is registered as an **additional stop sequence** purely as a
backstop. This harness has no such stop configured, so unconstrained runs
keep generating past that boundary into engine-owned territory
(`stops_at_boundary` failures); required-mode constrained decoding ends the
call cleanly at an accept state instead.
- Unconstrained decoding also **omits the thought channel entirely** in
situations where thinking should be enabled; constrained decoding with
`reasoning=True` enforces it (an empty thought `<\|channel>thought\n<channel\|>`
remains legal, matching the spec's no-thinking form).
## Files
- `test_gemma4_xgrammar.py` — basic smoke test (greedy, single tool, alignment check)
- `test_gemma4_scenarios.py` — scenario runner + report.md generator.
`--scenario a|b|c|all --samples N --temperature T --model ID --report PATH`
- `gemma_parser.py` — a pure port of sglang's `Gemma4Detector` parsing logic (for output verification)
- `Makefile` / `report.md`