|
| 1 | +--- |
| 2 | +title: Agents |
| 3 | +id: agents-api |
| 4 | +description: Tool-using agents with provider-agnostic chat model support. |
| 5 | +--- |
| 6 | + |
| 7 | +<a id="agent"></a> |
| 8 | + |
| 9 | +# Module agent |
| 10 | + |
| 11 | +<a id="agent.Agent"></a> |
| 12 | + |
| 13 | +## Agent |
| 14 | + |
| 15 | +A Haystack component that implements a tool-using agent with provider-agnostic chat model support. |
| 16 | + |
| 17 | +The component processes messages and executes tools until an exit condition is met. |
| 18 | +The exit condition can be triggered either by a direct text response or by invoking a specific designated tool. |
| 19 | +Multiple exit conditions can be specified. |
| 20 | + |
| 21 | +When you call an Agent without tools, it acts as a ChatGenerator, produces one response, then exits. |
| 22 | + |
| 23 | +### Usage example |
| 24 | +```python |
| 25 | +from haystack.components.agents import Agent |
| 26 | +from haystack.components.generators.chat import OpenAIChatGenerator |
| 27 | +from haystack.dataclasses import ChatMessage |
| 28 | +from haystack.tools.tool import Tool |
| 29 | + |
| 30 | +tools = [Tool(name="calculator", description="..."), Tool(name="search", description="...")] |
| 31 | + |
| 32 | +agent = Agent( |
| 33 | + chat_generator=OpenAIChatGenerator(), |
| 34 | + tools=tools, |
| 35 | + exit_conditions=["search"], |
| 36 | +) |
| 37 | + |
| 38 | +# Run the agent |
| 39 | +result = agent.run( |
| 40 | + messages=[ChatMessage.from_user("Find information about Haystack")] |
| 41 | +) |
| 42 | + |
| 43 | +assert "messages" in result # Contains conversation history |
| 44 | +``` |
| 45 | + |
| 46 | +<a id="agent.Agent.__init__"></a> |
| 47 | + |
| 48 | +#### Agent.\_\_init\_\_ |
| 49 | + |
| 50 | +```python |
| 51 | +def __init__(*, |
| 52 | + chat_generator: ChatGenerator, |
| 53 | + tools: Optional[Union[list[Tool], Toolset]] = None, |
| 54 | + system_prompt: Optional[str] = None, |
| 55 | + exit_conditions: Optional[list[str]] = None, |
| 56 | + state_schema: Optional[dict[str, Any]] = None, |
| 57 | + max_agent_steps: int = 100, |
| 58 | + streaming_callback: Optional[StreamingCallbackT] = None, |
| 59 | + raise_on_tool_invocation_failure: bool = False, |
| 60 | + tool_invoker_kwargs: Optional[dict[str, Any]] = None) -> None |
| 61 | +``` |
| 62 | + |
| 63 | +Initialize the agent component. |
| 64 | + |
| 65 | +**Arguments**: |
| 66 | + |
| 67 | +- `chat_generator`: An instance of the chat generator that your agent should use. It must support tools. |
| 68 | +- `tools`: List of Tool objects or a Toolset that the agent can use. |
| 69 | +- `system_prompt`: System prompt for the agent. |
| 70 | +- `exit_conditions`: List of conditions that will cause the agent to return. |
| 71 | +Can include "text" if the agent should return when it generates a message without tool calls, |
| 72 | +or tool names that will cause the agent to return once the tool was executed. Defaults to ["text"]. |
| 73 | +- `state_schema`: The schema for the runtime state used by the tools. |
| 74 | +- `max_agent_steps`: Maximum number of steps the agent will run before stopping. Defaults to 100. |
| 75 | +If the agent exceeds this number of steps, it will stop and return the current state. |
| 76 | +- `streaming_callback`: A callback that will be invoked when a response is streamed from the LLM. |
| 77 | +The same callback can be configured to emit tool results when a tool is called. |
| 78 | +- `raise_on_tool_invocation_failure`: Should the agent raise an exception when a tool invocation fails? |
| 79 | +If set to False, the exception will be turned into a chat message and passed to the LLM. |
| 80 | +- `tool_invoker_kwargs`: Additional keyword arguments to pass to the ToolInvoker. |
| 81 | + |
| 82 | +**Raises**: |
| 83 | + |
| 84 | +- `TypeError`: If the chat_generator does not support tools parameter in its run method. |
| 85 | +- `ValueError`: If the exit_conditions are not valid. |
| 86 | + |
| 87 | +<a id="agent.Agent.warm_up"></a> |
| 88 | + |
| 89 | +#### Agent.warm\_up |
| 90 | + |
| 91 | +```python |
| 92 | +def warm_up() -> None |
| 93 | +``` |
| 94 | + |
| 95 | +Warm up the Agent. |
| 96 | + |
| 97 | +<a id="agent.Agent.to_dict"></a> |
| 98 | + |
| 99 | +#### Agent.to\_dict |
| 100 | + |
| 101 | +```python |
| 102 | +def to_dict() -> dict[str, Any] |
| 103 | +``` |
| 104 | + |
| 105 | +Serialize the component to a dictionary. |
| 106 | + |
| 107 | +**Returns**: |
| 108 | + |
| 109 | +Dictionary with serialized data |
| 110 | + |
| 111 | +<a id="agent.Agent.from_dict"></a> |
| 112 | + |
| 113 | +#### Agent.from\_dict |
| 114 | + |
| 115 | +```python |
| 116 | +@classmethod |
| 117 | +def from_dict(cls, data: dict[str, Any]) -> "Agent" |
| 118 | +``` |
| 119 | + |
| 120 | +Deserialize the agent from a dictionary. |
| 121 | + |
| 122 | +**Arguments**: |
| 123 | + |
| 124 | +- `data`: Dictionary to deserialize from |
| 125 | + |
| 126 | +**Returns**: |
| 127 | + |
| 128 | +Deserialized agent |
| 129 | + |
| 130 | +<a id="agent.Agent.run"></a> |
| 131 | + |
| 132 | +#### Agent.run |
| 133 | + |
| 134 | +```python |
| 135 | +def run(messages: list[ChatMessage], |
| 136 | + streaming_callback: Optional[StreamingCallbackT] = None, |
| 137 | + *, |
| 138 | + break_point: Optional[AgentBreakpoint] = None, |
| 139 | + snapshot: Optional[AgentSnapshot] = None, |
| 140 | + system_prompt: Optional[str] = None, |
| 141 | + tools: Optional[Union[list[Tool], Toolset, list[str]]] = None, |
| 142 | + **kwargs: Any) -> dict[str, Any] |
| 143 | +``` |
| 144 | + |
| 145 | +Process messages and execute tools until an exit condition is met. |
| 146 | + |
| 147 | +**Arguments**: |
| 148 | + |
| 149 | +- `messages`: List of Haystack ChatMessage objects to process. |
| 150 | +- `streaming_callback`: A callback that will be invoked when a response is streamed from the LLM. |
| 151 | +The same callback can be configured to emit tool results when a tool is called. |
| 152 | +- `break_point`: An AgentBreakpoint, can be a Breakpoint for the "chat_generator" or a ToolBreakpoint |
| 153 | +for "tool_invoker". |
| 154 | +- `snapshot`: A dictionary containing a snapshot of a previously saved agent execution. The snapshot contains |
| 155 | +the relevant information to restart the Agent execution from where it left off. |
| 156 | +- `system_prompt`: System prompt for the agent. If provided, it overrides the default system prompt. |
| 157 | +- `tools`: Optional list of Tool objects, a Toolset, or list of tool names to use for this run. |
| 158 | +When passing tool names, tools are selected from the Agent's originally configured tools. |
| 159 | +- `kwargs`: Additional data to pass to the State schema used by the Agent. |
| 160 | +The keys must match the schema defined in the Agent's `state_schema`. |
| 161 | + |
| 162 | +**Raises**: |
| 163 | + |
| 164 | +- `RuntimeError`: If the Agent component wasn't warmed up before calling `run()`. |
| 165 | +- `BreakpointException`: If an agent breakpoint is triggered. |
| 166 | + |
| 167 | +**Returns**: |
| 168 | + |
| 169 | +A dictionary with the following keys: |
| 170 | +- "messages": List of all messages exchanged during the agent's run. |
| 171 | +- "last_message": The last message exchanged during the agent's run. |
| 172 | +- Any additional keys defined in the `state_schema`. |
| 173 | + |
| 174 | +<a id="agent.Agent.run_async"></a> |
| 175 | + |
| 176 | +#### Agent.run\_async |
| 177 | + |
| 178 | +```python |
| 179 | +async def run_async(messages: list[ChatMessage], |
| 180 | + streaming_callback: Optional[StreamingCallbackT] = None, |
| 181 | + *, |
| 182 | + break_point: Optional[AgentBreakpoint] = None, |
| 183 | + snapshot: Optional[AgentSnapshot] = None, |
| 184 | + system_prompt: Optional[str] = None, |
| 185 | + tools: Optional[Union[list[Tool], Toolset, |
| 186 | + list[str]]] = None, |
| 187 | + **kwargs: Any) -> dict[str, Any] |
| 188 | +``` |
| 189 | + |
| 190 | +Asynchronously process messages and execute tools until the exit condition is met. |
| 191 | + |
| 192 | +This is the asynchronous version of the `run` method. It follows the same logic but uses |
| 193 | +asynchronous operations where possible, such as calling the `run_async` method of the ChatGenerator |
| 194 | +if available. |
| 195 | + |
| 196 | +**Arguments**: |
| 197 | + |
| 198 | +- `messages`: List of Haystack ChatMessage objects to process. |
| 199 | +- `streaming_callback`: An asynchronous callback that will be invoked when a response is streamed from the |
| 200 | +LLM. The same callback can be configured to emit tool results when a tool is called. |
| 201 | +- `break_point`: An AgentBreakpoint, can be a Breakpoint for the "chat_generator" or a ToolBreakpoint |
| 202 | +for "tool_invoker". |
| 203 | +- `snapshot`: A dictionary containing a snapshot of a previously saved agent execution. The snapshot contains |
| 204 | +the relevant information to restart the Agent execution from where it left off. |
| 205 | +- `system_prompt`: System prompt for the agent. If provided, it overrides the default system prompt. |
| 206 | +- `tools`: Optional list of Tool objects, a Toolset, or list of tool names to use for this run. |
| 207 | +- `kwargs`: Additional data to pass to the State schema used by the Agent. |
| 208 | +The keys must match the schema defined in the Agent's `state_schema`. |
| 209 | + |
| 210 | +**Raises**: |
| 211 | + |
| 212 | +- `RuntimeError`: If the Agent component wasn't warmed up before calling `run_async()`. |
| 213 | +- `BreakpointException`: If an agent breakpoint is triggered. |
| 214 | + |
| 215 | +**Returns**: |
| 216 | + |
| 217 | +A dictionary with the following keys: |
| 218 | +- "messages": List of all messages exchanged during the agent's run. |
| 219 | +- "last_message": The last message exchanged during the agent's run. |
| 220 | +- Any additional keys defined in the `state_schema`. |
| 221 | + |
| 222 | +<a id="state/state"></a> |
| 223 | + |
| 224 | +# Module state/state |
| 225 | + |
| 226 | +<a id="state/state.State"></a> |
| 227 | + |
| 228 | +## State |
| 229 | + |
| 230 | +State is a container for storing shared information during the execution of an Agent and its tools. |
| 231 | + |
| 232 | +For instance, State can be used to store documents, context, and intermediate results. |
| 233 | + |
| 234 | +Internally it wraps a `_data` dictionary defined by a `schema`. Each schema entry has: |
| 235 | +```json |
| 236 | + "parameter_name": { |
| 237 | + "type": SomeType, # expected type |
| 238 | + "handler": Optional[Callable[[Any, Any], Any]] # merge/update function |
| 239 | + } |
| 240 | + ``` |
| 241 | + |
| 242 | +Handlers control how values are merged when using the `set()` method: |
| 243 | +- For list types: defaults to `merge_lists` (concatenates lists) |
| 244 | +- For other types: defaults to `replace_values` (overwrites existing value) |
| 245 | + |
| 246 | +A `messages` field with type `list[ChatMessage]` is automatically added to the schema. |
| 247 | + |
| 248 | +This makes it possible for the Agent to read from and write to the same context. |
| 249 | + |
| 250 | +### Usage example |
| 251 | +```python |
| 252 | +from haystack.components.agents.state import State |
| 253 | + |
| 254 | +my_state = State( |
| 255 | + schema={"gh_repo_name": {"type": str}, "user_name": {"type": str}}, |
| 256 | + data={"gh_repo_name": "my_repo", "user_name": "my_user_name"} |
| 257 | +) |
| 258 | +``` |
| 259 | + |
| 260 | +<a id="state/state.State.__init__"></a> |
| 261 | + |
| 262 | +#### State.\_\_init\_\_ |
| 263 | + |
| 264 | +```python |
| 265 | +def __init__(schema: dict[str, Any], data: Optional[dict[str, Any]] = None) |
| 266 | +``` |
| 267 | + |
| 268 | +Initialize a State object with a schema and optional data. |
| 269 | + |
| 270 | +**Arguments**: |
| 271 | + |
| 272 | +- `schema`: Dictionary mapping parameter names to their type and handler configs. |
| 273 | +Type must be a valid Python type, and handler must be a callable function or None. |
| 274 | +If handler is None, the default handler for the type will be used. The default handlers are: |
| 275 | + - For list types: `haystack.agents.state.state_utils.merge_lists` |
| 276 | + - For all other types: `haystack.agents.state.state_utils.replace_values` |
| 277 | +- `data`: Optional dictionary of initial data to populate the state |
| 278 | + |
| 279 | +<a id="state/state.State.get"></a> |
| 280 | + |
| 281 | +#### State.get |
| 282 | + |
| 283 | +```python |
| 284 | +def get(key: str, default: Any = None) -> Any |
| 285 | +``` |
| 286 | + |
| 287 | +Retrieve a value from the state by key. |
| 288 | + |
| 289 | +**Arguments**: |
| 290 | + |
| 291 | +- `key`: Key to look up in the state |
| 292 | +- `default`: Value to return if key is not found |
| 293 | + |
| 294 | +**Returns**: |
| 295 | + |
| 296 | +Value associated with key or default if not found |
| 297 | + |
| 298 | +<a id="state/state.State.set"></a> |
| 299 | + |
| 300 | +#### State.set |
| 301 | + |
| 302 | +```python |
| 303 | +def set(key: str, |
| 304 | + value: Any, |
| 305 | + handler_override: Optional[Callable[[Any, Any], Any]] = None) -> None |
| 306 | +``` |
| 307 | + |
| 308 | +Set or merge a value in the state according to schema rules. |
| 309 | + |
| 310 | +Value is merged or overwritten according to these rules: |
| 311 | + - if handler_override is given, use that |
| 312 | + - else use the handler defined in the schema for 'key' |
| 313 | + |
| 314 | +**Arguments**: |
| 315 | + |
| 316 | +- `key`: Key to store the value under |
| 317 | +- `value`: Value to store or merge |
| 318 | +- `handler_override`: Optional function to override the default merge behavior |
| 319 | + |
| 320 | +<a id="state/state.State.data"></a> |
| 321 | + |
| 322 | +#### State.data |
| 323 | + |
| 324 | +```python |
| 325 | +@property |
| 326 | +def data() |
| 327 | +``` |
| 328 | + |
| 329 | +All current data of the state. |
| 330 | + |
| 331 | +<a id="state/state.State.has"></a> |
| 332 | + |
| 333 | +#### State.has |
| 334 | + |
| 335 | +```python |
| 336 | +def has(key: str) -> bool |
| 337 | +``` |
| 338 | + |
| 339 | +Check if a key exists in the state. |
| 340 | + |
| 341 | +**Arguments**: |
| 342 | + |
| 343 | +- `key`: Key to check for existence |
| 344 | + |
| 345 | +**Returns**: |
| 346 | + |
| 347 | +True if key exists in state, False otherwise |
| 348 | + |
| 349 | +<a id="state/state.State.to_dict"></a> |
| 350 | + |
| 351 | +#### State.to\_dict |
| 352 | + |
| 353 | +```python |
| 354 | +def to_dict() |
| 355 | +``` |
| 356 | + |
| 357 | +Convert the State object to a dictionary. |
| 358 | + |
| 359 | +<a id="state/state.State.from_dict"></a> |
| 360 | + |
| 361 | +#### State.from\_dict |
| 362 | + |
| 363 | +```python |
| 364 | +@classmethod |
| 365 | +def from_dict(cls, data: dict[str, Any]) |
| 366 | +``` |
| 367 | + |
| 368 | +Convert a dictionary back to a State object. |
0 commit comments