> ## Documentation Index
> Fetch the complete documentation index at: https://docs.osmosis.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenAI Agents 集成

> 结合使用 OpenAI Agents SDK，在 Osmosis 上训练

Osmosis SDK 包含面向 [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/) 的集成。如果您的 rollout 基于 `Agent`、`Runner.run`、sessions、tools、handoffs 或其他 OpenAI Agents SDK primitives，请使用它。

该集成有三个主要对象：

| Object                 | Purpose                                                                          |
| ---------------------- | -------------------------------------------------------------------------------- |
| `OsmosisAgent`         | OpenAI Agents SDK `Agent` 的直接替代品，会把 `OsmosisRolloutModel` 绑定到活跃的 rollout context |
| `OsmosisRolloutModel`  | 占位 policy model，`OsmosisAgent` 会将其替换为活跃 rollout model                            |
| `OsmosisMemorySession` | In-memory session，用来记录 runner conversation，并将其作为 rollout sample 暴露给 grader       |

## 快速示例

```python theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/cli.json"]}}
from agents import ModelSettings, Runner
from osmosis_ai.rollout import AgentWorkflow, AgentWorkflowContext
from osmosis_ai.rollout.integrations.agents.openai_agents import (
    OsmosisAgent,
    OsmosisMemorySession,
    OsmosisRolloutModel,
)


class OpenAIWorkflow(AgentWorkflow):
    async def run(self, ctx: AgentWorkflowContext) -> None:
        agent = OsmosisAgent(
            name="assistant",
            instructions="Answer the user's request clearly.",
            model=OsmosisRolloutModel(),
            model_settings=ModelSettings(temperature=1.0, max_tokens=4096),
        )
        session = OsmosisMemorySession(name="assistant")
        await Runner.run(
            agent,
            ctx.prompt,
            session=session,
        )
```

<Warning>
  使用 `OsmosisRolloutModel` 时，请始终传入 `OsmosisMemorySession`。Session 会发布用于 rollout headers 的 sample ID，并持久化 grader 将读取的 conversation。请在 `AgentWorkflow.run()` 内构造 session，使其注册到活跃的 `RolloutContext`。
</Warning>

## 工作原理

<Steps>
  <Step title="在 run 内构造 agent">
    `OsmosisAgent` 会检查 `model` 参数是否为 `OsmosisRolloutModel`。如果是，它会把占位符替换为绑定到活跃 `RolloutContext` 的 `OsmosisLitellmModel`。
  </Step>

  <Step title="创建 memory session">
    `OsmosisMemorySession` 会在当前 `RolloutContext` 上将自身注册为 sample source。Session name 会成为 rollout sample ID。
  </Step>

  <Step title="运行 OpenAI agent">
    `Runner.run()` 通过 `get_items()` 和 `add_items()` 与 session 交互。Session 会以 canonical Responses API shape 存储持久化的 OpenAI Agents SDK items。
  </Step>

  <Step title="路由策略调用">
    解析后的 model 会向 Osmosis chat completions endpoint 发送请求，并为每次 model call 注入 `x-sample-id` 和 `x-rollout-id` headers。
  </Step>

  <Step title="收集 samples">
    `run()` 完成后，backend 会向 rollout context 请求 samples。Session 会返回包含 runner 持久化 conversation 的 `RolloutSample`。
  </Step>
</Steps>

## 完整示例

此示例使用 OpenAI Agents SDK tool，并使用 grader 从 session-backed sample 中读取最后一条 assistant text。

```python theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/cli.json"]}}
from agents import ModelSettings, Runner, function_tool
from osmosis_ai.rollout import (
    AgentWorkflow,
    AgentWorkflowContext,
    Grader,
    GraderContext,
)
from osmosis_ai.rollout.integrations.agents.openai_agents import (
    OsmosisAgent,
    OsmosisMemorySession,
    OsmosisRolloutModel,
)


@function_tool
def multiply(a: int, b: int) -> int:
    """Multiply two integers."""
    return a * b


class MultiplyWorkflow(AgentWorkflow):
    async def run(self, ctx: AgentWorkflowContext) -> None:
        agent = OsmosisAgent(
            name="multiply-agent",
            instructions="Use the multiply tool when arithmetic is required.",
            model=OsmosisRolloutModel(),
            model_settings=ModelSettings(temperature=1.0, max_tokens=4096),
            tools=[multiply],
        )
        session = OsmosisMemorySession(name="multiply-agent")
        await Runner.run(
            agent,
            ctx.prompt,
            session=session,
        )


def _last_text(sample) -> str:
    for item in reversed(sample.messages):
        if item.get("role") != "assistant":
            continue
        content = item.get("content", "")
        if isinstance(content, str):
            return content
        if isinstance(content, list):
            for block in content:
                if isinstance(block, dict):
                    text = block.get("text") or block.get("content")
                    if text:
                        return text
    return ""


class MultiplyGrader(Grader):
    async def grade(self, ctx: GraderContext) -> None:
        for sample_id, sample in ctx.samples.items():
            answer = _last_text(sample)
            reward = 1.0 if ctx.label and ctx.label.strip() in answer else 0.0
            ctx.set_sample_reward(sample_id, reward)
```

