# Contributor Guide
This guide helps new contributors get started with the OpenAI Agents Python repository. It covers repo structure, how to test your work, available utilities, and guidelines for commits and PRs.
**Location:** `AGENTS.md` at the repository root.
## Table of Contents
1. [Policies & Mandatory Rules](#policies--mandatory-rules)
2. [Project Structure Guide](#project-structure-guide)
3. [Operation Guide](#operation-guide)
4. [Code Review Rules](#code-review-rules)
## Policies & Mandatory Rules
### Mandatory Skill Usage
Repository skills are stored under `.agents/skills/`. A reference such as `$<skill-name>` in this file is a repository instruction reference, not a request for manual user invocation. When a rule requires a skill, read `.agents/skills/<skill-name>/SKILL.md` completely before taking task actions, follow its instructions, and resolve referenced files relative to that skill directory.
#### `$code-change-verification`
Run `$code-change-verification` before marking work complete when changes affect runtime code, tests, or build/test behavior.
Run it when you change:
- `src/agents/` (library code) or shared utilities.
- `tests/` or add or modify snapshot tests.
- `examples/`.
- Build or test configuration such as `pyproject.toml`, `Makefile`, `mkdocs.yml`, `docs/scripts/`, or CI workflows.
You can skip `$code-change-verification` for docs-only or repo-meta changes (for example, `docs/`, `.agents/`, `README.md`, `AGENTS.md`, `.github/`), unless a user explicitly asks to run the full verification stack.
Treat `$code-change-verification` as the post-review final gate, not as an iterative review check. When `$implementation-final-review` applies, satisfy its clean-review condition before starting the repository-wide format, lint, typecheck, and test stack. Immediately before starting that stack, use available read-only task or process evidence to check for another broad test, typecheck, build, examples, or integration command already running on the same host. When concrete contention is visible, keep making progress on review, remediation, evidence preparation, or focused checks and defer the broad stack until capacity is available. Do not add a repository lock, host-wide mutex, sentinel file, or user-triggered `finalize` step. Lack of host telemetry alone is not a blocker.
#### `$openai-knowledge`
When working on OpenAI API or OpenAI platform integrations in this repo (Responses API, tools, streaming, Realtime API, auth, models, rate limits, MCP, Agents SDK or ChatGPT Apps SDK), use `$openai-knowledge` to pull authoritative docs via the OpenAI Developer Docs MCP server (and guide setup if it is not configured).
#### `$implementation-strategy`
Before changing or reviewing runtime code, exported APIs, external configuration, persisted schemas, wire protocols, or other user-facing behavior, use `$implementation-strategy` to decide the compatibility boundary and implementation shape. Before coding, write an implementation scope contract that states the required behavior, compatibility requirements, intentionally unsupported cases and their failure behavior, and an already-supported alternative for those cases or that none exists. Treat this contract as a short, updateable engineering decision record, not as a new public API promise. During review, use the skill before requesting compatibility layers, migrations, new abstractions, or broader refactors.
Repeat the skill before editing each new review-feedback batch; an earlier strategy decision is stale when a comment would widen the supported contract or add another compatibility branch, resolver condition, or test permutation. Judge breaking changes against the latest release tag, not unreleased branch-local churn. Interfaces introduced or changed after the latest release tag may be rewritten without compatibility shims unless they define a released or explicitly supported durable external state boundary, or the user explicitly asks for a migration path. Unreleased persisted formats on `main` may be renumbered or squashed before release when intermediate snapshots are intentionally unsupported.
Independent reviewers dispatched by `$implementation-final-review` inherit the implementer's recorded implementation scope contract and do not rerun `$implementation-strategy` in their fresh review contexts. They report inconsistent or decision-incomplete strategy evidence as uncertainty to the implementer. The implementer remains responsible for rerunning `$implementation-strategy` before any review-feedback batch that widens the supported contract, adds a compatibility branch, changes ownership or protocol behavior, expands test permutations, or triggers a complexity reset.
#### `$implementation-final-review`
After implementing runtime code, tests, examples, build/test behavior, or behavior-impacting docs and completing focused tests, run `$implementation-final-review` before final `$code-change-verification` and `$pr-draft-summary` work and before declaring the task complete. Do not start repository-wide lint, typecheck, tests, builds, examples, or integration suites while the independent review is incomplete or finding-bearing. This repository instruction authorizes automatic invocation without a separate user mention. Do not invoke it for planning, investigation, review, or report-only tasks, repo-meta changes, or docs without behavior impact. The skill's clean-review gate does not replace any other mandatory repository skill or verification gate.
#### `$pr-draft-summary`
Before every final response for a task that changed runtime code, tests, examples, build/test configuration, or docs with behavior impact, invoke `$pr-draft-summary` to generate the required PR summary block, branch suggestion, title, and draft description. Determine whether to invoke it from the changed files, not from a subjective assessment of change size.
Skip `$pr-draft-summary` only for trivial or conversation-only tasks, repo-meta/doc-only tasks without behavior impact, an explicitly invoked `$release-candidate-prep` handoff that uses the complete `$final-release-review` report as its release-specific PR description, or when the user explicitly says not to include the PR draft block. The release exception applies to preparing the candidate itself, not to implementing or changing the release-preparation skill.
Producing the PR draft block is part of the local final handoff. It is required for eligible local-only or uncommitted changes and does not authorize creating a branch, committing, pushing, or opening a pull request.
#### `$release-candidate-prep`
Use `$release-candidate-prep` only when the user explicitly invokes it with a release version. It keeps the user's clean `main` checkout unchanged, creates a dedicated detached worktree at refreshed `origin/main`, runs the readiness gates there, creates `release/v<version>` in that worktree, updates `pyproject.toml` and `uv.lock`, freezes and checks `tests/fixtures/released_api_contract.json`, and creates one local release commit. It invokes `$final-release-review` as the controlling checker against both the pre-release source and the materialized candidate; a blocked release call stops the workflow, while a green final-candidate report becomes the release-specific PR description.
The skill replaces the former GitHub Actions release-PR creator. It must never push, open or edit a pull request, create a release, or mutate any other GitHub state. It leaves the dedicated worktree in place for green handoff, blocked review, or recoverable failure. Release tag creation and PyPI publication remain owned by their post-merge workflows. The release commit may contain only `pyproject.toml`, `uv.lock`, and `tests/fixtures/released_api_contract.json`; all runtime and documentation changes must land on `main` before preparation.
### Work Status Reporting
- Use `RUNNING` only in commentary while autonomous work remains and no user action is required. Do not end a turn with a final response that says the task is still running or asks the user to send a generic continuation prompt.
- Use `COMPLETE` in the final response only when the requested work and every applicable review, verification, and local handoff step are complete.
- Use `NEEDS_DECISION` in the final response only when progress requires a concrete user choice, expanded authority, or an unresolved external condition. State the exact decision or condition instead of asking the user to say "continue".
### Git Worktree and Branch Safety
Work in the user's current checkout and on the current branch by default. If the Codex task is already running in a selected Git worktree, use that worktree without requesting additional permission. Do not create or switch to another Git worktree, and do not create or switch branches, unless the user explicitly asks for or approves that exact action in the current conversation. A request to implement, investigate, review, test, or verify changes does not by itself authorize changing the active worktree or branch.
If isolation or a different checkout is needed, explain why and ask the user before changing Git state. This requirement also applies when another rule or workflow recommends a linked worktree: stop and request approval instead of choosing or creating one automatically.
### Documentation Release Timing
When a feature or bug fix introduces behavior that is not yet available in the latest published release, do not include `docs/` changes that describe that unreleased behavior in the feature or bug-fix pull request, and do not expect those changes as part of that pull request. Handle them in a separate docs-only pull request so maintainers can coordinate its merge timing with the release that makes the documentation accurate. This exception applies only when the documentation would be incorrect for the latest published release; documentation that is already accurate for released behavior remains part of the normal change scope.
### Documentation Verification Tiers
Classify documentation changes before choosing review and verification work. Use the narrowest tier that covers the complete diff, and move to a higher tier when any changed file or claim requires it.
- **Editorial:** Terminology, spelling, punctuation, formatting, or link-label changes that do not change documented behavior, runnable code, navigation, link targets, anchors, or generated reference content. Inspect the diff, run targeted searches for the corrected text, and run `git diff --check`. Check a link or anchor directly only when the edit can affect it. Skip `$implementation-final-review`, cross-language review, and `make build-docs` for this tier.
- **Content:** New or materially rewritten behavioral guidance, migration instructions, or runnable snippets that do not change documentation structure or tooling. Verify claims against the implementation and authoritative sources, execute or otherwise validate changed snippets when practical, perform the required focused cross-language review, and run `make build-docs` once after the content and review are stable. Do not repeat the full site build after edits that cannot affect its result.
- **Structural:** Added, removed, renamed, or moved pages; changes to `mkdocs.yml`, generated API reference inputs, documentation scripts, plugins, or build configuration. Run the relevant generators or focused tooling checks and `make build-docs` after the structure is stable. Apply `$code-change-verification` when the changed file is build or test configuration covered by that skill.
Existing warnings from a successful documentation build are not findings for an unrelated docs change. Evaluate the exit status and identify new errors, broken references, or warnings caused by the diff instead of reviewing the complete warning stream line by line. Reserve `make build-full-docs` and generated translation output for translation-tooling changes, explicit localization work, or a specifically requested broad localization audit.
### Scope Discipline and Complexity Reset
- Implement the narrowest explicitly stated set of behaviors that satisfies the request. Do not interpret every shape accepted by a host-language protocol, third-party library, or reflection API unless those shapes are required by the task or supported behavior shipped in the latest release.
- Prefer adapting the required case into an existing pipeline over creating a parallel contract, resolver, execution path, or source of truth. Continue to derive schema, validation, naming, documentation, and invocation from the existing source-of-truth functions, types, or modules.
- Every new abstraction, state field, cached classification, compatibility branch, or dispatch mode must map to a stated requirement, released contract, durable boundary, or verified runtime risk. Remove it if that mapping cannot be stated concretely.
- Treat a second related review finding that would add another condition, protocol hop, compatibility case, or test permutation to the same abstraction as a mandatory complexity-reset checkpoint, not another item to patch. Continue the design only when concrete evidence shows that the additional case belongs to the supported contract.
- When that signal appears, stop extending the current design. Re-read the original requirement, group all findings by root cause, compare the complete diff with the merge base of the intended target branch or with the latest release tag when it is the compatibility baseline, and replace branch-local machinery with a narrower contract. Existing unreleased code and tests are not sunk costs. Perform this reset proactively; do not wait for the user or reviewer to request it.
- A released-version reproducer proves reachability, not a supported contract. Verify the exact shape against documentation, tests, examples, intentional public typing, explicit maintainer intent, or concrete user reliance before adding compatibility machinery.
- Prefer an actionable error during construction or validation, before invocation or other side effects, and an existing supported alternative (for example a wrapper function, explicit override, or typed adapter) over partially emulating a broad protocol. Do not add another alternative when an adequate supported one already exists.
- A growing diff is not itself proof of overengineering, but unexpected cross-module spread, duplicated metadata, combinatorial tests, or repeated special cases requires restarting the design review from the original requirement before more code is added.
- Before handoff, verify that the patch has one source of truth per concern, tests the required behavior and intentionally unsupported cases, and does not accidentally make every constructible combination part of the supported SDK behavior.
### ExecPlans
Call out compatibility risk early in your plan only when the change affects behavior shipped in the latest release tag or a released or explicitly supported durable external state boundary, and confirm the approach before implementing changes that could impact users.
Use an ExecPlan when work is multi-step, spans several files, involves new features or refactors, or is likely to take more than about an hour. Start with the template and rules in `PLANS.md`, keep milestones and living sections (Progress, Surprises & Discoveries, Decision Log, Outcomes & Retrospective) up to date as you execute, and rewrite the plan if scope shifts. Call out compatibility risk only when the plan changes behavior shipped in the latest release tag or a released or explicitly supported durable external state boundary. Do not treat branch-local interface churn or unreleased post-tag changes on `main` as breaking by default; prefer direct replacement over compatibility layers in those cases, and renumber or squash unreleased persisted schemas before release when the intermediate snapshots are intentionally unsupported. If you intentionally skip an ExecPlan for a complex task, note why in your response so reviewers understand the choice.
### Public API Compatibility
Treat the parameter and dataclass field order of exported runtime APIs as a compatibility contract.
- For public constructors (for example `RunConfig`, `FunctionTool`, `AgentHookContext`), preserve existing positional argument meaning. Do not insert new constructor parameters or dataclass fields in the middle of existing public order.
- When adding a new optional public field/parameter, append it to the end whenever possible and keep old fields in the same order.
- If reordering is unavoidable, add an explicit compatibility layer and regression tests that exercise the old positional call pattern.
- Prefer keyword arguments at call sites to reduce accidental breakage, but do not rely on this to justify breaking positional compatibility for public APIs.
- Treat intended import paths and `__all__` membership as compatibility contracts. When adding or moving a public symbol, update the owning module, intended top-level or subpackage re-exports, and an import regression test. Keep top-level imports free of optional-dependency failures and runtime side effects; use lazy exports when needed.
### Platform, Docs, and Security Review
- Treat translation-safe English as a documentation compatibility requirement. In new or materially rewritten translatable prose under `docs/` (excluding generated API reference pages), state the actor, scope, ownership, ordering, modality, and lifecycle boundary explicitly whenever they affect the meaning. Use exact API identifiers in inline code, and replace ambiguous pronouns, overloaded nouns, or shorthand when a small clarification can prevent a materially different translation. Do not change the documented behavior merely to make a sentence easier to translate.
- For new or materially rewritten translatable prose, use a lightweight cross-language review of only the changed English sentences and their immediate context. Have an independent reviewer or review pass inspect the source from Japanese, Korean, and Chinese translation perspectives and report only concrete risks such as an ambiguous actor, scope, ownership, ordering, modality, lifecycle boundary, overloaded SDK term, or identifier corruption. Resolve concrete findings in the English source and review the revised lines once. Do not generate full localized pages for routine documentation changes. Pure link, formatting, typo, and other edits that do not change translatable meaning may skip this review.
- If a concrete concern cannot be resolved confidently from the English source, use a temporary translation of only the disputed sentence or paragraph as a focused probe; do not write or commit generated localized files. Reserve `docs/scripts/translate_docs.py --mode full --file <path>` and broader Japanese, Korean, and Chinese output review for changes to the translation tooling or translation controls, explicit localization work, or an explicitly requested broad translation audit. Add or change a fixed translation mapping only when actual cross-document evidence shows that one stable target term is correct across contexts. Prefer contextual guidance and established target-language developer terminology, including standard English terms, over a large or rigid mapping table.
- Treat runnable docs snippets as API compatibility checks. Before adding OpenAI API, provider, Responses, Realtime, WebSocket, or SDK constructor examples, verify the shown arguments and call shape against the actual implementation.
- When adding or updating code in `examples/` or runnable `docs/` snippets, import Agents SDK decorators from `agents.decorators`. Prefer `tool` over `function_tool`; keep non-decorator SDK imports on their existing public import paths.
- Do not let untrusted sandbox manifests opt themselves out of host filesystem or base-directory boundaries. Escape hatches for local source materialization must be controlled by trusted application code at the call site, not by serialized manifest data.
- When documenting sandbox or security grants, verify the actual implementation path enforces the grant or boundary. Do not claim a grant applies to `LocalDir`, `LocalFile`, archive extraction, or other materialization paths unless those paths actually consult it.
- When redacting OpenAI tool, MCP, model, or provider payloads, consider traceback display, exception chaining, `__context__`, logs, and telemetry. Suppressing display with `raise ... from None` is not enough if the original exception object still carries sensitive input data.
- For OpenAI platform or SDK-specific docs changes, prefer `$openai-knowledge` for authoritative platform behavior and inspect the local code path for SDK behavior. Do not rely on generic API assumptions when documenting Responses, Chat Completions, Realtime, tools, MCP, or provider adapters.
- For Realtime tracing changes, read [Realtime tracing architecture](.agents/references/realtime-tracing.md) before proposing SDK spans. Realtime API server traces and Agents SDK client traces are separate; `group_id` can correlate them but does not create a shared trace hierarchy.
## Project Structure Guide
### Overview
The OpenAI Agents Python repository provides the Python Agents SDK, examples, and documentation built with MkDocs. Use `uv run python ...` for Python commands to ensure a consistent environment.
### Repo Structure & Important Files
- `src/agents/`: Core library implementation.
- `tests/`: Test suite; see `tests/README.md` for snapshot guidance.
- `examples/`: Sample projects showing SDK usage.
- `docs/`: MkDocs documentation source; do not edit translated docs under `docs/ja`, `docs/ko`, or `docs/zh` (they are generated).
- `docs/scripts/`: Documentation utilities, including translation and reference generation.
- `mkdocs.yml`: Documentation site configuration.
- `Makefile`: Common developer commands.
- `pyproject.toml`, `uv.lock`: Python dependencies and tool configuration.
- `.github/PULL_REQUEST_TEMPLATE/pull_request_template.md`: Pull request template to use when opening PRs.
- `.agents/references/`: Durable SDK maintainer architecture references. Start with [the reference map](.agents/references/README.md) and open only the files relevant to the affected runtime boundary.
- `site/`: Built documentation output.
### Agents Core Runtime Guidelines
- For `Agent` fields, cloning, dynamic instructions, enabled tools or handoffs, output schemas, run context wrappers, usage aggregation, or public-versus-internal agent identity, read [Agent definition and run context](.agents/references/agent-definition-and-run-context.md).
- `src/agents/run.py` is the runtime entrypoint (`Runner`, `AgentRunner`). Keep it focused on orchestration and public flow control. Put new runtime logic under `src/agents/run_internal/` and import it into `run.py`.
- When `run.py` grows, refactor helpers into `run_internal/` modules (for example `run_loop.py`, `turn_resolution.py`, `tool_execution.py`, `session_persistence.py`) and leave only wiring and composition in `run.py`.
- For turn accounting, guardrail ordering, handoffs, interruptions, cancellation, hooks, or streaming behavior, read [Runner lifecycle](.agents/references/runner-lifecycle.md). Keep streaming and non-streaming paths behaviorally aligned.
- For new model output, tool call, approval, or run item variants, read [Run item lifecycle](.agents/references/run-item-lifecycle.md) and update every applicable processing, event, replay, persistence, tracing, and serialization surface.
- For function-tool parameter schemas, `Annotated` or `Field` metadata, strict JSON schema conversion, or structured output schemas, read [Function and output schema](.agents/references/function-and-output-schema.md).
- For function-tool naming, namespacing, lookup, approvals, tracing, or call-ID changes, read [Tool identity and routing](.agents/references/tool-identity.md) and use the canonical helpers in `src/agents/_tool_identity.py` instead of adding local normalization rules.
- For function-tool planning, approval ordering, tool guardrails, concurrency, cancellation, timeouts, hooks, or failure conversion, read [Tool execution lifecycle](.agents/references/tool-execution-lifecycle.md).
- For local MCP connection ownership, `MCPServerManager`, request serialization, tool caching or filtering, transport retries, cancellation, or cleanup, read [Local MCP server lifecycle](.agents/references/local-mcp-server-lifecycle.md).
- For trace or span context, processors, export, flush, shutdown, sensitive data, or resumed trace state, read [Tracing lifecycle](.agents/references/tracing-lifecycle.md).
- For `RealtimeSession` lifecycle, background-task, handoff, listener, connection, or cleanup changes, read [Realtime session lifecycle](.agents/references/realtime-session-lifecycle.md) and verify both normal and failure-path resource ownership.
- For `VoicePipeline`, streamed audio input, STT session ownership, TTS task ordering, voice lifecycle events, PCM framing, or voice tracing changes, read [Voice pipeline lifecycle](.agents/references/voice-pipeline-lifecycle.md).
- For server-managed conversation (`conversation_id`, `previous_response_id`, `auto_previous_response_id`), read [Conversation state ownership](.agents/references/conversation-state-ownership.md) before changing continuation, filtering, retry, compaction, handoffs, or resume behavior.
- For client-managed session input, per-turn saves, retry rewind, backend atomicity, or compaction replacement, read [Session persistence](.agents/references/session-persistence.md).
- For model resolution, `ModelSettings`, provider adapters, Responses versus Chat Completions capabilities, request conversion, terminal events, transport reuse, or model retries, read [Model and provider boundaries](.agents/references/model-provider-boundaries.md).
- If the serialized `RunState` shape changes, read [RunState schema and resume boundary](.agents/references/runstate-schema.md) and follow its release-boundary, schema-version, backward-read, and regression-test rules.
- For sandbox session ownership, agent preparation, manifests, host-path materialization, snapshots, resume state, or cleanup, read [Sandbox runtime boundary](.agents/references/sandbox-runtime-boundary.md).
## Operation Guide
### Prerequisites
- Python 3.10+.
- `uv` installed for dependency management (`uv sync`) and `uv run` for Python commands.
- `make` available to run repository tasks.
### Development Workflow
1. Stay in the user's current checkout and on the current branch unless the user explicitly asks for or approves a Git state change.
2. If the user explicitly requests a feature/fix branch, create one with a descriptive name:
```bash
git checkout -b feat/<short-description>
```
3. If dependencies changed or you are setting up the repo, run `make sync`.
4. Implement changes and add or update tests alongside code updates.
5. Highlight compatibility or API risks in your plan before implementing changes that alter the latest released behavior or a released or explicitly supported durable external state boundary.
6. Verify documentation changes according to [Documentation Verification Tiers](#documentation-verification-tiers). Do not run a full documentation build for an editorial-only change.
7. When `$code-change-verification` applies, run it to execute the full verification stack before marking work complete.
8. Commit with concise, imperative messages; keep commits small and focused, then open a pull request.
9. Before reporting eligible code changes as complete, invoke `$pr-draft-summary` as the final handoff step unless the task falls under the documented skip cases. Do not omit it based on perceived change size or because the work remains local or uncommitted.
### Testing & Automated Checks
Before submitting changes, ensure relevant checks pass and extend tests when you touch code.
For provider-neutral agent workflow tests, prefer `ScriptedModel` from `agents.testing` over adding a new mock or fake `Model`. Prefer `ScriptedRealtimeModel` from `agents.realtime.testing` for Realtime session tests, the scripted utilities from `agents.voice.testing` for Voice pipeline tests, and `scripted_sandbox_session()` from `agents.testing` for deterministic Sandbox session calls. Keep a specialized test double only when the test specifically requires provider-wire conversion, malformed streams, controlled suspension or concurrency, or an exact cancellation or lifecycle boundary that the scripted utilities cannot preserve; document that boundary in the test.
Before adding or changing async, retry, timeout, subprocess, PTY, warning, or xdist-sensitive tests, read [Performance and determinism](tests/README.md#performance-and-determinism) and preserve the applicable behavioral and lifecycle coverage while optimizing execution.
When `$code-change-verification` applies, run it to execute the required verification stack from the repository root. Rerun the full stack after applying fixes.
#### Unit tests and type checking
- Run the full test suite:
```bash
make tests
```
- Run a focused test:
```bash
uv run pytest -s -k <pattern>
```
- Type checking:
```bash
make typecheck
```
#### Snapshot tests
Some tests rely on inline snapshots; see `tests/README.md` for details. Re-run `make tests` after updating snapshots.
- Fix snapshots:
```bash
make snapshots-fix
```
- Create new snapshots:
```bash
make snapshots-create
```
#### Coverage
- Generate coverage (fails if coverage drops below threshold):
```bash
make coverage
```
#### Formatting, linting, and type checking
- Formatting and linting use `ruff`; run `make format` (applies fixes) and `make lint` (checks only).
- Type hints must pass `make typecheck`.
- Write comments as full sentences ending with a period.
- Imports are managed by Ruff and should stay sorted.
- Do not hard-wrap prose in Markdown or other non-code text files at a fixed column width. Keep each paragraph on one source line unless the file format or Markdown structure requires a line break, such as for lists, tables, blockquotes, or code fences.
#### Mandatory local run order
When `$code-change-verification` applies, run the full sequence in order (or use the skill scripts):
```bash
make format
make lint
make typecheck
make tests
```
### Utilities & Tips
- Install or refresh development dependencies:
```bash
make sync
```
- Run tests against the oldest supported version (Python 3.10) in an isolated environment:
```bash
UV_PROJECT_ENVIRONMENT=.venv_310 uv sync --python 3.10 --all-extras --all-packages --group dev
UV_PROJECT_ENVIRONMENT=.venv_310 uv run --python 3.10 -m pytest
```
- Documentation workflows:
```bash
make build-docs # build stable content or structural docs changes
make serve-docs # preview docs locally
make build-full-docs # run translations and build when explicitly required
```
- Snapshot helpers:
```bash
make snapshots-fix
make snapshots-create
```
- Use `examples/` to see common SDK usage patterns.
- Review `Makefile` for common commands and use `uv run` for Python invocations.
- Explore `docs/` and `docs/scripts/` to understand the documentation pipeline.
- Consult `tests/README.md` for test and snapshot workflows.
- Check `mkdocs.yml` to understand how docs are organized.
### Pull Request & Commit Guidelines
- Use the template at `.github/PULL_REQUEST_TEMPLATE/pull_request_template.md`; include a summary, test plan, and issue number if applicable.
- In copy-ready GitHub text, use native issue and pull-request references: exactly `#123` for this repository and `owner/repo#123` for another repository. Do not qualify same-repository references as `openai/openai-agents-python#123`. Preserve closing forms such as `Fixes #123` or `Resolves #123`. Never wrap these references in Markdown links such as `[PR #123](https://github.com/owner/repo/pull/123)` or `[#123](...)`; those Codex-friendly links require manual cleanup after pasting into GitHub. Use descriptive Markdown links only for external resources or GitHub targets that cannot be expressed as a native issue or pull-request reference.
- Add tests for new behavior when feasible. Update documentation for user-facing changes, except unreleased-behavior documentation that must follow the separate docs-only pull request policy above.
- Run `make format`, `make lint`, `make typecheck`, and `make tests` before marking work ready.
- Commit messages should be concise and written in the imperative mood. Small, focused commits are preferred.
## Code Review Rules
- Use `$implementation-strategy` to establish the requested outcome and latest released compatibility boundary before judging implementation scope or architecture.
- Treat added complexity as an actionable finding only when specific machinery is not required by the task, a released contract, supported durable state, or a verified runtime or platform risk. Identify the unnecessary machinery and recommend the smallest safe removal or direct replacement.
- Do not request speculative abstractions, general-purpose helpers, configuration knobs, dependencies, compatibility layers, feature flags, parallel code paths, or extensibility for hypothetical future consumers.
- Do not process a sequence of related review comments as independent local fixes when they expose the same missing boundary. Classify them together, decide whether the disputed shapes belong to the supported contract, and prefer one narrowing redesign over accumulating branches.
- Review the complete diff from the merge base of the intended target branch, or from the latest release tag when it is the compatibility baseline, not only the latest incremental fix. Passing tests do not justify branch-local machinery that no longer matches the original requirement.
- Keep findings scoped to the patch. Do not block on unrelated cleanup, pre-existing bugs, or optional refactors; report them separately when useful.
- Require a broader refactor only when concrete evidence shows the focused change would otherwise be incorrect, unsafe, incompatible, or materially harder to maintain.
### Baseline review expectations
- โ
Checks pass (`make format`, `make lint`, `make typecheck`, `make tests`).
- โ
Tests cover new behavior and edge cases.
- โ
Code is readable, maintainable, and consistent with existing style.
- โ
Examples are updated if behavior changes.
- โ
History is clean with a clear PR description.
---
name: release-candidate-prep
description: Preflight and prepare an OpenAI Agents Python release candidate in a dedicated worktree from exact origin/main, gate readiness before branch creation, freeze the released API contract, create or replace the local release branch with one release commit, enforce final release review as a checker, and produce release-specific PR text. Use only when explicitly invoked with a version. Never push, open a PR, or mutate GitHub.
---
# Release Candidate Preparation
Use this skill only when the user explicitly invokes `$release-candidate-prep` and supplies a release version without a leading `v`, for example `VERSION=0.20.1`. This skill replaces the removed GitHub Actions release-PR creator with a reviewed local workflow.
## Non-negotiable boundaries
- Treat explicit invocation as authorization to fetch `origin/main`, create one dedicated detached release worktree, run branch-free release-readiness gates there, create or replace the local `release/v<version>` in that worktree only after those gates pass, update the three release-owned files, and create one local commit. If the branch already exists locally or remotely, the required final local state is still exact current `origin/main` plus only the new release commit; an existing local branch may be replaced only when it is not checked out in another worktree.
- Keep the user's source checkout on its existing clean `main` commit. Do not fast-forward it, switch its branch, or materialize release files there. Leave the dedicated release worktree in place for green handoff, blocked review, or recoverable failure.
- Never push, open or edit a pull request, add labels or milestones, create a release, or otherwise mutate GitHub. Never run `gh`.
- Own exactly `pyproject.toml`, `uv.lock`, and `tests/fixtures/released_api_contract.json`. Runtime, documentation, workflow, or other repository changes must land on `main` before release preparation.
- Do not stash, delete, overwrite or remove an existing worktree, or work around unrelated local changes. Fail before branch creation when the initial checkout is dirty or is not on `main`, the dedicated worktree is not clean and detached at refreshed `origin/main`, an existing local release branch is checked out in another worktree, the prospective packaged-contract gate fails after the allowed dependency-bootstrap recovery, the planning review blocks, or `origin/main` advances after those gates run.
- Treat `$final-release-review` as the controlling release checker, not only as a report generator. Its planning gate must be green before branch creation, and its final-candidate gate must inspect the materialized worktree and be green before PR-ready handoff. Any candidate content, commit, or base change invalidates the previous green result.
- Remove inherited `OPENAI_API_KEY` from every child command. Release preparation does not require a live OpenAI API request.
- Stop after the local commit, final release review, and copy-ready handoff. The user owns the push and pull-request creation.
## 1. Establish the release input
Require one semver-like version without a leading `v`. Do not infer a version from milestones, branch names, or local modifications. Announce that the skill will create and retain a dedicated release worktree with one local commit, keep the source checkout unchanged, and not write to GitHub.
Read `$final-release-review` completely before starting. Its final-candidate report is the release pull request description. Do not use `$pr-draft-summary` for the release candidate itself; this skill owns the fixed release branch, commit subject, title, and description. Continue to use `$pr-draft-summary` normally when implementing changes to this skill or other repository behavior.
## 2. Create an isolated branch-free preflight input
From the repository root, run:
```bash
env -u OPENAI_API_KEY -u GITHUB_TOKEN -u GH_TOKEN UV_DEFAULT_INDEX=https://pypi.org/simple uv run --frozen python .agents/skills/release-candidate-prep/scripts/prepare.py preflight --version <version> --worktree-root <codex-worktree-root>
```
The helper must complete all of these operations or fail with an actionable error while leaving the source checkout on its original `main` commit:
1. Verify the repository root, `main` branch, and clean working tree.
2. Inspect whether `release/v<version>` exists locally or remotely. Permit replacement, but fail if the local branch is checked out in another worktree.
3. Fetch `main` into `origin/main` without merging or switching the source checkout.
4. Choose a unique task-oriented path under the configured Codex worktree root. Check both the filesystem and `git worktree list`; never reuse or delete a collision.
5. Create a detached worktree at exact refreshed `origin/main`, then require that worktree to be clean, detached, and at the exact 40-character base commit.
6. Recheck that an existing local release branch remains replaceable and require the source checkout to remain clean on `main` at its original commit.
7. Print the exact base commit, unchanged source-checkout commit, planned branch, and dedicated worktree path for both readiness gates and later materialization.
Record the base commit as `<preflight-base>`, the source-checkout commit as `<source-head>`, and the path as `<release-worktree>`. Do not create or switch branches yet. Keep the detached worktree if a later gate blocks so its exact reviewed source remains inspectable.
## 3. Run the branch-free readiness gates
Bootstrap the dedicated worktree before starting either readiness gate:
```bash
env -u OPENAI_API_KEY -u GITHUB_TOKEN -u GH_TOKEN UV_DEFAULT_INDEX=https://pypi.org/simple make sync
```
This dependency installation is mandatory environment preparation, not candidate materialization. It matches the prospective-contract CI job, which installs all optional dependencies before generating the contract. After synchronization, require `<release-worktree>` to remain clean except for ignored environment or `.tmp` output. If synchronization changes a tracked or untracked repository path, stop with that evidence instead of treating the changed checkout as the reviewed source.
Run both gates against exact `<preflight-base>` before materializing any candidate:
1. Start the prospective packaged-contract gate from `<release-worktree>`:
```bash
env -u OPENAI_API_KEY -u GITHUB_TOKEN -u GH_TOKEN UV_DEFAULT_INDEX=https://pypi.org/simple make check-prospective-released-api-contract
```
2. Invoke `$final-release-review` from `<release-worktree>` in **pre-release planning** mode with `TARGET=<preflight-base>` and the requested version as the release intent. Require its release-checker result to be **GREEN LIGHT TO SHIP**. Keep the target pinned to the commit rather than allowing a later `origin/main` refresh to change the reviewed source, and require all local source, contract, and package inspection to use the dedicated worktree.
These gates are independent consumers of the same clean source commit. Start the prospective command as a long-running session and perform the read-only planning review while it runs when the execution environment supports overlap. Wait for both results before continuing. If concurrency is unavailable, run them sequentially with the prospective gate first; correctness must not depend on overlap.
If the prospective command reports only that optional dependency modules are unavailable, treat the result as a recoverable environment-bootstrap failure rather than a contract-gate decision. Do not ask the user to choose between synchronization and fixing `main`. Rerun the credential-free `make sync` command, require the worktree to remain clean, and retry the prospective command exactly once. Do not use this recovery for a contract mismatch, packaging or runtime compatibility failure, changed repository path, or any other substantive gate failure.
If dependency synchronization still fails, the prospective command still reports unavailable dependency modules after the single retry, or either gate otherwise fails or blocks, stop without creating `release/v<version>`, leave the source checkout unchanged, retain the detached worktree, and report its path plus the exact failure or the planning review's unblock checklist. Classify a dependency installation failure as environment or dependency setup, a contract-generation mismatch as public-surface or `tests/fixtures/released_api_contract_policy.json` work on `main`, and a packaged compatibility failure by its actual failing source, packaging, platform, or runtime path. A blocked planning review should direct runtime or documentation-timing follow-up to `main` as applicable. Do not continue merely because the review produced a well-formed report.
After both gates pass, require all of the following before materialization:
- The source checkout is still clean on `main` at the same commit it had before preflight.
- `<release-worktree>` is clean except for ignored `.tmp` output, remains detached, and has `HEAD == <preflight-base>`.
- The planning review's green gate applies to `<preflight-base>` and the requested release intent.
## 4. Materialize the uncommitted candidate
Run:
```bash
env -u OPENAI_API_KEY -u GITHUB_TOKEN -u GH_TOKEN UV_DEFAULT_INDEX=https://pypi.org/simple uv run --frozen python .agents/skills/release-candidate-prep/scripts/prepare.py materialize --version <version> --expected-base <preflight-base> --expected-source-head <source-head> --worktree <release-worktree>
```
The helper must complete all of these operations or fail with an actionable error:
1. Repeat the source-root, clean `main`, version, registered-worktree, detached-HEAD, and release-branch replaceability checks.
2. Refresh `origin/main` again without moving the source checkout.
3. Require refreshed `origin/main` and `<release-worktree>` HEAD to equal `<preflight-base>`. If `origin/main` advanced, retain the old detached worktree and rerun preflight plus both readiness gates in a new exact-base worktree.
4. Keep the worktree detached while updating the single project version declaration in `pyproject.toml`.
5. Run `make sync` with `UV_DEFAULT_INDEX=https://pypi.org/simple`.
6. Run `make update-released-api-contract VERSION=<version>` and then `make check-released-api-contract VERSION=<version>`.
7. Require exactly the three release-owned paths to be modified in `<release-worktree>`, leave them unstaged and uncommitted, and confirm that the source checkout remains unchanged.
8. Only after those candidate checks pass, create or reset the local `release/v<version>` inside `<release-worktree>` to exact `<preflight-base>` while preserving the validated unstaged manifest. Do not retain commits or content from an older local or remote candidate. This delayed replacement must leave an existing local branch unchanged when candidate generation fails.
If the helper fails after branch creation, preserve its local branch, dedicated worktree, and working-tree evidence. Report the failing command and state rather than guessing whether a partial run is safe to resume. Never remove the worktree as automatic cleanup.
## 5. Review and commit the exact release diff
Run the remaining commands from `<release-worktree>`. Inspect all release-owned files before staging:
```bash
git status --short
git diff --check
git diff -- pyproject.toml uv.lock tests/fixtures/released_api_contract.json
```
Confirm all of the following:
- `pyproject.toml` and the editable `openai-agents` entry in `uv.lock` declare the requested version.
- The API contract baseline is `v<version>` and its `baseline_commit` is the exact `origin/main` source commit on which the release branch is based.
- The generated contract preserves the previous release and freezes intended new exports and signatures.
- Any intended `public_properties`, `canonical_imports`, or `public_modules` policy additions have been reviewed explicitly; the updater deliberately does not infer them.
- No path outside the three-file release manifest is changed, staged, or untracked.
Stage only the manifest and create exactly one local commit:
```bash
git add pyproject.toml uv.lock tests/fixtures/released_api_contract.json
git commit -m "release: <version>"
```
Do not amend unrelated content into the commit.
## 6. Run the final-candidate release review
Invoke `$final-release-review` from `<release-worktree>` in final-candidate mode with the release commit as `TARGET=HEAD`. This invocation is a release checker: it must inspect the complete candidate diff and the actual checked-out `release/v<version>` contents, including `pyproject.toml`, the editable `openai-agents` entry in `uv.lock`, and `tests/fixtures/released_api_contract.json`. The branch, package metadata, lockfile, contract baseline, contract `baseline_commit`, and intended version must agree.
If the review is blocked, stop. Return its unblock checklist, retain the local branch, commit, and worktree for follow-up, and do not present the candidate as PR-ready. A report body does not authorize continuation when the release call is blocked. After any fix, regenerate the API contract when the public surface may have changed, restore a single release commit, and rerun the complete final-candidate review.
The earlier planning review proves that the source commit was ready before branch creation. This final-candidate review remains required because it verifies the materialized branch, version metadata, lockfile, and frozen contract together. Treat its green release call as the handoff gate, then reuse its complete report as the release pull request description; do not substitute the planning report.
## 7. Recheck main freshness
After a green review, fetch `origin main` again without credentials from `<release-worktree>` and compare it with the release commit's parent. If they differ, the candidate is stale. First verify that the branch is clean, has exactly one local commit, and that the commit changes only the three-file release manifest. Rebase that commit onto the new `origin/main` so Git detects any conflicting release metadata. After a clean rebase, move the local release branch back to `origin/main` with a mixed reset, which preserves the rebased release tree as unstaged task-owned changes. Restore all three release-owned files (`pyproject.toml`, `uv.lock`, and `tests/fixtures/released_api_contract.json`) from `origin/main`, run `make sync`, and require the worktree to be clean at the new base. Run `make check-prospective-released-api-contract` only in that internally consistent base state, where the installed project version and frozen contract baseline agree. Then update `pyproject.toml` to `<version>`, run `make sync`, run `make update-released-api-contract VERSION=<version>` and `make check-released-api-contract VERSION=<version>`, review the exact manifest again, and recreate the single `release: <version>` commit. The base and candidate content changed, so the previous green check is invalid: rerun `$final-release-review` from the worktree and require a new green release call. Repeat until the reviewed local branch is exactly one commit ahead of current `origin/main` and that commit changes only the three-file release manifest.
If replay conflicts or another path changes, stop with recoverable evidence. Do not force a resolution that expands the release commit beyond its manifest.
## 8. Produce the release handoff
For a green, current candidate, return the `$final-release-review` report plus this release-specific block in English:
```markdown
# Release Pull Request
## Branch
release/v<version>
## Commit
release: <version>
## Title
Release <version>
## Description
<the complete final-candidate report from $final-release-review>
```
Apply the repository's GitHub paste-readiness rules to the report. Use native `#123` references for this repository and `owner/repo#123` for another repository. Keep the required compare URL. Do not include local paths, Codex citations, operational diagnostics, or app directives inside the copy-ready description.
Also report the dedicated worktree path, local branch, commit SHA, parent `origin/main` commit, and the exact three-file manifest outside the copy-ready block. State explicitly that the source checkout was left unchanged, nothing was pushed, and no pull request was created. Leave the worktree in place for the user's handoff.
If `release/v<version>` already exists on `origin`, inspect its exact current commit with credential-free `git ls-remote --heads origin release/v<version>` immediately before handoff and record it as `<observed-remote-release-commit>`. State explicitly that the local branch has replaced the old candidate and now contains exact current `origin/main` plus only the new `release: <version>` commit. Because this skill never mutates GitHub, provide the user with the exact `git push --force-with-lease=refs/heads/release/v<version>:<observed-remote-release-commit> origin release/v<version>` command to replace the remote branch themselves; never run it. A normal push or an unspecified lease is insufficient for this replacement case. If the remote branch changes after inspection, the explicit lease must reject the push instead of overwriting unseen work.
## Failure behavior
- Preflight or worktree creation failure: leave the source checkout unchanged and do not delete or reuse any colliding worktree.
- Dependency-bootstrap failure: retry unavailable optional dependency setup only as described in the readiness-gate procedure, then retain the detached worktree and return the exact failure if recovery does not succeed.
- Prospective-contract failure after the allowed dependency-bootstrap recovery or blocked planning review: retain the detached worktree, do not create the release branch, and return the exact failure or unblock checklist.
- Materialization failure before successful branch replacement: retain the detached worktree and its uncommitted evidence, and leave any existing local release branch unchanged. Failure after successful branch replacement must retain the worktree, branch, and evidence exactly as left by the failing command.
- Blocked final-candidate review: retain the single release commit and worktree, do not call the candidate PR-ready, and return the checker-derived unblock checklist.
- Freshness conflict or unexpected changed path: stop with recoverable worktree evidence rather than forcing a resolution or expanding the release manifest.
---
name: pr-draft-summary
description: Create the required PR-ready summary block, branch suggestion, title, and draft description for openai-agents-python. Use before the final response whenever the current task changed runtime code, tests, examples, build/test configuration, or docs with behavior impact, regardless of perceived change size and including local-only or uncommitted work. Skip only for trivial or conversation-only tasks, repo-meta/doc-only tasks without behavior impact, an explicitly invoked $release-candidate-prep handoff, or when the user explicitly says not to include the PR draft block.
---
# PR Draft Summary
## Purpose
Produce the PR-ready summary required in this repository after eligible code work is complete: a concise summary plus a PR-ready title and draft description that begins with "This pull request <verb> ...". The block should be ready to paste into a PR for openai-agents-python.
## When to Trigger
- Before every final response, check whether the current task changed runtime code (`src/agents/`), tests (`tests/`), examples (`examples/`), build/test configuration, or docs with behavior impact.
- If it did, run this skill after required verification and before sending the final response. Do not use perceived change size to decide whether to run it.
- Run it for eligible local-only and uncommitted work even when the user did not ask to create a pull request. Producing this text does not authorize creating a branch, committing, pushing, or opening a pull request.
- Skip only for trivial or conversation-only tasks, repo-meta/doc-only tasks without behavior impact, an explicitly invoked `$release-candidate-prep` handoff that uses the complete `$final-release-review` report as its release-specific PR description, or when the user explicitly says not to include the PR draft block. This exception applies to preparing the release candidate itself, not to implementing or changing the release-preparation skill.
## Inputs to Collect Automatically (do not ask the user)
- Current branch: `git rev-parse --abbrev-ref HEAD`.
- Working tree: `git status -sb`.
- Untracked files: `git ls-files --others --exclude-standard` (use with `git status -sb` to ensure they are surfaced; `--stat` does not include them).
- Changed files: `git diff --name-only` (unstaged) and `git diff --name-only --cached` (staged); sizes via `git diff --stat` and `git diff --stat --cached`.
- Latest release tag (prefer remote-aware lookup): `LATEST_RELEASE_TAG=$(.agents/skills/final-release-review/scripts/find_latest_release_tag.sh origin 'v*' 2>/dev/null || git tag -l 'v*' --sort=-v:refname | head -n1)`.
- Base reference (use the branch's upstream, fallback to `origin/main`):
- `BASE_REF=$(git rev-parse --abbrev-ref --symbolic-full-name @{upstream} 2>/dev/null || echo origin/main)`.
- `BASE_COMMIT=$(git merge-base --fork-point "$BASE_REF" HEAD || git merge-base "$BASE_REF" HEAD || echo "$BASE_REF")`.
- Commits ahead of the base fork point: `git log --oneline --no-merges ${BASE_COMMIT}..HEAD`.
- Category signals for this repo: runtime (`src/agents/`), tests (`tests/`), examples (`examples/`), docs (`docs/`, `mkdocs.yml`), build/test config (`pyproject.toml`, `uv.lock`, `Makefile`, `.github/`).
## Workflow
1) Run the commands above without asking the user; compute `BASE_REF`/`BASE_COMMIT` first so later commands reuse them.
2) If there are no staged/unstaged/untracked changes and no commits ahead of `${BASE_COMMIT}`, reply briefly that no code changes were detected and skip emitting the PR block.
3) Infer change type from the touched paths listed under "Category signals"; classify as feature, fix, refactor, or docs-with-impact, and flag backward-compatibility risk only when the diff changes released public APIs, external config, persisted data, serialized state, or wire protocols. Judge that risk against `LATEST_RELEASE_TAG`, not unreleased branch-only churn.
4) Summarize changes in 1โ3 short sentences using the key paths (top 5) and `git diff --stat` output; explicitly call out untracked files from `git status -sb`/`git ls-files --others --exclude-standard` because `--stat` does not include them. If the working tree is clean but there are commits ahead of `${BASE_COMMIT}`, summarize using those commit messages.
5) Choose the lead verb for the description: feature โ `adds`, bug fix โ `fixes`, refactor/perf โ `improves` or `updates`, docs-only โ `updates`.
6) Suggest a branch name. If already off main, keep it; otherwise propose `feat/<slug>`, `fix/<slug>`, or `docs/<slug>` based on the primary area (e.g., `docs/pr-draft-summary-guidance`).
7) If the current branch matches `issue-<number>` (digits only), keep that branch suggestion. Optionally pull light issue context (for example via the GitHub API) when available, but do not block or retry if it is not. When an issue number is present, use the native same-repository reference `#<number>` and include an auto-closing line such as `This pull request resolves #<number>.`. Do not add the explicit issue URL or wrap the reference in a Markdown link.
8) Draft the PR title and description using the template below. Apply the repository-wide GitHub paste-readiness rule: use exactly `#123` for same-repository issues or PRs and `owner/repo#123` for cross-repository references; never emit `[PR #123](https://github.com/owner/repo/pull/123)`, `[#123](...)`, Codex navigation links, local file links, Codex-only citation markers or footnotes, or app directives in the copy-ready block. Preserve ordinary descriptive links to API docs, design notes, and other targets without native GitHub issue or pull-request syntax.
9) Normalize references before returning the block: replace every same-repository URL or `openai/openai-agents-python#<number>` reference with `#<number>`, replace every cross-repository issue or pull-request URL with `owner/repo#<number>`, then rescan the full block. Do not return it while a Markdown-linked issue or pull-request label, a same-repository qualified reference, or a bare GitHub issue or pull-request URL remains.
10) Output only the block in "Output Format". Keep any surrounding status note minimal and in English.
## Output Format
When closing out a task, add this concise Markdown block (English only) after any brief status note unless the task falls under the documented skip cases or the user says they do not want it.
```
# Pull Request Draft
## Branch name suggestion
git checkout -b <kebab-case suggestion, e.g., feat/pr-draft-summary-skill>
## Title
<single-line imperative title, which can be a commit message; if a common prefix like chore: and feat: etc., having them is preferred>
## Description
<include what you changed plus a draft pull request title and description for your local changes; start the description with prose such as "This pull request resolves/updates/adds ..." using a verb that matches the change (you can use bullets later), explain the change background (for bugs, clearly describe the bug, symptoms, or repro; for features, what is needed and why), any behavior changes or considerations to be aware of, and you do not need to mention tests you ran.>
```
Keep it tightโno redundant prose around the block, and avoid repeating details between `Changes` and the description. Tests do not need to be listed unless specifically requested.
---
search:
exclude: true
---
# ใจใผใธใงใณใ
ใจใผใธใงใณใใฏใใขใใชใฎไธญๆ ธใจใชใๆงๆ่ฆ็ด ใงใใใจใผใธใงใณใใจใฏใๆ็คบใใใผใซใใใใณใใณใใชใใใฌใผใใฌใผใซใstructured outputs ใชใฉใฎไปปๆใฎๅฎ่กๆๅไฝใ่จญๅฎใใๅคง่ฆๆจก่จ่ชใขใใซ๏ผLLM๏ผใงใใ
`SandboxAgent` ใงใฏใชใใๅไธใฎๅบๆฌ `Agent` ใๅฎ็พฉใพใใฏใซในใฟใใคใบใใๅ ดๅใฏใใใฎใใผใธใไฝฟ็จใใฆใใ ใใใ่คๆฐใฎใจใผใธใงใณใใใฉใฎใใใซ้ฃๆบใใใใใๆฑบๅฎใใๅ ดๅใฏใ[ใจใผใธใงใณใใชใผใฑในใใฌใผใทใงใณ](multi_agent.md)ใๅ็
งใใฆใใ ใใใใใใใงในใใงๅฎ็พฉใใใใใกใคใซใจใตใณใใใใฏในใใคใใฃใใฎๆฉ่ฝใๅใใๅ้ขใฏใผใฏในใใผในๅ
ใงใจใผใธใงใณใใๅฎ่กใใๅ ดๅใฏใ[ใตใณใใใใฏในใจใผใธใงใณใใฎๆฆๅฟต](sandbox/guide.md)ใๅ็
งใใฆใใ ใใใ
SDK ใฏใOpenAIใขใใซใซๅฏพใใฆใใใฉใซใใง Responses API ใไฝฟ็จใใพใใใใใใง้่ฆใชใฎใฏใชใผใฑในใใฌใผใทใงใณใงใใ`Agent` ใจ `Runner` ใ็ตใฟๅใใใใใจใงใSDK ใใฟใผใณใใใผใซใใฌใผใใฌใผใซใใใณใใชใใใปใใทใงใณใ็ฎก็ใงใใพใใใใฎใซใผใใ่ช่บซใง็ฎก็ใใๅ ดๅใฏใไปฃใใใซ Responses API ใ็ดๆฅไฝฟ็จใใฆใใ ใใใ
## ๆฌกใฎใฌใคใใฎ้ธๆ
ใใฎใใผใธใฏใใจใผใธใงใณใๅฎ็พฉใฎใใใจใใฆไฝฟ็จใใฆใใ ใใใๆฌกใซๆฑบๅฎใใๅฟ
่ฆใใใๅ
ๅฎนใซๅฟใใฆใ้ข้ฃใใใฌใคใใซ้ฒใใงใใ ใใใ
| ็ฎ็ | ๆฌกใซ่ชญใใฌใคใ |
| --- | --- |
| ใขใใซใพใใฏใใญใใคใใผใฎ่จญๅฎใ้ธๆใใ | [ใขใใซ](models/index.md) |
| ใจใผใธใงใณใใซๆฉ่ฝใ่ฟฝๅ ใใ | [ใใผใซ](tools.md) |
| ๅฎ้ใฎใชใใธใใชใใใญใฅใกใณใไธๅผใใพใใฏๅ้ขใฏใผใฏในใใผในใๅฏพ่ฑกใซใจใผใธใงใณใใๅฎ่กใใ | [ใตใณใใใใฏในใจใผใธใงใณใใฎใฏใคใใฏในใฟใผใ](sandbox_agents.md) |
| ใใใผใธใฃใผๆนๅผใฎใชใผใฑในใใฌใผใทใงใณใจใใณใใชใใฎใฉใกใใไฝฟ็จใใใๆฑบๅฎใใ | [ใจใผใธใงใณใใชใผใฑในใใฌใผใทใงใณ](multi_agent.md) |
| ใใณใใชใใฎๅไฝใ่จญๅฎใใ | [ใใณใใชใ](handoffs.md) |
| ใฟใผใณใฎๅฎ่กใใคใใณใใฎในใใชใผใใณใฐใใพใใฏไผ่ฉฑ็ถๆ
ใฎ็ฎก็ใ่กใ | [ใจใผใธใงใณใใฎๅฎ่ก](running_agents.md) |
| ๆ็ตๅบๅใๅฎ่ก้
็ฎใใพใใฏๅ้ๅฏ่ฝใช็ถๆ
ใ็ขบ่ชใใ | [ๅฎ่ก็ตๆ](results.md) |
| ใญใผใซใซใฎไพๅญ้ขไฟใจๅฎ่กๆ็ถๆ
ใๅ
ฑๆใใ | [ใณใณใใญในใ็ฎก็](context.md) |
## ๅบๆฌ่จญๅฎ
ใจใผใธใงใณใใงๆใไธ่ฌ็ใชใใญใใใฃใฏๆฌกใฎใจใใใงใใ
| ใใญใใใฃ | ๅฟ
้ | ่ชฌๆ |
| --- | --- | --- |
| `name` | ใฏใ | ไบบใ่ชญใใๅฝขๅผใฎใจใผใธใงใณใๅใงใใ |
| `instructions` | ใใใ | ใทในใใ ใใญใณใใใพใใฏๅ็ใชๆ็คบใฎใณใผใซใใใฏใงใใไฝฟ็จใๅผทใๆจๅฅจใใพใใ[ๅ็ใชๆ็คบ](#dynamic-instructions)ใๅ็
งใใฆใใ ใใใ |
| `prompt` | ใใใ | OpenAIใฎ Responses API ็จใใญใณใใ่จญๅฎใงใใ้็ใชใใญใณใใใชใใธใงใฏใใพใใฏ้ขๆฐใๅใๅใใพใใ[ใใญใณใใใใณใใฌใผใ](#prompt-templates)ใๅ็
งใใฆใใ ใใใ |
| `handoff_description` | ใใใ | ใใฎใจใผใธใงใณใใใใณใใชใๅ
ใจใใฆๆ็คบใใใ้ใซๅ
ฌ้ใใใ็ญใ่ชฌๆใงใใ |
| `handoffs` | ใใใ | ไผ่ฉฑใๅฐ้ใจใผใธใงใณใใซๅง่ญฒใใพใใ[ใใณใใชใ](handoffs.md)ใๅ็
งใใฆใใ ใใใ |
| `model` | ใใใ | ไฝฟ็จใใLLMใงใใ[ใขใใซ](models/index.md)ใๅ็
งใใฆใใ ใใใ |
| `model_settings` | ใใใ | `temperature`ใ`top_p`ใ`tool_choice` ใชใฉใฎใขใใซ่ชฟๆดใใฉใกใผใฟใผใงใใ |
| `tools` | ใใใ | ใจใผใธใงใณใใๅผใณๅบใใใใผใซใงใใ[ใใผใซ](tools.md)ใๅ็
งใใฆใใ ใใใ |
| `mcp_servers` | ใใใ | MCPๅฏพๅฟใใผใซใใจใผใธใงใณใใซๆไพใใMCPใตใผใใผใงใใ[MCPใฌใคใ](mcp.md)ใๅ็
งใใฆใใ ใใใ |
| `mcp_config` | ใใใ | ในใญใผใใฎ strict ใขใผใใธใฎๅคๆใMCPใจใฉใผใฎๅฝขๅผ่ชฟๆดใชใฉใMCPใใผใซใฎๆบๅๆนๆณใ่ฉณ็ดฐใซ่ชฟๆดใใพใใ[MCPใฌใคใ](mcp.md#agent-level-mcp-configuration)ใๅ็
งใใฆใใ ใใใ |
| `input_guardrails` | ใใใ | ใใฎใจใผใธใงใณใใใงใผใณใธใฎๆๅใฎใฆใผใถใผๅ
ฅๅใซๅฏพใใฆๅฎ่กใใใใฌใผใใฌใผใซใงใใ[ใฌใผใใฌใผใซ](guardrails.md)ใๅ็
งใใฆใใ ใใใ |
| `output_guardrails` | ใใใ | ใใฎใจใผใธใงใณใใฎๆ็ตๅบๅใซๅฏพใใฆๅฎ่กใใใใฌใผใใฌใผใซใงใใ[ใฌใผใใฌใผใซ](guardrails.md)ใๅ็
งใใฆใใ ใใใ |
| `output_type` | ใใใ | ใใฌใผใณใใญในใใฎไปฃใใใซไฝฟ็จใใๆง้ ๅใใใๅบๅๅใงใใ[ๅบๅๅ](#output-types)ใๅ็
งใใฆใใ ใใใ |
| `hooks` | ใใใ | ใจใผใธใงใณใๅไฝใฎใฉใคใใตใคใฏใซใณใผใซใใใฏใงใใ[ใฉใคใใตใคใฏใซใคใใณใ๏ผใใใฏ๏ผ](#lifecycle-events-hooks)ใๅ็
งใใฆใใ ใใใ |
| `tool_use_behavior` | ใใใ | ใใผใซใฎๅฎ่ก็ตๆใใขใใซใซๆปใใฆใซใผใใ็ถ็ถใใใใๅฎ่กใ็ตไบใใใใๅถๅพกใใพใใ[ใใผใซไฝฟ็จๆใฎๅไฝ](#tool-use-behavior)ใๅ็
งใใฆใใ ใใใ |
| `reset_tool_choice` | ใใใ | ใใผใซไฝฟ็จใซใผใใๅ้ฟใใใใใใใผใซๅผใณๅบใๅพใซ `tool_choice` ใใชใปใใใใพใ๏ผใใใฉใซใ๏ผ`True`๏ผใ[ใใผใซไฝฟ็จใฎๅผทๅถ](#forcing-tool-use)ใๅ็
งใใฆใใ ใใใ |
```python
from agents import Agent
from agents.decorators import tool
@tool
def get_weather(city: str) -> str:
"""returns weather info for the specified city."""
return f"The weather in {city} is sunny"
agent = Agent(
name="Haiku agent",
instructions="Always respond in haiku form",
model="gpt-5-nano",
tools=[get_weather],
)
```
ใใฎใปใฏใทใงใณใฎๅ
ๅฎนใฏใในใฆ `Agent` ใซ้ฉ็จใใใพใใ`SandboxAgent` ใฏๅใ่ใๆนใๅบ็คใจใใใฏใผใฏในใใผในๅไฝใฎๅฎ่กๅใใซ `default_manifest`ใ`base_instructions`ใ`capabilities`ใ`run_as` ใ่ฟฝๅ ใใพใใ[ใตใณใใใใฏในใจใผใธใงใณใใฎๆฆๅฟต](sandbox/guide.md)ใๅ็
งใใฆใใ ใใใ
## ใใญใณใใใใณใใฌใผใ
`prompt` ใ่จญๅฎใใใใจใงใOpenAIใใฉใใใใฉใผใ ใงไฝๆใใใใญใณใใใใณใใฌใผใใๅ็
งใงใใพใใใใใฏใResponses API ็ต็ฑใงOpenAIใขใใซใซใขใฏใปในใใๅ ดๅใซๆฉ่ฝใใพใใ
ไฝฟ็จๆ้ ใฏๆฌกใฎใจใใใงใใ
1. https://platform.openai.com/playground/prompts ใซใขใฏใปในใใพใใ
2. ๆฐใใใใญใณใใๅคๆฐ `poem_style` ใไฝๆใใพใใ
3. ๆฌกใฎๅ
ๅฎนใงใทในใใ ใใญใณใใใไฝๆใใพใใ
```
Write a poem in {{poem_style}}
```
4. `--prompt-id` ใใฉใฐใๆๅฎใใฆใณใผใไพใๅฎ่กใใพใใ
```python
from agents import Agent
agent = Agent(
name="Prompted assistant",
prompt={
"id": "pmpt_123",
"version": "1",
"variables": {"poem_style": "haiku"},
},
)
```
ๅฎ่กๆใซใใญใณใใใๅ็ใซ็ๆใใใใจใใงใใพใใ
```python
from dataclasses import dataclass
from agents import Agent, GenerateDynamicPromptData, Runner
@dataclass
class PromptContext:
prompt_id: str
poem_style: str
async def build_prompt(data: GenerateDynamicPromptData):
ctx: PromptContext = data.context.context
return {
"id": ctx.prompt_id,
"version": "1",
"variables": {"poem_style": ctx.poem_style},
}
agent = Agent(name="Prompted assistant", prompt=build_prompt)
result = await Runner.run(
agent,
"Say hello",
context=PromptContext(prompt_id="pmpt_123", poem_style="limerick"),
)
```
## ใณใณใใญในใ
ใจใผใธใงใณใใฏใใใฎ `context` ๅใซ้ขใใฆใธใงใใชใใฏใงใใใณใณใใญในใใฏไพๅญๆงๆณจๅ
ฅใฎไป็ตใฟใงใใ่ช่บซใงไฝๆใใฆ `Runner.run()` ใซๆธกใใชใใธใงใฏใใงใใใใในใฆใฎใจใผใธใงใณใใใใผใซใใใณใใชใใชใฉใซๆธกใใใพใใใพใใใจใผใธใงใณใๅฎ่กใซๅฟ
่ฆใชไพๅญ้ขไฟใจ็ถๆ
ใใพใจใใๆ่ปใชใณใณใใใจใใฆๆฉ่ฝใใพใใใณใณใใญในใใซใฏไปปๆใฎ Python ใชใใธใงใฏใใๆๅฎใงใใพใใ
`RunContextWrapper` ใฎๅ
จๆฉ่ฝใๅ
ฑๆใฎไฝฟ็จ้่ฟฝ่ทกใใในใใใใ `tool_input`ใใทใชใขใฉใคใบใซ้ขใใๆณจๆไบ้
ใซใคใใฆใฏใ[ใณใณใใญในใใฌใคใ](context.md)ใๅ็
งใใฆใใ ใใใ
```python
from dataclasses import dataclass
@dataclass
class Purchase:
id: str
@dataclass
class UserContext:
name: str
uid: str
is_pro_user: bool
async def fetch_purchases(self) -> list[Purchase]:
# implement your logic here
return []
agent = Agent[UserContext](
...,
)
```
## ๅบๅๅ
ใใใฉใซใใงใฏใใจใผใธใงใณใใฏใใฌใผใณใใญในใ๏ผใคใพใ `str`๏ผๅฝขๅผใฎๅบๅใ็ๆใใพใใใจใผใธใงใณใใซ็นๅฎใฎๅใฎๅบๅใ็ๆใใใๅ ดๅใฏใ`output_type` ใใฉใกใผใฟใผใไฝฟ็จใงใใพใใไธ่ฌ็ใซใฏ [Pydantic](https://docs.pydantic.dev/) ใชใใธใงใฏใใไฝฟ็จใใพใใใPydantic ใฎ [TypeAdapter](https://docs.pydantic.dev/latest/api/type_adapter/) ใงใฉใใใงใใไปปๆใฎๅใใตใใผใใใฆใใพใใใใใซใฏใdataclassใใชในใใTypedDict ใชใฉใๅซใพใใพใใ
```python
from pydantic import BaseModel
from agents import Agent
class CalendarEvent(BaseModel):
name: str
date: str
participants: list[str]
agent = Agent(
name="Calendar extractor",
instructions="Extract calendar events from text",
output_type=CalendarEvent,
)
```
!!! note
`output_type` ใๆธกใใจใ้ๅธธใฎใใฌใผใณใใญในใใฌในใใณในใงใฏใชใใ[structured outputs](https://platform.openai.com/docs/guides/structured-outputs)ใไฝฟ็จใใใใใขใใซใซๆ็คบใใพใใ
## ใใซใใจใผใธใงใณใใทในใใ ใฎ่จญ่จใใฟใผใณ
ใใซใใจใผใธใงใณใใทในใใ ใซใฏๅคใใฎ่จญ่จๆนๆณใใใใพใใใไธ่ฌ็ใซใฏๅบใ้ฉ็จใงใใๆฌกใฎ 2 ใคใฎใใฟใผใณใไฝฟ็จใใใพใใ
1. ใใใผใธใฃใผ๏ผagents as tools๏ผ๏ผไธญๅคฎใฎใใใผใธใฃใผ๏ผใชใผใฑในใใฌใผใฟใผใๅฐ้ใตใใจใผใธใงใณใใใใผใซใจใใฆๅผใณๅบใใไผ่ฉฑใฎๅถๅพกใ็ถญๆใใพใใ
2. ใใณใใชใ๏ผๅฏพ็ญใชใจใผใธใงใณใใใไผ่ฉฑใๅผใ็ถใๅฐ้ใจใผใธใงใณใใซๅถๅพกใใใณใใชใใใพใใใใใฏๅๆฃๅใฎใใฟใผใณใงใใ
่ฉณ็ดฐใซใคใใฆใฏใ[ใจใผใธใงใณใๆง็ฏใฎๅฎ่ทตใฌใคใ](https://cdn.openai.com/business-guides-and-resources/a-practical-guide-to-building-agents.pdf)ใๅ็
งใใฆใใ ใใใ
### ใใใผใธใฃใผ๏ผagents as tools๏ผ
`customer_facing_agent` ใฏใในใฆใฎใฆใผใถใผๆไฝใๅฆ็ใใใใผใซใจใใฆๅ
ฌ้ใใใๅฐ้ใตใใจใผใธใงใณใใๅผใณๅบใใพใใ่ฉณ็ดฐใซใคใใฆใฏใ[ใใผใซ](tools.md#agents-as-tools)ใฎใใญใฅใกใณใใๅ็
งใใฆใใ ใใใ
```python
from agents import Agent
booking_agent = Agent(...)
refund_agent = Agent(...)
customer_facing_agent = Agent(
name="Customer-facing agent",
instructions=(
"Handle all direct user communication. "
"Call the relevant tools when specialized expertise is needed."
),
tools=[
booking_agent.as_tool(
tool_name="booking_expert",
tool_description="Handles booking questions and requests.",
),
refund_agent.as_tool(
tool_name="refund_expert",
tool_description="Handles refund questions and requests.",
)
],
)
```
### ใใณใใชใ
่จญๅฎใใใใใณใใชใๅ
ใฏใใจใผใธใงใณใใๅฆ็ใๅง่ญฒใงใใใตใใจใผใธใงใณใใงใใใใณใใชใใ็บ็ใใใจใๅง่ญฒๅ
ใฎใจใผใธใงใณใใไผ่ฉฑๅฑฅๆญดใๅใๅใใไผ่ฉฑใๅผใ็ถใใพใใใใฎใใฟใผใณใซใใใๅไธใฎใฟในใฏใซ็นๅใใใขใธใฅใผใซๅผใฎๅฐ้ใจใผใธใงใณใใๆง็ฏใงใใพใใ่ฉณ็ดฐใซใคใใฆใฏใ[ใใณใใชใ](handoffs.md)ใฎใใญใฅใกใณใใๅ็
งใใฆใใ ใใใ
```python
from agents import Agent
booking_agent = Agent(...)
refund_agent = Agent(...)
triage_agent = Agent(
name="Triage agent",
instructions=(
"Help the user with their questions. "
"If they ask about booking, hand off to the booking agent. "
"If they ask about refunds, hand off to the refund agent."
),
handoffs=[booking_agent, refund_agent],
)
```
## ๅ็ใชๆ็คบ
ใปใจใใฉใฎๅ ดๅใใจใผใธใงใณใใฎไฝๆๆใซๆ็คบใๆๅฎใงใใพใใใใ ใใ้ขๆฐใไฝฟ็จใใฆๅ็ใชๆ็คบใๆๅฎใใใใจใใงใใพใใใใฎ้ขๆฐใฏใจใผใธใงใณใใจใณใณใใญในใใๅใๅใใใใญใณใใใ่ฟใๅฟ
่ฆใใใใพใใ้ๅธธใฎ้ขๆฐใจ `async` ้ขๆฐใฎไธกๆนใไฝฟ็จใงใใพใใ
```python
from agents import Agent, RunContextWrapper
def dynamic_instructions(
context: RunContextWrapper[UserContext], agent: Agent[UserContext]
) -> str:
return f"The user's name is {context.context.name}. Help them with their questions."
agent = Agent[UserContext](
name="Triage agent",
instructions=dynamic_instructions,
)
```
## ใฉใคใใตใคใฏใซใคใใณใ๏ผใใใฏ๏ผ
ใจใผใธใงใณใใฎใฉใคใใตใคใฏใซใ็ฃ่ฆใใใๅ ดๅใใใใพใใใใจใใฐใ็นๅฎใฎใคใใณใใ็บ็ใใใจใใซใใคใใณใใฎใญใฐ่จ้ฒใใใผใฟใฎไบๅๅๅพใไฝฟ็จ้ใฎ่จ้ฒใ่กใๅ ดๅใงใใ
ใใใฏใซใฏๆฌกใฎ 2 ใคใฎในใณใผใใใใใพใใ
- [`RunHooks`][agents.lifecycle.RunHooks] ใฏใไปใฎใจใผใธใงใณใใธใฎใใณใใชใใๅซใ `Runner.run(...)` ๅผใณๅบใๅ
จไฝใ็ฃ่ฆใใพใใ
- [`AgentHooks`][agents.lifecycle.AgentHooks] ใฏใ`agent.hooks` ใไปใใฆ็นๅฎใฎใจใผใธใงใณใใคใณในใฟใณในใซใขใฟใใใใใพใใ
ใณใผใซใใใฏใฎใณใณใใญในใใใใคใใณใใซๅฟใใฆๅคใใใพใใ
- ใจใผใธใงใณใใฎ้ๅง๏ผ็ตไบใใใฏใฏใๅ
ใฎใณใณใใญในใใใฉใใใใๅ
ฑๆใฎๅฎ่กไฝฟ็จ้็ถๆ
ใไฟๆใใ [`AgentHookContext`][agents.run_context.AgentHookContext] ใๅใๅใใพใใ
- LLMใใใผใซใใใณใใชใใฎๅใใใฏใฏใ[`RunContextWrapper`][agents.run_context.RunContextWrapper] ใๅใๅใใพใใ
ไธ่ฌ็ใชใใใฏใฎใฟใคใใณใฐใฏๆฌกใฎใจใใใงใใ
- `on_agent_start`๏ผ็นๅฎใฎใจใผใธใงใณใใๅฎ่กใ้ๅงใใใจใใ`on_agent_end`๏ผใใฎใจใผใธใงใณใใๆ็ตๅบๅใฎ็ๆใๅฎไบใใใจใใ
- `on_llm_start` / `on_llm_end`๏ผๅใขใใซๅผใณๅบใใฎ็ดๅใจ็ดๅพใ
- `on_tool_start` / `on_tool_end`๏ผๅใญใผใซใซใใผใซๅผใณๅบใใฎๅๅพใ้ขๆฐใใผใซใฎๅ ดๅใใใใฏใฎ `context` ใฏ้ๅธธ `ToolContext` ใงใใใใใ`tool_call_id` ใชใฉใฎใใผใซๅผใณๅบใใกใฟใใผใฟใ็ขบ่ชใงใใพใใ
- `on_handoff`๏ผๅถๅพกใใใใจใผใธใงใณใใใๅฅใฎใจใผใธใงใณใใซ็งปใฃใใจใใ
ใฏใผใฏใใญใผๅ
จไฝใๅไธใฎใชใใถใผใใผใง็ฃ่ฆใใๅ ดๅใฏ `RunHooks` ใไฝฟ็จใใ็นๅฎใฎใจใผใธใงใณใใซ้ๅฎใใใใฉใคใใตใคใฏใซใณใผใซใใใฏใๅฟ
่ฆใชๅ ดๅใฏ `AgentHooks` ใไฝฟ็จใใฆใใ ใใใ
```python
from agents import Agent, RunHooks, Runner
class LoggingHooks(RunHooks):
async def on_agent_start(self, context, agent):
print(f"Starting {agent.name}")
async def on_llm_end(self, context, agent, response):
print(f"{agent.name} produced {len(response.output)} output items")
async def on_agent_end(self, context, agent, output):
print(f"{agent.name} finished with usage: {context.usage}")
agent = Agent(name="Assistant", instructions="Be concise.")
result = await Runner.run(agent, "Explain quines", hooks=LoggingHooks())
print(result.final_output)
```
ใณใผใซใใใฏใฎๅ
จๆฉ่ฝใซใคใใฆใฏใ[ใฉใคใใตใคใฏใซ API ใชใใกใฌใณใน](ref/lifecycle.md)ใๅ็
งใใฆใใ ใใใ
## ใฌใผใใฌใผใซ
ใฌใผใใฌใผใซใไฝฟ็จใใใจใใจใผใธใงใณใใฎๅฎ่กใจไธฆ่กใใฆใฆใผใถใผๅ
ฅๅใซๅฏพใใใใงใใฏ๏ผๆค่จผใๅฎ่กใใ็ๆๅพใฎใจใผใธใงใณใๅบๅใซๅฏพใใฆใใใงใใฏ๏ผๆค่จผใๅฎ่กใงใใพใใใใจใใฐใใฆใผใถใผๅ
ฅๅใจใจใผใธใงใณใๅบๅใฎ้ข้ฃๆงใ็ขบ่ชใงใใพใใ่ฉณ็ดฐใซใคใใฆใฏใ[ใฌใผใใฌใผใซ](guardrails.md)ใฎใใญใฅใกใณใใๅ็
งใใฆใใ ใใใ
## ใจใผใธใงใณใใฎใฏใญใผใณ๏ผใณใใผ
ใจใผใธใงใณใใฎ `clone()` ใกใฝใใใไฝฟ็จใใใจใใจใผใธใงใณใใ่ค่ฃฝใใๅฟ
่ฆใซๅฟใใฆไปปๆใฎใใญใใใฃใๅคๆดใงใใพใใ
```python
pirate_agent = Agent(
name="Pirate",
instructions="Write like a pirate",
model="gpt-5.6-sol",
)
robot_agent = pirate_agent.clone(
name="Robot",
instructions="Write like a robot",
)
```
## ใใผใซไฝฟ็จใฎๅผทๅถ
ใใผใซใฎใชในใใๆๅฎใใฆใใLLMใๅฟ
ใใใผใซใไฝฟ็จใใใจใฏ้ใใพใใใ[`ModelSettings.tool_choice`][agents.model_settings.ModelSettings.tool_choice] ใ่จญๅฎใใใใจใงใใใผใซใฎไฝฟ็จใๅผทๅถใงใใพใใๆๅนใชๅคใฏๆฌกใฎใจใใใงใใ
1. `auto`๏ผใใผใซใไฝฟ็จใใใใฉใใใLLMใๅคๆญใงใใพใใ
2. `required`๏ผLLMใซใใผใซใฎไฝฟ็จใ่ฆๆฑใใพใใใใฉใฎใใผใซใไฝฟ็จใใใใฏLLMใ้ฉๅใซๅคๆญใงใใพใใ
3. `none`๏ผLLMใซใใผใซใ _ไฝฟ็จใใใชใ_ ใใจใ่ฆๆฑใใพใใ
4. `my_tool` ใชใฉใฎ็นๅฎใฎๆๅญๅใ่จญๅฎใใใจใLLMใซใใฎ็นๅฎใฎใใผใซใฎไฝฟ็จใ่ฆๆฑใใพใใ
OpenAI Responses ใฎใใผใซๆค็ดขใไฝฟ็จใใๅ ดๅใๅๅไปใใใผใซใฎ้ธๆใซใฏใใใซๅถ็ดใใใใพใใ`tool_choice` ใงใฏใไฟฎ้ฃพใชใใฎๅๅ็ฉบ้ๅใ้
ๅปถใฎใฟใฎใใผใซใๆๅฎใงใใใ`tool_choice="tool_search"` ใงใฏ [`ToolSearchTool`][agents.tool.ToolSearchTool] ใๆๅฎใงใใพใใใใใฎใใใชๅ ดๅใฏใ`auto` ใพใใฏ `required` ใไฝฟ็จใใฆใใ ใใใResponses ๅบๆใฎๅถ็ดใซใคใใฆใฏใ[ใในใๅใใผใซๆค็ดข](tools.md#hosted-tool-search)ใๅ็
งใใฆใใ ใใใ
```python
from agents import Agent, ModelSettings
from agents.decorators import tool
@tool
def get_weather(city: str) -> str:
"""Returns weather info for the specified city."""
return f"The weather in {city} is sunny"
agent = Agent(
name="Weather Agent",
instructions="Retrieve weather details.",
tools=[get_weather],
model_settings=ModelSettings(tool_choice="get_weather")
)
```
## ใใผใซไฝฟ็จๆใฎๅไฝ
`Agent` ่จญๅฎใฎ `tool_use_behavior` ใใฉใกใผใฟใผใฏใใใผใซๅบๅใฎๅฆ็ๆนๆณใๅถๅพกใใพใใ
- `"run_llm_again"`๏ผใใใฉใซใใงใใใใผใซใๅฎ่กใใใใใฎ็ตๆใLLMใๅฆ็ใใฆๆ็ตใฌในใใณในใ็ๆใใพใใ
- `"stop_on_first_tool"`๏ผๆๅใฎใใผใซๅผใณๅบใใฎๅบๅใใLLMใซใใ่ฟฝๅ ๅฆ็ใชใใงๆ็ตใฌในใใณในใจใใฆไฝฟ็จใใพใใ
```python
from agents import Agent
from agents.decorators import tool
@tool
def get_weather(city: str) -> str:
"""Returns weather info for the specified city."""
return f"The weather in {city} is sunny"
agent = Agent(
name="Weather Agent",
instructions="Retrieve weather details.",
tools=[get_weather],
tool_use_behavior="stop_on_first_tool"
)
```
- `StopAtTools(stop_at_tool_names=[...])`๏ผๆๅฎใใใใใผใซใฎใใใใใๅผใณๅบใใใใจๅๆญขใใใใฎๅบๅใๆ็ตใฌในใใณในใจใใฆไฝฟ็จใใพใใ
```python
from agents import Agent
from agents.agent import StopAtTools
from agents.decorators import tool
@tool
def get_weather(city: str) -> str:
"""Returns weather info for the specified city."""
return f"The weather in {city} is sunny"
@tool
def sum_numbers(a: int, b: int) -> int:
"""Adds two numbers."""
return a + b
agent = Agent(
name="Stop At Stock Agent",
instructions="Get weather or sum numbers.",
tools=[get_weather, sum_numbers],
tool_use_behavior=StopAtTools(stop_at_tool_names=["get_weather"])
)
```
- `ToolsToFinalOutputFunction`๏ผใใผใซใฎๅฎ่ก็ตๆใๅฆ็ใใๆ็ตๅบๅใงๅฎ่กใ็ตไบใใใใLLMใซใใๅฆ็ใ็ถ่กใใใใๆฑบๅฎใใใซในใฟใ ้ขๆฐใงใใ
```python
from agents import Agent, FunctionToolResult, RunContextWrapper
from agents.agent import ToolsToFinalOutputResult
from agents.decorators import tool
from typing import List, Any
@tool
def get_weather(city: str) -> str:
"""Returns weather info for the specified city."""
return f"The weather in {city} is sunny"
def custom_tool_handler(
context: RunContextWrapper[Any],
tool_results: List[FunctionToolResult]
) -> ToolsToFinalOutputResult:
"""Processes tool results to decide final output."""
for result in tool_results:
if result.output and "sunny" in result.output:
return ToolsToFinalOutputResult(
is_final_output=True,
final_output=f"Final weather: {result.output}"
)
return ToolsToFinalOutputResult(
is_final_output=False,
final_output=None
)
agent = Agent(
name="Weather Agent",
instructions="Retrieve weather details.",
tools=[get_weather],
tool_use_behavior=custom_tool_handler
)
```
!!! note
็ก้ใซใผใใ้ฒใใใใใใฌใผใ ใฏใผใฏใฏใใผใซๅผใณๅบใๅพใซ `tool_choice` ใ่ชๅ็ใซใautoใใซใชใปใใใใพใใใใฎๅไฝใฏใ[`agent.reset_tool_choice`][agents.agent.Agent.reset_tool_choice] ใง่จญๅฎใงใใพใใ็ก้ใซใผใใ็บ็ใใ็็ฑใฏใใใผใซใฎๅฎ่ก็ตๆใLLMใซ้ไฟกใใใๅพใ`tool_choice` ใซใใฃใฆLLMใใใใซๅฅใฎใใผใซๅผใณๅบใใ็ๆใ็ถใใใใใงใใ
---
search:
exclude: true
---
# ์์ด์ ํธ
์์ด์ ํธ๋ ์ฑ์ ํต์ฌ ๊ตฌ์ฑ ์์์
๋๋ค. ์์ด์ ํธ๋ ์ง์นจ, ๋๊ตฌ ๋ฐ ํธ๋์คํ, ๊ฐ๋๋ ์ผ, structured outputs์ ๊ฐ์ ์ ํ์ ๋ฐํ์ ๋์์ผ๋ก ๊ตฌ์ฑ๋ ๋๊ท๋ชจ ์ธ์ด ๋ชจ๋ธ(LLM)์
๋๋ค.
`SandboxAgent`๊ฐ ์๋ ๋จ์ผ ๊ธฐ๋ณธ `Agent`์ ์ ์ํ๊ฑฐ๋ ์ฌ์ฉ์ ์ง์ ํ๋ ค๋ฉด ์ด ํ์ด์ง๋ฅผ ์ฌ์ฉํ์ธ์. ์ฌ๋ฌ ์์ด์ ํธ์ ํ์
๋ฐฉ์์ ๊ฒฐ์ ํ๋ ค๋ฉด [์์ด์ ํธ ์ค์ผ์คํธ๋ ์ด์
](multi_agent.md)์ ์ฝ์ด๋ณด์ธ์. ์์ด์ ํธ๊ฐ ๋งค๋ํ์คํธ์ ์ ์๋ ํ์ผ๊ณผ ์๋๋ฐ์ค ๋ค์ดํฐ๋ธ ๊ธฐ๋ฅ์ ๊ฐ์ถ ๊ฒฉ๋ฆฌ๋ ์ํฌ์คํ์ด์ค ๋ด์์ ์คํ๋์ด์ผ ํ๋ค๋ฉด [์๋๋ฐ์ค ์์ด์ ํธ ๊ฐ๋
](sandbox/guide.md)์ ์ฝ์ด๋ณด์ธ์.
SDK๋ OpenAI ๋ชจ๋ธ์ ๊ธฐ๋ณธ์ ์ผ๋ก Responses API๋ฅผ ์ฌ์ฉํ์ง๋ง, ์ฌ๊ธฐ์ ์ค์ํ ์ฐจ์ด๋ ์ค์ผ์คํธ๋ ์ด์
์
๋๋ค. `Agent`์ `Runner`์ ์ฌ์ฉํ๋ฉด SDK๊ฐ ํด, ๋๊ตฌ, ๊ฐ๋๋ ์ผ, ํธ๋์คํ ๋ฐ ์ธ์
์ ๋์ ๊ด๋ฆฌํ ์ ์์ต๋๋ค. ์ด ๋ฃจํ๋ฅผ ์ง์ ๊ด๋ฆฌํ๋ ค๋ฉด Responses API๋ฅผ ์ง์ ์ฌ์ฉํ์ธ์.
## ๋ค์ ๊ฐ์ด๋ ์ ํ
์ด ํ์ด์ง๋ฅผ ์์ด์ ํธ ์ ์์ ์ค์ฌ ๊ฐ์ด๋๋ก ํ์ฉํ์ธ์. ๋ค์์ ๋ด๋ ค์ผ ํ ๊ฒฐ์ ์ ๋ง๋ ์ธ์ ๊ฐ์ด๋๋ก ์ด๋ํ์ธ์.
| ์ํ๋ ์์
| ๋ค์ ๋ฌธ์ |
| --- | --- |
| ๋ชจ๋ธ ๋๋ ์ ๊ณต์ ์ค์ ์ ํ | [๋ชจ๋ธ](models/index.md) |
| ์์ด์ ํธ์ ๊ธฐ๋ฅ ์ถ๊ฐ | [๋๊ตฌ](tools.md) |
| ์ค์ ์ ์ฅ์, ๋ฌธ์ ๋ฒ๋ค ๋๋ ๊ฒฉ๋ฆฌ๋ ์ํฌ์คํ์ด์ค์์ ์์ด์ ํธ ์คํ | [์๋๋ฐ์ค ์์ด์ ํธ ๋น ๋ฅธ ์์](sandbox_agents.md) |
| ๊ด๋ฆฌ์ ์คํ์ผ ์ค์ผ์คํธ๋ ์ด์
๊ณผ ํธ๋์คํ ์ค ์ ํ | [์์ด์ ํธ ์ค์ผ์คํธ๋ ์ด์
](multi_agent.md) |
| ํธ๋์คํ ๋์ ๊ตฌ์ฑ | [ํธ๋์คํ](handoffs.md) |
| ํด ์คํ, ์ด๋ฒคํธ ์คํธ๋ฆฌ๋ฐ ๋๋ ๋ํ ์ํ ๊ด๋ฆฌ | [์์ด์ ํธ ์คํ](running_agents.md) |
| ์ต์ข
์ถ๋ ฅ, ์คํ ํญ๋ชฉ ๋๋ ์ฌ๊ฐ ๊ฐ๋ฅํ ์ํ ๊ฒ์ฌ | [๊ฒฐ๊ณผ](results.md) |
| ๋ก์ปฌ ์ข
์์ฑ๊ณผ ๋ฐํ์ ์ํ ๊ณต์ | [์ปจํ
์คํธ ๊ด๋ฆฌ](context.md) |
## ๊ธฐ๋ณธ ๊ตฌ์ฑ
์์ด์ ํธ์ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์์ฑ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
| ์์ฑ | ํ์ ์ฌ๋ถ | ์ค๋ช
|
| --- | --- | --- |
| `name` | ์ | ์ฌ๋์ด ์ฝ์ ์ ์๋ ์์ด์ ํธ ์ด๋ฆ |
| `instructions` | ์๋์ | ์์คํ
ํ๋กฌํํธ ๋๋ ๋์ ์ง์นจ ์ฝ๋ฐฑ. ์ฌ์ฉ์ ๊ฐ๋ ฅํ ๊ถ์ฅํฉ๋๋ค. [๋์ ์ง์นจ](#dynamic-instructions)์ ์ฐธ์กฐํ์ธ์. |
| `prompt` | ์๋์ | OpenAI Responses API ํ๋กฌํํธ ๊ตฌ์ฑ. ์ ์ ํ๋กฌํํธ ๊ฐ์ฒด ๋๋ ํจ์๋ฅผ ํ์ฉํฉ๋๋ค. [ํ๋กฌํํธ ํ
ํ๋ฆฟ](#prompt-templates)์ ์ฐธ์กฐํ์ธ์. |
| `handoff_description` | ์๋์ | ์ด ์์ด์ ํธ๊ฐ ํธ๋์คํ ๋์์ผ๋ก ์ ๊ณต๋ ๋ ํ์๋๋ ๊ฐ๋จํ ์ค๋ช
|
| `handoffs` | ์๋์ | ๋ํ๋ฅผ ์ ๋ฌธ ์์ด์ ํธ์๊ฒ ์์ํฉ๋๋ค. [ํธ๋์คํ](handoffs.md)๋ฅผ ์ฐธ์กฐํ์ธ์. |
| `model` | ์๋์ | ์ฌ์ฉํ LLM. [๋ชจ๋ธ](models/index.md)์ ์ฐธ์กฐํ์ธ์. |
| `model_settings` | ์๋์ | `temperature`, `top_p`, `tool_choice`๊ณผ ๊ฐ์ ๋ชจ๋ธ ์กฐ์ ๋งค๊ฐ๋ณ์ |
| `tools` | ์๋์ | ์์ด์ ํธ๊ฐ ํธ์ถํ ์ ์๋ ๋๊ตฌ. [๋๊ตฌ](tools.md)๋ฅผ ์ฐธ์กฐํ์ธ์. |
| `mcp_servers` | ์๋์ | ์์ด์ ํธ์ MCP ๊ธฐ๋ฐ ๋๊ตฌ๋ฅผ ์ ๊ณตํ๋ MCP ์๋ฒ. [MCP ๊ฐ์ด๋](mcp.md)๋ฅผ ์ฐธ์กฐํ์ธ์. |
| `mcp_config` | ์๋์ | ์คํค๋ง๋ฅผ ์๊ฒฉ ๋ชจ๋๋ก ๋ณํํ๊ณ MCP ์คํจ ํ์์ ์ง์ ํ๋ ๋ฑ MCP ๋๊ตฌ๊ฐ ์ค๋น๋๋ ๋ฐฉ์์ ์ธ๋ถ ์กฐ์ ํฉ๋๋ค. [MCP ๊ฐ์ด๋](mcp.md#agent-level-mcp-configuration)๋ฅผ ์ฐธ์กฐํ์ธ์. |
| `input_guardrails` | ์๋์ | ์ด ์์ด์ ํธ ์ฒด์ธ์ ์ฒซ ๋ฒ์งธ ์ฌ์ฉ์ ์
๋ ฅ์์ ์คํ๋๋ ๊ฐ๋๋ ์ผ. [๊ฐ๋๋ ์ผ](guardrails.md)์ ์ฐธ์กฐํ์ธ์. |
| `output_guardrails` | ์๋์ | ์ด ์์ด์ ํธ์ ์ต์ข
์ถ๋ ฅ์์ ์คํ๋๋ ๊ฐ๋๋ ์ผ. [๊ฐ๋๋ ์ผ](guardrails.md)์ ์ฐธ์กฐํ์ธ์. |
| `output_type` | ์๋์ | ์ผ๋ฐ ํ
์คํธ ๋์ ์ฌ์ฉํ ๊ตฌ์กฐํ๋ ์ถ๋ ฅ ํ์
. [์ถ๋ ฅ ํ์
](#output-types)์ ์ฐธ์กฐํ์ธ์. |
| `hooks` | ์๋์ | ์์ด์ ํธ ๋ฒ์์ ์๋ช
์ฃผ๊ธฐ ์ฝ๋ฐฑ. [์๋ช
์ฃผ๊ธฐ ์ด๋ฒคํธ(ํ
)](#lifecycle-events-hooks)๋ฅผ ์ฐธ์กฐํ์ธ์. |
| `tool_use_behavior` | ์๋์ | ๋๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ๋ชจ๋ธ๋ก ๋ค์ ์ ๋ฌํ ์ง ๋๋ ์คํ์ ์ข
๋ฃํ ์ง ์ ์ดํฉ๋๋ค. [๋๊ตฌ ์ฌ์ฉ ๋์](#tool-use-behavior)์ ์ฐธ์กฐํ์ธ์. |
| `reset_tool_choice` | ์๋์ | ๋๊ตฌ ์ฌ์ฉ ๋ฃจํ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ๋๊ตฌ ํธ์ถ ํ `tool_choice`์ ์ฌ์ค์ ํฉ๋๋ค(๊ธฐ๋ณธ๊ฐ: `True`). [๋๊ตฌ ์ฌ์ฉ ๊ฐ์ ](#forcing-tool-use)๋ฅผ ์ฐธ์กฐํ์ธ์. |
```python
from agents import Agent
from agents.decorators import tool
@tool
def get_weather(city: str) -> str:
"""returns weather info for the specified city."""
return f"The weather in {city} is sunny"
agent = Agent(
name="Haiku agent",
instructions="Always respond in haiku form",
model="gpt-5-nano",
tools=[get_weather],
)
```
์ด ์น์
์ ๋ชจ๋ ๋ด์ฉ์ `Agent`์ ์ ์ฉ๋ฉ๋๋ค. `SandboxAgent`์ ๋์ผํ ๊ฐ๋
์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ฉฐ, ์ํฌ์คํ์ด์ค ๋ฒ์ ์คํ์ ์ํ `default_manifest`, `base_instructions`, `capabilities`, `run_as`์ ์ถ๊ฐํฉ๋๋ค. [์๋๋ฐ์ค ์์ด์ ํธ ๊ฐ๋
](sandbox/guide.md)์ ์ฐธ์กฐํ์ธ์.
## ํ๋กฌํํธ ํ
ํ๋ฆฟ
`prompt`์ ์ค์ ํ์ฌ OpenAI ํ๋ซํผ์์ ์์ฑํ ํ๋กฌํํธ ํ
ํ๋ฆฟ์ ์ฐธ์กฐํ ์ ์์ต๋๋ค. ์ด ๊ธฐ๋ฅ์ Responses API๋ฅผ ํตํด OpenAI ๋ชจ๋ธ์ ์ ๊ทผํ ๋ ์๋ํฉ๋๋ค.
์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1. https://platform.openai.com/playground/prompts ๋ก ์ด๋ํฉ๋๋ค.
2. ์ ํ๋กฌํํธ ๋ณ์ `poem_style`๋ฅผ ์์ฑํฉ๋๋ค.
3. ๋ค์ ๋ด์ฉ์ผ๋ก ์์คํ
ํ๋กฌํํธ๋ฅผ ์์ฑํฉ๋๋ค.
```
Write a poem in {{poem_style}}
```
4. `--prompt-id` ํ๋๊ทธ๋ฅผ ์ฌ์ฉํ์ฌ ์์ ๋ฅผ ์คํํฉ๋๋ค.
```python
from agents import Agent
agent = Agent(
name="Prompted assistant",
prompt={
"id": "pmpt_123",
"version": "1",
"variables": {"poem_style": "haiku"},
},
)
```
๋ฐํ์์ ํ๋กฌํํธ๋ฅผ ๋์ ์ผ๋ก ์์ฑํ ์๋ ์์ต๋๋ค.
```python
from dataclasses import dataclass
from agents import Agent, GenerateDynamicPromptData, Runner
@dataclass
class PromptContext:
prompt_id: str
poem_style: str
async def build_prompt(data: GenerateDynamicPromptData):
ctx: PromptContext = data.context.context
return {
"id": ctx.prompt_id,
"version": "1",
"variables": {"poem_style": ctx.poem_style},
}
agent = Agent(name="Prompted assistant", prompt=build_prompt)
result = await Runner.run(
agent,
"Say hello",
context=PromptContext(prompt_id="pmpt_123", poem_style="limerick"),
)
```
## ์ปจํ
์คํธ
์์ด์ ํธ๋ `context` ํ์
์ ๋ํด ์ ๋ค๋ฆญ์
๋๋ค. ์ปจํ
์คํธ๋ ์ข
์์ฑ ์ฃผ์
๋๊ตฌ์
๋๋ค. ์ปจํ
์คํธ๋ ์ฌ์ฉ์๊ฐ ์์ฑํ์ฌ `Runner.run()`์ ์ ๋ฌํ๋ ๊ฐ์ฒด๋ก, ๋ชจ๋ ์์ด์ ํธ, ๋๊ตฌ, ํธ๋์คํ ๋ฑ์ ์ ๋ฌ๋๋ฉฐ ์์ด์ ํธ ์คํ์ ํ์ํ ์ข
์์ฑ๊ณผ ์ํ๋ฅผ ๋ด๋ ์ปจํ
์ด๋ ์ญํ ์ ํฉ๋๋ค. ๋ชจ๋ Python ๊ฐ์ฒด๋ฅผ ์ปจํ
์คํธ๋ก ์ ๊ณตํ ์ ์์ต๋๋ค.
์ ์ฒด `RunContextWrapper` ์ธํฐํ์ด์ค, ๊ณต์ ์ฌ์ฉ๋ ์ถ์ , ์ค์ฒฉ๋ `tool_input` ๋ฐ ์ง๋ ฌํ ์ ์ฃผ์ ์ฌํญ์ [์ปจํ
์คํธ ๊ฐ์ด๋](context.md)๋ฅผ ์ฐธ์กฐํ์ธ์.
```python
from dataclasses import dataclass
@dataclass
class Purchase:
id: str
@dataclass
class UserContext:
name: str
uid: str
is_pro_user: bool
async def fetch_purchases(self) -> list[Purchase]:
# implement your logic here
return []
agent = Agent[UserContext](
...,
)
```
## ์ถ๋ ฅ ํ์
๊ธฐ๋ณธ์ ์ผ๋ก ์์ด์ ํธ๋ ์ผ๋ฐ ํ
์คํธ(์ฆ, `str`) ์ถ๋ ฅ์ ์์ฑํฉ๋๋ค. ์์ด์ ํธ๊ฐ ํน์ ํ์
์ ์ถ๋ ฅ์ ์์ฑํ๋๋ก ํ๋ ค๋ฉด `output_type` ๋งค๊ฐ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ผ๋ฐ์ ์ผ๋ก [Pydantic](https://docs.pydantic.dev/) ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ง๋ง, ๋ฐ์ดํฐ ํด๋์ค, ๋ฆฌ์คํธ, TypedDict ๋ฑ Pydantic [TypeAdapter](https://docs.pydantic.dev/latest/api/type_adapter/)๋ก ๋ํํ ์ ์๋ ๋ชจ๋ ํ์
์ ์ง์ํฉ๋๋ค.
```python
from pydantic import BaseModel
from agents import Agent
class CalendarEvent(BaseModel):
name: str
date: str
participants: list[str]
agent = Agent(
name="Calendar extractor",
instructions="Extract calendar events from text",
output_type=CalendarEvent,
)
```
!!! note
`output_type`์ ์ ๋ฌํ๋ฉด ๋ชจ๋ธ์ด ์ผ๋ฐ์ ์ธ ์ผ๋ฐ ํ
์คํธ ์๋ต ๋์ [structured outputs](https://platform.openai.com/docs/guides/structured-outputs)๋ฅผ ์ฌ์ฉํ๋๋ก ์ง์ ํฉ๋๋ค.
## ๋ค์ค ์์ด์ ํธ ์์คํ
์ค๊ณ ํจํด
๋ค์ค ์์ด์ ํธ ์์คํ
์ ์ค๊ณํ๋ ๋ฐฉ๋ฒ์ ๋ค์ํ์ง๋ง, ์ผ๋ฐ์ ์ผ๋ก ํญ๋๊ฒ ์ ์ฉํ ์ ์๋ ๋ค์ ๋ ๊ฐ์ง ํจํด์ด ์ฌ์ฉ๋ฉ๋๋ค.
1. ๊ด๋ฆฌ์(Agents as tools): ์ค์ ๊ด๋ฆฌ์/์ค์ผ์คํธ๋ ์ดํฐ๊ฐ ์ ๋ฌธ ํ์ ์์ด์ ํธ๋ฅผ ๋๊ตฌ๋ก ํธ์ถํ๊ณ ๋ํ์ ์ ์ด๊ถ์ ์ ์งํฉ๋๋ค.
2. ํธ๋์คํ: ๋๋ฑํ ์์ด์ ํธ๊ฐ ๋ํ์ ์ ์ด๊ถ์ ์ธ๊ณ๋ฐ์ ์ ๋ฌธ ์์ด์ ํธ์๊ฒ ์ ์ด๊ถ์ ํธ๋์คํํฉ๋๋ค. ์ด๋ ํ์ค์ํ๋ ๋ฐฉ์์
๋๋ค.
์์ธํ ๋ด์ฉ์ [์์ด์ ํธ ๊ตฌ์ถ ์ค์ ๊ฐ์ด๋](https://cdn.openai.com/business-guides-and-resources/a-practical-guide-to-building-agents.pdf)๋ฅผ ์ฐธ์กฐํ์ธ์.
### ๊ด๋ฆฌ์(Agents as tools)
`customer_facing_agent`์ ๋ชจ๋ ์ฌ์ฉ์ ์ํธ์์ฉ์ ์ฒ๋ฆฌํ๊ณ ๋๊ตฌ๋ก ๋
ธ์ถ๋ ์ ๋ฌธ ํ์ ์์ด์ ํธ๋ฅผ ํธ์ถํฉ๋๋ค. ์์ธํ ๋ด์ฉ์ [๋๊ตฌ](tools.md#agents-as-tools) ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ธ์.
```python
from agents import Agent
booking_agent = Agent(...)
refund_agent = Agent(...)
customer_facing_agent = Agent(
name="Customer-facing agent",
instructions=(
"Handle all direct user communication. "
"Call the relevant tools when specialized expertise is needed."
),
tools=[
booking_agent.as_tool(
tool_name="booking_expert",
tool_description="Handles booking questions and requests.",
),
refund_agent.as_tool(
tool_name="refund_expert",
tool_description="Handles refund questions and requests.",
)
],
)
```
### ํธ๋์คํ
๊ตฌ์ฑ๋ ํธ๋์คํ ๋์์ ์์ด์ ํธ๊ฐ ์์
์ ์์ํ ์ ์๋ ํ์ ์์ด์ ํธ์
๋๋ค. ํธ๋์คํ๊ฐ ๋ฐ์ํ๋ฉด ์์๋ฐ์ ์์ด์ ํธ๊ฐ ๋ํ ๊ธฐ๋ก์ ์ ๋ฌ๋ฐ์ ๋ํ๋ฅผ ์ด์ด๊ฐ๋๋ค. ์ด ํจํด์ ์ฌ์ฉํ๋ฉด ๋จ์ผ ์์
์ ํนํ๋ ๋ชจ๋์ ์ ๋ฌธ ์์ด์ ํธ๋ฅผ ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ์์ธํ ๋ด์ฉ์ [ํธ๋์คํ](handoffs.md) ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ธ์.
```python
from agents import Agent
booking_agent = Agent(...)
refund_agent = Agent(...)
triage_agent = Agent(
name="Triage agent",
instructions=(
"Help the user with their questions. "
"If they ask about booking, hand off to the booking agent. "
"If they ask about refunds, hand off to the refund agent."
),
handoffs=[booking_agent, refund_agent],
)
```
## ๋์ ์ง์นจ
๋๋ถ๋ถ์ ๊ฒฝ์ฐ ์์ด์ ํธ๋ฅผ ์์ฑํ ๋ ์ง์นจ์ ์ ๊ณตํ ์ ์์ต๋๋ค. ํ์ง๋ง ํจ์๋ฅผ ํตํด ๋์ ์ง์นจ์ ์ ๊ณตํ ์๋ ์์ต๋๋ค. ํจ์๋ ์์ด์ ํธ์ ์ปจํ
์คํธ๋ฅผ ์ ๋ฌ๋ฐ์ผ๋ฉฐ ํ๋กฌํํธ๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค. ์ผ๋ฐ ํจ์์ `async` ํจ์๊ฐ ๋ชจ๋ ํ์ฉ๋ฉ๋๋ค.
```python
from agents import Agent, RunContextWrapper
def dynamic_instructions(
context: RunContextWrapper[UserContext], agent: Agent[UserContext]
) -> str:
return f"The user's name is {context.context.name}. Help them with their questions."
agent = Agent[UserContext](
name="Triage agent",
instructions=dynamic_instructions,
)
```
## ์๋ช
์ฃผ๊ธฐ ์ด๋ฒคํธ(ํ
)
์์ด์ ํธ์ ์๋ช
์ฃผ๊ธฐ๋ฅผ ๊ด์ฐฐํด์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ํน์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋ ์ด๋ฒคํธ๋ฅผ ๊ธฐ๋กํ๊ฑฐ๋, ๋ฐ์ดํฐ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ์ ธ์ค๊ฑฐ๋, ์ฌ์ฉ๋์ ๊ธฐ๋กํ ์ ์์ต๋๋ค.
ํ
์๋ ๋ ๊ฐ์ง ๋ฒ์๊ฐ ์์ต๋๋ค.
- [`RunHooks`][agents.lifecycle.RunHooks]์ ๋ค๋ฅธ ์์ด์ ํธ๋ก์ ํธ๋์คํ๋ฅผ ํฌํจํ์ฌ ์ ์ฒด `Runner.run(...)` ํธ์ถ์ ๊ด์ฐฐํฉ๋๋ค.
- [`AgentHooks`][agents.lifecycle.AgentHooks]๋ `agent.hooks`์ ํตํด ํน์ ์์ด์ ํธ ์ธ์คํด์ค์ ์ฐ๊ฒฐ๋ฉ๋๋ค.
์ฝ๋ฐฑ ์ปจํ
์คํธ๋ ์ด๋ฒคํธ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋๋ค.
- ์์ด์ ํธ ์์/์ข
๋ฃ ํ
์ ์๋ ์ปจํ
์คํธ๋ฅผ ๋ํํ๊ณ ๊ณต์ ์คํ ์ฌ์ฉ๋ ์ํ๋ฅผ ํฌํจํ๋ [`AgentHookContext`][agents.run_context.AgentHookContext]์ ์ ๋ฌ๋ฐ์ต๋๋ค.
- LLM, ๋๊ตฌ ๋ฐ ํธ๋์คํ ํ
์ [`RunContextWrapper`][agents.run_context.RunContextWrapper]๋ฅผ ์ ๋ฌ๋ฐ์ต๋๋ค.
์ผ๋ฐ์ ์ธ ํ
์คํ ์์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- `on_agent_start`: ํน์ ์์ด์ ํธ๊ฐ ์คํ์ ์์ํ ๋, `on_agent_end`: ํด๋น ์์ด์ ํธ๊ฐ ์ต์ข
์ถ๋ ฅ ์์ฑ์ ๋ง์ณค์ ๋
- `on_llm_start` / `on_llm_end`: ๊ฐ ๋ชจ๋ธ ํธ์ถ ์ง์ ๊ณผ ์งํ
- `on_tool_start` / `on_tool_end`: ๊ฐ ๋ก์ปฌ ๋๊ตฌ ํธ์ถ ์ ํ. ํจ์ ๋๊ตฌ์ ๊ฒฝ์ฐ `context` ํ
์ ์ผ๋ฐ์ ์ผ๋ก `ToolContext`์ด๋ฏ๋ก `tool_call_id`๊ณผ ๊ฐ์ ๋๊ตฌ ํธ์ถ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ฌํ ์ ์์ต๋๋ค.
- `on_handoff`: ์ ์ด๊ถ์ด ํ ์์ด์ ํธ์์ ๋ค๋ฅธ ์์ด์ ํธ๋ก ์ด๋ํ ๋
์ ์ฒด ์ํฌํ๋ก๋ฅผ ๊ด์ฐฐํ๋ ๋จ์ผ ๊ด์ฐฐ์๊ฐ ํ์ํ๋ฉด `RunHooks`์ ์ฌ์ฉํ๊ณ , ํน์ ์์ด์ ํธ๋ก ๋ฒ์๊ฐ ํ์ ๋ ์๋ช
์ฃผ๊ธฐ ์ฝ๋ฐฑ์ด ํ์ํ๋ฉด `AgentHooks`์ ์ฌ์ฉํ์ธ์.
```python
from agents import Agent, RunHooks, Runner
class LoggingHooks(RunHooks):
async def on_agent_start(self, context, agent):
print(f"Starting {agent.name}")
async def on_llm_end(self, context, agent, response):
print(f"{agent.name} produced {len(response.output)} output items")
async def on_agent_end(self, context, agent, output):
print(f"{agent.name} finished with usage: {context.usage}")
agent = Agent(name="Assistant", instructions="Be concise.")
result = await Runner.run(agent, "Explain quines", hooks=LoggingHooks())
print(result.final_output)
```
์ ์ฒด ์ฝ๋ฐฑ ์ธํฐํ์ด์ค๋ [์๋ช
์ฃผ๊ธฐ API ๋ ํผ๋ฐ์ค](ref/lifecycle.md)๋ฅผ ์ฐธ์กฐํ์ธ์.
## ๊ฐ๋๋ ์ผ
๊ฐ๋๋ ์ผ์ ์ฌ์ฉํ๋ฉด ์์ด์ ํธ ์คํ๊ณผ ๋ณ๋ ฌ๋ก ์ฌ์ฉ์ ์
๋ ฅ์ ๋ํ ๊ฒ์ฌ/๊ฒ์ฆ์ ์คํํ๊ณ , ์์ด์ ํธ ์ถ๋ ฅ์ด ์์ฑ๋ ํ ํด๋น ์ถ๋ ฅ์ ๊ฒ์ฌํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ์ฌ์ฉ์ ์
๋ ฅ๊ณผ ์์ด์ ํธ ์ถ๋ ฅ์ ๊ด๋ จ์ฑ์ ํ์ธํ ์ ์์ต๋๋ค. ์์ธํ ๋ด์ฉ์ [๊ฐ๋๋ ์ผ](guardrails.md) ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ธ์.
## ์์ด์ ํธ ๋ณต์ /๋ณต์ฌ
์์ด์ ํธ์ `clone()` ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ์์ด์ ํธ๋ฅผ ๋ณต์ ํ๊ณ ์ํ๋ ์์ฑ์ ์ ํ์ ์ผ๋ก ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
```python
pirate_agent = Agent(
name="Pirate",
instructions="Write like a pirate",
model="gpt-5.6-sol",
)
robot_agent = pirate_agent.clone(
name="Robot",
instructions="Write like a robot",
)
```
## ๋๊ตฌ ์ฌ์ฉ ๊ฐ์
๋๊ตฌ ๋ชฉ๋ก์ ์ ๊ณตํ๋ค๊ณ ํด์ LLM์ด ํญ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์๋๋๋ค. [`ModelSettings.tool_choice`][agents.model_settings.ModelSettings.tool_choice]์ ์ค์ ํ์ฌ ๋๊ตฌ ์ฌ์ฉ์ ๊ฐ์ ํ ์ ์์ต๋๋ค. ์ ํจํ ๊ฐ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
1. `auto`: LLM์ด ๋๊ตฌ ์ฌ์ฉ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ ์ ์์ต๋๋ค.
2. `required`: LLM์ด ๋๊ตฌ๋ฅผ ์ฌ์ฉํด์ผ ํ์ง๋ง ์ฌ์ฉํ ๋๊ตฌ๋ ์ง๋ฅ์ ์ผ๋ก ๊ฒฐ์ ํ ์ ์์ต๋๋ค.
3. `none`: LLM์ด ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ง _์๋๋ก_ ์ง์ ํฉ๋๋ค.
4. `my_tool`๊ณผ ๊ฐ์ ํน์ ๋ฌธ์์ด ์ค์ : LLM์ด ํด๋น ๋๊ตฌ๋ฅผ ์ฌ์ฉํ๋๋ก ์ง์ ํฉ๋๋ค.
OpenAI Responses ๋๊ตฌ ๊ฒ์์ ์ฌ์ฉํ ๋๋ ์ด๋ฆ์ด ์ง์ ๋ ๋๊ตฌ ์ ํ์ ๋ ๋ง์ ์ ์ฝ์ด ์์ต๋๋ค. `tool_choice`์ ์ฌ์ฉํ์ฌ ๋จ๋
๋ค์์คํ์ด์ค ์ด๋ฆ์ด๋ ์ง์ฐ ์ ์ฉ ๋๊ตฌ๋ฅผ ๋์์ผ๋ก ์ง์ ํ ์ ์์ผ๋ฉฐ, `tool_choice="tool_search"`์ [`ToolSearchTool`][agents.tool.ToolSearchTool]์ ๋์์ผ๋ก ์ง์ ํ์ง ์์ต๋๋ค. ์ด๋ฌํ ๊ฒฝ์ฐ์๋ `auto` ๋๋ `required`์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค. Responses ๊ด๋ จ ์ ์ฝ ์กฐ๊ฑด์ [ํธ์คํฐ๋ ํด ๊ฒ์](tools.md#hosted-tool-search)์ ์ฐธ์กฐํ์ธ์.
```python
from agents import Agent, ModelSettings
from agents.decorators import tool
@tool
def get_weather(city: str) -> str:
"""Returns weather info for the specified city."""
return f"The weather in {city} is sunny"
agent = Agent(
name="Weather Agent",
instructions="Retrieve weather details.",
tools=[get_weather],
model_settings=ModelSettings(tool_choice="get_weather")
)
```
## ๋๊ตฌ ์ฌ์ฉ ๋์
`Agent` ๊ตฌ์ฑ์ `tool_use_behavior` ๋งค๊ฐ๋ณ์๋ ๋๊ตฌ ์ถ๋ ฅ์ ์ฒ๋ฆฌ ๋ฐฉ์์ ์ ์ดํฉ๋๋ค.
- `"run_llm_again"`: ๊ธฐ๋ณธ๊ฐ์
๋๋ค. ๋๊ตฌ๊ฐ ์คํ๋๋ฉฐ LLM์ด ๊ฒฐ๊ณผ๋ฅผ ์ฒ๋ฆฌํ์ฌ ์ต์ข
์๋ต์ ์์ฑํฉ๋๋ค.
- `"stop_on_first_tool"`: ์ถ๊ฐ์ ์ธ LLM ์ฒ๋ฆฌ ์์ด ์ฒซ ๋ฒ์งธ ๋๊ตฌ ํธ์ถ์ ์ถ๋ ฅ์ ์ต์ข
์๋ต์ผ๋ก ์ฌ์ฉํฉ๋๋ค.
```python
from agents import Agent
from agents.decorators import tool
@tool
def get_weather(city: str) -> str:
"""Returns weather info for the specified city."""
return f"The weather in {city} is sunny"
agent = Agent(
name="Weather Agent",
instructions="Retrieve weather details.",
tools=[get_weather],
tool_use_behavior="stop_on_first_tool"
)
```
- `StopAtTools(stop_at_tool_names=[...])`: ์ง์ ๋ ๋๊ตฌ ์ค ํ๋๋ผ๋ ํธ์ถ๋๋ฉด ์ค์งํ๊ณ ํด๋น ์ถ๋ ฅ์ ์ต์ข
์๋ต์ผ๋ก ์ฌ์ฉํฉ๋๋ค.
```python
from agents import Agent
from agents.agent import StopAtTools
from agents.decorators import tool
@tool
def get_weather(city: str) -> str:
"""Returns weather info for the specified city."""
return f"The weather in {city} is sunny"
@tool
def sum_numbers(a: int, b: int) -> int:
"""Adds two numbers."""
return a + b
agent = Agent(
name="Stop At Stock Agent",
instructions="Get weather or sum numbers.",
tools=[get_weather, sum_numbers],
tool_use_behavior=StopAtTools(stop_at_tool_names=["get_weather"])
)
```
- `ToolsToFinalOutputFunction`: ๋๊ตฌ ๊ฒฐ๊ณผ๋ฅผ ์ฒ๋ฆฌํ๊ณ ์ต์ข
์ถ๋ ฅ์ผ๋ก ์คํ์ ์ข
๋ฃํ ์ง, LLM์ผ๋ก ์ฒ๋ฆฌ๋ฅผ ๊ณ์ํ ์ง ๊ฒฐ์ ํ๋ ์ฌ์ฉ์ ์ง์ ํจ์์
๋๋ค.
```python
from agents import Agent, FunctionToolResult, RunContextWrapper
from agents.agent import ToolsToFinalOutputResult
from agents.decorators import tool
from typing import List, Any
@tool
def get_weather(city: str) -> str:
"""Returns weather info for the specified city."""
return f"The weather in {city} is sunny"
def custom_tool_handler(
context: RunContextWrapper[Any],
tool_results: List[FunctionToolResult]
) -> ToolsToFinalOutputResult:
"""Processes tool results to decide final output."""
for result in tool_results:
if result.output and "sunny" in result.output:
return ToolsToFinalOutputResult(
is_final_output=True,
final_output=f"Final weather: {result.output}"
)
return ToolsToFinalOutputResult(
is_final_output=False,
final_output=None
)
agent = Agent(
name="Weather Agent",
instructions="Retrieve weather details.",
tools=[get_weather],
tool_use_behavior=custom_tool_handler
)
```
!!! note
๋ฌดํ ๋ฃจํ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ํ๋ ์์ํฌ๋ ๋๊ตฌ ํธ์ถ ํ `tool_choice`์ ์๋์ผ๋ก "auto"๋ก ์ฌ์ค์ ํฉ๋๋ค. ์ด ๋์์ [`agent.reset_tool_choice`][agents.agent.Agent.reset_tool_choice]๋ฅผ ํตํด ๊ตฌ์ฑํ ์ ์์ต๋๋ค. ๋ฌดํ ๋ฃจํ๋ ๋๊ตฌ ๊ฒฐ๊ณผ๊ฐ LLM์ผ๋ก ์ ์ก๋ ํ `tool_choice`์ผ๋ก ์ธํด LLM์ด ๋ ๋ค๋ฅธ ๋๊ตฌ ํธ์ถ์ ์์ฑํ๋ ๊ณผ์ ์ด ๋์์ด ๋ฐ๋ณต๋๊ธฐ ๋๋ฌธ์ ๋ฐ์ํฉ๋๋ค.