Skip to content
101 changes: 100 additions & 1 deletion docs/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,107 @@ Supplying a list of tools doesn't always mean the LLM will use a tool. You can f
3. `none`, which requires the LLM to _not_ use a tool.
4. Setting a specific string e.g. `my_tool`, which requires the LLM to use that specific tool.

```python
from agents import Agent, Runner, function_tool, ModelSettings

@function_tool
def get_stock_price(ticker: str) -> str:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would like to avoid this example in the document page. Can you simply reuse the fetch_purchases for these added examples? The main purpose is to share the ways to pass customization options, not to share a variety of examples.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would like to avoid this example in the document page. Can you simply reuse the fetch_purchases for these added examples? The main purpose is to share the ways to pass customization options, not to share a variety of examples.

Hi, thanks for the review and the valuable feedback!

I've addressed your comments regarding the get_stock_price example and replaced it with get_weather to keep the documentation consistent and focused on demonstrating tool_use_behavior options rather than introducing new tools.

You're absolutely right about the main purpose being to share customization options. My intention with the detailed examples was to ensure that developers can easily understand and implement these advanced behaviors without confusion.

Personally, I've spent a considerable amount of time troubleshooting and experimenting with StopAtTools and ToolsToFinalOutputFunction because clear, runnable examples were not readily available. This led to significant time wastage for me. By providing these simplified yet comprehensive examples directly in the documentation, we can prevent other developers from facing similar challenges, saving them countless hours of debugging and guesswork.

I believe these changes make the documentation much more user-friendly and reduce the friction for anyone integrating with the Agent SDK.

Please let me know if any further adjustments are needed.

"""Fetches the stock price for a given ticker symbol."""
prices = {"AAPL": "$150.00", "GOOGL": "$2750.00"}
return prices.get(ticker, "Stock not found")

agent = Agent(
name="Stock Price Agent",
instructions="Retrieve the stock price if relevant, otherwise respond directly.",
tools=[get_stock_price],
model_settings=ModelSettings(tool_choice="get_stock_price")
)

```

## Tool Use Behavior

The `tool_use_behavior` parameter in the `Agent` configuration controls how tool outputs are handled:
- `"run_llm_again"`: The default. Tools are run, and the LLM processes the results to produce a final response.
- `"stop_on_first_tool"`: The output of the first tool call is used as the final response, without further LLM processing.

```python
from agents import Agent, Runner, function_tool, ModelSettings

@function_tool
def get_stock_price(ticker: str) -> str:
"""Fetches the stock price for a given ticker symbol."""
prices = {"AAPL": "$150.00", "GOOGL": "$2750.00"}
return prices.get(ticker, "Stock not found")

# Create the agent
agent = Agent(
name="Stock Price Agent",
instructions="Retrieve the stock price.",
tools=[get_stock_price],
tool_use_behavior="stop_on_first_tool"
)
```

- `StopAtTools(stop_at_tool_names=[...])`: Stops if any specified tool is called, using its output as the final response.
```python
from agents import Agent, Runner, function_tool
from agents.agent import StopAtTools

@function_tool
def get_stock_price(ticker: str) -> str:
"""Fetches the stock price for a given ticker symbol."""
prices = {"AAPL": "$150.00", "GOOGL": "$2750.00"}
return prices.get(ticker, "Stock not found")

agent = Agent(
name="Stop At Stock Agent",
instructions="Get stock price and stop.",
tools=[get_stock_price],
tool_use_behavior=StopAtTools(stop_at_tool_names=["get_stock_price"])
)
```
- `ToolsToFinalOutputFunction`: A custom function that processes tool results and decides whether to stop or continue with the LLM.

```python

from agents import Agent, Runner, function_tool, FunctionToolResult, RunContextWrapper
from agents.agent import ToolsToFinalOutputResult
from typing import List, Any

@function_tool
def get_product_price(product_id: str) -> str:
"""Fetches the price for a given product ID."""
prices = {"P101": "$25.00", "P102": "$49.99"}
return prices.get(product_id, "Product not found")

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 "$25.00" in result.output:
return ToolsToFinalOutputResult(
is_final_output=True,
final_output=f"Final result: {result.output}"
)
return ToolsToFinalOutputResult(
is_final_output=False,
final_output=None
)

# Create the agent
agent = Agent(
name="Product Price Agent",
instructions="Retrieve product prices and format them.",
tools=[get_product_price],
tool_use_behavior=custom_tool_handler
)

```

!!! note

To prevent infinite loops, the framework automatically resets `tool_choice` to "auto" after a tool call. This behavior is configurable via [`agent.reset_tool_choice`][agents.agent.Agent.reset_tool_choice]. The infinite loop is because tool results are sent to the LLM, which then generates another tool call because of `tool_choice`, ad infinitum.

If you want the Agent to completely stop after a tool call (rather than continuing with auto mode), you can set [`Agent.tool_use_behavior="stop_on_first_tool"`] which will directly use the tool output as the final response without further LLM processing.