Skip to content

Make 'Propose a Job' and 'Launch a Job' Different Tools

2026-09-13

"Propose a training job" and "launch a training job on 64 GPUs" are different operations. So are "draft a cleanup of old checkpoints" and "delete them." An agent in a research lab will get tools with real costs, and the interface should make the difference between suggesting and doing impossible to blur.

OpenAI's function calling guide describes the flow: the model returns a function call with a name and arguments, your application executes code with that input, and you send the result back. The model never runs anything itself. What a call is allowed to do is decided entirely by your code.

Use that. Give the agent two tools:

  • propose_job(config, gpus, hours, reason) validates the arguments, stores the proposal and returns a proposal ID and a hash of the exact arguments;
  • launch_job(proposal_id) launches only if a human approved that ID, and only if the stored hash still matches.

The model can assemble the proposal, estimate its cost (GPUs × hours × price per GPU-hour, shown so a reviewer can check it) and explain why. It cannot grant itself the approval.

The check, as three tests against a fake scheduler:

  1. launch_job on an unapproved proposal is refused, and nothing reaches the scheduler.
  2. A proposal edited after approval (64 GPUs becomes 128) no longer matches its hash and is refused.
  3. Calling launch_job twice with the same approved ID, as a retry would, starts one job, not two.

Inspect the recorded state transitions (proposed, approved, launched), not the agent's final chat message. The book's approval chapter builds an exact-approval gate like this one from scratch; the chapter after it, on ambiguous orders, covers the retry case.

OpenAI documentation.