<Note>
  OpenAI Agents SDK sessions 持久化的是 conversation items，而不是 Strands-style messages。为 OpenAI Agents rollouts 编写 graders 时，请把 `sample.messages` 当作 runner 的 persisted session items 来检查。
</Note>

## OsmosisRolloutModel

`OsmosisRolloutModel` 是占位符。不要直接调用它，也不要在 rollout 代码中传入固定 policy model name。在 workspace templates 中，采样选项放在 OpenAI Agents `ModelSettings` 中。

```python theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/cli.json"]}}
from agents import ModelSettings
from osmosis_ai.rollout.integrations.agents.openai_agents import (
    OsmosisAgent,
    OsmosisRolloutModel,
)

agent = OsmosisAgent(
    name="assistant",
    model=OsmosisRolloutModel(),
    model_settings=ModelSettings(
        temperature=1.0,
        top_p=1.0,
        max_tokens=4096,
    ),
)
```

运行时，`OsmosisAgent` 会把该占位符替换为指向活跃 Osmosis rollout endpoint 的 model。

<Warning>
  `OsmosisRolloutModel` 与 Strands integration 的占位符 constructor 不同。OpenAI Agents examples 使用 `OsmosisRolloutModel()` 和 `ModelSettings(...)`，而不是 `params={...}` dict。
</Warning>

## Sessions 和 Sample IDs

当 `Runner.run()` 使用 `OsmosisRolloutModel` 时，每次调用请使用恰好一个 `OsmosisMemorySession`。

```python theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/cli.json"]}}
session = OsmosisMemorySession(name="main")
await Runner.run(agent, ctx.prompt, session=session)
```

Session name 会用作 sample ID。如果您的 workflow 为同一个 prompt 运行多个独立 agents，请为每个 session 指定不同 name：

```python theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/cli.json"]}}
planner_session = OsmosisMemorySession(name="planner")
executor_session = OsmosisMemorySession(name="executor")
```

请在 `run()` 内创建 sessions。在活跃 rollout context 之外创建的 session 无法在 rollout run 内复用，因为它没有注册到该 context。

## 从 OpenAI Agents SDK 迁移

如果您已有 OpenAI Agents SDK workflow，可以通过四步迁移：

<Steps>
  <Step title="用 OsmosisAgent 替换 Agent">
    修改 import 和 class：

    ```python theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/cli.json"]}}
    from osmosis_ai.rollout.integrations.agents.openai_agents import OsmosisAgent
    ```

    然后构造 `OsmosisAgent(...)`，而不是 `Agent(...)`。
  </Step>

  <Step title="替换 policy model">
    将固定 model string 替换为 `OsmosisRolloutModel` 占位符：

    ```python theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/cli.json"]}}
    from osmosis_ai.rollout.integrations.agents.openai_agents import OsmosisRolloutModel

    model = OsmosisRolloutModel()
    ```
  </Step>

  <Step title="添加 OsmosisMemorySession">
    在 `AgentWorkflow.run()` 内创建 session，并传给 `Runner.run()`：

    ```python theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/cli.json"]}}
    session = OsmosisMemorySession(name="main")
    await Runner.run(agent, ctx.prompt, session=session)
    ```
  </Step>

  <Step title="包装到 AgentWorkflow 中">
    将 runner call 放入 `AgentWorkflow.run()` 方法。除非 tools、instructions、handoffs 和 agent 行为依赖 out-of-band state，否则保持它们不变。
  </Step>
</Steps>

## 评估

使用普通 eval 命令：

```cli theme={"theme":{"light":"github-light","dark":"github-dark"},"languages":{"custom":["/languages/cli.json"]}}
osmosis eval submit configs/eval/<rollout-name>.toml
```

Eval 期间，平台会把 `openai/osmosis-rollout` 路由到 eval TOML 中 `[experiment].model_path` 指定的 model。训练期间，Osmosis 会把同一个占位符路由到当前训练中的 policy。

## 下一步

<CardGroup cols={2}>
  <Card title="构建 AgentWorkflow" icon="robot" href="/zh/cli/rollout/agent-workflows">
    查看共享的 `AgentWorkflow.run(ctx)` contract。
  </Card>

  <Card title="构建 Graders" icon="scale-balanced" href="/zh/cli/rollout/graders">
    为 OpenAI Agents session samples 编写 reward 逻辑。
  </Card>

  <Card title="评估" icon="flask-vial" href="/zh/cli/rollout/eval">
    在训练前为您的 OpenAI Agents rollout 提交 evaluation run。
  </Card>
</CardGroup>
