Nathan Lambert
Course on RLHF and post-training. Chapter 13.
Who is the president today?
Move all the arXiv papers in my downloads folder to my ~/research/ directory with names indicating the date of the paper.
The first fails on the knowledge cutoff – but it is one search query away.
The second, the weights cannot even attempt: it requires acting on the world, not describing it.
Tool use is what closes both gaps. It started by addressing structural limitations in LLMs and grew into the central way to push performance. Tool use is a trained skill – everything in this course (SFT, preference tuning, RL) applies to it.
LLMs are now systems and this lecture is about the transition from static weights to today.
Tool use started as “call a calculator.” It was implemented to help with hard multiple-choice questions and code execution. It is now used in…

Chapter 13 covers the mechanics of tool use. The last third of today goes beyond the book content with a bit of recent work on tool use and RL at scale.
Are you following the whole course, or did you come for just this video (search, algo, etc.)?
From most general to most specific – these share training characteristics, but are important to get right:
Task: Print \pi to 50 digits – without reciting it from memory (parameters) and risking hallucination.
The model writes the program; the interpreter provides the answer. Tools let models remove some of the stochastic elements of “stochastic parrots.”
... the model is mid-generation, sampling tokens ...
<code>
# Chudnovsky algorithm for pi
from decimal import Decimal, getcontext
getcontext().prec = 60
C = 426880 * Decimal(10005).sqrt()
K, M, X, L, S = 6, 1, 1, 13591409, Decimal(13591409)
for i in range(1, 100):
M = M * (K**3 - 16*K) // i**3
K += 12; L += 545140134
X *= -262537412640768000
S += Decimal(M * L) / X
print(str(C / S)[:52])
</code>
<output>
3.14159265358979323846264338327950288419716939937510
</output>
... the output is now in context; generation continues ...
Years on the left are when the work first appeared (arXiv); citation years in parentheses are the official publication date, so some lag by a year.
“…reasoning traces help the model induce, track, and update action plans as well as handle exceptions, while actions allow it to interface with and gather additional information from external sources such as knowledge bases or environments.”
Before ReAct, reasoning (chain-of-thought) and acting (tool calls) were separate literatures. Interleaving them in one token stream is the pattern every modern agent still uses – o3’s tool-calls-inside-thinking is this idea, scaled up with RL.

Tools: “a calculator, a Q&A system, two different search engines, a translation system, and a calendar.”
Via a self-labelling/synthetic data mechanism:
No human tool-use demonstrations required – an early instance of synthetic-data flywheels.

The eval ladder mirrors the capability ladder we’ve seen over time:
format \rightarrow selection \rightarrow consistency \rightarrow full tasks.

Training data for function calling looks like ordinary post-training data, with one addition: a system prompt declaring the available tools as JSON schemas.
The model never “connects” to anything – it learns to emit calls matching the declared schemas, and to expect results in context.
Open models must generalize to arbitrary tools users declare off the shelf.
<system>
You are a function-calling AI model. You are
provided function signatures within <functions>
XML tags. You may call one or more functions.
</system>
<functions>
[{
"name": "search_movies",
"description": "Search movies by title.",
"parameters": {
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"]
}
},
{ "name": "get_showtimes", ... },
{ "name": "get_movie_details", ... }]
</functions>
<user> ... </user>
messages = [...]
while True:
resp = model(messages, tools=tools)
if not resp.tool_calls:
return resp.text
messages.append(resp.message)
for call in resp.tool_calls:
result = execute_tool(
call.name, call.args)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": result})
The model’s only power is emitting tokens; the orchestrator parses them, executes the tools, and appends results to the context. Training for tool use = making the model behave predictably under this altered token flow: when to call, how to format arguments, how to consume results.
Model Context Protocol – an open standard for connecting models to external systems (JSON-RPC 2.0 underneath).
Server primitives:
Architecture: servers wrap a capability \rightarrow clients aggregate servers \rightarrow hosts (Claude, ChatGPT apps) provide the interface. Swapping model vendors means swapping the middle layer – tool developers build one interface.
{
"name": "get_weather",
"description": "Get current weather",
"inputSchema": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City or coordinates"
}
},
"required": ["location"]
}
}
MCP standardized the tool side. The harness (or agent scaffold) is everything wrapped around the weights on the model side:
(growing in complexity)
Claude Code, Codex CLI, and OpenHands are all popular harnesses – the same models behave very differently inside different ones.
Benchmark scores are model × harness scores.
tool_calls vs. Anthropic’s tool_use blocks vs. Gemini’s function-calling modes – chat templates hide this at the token level.
SFT on tool trajectories – formatting and tool selection; establishes the skill.
Preference tuning still works, but is less popular today.
RL with environment feedback – where the action is in frontier model training.
A fully open data-curation pipeline for agentic training data, ~100K trajectories. https://arxiv.org/abs/2606.24855



Most of the effort goes into stability during scaling, rather than speed or learning efficiency:
Kimi K3 (July 2026) spends one sentence on its RL algorithm (“follows the algorithm in Kimi K2.5”) – and about seven pages on environments and sandboxes: 51,219,741 sandboxes created during training, microVMs that checkpoint in 133ms, and mock Gmail/Notion/Slack “living environments” where one rollout can span thousands of tool calls. Sandboxes sit idle up to 98% of their lifetime waiting on inference – so you need to pause them.

Open models train across multiple harnesses so deployment is smooth.
Polar (NVIDIA): same model, same GRPO, same tasks – +22.6 points on SWE-Bench Verified training through the Codex harness (3.8 → 26.4: RL teaching an unfamiliar harness), +0.6 through Qwen Code (already fluent: 34.6 → 35.2).
Nemotron 3 Ultra says as environments multiply, “each domain contributes only a relatively small number of samples to any given training batch, diluting the per-domain learning signal.”
A common answer is to train domain experts with RL, then merge them via multi-teacher on-policy distillation (the MOPD from Conversation 1).
Some example MOPD gains from Nemotron 3 Ultra (NVIDIA, 2026):
| Benchmark | SFT | RLVR | MOPD | Teacher |
|---|---|---|---|---|
| TauBench Telecom | 55.7 | 82.7 | 92.9 | 94.0 |
| Terminal-Bench 2.0 | 34.5 | 44.5 | 54.0 | 50.0 |
| BrowseComp | 14.3 | 31.0 | 44.4 | 51.0 |
| SWE-Bench Verified | 63.5 | 65.8 | 71.7 | 72.5 |
GLM-5’s slides-RL policy discovered overflow: hidden to make an overflowing slide measure 16:9, and flex-padding to stretch short ones – the fix was patching the renderer, not the reward.
Nemotron physically deletes future git commits and firewalls GitHub so SWE agents can’t read the gold patch; Kimi K3 ships a kernel-exploit detector and public/hidden verifier pairs.
(of course, the OpenAI hack of HuggingFace 😳)
