Skip to main content
One-shot rewrites with token-efficient reasoning: select public tool-calling conversations, Beam rewrites each in one shot with a thought before every assistant turn, verify and audit and assemble, train.jsonl, fine-tune Gemma 4 with TRL, evaluate before and after. This recipe is the left half; the TRL fine-tuning recipe in this cookbook is the right half.

What you’ll build

Beam is a strong reasoning model, and that makes it a strong teacher. The thoughts it writes can be distilled into a much smaller model, and a student that has learned to think briefly and to the point before acting spends far fewer tokens than one left to think on its own. The recipe applies Beam to existing tool-calling datasets: Beam rewrites each conversation with a short thought before every assistant turn and changes nothing else. A thought is about 350 characters on average. What Beam adds is judgement in context. The teacher sees the whole conversation at once, so each thought is written with the later turns in sight: it names the function it is about to call, justifies each argument, and says why a result settles the question or why another call is needed. One conversation before and after the teacher: the user turn, two tool calls, two results and the reply are unchanged, and a short thought appears above each assistant turn. A real conversation from the first run. The reply is verified turn by turn: every assistant turn needs a thought and every tool call has to come back verbatim, so the teacher can change nothing but the thoughts.

What you’ll learn

  • Whole conversations, not single turns. A thought that cannot see a later result cannot justify the call that uses it, so Beam writes every thought in one pass, and each tool call must come back verbatim.
  • Two rules shape the behaviour. ToolACE conversations must act, not ask: a text reply with no tool result to draw on drops the conversation. Nemotron conversations must look up, then act: a call argument has to come from an earlier result. A good tool-calling assistant acts when it has what it needs, asks only when it must, and uses what it just learned.
  • The audit catches cheating thoughts. A value quoted from the next tool result, or a mention of “the example” or “the rewrite”, drops the whole conversation.
Two selection rules as two funnels: Nemotron from 52,828 rows in the pool to 2,796 kept, ToolACE from 11,300 conversations to 1,145 kept. The look-up-then-act rule rejects more Nemotron rows than every other test combined, and the act-don’t-ask rule is the most consequential line on the ToolACE side: what remains is the part of ToolACE that acts.

What you need

  • A Reflection API key in a .env file in this folder, as REFLECTION_API_KEY=<your key>; the cookbook’s .env.example lists the variables, and the other two default to the API and Beam.
  • A Linux machine with Python 3.12, 16 GB of RAM and 3 GB of disk, no GPU. requirements.txt pins the dependencies and config.py pins the two public dataset revisions.
Teacher tokens per conversation: ToolACE about 1,500 prompt and 1,500 completion tokens, Nemotron about 6,200 and 10,500. The recipe skips the 1,302 conversations without a call that our run sent, so a full run sends about 1,635 ToolACE conversations and about 55M tokens in total; at 32 concurrent requests (WORKERS=32 bash run.sh; the default is 16) the teacher stage takes about 3 hours.

Run it

Try it in two minutes

run.sh runs the six stages into work/, keeping 20 conversations of each source spread evenly over the selection. One line per stage tells you it worked:
<details> <summary>The full output of the first run</summary>
The audit summaries and the assemble and mix statistics follow as JSON; assemble kept 12 of the 20 ToolACE conversations (8 replied in text without a result to draw on) and 19 of the 20 Nemotron ones (one lost a turn to the audit), and mix wrote 31 conversations with a mean thought of 342 characters. A progress bar runs during the teacher stage. ok_turns counts assistant turns that received an accepted thought; bad counts conversations that failed every attempt. Those are retried the next time you run the same command, and completed conversations are matched to their rows by id, so a changed LIMIT or selection cannot mix thoughts up. </details>

Build the full set

The same six stages without LIMIT, about 3 hours with WORKERS=32 (the default is 16). The teacher stage appends to its output and resumes after an interruption, so after an outage you run the same command again. Its thought style is one sentence of the prompt in teacher.py:
Write the thought the way a careful engineer thinks before acting: enough to justify the decision and each parameter value, and nothing that does not change the decision.

Check the data

Five audit checks and the thoughts they dropped in our ToolACE run: future leak 2, task reference 15, tool markup or code fence 0, too short 1, mostly non-ASCII 1. The future-leak check matters more than it sounds: the teacher sees results the student will not have seen when it writes its own thought, and a thought that leaks one teaches the student to invent results. A conversation is kept only when every assistant turn has an accepted thought.
<details> <summary>The remaining smoke-test lines</summary>
The test builds small tool-calling conversations and the replies a teacher gives for them, then runs every stage after the teacher on them. With REFLECTION_API_KEY set it also sends one conversation to the teacher and checks that both assistant turns received an accepted thought. </details>

Common fixes

COMMON_FIXES.md lists the symptoms we hit, their causes and the fix for each: a missing API key, dropped requests in the teacher stage, a slow teacher stage, a failed pool stream, a failed ToolACE download, and fewer rows than expected after assemble.

Next steps

  • Fine-tune on work/train.jsonl. The TRL fine-tuning recipe in this cookbook trains Gemma 4 on this file and evaluates before and after.
  • Use your own conversations. Write them in the ToolACE row format or in OpenAI chat format and convert them with nemotron.to_toolace_row, then run enrich, audit, assemble and mix unchanged. To draw more data, raise the sample sizes in config.py and keep the audit.
  • Change the thought style with --thought-style verbose or concise: verbose matched the recipe’s accuracy at 25 to 30% more output tokens, concise saved another 25% of tokens but cost the 12B five points.
  • Related reading. The ToolACE paper describes how its conversations and APIs were generated; the Nemotron-SFT-Agentic-v2 card describes the customer-service trajectories; BFCL is the benchmark the SFT recipe reports.
Last modified on October 20, 2026