Agentic OPD requires a custom Rollout (you control the generation process yourself, such as multi-turn interaction, passing the tools parameter to produce structured tool_call). Reward is optional. This article introduces function development for both the Reward-disabled and Reward-enabled modes.
tools parameter to produce structured tool_call (tool calls), etc.); Reward is optional. It consists of three parts: tool definitions + Rollout (sampling to produce trajectories) + Reward (scoring, optional). For the training overview, see Online Policy Distillation Training Overview.
Development Overview
The key difference between Agentic OPD and Model OPD is whether tool calls, multi-turn, or custom interactions are involved:
- Model OPD is used for pure-text tasks, where the student model directly generates text output.
- Agentic OPD is used for tasks requiring tool calls or multi-turn interaction. By passing the
toolsparameter, the framework passes tool information directly to the model, and the model returns a structuredtool_callsfield (native tool calls).
RolloutFunctionComponent, and the training signal is dominated by teacher-model distillation.
The differences between the two modes are as follows.
Dimension | No Reward (only Rollout) | With Reward (Rollout + Reward) |
|---|---|---|
Development Work | Write the Rollout function (custom generation process) | Additionally write a Reward scoring function |
Training Signal | Teacher-model distillation as the only supervision | Teacher distillation + task reward |
Applicable Scenario | Only tool-call shape alignment needed, teacher model already the ceiling | Need to optimize tool selection and parameters by business goal |
Data Format
One JSONL record per line, containing two fields: messages (conversation) and rollout_extra (additional information).
messages: the conversation list, arranged with alternating user/assistant turns; the first turn can be user or system.rollout_extra: additional information that can store sample_id, category, solution, etc.solutionis a JSON string storing the standard answer for Reward scoring; when Reward is not enabled it serves only as a marker and is not consumed.
query_status, delete_item) are defined in the Tool Definitions section below, and Rollout injects tools by passing the tools parameter—see the Rollout Function Structure section:
- Single-turn · tool_call
- Multi-turn · tool_call
- Single-turn · No tool call
query_status tool to query:Rollout Function Development
Agentic OPD requires a custom Rollout (you control the generation process yourself). This section covers Rollout function development: tool definitions, Rollout function structure, and Tracing integration.
Tool Definitions
Tool definitions are a prerequisite for Rollout. First define the tool_spec, then implement the Rollout processor; both belong to the functions/ subpackage. The directory structure is as follows (__init__.py makes the directory an importable Python package; without it, classpath resolution fails):
classpath of the submission script points to functions.rollout.my_rollout.MyRolloutProcessor (i.e., the MyRolloutProcessor class inside functions/rollout/my_rollout.py); the Reward class likewise points to functions.reward.my_reward.MyRewardProcessor.
Tool definitions consist of three parts:
- System Prompt: constrains when to call a tool and when to reply with a text prefix
- Tool Definition List: a JSON Schema list, directly used by passing the
toolsparameter inside Rollout; the framework automatically renders tool information to the model; the format is consistent with OpenAI function calling - High-Risk Operation Set: marks destructive tool names so that Reward can judge whether the model mis-invoked a dangerous tool
tool_calls by passing the tools parameter through the framework.
Rollout Function Structure
Inherit AbstractRolloutProcessor and implement async process(input: RolloutInput) -> RolloutOutput. Decorate process with @observe_processor (automatically integrates Tracing). Key steps:
- Retrieve model resources: take
model_resource(api_key/base_url/model_name) andsampling_paramsfromRolloutInput - Construct and wrap the LLM: construct
ChatOpenAI, calltrace_clientto wrap it - Sample: pass the
toolsparameter to inject tool definitions,ainvoketo sample (single turn, without executing tools) - Construct output: construct
AgentOutput(containing nativetool_calls,rollout_metrics), placed inRolloutOutput.agent_output - Exception fallback: return the
ROLLOUT_ERRORfallback text and set status to FAILED
RolloutInput → AgentOutput → RolloutOutput.
Field | Source | Meaning |
|---|---|---|
| RolloutInput | Contains api_key/base_url/model_name; used to construct ChatOpenAI |
| RolloutInput | Sampling parameters such as temperature/max_tokens/timeout |
| RolloutInput | Input conversation list, containing system/user/assistant |
| RolloutInput | Passed through to AgentOutput for Reward to read |
| AgentOutput | Output conversation; the last assistant turn contains tool_calls |
| AgentOutput | Reports latency (seconds) and tool_call_count (float) |
| AgentOutput | Placeholder 0.0, overwritten by Reward |
| RolloutOutput | SUCCESS or FAILED |
| RolloutOutput | Exception type name; None when normal |
Tracing Integration
Rollout constructs its own LLM client and, unlike Reward (where @observe_processor implicitly injects it), must explicitly call trace_client to wrap the client. Integration steps:
- Take
model_resource(containing api_key/base_url/model_name) andsampling_paramsfromRolloutInput, and construct the LLM client (such asChatOpenAI) - Call
trace_client(llm)to wrap it—after that, all LLM requests from this client automatically produce an LLM Span (recording model name, request content, Token usage, latency) - After wrapping, pass the
toolsparameter andainvoketo sample
ChatOpenAI (recommended; wraps the OpenAI-compatible interface); you can also use the openai SDK directly—just replace ChatOpenAI and the message classes.
If trace_client is not called, LLM requests produce no Span and the trajectory page will not show the tool-call chain (training is unaffected). For full Tracing configuration (decorators, Span types, metric paths), see Observable Configuration.
Development Reference Without Reward
When Reward is not enabled, the functions list only contains the Rollout component, and teacher-model distillation is the only supervision signal. Submit with the AgenticRL client; the functions list only contains RolloutFunctionComponent, without passing RewardFunctionComponent. Construct function_components to specify the working directory and classpath, and configure teacher_model (teacher model), the student model, dataset paths, and resource specifications. The teacher_model field triggers distillation; for hyperparameter configuration, see Training Configuration.
Development With Reward Enabled
Reward is an optional component; once enabled, RewardFunctionComponent is appended to the functions list. Agentic Reward is simpler than Model OPD: via the chat-completions interface, the parser takes effect, and the output content is clean with no need to strip thinking text.
Reward Function Structure
Inherit AbstractRewardProcessor and implement async process(input: RewardInput) -> RewardOutput; decorate process with @observe_processor (automatically integrates Tracing). The process does five things:
- Skip failed samples: when Rollout fails (the last-turn content starts with
ROLLOUT_ERROR:), return 0 points directly without scoring - Retrieve the standard answer:
ground_truth(the scoring baseline; taken fromRewardInputfirst, or read from the data fieldrollout_extra.solutionwhen missing) - Retrieve the student output: take
tool_callsfrom the last assistant message (the tool calls produced by the student model) - Score: compare the standard answer with the student output to compute
reward_score(main score) andreward_metrics(per-dimension scores) - Construct the return: place
reward_scoreseparately inReward.reward_score, put the remaining dimensions intoreward_metrics, and wrap asRewardOutput
agent_output (the student output) is produced by Rollout; Reward only reads it, never writes. For full Tracing configuration, see Observable Configuration.
Field | Source | Meaning |
|---|---|---|
| RewardInput | Scoring baseline; can be None |
| RewardInput | Produced by Rollout; Reward only reads |
| agent_output.messages | Conversation trajectory containing tool_calls |
| agent_output.rollout_extra | Passed-through additional information; solution can be read |
| Reward | Main score, reported separately, not in metrics |
| Reward | Other dimensions dict, each value a float |
| RewardOutput | SUCCESS or FAILED |
| RewardOutput | Exception info; None when normal |
Scoring Logic
reward_score is the main reward scalar, and reward_metrics is a dictionary of additional dimensions (each value a float). The scoring function implementation is in the Reward Function Structure section above. Key conventions:
- Main score reported separately:
reward_scoreis assigned separately toReward.reward_scoreand does not duplicate intoreward_metrics(metrics.pop("reward_score")) - Dimensions are custom: dimensions and weights are defined by the task; implement them per your business needs
- Parameter comparison: argument comparison uses whole-serialization equality: compare strings after
json.dumps(args, sort_keys=True, separators=(",", ":")) - Focus on business constraints: teacher-model distillation already provides dense distribution-level supervision, so Reward need not cover everything—focus on the business constraints that the teacher model cannot cover (such as whether
safe_actionmis-invoked a destructive tool, or whetherformat_validis compliant)
Submit a Training Task With Reward Enabled
After writing MyRewardProcessor, register both RolloutFunctionComponent and RewardFunctionComponent in the functions list. run() completes registration → upload data → submit the task in one step.
RolloutFunctionComponent is consistent with the no-Reward mode, and RewardFunctionComponent points to the module where MyRewardProcessor resides. For full field descriptions, see Training Configuration.
Function Testing
Before submitting for training, locally validate the scoring logic and Rollout output structure first, to avoid discovering errors only inside the training task (which wastes compute).
Feed sample messages + ground_truth into your_scoring_function and assert reward_score and each dimension value. For Rollout, construct a mock RolloutInput and call process locally to validate the output structure. Local unit tests only validate function logic, not remote training effects.
Run tests with pytest (install first with pip install pytest if not installed):
RolloutInput and call the Rollout process, fill three fields: model_resource (api_key/base_url/model_name), sampling_params (sampling parameters), and messages (conversation list). Example:
Next Steps
- Training parameters and submission configuration → Online Policy Distillation Training Configuration
- Observable configuration → Online Policy Distillation Observable Configuration
- Review the training overview → Online Policy Distillation Training Overview