tools_api.md
1 --- 2 title: Tools 3 id: tools-api 4 description: Unified abstractions to represent tools across the framework. 5 slug: "/tools-api" 6 --- 7 8 <a id="tool"></a> 9 10 # Module tool 11 12 <a id="tool.Tool"></a> 13 14 ## Tool 15 16 Data class representing a Tool that Language Models can prepare a call for. 17 18 Accurate definitions of the textual attributes such as `name` and `description` 19 are important for the Language Model to correctly prepare the call. 20 21 **Arguments**: 22 23 - `name`: Name of the Tool. 24 - `description`: Description of the Tool. 25 - `parameters`: A JSON schema defining the parameters expected by the Tool. 26 - `function`: The function that will be invoked when the Tool is called. 27 - `outputs_to_string`: Optional dictionary defining how a tool outputs should be converted into a string. 28 If the source is provided only the specified output key is sent to the handler. 29 If the source is omitted the whole tool result is sent to the handler. 30 Example: 31 ```python 32 { 33 "source": "docs", "handler": format_documents 34 } 35 ``` 36 - `inputs_from_state`: Optional dictionary mapping state keys to tool parameter names. 37 Example: `{"repository": "repo"}` maps state's "repository" to tool's "repo" parameter. 38 - `outputs_to_state`: Optional dictionary defining how tool outputs map to keys within state as well as optional handlers. 39 If the source is provided only the specified output key is sent to the handler. 40 Example: 41 ```python 42 { 43 "documents": {"source": "docs", "handler": custom_handler} 44 } 45 ``` 46 If the source is omitted the whole tool result is sent to the handler. 47 Example: 48 ```python 49 { 50 "documents": {"handler": custom_handler} 51 } 52 ``` 53 54 <a id="tool.Tool.tool_spec"></a> 55 56 #### Tool.tool\_spec 57 58 ```python 59 @property 60 def tool_spec() -> dict[str, Any] 61 ``` 62 63 Return the Tool specification to be used by the Language Model. 64 65 <a id="tool.Tool.invoke"></a> 66 67 #### Tool.invoke 68 69 ```python 70 def invoke(**kwargs: Any) -> Any 71 ``` 72 73 Invoke the Tool with the provided keyword arguments. 74 75 <a id="tool.Tool.to_dict"></a> 76 77 #### Tool.to\_dict 78 79 ```python 80 def to_dict() -> dict[str, Any] 81 ``` 82 83 Serializes the Tool to a dictionary. 84 85 **Returns**: 86 87 Dictionary with serialized data. 88 89 <a id="tool.Tool.from_dict"></a> 90 91 #### Tool.from\_dict 92 93 ```python 94 @classmethod 95 def from_dict(cls, data: dict[str, Any]) -> "Tool" 96 ``` 97 98 Deserializes the Tool from a dictionary. 99 100 **Arguments**: 101 102 - `data`: Dictionary to deserialize from. 103 104 **Returns**: 105 106 Deserialized Tool. 107 108 <a id="from_function"></a> 109 110 # Module from\_function 111 112 <a id="from_function.create_tool_from_function"></a> 113 114 #### create\_tool\_from\_function 115 116 ```python 117 def create_tool_from_function( 118 function: Callable, 119 name: Optional[str] = None, 120 description: Optional[str] = None, 121 inputs_from_state: Optional[dict[str, str]] = None, 122 outputs_to_state: Optional[dict[str, dict[str, 123 Any]]] = None) -> "Tool" 124 ``` 125 126 Create a Tool instance from a function. 127 128 Allows customizing the Tool name and description. 129 For simpler use cases, consider using the `@tool` decorator. 130 131 ### Usage example 132 133 ```python 134 from typing import Annotated, Literal 135 from haystack.tools import create_tool_from_function 136 137 def get_weather( 138 city: Annotated[str, "the city for which to get the weather"] = "Munich", 139 unit: Annotated[Literal["Celsius", "Fahrenheit"], "the unit for the temperature"] = "Celsius"): 140 '''A simple function to get the current weather for a location.''' 141 return f"Weather report for {city}: 20 {unit}, sunny" 142 143 tool = create_tool_from_function(get_weather) 144 145 print(tool) 146 >>> Tool(name='get_weather', description='A simple function to get the current weather for a location.', 147 >>> parameters={ 148 >>> 'type': 'object', 149 >>> 'properties': { 150 >>> 'city': {'type': 'string', 'description': 'the city for which to get the weather', 'default': 'Munich'}, 151 >>> 'unit': { 152 >>> 'type': 'string', 153 >>> 'enum': ['Celsius', 'Fahrenheit'], 154 >>> 'description': 'the unit for the temperature', 155 >>> 'default': 'Celsius', 156 >>> }, 157 >>> } 158 >>> }, 159 >>> function=<function get_weather at 0x7f7b3a8a9b80>) 160 ``` 161 162 **Arguments**: 163 164 - `function`: The function to be converted into a Tool. 165 The function must include type hints for all parameters. 166 The function is expected to have basic python input types (str, int, float, bool, list, dict, tuple). 167 Other input types may work but are not guaranteed. 168 If a parameter is annotated using `typing.Annotated`, its metadata will be used as parameter description. 169 - `name`: The name of the Tool. If not provided, the name of the function will be used. 170 - `description`: The description of the Tool. If not provided, the docstring of the function will be used. 171 To intentionally leave the description empty, pass an empty string. 172 - `inputs_from_state`: Optional dictionary mapping state keys to tool parameter names. 173 Example: `{"repository": "repo"}` maps state's "repository" to tool's "repo" parameter. 174 - `outputs_to_state`: Optional dictionary defining how tool outputs map to state and message handling. 175 Example: 176 ```python 177 { 178 "documents": {"source": "docs", "handler": custom_handler}, 179 "message": {"source": "summary", "handler": format_summary} 180 } 181 ``` 182 183 **Raises**: 184 185 - `ValueError`: If any parameter of the function lacks a type hint. 186 - `SchemaGenerationError`: If there is an error generating the JSON schema for the Tool. 187 188 **Returns**: 189 190 The Tool created from the function. 191 192 <a id="from_function.tool"></a> 193 194 #### tool 195 196 ```python 197 def tool( 198 function: Optional[Callable] = None, 199 *, 200 name: Optional[str] = None, 201 description: Optional[str] = None, 202 inputs_from_state: Optional[dict[str, str]] = None, 203 outputs_to_state: Optional[dict[str, dict[str, Any]]] = None 204 ) -> Union[Tool, Callable[[Callable], Tool]] 205 ``` 206 207 Decorator to convert a function into a Tool. 208 209 Can be used with or without parameters: 210 @tool # without parameters 211 def my_function(): ... 212 213 @tool(name="custom_name") # with parameters 214 def my_function(): ... 215 216 ### Usage example 217 ```python 218 from typing import Annotated, Literal 219 from haystack.tools import tool 220 221 @tool 222 def get_weather( 223 city: Annotated[str, "the city for which to get the weather"] = "Munich", 224 unit: Annotated[Literal["Celsius", "Fahrenheit"], "the unit for the temperature"] = "Celsius"): 225 '''A simple function to get the current weather for a location.''' 226 return f"Weather report for {city}: 20 {unit}, sunny" 227 228 print(get_weather) 229 >>> Tool(name='get_weather', description='A simple function to get the current weather for a location.', 230 >>> parameters={ 231 >>> 'type': 'object', 232 >>> 'properties': { 233 >>> 'city': {'type': 'string', 'description': 'the city for which to get the weather', 'default': 'Munich'}, 234 >>> 'unit': { 235 >>> 'type': 'string', 236 >>> 'enum': ['Celsius', 'Fahrenheit'], 237 >>> 'description': 'the unit for the temperature', 238 >>> 'default': 'Celsius', 239 >>> }, 240 >>> } 241 >>> }, 242 >>> function=<function get_weather at 0x7f7b3a8a9b80>) 243 ``` 244 245 **Arguments**: 246 247 - `function`: The function to decorate (when used without parameters) 248 - `name`: Optional custom name for the tool 249 - `description`: Optional custom description 250 - `inputs_from_state`: Optional dictionary mapping state keys to tool parameter names 251 - `outputs_to_state`: Optional dictionary defining how tool outputs map to state and message handling 252 253 **Returns**: 254 255 Either a Tool instance or a decorator function that will create one 256 257 <a id="component_tool"></a> 258 259 # Module component\_tool 260 261 <a id="component_tool.ComponentTool"></a> 262 263 ## ComponentTool 264 265 A Tool that wraps Haystack components, allowing them to be used as tools by LLMs. 266 267 ComponentTool automatically generates LLM-compatible tool schemas from component input sockets, 268 which are derived from the component's `run` method signature and type hints. 269 270 271 Key features: 272 - Automatic LLM tool calling schema generation from component input sockets 273 - Type conversion and validation for component inputs 274 - Support for types: 275 - Dataclasses 276 - Lists of dataclasses 277 - Basic types (str, int, float, bool, dict) 278 - Lists of basic types 279 - Automatic name generation from component class name 280 - Description extraction from component docstrings 281 282 To use ComponentTool, you first need a Haystack component - either an existing one or a new one you create. 283 You can create a ComponentTool from the component by passing the component to the ComponentTool constructor. 284 Below is an example of creating a ComponentTool from an existing SerperDevWebSearch component. 285 286 ## Usage Example: 287 288 ```python 289 from haystack import component, Pipeline 290 from haystack.tools import ComponentTool 291 from haystack.components.websearch import SerperDevWebSearch 292 from haystack.utils import Secret 293 from haystack.components.tools.tool_invoker import ToolInvoker 294 from haystack.components.generators.chat import OpenAIChatGenerator 295 from haystack.dataclasses import ChatMessage 296 297 # Create a SerperDev search component 298 search = SerperDevWebSearch(api_key=Secret.from_env_var("SERPERDEV_API_KEY"), top_k=3) 299 300 # Create a tool from the component 301 tool = ComponentTool( 302 component=search, 303 name="web_search", # Optional: defaults to "serper_dev_web_search" 304 description="Search the web for current information on any topic" # Optional: defaults to component docstring 305 ) 306 307 # Create pipeline with OpenAIChatGenerator and ToolInvoker 308 pipeline = Pipeline() 309 pipeline.add_component("llm", OpenAIChatGenerator(model="gpt-4o-mini", tools=[tool])) 310 pipeline.add_component("tool_invoker", ToolInvoker(tools=[tool])) 311 312 # Connect components 313 pipeline.connect("llm.replies", "tool_invoker.messages") 314 315 message = ChatMessage.from_user("Use the web search tool to find information about Nikola Tesla") 316 317 # Run pipeline 318 result = pipeline.run({"llm": {"messages": [message]}}) 319 320 print(result) 321 ``` 322 323 <a id="component_tool.ComponentTool.__init__"></a> 324 325 #### ComponentTool.\_\_init\_\_ 326 327 ```python 328 def __init__( 329 component: Component, 330 name: Optional[str] = None, 331 description: Optional[str] = None, 332 parameters: Optional[dict[str, Any]] = None, 333 *, 334 outputs_to_string: Optional[dict[str, Union[str, Callable[[Any], 335 str]]]] = None, 336 inputs_from_state: Optional[dict[str, str]] = None, 337 outputs_to_state: Optional[dict[str, dict[str, Union[str, 338 Callable]]]] = None 339 ) -> None 340 ``` 341 342 Create a Tool instance from a Haystack component. 343 344 **Arguments**: 345 346 - `component`: The Haystack component to wrap as a tool. 347 - `name`: Optional name for the tool (defaults to snake_case of component class name). 348 - `description`: Optional description (defaults to component's docstring). 349 - `parameters`: A JSON schema defining the parameters expected by the Tool. 350 Will fall back to the parameters defined in the component's run method signature if not provided. 351 - `outputs_to_string`: Optional dictionary defining how a tool outputs should be converted into a string. 352 If the source is provided only the specified output key is sent to the handler. 353 If the source is omitted the whole tool result is sent to the handler. 354 Example: 355 ```python 356 { 357 "source": "docs", "handler": format_documents 358 } 359 ``` 360 - `inputs_from_state`: Optional dictionary mapping state keys to tool parameter names. 361 Example: `{"repository": "repo"}` maps state's "repository" to tool's "repo" parameter. 362 - `outputs_to_state`: Optional dictionary defining how tool outputs map to keys within state as well as optional handlers. 363 If the source is provided only the specified output key is sent to the handler. 364 Example: 365 ```python 366 { 367 "documents": {"source": "docs", "handler": custom_handler} 368 } 369 ``` 370 If the source is omitted the whole tool result is sent to the handler. 371 Example: 372 ```python 373 { 374 "documents": {"handler": custom_handler} 375 } 376 ``` 377 378 **Raises**: 379 380 - `ValueError`: If the component is invalid or schema generation fails. 381 382 <a id="component_tool.ComponentTool.to_dict"></a> 383 384 #### ComponentTool.to\_dict 385 386 ```python 387 def to_dict() -> dict[str, Any] 388 ``` 389 390 Serializes the ComponentTool to a dictionary. 391 392 <a id="component_tool.ComponentTool.from_dict"></a> 393 394 #### ComponentTool.from\_dict 395 396 ```python 397 @classmethod 398 def from_dict(cls, data: dict[str, Any]) -> "ComponentTool" 399 ``` 400 401 Deserializes the ComponentTool from a dictionary. 402 403 <a id="component_tool.ComponentTool.tool_spec"></a> 404 405 #### ComponentTool.tool\_spec 406 407 ```python 408 @property 409 def tool_spec() -> dict[str, Any] 410 ``` 411 412 Return the Tool specification to be used by the Language Model. 413 414 <a id="component_tool.ComponentTool.invoke"></a> 415 416 #### ComponentTool.invoke 417 418 ```python 419 def invoke(**kwargs: Any) -> Any 420 ``` 421 422 Invoke the Tool with the provided keyword arguments. 423 424 <a id="toolset"></a> 425 426 # Module toolset 427 428 <a id="toolset.Toolset"></a> 429 430 ## Toolset 431 432 A collection of related Tools that can be used and managed as a cohesive unit. 433 434 Toolset serves two main purposes: 435 436 1. Group related tools together: 437 Toolset allows you to organize related tools into a single collection, making it easier 438 to manage and use them as a unit in Haystack pipelines. 439 440 **Example**: 441 442 ```python 443 from haystack.tools import Tool, Toolset 444 from haystack.components.tools import ToolInvoker 445 446 # Define math functions 447 def add_numbers(a: int, b: int) -> int: 448 return a + b 449 450 def subtract_numbers(a: int, b: int) -> int: 451 return a - b 452 453 # Create tools with proper schemas 454 add_tool = Tool( 455 name="add", 456 description="Add two numbers", 457 parameters={ 458 "type": "object", 459 "properties": { 460 "a": {"type": "integer"}, 461 "b": {"type": "integer"} 462 }, 463 "required": ["a", "b"] 464 }, 465 function=add_numbers 466 ) 467 468 subtract_tool = Tool( 469 name="subtract", 470 description="Subtract b from a", 471 parameters={ 472 "type": "object", 473 "properties": { 474 "a": {"type": "integer"}, 475 "b": {"type": "integer"} 476 }, 477 "required": ["a", "b"] 478 }, 479 function=subtract_numbers 480 ) 481 482 # Create a toolset with the math tools 483 math_toolset = Toolset([add_tool, subtract_tool]) 484 485 # Use the toolset with a ToolInvoker or ChatGenerator component 486 invoker = ToolInvoker(tools=math_toolset) 487 ``` 488 489 2. Base class for dynamic tool loading: 490 By subclassing Toolset, you can create implementations that dynamically load tools 491 from external sources like OpenAPI URLs, MCP servers, or other resources. 492 493 494 **Example**: 495 496 ```python 497 from haystack.core.serialization import generate_qualified_class_name 498 from haystack.tools import Tool, Toolset 499 from haystack.components.tools import ToolInvoker 500 501 class CalculatorToolset(Toolset): 502 '''A toolset for calculator operations.''' 503 504 def __init__(self): 505 tools = self._create_tools() 506 super().__init__(tools) 507 508 def _create_tools(self): 509 # These Tool instances are obviously defined statically and for illustration purposes only. 510 # In a real-world scenario, you would dynamically load tools from an external source here. 511 tools = [] 512 add_tool = Tool( 513 name="add", 514 description="Add two numbers", 515 parameters={ 516 "type": "object", 517 "properties": {"a": {"type": "integer"}, "b": {"type": "integer"}}, 518 "required": ["a", "b"], 519 }, 520 function=lambda a, b: a + b, 521 ) 522 523 multiply_tool = Tool( 524 name="multiply", 525 description="Multiply two numbers", 526 parameters={ 527 "type": "object", 528 "properties": {"a": {"type": "integer"}, "b": {"type": "integer"}}, 529 "required": ["a", "b"], 530 }, 531 function=lambda a, b: a * b, 532 ) 533 534 tools.append(add_tool) 535 tools.append(multiply_tool) 536 537 return tools 538 539 def to_dict(self): 540 return { 541 "type": generate_qualified_class_name(type(self)), 542 "data": {}, # no data to serialize as we define the tools dynamically 543 } 544 545 @classmethod 546 def from_dict(cls, data): 547 return cls() # Recreate the tools dynamically during deserialization 548 549 # Create the dynamic toolset and use it with ToolInvoker 550 calculator_toolset = CalculatorToolset() 551 invoker = ToolInvoker(tools=calculator_toolset) 552 ``` 553 554 Toolset implements the collection interface (__iter__, __contains__, __len__, __getitem__), 555 making it behave like a list of Tools. This makes it compatible with components that expect 556 iterable tools, such as ToolInvoker or Haystack chat generators. 557 558 When implementing a custom Toolset subclass for dynamic tool loading: 559 - Perform the dynamic loading in the __init__ method 560 - Override to_dict() and from_dict() methods if your tools are defined dynamically 561 - Serialize endpoint descriptors rather than tool instances if your tools 562 are loaded from external sources 563 564 <a id="toolset.Toolset.__post_init__"></a> 565 566 #### Toolset.\_\_post\_init\_\_ 567 568 ```python 569 def __post_init__() 570 ``` 571 572 Validate and set up the toolset after initialization. 573 574 This handles the case when tools are provided during initialization. 575 576 <a id="toolset.Toolset.__iter__"></a> 577 578 #### Toolset.\_\_iter\_\_ 579 580 ```python 581 def __iter__() -> Iterator[Tool] 582 ``` 583 584 Return an iterator over the Tools in this Toolset. 585 586 This allows the Toolset to be used wherever a list of Tools is expected. 587 588 **Returns**: 589 590 An iterator yielding Tool instances 591 592 <a id="toolset.Toolset.__contains__"></a> 593 594 #### Toolset.\_\_contains\_\_ 595 596 ```python 597 def __contains__(item: Any) -> bool 598 ``` 599 600 Check if a tool is in this Toolset. 601 602 Supports checking by: 603 - Tool instance: tool in toolset 604 - Tool name: "tool_name" in toolset 605 606 **Arguments**: 607 608 - `item`: Tool instance or tool name string 609 610 **Returns**: 611 612 True if contained, False otherwise 613 614 <a id="toolset.Toolset.add"></a> 615 616 #### Toolset.add 617 618 ```python 619 def add(tool: Union[Tool, "Toolset"]) -> None 620 ``` 621 622 Add a new Tool or merge another Toolset. 623 624 **Arguments**: 625 626 - `tool`: A Tool instance or another Toolset to add 627 628 **Raises**: 629 630 - `ValueError`: If adding the tool would result in duplicate tool names 631 - `TypeError`: If the provided object is not a Tool or Toolset 632 633 <a id="toolset.Toolset.to_dict"></a> 634 635 #### Toolset.to\_dict 636 637 ```python 638 def to_dict() -> dict[str, Any] 639 ``` 640 641 Serialize the Toolset to a dictionary. 642 643 **Returns**: 644 645 A dictionary representation of the Toolset 646 Note for subclass implementers: 647 The default implementation is ideal for scenarios where Tool resolution is static. However, if your subclass 648 of Toolset dynamically resolves Tool instances from external sources—such as an MCP server, OpenAPI URL, or 649 a local OpenAPI specification—you should consider serializing the endpoint descriptor instead of the Tool 650 instances themselves. This strategy preserves the dynamic nature of your Toolset and minimizes the overhead 651 associated with serializing potentially large collections of Tool objects. Moreover, by serializing the 652 descriptor, you ensure that the deserialization process can accurately reconstruct the Tool instances, even 653 if they have been modified or removed since the last serialization. Failing to serialize the descriptor may 654 lead to issues where outdated or incorrect Tool configurations are loaded, potentially causing errors or 655 unexpected behavior. 656 657 <a id="toolset.Toolset.from_dict"></a> 658 659 #### Toolset.from\_dict 660 661 ```python 662 @classmethod 663 def from_dict(cls, data: dict[str, Any]) -> "Toolset" 664 ``` 665 666 Deserialize a Toolset from a dictionary. 667 668 **Arguments**: 669 670 - `data`: Dictionary representation of the Toolset 671 672 **Returns**: 673 674 A new Toolset instance 675 676 <a id="toolset.Toolset.__add__"></a> 677 678 #### Toolset.\_\_add\_\_ 679 680 ```python 681 def __add__(other: Union[Tool, "Toolset", list[Tool]]) -> "Toolset" 682 ``` 683 684 Concatenate this Toolset with another Tool, Toolset, or list of Tools. 685 686 **Arguments**: 687 688 - `other`: Another Tool, Toolset, or list of Tools to concatenate 689 690 **Raises**: 691 692 - `TypeError`: If the other parameter is not a Tool, Toolset, or list of Tools 693 - `ValueError`: If the combination would result in duplicate tool names 694 695 **Returns**: 696 697 A new Toolset containing all tools 698 699 <a id="toolset.Toolset.__len__"></a> 700 701 #### Toolset.\_\_len\_\_ 702 703 ```python 704 def __len__() -> int 705 ``` 706 707 Return the number of Tools in this Toolset. 708 709 **Returns**: 710 711 Number of Tools 712 713 <a id="toolset.Toolset.__getitem__"></a> 714 715 #### Toolset.\_\_getitem\_\_ 716 717 ```python 718 def __getitem__(index) 719 ``` 720 721 Get a Tool by index. 722 723 **Arguments**: 724 725 - `index`: Index of the Tool to get 726 727 **Returns**: 728 729 The Tool at the specified index