SpyBara
Go Premium

Documentation 2026-10-18 23:00 UTC to 2026-10-19 23:00 UTC

8 files changed +11 −355. View all changes and history on the product overview
2026
Sat 31 23:01 Fri 30 23:59 Thu 29 23:59 Wed 28 23:00 Tue 27 23:58 Mon 26 23:58 Sat 24 23:02 Fri 23 23:58 Thu 22 22:59 Wed 21 23:02 Tue 20 23:02 Mon 19 23:00 Sun 18 23:00 Sat 17 22:57 Fri 16 23:02 Thu 15 23:00 Wed 14 23:59 Tue 13 23:00 Sun 11 23:59 Sat 10 23:58 Fri 9 22:57 Thu 8 23:01 Wed 7 23:57 Tue 6 22:58 Mon 5 22:59 Sun 4 22:58 Fri 2 23:58 Thu 1 22:59

guides/agents-api/environments/providers/runloop.md +0 −29 deleted

File Deleted View Diff

1# Runloop

2 

3> For the complete documentation index, see [llms.txt](/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.

4 

5See the [application-managed example](https://github.com/openai/openai-cookbook/tree/main/examples/agents_api/sandboxes/runloop/application_managed) in the OpenAI Cookbook.

6 

7This guide uses **application-managed** provisioning: your application starts the Devbox, connects its executor, and shuts it down when finished. See [Sandbox lifecycle](https://developers.openai.com/api/docs/guides/agents-api/environments/lifecycle) for the lifecycle behavior.

8 

9## Before you begin

10 

11Use the Runloop SDK or API to manage a Devbox, and HTTP requests to manage Agents API sessions.

12 

13Set `RUNLOOP_API_KEY` and use `OPENAI_API_KEY` for application requests. Set `OPENAI_EXECUTOR_API_KEY` to an [environment key](https://developers.openai.com/api/docs/guides/agents-api/environments/self-hosted#authentication), and pass only that key into the Devbox as `CODEX_API_KEY`.

14 

15## Application-managed

16 

171. [Create a self-hosted session](https://developers.openai.com/api/docs/guides/agents-api/environments/self-hosted#create-or-reuse-a-session) and save its environment ID.

182. Create a Runloop Devbox with the session's working directory and install the Codex CLI inside it.

193. [Start the executor](https://developers.openai.com/api/docs/guides/agents-api/environments/self-hosted#start-the-executor) in the background with the environment ID and environment key.

204. [Send input and inspect the result](https://developers.openai.com/api/docs/guides/agents-api/sessions). For a file task, create `brief.txt` in the workspace and ask the agent to write a migration plan to `plan.md`.

215. Check that the turn completed, retrieve any files you need, then shut down the Devbox and [delete the session](https://developers.openai.com/api/docs/guides/agents-api/sessions/manage#delete-a-session).

22 

23Use bounded setup and execution timeouts, plus a Devbox lifetime limit as a fallback if your application exits unexpectedly. Keep the session and Devbox alive if you need follow-up turns. Use one provisioning owner per session; do not attach a provisioning webhook handler to sessions your application manages directly.

24 

25## References

26 

27- Read [Runloop documentation](https://docs.runloop.ai/)

28- Read [Runloop Python SDK](https://runloopai.github.io/api-client-python/)

29- Read [Runloop TypeScript SDK](https://runloopai.github.io/api-client-ts/stable/)

Details

224| Daytona | [Daytona setup](https://developers.openai.com/api/docs/guides/agents-api/environments/providers/daytona) |224| Daytona | [Daytona setup](https://developers.openai.com/api/docs/guides/agents-api/environments/providers/daytona) |

225| Blaxel | [Blaxel setup](https://developers.openai.com/api/docs/guides/agents-api/environments/providers/blaxel) |225| Blaxel | [Blaxel setup](https://developers.openai.com/api/docs/guides/agents-api/environments/providers/blaxel) |

226| E2B | [E2B setup](https://developers.openai.com/api/docs/guides/agents-api/environments/providers/e2b) |226| E2B | [E2B setup](https://developers.openai.com/api/docs/guides/agents-api/environments/providers/e2b) |

227| Runloop | [Runloop setup](https://developers.openai.com/api/docs/guides/agents-api/environments/providers/runloop) |

228| DigitalOcean | [DigitalOcean setup](https://developers.openai.com/api/docs/guides/agents-api/environments/providers/digitalocean) |227| DigitalOcean | [DigitalOcean setup](https://developers.openai.com/api/docs/guides/agents-api/environments/providers/digitalocean) |

229| AWS Lambda MicroVMs | [AWS setup](https://developers.openai.com/api/docs/guides/agents-api/environments/providers/aws) |228| AWS Lambda MicroVMs | [AWS setup](https://developers.openai.com/api/docs/guides/agents-api/environments/providers/aws) |

230| Oracle Cloud Infrastructure (OCI) | [OCI setup](https://developers.openai.com/api/docs/guides/agents-api/environments/providers/oci) |229| Oracle Cloud Infrastructure (OCI) | [OCI setup](https://developers.openai.com/api/docs/guides/agents-api/environments/providers/oci) |

Details

499 499 

500- **Session items:** [List items](https://developers.openai.com/api/reference/resources/beta/subresources/agents/subresources/sessions/subresources/items/methods/list) to retrieve the root agent's messages and tool calls across turns.500- **Session items:** [List items](https://developers.openai.com/api/reference/resources/beta/subresources/agents/subresources/sessions/subresources/items/methods/list) to retrieve the root agent's messages and tool calls across turns.

501- **Turns:** [List turns](https://developers.openai.com/api/reference/resources/beta/subresources/agents/subresources/sessions/subresources/turns/methods/list) to browse the session's work. [Retrieve a turn](https://developers.openai.com/api/reference/resources/beta/subresources/agents/subresources/sessions/subresources/turns/methods/retrieve) by ID to inspect its status, timestamps, usage, and error.501- **Turns:** [List turns](https://developers.openai.com/api/reference/resources/beta/subresources/agents/subresources/sessions/subresources/turns/methods/list) to browse the session's work. [Retrieve a turn](https://developers.openai.com/api/reference/resources/beta/subresources/agents/subresources/sessions/subresources/turns/methods/retrieve) by ID to inspect its status, timestamps, usage, and error.

502- **Items from one turn:** For a root-agent turn, filter session items by `turn_id`. Each subagent has its own [item history](https://developers.openai.com/api/reference/resources/beta/subresources/agents/subresources/sessions/subresources/subagents/subresources/items/methods/list) and a [per-turn items endpoint](https://developers.openai.com/api/reference/resources/beta/subresources/agents/subresources/sessions/subresources/subagents/subresources/turns/subresources/items/methods/list).502- **Items from one turn:** For a root-agent turn, use the [List turn items](https://developers.openai.com/api/reference/resources/beta/subresources/agents/subresources/sessions/subresources/turns/subresources/items/methods/list) endpoint. Each subagent has its own [item history](https://developers.openai.com/api/reference/resources/beta/subresources/agents/subresources/sessions/subresources/subagents/subresources/items/methods/list) and a [per-turn items endpoint](https://developers.openai.com/api/reference/resources/beta/subresources/agents/subresources/sessions/subresources/subagents/subresources/turns/subresources/items/methods/list).

503 503 

504List endpoints return one page at a time. Use SDK pagination helpers or the `after` cursor to retrieve more results. A single page may not contain every item for a turn. Use `order: "asc"` to read items from oldest to newest.504List endpoints return one page at a time. Use SDK pagination helpers or the `after` cursor to retrieve more results. A single page may not contain every item for a turn. Use `order: "asc"` to read items from oldest to newest.

505 505 

Details

732| Docker | `DockerSandboxClient` | [Docker documentation](https://docs.docker.com/)<br />[TypeScript Docker SDK example](https://github.com/openai/openai-agents-js/blob/main/examples/docs/sandbox-agents/docker-client.ts)<br />[Python Docker SDK example](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/docker/docker_runner.py) |732| Docker | `DockerSandboxClient` | [Docker documentation](https://docs.docker.com/)<br />[TypeScript Docker SDK example](https://github.com/openai/openai-agents-js/blob/main/examples/docs/sandbox-agents/docker-client.ts)<br />[Python Docker SDK example](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/docker/docker_runner.py) |

733| E2B | `E2BSandboxClient` | [Sandbox documentation](https://e2b.dev/docs)<br />[OpenAI Agents SDK guide](https://e2b.dev/docs/agents/openai-agents-sdk)<br />[Launch blog](https://e2b.dev/blog/e2b-is-now-in-agents-sdk) |733| E2B | `E2BSandboxClient` | [Sandbox documentation](https://e2b.dev/docs)<br />[OpenAI Agents SDK guide](https://e2b.dev/docs/agents/openai-agents-sdk)<br />[Launch blog](https://e2b.dev/blog/e2b-is-now-in-agents-sdk) |

734| Modal | `ModalSandboxClient` | [Sandbox guide](https://modal.com/docs/guide/sandboxes)<br />[Integration blog](https://modal.com/blog/building-with-modal-and-the-openai-agent-sdk)<br />[Example repo](https://github.com/modal-labs/openai-agents-python-example)<br />[Modal extension reference](https://github.com/modal-labs/openai-agents-python-example?tab=readme-ov-file#modal-extension-reference) |734| Modal | `ModalSandboxClient` | [Sandbox guide](https://modal.com/docs/guide/sandboxes)<br />[Integration blog](https://modal.com/blog/building-with-modal-and-the-openai-agent-sdk)<br />[Example repo](https://github.com/modal-labs/openai-agents-python-example)<br />[Modal extension reference](https://github.com/modal-labs/openai-agents-python-example?tab=readme-ov-file#modal-extension-reference) |

735| Runloop | `RunloopSandboxClient` | [Devbox overview](https://docs.runloop.ai/docs/devboxes/overview)<br />[Tunnels](https://docs.runloop.ai/docs/devboxes/tunnels) |

736| Unix-local | `UnixLocalSandboxClient` | [TypeScript local SDK example](https://github.com/openai/openai-agents-js/blob/main/examples/docs/sandbox-agents/basic.ts)<br />[Python local SDK example](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/unix_local_runner.py) |735| Unix-local | `UnixLocalSandboxClient` | [TypeScript local SDK example](https://github.com/openai/openai-agents-js/blob/main/examples/docs/sandbox-agents/basic.ts)<br />[Python local SDK example](https://github.com/openai/openai-agents-python/blob/main/examples/sandbox/unix_local_runner.py) |

737| Vercel | `VercelSandboxClient` | [Sandbox documentation](https://vercel.com/docs/vercel-sandbox)<br />[OpenAI Agents SDK guide](https://vercel.com/kb/guide/building-an-agent-with-openai-agents-sdk-and-vercel-sandbox)<br />[FastAPI template](https://vercel.com/templates/template/openai-agents-sdk-with-fastapi)<br />[Sample app](https://github.com/vercel-labs/openai-agents-fastapi-starter) |736| Vercel | `VercelSandboxClient` | [Sandbox documentation](https://vercel.com/docs/vercel-sandbox)<br />[OpenAI Agents SDK guide](https://vercel.com/kb/guide/building-an-agent-with-openai-agents-sdk-and-vercel-sandbox)<br />[FastAPI template](https://vercel.com/templates/template/openai-agents-sdk-with-fastapi)<br />[Sample app](https://github.com/vercel-labs/openai-agents-fastapi-starter) |

738 737 

Details

313 313 

314The `probability` is the model's estimate that the condition is true. Use it to flag photos for review based on a threshold you choose.314The `probability` is the model's estimate that the condition is true. Use it to flag photos for review based on a threshold you choose.

315 315 

316Images must be inline base64 data URLs. Hosted HTTP or HTTPS image URLs and `file_id` inputs aren't supported by this endpoint. Combine `input_text` and `input_image` parts in a user message to evaluate images together with instructions or other context.316Provide images as inline base64 data URLs or publicly accessible HTTP or HTTPS URLs. This endpoint doesn't support `file_id` inputs. Combine `input_text` and `input_image` parts in a user message to evaluate images together with instructions or other context.

317 317 

318## Select from fixed options318## Select from fixed options

319 319 

Details

15 15 

16## When to use reinforcement fine-tuning16## When to use reinforcement fine-tuning

17 17 

18Agentic workflows are designed to make decisions that are both correct and verifiable. RFT can help by providing explicit rubrics and using code‑based or LLM‑based graders to measure functional success, factual accuracy, or policy compliance.18An agentic workflow is designed to make decisions that are both correct and verifiable. RFT can help by providing explicit rubrics and using code‑based or LLM‑based graders to measure functional success, factual accuracy, or policy compliance.

19 19 

20Across early users, three clear use cases have emerged:20Across early users, three clear use cases have emerged:

21 21 


121 121 

122 122 

123 123 

124#### Production-ready API snippets that compile and pass AST checks

125 

126 

127 

128Use case

129 

130

131 

132> **Company**: [Runloop](https://www.runloop.ai) is a platform for AI-powered coding agents to be deployed into production and built with public and custom benchmarking capabilities to refine performance.

133>

134> **Problem to solve**: Runloop wanted to improve model performance at using third-party APIs, such as the Stripe API, which can be large and complex without a human in the loop. If they could train a model to use the Stripe API, Runloop could turn economically impactful business cases into working code.

135>

136> **Objective**: Their goal was teaching the model to master usage of the Stripe API, including writing complete code snippets for arbitrary user requests by either adapting information from existing integration guides, merging information from multiple guides, or inferring information not explicitly stated in the guides. They used RFT with two primary rewards:

137>

138> 1. Reward the model for outputting the answer in a Markdown format that aligns with expectation of how a "dynamic" integration guide should look.

139> 1. Reward the model for producing "correct" code snippets by validating the outputted code via AST Grep. This allows them to confirm the model is making the correct Stripe SDK calls with the correct parameters and in some cases even in the correct order.

140 

141 

142

143 

144

145 

146

147Grader code

148 

149

150 

151````python

152# Note this file gets uploaded to the OpenAI API as a grader

153from ast_grep_py import SgRoot

154from pydantic import BaseModel, Field # type: ignore

155from typing import Any

156import re

157 

158SUPPORTED_LANGUAGES = ['typescript', 'javascript', 'ts', 'js']

159 

160class CodeBlock(BaseModel):

161 language: str = Field(

162 description="Programming language of the code block (e.g., 'python', 'javascript')",

163 examples=["python", "javascript", "typescript"]

164 )

165 path: str = Field(

166 description="Target file path where the code should be written",

167 examples=["main.py", "src/app.js", "index.html"]

168 )

169 code: str = Field(

170 description="Actual code content extracted from the code block"

171 )

172 

173class ASTGrepPattern(BaseModel):

174 file_path_mask: str = Field(..., description="The file path pattern to match against")

175 pattern: str = Field(..., description="The main AST grep pattern to search for")

176 additional_greps: list[str] | None = Field(

177 default=None,

178 description="Additional patterns that must also be present in the matched code"

179 )

180 

181def extract_code_blocks(llm_output: str) -> list[CodeBlock]:

182 # Regular expression to match code blocks with optional language and path

183 try:

184 pattern = r"```(\w+\s+)?([\w./-]+)?\n([\s\S]*?)\n```"

185 matches = list(re.finditer(pattern, llm_output, re.DOTALL))

186 

187 print(f"Found {len(matches)} code blocks in the LLM output")

188 

189 # Check if any code blocks were found

190 if not matches:

191 raise Exception("No code blocks found in the LLM response")

192 

193 code_blocks: list[CodeBlock] = []

194 for match in matches:

195 language = match.group(1) or ""

196 path = match.group(2) or ""

197 code = match.group(3)

198 

199 # Clean the path and language

200 path = path.strip()

201 language = language.strip()

202 

203 # If path is relative (doesn't start with /), prefix with /home/user/testbed/

204 if path and not path.startswith("/"):

205 original_path = path

206 path = f"/home/user/testbed/{path}"

207 print(

208 f"Converting relative path '{original_path}' to absolute path '{path}'"

209 )

210 

211 code_blocks.append(

212 CodeBlock(language=language, path=path, code=code.strip())

213 )

214 

215 # Check for missing language or path in code blocks

216 missing_language = [

217 i for i, block in enumerate(code_blocks) if not block.language

218 ]

219 missing_path = [i for i, block in enumerate(code_blocks) if not block.path]

220 

221 if missing_language:

222 print(

223 f"WARNING: Code blocks at positions {missing_language} are missing language identifiers"

224 )

225 raise Exception(

226 f"Code blocks at positions {missing_language} are missing language identifiers"

227 )

228 

229 if missing_path:

230 print(

231 f"WARNING: Code blocks at positions {missing_path} are missing file paths"

232 )

233 raise Exception(

234 f"Code blocks at positions {missing_path} are missing file paths"

235 )

236 

237 paths = [block.path for block in code_blocks if block.path]

238 print(

239 f"Successfully extracted {len(code_blocks)} code blocks with paths: {', '.join(paths)}"

240 )

241 

242 except Exception as e:

243 print(f"Error extracting code blocks: {str(e)}")

244 raise

245 

246 return code_blocks

247 

248 

249def calculate_ast_grep_score(code_blocks: list[CodeBlock], ast_greps: Any) -> float:

250 # Convert ast_greps to list if it's a dict

251 if isinstance(ast_greps, dict):

252 ast_greps = [ast_greps]

253 

254 # Parse each grep pattern into the Pydantic model

255 parsed_patterns: list[ASTGrepPattern] = []

256 for grep in ast_greps:

257 try:

258 pattern = ASTGrepPattern(**grep)

259 parsed_patterns.append(pattern)

260 except Exception as e:

261 print(f"Error parsing AST grep pattern: {e}")

262 return 0.0

263 

264 if not parsed_patterns:

265 return 0.0

266 

267 total_score = 0.0

268 pattern_count = len(parsed_patterns)

269 

270 # Filter code blocks to only include TypeScript and JavaScript files

271 supported_blocks = [

272 block for block in code_blocks

273 if block.language.lower() in SUPPORTED_LANGUAGES

274 ]

275 

276 if not supported_blocks:

277 print("No TypeScript or JavaScript code blocks found to analyze")

278 return 0.0

279 

280 for pattern in parsed_patterns:

281 # Find matching code blocks based on path prefix

282 matching_blocks = [

283 block for block in supported_blocks

284 if block.path.startswith(pattern.file_path_mask)

285 ]

286 

287 if not matching_blocks:

288 print(f"No matching code blocks found for path prefix: {pattern.file_path_mask}")

289 continue

290 

291 pattern_found = False

292 for block in matching_blocks:

293 try:

294 # Create AST root for the code block

295 root = SgRoot(block.code, block.language)

296 node = root.root()

297 

298 # Check main pattern

299 matches = node.find(pattern=pattern.pattern)

300 if not matches:

301 continue

302 

303 # If we have additional greps, check them too

304 if pattern.additional_greps:

305 all_additional_found = True

306 for additional_grep in pattern.additional_greps:

307 if additional_grep not in block.code:

308 all_additional_found = False

309 break

310 

311 if not all_additional_found:

312 continue

313 

314 # If we get here, we found a match with all required patterns

315 pattern_found = True

316 break

317 

318 except Exception as e:

319 print(f"Error processing code block {block.path}: {e}")

320 continue

321 

322 if pattern_found:

323 total_score += 1.0

324 

325 # Return average score across all patterns

326 return total_score / pattern_count if pattern_count > 0 else 0.0

327 

328def grade_format(output_text: str) -> float:

329 # Find <plan> and </plan> tags

330 plan_start = output_text.find('<plan>')

331 plan_end = output_text.find('</plan>')

332 

333 # Find <code> and </code> tags

334 code_start = output_text.find('<code>')

335 code_end = output_text.find('</code>')

336 

337 reward = 0.0

338 

339 if plan_start == -1 or plan_end == -1 or code_start == -1 or code_end == -1:

340 print(f'missing plan or code tags. format reward: {reward}')

341 return reward

342 reward += 0.1 # total: 0.1

343 

344 if not (plan_start < plan_end < code_start < code_end):

345 print(f'tags present but not in the correct order. format reward: {reward}')

346 return reward

347 reward += 0.1 # total: 0.2

348 

349 # Check if there are any stray tags

350 plan_tags = re.findall(r'</?plan>', output_text)

351 code_tags = re.findall(r'</?code>', output_text)

352 

353 if len(plan_tags) != 2 or len(code_tags) != 2:

354 print(f'found stray plan or code tags. format reward: {reward}')

355 return reward

356 reward += 0.2 # total: 0.4

357 

358 # Extract content after </code> tag

359 after_tags = output_text[code_end + len('</code>'):].strip()

360 if after_tags:

361 print(f'found text after code tags. format reward: {reward}')

362 return reward

363 reward += 0.2 # total: 0.6

364 

365 # Extract content inside <plan> tags

366 plan_content = output_text[plan_start + len('<plan>'):plan_end].strip()

367 if not plan_content:

368 print(f'no plan content found. format reward: {reward}')

369 return reward

370 reward += 0.1 # total: 0.7

371 

372 # Extract content inside <code> tags

373 code_content = output_text[code_start + len('<code>'):code_end].strip()

374 if not code_content:

375 print(f'no code content found. format reward: {reward}')

376 return reward

377 reward += 0.1 # total: 0.8

378 

379 # Extract content between </plan> and <code> tags

380 between_tags = output_text[plan_end + len('</plan>'):code_start].strip()

381 if between_tags:

382 print(f'found text between plan and code tags. format reward: {reward}')

383 return reward

384 reward += 0.2 # total: 1.0

385 

386 if reward == 1.0:

387 print(f'global format reward: {reward}')

388 

389 return reward

390 

391def grade(sample: Any, item: Any) -> float:

392 try:

393 output_text = sample["output_text"]

394 

395 format_reward = grade_format(output_text)

396 if format_reward < 1.0:

397 return format_reward

398 

399 # Extract code content for grading

400 code_start = output_text.find('<code>')

401 code_end = output_text.find('</code>')

402 code_to_grade: str = output_text[code_start + len('<code>'):code_end].strip()

403 code_blocks: list[CodeBlock] = []

404 try:

405 code_blocks = extract_code_blocks(code_to_grade)

406 except Exception as e:

407 print(f'error extracting code blocks: {e}')

408 return 0.5

409 

410 ast_greps = item["reference_answer"]["ast_greps"]

411 ast_grep_score = calculate_ast_grep_score(code_blocks, ast_greps)

412 

413 return (format_reward + ast_grep_score) / 2.0

414 except Exception as e:

415 print(f"Error during grading: {str(e)}")

416 return 0.0

417````

418 

419 

420

421 

422

423 

424

425Results

426 

427

428 

429> Looking at the total reward (format and AST Grep) together, Runloop has seen improvements of on average **12%** of the RFT model compared to the base o3-mini model on the benchmark.

430>

431> They implement two types of tests, one providing explicit content from the integration guides (assessing reasoning and instruction following) and one without (assessing knowledge recall). Both variants saw improvement of over **8%**.

432>

433> “OpenAIs RFT platform gives us access to the best generalized reasoning models in the world, with the toolset to supercharge that reasoning on problem domains important to our business.”

434>

435> —[Runloop](https://www.runloop.ai/)

436 

437 

438 

439#### Correct handling of conflicts and dupes in a schedule manager124#### Correct handling of conflicts and dupes in a schedule manager

440 125 

441 126 


636 321 

637### 3. Apply complex rules correctly322### 3. Apply complex rules correctly

638 323 

639This use case involves pulling verifiable facts or entities from unstructured inputs into clearly defined schemas (e.g., JSON objects, condition codes, medical codes, legal citations, or financial metrics).324This use case involves pulling verifiable facts or entities from unstructured inputs into defined schemas (for example, JSON objects, condition codes, medical codes, legal citations, or financial metrics).

640 325 

641Successful extraction tasks typically benefit from precise, continuous grading methodologies—like span-level F1 scores, fuzzy text-matching metrics, or numeric accuracy checks—to evaluate how accurately the extracted information aligns with ground truth. Define explicit success criteria and detailed rubrics. Then, the model can achieve reliable, repeatable improvements.326Successful extraction tasks typically benefit from precise, continuous grading methodologies—like span-level F1 scores, fuzzy text-matching metrics, or numeric accuracy checks—to evaluate how accurately the extracted information aligns with ground truth. Define explicit success criteria and detailed rubrics. Then, the model can achieve reliable, repeatable improvements.

642 327 


773 458 

774**Before implementing RFT, we strongly recommended creating and running an eval for the task you intend to fine-tune on**. If the model you intend to fine-tune scores at either the absolute minimum or absolute maximum possible score, then RFT won’t be useful to you.459**Before implementing RFT, we strongly recommended creating and running an eval for the task you intend to fine-tune on**. If the model you intend to fine-tune scores at either the absolute minimum or absolute maximum possible score, then RFT won’t be useful to you.

775 460 

776RFT works by reinforcing better answers to provided prompts. If we can’t distinguish the quality of different answers (i.e., if they all receive the minimum or maximum possible score), then there's no training signal to learn from. However, if your eval scores somewhere in the range between the minimum and maximum possible scores, there's enough data to work with.461RFT works by reinforcing better answers to provided prompts. If we can’t distinguish the quality of different answers (that is, if they all receive the minimum or maximum possible score), then there's no training signal to learn from. However, if your eval scores somewhere in the range between the minimum and maximum possible scores, there's enough data to work with.

777 462 

778An effective eval reveals opportunities where human experts consistently agree but current frontier models struggle, presenting a valuable gap for RFT to close. [Get started with evals](https://developers.openai.com/api/docs/guides/evals).463An effective eval reveals opportunities where human experts consistently agree but current frontier models struggle, presenting a valuable gap for RFT to close. [Get started with evals](https://developers.openai.com/api/docs/guides/evals).

779 464 


781 466 

782To see improvements in your fine-tuned model, there are two main places to revisit and refine: making sure your task is well defined, and making your grading scheme more robust.467To see improvements in your fine-tuned model, there are two main places to revisit and refine: making sure your task is well defined, and making your grading scheme more robust.

783 468 

784### Reframe or clarify your task469<a id="reframe-or-clarify-your-task"></a>

470 

471### Revise or clarify your task

785 472 

786Good tasks give the model a fair chance to learn and let you quantify improvements.473Good tasks give the model a fair chance to learn and let you quantify improvements.

787 474 

788- **Start with a task the model can already solve occasionally**. RFT works by sampling many answers, keeping what looks best, and nudging the model toward those answers. If the model never gets the answer correct today, it cannot improve.475- **Start with a task the model can already solve occasionally**. RFT works by sampling many answers, keeping what looks best, and nudging the model toward those answers. If the model never gets the answer correct today, it cannot improve.

789- **Make sure each answer can be graded**. A grader must read an answer and produce a score without a person in the loop. We support multiple [grader types](https://developers.openai.com/api/docs/guides/graders), including custom Python graders and LLM judges. If you can't write code to judge the answer with an available grader, RFT is not the right tool.476- **Make sure each answer can be graded**. A grader must read an answer and produce a score without a person in the loop. We support multiple [grader types](https://developers.openai.com/api/docs/guides/graders), including custom Python graders and LLM judges. If you can't write code to judge the answer with an available grader, RFT is not the right tool.

790- **Remove doubt about the “right” answer**. If two careful people often disagree on the solution, the task is too fuzzy. Rewrite the prompt, add context, or split the task into clearer parts until domain experts agree.477- **Remove doubt about the “right” answer**. If two careful people often disagree on the solution, the task is too fuzzy. Rewrite the prompt, add context, or split the task into clearer parts until domain experts agree.

791- **Limit lucky guesses**. If the task is multiple choice with one obvious best pick, the model can win by chance. Add more classes, ask for short open‑ended text, or tweak the format so guessing is costly.478- **Limit lucky guesses**. If the task is multiple choice with one best option, the model can win by chance. Add more classes, ask for short open‑ended text, or tweak the format so guessing is costly.

792 479 

793### Strengthen your grader480### Strengthen your grader

794 481 

libraries.md +1 −1

Details

173<dependency>173<dependency>

174 <groupId>com.openai</groupId>174 <groupId>com.openai</groupId>

175 <artifactId>openai-java</artifactId>175 <artifactId>openai-java</artifactId>

176 <version>4.85.0</version>176 <version>4.86.0</version>

177</dependency>177</dependency>

178```178```

179 179 

quickstart.md +1 −1

Details

190<dependency>190<dependency>

191 <groupId>com.openai</groupId>191 <groupId>com.openai</groupId>

192 <artifactId>openai-java</artifactId>192 <artifactId>openai-java</artifactId>

193 <version>4.85.0</version>193 <version>4.86.0</version>

194</dependency>194</dependency>

195```195```

196 196