chore: import upstream snapshot with attribution
CodeQL / Analyze (python) (push) Has been cancelled
Update Platform Components Table / update (push) Has been cancelled
Docker image release / Build base image (push) Has been cancelled
Sync docs with Docusaurus / sync (push) Has been cancelled
Tests / Check if changed (push) Has been cancelled
Tests / format (push) Has been cancelled
Tests / check-imports (push) Has been cancelled
Tests / Unit / macos-latest (push) Has been cancelled
Tests / Unit / ubuntu-latest (push) Has been cancelled
Tests / Unit / windows-latest (push) Has been cancelled
Tests / mypy (push) Has been cancelled
Tests / Integration / ubuntu-latest (push) Has been cancelled
Tests / Integration / macos-latest (push) Has been cancelled
Tests / Integration / windows-latest (push) Has been cancelled
Tests / notify-slack-on-failure (push) Has been cancelled
Tests / Mark tests as completed (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:22:28 +08:00
commit c56bef871b
9296 changed files with 1854228 additions and 0 deletions
@@ -0,0 +1,528 @@
---
title: "Agents"
id: agents-api
description: "Tool-using agents with provider-agnostic chat model support."
slug: "/agents-api"
---
## agent
### Agent
A tool-using Agent powered by a large language model.
The Agent processes messages and calls tools until it meets an exit condition.
You can set one or more exit conditions to control when it stops.
For example, it can stop after generating a response or after calling a tool.
Without tools, the Agent works like a standard LLM that generates text. It produces one response and then stops.
### Usage examples
This is an example agent that:
1. Searches for tipping customs in France.
1. Uses a calculator to compute tips based on its findings.
1. Returns the final answer with its context.
```python
from haystack.components.agents import Agent
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.generators.utils import print_streaming_chunk
from haystack.dataclasses import ChatMessage
from haystack.tools import tool
from typing import Annotated, Literal
# Tool functions - in practice, these would have real implementations
@tool
def search(query: Annotated[str, "The search query"]) -> str:
'''Search for information on the web.'''
# Placeholder: would call actual search API
return "In France, a 15% service charge is typically included, but leaving 5-10% extra is appreciated."
@tool
def calculator(
operation: Annotated[Literal["multiply", "percentage"], "The mathematical operation to perform"],
a: Annotated[float, "First number"],
b: Annotated[float, "Second number"],
) -> float:
'''Perform mathematical calculations.'''
if operation == "multiply":
return a * b
elif operation == "percentage":
return (a / 100) * b
return 0
agent = Agent(
system_prompt=(
"You are a helpful assistant. Use the 'search' tool to find information "
"about a user's question and the 'calculator' tool to perform math."
),
chat_generator=OpenAIChatGenerator(),
tools=[search, calculator],
streaming_callback=print_streaming_chunk,
)
result = agent.run(
messages=[ChatMessage.from_user("Calculate the appropriate tip for an €85 meal in France")]
)
# Access the final response from the Agent
# print(result["last_message"].text)
```
#### Using a `user_prompt` template with variables
You can define a reusable `user_prompt` with Jinja2 template variables so the Agent can be invoked
with different inputs without manually constructing `ChatMessage` objects each time.
This is especially useful when embedding the Agent in a pipeline.
```python
from haystack.components.agents import Agent
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.tools import tool
from typing import Annotated
@tool
def translate(
text: Annotated[str, "The text to translate"],
target_language: Annotated[str, "The language to translate to"],
) -> str:
"""Translate text to a target language."""
# Placeholder: would call an actual translation API
return f"[Translated '{text}' to {target_language}]"
agent = Agent(
chat_generator=OpenAIChatGenerator(),
tools=[translate],
system_prompt="You are a helpful translation assistant.",
user_prompt="""{% message role="user"%}
Translate the following document to {{ language }}: {{ document }}
{% endmessage %}""",
required_variables=["language", "document"],
)
# The template variables 'language' and 'document' become inputs to the run method
result = agent.run(
messages=[],
language="French",
document="The weather is lovely today and the sun is shining.",
)
print(result["last_message"].text)
```
#### Using hooks to influence the run loop
Hooks are callables that receive the live `State` and run at specific points in the Agent loop:
- `before_llm`: runs before each chat-generator call.
- `before_tool`: runs after the model requests tool calls, before any tools run. After these hooks run, the Agent
re-reads the current last message from `state.data["messages"]`. If that message has tool calls, those calls are
executed. If it has no tool calls, no tools run for that step, no tool-based exit condition is triggered, and the
Agent loops back to the next LLM call unless `max_agent_steps` has been reached.
- `after_tool`: runs after tools execute, once their result messages are in `state.data["messages"]`, before the
exit check and the next LLM call. Use it to rewrite the freshly produced tool-result messages (e.g. offload,
redact, truncate, or summarize results). It does not run on the plain-text exit step, where no tools run.
- `on_exit`: runs when the Agent is about to stop on an exit condition. An `on_exit` hook can keep the Agent
running by setting `state.set("continue_run", True)`.
Use the `@hook` decorator to build a hook from a function. This `on_exit` hook keeps the Agent running until a
required tool has been called.
```python
from haystack.components.agents import Agent
from haystack.components.agents.state import State
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
from haystack.hooks import hook
from haystack.tools import tool
from typing import Annotated
@tool
def save_result(content: Annotated[str, "The result to save"]) -> str:
"""Save the final result."""
# Placeholder: would persist `content` to a database or the file system
return "saved"
@hook
def require_save(state: State) -> None:
if state.get("tool_call_counts", {}).get("save_result", 0) == 0:
state.set("messages", [ChatMessage.from_system("Call `save_result` before finishing.")])
state.set("continue_run", True) # keep the Agent running instead of stopping
agent = Agent(
chat_generator=OpenAIChatGenerator(),
tools=[save_result],
hooks={"on_exit": [require_save]},
)
```
#### __init__
```python
__init__(
*,
chat_generator: ChatGenerator,
tools: ToolsType | None = None,
system_prompt: str | None = None,
user_prompt: str | None = None,
required_variables: list[str] | Literal["*"] | None = None,
exit_conditions: list[str] | None = None,
state_schema: dict[str, Any] | None = None,
max_agent_steps: int = 100,
streaming_callback: StreamingCallbackT | None = None,
raise_on_tool_invocation_failure: bool = False,
tool_concurrency_limit: int = 4,
tool_streaming_callback_passthrough: bool = False,
hooks: dict[HookPoint, list[Hook]] | None = None
) -> None
```
Initialize the agent component.
**Parameters:**
- **chat_generator** (<code>ChatGenerator</code>) An instance of the chat generator that your agent should use. It must support tools.
- **tools** (<code>ToolsType | None</code>) A list of Tool and/or Toolset objects, or a single Toolset that the agent can use.
- **system_prompt** (<code>str | None</code>) System prompt for the agent. Can be a plain string template or a Jinja2 message template.
For details on the supported template syntax, refer to the
[documentation](https://docs.haystack.deepset.ai/docs/chatpromptbuilder#string-templates).
- **user_prompt** (<code>str | None</code>) User prompt for the agent. Can be a plain string template or a Jinja2 message template.
If provided, this is appended to the messages provided at runtime.
For details on the supported template syntax, refer to the
[documentation](https://docs.haystack.deepset.ai/docs/chatpromptbuilder#string-templates).
- **required_variables** (<code>list\[str\] | Literal['\*'] | None</code>) Lists the variables that must be provided as inputs to `user_prompt` or `system_prompt`.
If a required variable is not provided at run time, an exception is raised.
If set to `"*"`, all variables found in the prompts are required. Optional.
- **exit_conditions** (<code>list\[str\] | None</code>) List of conditions that will cause the agent to return.
Can include "text" if the agent should return when it generates a message without tool calls,
or tool names that will cause the agent to return once the tool was executed. Defaults to ["text"].
- **state_schema** (<code>dict\[str, Any\] | None</code>) A dictionary defining the agent's runtime state. Each key maps to a type config
with `"type"` (required) and an optional `"handler"` for merging values across tool calls.
Tools can read from and write to state keys using `inputs_from_state` and `outputs_to_state`.
- **max_agent_steps** (<code>int</code>) Maximum number of steps the agent will run before stopping. Defaults to 100.
A step is one chat-generator call plus the execution of every tool call the model requested in
that call (if any). If the agent reaches this number of steps it stops and returns the current state.
- **streaming_callback** (<code>StreamingCallbackT | None</code>) A callback that will be invoked when a response is streamed from the LLM.
The same callback can be configured to emit tool results when a tool is called.
- **raise_on_tool_invocation_failure** (<code>bool</code>) Should the agent raise an exception when a tool invocation fails?
If set to False, the exception will be turned into a chat message and passed to the LLM.
- **tool_concurrency_limit** (<code>int</code>) Maximum number of tool calls to execute at the same time.
Defaults to 4. Set to 1 to disable parallel tool execution.
- **tool_streaming_callback_passthrough** (<code>bool</code>) If True, pass the streaming callback to tools that accept it.
- **hooks** (<code>dict\[HookPoint, list\[Hook\]\] | None</code>) A dictionary mapping a hook point to a list of hooks the Agent runs at that point. Each hook
receives the live `State` and influences the run by mutating it in place; hooks for a hook point run in
list order. Valid hook points are:
- "before_llm": Runs before each chat-generator call.
- "before_tool": Runs after the model requests tool calls, before any tools run. After these hooks run,
the Agent re-reads the current last message from `state.data["messages"]`. If that message contains tool
calls, those calls are executed. If it does not, no tools run for that step, no tool-based exit condition
is triggered, and the Agent loops back to the next LLM call unless `max_agent_steps` has been reached.
- "after_tool": Runs after tools execute, once their result messages are in `state.data["messages"]`,
before the exit check and the next LLM call. Use it to rewrite the freshly produced tool-result messages
(e.g. offload, redact, truncate, or summarize results). It does not run on the plain-text exit step,
where no tools run.
- "on_exit": Runs when the Agent is about to stop on an exit condition. An "on_exit" hook can keep the
Agent running by setting the `continue_run` control flag (`state.set("continue_run", True)`), usually
alongside a message telling the model what to do next. "on_exit" hooks run when the Agent stops on an
exit condition, but not when it stops because `max_agent_steps` is reached.
**Raises:**
- <code>TypeError</code> If the chat_generator does not support tools parameter in its run method.
- <code>ValueError</code> If any `user_prompt` variable overlaps with the `state_schema` or `run` method parameters,
if a hook is registered under an unknown hook point, or if a hook is registered under a hook point it does
not support (via its `allowed_hook_points`).
#### warm_up
```python
warm_up() -> None
```
Warm up the tools, hooks, and the underlying chat generator.
#### warm_up_async
```python
warm_up_async() -> None
```
Warm up the tools, hooks, and the underlying chat generator on the serving event loop.
#### close
```python
close() -> None
```
Release the hooks' and the underlying chat generator's resources.
#### close_async
```python
close_async() -> None
```
Release the hooks' and the underlying chat generator's async resources.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> Agent
```
Deserialize the agent from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Dictionary to deserialize from.
**Returns:**
- <code>Agent</code> Deserialized agent.
#### run
```python
run(
messages: list[ChatMessage],
streaming_callback: StreamingCallbackT | None = None,
*,
generation_kwargs: dict[str, Any] | None = None,
tools: ToolsType | list[str] | None = None,
hook_context: dict[str, Any] | None = None,
**kwargs: Any
) -> dict[str, Any]
```
Process messages and execute tools until an exit condition is met.
**Parameters:**
- **messages** (<code>list\[ChatMessage\]</code>) List of Haystack ChatMessage objects to process.
- **streaming_callback** (<code>StreamingCallbackT | None</code>) A callback that will be invoked when a response is streamed from the LLM.
The same callback can be configured to emit tool results when a tool is called.
- **generation_kwargs** (<code>dict\[str, Any\] | None</code>) Additional keyword arguments for LLM. These parameters will
override the parameters passed during component initialization.
- **tools** (<code>ToolsType | list\[str\] | None</code>) Optional list of Tool objects, a Toolset, or list of tool names to use for this run.
When passing tool names, tools are selected from the Agent's originally configured tools.
- **hook_context** (<code>dict\[str, Any\] | None</code>) Optional dictionary of request-scoped resources made available to hooks via
`state.data.get("hook_context")`. Useful in web/server environments to provide per-request objects
(e.g., WebSocket connections, async queues, Redis pub/sub clients) that a hook can use, for
example a ConfirmationHook driving non-blocking user interaction.
- **kwargs** (<code>Any</code>) Additional data to pass to the State schema used by the Agent.
The keys must match the schema defined in the Agent's `state_schema`.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- "messages": List of all messages exchanged during the agent's run.
- "last_message": The last message exchanged during the agent's run.
- "step_count": The number of steps the agent ran. A step is one chat-generator call plus the
execution of every tool call the model requested in that call (if any). The counter is incremented
after each step completes, including the final step that hits an exit condition or `max_agent_steps`.
- "token_usage": Aggregated token usage from every LLM call in the run, summed from each LLM message's
`meta["usage"]`.
- "tool_call_counts": Mapping of tool name to the number of times that tool was invoked.
- Any additional keys defined in the `state_schema`.
#### run_async
```python
run_async(
messages: list[ChatMessage],
streaming_callback: StreamingCallbackT | None = None,
*,
generation_kwargs: dict[str, Any] | None = None,
tools: ToolsType | list[str] | None = None,
hook_context: dict[str, Any] | None = None,
**kwargs: Any
) -> dict[str, Any]
```
Asynchronously process messages and execute tools until the exit condition is met.
This is the asynchronous version of the `run` method. It follows the same logic but uses
asynchronous operations where possible, such as calling the `run_async` method of the ChatGenerator
if available.
**Parameters:**
- **messages** (<code>list\[ChatMessage\]</code>) List of Haystack ChatMessage objects to process.
- **streaming_callback** (<code>StreamingCallbackT | None</code>) An asynchronous callback that will be invoked when a response is streamed from the
LLM. The same callback can be configured to emit tool results when a tool is called.
- **generation_kwargs** (<code>dict\[str, Any\] | None</code>) Additional keyword arguments for LLM. These parameters will
override the parameters passed during component initialization.
- **tools** (<code>ToolsType | list\[str\] | None</code>) Optional list of Tool objects, a Toolset, or list of tool names to use for this run.
- **hook_context** (<code>dict\[str, Any\] | None</code>) Optional dictionary of request-scoped resources made available to hooks via
`state.data.get("hook_context")`. Useful in web/server environments to provide per-request objects
(e.g., WebSocket connections, async queues, Redis pub/sub clients) that a hook can use, for
example a ConfirmationHook driving non-blocking user interaction.
- **kwargs** (<code>Any</code>) Additional data to pass to the State schema used by the Agent.
The keys must match the schema defined in the Agent's `state_schema`.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- "messages": List of all messages exchanged during the agent's run.
- "last_message": The last message exchanged during the agent's run.
- "step_count": The number of steps the agent ran. A step is one chat-generator call plus the
execution of every tool call the model requested in that call (if any). The counter is incremented
after each step completes, including the final step that hits an exit condition or `max_agent_steps`.
- "token_usage": Aggregated token usage from every LLM call in the run, summed from each LLM message's
`meta["usage"]`.
- "tool_call_counts": Mapping of tool name to the number of times that tool was invoked.
- Any additional keys defined in the `state_schema`.
## state/state
### State
State is a container for storing shared information during the execution of an Agent and its tools.
For instance, State can be used to store documents, context, and intermediate results.
Internally it wraps a `_data` dictionary defined by a `schema`. Each schema entry has:
```json
"parameter_name": {
"type": SomeType, # expected type
"handler": Optional[Callable[[Any, Any], Any]] # merge/update function
}
```
Handlers control how values are merged when using the `set()` method:
- For list types: defaults to `merge_lists` (concatenates lists)
- For other types: defaults to `replace_values` (overwrites existing value)
A `messages` field with type `list[ChatMessage]` is automatically added to the schema.
This makes it possible for the Agent to read from and write to the same context.
### Usage example
```python
from haystack.components.agents.state import State
my_state = State(
schema={"gh_repo_name": {"type": str}, "user_name": {"type": str}},
data={"gh_repo_name": "my_repo", "user_name": "my_user_name"}
)
```
#### __init__
```python
__init__(schema: dict[str, Any], data: dict[str, Any] | None = None) -> None
```
Initialize a State object with a schema and optional data.
**Parameters:**
- **schema** (<code>dict\[str, Any\]</code>) Dictionary mapping parameter names to their type and handler configs.
Type must be a valid Python type, and handler must be a callable function or None.
If handler is None, the default handler for the type will be used. The default handlers are:
- For list types: `haystack.agents.state.state_utils.merge_lists`
- For all other types: `haystack.agents.state.state_utils.replace_values`
- **data** (<code>dict\[str, Any\] | None</code>) Optional dictionary of initial data to populate the state
#### get
```python
get(key: str, default: Any = None) -> Any
```
Retrieve a value from the state by key.
**Parameters:**
- **key** (<code>str</code>) Key to look up in the state
- **default** (<code>Any</code>) Value to return if key is not found
**Returns:**
- <code>Any</code> Value associated with key or default if not found
#### set
```python
set(
key: str,
value: Any,
handler_override: Callable[[Any, Any], Any] | None = None,
) -> None
```
Set or merge a value in the state according to schema rules.
Value is merged or overwritten according to these rules:
- if handler_override is given, use that
- else use the handler defined in the schema for 'key'
**Parameters:**
- **key** (<code>str</code>) Key to store the value under
- **value** (<code>Any</code>) Value to store or merge
- **handler_override** (<code>Callable\\[[Any, Any\], Any\] | None</code>) Optional function to override the default merge behavior
#### data
```python
data: dict[str, Any]
```
All current data of the state.
#### has
```python
has(key: str) -> bool
```
Check if a key exists in the state.
**Parameters:**
- **key** (<code>str</code>) Key to check for existence
**Returns:**
- <code>bool</code> True if key exists in state, False otherwise
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Convert the State object to a dictionary.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> State
```
Convert a dictionary back to a State object.
@@ -0,0 +1,551 @@
---
title: "Builders"
id: builders-api
description: "Extract the output of a Generator to an Answer format, and build prompts."
slug: "/builders-api"
---
## answer_builder
### AnswerBuilder
Converts a query and Generator replies into a `GeneratedAnswer` object.
AnswerBuilder parses Generator replies using custom regular expressions.
Check out the usage example below to see how it works.
Optionally, it can also take documents and metadata from the Generator to add to the `GeneratedAnswer` object.
AnswerBuilder works with both non-chat and chat Generators.
### Usage example
```python
from haystack.components.builders import AnswerBuilder
builder = AnswerBuilder(pattern="Answer: (.*)")
builder.run(query="What's the answer?", replies=["This is an argument. Answer: This is the answer."])
```
### Usage example with documents and reference pattern
```python
from haystack import Document
from haystack.components.builders import AnswerBuilder
replies = ["The capital of France is Paris [2]."]
docs = [
Document(content="Berlin is the capital of Germany."),
Document(content="Paris is the capital of France."),
Document(content="Rome is the capital of Italy."),
]
builder = AnswerBuilder(reference_pattern="\[(\d+)\]", return_only_referenced_documents=False)
result = builder.run(query="What is the capital of France?", replies=replies, documents=docs)["answers"][0]
print(f"Answer: {result.data}")
print("References:")
for doc in result.documents:
if doc.meta["referenced"]:
print(f"[{doc.meta['source_index']}] {doc.content}")
print("Other sources:")
for doc in result.documents:
if not doc.meta["referenced"]:
print(f"[{doc.meta['source_index']}] {doc.content}")
# >> Answer: The capital of France is Paris
# >> References:
# >> [2] Paris is the capital of France.
# >> Other sources:
# >> [1] Berlin is the capital of Germany.
# >> [3] Rome is the capital of Italy.
```
#### __init__
```python
__init__(
pattern: str | None = None,
reference_pattern: str | None = None,
last_message_only: bool = False,
*,
return_only_referenced_documents: bool = True,
expand_reference_ranges: bool = False
) -> None
```
Creates an instance of the AnswerBuilder component.
**Parameters:**
- **pattern** (<code>str | None</code>) The regular expression pattern to extract the answer text from the Generator.
If not specified, the entire response is used as the answer.
The regular expression can have one capture group at most.
If present, the capture group text
is used as the answer. If no capture group is present, the whole match is used as the answer.
Examples:
`[^\n]+$` finds "this is an answer" in a string "this is an argument.\\nthis is an answer".
`Answer: (.*)` finds "this is an answer" in a string "this is an argument. Answer: this is an answer".
- **reference_pattern** (<code>str | None</code>) The regular expression pattern used for parsing the document references.
If not specified, no parsing is done, and all documents are returned.
References need to be specified as indices of the input documents and start at [1].
Example: `\[(\d+)\]` finds "1" in a string "this is an answer[1]".
If this parameter is provided, documents metadata will contain a "referenced" key with a boolean value.
- **last_message_only** (<code>bool</code>) If False (default value), all messages are used as the answer.
If True, only the last message is used as the answer.
- **return_only_referenced_documents** (<code>bool</code>) To be used in conjunction with `reference_pattern`.
If True (default value), only the documents that were actually referenced in `replies` are returned.
If False, all documents are returned.
If `reference_pattern` is not provided, this parameter has no effect, and all documents are returned.
- **expand_reference_ranges** (<code>bool</code>) If True, reference ranges like `[6-10]` are expanded to documents 6 through 10.
Defaults to False for backwards compatibility.
When enabled with the default `reference_pattern`, a broader pattern is used automatically.
#### run
```python
run(
query: str,
replies: list[str] | list[ChatMessage],
meta: list[dict[str, Any]] | None = None,
documents: list[Document] | None = None,
pattern: str | None = None,
reference_pattern: str | None = None,
expand_reference_ranges: bool | None = None,
) -> dict[str, Any]
```
Turns the output of a Generator into `GeneratedAnswer` objects using regular expressions.
**Parameters:**
- **query** (<code>str</code>) The input query used as the Generator prompt.
- **replies** (<code>list\[str\] | list\[ChatMessage\]</code>) The output of the Generator. Can be a list of strings or a list of `ChatMessage` objects.
- **meta** (<code>list\[dict\[str, Any\]\] | None</code>) The metadata returned by the Generator. If not specified, the generated answer will contain no metadata.
- **documents** (<code>list\[Document\] | None</code>) The documents used as the Generator inputs. If specified, they are added to
the `GeneratedAnswer` objects.
The Document copies inside the returned `GeneratedAnswer.documents` each include a "source_index" key,
representing the document's 1-based position in the input list. The original input documents are
not modified.
When `reference_pattern` is provided:
- "referenced" key is added to the Document copies inside `GeneratedAnswer.documents`, indicating if
the document was referenced in the output.
- `return_only_referenced_documents` init parameter controls if all or only referenced documents are
returned.
- **pattern** (<code>str | None</code>) The regular expression pattern to extract the answer text from the Generator.
If not specified, the entire response is used as the answer.
The regular expression can have one capture group at most.
If present, the capture group text
is used as the answer. If no capture group is present, the whole match is used as the answer.
Examples:
`[^\n]+$` finds "this is an answer" in a string "this is an argument.\\nthis is an answer".
`Answer: (.*)` finds "this is an answer" in a string
"this is an argument. Answer: this is an answer".
- **reference_pattern** (<code>str | None</code>) The regular expression pattern used for parsing the document references.
If not specified, no parsing is done, and all documents are returned.
References need to be specified as indices of the input documents and start at [1].
Example: `\[(\d+)\]` finds "1" in a string "this is an answer[1]".
- **expand_reference_ranges** (<code>bool | None</code>) If True, reference ranges like `[6-10]` are expanded to documents 6 through 10.
If not specified, the value from the component initialization is used.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- `answers`: The answers received from the output of the Generator.
## chat_prompt_builder
### ChatPromptBuilder
Renders a chat prompt from a template using Jinja2 syntax.
A template can be a list of `ChatMessage` objects, or a special string, as shown in the usage examples.
It constructs prompts using static or dynamic templates, which you can update for each pipeline run.
Template variables in the template are required by default. To make any subset of variables optional,
set `required_variables` to an explicit list of the variables that should remain required; any variable
not listed becomes optional and defaults to an empty string when missing.
Set `required_variables` to `None` to mark every variable as optional.
### Usage examples
#### Static ChatMessage prompt template
```python
template = [ChatMessage.from_user("Translate to {{ target_language }}. Context: {{ snippet }}; Translation:")]
builder = ChatPromptBuilder(template=template)
builder.run(target_language="spanish", snippet="I can't speak spanish.")
```
#### Overriding static ChatMessage template at runtime
```python
template = [ChatMessage.from_user("Translate to {{ target_language }}. Context: {{ snippet }}; Translation:")]
builder = ChatPromptBuilder(template=template)
builder.run(target_language="spanish", snippet="I can't speak spanish.")
msg = "Translate to {{ target_language }} and summarize. Context: {{ snippet }}; Summary:"
summary_template = [ChatMessage.from_user(msg)]
builder.run(target_language="spanish", snippet="I can't speak spanish.", template=summary_template)
```
#### Dynamic ChatMessage prompt template
```python
from haystack.components.builders import ChatPromptBuilder
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
from haystack import Pipeline
# no parameter init, we don't use any runtime template variables
prompt_builder = ChatPromptBuilder()
llm = OpenAIChatGenerator(model="gpt-5-mini")
pipe = Pipeline()
pipe.add_component("prompt_builder", prompt_builder)
pipe.add_component("llm", llm)
pipe.connect("prompt_builder.prompt", "llm.messages")
location = "Berlin"
language = "English"
system_message = ChatMessage.from_system("You are an assistant giving information to tourists in {{language}}")
messages = [system_message, ChatMessage.from_user("Tell me about {{location}}")]
res = pipe.run(data={"prompt_builder": {"template_variables": {"location": location, "language": language},
"template": messages}})
print(res)
# >> {'llm': {'replies': [ChatMessage(_role=<ChatRole.ASSISTANT: 'assistant'>, _content=[TextContent(text=
# "Berlin is the capital city of Germany and one of the most vibrant
# and diverse cities in Europe. Here are some key things to know...Enjoy your time exploring the vibrant and dynamic
# capital of Germany!")], _name=None, _meta={'model': 'gpt-5-mini',
# 'index': 0, 'finish_reason': 'stop', 'usage': {'prompt_tokens': 27, 'completion_tokens': 681, 'total_tokens':
# 708}})]}}
messages = [system_message, ChatMessage.from_user("What's the weather forecast for {{location}} in the next {{day_count}} days?")]
res = pipe.run(data={"prompt_builder": {"template_variables": {"location": location, "day_count": "5"},
"template": messages}})
print(res)
# >> {'llm': {'replies': [ChatMessage(_role=<ChatRole.ASSISTANT: 'assistant'>, _content=[TextContent(text=
# "Here is the weather forecast for Berlin in the next 5
# days:\n\nDay 1: Mostly cloudy with a high of 22°C (72°F) and...so it's always a good idea to check for updates
# closer to your visit.")], _name=None, _meta={'model': 'gpt-5-mini',
# 'index': 0, 'finish_reason': 'stop', 'usage': {'prompt_tokens': 37, 'completion_tokens': 201,
# 'total_tokens': 238}})]}}
```
#### String prompt template
```python
from haystack.components.builders import ChatPromptBuilder
from haystack.dataclasses.image_content import ImageContent
template = """
{% message role="system" %}
You are a helpful assistant.
{% endmessage %}
{% message role="user" %}
Hello! I am {{user_name}}. What's the difference between the following images?
{% for image in images %}
{{ image | templatize_part }}
{% endfor %}
{% endmessage %}
"""
images = [ImageContent.from_file_path("test/test_files/images/apple.jpg"),
ImageContent.from_file_path("test/test_files/images/haystack-logo.png")]
builder = ChatPromptBuilder(template=template)
builder.run(user_name="John", images=images)
```
#### __init__
```python
__init__(
template: list[ChatMessage] | str | None = None,
required_variables: list[str] | Literal["*"] | None = "*",
variables: list[str] | None = None,
) -> None
```
Constructs a ChatPromptBuilder component.
**Parameters:**
- **template** (<code>list\[ChatMessage\] | str | None</code>) A list of `ChatMessage` objects or a string template. The component looks for Jinja2 template syntax and
renders the prompt with the provided variables. Provide the template in either
the `init` method`or the`run\` method.
- **required_variables** (<code>list\[str\] | Literal['\*'] | None</code>) List variables that must be provided as input to ChatPromptBuilder.
Defaults to `"*"`, which marks every variable found in the prompt as required.
Pass an explicit list to only require a subset of the variables; any variable not listed becomes
optional and is replaced with an empty string in the rendered prompt when missing.
Set to `None` to mark every variable as optional.
- **variables** (<code>list\[str\] | None</code>) List input variables to use in prompt templates instead of the ones inferred from the
`template` parameter. For example, to use more variables during prompt engineering than the ones present
in the default template, you can provide them here.
#### run
```python
run(
template: list[ChatMessage] | str | None = None,
template_variables: dict[str, Any] | None = None,
**kwargs: Any
) -> dict[str, list[ChatMessage]]
```
Renders the prompt template with the provided variables.
It applies the template variables to render the final prompt. You can provide variables with pipeline kwargs.
To overwrite the default template, you can set the `template` parameter.
To overwrite pipeline kwargs, you can set the `template_variables` parameter.
**Parameters:**
- **template** (<code>list\[ChatMessage\] | str | None</code>) An optional list of `ChatMessage` objects or string template to overwrite ChatPromptBuilder's default
template.
If `None`, the default template provided at initialization is used.
- **template_variables** (<code>dict\[str, Any\] | None</code>) An optional dictionary of template variables to overwrite the pipeline variables.
- **kwargs** (<code>Any</code>) Pipeline variables used for rendering the prompt.
**Returns:**
- <code>dict\[str, list\[ChatMessage\]\]</code> A dictionary with the following keys:
- `prompt`: The updated list of `ChatMessage` objects after rendering the templates.
**Raises:**
- <code>ValueError</code> If `chat_messages` is empty or contains elements that are not instances of `ChatMessage`.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Returns a dictionary representation of the component.
**Returns:**
- <code>dict\[str, Any\]</code> Serialized dictionary representation of the component.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> ChatPromptBuilder
```
Deserialize this component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) The dictionary to deserialize and create the component.
**Returns:**
- <code>ChatPromptBuilder</code> The deserialized component.
## prompt_builder
### PromptBuilder
Renders a prompt filling in any variables so that it can send it to a Generator.
The prompt uses Jinja2 template syntax.
The variables in the default template are used as PromptBuilder's input and are all required by default.
To make any subset of variables optional, set `required_variables` to an explicit list of the variables that
should remain required. Optional variables are replaced with an empty string in the rendered prompt.
To try out different prompts, you can replace the prompt template at runtime by
providing a template for each pipeline run invocation.
### Usage examples
#### On its own
This example uses PromptBuilder to render a prompt template and fill it with `target_language`
and `snippet`. PromptBuilder returns a prompt with the string "Translate the following context to Spanish.
Context: I can't speak Spanish.; Translation:".
```python
from haystack.components.builders import PromptBuilder
template = "Translate the following context to {{ target_language }}. Context: {{ snippet }}; Translation:"
builder = PromptBuilder(template=template)
builder.run(target_language="spanish", snippet="I can't speak spanish.")
```
#### In a Pipeline
This is an example of a RAG pipeline where PromptBuilder renders a custom prompt template and fills it
with the contents of the retrieved documents and a query. The rendered prompt is then sent to a ChatGenerator.
```python
from haystack import Pipeline, Document
from haystack.utils import Secret
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.builders.prompt_builder import PromptBuilder
# in a real world use case documents could come from a retriever, web, or any other source
documents = [Document(content="Joe lives in Berlin"), Document(content="Joe is a software engineer")]
prompt_template = """
Given these documents, answer the question.
Documents:
{% for doc in documents %}
{{ doc.content }}
{% endfor %}
Question: {{query}}
Answer:
"""
p = Pipeline()
p.add_component(instance=PromptBuilder(template=prompt_template), name="prompt_builder")
p.add_component(instance=OpenAIChatGenerator(api_key=Secret.from_env_var("OPENAI_API_KEY")), name="llm")
p.connect("prompt_builder", "llm")
question = "Where does Joe live?"
result = p.run({"prompt_builder": {"documents": documents, "query": question}})
print(result)
```
#### Changing the template at runtime (prompt engineering)
You can change the prompt template of an existing pipeline, like in this example:
```python
documents = [
Document(content="Joe lives in Berlin", meta={"name": "doc1"}),
Document(content="Joe is a software engineer", meta={"name": "doc1"}),
]
new_template = """
You are a helpful assistant.
Given these documents, answer the question.
Documents:
{% for doc in documents %}
Document {{ loop.index }}:
Document name: {{ doc.meta['name'] }}
{{ doc.content }}
{% endfor %}
Question: {{ query }}
Answer:
"""
p.run({
"prompt_builder": {
"documents": documents,
"query": question,
"template": new_template,
},
})
```
To replace the variables in the default template when testing your prompt,
pass the new variables in the `variables` parameter.
#### Overwriting variables at runtime
To overwrite the values of variables, use `template_variables` during runtime:
```python
language_template = """
You are a helpful assistant.
Given these documents, answer the question.
Documents:
{% for doc in documents %}
Document {{ loop.index }}:
Document name: {{ doc.meta['name'] }}
{{ doc.content }}
{% endfor %}
Question: {{ query }}
Please provide your answer in {{ answer_language | default('English') }}
Answer:
"""
p.run({
"prompt_builder": {
"documents": documents,
"query": question,
"template": language_template,
"template_variables": {"answer_language": "German"},
},
})
```
Note that `language_template` introduces variable `answer_language` which is not bound to any pipeline variable.
If not set otherwise, it will use its default value 'English'.
This example overwrites its value to 'German'.
Use `template_variables` to overwrite pipeline variables (such as documents) as well.
#### __init__
```python
__init__(
template: str,
required_variables: list[str] | Literal["*"] | None = "*",
variables: list[str] | None = None,
) -> None
```
Constructs a PromptBuilder component.
**Parameters:**
- **template** (<code>str</code>) A prompt template that uses Jinja2 syntax to add variables. For example:
`"Summarize this document: {{ documents[0].content }}\nSummary:"`
It's used to render the prompt.
The variables in the default template are input for PromptBuilder and are all required by default.
- **required_variables** (<code>list\[str\] | Literal['\*'] | None</code>) List variables that must be provided as input to PromptBuilder.
Defaults to `"*"`, which marks every variable found in the prompt as required.
Pass an explicit list to only require a subset of the variables; any variable not listed becomes
optional and is replaced with an empty string in the rendered prompt when missing.
Set to `None` to mark every variable as optional.
- **variables** (<code>list\[str\] | None</code>) List input variables to use in prompt templates instead of the ones inferred from the
`template` parameter. For example, to use more variables during prompt engineering than the ones present
in the default template, you can provide them here.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Returns a dictionary representation of the component.
**Returns:**
- <code>dict\[str, Any\]</code> Serialized dictionary representation of the component.
#### run
```python
run(
template: str | None = None,
template_variables: dict[str, Any] | None = None,
**kwargs: Any
) -> dict[str, Any]
```
Renders the prompt template with the provided variables.
It applies the template variables to render the final prompt. You can provide variables via pipeline kwargs.
In order to overwrite the default template, you can set the `template` parameter.
In order to overwrite pipeline kwargs, you can set the `template_variables` parameter.
**Parameters:**
- **template** (<code>str | None</code>) An optional string template to overwrite PromptBuilder's default template. If None, the default template
provided at initialization is used.
- **template_variables** (<code>dict\[str, Any\] | None</code>) An optional dictionary of template variables to overwrite the pipeline variables.
- **kwargs** (<code>Any</code>) Pipeline variables used for rendering the prompt.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- `prompt`: The updated prompt text after rendering the prompt template.
**Raises:**
- <code>ValueError</code> If any of the required template variables is not provided.
@@ -0,0 +1,114 @@
---
title: "Caching"
id: caching-api
description: "Checks if any document coming from the given URL is already present in the store."
slug: "/caching-api"
---
## cache_checker
### CacheChecker
Checks for the presence of documents in a Document Store based on a specified field in each document's metadata.
If matching documents are found, they are returned as "hits". If not found in the cache, the items
are returned as "misses".
### Usage example
```python
from haystack import Document
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.components.caching.cache_checker import CacheChecker
docstore = InMemoryDocumentStore()
documents = [
Document(content="doc1", meta={"url": "https://example.com/1"}),
Document(content="doc2", meta={"url": "https://example.com/2"}),
Document(content="doc3", meta={"url": "https://example.com/1"}),
Document(content="doc4", meta={"url": "https://example.com/2"}),
]
docstore.write_documents(documents)
checker = CacheChecker(docstore, cache_field="url")
results = checker.run(items=["https://example.com/1", "https://example.com/5"])
assert results == {"hits": [documents[0], documents[2]], "misses": ["https://example.com/5"]}
```
#### __init__
```python
__init__(document_store: DocumentStore, cache_field: str) -> None
```
Creates a CacheChecker component.
**Parameters:**
- **document_store** (<code>DocumentStore</code>) Document Store to check for the presence of specific documents.
- **cache_field** (<code>str</code>) Name of the document's metadata field
to check for cache hits.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> CacheChecker
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Dictionary to deserialize from.
**Returns:**
- <code>CacheChecker</code> Deserialized component.
#### run
```python
run(items: list[Any]) -> dict[str, Any]
```
Checks if any document associated with the specified cache field is already present in the store.
**Parameters:**
- **items** (<code>list\[Any\]</code>) Values to be checked against the cache field.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with two keys:
- `hits` - Documents that matched with at least one of the items.
- `misses` - Items that were not present in any documents.
#### run_async
```python
run_async(items: list[Any]) -> dict[str, Any]
```
Asynchronously checks if any document associated with the specified cache field is already present in the store.
**Parameters:**
- **items** (<code>list\[Any\]</code>) Values to be checked against the cache field.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with two keys:
- `hits` - Documents that matched with at least one of the items.
- `misses` - Items that were not present in any documents.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,598 @@
---
title: "Document Stores"
id: document-stores-api
description: "Stores your texts and meta data and provides them to the Retriever at query time."
slug: "/document-stores-api"
---
## document_store
### BM25DocumentStats
A dataclass for managing document statistics for BM25 retrieval.
**Parameters:**
- **freq_token** (<code>dict\[str, int\]</code>) A Counter of token frequencies in the document.
- **doc_len** (<code>int</code>) Number of tokens in the document.
### InMemoryDocumentStore
Stores data in-memory. It's ephemeral and cannot be saved to disk.
#### __init__
```python
__init__(
bm25_tokenization_regex: str = "(?u)\\b\\w+\\b",
bm25_algorithm: Literal["BM25Okapi", "BM25L", "BM25Plus"] = "BM25L",
bm25_parameters: dict | None = None,
embedding_similarity_function: Literal[
"dot_product", "cosine"
] = "dot_product",
index: str | None = None,
shared: bool = True,
async_executor: ThreadPoolExecutor | None = None,
return_embedding: bool = True,
) -> None
```
Initializes the DocumentStore.
**Parameters:**
- **bm25_tokenization_regex** (<code>str</code>) The regular expression used to tokenize the text for BM25 retrieval.
- **bm25_algorithm** (<code>Literal['BM25Okapi', 'BM25L', 'BM25Plus']</code>) The BM25 algorithm to use. One of "BM25Okapi", "BM25L", or "BM25Plus".
- **bm25_parameters** (<code>dict | None</code>) Parameters for BM25 implementation in a dictionary format.
For example: `{'k1':1.5, 'b':0.75, 'epsilon':0.25}`
You can learn more about these parameters by visiting https://github.com/dorianbrown/rank_bm25.
- **embedding_similarity_function** (<code>Literal['dot_product', 'cosine']</code>) The similarity function used to compare Documents embeddings.
One of "dot_product" (default) or "cosine". To choose the most appropriate function, look for information
about your embedding model.
- **index** (<code>str | None</code>) A specific index to store the documents. If not specified, a random UUID is used.
When `shared` is True, instances using the same index share the same documents.
- **shared** (<code>bool</code>) Whether the documents live in process-global storage shared across instances using the same
index (True, the default), or are kept instance-local and freed when this instance is garbage collected
(False). Shared storage persists for the lifetime of the process, so prefer `shared=False` for stores
that are created frequently (for example per request) to avoid unbounded memory growth.
- **async_executor** (<code>ThreadPoolExecutor | None</code>) Optional ThreadPoolExecutor to use for async calls. If not provided, a single-threaded
executor will be initialized and used.
- **return_embedding** (<code>bool</code>) Whether to return the embedding of the retrieved Documents. Default is True.
#### shutdown
```python
shutdown() -> None
```
Explicitly shutdown the executor if we own it.
#### storage
```python
storage: dict[str, Document]
```
Utility property that returns the storage used by this instance of InMemoryDocumentStore.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> InMemoryDocumentStore
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) The dictionary to deserialize from.
**Returns:**
- <code>InMemoryDocumentStore</code> The deserialized component.
#### save_to_disk
```python
save_to_disk(path: str) -> None
```
Write the database and its data to disk as a JSON file.
**Parameters:**
- **path** (<code>str</code>) The path to the JSON file.
#### load_from_disk
```python
load_from_disk(path: str) -> InMemoryDocumentStore
```
Load the database and its data from disk as a JSON file.
**Parameters:**
- **path** (<code>str</code>) The path to the JSON file.
**Returns:**
- <code>InMemoryDocumentStore</code> The loaded InMemoryDocumentStore.
#### count_documents
```python
count_documents() -> int
```
Returns the number of documents present in the DocumentStore.
#### filter_documents
```python
filter_documents(filters: dict[str, Any] | None = None) -> list[Document]
```
Returns the documents that match the filters provided.
**Parameters:**
- **filters** (<code>dict\[str, Any\] | None</code>) The filters to apply. For a detailed specification of the filters, refer to the
[documentation](https://docs.haystack.deepset.ai/docs/metadata-filtering).
**Returns:**
- <code>list\[Document\]</code> A list of Documents that match the given filters.
#### write_documents
```python
write_documents(
documents: list[Document], policy: DuplicatePolicy = DuplicatePolicy.NONE
) -> int
```
Refer to the DocumentStore.write_documents() protocol documentation.
If `policy` is set to `DuplicatePolicy.NONE` defaults to `DuplicatePolicy.FAIL`.
#### delete_documents
```python
delete_documents(document_ids: list[str]) -> None
```
Deletes all documents with matching document_ids from the DocumentStore.
**Parameters:**
- **document_ids** (<code>list\[str\]</code>) The document_ids to delete.
#### delete_all_documents
```python
delete_all_documents() -> None
```
Deletes all documents in the document store.
#### update_by_filter
```python
update_by_filter(filters: dict[str, Any], meta: dict[str, Any]) -> int
```
Updates the metadata of all documents that match the provided filters.
**Parameters:**
- **filters** (<code>dict\[str, Any\]</code>) The filters to apply to select documents for updating.
For filter syntax, see filter_documents.
- **meta** (<code>dict\[str, Any\]</code>) The metadata fields to update. These will be merged with existing metadata.
**Returns:**
- <code>int</code> The number of documents updated.
**Raises:**
- <code>ValueError</code> if filters have invalid syntax.
#### delete_by_filter
```python
delete_by_filter(filters: dict[str, Any]) -> int
```
Deletes all documents that match the provided filters.
**Parameters:**
- **filters** (<code>dict\[str, Any\]</code>) The filters to apply to select documents for deletion.
For filter syntax, see filter_documents.
**Returns:**
- <code>int</code> The number of documents deleted.
**Raises:**
- <code>ValueError</code> if filters have invalid syntax.
#### count_documents_by_filter
```python
count_documents_by_filter(filters: dict[str, Any]) -> int
```
Returns the number of documents that match the provided filters.
**Parameters:**
- **filters** (<code>dict\[str, Any\]</code>) The filters to apply.
For a detailed specification of the filters, refer to the
[documentation](https://docs.haystack.deepset.ai/docs/metadata-filtering).
**Returns:**
- <code>int</code> The number of documents that match the filters.
#### count_unique_metadata_by_filter
```python
count_unique_metadata_by_filter(
filters: dict[str, Any], metadata_fields: list[str]
) -> dict[str, int]
```
Returns the number of unique values for each specified metadata field from documents matching the filters.
**Parameters:**
- **filters** (<code>dict\[str, Any\]</code>) The filters to apply.
For a detailed specification of the filters, refer to the
[documentation](https://docs.haystack.deepset.ai/docs/metadata-filtering).
- **metadata_fields** (<code>list\[str\]</code>) List of field names to count unique values for.
Field names can include or omit the "meta." prefix.
**Returns:**
- <code>dict\[str, int\]</code> A dictionary mapping each metadata field name (without "meta." prefix)
to the count of its unique values among the filtered documents.
#### get_metadata_fields_info
```python
get_metadata_fields_info() -> dict[str, dict[str, str]]
```
Returns information about the metadata fields present in the stored documents.
Types are inferred from the stored values (keyword, int, float, boolean).
**Returns:**
- <code>dict\[str, dict\[str, str\]\]</code> A dictionary mapping each metadata field name to a dict with a "type" key.
#### get_metadata_field_min_max
```python
get_metadata_field_min_max(metadata_field: str) -> dict[str, Any]
```
Returns the minimum and maximum values for the given metadata field across all documents.
**Parameters:**
- **metadata_field** (<code>str</code>) The metadata field name. Can include or omit the "meta." prefix.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with "min" and "max" keys. Returns `{"min": None, "max": None}`
if the field is missing or has no values.
#### get_metadata_field_unique_values
```python
get_metadata_field_unique_values(
metadata_field: str, search_term: str | None = None
) -> tuple[list[str], int]
```
Returns unique values for a metadata field, optionally filtered by a search term in content.
**Parameters:**
- **metadata_field** (<code>str</code>) The metadata field name. Can include or omit the "meta." prefix.
- **search_term** (<code>str | None</code>) If set, only documents whose content contains this term (case-insensitive)
are considered.
**Returns:**
- <code>tuple\[list\[str\], int\]</code> A tuple of (list of unique values, total count of unique values).
#### bm25_retrieval
```python
bm25_retrieval(
query: str,
filters: dict[str, Any] | None = None,
top_k: int = 10,
scale_score: bool = False,
) -> list[Document]
```
Retrieves documents that are most relevant to the query using BM25 algorithm.
**Parameters:**
- **query** (<code>str</code>) The query string.
- **filters** (<code>dict\[str, Any\] | None</code>) A dictionary with filters to narrow down the search space.
- **top_k** (<code>int</code>) The number of top documents to retrieve. Default is 10.
- **scale_score** (<code>bool</code>) Whether to scale the scores of the retrieved documents. Default is False.
**Returns:**
- <code>list\[Document\]</code> A list of the top_k documents most relevant to the query.
#### embedding_retrieval
```python
embedding_retrieval(
query_embedding: list[float],
filters: dict[str, Any] | None = None,
top_k: int = 10,
scale_score: bool = False,
return_embedding: bool | None = False,
) -> list[Document]
```
Retrieves documents that are most similar to the query embedding using a vector similarity metric.
**Parameters:**
- **query_embedding** (<code>list\[float\]</code>) Embedding of the query.
- **filters** (<code>dict\[str, Any\] | None</code>) A dictionary with filters to narrow down the search space.
- **top_k** (<code>int</code>) The number of top documents to retrieve. Default is 10.
- **scale_score** (<code>bool</code>) Whether to scale the scores of the retrieved Documents. Default is False.
- **return_embedding** (<code>bool | None</code>) Whether to return the embedding of the retrieved Documents.
If not provided, the value of the `return_embedding` parameter set at component
initialization will be used. Default is False.
**Returns:**
- <code>list\[Document\]</code> A list of the top_k documents most relevant to the query.
**Raises:**
- <code>ValueError</code> if filters have invalid syntax.
#### count_documents_async
```python
count_documents_async() -> int
```
Returns the number of documents present in the DocumentStore.
#### filter_documents_async
```python
filter_documents_async(filters: dict[str, Any] | None = None) -> list[Document]
```
Returns the documents that match the filters provided.
**Parameters:**
- **filters** (<code>dict\[str, Any\] | None</code>) The filters to apply. For a detailed specification of the filters, refer to the
[documentation](https://docs.haystack.deepset.ai/docs/metadata-filtering).
**Returns:**
- <code>list\[Document\]</code> A list of Documents that match the given filters.
#### write_documents_async
```python
write_documents_async(
documents: list[Document], policy: DuplicatePolicy = DuplicatePolicy.NONE
) -> int
```
Refer to the DocumentStore.write_documents() protocol documentation.
If `policy` is set to `DuplicatePolicy.NONE` defaults to `DuplicatePolicy.FAIL`.
#### delete_documents_async
```python
delete_documents_async(document_ids: list[str]) -> None
```
Deletes all documents with matching document_ids from the DocumentStore.
**Parameters:**
- **document_ids** (<code>list\[str\]</code>) The document_ids to delete.
#### update_by_filter_async
```python
update_by_filter_async(filters: dict[str, Any], meta: dict[str, Any]) -> int
```
Updates the metadata of all documents that match the provided filters.
**Parameters:**
- **filters** (<code>dict\[str, Any\]</code>) The filters to apply to select documents for updating.
For filter syntax, see filter_documents.
- **meta** (<code>dict\[str, Any\]</code>) The metadata fields to update. These will be merged with existing metadata.
**Returns:**
- <code>int</code> The number of documents updated.
#### count_documents_by_filter_async
```python
count_documents_by_filter_async(filters: dict[str, Any]) -> int
```
Returns the number of documents that match the provided filters.
**Parameters:**
- **filters** (<code>dict\[str, Any\]</code>) The filters to apply.
For a detailed specification of the filters, refer to the
[documentation](https://docs.haystack.deepset.ai/docs/metadata-filtering).
**Returns:**
- <code>int</code> The number of documents that match the filters.
#### count_unique_metadata_by_filter_async
```python
count_unique_metadata_by_filter_async(
filters: dict[str, Any], metadata_fields: list[str]
) -> dict[str, int]
```
Returns the number of unique values for each specified metadata field from documents matching the filters.
**Parameters:**
- **filters** (<code>dict\[str, Any\]</code>) The filters to apply.
For a detailed specification of the filters, refer to the
[documentation](https://docs.haystack.deepset.ai/docs/metadata-filtering).
- **metadata_fields** (<code>list\[str\]</code>) List of field names to count unique values for.
Field names can include or omit the "meta." prefix.
**Returns:**
- <code>dict\[str, int\]</code> A dictionary mapping each metadata field name (without "meta." prefix)
to the count of its unique values among the filtered documents.
#### get_metadata_fields_info_async
```python
get_metadata_fields_info_async() -> dict[str, dict[str, str]]
```
Returns information about the metadata fields present in the stored documents.
Types are inferred from the stored values (keyword, int, float, boolean).
**Returns:**
- <code>dict\[str, dict\[str, str\]\]</code> A dictionary mapping each metadata field name to a dict with a "type" key.
#### get_metadata_field_min_max_async
```python
get_metadata_field_min_max_async(metadata_field: str) -> dict[str, Any]
```
Returns the minimum and maximum values for the given metadata field across all documents.
**Parameters:**
- **metadata_field** (<code>str</code>) The metadata field name. Can include or omit the "meta." prefix.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with "min" and "max" keys. Returns `{"min": None, "max": None}`
if the field is missing or has no values.
#### get_metadata_field_unique_values_async
```python
get_metadata_field_unique_values_async(
metadata_field: str, search_term: str | None = None
) -> tuple[list[str], int]
```
Returns unique values for a metadata field, optionally filtered by a search term in content.
**Parameters:**
- **metadata_field** (<code>str</code>) The metadata field name. Can include or omit the "meta." prefix.
- **search_term** (<code>str | None</code>) If set, only documents whose content contains this term (case-insensitive)
are considered.
**Returns:**
- <code>tuple\[list\[str\], int\]</code> A tuple of (list of unique values, total count of unique values).
#### delete_all_documents_async
```python
delete_all_documents_async() -> None
```
Deletes all documents in the document store.
#### bm25_retrieval_async
```python
bm25_retrieval_async(
query: str,
filters: dict[str, Any] | None = None,
top_k: int = 10,
scale_score: bool = False,
) -> list[Document]
```
Retrieves documents that are most relevant to the query using BM25 algorithm.
**Parameters:**
- **query** (<code>str</code>) The query string.
- **filters** (<code>dict\[str, Any\] | None</code>) A dictionary with filters to narrow down the search space.
- **top_k** (<code>int</code>) The number of top documents to retrieve. Default is 10.
- **scale_score** (<code>bool</code>) Whether to scale the scores of the retrieved documents. Default is False.
**Returns:**
- <code>list\[Document\]</code> A list of the top_k documents most relevant to the query.
#### embedding_retrieval_async
```python
embedding_retrieval_async(
query_embedding: list[float],
filters: dict[str, Any] | None = None,
top_k: int = 10,
scale_score: bool = False,
return_embedding: bool = False,
) -> list[Document]
```
Retrieves documents that are most similar to the query embedding using a vector similarity metric.
**Parameters:**
- **query_embedding** (<code>list\[float\]</code>) Embedding of the query.
- **filters** (<code>dict\[str, Any\] | None</code>) A dictionary with filters to narrow down the search space.
- **top_k** (<code>int</code>) The number of top documents to retrieve. Default is 10.
- **scale_score** (<code>bool</code>) Whether to scale the scores of the retrieved Documents. Default is False.
- **return_embedding** (<code>bool</code>) Whether to return the embedding of the retrieved Documents. Default is False.
**Returns:**
- <code>list\[Document\]</code> A list of the top_k documents most relevant to the query.
@@ -0,0 +1,129 @@
---
title: "Document Writers"
id: document-writers-api
description: "Writes Documents to a DocumentStore."
slug: "/document-writers-api"
---
## document_writer
### DocumentWriter
Writes documents to a DocumentStore.
### Usage example
```python
from haystack import Document
from haystack.components.writers import DocumentWriter
from haystack.document_stores.in_memory import InMemoryDocumentStore
docs = [
Document(content="Python is a popular programming language"),
]
doc_store = InMemoryDocumentStore()
writer = DocumentWriter(document_store=doc_store)
writer.run(docs)
```
#### __init__
```python
__init__(
document_store: DocumentStore,
policy: DuplicatePolicy = DuplicatePolicy.NONE,
) -> None
```
Create a DocumentWriter component.
**Parameters:**
- **document_store** (<code>DocumentStore</code>) The instance of the document store where you want to store your documents.
- **policy** (<code>DuplicatePolicy</code>) The policy to apply when a Document with the same ID already exists in the DocumentStore.
- `DuplicatePolicy.NONE`: Default policy, relies on the DocumentStore settings.
- `DuplicatePolicy.SKIP`: Skips documents with the same ID and doesn't write them to the DocumentStore.
- `DuplicatePolicy.OVERWRITE`: Overwrites documents with the same ID.
- `DuplicatePolicy.FAIL`: Raises an error if a Document with the same ID is already in the DocumentStore.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> DocumentWriter
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) The dictionary to deserialize from.
**Returns:**
- <code>DocumentWriter</code> The deserialized component.
**Raises:**
- <code>DeserializationError</code> If the document store is not properly specified in the serialization data or its type cannot be imported.
#### run
```python
run(
documents: list[Document], policy: DuplicatePolicy | None = None
) -> dict[str, int]
```
Run the DocumentWriter on the given input data.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) A list of documents to write to the document store.
- **policy** (<code>DuplicatePolicy | None</code>) The policy to use when encountering duplicate documents.
**Returns:**
- <code>dict\[str, int\]</code> Number of documents written to the document store.
**Raises:**
- <code>ValueError</code> If the specified document store is not found.
#### run_async
```python
run_async(
documents: list[Document], policy: DuplicatePolicy | None = None
) -> dict[str, int]
```
Asynchronously run the DocumentWriter on the given input data.
This is the asynchronous version of the `run` method. It has the same parameters and return values
but can be used with `await` in async code.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) A list of documents to write to the document store.
- **policy** (<code>DuplicatePolicy | None</code>) The policy to use when encountering duplicate documents.
**Returns:**
- <code>dict\[str, int\]</code> Number of documents written to the document store.
**Raises:**
- <code>ValueError</code> If the specified document store is not found.
- <code>TypeError</code> If the specified document store does not implement `write_documents_async`.
@@ -0,0 +1,929 @@
---
title: "Embedders"
id: embedders-api
description: "Transforms queries into vectors to look for similar or relevant Documents."
slug: "/embedders-api"
---
## azure_document_embedder
### AzureOpenAIDocumentEmbedder
Bases: <code>OpenAIDocumentEmbedder</code>
Calculates document embeddings using OpenAI models deployed on Azure.
### Usage example
<!-- test-ignore -->
```python
from haystack import Document
from haystack.components.embedders import AzureOpenAIDocumentEmbedder
doc = Document(content="I love pizza!")
document_embedder = AzureOpenAIDocumentEmbedder()
result = document_embedder.run([doc])
print(result['documents'][0].embedding)
# [0.017020374536514282, -0.023255806416273117, ...]
```
#### __init__
```python
__init__(
azure_endpoint: str | None = None,
api_version: str | None = "2023-05-15",
azure_deployment: str = "text-embedding-ada-002",
dimensions: int | None = None,
api_key: Secret | None = Secret.from_env_var(
"AZURE_OPENAI_API_KEY", strict=False
),
azure_ad_token: Secret | None = Secret.from_env_var(
"AZURE_OPENAI_AD_TOKEN", strict=False
),
organization: str | None = None,
prefix: str = "",
suffix: str = "",
batch_size: int = 32,
progress_bar: bool = True,
meta_fields_to_embed: list[str] | None = None,
embedding_separator: str = "\n",
timeout: float | None = None,
max_retries: int | None = None,
*,
default_headers: dict[str, str] | None = None,
azure_ad_token_provider: AzureADTokenProvider | None = None,
http_client_kwargs: dict[str, Any] | None = None,
raise_on_failure: bool = False
) -> None
```
Creates an AzureOpenAIDocumentEmbedder component.
**Parameters:**
- **azure_endpoint** (<code>str | None</code>) The endpoint of the model deployed on Azure.
- **api_version** (<code>str | None</code>) The version of the API to use.
- **azure_deployment** (<code>str</code>) The name of the model deployed on Azure. The default model is text-embedding-ada-002.
- **dimensions** (<code>int | None</code>) The number of dimensions of the resulting embeddings. Only supported in text-embedding-3
and later models.
- **api_key** (<code>Secret | None</code>) The Azure OpenAI API key.
You can set it with an environment variable `AZURE_OPENAI_API_KEY`, or pass with this
parameter during initialization.
- **azure_ad_token** (<code>Secret | None</code>) Microsoft Entra ID token, see Microsoft's
[Entra ID](https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id)
documentation for more information. You can set it with an environment variable
`AZURE_OPENAI_AD_TOKEN`, or pass with this parameter during initialization.
Previously called Azure Active Directory.
- **organization** (<code>str | None</code>) Your organization ID. See OpenAI's
[Setting Up Your Organization](https://platform.openai.com/docs/guides/production-best-practices/setting-up-your-organization)
for more information.
- **prefix** (<code>str</code>) A string to add at the beginning of each text.
- **suffix** (<code>str</code>) A string to add at the end of each text.
- **batch_size** (<code>int</code>) Number of documents to embed at once.
- **progress_bar** (<code>bool</code>) If `True`, shows a progress bar when running.
- **meta_fields_to_embed** (<code>list\[str\] | None</code>) List of metadata fields to embed along with the document text.
- **embedding_separator** (<code>str</code>) Separator used to concatenate the metadata fields to the document text.
- **timeout** (<code>float | None</code>) The timeout for `AzureOpenAI` client calls, in seconds.
If not set, defaults to either the
`OPENAI_TIMEOUT` environment variable, or 30 seconds.
- **max_retries** (<code>int | None</code>) Maximum number of retries to contact AzureOpenAI after an internal error.
If not set, defaults to either the `OPENAI_MAX_RETRIES` environment variable or to 5 retries.
- **default_headers** (<code>dict\[str, str\] | None</code>) Default headers to send to the AzureOpenAI client.
- **azure_ad_token_provider** (<code>AzureADTokenProvider | None</code>) A function that returns an Azure Active Directory token, will be invoked on
every request.
- **http_client_kwargs** (<code>dict\[str, Any\] | None</code>) A dictionary of keyword arguments to configure a custom `httpx.Client`or `httpx.AsyncClient`.
For more information, see the [HTTPX documentation](https://www.python-httpx.org/api/#client).
- **raise_on_failure** (<code>bool</code>) Whether to raise an exception if the embedding request fails. If `False`, the component will log the error
and continue processing the remaining documents. If `True`, it will raise an exception on failure.
#### warm_up
```python
warm_up() -> None
```
Initializes the synchronous AzureOpenAI client.
#### warm_up_async
```python
warm_up_async() -> None
```
Initializes the asynchronous AzureOpenAI client on the serving event loop.
#### close
```python
close() -> None
```
Releases the synchronous AzureOpenAI client.
#### close_async
```python
close_async() -> None
```
Releases the asynchronous AzureOpenAI client.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> AzureOpenAIDocumentEmbedder
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Dictionary to deserialize from.
**Returns:**
- <code>AzureOpenAIDocumentEmbedder</code> Deserialized component.
## azure_text_embedder
### AzureOpenAITextEmbedder
Bases: <code>OpenAITextEmbedder</code>
Embeds strings using OpenAI models deployed on Azure.
### Usage example
<!-- test-ignore -->
```python
from haystack.components.embedders import AzureOpenAITextEmbedder
text_to_embed = "I love pizza!"
text_embedder = AzureOpenAITextEmbedder()
print(text_embedder.run(text_to_embed))
# {'embedding': [0.017020374536514282, -0.023255806416273117, ...],
# 'meta': {'model': 'text-embedding-ada-002-v2',
# 'usage': {'prompt_tokens': 4, 'total_tokens': 4}}}
```
#### __init__
```python
__init__(
azure_endpoint: str | None = None,
api_version: str | None = "2023-05-15",
azure_deployment: str = "text-embedding-ada-002",
dimensions: int | None = None,
api_key: Secret | None = Secret.from_env_var(
"AZURE_OPENAI_API_KEY", strict=False
),
azure_ad_token: Secret | None = Secret.from_env_var(
"AZURE_OPENAI_AD_TOKEN", strict=False
),
organization: str | None = None,
timeout: float | None = None,
max_retries: int | None = None,
prefix: str = "",
suffix: str = "",
*,
default_headers: dict[str, str] | None = None,
azure_ad_token_provider: AzureADTokenProvider | None = None,
http_client_kwargs: dict[str, Any] | None = None
) -> None
```
Creates an AzureOpenAITextEmbedder component.
**Parameters:**
- **azure_endpoint** (<code>str | None</code>) The endpoint of the model deployed on Azure.
- **api_version** (<code>str | None</code>) The version of the API to use.
- **azure_deployment** (<code>str</code>) The name of the model deployed on Azure. The default model is text-embedding-ada-002.
- **dimensions** (<code>int | None</code>) The number of dimensions the resulting output embeddings should have. Only supported in text-embedding-3
and later models.
- **api_key** (<code>Secret | None</code>) The Azure OpenAI API key.
You can set it with an environment variable `AZURE_OPENAI_API_KEY`, or pass with this
parameter during initialization.
- **azure_ad_token** (<code>Secret | None</code>) Microsoft Entra ID token, see Microsoft's
[Entra ID](https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-id)
documentation for more information. You can set it with an environment variable
`AZURE_OPENAI_AD_TOKEN`, or pass with this parameter during initialization.
Previously called Azure Active Directory.
- **organization** (<code>str | None</code>) Your organization ID. See OpenAI's
[Setting Up Your Organization](https://platform.openai.com/docs/guides/production-best-practices/setting-up-your-organization)
for more information.
- **timeout** (<code>float | None</code>) The timeout for `AzureOpenAI` client calls, in seconds.
If not set, defaults to either the
`OPENAI_TIMEOUT` environment variable, or 30 seconds.
- **max_retries** (<code>int | None</code>) Maximum number of retries to contact AzureOpenAI after an internal error.
If not set, defaults to either the `OPENAI_MAX_RETRIES` environment variable, or to 5 retries.
- **prefix** (<code>str</code>) A string to add at the beginning of each text.
- **suffix** (<code>str</code>) A string to add at the end of each text.
- **default_headers** (<code>dict\[str, str\] | None</code>) Default headers to send to the AzureOpenAI client.
- **azure_ad_token_provider** (<code>AzureADTokenProvider | None</code>) A function that returns an Azure Active Directory token, will be invoked on
every request.
- **http_client_kwargs** (<code>dict\[str, Any\] | None</code>) A dictionary of keyword arguments to configure a custom `httpx.Client`or `httpx.AsyncClient`.
For more information, see the [HTTPX documentation](https://www.python-httpx.org/api/#client).
#### warm_up
```python
warm_up() -> None
```
Initializes the synchronous Azure OpenAI client.
#### warm_up_async
```python
warm_up_async() -> None
```
Initializes the asynchronous Azure OpenAI client on the serving event loop.
#### close
```python
close() -> None
```
Releases the synchronous Azure OpenAI client.
#### close_async
```python
close_async() -> None
```
Releases the asynchronous Azure OpenAI client.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> AzureOpenAITextEmbedder
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Dictionary to deserialize from.
**Returns:**
- <code>AzureOpenAITextEmbedder</code> Deserialized component.
## mock_document_embedder
### MockDocumentEmbedder
A Document Embedder that returns deterministic embeddings without calling any API.
It is a drop-in replacement for real Document Embedders (such as `OpenAIDocumentEmbedder`) in tests, smoke tests,
and quick prototypes. It implements the same interface (`run`, `run_async`, serialization) but never contacts an
external service, so it is fully deterministic and free to run.
The embedding is selected based on how the component is configured:
- **Deterministic (default)**: with no configuration, each document's embedding is derived from a hash of its
(prepared) text. The same text always yields the same embedding, and different texts yield different
embeddings, so the mock works in retrieval pipelines and is reproducible across runs and processes.
- **Fixed embedding**: pass an `embedding` vector. The same vector is assigned to every document.
- **Dynamic embedding**: pass an `embedding_fn` callable that receives the (prepared) text of a document and
returns the embedding. This is useful when the embedding should depend on the input in a custom way.
Like real Document Embedders, the metadata fields listed in `meta_fields_to_embed` are concatenated with the
document content before embedding, so the deterministic embedding reflects the embedded metadata.
### Usage example
```python
from haystack import Document
from haystack.components.embedders import MockDocumentEmbedder
embedder = MockDocumentEmbedder(dimension=8)
result = embedder.run([Document(content="I love pizza!")])
print(result["documents"][0].embedding) # a deterministic list of 8 floats
```
#### __init__
```python
__init__(
embedding: list[float] | None = None,
*,
embedding_fn: EmbeddingFn | None = None,
dimension: int = 768,
model: str = "mock-model",
meta: dict[str, Any] | None = None,
prefix: str = "",
suffix: str = "",
meta_fields_to_embed: list[str] | None = None,
embedding_separator: str = "\n",
progress_bar: bool = False
) -> None
```
Creates an instance of MockDocumentEmbedder.
**Parameters:**
- **embedding** (<code>list\[float\] | None</code>) An optional fixed embedding assigned to every document. Mutually exclusive with
`embedding_fn`. If neither is provided, a deterministic embedding is derived from each document's text.
- **embedding_fn** (<code>EmbeddingFn | None</code>) An optional callable that receives the prepared text of a document and returns the
embedding as a list of floats. Mutually exclusive with `embedding`. To support serialization, pass a
named function (lambdas and nested functions cannot be serialized).
- **dimension** (<code>int</code>) The number of dimensions of the deterministic embedding. Ignored when `embedding` or
`embedding_fn` is provided, since their length is determined by the value or callable.
- **model** (<code>str</code>) The model name reported in the metadata. Purely cosmetic; no model is loaded.
- **meta** (<code>dict\[str, Any\] | None</code>) Additional metadata merged into the output `meta`.
- **prefix** (<code>str</code>) A string to add at the beginning of each text before embedding.
- **suffix** (<code>str</code>) A string to add at the end of each text before embedding.
- **meta_fields_to_embed** (<code>list\[str\] | None</code>) List of metadata fields to embed along with the document text.
- **embedding_separator** (<code>str</code>) Separator used to concatenate the metadata fields to the document text.
- **progress_bar** (<code>bool</code>) Accepted for interface compatibility with real Document Embedders and ignored.
**Raises:**
- <code>ValueError</code> If both `embedding` and `embedding_fn` are provided, if `dimension` is not positive, or
if `embedding` is an empty list.
- <code>TypeError</code> If `embedding` is not a sequence of numbers.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize the component to a dictionary.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> MockDocumentEmbedder
```
Deserialize the component from a dictionary.
#### warm_up
```python
warm_up() -> None
```
No-op warm up, provided for interface compatibility with real Embedders.
#### run
```python
run(documents: list[Document]) -> dict[str, Any]
```
Return the input documents with deterministic embeddings added, without calling any API.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) A list of documents to embed.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- `documents`: A list of documents with embeddings.
- `meta`: Metadata about the (mock) model.
**Raises:**
- <code>TypeError</code> If `documents` is not a list of `Document` objects.
#### run_async
```python
run_async(documents: list[Document]) -> dict[str, Any]
```
Asynchronously return the input documents with deterministic embeddings added, without calling any API.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) A list of documents to embed.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- `documents`: A list of documents with embeddings.
- `meta`: Metadata about the (mock) model.
**Raises:**
- <code>TypeError</code> If `documents` is not a list of `Document` objects.
## mock_text_embedder
### MockTextEmbedder
A Text Embedder that returns deterministic embeddings without calling any API.
It is a drop-in replacement for real Text Embedders (such as `OpenAITextEmbedder`) in tests, smoke tests, and
quick prototypes. It implements the same interface (`run`, `run_async`, serialization) but never contacts an
external service, so it is fully deterministic and free to run.
The embedding is selected based on how the component is configured:
- **Deterministic (default)**: with no configuration, the embedding is derived from a hash of the input text.
The same text always yields the same embedding, and different texts yield different embeddings, so the mock
works in retrieval pipelines and is reproducible across runs and processes.
- **Fixed embedding**: pass an `embedding` vector. The same vector is returned for every input.
- **Dynamic embedding**: pass an `embedding_fn` callable that receives the (prepared) text and returns the
embedding. This is useful when the embedding should depend on the input in a custom way.
### Usage example
```python
from haystack.components.embedders import MockTextEmbedder
embedder = MockTextEmbedder(dimension=8)
result = embedder.run("I love pizza!")
print(result["embedding"]) # a deterministic list of 8 floats
```
#### __init__
```python
__init__(
embedding: list[float] | None = None,
*,
embedding_fn: EmbeddingFn | None = None,
dimension: int = 768,
model: str = "mock-model",
meta: dict[str, Any] | None = None,
prefix: str = "",
suffix: str = ""
) -> None
```
Creates an instance of MockTextEmbedder.
**Parameters:**
- **embedding** (<code>list\[float\] | None</code>) An optional fixed embedding returned for every input. Mutually exclusive with
`embedding_fn`. If neither is provided, a deterministic embedding is derived from the input text.
- **embedding_fn** (<code>EmbeddingFn | None</code>) An optional callable that receives the prepared text (after `prefix`/`suffix` are
applied) and returns the embedding as a list of floats. Mutually exclusive with `embedding`. To support
serialization, pass a named function (lambdas and nested functions cannot be serialized).
- **dimension** (<code>int</code>) The number of dimensions of the deterministic embedding. Ignored when `embedding` or
`embedding_fn` is provided, since their length is determined by the value or callable.
- **model** (<code>str</code>) The model name reported in the metadata. Purely cosmetic; no model is loaded.
- **meta** (<code>dict\[str, Any\] | None</code>) Additional metadata merged into the output `meta`.
- **prefix** (<code>str</code>) A string to add at the beginning of the text before embedding.
- **suffix** (<code>str</code>) A string to add at the end of the text before embedding.
**Raises:**
- <code>ValueError</code> If both `embedding` and `embedding_fn` are provided, if `dimension` is not positive, or
if `embedding` is an empty list.
- <code>TypeError</code> If `embedding` is not a sequence of numbers.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize the component to a dictionary.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> MockTextEmbedder
```
Deserialize the component from a dictionary.
#### warm_up
```python
warm_up() -> None
```
No-op warm up, provided for interface compatibility with real Embedders.
#### run
```python
run(text: str) -> dict[str, Any]
```
Return a deterministic embedding for the input text without calling any API.
**Parameters:**
- **text** (<code>str</code>) The text to embed.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- `embedding`: The embedding of the input text.
- `meta`: Metadata about the (mock) model.
**Raises:**
- <code>TypeError</code> If `text` is not a string.
#### run_async
```python
run_async(text: str) -> dict[str, Any]
```
Asynchronously return a deterministic embedding for the input text without calling any API.
**Parameters:**
- **text** (<code>str</code>) The text to embed.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- `embedding`: The embedding of the input text.
- `meta`: Metadata about the (mock) model.
**Raises:**
- <code>TypeError</code> If `text` is not a string.
## openai_document_embedder
### OpenAIDocumentEmbedder
Computes document embeddings using OpenAI models.
### Usage example
<!-- test-ignore -->
```python
from haystack import Document
from haystack.components.embedders import OpenAIDocumentEmbedder
doc = Document(content="I love pizza!")
document_embedder = OpenAIDocumentEmbedder()
result = document_embedder.run([doc])
print(result['documents'][0].embedding)
# [0.017020374536514282, -0.023255806416273117, ...]
```
#### __init__
```python
__init__(
api_key: Secret = Secret.from_env_var("OPENAI_API_KEY"),
model: str = "text-embedding-ada-002",
dimensions: int | None = None,
api_base_url: str | None = None,
organization: str | None = None,
prefix: str = "",
suffix: str = "",
batch_size: int = 32,
progress_bar: bool = True,
meta_fields_to_embed: list[str] | None = None,
embedding_separator: str = "\n",
timeout: float | None = None,
max_retries: int | None = None,
http_client_kwargs: dict[str, Any] | None = None,
*,
raise_on_failure: bool = False
) -> None
```
Creates an OpenAIDocumentEmbedder component.
Before initializing the component, you can set the 'OPENAI_TIMEOUT' and 'OPENAI_MAX_RETRIES'
environment variables to override the `timeout` and `max_retries` parameters respectively
in the OpenAI client.
**Parameters:**
- **api_key** (<code>Secret</code>) The OpenAI API key.
You can set it with an environment variable `OPENAI_API_KEY`, or pass with this parameter
during initialization.
- **model** (<code>str</code>) The name of the model to use for calculating embeddings.
The default model is `text-embedding-ada-002`.
- **dimensions** (<code>int | None</code>) The number of dimensions of the resulting embeddings. Only `text-embedding-3` and
later models support this parameter.
- **api_base_url** (<code>str | None</code>) Overrides the default base URL for all HTTP requests.
- **organization** (<code>str | None</code>) Your OpenAI organization ID. See OpenAI's
[Setting Up Your Organization](https://platform.openai.com/docs/guides/production-best-practices/setting-up-your-organization)
for more information.
- **prefix** (<code>str</code>) A string to add at the beginning of each text.
- **suffix** (<code>str</code>) A string to add at the end of each text.
- **batch_size** (<code>int</code>) Number of documents to embed at once.
- **progress_bar** (<code>bool</code>) If `True`, shows a progress bar when running.
- **meta_fields_to_embed** (<code>list\[str\] | None</code>) List of metadata fields to embed along with the document text.
- **embedding_separator** (<code>str</code>) Separator used to concatenate the metadata fields to the document text.
- **timeout** (<code>float | None</code>) Timeout for OpenAI client calls. If not set, it defaults to either the
`OPENAI_TIMEOUT` environment variable, or 30 seconds.
- **max_retries** (<code>int | None</code>) Maximum number of retries to contact OpenAI after an internal error.
If not set, it defaults to either the `OPENAI_MAX_RETRIES` environment variable, or 5 retries.
- **http_client_kwargs** (<code>dict\[str, Any\] | None</code>) A dictionary of keyword arguments to configure a custom `httpx.Client`or `httpx.AsyncClient`.
For more information, see the [HTTPX documentation](https://www.python-httpx.org/api/#client).
- **raise_on_failure** (<code>bool</code>) Whether to raise an exception if the embedding request fails. If `False`, the component will log the error
and continue processing the remaining documents. If `True`, it will raise an exception on failure.
#### warm_up
```python
warm_up() -> None
```
Initializes the synchronous OpenAI client.
#### warm_up_async
```python
warm_up_async() -> None
```
Initializes the asynchronous OpenAI client on the serving event loop.
#### close
```python
close() -> None
```
Releases the synchronous OpenAI client.
#### close_async
```python
close_async() -> None
```
Releases the asynchronous OpenAI client.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> OpenAIDocumentEmbedder
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Dictionary to deserialize from.
**Returns:**
- <code>OpenAIDocumentEmbedder</code> Deserialized component.
#### run
```python
run(documents: list[Document]) -> dict[str, Any]
```
Embeds a list of documents.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) A list of documents to embed.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- `documents`: A list of documents with embeddings.
- `meta`: Information about the usage of the model.
#### run_async
```python
run_async(documents: list[Document]) -> dict[str, Any]
```
Embeds a list of documents asynchronously.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) A list of documents to embed.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- `documents`: A list of documents with embeddings.
- `meta`: Information about the usage of the model.
## openai_text_embedder
### OpenAITextEmbedder
Embeds strings using OpenAI models.
You can use it to embed user query and send it to an embedding Retriever.
### Usage example
<!-- test-ignore -->
```python
from haystack.components.embedders import OpenAITextEmbedder
text_to_embed = "I love pizza!"
text_embedder = OpenAITextEmbedder()
print(text_embedder.run(text_to_embed))
# {'embedding': [0.017020374536514282, -0.023255806416273117, ...],
# 'meta': {'model': 'text-embedding-ada-002-v2',
# 'usage': {'prompt_tokens': 4, 'total_tokens': 4}}}
```
#### __init__
```python
__init__(
api_key: Secret = Secret.from_env_var("OPENAI_API_KEY"),
model: str = "text-embedding-ada-002",
dimensions: int | None = None,
api_base_url: str | None = None,
organization: str | None = None,
prefix: str = "",
suffix: str = "",
timeout: float | None = None,
max_retries: int | None = None,
http_client_kwargs: dict[str, Any] | None = None,
) -> None
```
Creates an OpenAITextEmbedder component.
Before initializing the component, you can set the 'OPENAI_TIMEOUT' and 'OPENAI_MAX_RETRIES'
environment variables to override the `timeout` and `max_retries` parameters respectively
in the OpenAI client.
**Parameters:**
- **api_key** (<code>Secret</code>) The OpenAI API key.
You can set it with an environment variable `OPENAI_API_KEY`, or pass with this parameter
during initialization.
- **model** (<code>str</code>) The name of the model to use for calculating embeddings.
The default model is `text-embedding-ada-002`.
- **dimensions** (<code>int | None</code>) The number of dimensions of the resulting embeddings. Only `text-embedding-3` and
later models support this parameter.
- **api_base_url** (<code>str | None</code>) Overrides default base URL for all HTTP requests.
- **organization** (<code>str | None</code>) Your organization ID. See OpenAI's
[production best practices](https://platform.openai.com/docs/guides/production-best-practices/setting-up-your-organization)
for more information.
- **prefix** (<code>str</code>) A string to add at the beginning of each text to embed.
- **suffix** (<code>str</code>) A string to add at the end of each text to embed.
- **timeout** (<code>float | None</code>) Timeout for OpenAI client calls. If not set, it defaults to either the
`OPENAI_TIMEOUT` environment variable, or 30 seconds.
- **max_retries** (<code>int | None</code>) Maximum number of retries to contact OpenAI after an internal error.
If not set, it defaults to either the `OPENAI_MAX_RETRIES` environment variable, or set to 5.
- **http_client_kwargs** (<code>dict\[str, Any\] | None</code>) A dictionary of keyword arguments to configure a custom `httpx.Client`or `httpx.AsyncClient`.
For more information, see the [HTTPX documentation](https://www.python-httpx.org/api/#client).
#### warm_up
```python
warm_up() -> None
```
Initializes the synchronous OpenAI client.
#### warm_up_async
```python
warm_up_async() -> None
```
Initializes the asynchronous OpenAI client on the serving event loop.
#### close
```python
close() -> None
```
Releases the synchronous OpenAI client.
#### close_async
```python
close_async() -> None
```
Releases the asynchronous OpenAI client.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> OpenAITextEmbedder
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Dictionary to deserialize from.
**Returns:**
- <code>OpenAITextEmbedder</code> Deserialized component.
#### run
```python
run(text: str) -> dict[str, Any]
```
Embeds a single string.
**Parameters:**
- **text** (<code>str</code>) Text to embed.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- `embedding`: The embedding of the input text.
- `meta`: Information about the usage of the model.
#### run_async
```python
run_async(text: str) -> dict[str, Any]
```
Asynchronously embed a single string.
This is the asynchronous version of the `run` method. It has the same parameters and return values
but can be used with `await` in async code.
**Parameters:**
- **text** (<code>str</code>) Text to embed.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- `embedding`: The embedding of the input text.
- `meta`: Information about the usage of the model.
@@ -0,0 +1,108 @@
---
title: "Evaluation"
id: evaluation-api
description: "Represents the results of evaluation."
slug: "/evaluation-api"
---
## eval_run_result
### EvaluationRunResult
Contains the inputs and the outputs of an evaluation pipeline and provides methods to inspect them.
#### __init__
```python
__init__(
run_name: str,
inputs: dict[str, list[Any]],
results: dict[str, dict[str, Any]],
) -> None
```
Initialize a new evaluation run result.
**Parameters:**
- **run_name** (<code>str</code>) Name of the evaluation run.
- **inputs** (<code>dict\[str, list\[Any\]\]</code>) Dictionary containing the inputs used for the run. Each key is the name of the input and its value is a list
of input values. The length of the lists should be the same.
- **results** (<code>dict\[str, dict\[str, Any\]\]</code>) Dictionary containing the results of the evaluators used in the evaluation pipeline. Each key is the name
of the metric and its value is dictionary with the following keys:
- 'score': The aggregated score for the metric.
- 'individual_scores': A list of scores for each input sample.
#### aggregated_report
```python
aggregated_report(
output_format: Literal["json", "csv", "df"] = "json",
csv_file: str | None = None,
) -> Union[dict[str, list[Any]], DataFrame, str]
```
Generates a report with aggregated scores for each metric.
**Parameters:**
- **output_format** (<code>Literal['json', 'csv', 'df']</code>) The output format for the report, "json", "csv", or "df", default to "json".
- **csv_file** (<code>str | None</code>) Filepath to save CSV output if `output_format` is "csv", must be provided.
**Returns:**
- <code>Union\[dict\[str, list\[Any\]\], DataFrame, str\]</code> JSON or DataFrame with aggregated scores, in case the output is set to a CSV file, a message confirming the
successful write or an error message.
#### detailed_report
```python
detailed_report(
output_format: Literal["json", "csv", "df"] = "json",
csv_file: str | None = None,
) -> Union[dict[str, list[Any]], DataFrame, str]
```
Generates a report with detailed scores for each metric.
**Parameters:**
- **output_format** (<code>Literal['json', 'csv', 'df']</code>) The output format for the report, "json", "csv", or "df", default to "json".
- **csv_file** (<code>str | None</code>) Filepath to save CSV output if `output_format` is "csv", must be provided.
**Returns:**
- <code>Union\[dict\[str, list\[Any\]\], DataFrame, str\]</code> JSON or DataFrame with the detailed scores, in case the output is set to a CSV file, a message confirming
the successful write or an error message.
#### comparative_detailed_report
```python
comparative_detailed_report(
other: EvaluationRunResult,
keep_columns: list[str] | None = None,
output_format: Literal["json", "csv", "df"] = "json",
csv_file: str | None = None,
) -> Union[str, DataFrame, None]
```
Generates a report with detailed scores for each metric from two evaluation runs for comparison.
**Parameters:**
- **other** (<code>EvaluationRunResult</code>) Results of another evaluation run to compare with.
- **keep_columns** (<code>list\[str\] | None</code>) List of common column names to keep from the inputs of the evaluation runs to compare.
- **output_format** (<code>Literal['json', 'csv', 'df']</code>) The output format for the report, "json", "csv", or "df", default to "json".
- **csv_file** (<code>str | None</code>) Filepath to save CSV output if `output_format` is "csv", must be provided.
**Returns:**
- <code>Union\[str, DataFrame, None\]</code> JSON or DataFrame with a comparison of the detailed scores, in case the output is set to a CSV file,
a message confirming the successful write or an error message.
**Raises:**
- <code>TypeError</code> If `other` is not an EvaluationRunResult instance, or if the detailed reports are not
dictionaries.
- <code>ValueError</code> If the `other` parameter is missing required attributes.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,588 @@
---
title: "Extractors"
id: extractors-api
description: "Components to extract specific elements from textual data."
slug: "/extractors-api"
---
## image/llm_document_content_extractor
### LLMDocumentContentExtractor
Extracts textual content and optionally metadata from image-based documents using a vision-enabled LLM.
One prompt and one LLM call per document. The component converts each document to an image via
DocumentToImageContent and sends it to the ChatGenerator. The prompt must not contain Jinja variables.
Response handling:
- If the LLM returns a **plain string** (non-JSON or not a JSON object), it is written to the document's content.
- If the LLM returns a **JSON object with only the key** `document_content`, that value is written to content.
- If the LLM returns a **JSON object with multiple keys**, the value of `document_content` (if present) is
written to content and all other keys are merged into the document's metadata.
The ChatGenerator can be configured to return JSON (e.g. `response_format={"type": "json_object"}`
in `generation_kwargs`).
Documents that fail extraction are returned in `failed_documents` with `content_extraction_error` in metadata.
### Usage example
```python
from haystack import Document
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.extractors.image import LLMDocumentContentExtractor
prompt = """
Extract the content from the provided image.
Format everything as markdown. Return only the extracted content as a JSON object with the key 'document_content'.
No markdown, no code fence, only raw JSON.
Extract metadata about the image like source of the image, date of creation, etc. if you can.
Return this metadata as additional key-value pairs in the same JSON object.
"""
chat_generator = OpenAIChatGenerator(
generation_kwargs={
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "entity_extraction",
"schema": {
"type": "object",
"properties": {
"document_content": {"type": "string"},
"author": {"type": "string"},
"date": {"type": "string"},
"document_type": {"type": "string"},
"title": {"type": "string"},
},
"additionalProperties": False,
},
},
}
}
)
extractor = LLMDocumentContentExtractor(
chat_generator=chat_generator,
file_path_meta_field="file_path",
raise_on_failure=False
)
documents = [
Document(content="", meta={"file_path": "test/test_files/images/image_metadata.png"}),
Document(content="", meta={"file_path": "test/test_files/images/apple.jpg", "page_number": 1})
]
result = extractor.run(documents=documents)
updated_documents = result["documents"]
```
#### __init__
```python
__init__(
*,
chat_generator: ChatGenerator,
prompt: str = DEFAULT_PROMPT_TEMPLATE,
file_path_meta_field: str = "file_path",
root_path: str | None = None,
detail: Literal["auto", "high", "low"] | None = None,
size: tuple[int, int] | None = None,
raise_on_failure: bool = False,
max_workers: int = 3
) -> None
```
Initialize the LLMDocumentContentExtractor component.
**Parameters:**
- **chat_generator** (<code>ChatGenerator</code>) A ChatGenerator that supports vision input. Optionally configured for JSON
(e.g. `response_format={"type": "json_object"}` in `generation_kwargs`).
- **prompt** (<code>str</code>) Prompt for extraction. Must not contain Jinja variables.
- **file_path_meta_field** (<code>str</code>) The metadata field in the Document that contains the file path to the image or PDF.
- **root_path** (<code>str | None</code>) The root directory path where document files are located. If provided, file paths in
document metadata will be resolved relative to this path. If None, file paths are treated as absolute paths.
- **detail** (<code>Literal['auto', 'high', 'low'] | None</code>) Optional detail level of the image (only supported by OpenAI). Can be "auto", "high", or "low".
- **size** (<code>tuple\[int, int\] | None</code>) If provided, resizes the image to fit within (width, height) while keeping aspect ratio.
- **raise_on_failure** (<code>bool</code>) If True, exceptions from the LLM are raised. If False, failed documents are returned.
- **max_workers** (<code>int</code>) Maximum number of threads for parallel LLM calls.
#### warm_up
```python
warm_up() -> None
```
Warm up the underlying chat generator.
#### warm_up_async
```python
warm_up_async() -> None
```
Warm up the underlying chat generator on the serving event loop.
#### close
```python
close() -> None
```
Release the underlying chat generator's resources.
#### close_async
```python
close_async() -> None
```
Release the underlying chat generator's async resources.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> LLMDocumentContentExtractor
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Dictionary with serialized data.
**Returns:**
- <code>LLMDocumentContentExtractor</code> An instance of the component.
#### run
```python
run(documents: list[Document]) -> dict[str, list[Document]]
```
Run extraction on image-based documents. One LLM call per document.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) A list of image-based documents to process. Each must have a valid file path in its metadata.
**Returns:**
- <code>dict\[str, list\[Document\]\]</code> A dictionary with "documents" (successfully processed) and "failed_documents" (with failure metadata).
#### run_async
```python
run_async(documents: list[Document]) -> dict[str, list[Document]]
```
Asynchronously run extraction on image-based documents. One LLM call per document.
This is the asynchronous version of the `run` method. It has the same parameters and return values
but can be used with `await` in an async code. LLM calls are made concurrently, bounded by `max_workers`.
If the chat generator only implements a synchronous `run` method, it is executed in a thread to avoid
blocking the event loop.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) A list of image-based documents to process. Each must have a valid file path in its metadata.
**Returns:**
- <code>dict\[str, list\[Document\]\]</code> A dictionary with "documents" (successfully processed) and "failed_documents" (with failure metadata).
## llm_metadata_extractor
### LLMMetadataExtractor
Extracts metadata from documents using a Large Language Model (LLM).
The metadata is extracted by providing a prompt to an LLM that generates the metadata.
This component expects as input a list of documents and a prompt. The prompt must have exactly one variable, called
`document`, that points to a single document in the list of documents. So to access the content of the document,
you can use `{{ document.content }}` in the prompt.
The component will run the LLM on each document in the list and extract metadata from the document. The metadata
will be added to the document's metadata field. If the LLM fails to extract metadata from a document, the document
will be added to the `failed_documents` list. The failed documents will have the keys `metadata_extraction_error` and
`metadata_extraction_response` in their metadata. These documents can be re-run with another extractor to
extract metadata by using the `metadata_extraction_response` and `metadata_extraction_error` in the prompt.
```python
from haystack import Document
from haystack.components.extractors.llm_metadata_extractor import LLMMetadataExtractor
from haystack.components.generators.chat import OpenAIChatGenerator
NER_PROMPT = '''
-Goal-
Given text and a list of entity types, identify all entities of those types from the text.
-Steps-
1. Identify all entities. For each identified entity, extract the following information:
- entity: Name of the entity
- entity_type: One of the following types: [organization, product, service, industry]
Format each entity as a JSON like: {"entity": <entity_name>, "entity_type": <entity_type>}
2. Return output in a single list with all the entities identified in steps 1.
-Examples-
######################
Example 1:
entity_types: [organization, person, partnership, financial metric, product, service, industry, investment strategy, market trend]
text: Another area of strength is our co-brand issuance. Visa is the primary network partner for eight of the top
10 co-brand partnerships in the US today and we are pleased that Visa has finalized a multi-year extension of
our successful credit co-branded partnership with Alaska Airlines, a portfolio that benefits from a loyal customer
base and high cross-border usage.
We have also had significant co-brand momentum in CEMEA. First, we launched a new co-brand card in partnership
with Qatar Airways, British Airways and the National Bank of Kuwait. Second, we expanded our strong global
Marriott relationship to launch Qatar's first hospitality co-branded card with Qatar Islamic Bank. Across the
United Arab Emirates, we now have exclusive agreements with all the leading airlines marked by a recent
agreement with Emirates Skywards.
And we also signed an inaugural Airline co-brand agreement in Morocco with Royal Air Maroc. Now newer digital
issuers are equally
------------------------
output:
{"entities": [{"entity": "Visa", "entity_type": "company"}, {"entity": "Alaska Airlines", "entity_type": "company"}, {"entity": "Qatar Airways", "entity_type": "company"}, {"entity": "British Airways", "entity_type": "company"}, {"entity": "National Bank of Kuwait", "entity_type": "company"}, {"entity": "Marriott", "entity_type": "company"}, {"entity": "Qatar Islamic Bank", "entity_type": "company"}, {"entity": "Emirates Skywards", "entity_type": "company"}, {"entity": "Royal Air Maroc", "entity_type": "company"}]}
#############################
-Real Data-
######################
entity_types: [company, organization, person, country, product, service]
text: {{ document.content }}
######################
output:
'''
docs = [
Document(content="deepset was founded in 2018 in Berlin, and is known for its Haystack framework"),
Document(content="Hugging Face is a company that was founded in New York, USA and is known for its Transformers library")
]
chat_generator = OpenAIChatGenerator(
generation_kwargs={
"max_completion_tokens": 500,
"temperature": 0.0,
"seed": 0,
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "entity_extraction",
"schema": {
"type": "object",
"properties": {
"entities": {
"type": "array",
"items": {
"type": "object",
"properties": {
"entity": {"type": "string"},
"entity_type": {"type": "string"}
},
"required": ["entity", "entity_type"],
"additionalProperties": False
}
}
},
"required": ["entities"],
"additionalProperties": False
}
}
},
},
max_retries=1,
timeout=60.0,
)
extractor = LLMMetadataExtractor(
prompt=NER_PROMPT,
chat_generator=chat_generator,
expected_keys=["entities"],
raise_on_failure=False,
)
extractor.run(documents=docs)
# >> {'documents': [
# Document(id=.., content: 'deepset was founded in 2018 in Berlin, and is known for its Haystack framework',
# meta: {'entities': [{'entity': 'deepset', 'entity_type': 'company'}, {'entity': 'Berlin', 'entity_type': 'city'},
# {'entity': 'Haystack', 'entity_type': 'product'}]}),
# Document(id=.., content: 'Hugging Face is a company that was founded in New York, USA and is known for its Transformers library',
# meta: {'entities': [
# {'entity': 'Hugging Face', 'entity_type': 'company'}, {'entity': 'New York', 'entity_type': 'city'},
# {'entity': 'USA', 'entity_type': 'country'}, {'entity': 'Transformers', 'entity_type': 'product'}
# ]})
# ]
# 'failed_documents': []
# }
# >>
```
#### __init__
```python
__init__(
prompt: str,
chat_generator: ChatGenerator,
expected_keys: list[str] | None = None,
page_range: list[str | int] | None = None,
raise_on_failure: bool = False,
max_workers: int = 3,
) -> None
```
Initializes the LLMMetadataExtractor.
**Parameters:**
- **prompt** (<code>str</code>) The prompt to be used for the LLM. It must contain exactly one variable, called `document`,
which points to a single document in the list of documents. For example, to access the content of the
document, use `{{ document.content }}` in the prompt.
- **chat_generator** (<code>ChatGenerator</code>) a ChatGenerator instance which represents the LLM. In order for the component to work,
the LLM should be configured to return a JSON object. For example, when using the OpenAIChatGenerator, you
should pass `{"response_format": {"type": "json_object"}}` in the `generation_kwargs`.
- **expected_keys** (<code>list\[str\] | None</code>) The keys expected in the JSON output from the LLM.
- **page_range** (<code>list\[str | int\] | None</code>) A range of pages to extract metadata from. For example, page_range=['1', '3'] will extract
metadata from the first and third pages of each document. It also accepts printable range strings, e.g.:
['1-3', '5', '8', '10-12'] will extract metadata from pages 1, 2, 3, 5, 8, 10,11, 12.
If None, metadata will be extracted from the entire document for each document in the documents list.
This parameter is optional and can be overridden in the `run` method.
- **raise_on_failure** (<code>bool</code>) Whether to raise an error on failure during the execution of the Generator or
validation of the JSON output.
- **max_workers** (<code>int</code>) The maximum number of workers to use in the thread pool executor.
This parameter is used limit the maximum number of requests that should be allowed to run concurrently
when using the `run_async` method.
#### warm_up
```python
warm_up() -> None
```
Warm up the underlying chat generator and splitter.
#### warm_up_async
```python
warm_up_async() -> None
```
Warm up the underlying chat generator and splitter on the serving event loop.
#### close
```python
close() -> None
```
Release the underlying chat generator's and splitter's resources.
#### close_async
```python
close_async() -> None
```
Release the underlying chat generator's and splitter's async resources.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> LLMMetadataExtractor
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Dictionary with serialized data.
**Returns:**
- <code>LLMMetadataExtractor</code> An instance of the component.
#### run
```python
run(
documents: list[Document], page_range: list[str | int] | None = None
) -> dict[str, Any]
```
Extract metadata from documents using a Large Language Model.
If `page_range` is provided, the metadata will be extracted from the specified range of pages. This component
will split the documents into pages and extract metadata from the specified range of pages. The metadata will be
extracted from the entire document if `page_range` is not provided.
The original documents will be returned updated with the extracted metadata.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) List of documents to extract metadata from.
- **page_range** (<code>list\[str | int\] | None</code>) A range of pages to extract metadata from. For example, page_range=['1', '3'] will extract
metadata from the first and third pages of each document. It also accepts printable range
strings, e.g.: ['1-3', '5', '8', '10-12'] will extract metadata from pages 1, 2, 3, 5, 8, 10,
11, 12.
If None, metadata will be extracted from the entire document for each document in the
documents list.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the keys:
- "documents": A list of documents that were successfully updated with the extracted metadata.
- "failed_documents": A list of documents that failed to extract metadata. These documents will have
"metadata_extraction_error" and "metadata_extraction_response" in their metadata. These documents can be
re-run with the extractor to extract metadata.
#### run_async
```python
run_async(
documents: list[Document], page_range: list[str | int] | None = None
) -> dict[str, Any]
```
Asynchronously extract metadata from documents using a Large Language Model.
If `page_range` is provided, the metadata will be extracted from the specified range of pages. This component
will split the documents into pages and extract metadata from the specified range of pages. The metadata will be
extracted from the entire document if `page_range` is not provided.
The original documents will be returned updated with the extracted metadata.
This is the asynchronous version of the `run` method. It has the same parameters
and return values but can be used with `await` in an async code.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) List of documents to extract metadata from.
- **page_range** (<code>list\[str | int\] | None</code>) A range of pages to extract metadata from. For example, page_range=['1', '3'] will extract
metadata from the first and third pages of each document. It also accepts printable range
strings, e.g.: ['1-3', '5', '8', '10-12'] will extract metadata from pages 1, 2, 3, 5, 8, 10,
11, 12.
If None, metadata will be extracted from the entire document for each document in the
documents list.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the keys:
- "documents": A list of documents that were successfully updated with the extracted metadata.
- "failed_documents": A list of documents that failed to extract metadata. These documents will have
"metadata_extraction_error" and "metadata_extraction_response" in their metadata. These documents can be
re-run with the extractor to extract metadata.
## regex_text_extractor
### RegexTextExtractor
Extracts text from chat message or string input using a regex pattern.
RegexTextExtractor parses input text or ChatMessages using a provided regular expression pattern.
It can be configured to search through all messages or only the last message in a list of ChatMessages.
### Usage example
```python
from haystack.components.extractors import RegexTextExtractor
from haystack.dataclasses import ChatMessage
# Using with a string
parser = RegexTextExtractor(regex_pattern='<issue url="(.+)">')
result = parser.run(text_or_messages='<issue url="github.com/hahahaha">hahahah</issue>')
# result: {"captured_text": "github.com/hahahaha"}
# Using with ChatMessages
messages = [ChatMessage.from_user('<issue url="github.com/hahahaha">hahahah</issue>')]
result = parser.run(text_or_messages=messages)
# result: {"captured_text": "github.com/hahahaha"}
```
#### __init__
```python
__init__(regex_pattern: str) -> None
```
Creates an instance of the RegexTextExtractor component.
**Parameters:**
- **regex_pattern** (<code>str</code>) The regular expression pattern used to extract text.
The pattern should include a capture group to extract the desired text.
Example: `'<issue url="(.+)">'` captures `'github.com/hahahaha'` from `'<issue url="github.com/hahahaha">'`.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> RegexTextExtractor
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) The dictionary to deserialize from.
**Returns:**
- <code>RegexTextExtractor</code> The deserialized component.
#### run
```python
run(text_or_messages: str | list[ChatMessage]) -> dict[str, str]
```
Extracts text from input using the configured regex pattern.
**Parameters:**
- **text_or_messages** (<code>str | list\[ChatMessage\]</code>) Either a string or a list of ChatMessage objects to search through.
**Returns:**
- <code>dict\[str, str\]</code> - `{"captured_text": "matched text"}` if a match is found
- `{"captured_text": ""}` if no match is found
**Raises:**
- <code>TypeError</code> if receiving a list the last element is not a ChatMessage instance.
@@ -0,0 +1,153 @@
---
title: "Fetchers"
id: fetchers-api
description: "Fetches content from a list of URLs and returns a list of extracted content streams."
slug: "/fetchers-api"
---
## link_content
### LinkContentFetcher
Fetches and extracts content from URLs.
It supports various content types, retries on failures, and automatic user-agent rotation for failed web
requests. Use it as the data-fetching step in your pipelines.
You may need to convert LinkContentFetcher's output into a list of documents. Use HTMLToDocument
converter to do this.
### Usage example
```python
from haystack.components.fetchers.link_content import LinkContentFetcher
fetcher = LinkContentFetcher()
streams = fetcher.run(urls=["https://www.google.com"])["streams"]
assert len(streams) == 1
assert streams[0].meta == {'content_type': 'text/html', 'url': 'https://www.google.com'}
assert streams[0].data
```
For async usage:
```python
import asyncio
from haystack.components.fetchers import LinkContentFetcher
async def fetch_async():
fetcher = LinkContentFetcher()
result = await fetcher.run_async(urls=["https://www.google.com"])
return result["streams"]
streams = asyncio.run(fetch_async())
```
#### __init__
```python
__init__(
raise_on_failure: bool = True,
user_agents: list[str] | None = None,
retry_attempts: int = 2,
timeout: int = 3,
http2: bool = False,
client_kwargs: dict | None = None,
request_headers: dict[str, str] | None = None,
) -> None
```
Initializes the component.
**Parameters:**
- **raise_on_failure** (<code>bool</code>) If `True`, raises an exception if it fails to fetch a single URL.
For multiple URLs, it logs errors and returns the content it successfully fetched.
- **user_agents** (<code>list\[str\] | None</code>) [User agents](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent)
for fetching content. If `None`, a default user agent is used.
- **retry_attempts** (<code>int</code>) The number of times to retry to fetch the URL's content.
- **timeout** (<code>int</code>) Timeout in seconds for the request.
- **http2** (<code>bool</code>) Whether to enable HTTP/2 support for requests. Defaults to False.
Requires the 'h2' package to be installed (via `pip install httpx[http2]`).
- **client_kwargs** (<code>dict | None</code>) Additional keyword arguments to pass to the httpx client.
If `None`, default values are used.
#### warm_up
```python
warm_up() -> None
```
Initializes the synchronous httpx client.
#### warm_up_async
```python
warm_up_async() -> None
```
Initializes the asynchronous httpx client on the serving event loop.
#### close
```python
close() -> None
```
Releases the synchronous httpx client.
#### close_async
```python
close_async() -> None
```
Releases the asynchronous httpx client.
#### run
```python
run(urls: list[str]) -> dict[str, Any]
```
Fetches content from a list of URLs and returns a list of extracted content streams.
Each content stream is a `ByteStream` object containing the extracted content as binary data.
Each ByteStream object in the returned list corresponds to the contents of a single URL.
The content type of each stream is stored in the metadata of the ByteStream object under
the key "content_type". The URL of the fetched content is stored under the key "url".
**Parameters:**
- **urls** (<code>list\[str\]</code>) A list of URLs to fetch content from.
**Returns:**
- <code>dict\[str, Any\]</code> `ByteStream` objects representing the extracted content.
**Raises:**
- <code>Exception</code> If the provided list of URLs contains only a single URL, and `raise_on_failure` is set to
`True`, an exception will be raised in case of an error during content retrieval.
In all other scenarios, any retrieval errors are logged, and a list of successfully retrieved `ByteStream`
objects is returned.
#### run_async
```python
run_async(urls: list[str]) -> dict[str, Any]
```
Asynchronously fetches content from a list of URLs and returns a list of extracted content streams.
This is the asynchronous version of the `run` method with the same parameters and return values.
**Parameters:**
- **urls** (<code>list\[str\]</code>) A list of URLs to fetch content from.
**Returns:**
- <code>dict\[str, Any\]</code> `ByteStream` objects representing the extracted content.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,609 @@
---
title: "Hooks"
id: hooks-api
description: "Hooks that run at points in the Agent's run loop and influence it by mutating State, including built-in tool result offloading."
slug: "/hooks-api"
---
## from_function
### FunctionHook
Wraps a function (or a sync/async pair) into a serializable `Hook`.
Produced by the `@hook` decorator for the single-function case. To give a hook both an optimized sync and async
path, construct it directly with both `function` and `async_function` set.
#### __init__
```python
__init__(
function: Callable[[State], None] | None = None,
async_function: Callable[[State], Awaitable[None]] | None = None,
) -> None
```
Initialize the hook with a synchronous function, an async function, or both.
**Parameters:**
- **function** (<code>Callable\\[[State\], None\] | None</code>) The synchronous function invoked by `run`. Must be a regular function — coroutine functions
should be passed to `async_function` instead. Either `function` or `async_function` (or both) must be set.
- **async_function** (<code>Callable\\[[State\], Awaitable[None]\] | None</code>) Optional coroutine function awaited by `run_async`. When only `async_function` is set,
`run` raises a `RuntimeError`. When only `function` is set, `run_async` calls `function`.
**Raises:**
- <code>ValueError</code> If neither is set, if `function` is a coroutine function, if `async_function` is not, or
if a provided function does not declare a `State`-typed parameter.
#### run
```python
run(state: State) -> None
```
Run the synchronous function against the live `State`.
**Parameters:**
- **state** (<code>State</code>) The Agent's live `State`, mutated in place by the wrapped function.
**Raises:**
- <code>RuntimeError</code> If the hook only has an `async_function`; use the Agent's async run methods instead.
#### run_async
```python
run_async(state: State) -> None
```
Await the async function if set, otherwise call the synchronous function.
**Parameters:**
- **state** (<code>State</code>) The Agent's live `State`, mutated in place by the wrapped function.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize the hook, storing each wrapped function as an importable reference.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the hook's type and the import paths of its sync/async functions.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> FunctionHook
```
Deserialize the hook, resolving each function from its importable reference.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) The serialized hook dictionary produced by `to_dict`.
**Returns:**
- <code>FunctionHook</code> The reconstructed `FunctionHook`.
### hook
```python
hook(function: Callable[[State], None | Awaitable[None]]) -> FunctionHook
```
Wrap a function into a `Hook` the Agent can invoke during its run loop.
The decorated function receives the Agent's `State` and influences the run by mutating it in place. A coroutine
function is wrapped as the hook's async path; a regular function as its sync path. To give a single hook both
paths, construct a `FunctionHook` directly with both `function` and `async_function`.
### Usage example
```python
from haystack.components.agents import Agent
from haystack.hooks import hook
from haystack.components.agents.state import State
from haystack.dataclasses import ChatMessage
@hook
def require_save(state: State) -> None:
if state.get("tool_call_counts", {}).get("save", 0) == 0:
state.set("messages", [ChatMessage.from_system("You must call `save` before finishing.")])
state.set("continue_run", True)
agent = Agent(chat_generator=..., tools=[...], hooks={"on_exit": [require_save]})
```
**Parameters:**
- **function** (<code>Callable\\[[State\], None | Awaitable[None]\]</code>) A callable taking the Agent's `State` and returning `None` (sync or async).
**Returns:**
- <code>FunctionHook</code> A `FunctionHook` wrapping the function.
## protocol
### Hook
Bases: <code>Protocol</code>
A callable the Agent invokes at a point in its run loop, receiving the live `State`.
A hook influences the run only by mutating `State` in place. At least `messages` (the conversation),
`step_count`, `token_usage` and `tool_call_counts` are available; any additional keys defined in the Agent's
`state_schema` are available too. The same hook object can be registered under multiple hook points.
Implement this protocol directly for stateful hooks (e.g. one wrapping a component), or use the `@hook` decorator to
wrap a plain `(State) -> None` function.
A hook may additionally define `async def run_async(self, state: State) -> None` for true async behavior; when
absent, the Agent calls `run` during async runs. It is left off this protocol on purpose so sync-only hooks
don't have to implement it.
A hook may also implement the optional lifecycle methods `warm_up` / `warm_up_async` and `close` / `close_async`.
The Agent calls them from its own `warm_up` / `warm_up_async` and `close` / `close_async`, so a hook can defer
opening clients or reading credentials until warm-up and release them on close.
#### run
```python
run(state: State) -> None
```
Run the hook against the live `State`, mutating it in place.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize the hook to a dictionary.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> Hook
```
Deserialize the hook from a dictionary.
## tool_result_offloading/hooks
### ToolResultOffloadHook
Offload tool results to a `ToolResultStore`, replacing them in the conversation with a compact pointer.
This `after_tool` Agent hook writes the full result to the store so the next LLM call sees a reference instead of
the full result. Register it on an `Agent` under the `after_tool` hook point. Which tools offload, and under what
condition, is controlled per tool by `offload_strategies`:
```python
from haystack.components.agents import Agent
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.hooks.tool_result_offloading import (
AlwaysOffload,
FileSystemToolResultStore,
NeverOffload,
OffloadOverChars,
ToolResultOffloadHook,
)
hook = ToolResultOffloadHook(
store=FileSystemToolResultStore(root="tool_results"),
offload_strategies={
"web_search": AlwaysOffload(), # force offload
"get_time": NeverOffload(), # opt out
("read_file", "list_dir"): OffloadOverChars(4000), # tuple key: shared policy
"*": OffloadOverChars(8000), # wildcard default for any unlisted tool
},
)
agent = Agent(
chat_generator=OpenAIChatGenerator(model="gpt-5.4-nano"),
tools=[web_search, get_time, read_file, list_dir],
hooks={"after_tool": [hook]},
)
```
A key may be a single tool name, a tuple of tool names sharing one policy, or the wildcard `"*"` which applies to
any tool without a more specific entry. More specific keys win. A tool with no matching key (and no `"*"`) is not
offloaded.
Only successful, text tool output is offloaded. Error results (including `before_tool` human-in-the-loop
rejections) are always left in context. Non-text results (image or file content) are also left in context, and a
warning is logged when such a result has a matching offload policy; supporting only text is a deliberate choice
for now. Each result is offloaded at most once, even though the hook runs on every tool step.
The hook keeps no mutable state, so a single instance can be shared across concurrent runs. The constructor
`store`, however, is shared by every run that does not override it — fine for single-user or local use, but in a
multi-user server give each run its own isolated store (a per-session directory or sandbox) via `hook_context`
under the key `RESULT_STORE_CONTEXT_KEY`
(`agent.run(messages=[...], hook_context={RESULT_STORE_CONTEXT_KEY: per_request_store})`); it overrides the
constructor store for that run. Isolating the store per run keeps concurrent users from colliding on store keys or
reading each other's offloaded results — important especially when a bash/read tool is scoped to the store.
#### __init__
```python
__init__(
store: ToolResultStore,
offload_strategies: dict[str | tuple[str, ...], OffloadPolicy],
*,
preview_chars: int = 200
) -> None
```
Initialize the hook with a store and per-tool offload strategies.
**Parameters:**
- **store** (<code>ToolResultStore</code>) Where offloaded results are written. Can be overridden per run via `hook_context`.
- **offload_strategies** (<code>dict\[str | tuple\[str, ...\], OffloadPolicy\]</code>) Mapping of tool name (or a tuple of tool names, or the wildcard `"*"`) to the
`OffloadPolicy` that decides whether that tool's results are offloaded.
- **preview_chars** (<code>int</code>) Number of leading characters of the original result to include in the pointer left in
the conversation, so the model knows roughly what was offloaded.
#### run
```python
run(state: State) -> None
```
Offload the freshly produced tool results in `state.data["messages"]` according to `offload_strategies`.
Considers only the trailing block of tool-result messages (the current step's results); earlier history is
left untouched. Offloads each of those messages its policy opts in for, and writes the rewritten conversation
back to `messages` only if at least one message changed.
Results are written to the store this run resolves to: a per-run store passed in `state`'s `hook_context`
under `RESULT_STORE_CONTEXT_KEY` if present, otherwise the store the hook was constructed with. Supply the
per-run store when calling the Agent, e.g.
`agent.run(messages=[...], hook_context={RESULT_STORE_CONTEXT_KEY: per_request_store})`. In a multi-user
server, pass an isolated store per run this way so concurrent users write to separate locations and never
read each other's results.
The hook keeps no mutable state, so a single instance is safe to share across concurrent runs; isolation
comes entirely from giving each run its own store via `hook_context`.
**Parameters:**
- **state** (<code>State</code>) The Agent's live `State`. Reads the per-run store from `hook_context` and rewrites the offloaded
tool-result messages back into `messages`.
**Returns:**
- <code>None</code> None. The hook mutates `state` in place.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize the hook, including its store and per-tool offload strategies.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary representation of the hook.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> ToolResultOffloadHook
```
Deserialize the hook, reconstructing its store and offload strategies.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) A dictionary representation produced by `to_dict`.
**Returns:**
- <code>ToolResultOffloadHook</code> The deserialized `ToolResultOffloadHook`.
## tool_result_offloading/policies
### AlwaysOffload
Bases: <code>OffloadPolicy</code>
Offload every result of the tool it is assigned to.
#### should_offload
```python
should_offload(tool_name: str, result: str, state: State) -> bool
```
Decide whether to offload the given tool result.
**Parameters:**
- **tool_name** (<code>str</code>) The name of the tool that produced the result (unused; this policy always offloads).
- **result** (<code>str</code>) The tool result string (unused; this policy always offloads).
- **state** (<code>State</code>) The Agent's live `State` (unused; this policy always offloads).
**Returns:**
- <code>bool</code> Always True.
### NeverOffload
Bases: <code>OffloadPolicy</code>
Never offload; keep the tool's full result in context. Use to opt a tool out of a wildcard default.
#### should_offload
```python
should_offload(tool_name: str, result: str, state: State) -> bool
```
Decide whether to offload the given tool result.
**Parameters:**
- **tool_name** (<code>str</code>) The name of the tool that produced the result (unused; this policy never offloads).
- **result** (<code>str</code>) The tool result string (unused; this policy never offloads).
- **state** (<code>State</code>) The Agent's live `State` (unused; this policy never offloads).
**Returns:**
- <code>bool</code> Always False.
### OffloadOverChars
Bases: <code>OffloadPolicy</code>
Offload a result only when its string length exceeds `threshold` characters.
#### __init__
```python
__init__(threshold: int) -> None
```
Initialize the policy with its character threshold.
**Parameters:**
- **threshold** (<code>int</code>) Offload the result when its length in characters is strictly greater than this value.
#### should_offload
```python
should_offload(tool_name: str, result: str, state: State) -> bool
```
Decide whether to offload the given tool result based on its length.
**Parameters:**
- **tool_name** (<code>str</code>) The name of the tool that produced the result (unused; only length is considered).
- **result** (<code>str</code>) The tool result string whose length is compared against the threshold.
- **state** (<code>State</code>) The Agent's live `State` (unused; only length is considered).
**Returns:**
- <code>bool</code> True when `result` is longer than `threshold` characters, otherwise False.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize the policy, including its threshold.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary representation of the policy.
## tool_result_offloading/stores
### FileSystemToolResultStore
Bases: <code>ToolResultStore</code>
A `ToolResultStore` that writes offloaded tool results to files under a root directory on the local file system.
```python
from haystack.hooks.tool_result_offloading import FileSystemToolResultStore
store = FileSystemToolResultStore(root="tool_results")
reference = store.write(key="search_1.txt", content="...")
store.read(reference)
```
#### __init__
```python
__init__(root: str | Path) -> None
```
Initialize the store with the root directory results are written under.
**Parameters:**
- **root** (<code>str | Path</code>) Directory under which result files are written. Created on first write if it does not exist.
#### write
```python
write(*, key: str, content: str) -> str
```
Write `content` to `<root>/<key>`, creating parent directories, and return the file path.
The resolved target must stay within the root directory: a `key` that escapes it (e.g. containing `../` or an
absolute path) is rejected, so a tool-provided key cannot write outside the store.
**Parameters:**
- **key** (<code>str</code>) Relative file name for the result within the store root.
- **content** (<code>str</code>) The tool result to persist.
**Returns:**
- <code>str</code> The absolute path the content was written to, as a string, for use with `read`.
**Raises:**
- <code>ValueError</code> If `key` resolves to a location outside the store root.
#### read
```python
read(reference: str) -> str
```
Read back the content previously written to `reference`.
**Parameters:**
- **reference** (<code>str</code>) A path returned by `write`.
**Returns:**
- <code>str</code> The stored content.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize the store, storing its root directory as a string.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary representation of the store.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> FileSystemToolResultStore
```
Deserialize the store from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) A dictionary representation produced by `to_dict`.
**Returns:**
- <code>FileSystemToolResultStore</code> The deserialized `FileSystemToolResultStore`.
## tool_result_offloading/types/protocol
### ToolResultStore
Bases: <code>Protocol</code>
A place a `ToolResultOffloadHook` writes offloaded tool results to, and reads them back from.
Implementations decide where and how the content lives (local disk, an isolated sandbox filesystem, object
storage, ...). `write` returns an opaque reference string that the Agent puts in the conversation in place of the
full result; `read` resolves that reference back to the original content.
Implement both `to_dict` and `from_dict` to make a custom store serializable; the default implementations below
cover stores whose constructor takes no arguments.
#### write
```python
write(*, key: str, content: str) -> str
```
Persist `content` under `key` and return an opaque reference to it.
**Parameters:**
- **key** (<code>str</code>) A stable, per-result identifier the hook derives from the tool call (e.g. a file name).
- **content** (<code>str</code>) The tool result to persist.
**Returns:**
- <code>str</code> A reference string (e.g. a path or URI) that `read` can later resolve.
#### read
```python
read(reference: str) -> str
```
Return the content previously stored under `reference`.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize the store to a dictionary.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> ToolResultStore
```
Deserialize the store from a dictionary.
### OffloadPolicy
Bases: <code>Protocol</code>
Decides, per tool result, whether the `ToolResultOffloadHook` offloads it to the store or leaves it in context.
A `ToolResultOffloadHook` maps tool names to policies, so different tools can offload under different conditions
(always, never, or a custom rule such as a size threshold).
Implement both `to_dict` and `from_dict` to make a custom policy serializable; the default implementations below
cover policies whose constructor takes no arguments.
#### should_offload
```python
should_offload(tool_name: str, result: str, state: State) -> bool
```
Return whether the given tool result should be offloaded.
**Parameters:**
- **tool_name** (<code>str</code>) The name of the tool that produced the result.
- **result** (<code>str</code>) The tool result as a string (the content that would otherwise stay in the conversation).
- **state** (<code>State</code>) The Agent's live `State`, for policies that decide based on run context.
**Returns:**
- <code>bool</code> True to offload the result to the store, False to leave it in context.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize the policy to a dictionary.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> OffloadPolicy
```
Deserialize the policy from a dictionary.
@@ -0,0 +1,471 @@
---
title: "Human-in-the-Loop"
id: human-in-the-loop-api
description: "Abstractions for integrating human feedback and interaction into Agent workflows."
slug: "/human-in-the-loop-api"
---
## dataclasses
### ConfirmationUIResult
Result of the confirmation UI interaction.
**Parameters:**
- **action** (<code>str</code>) The action taken by the user such as "confirm", "reject", or "modify".
This action type is not enforced to allow for custom actions to be implemented.
- **feedback** (<code>str | None</code>) Optional feedback message from the user. For example, if the user rejects the tool execution,
they might provide a reason for the rejection.
- **new_tool_params** (<code>dict\[str, Any\] | None</code>) Optional set of new parameters for the tool. For example, if the user chooses to modify the tool parameters,
they can provide a new set of parameters here.
### ToolExecutionDecision
Decision made regarding tool execution.
**Parameters:**
- **tool_name** (<code>str</code>) The name of the tool to be executed.
- **execute** (<code>bool</code>) A boolean indicating whether to execute the tool with the provided parameters.
- **tool_call_id** (<code>str | None</code>) Optional unique identifier for the tool call. This can be used to track and correlate the decision with a
specific tool invocation.
- **feedback** (<code>str | None</code>) Optional feedback message.
For example, if the tool execution is rejected, this can contain the reason. Or if the tool parameters were
modified, this can contain the modification details.
- **final_tool_params** (<code>dict\[str, Any\] | None</code>) Optional final parameters for the tool if execution is confirmed or modified.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Convert the ToolExecutionDecision to a dictionary representation.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary containing the tool execution decision details.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> ToolExecutionDecision
```
Populate the ToolExecutionDecision from a dictionary representation.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) A dictionary containing the tool execution decision details.
**Returns:**
- <code>ToolExecutionDecision</code> An instance of ToolExecutionDecision.
## hooks
### ConfirmationHook
A `before_tool` Agent hook that applies Human-in-the-Loop confirmation strategies to pending tool calls.
Register it on an `Agent` to confirm, modify, or reject tool calls before they run:
```python
from haystack.components.agents import Agent
from haystack.human_in_the_loop import (
AlwaysAskPolicy,
BlockingConfirmationStrategy,
ConfirmationHook,
NeverAskPolicy,
RichConsoleUI,
SimpleConsoleUI,
)
hook = ConfirmationHook(
confirmation_strategies={
"my_tool": BlockingConfirmationStrategy(
confirmation_policy=NeverAskPolicy(), confirmation_ui=SimpleConsoleUI()
)
}
)
agent = Agent(chat_generator=..., tools=[...], hooks={"before_tool": [hook]})
```
A key may be a single tool name, a tuple of tool names sharing one strategy, or the wildcard `"*"` which applies
to any tool without a more specific entry. More specific keys win, so you can set a default for all tools and
override individual ones:
```python
hook = ConfirmationHook(
confirmation_strategies={
"delete_file": BlockingConfirmationStrategy(
confirmation_policy=AlwaysAskPolicy(), confirmation_ui=RichConsoleUI()
),
"*": BlockingConfirmationStrategy(
confirmation_policy=NeverAskPolicy(), confirmation_ui=SimpleConsoleUI()
),
}
)
```
Request-scoped resources for the strategies (e.g. a WebSocket or queue) are passed per run via the Agent's
`hook_context` argument (`agent.run(messages=[...], hook_context={...})`) and read by the hook with
`state.data.get("hook_context")`.
This hook only makes sense at the `before_tool` hook point, where the pending tool calls exist (between the model
requesting tools and those tools running); the Agent enforces this and raises if it is registered elsewhere. Use a
single ConfirmationHook with one entry per tool (or per tuple of tools) in `confirmation_strategies` rather than
registering several hooks.
#### __init__
```python
__init__(
confirmation_strategies: dict[str | tuple[str, ...], ConfirmationStrategy],
) -> None
```
Initialize the hook with its per-tool confirmation strategies.
**Parameters:**
- **confirmation_strategies** (<code>dict\[str | tuple\[str, ...\], ConfirmationStrategy\]</code>) Mapping of tool name (or a tuple of tool names) to its `ConfirmationStrategy`.
The wildcard key `"*"` applies to any tool without a more specific entry.
#### run
```python
run(state: State) -> None
```
Confirm the pending tool calls, rewriting the `messages` in `state` to reflect modifications and rejections.
**Parameters:**
- **state** (<code>State</code>) The Agent's live `State`. Reads the available tools (`state.data.get("tools")`) and the per-run
context (`state.data.get("hook_context")`), and the pending tool calls from the last message; writes the
updated conversation back to `messages`. Reads go through `state.data` rather than `state.get`, which
deep-copies and would break non-copyable resources (e.g. a WebSocket or client) in `hook_context`.
#### run_async
```python
run_async(state: State) -> None
```
Async version of `run`.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize the hook, including its confirmation strategies (tuple keys become JSON-array strings).
#### from_dict
```python
from_dict(data: dict[str, Any]) -> ConfirmationHook
```
Deserialize the hook, reconstructing its confirmation strategies.
## policies
### AlwaysAskPolicy
Bases: <code>ConfirmationPolicy</code>
Always ask for confirmation.
#### should_ask
```python
should_ask(
tool_name: str, tool_description: str, tool_params: dict[str, Any]
) -> bool
```
Always ask for confirmation before executing the tool.
**Parameters:**
- **tool_name** (<code>str</code>) The name of the tool to be executed.
- **tool_description** (<code>str</code>) The description of the tool.
- **tool_params** (<code>dict\[str, Any\]</code>) The parameters to be passed to the tool.
**Returns:**
- <code>bool</code> Always returns True, indicating confirmation is needed.
### NeverAskPolicy
Bases: <code>ConfirmationPolicy</code>
Never ask for confirmation.
#### should_ask
```python
should_ask(
tool_name: str, tool_description: str, tool_params: dict[str, Any]
) -> bool
```
Never ask for confirmation, always proceed with tool execution.
**Parameters:**
- **tool_name** (<code>str</code>) The name of the tool to be executed.
- **tool_description** (<code>str</code>) The description of the tool.
- **tool_params** (<code>dict\[str, Any\]</code>) The parameters to be passed to the tool.
**Returns:**
- <code>bool</code> Always returns False, indicating no confirmation is needed.
### AskOncePolicy
Bases: <code>ConfirmationPolicy</code>
Ask only once per tool with specific parameters.
#### __init__
```python
__init__() -> None
```
Creates an instance of AskOncePolicy.
#### should_ask
```python
should_ask(
tool_name: str, tool_description: str, tool_params: dict[str, Any]
) -> bool
```
Ask for confirmation only once per tool with specific parameters.
**Parameters:**
- **tool_name** (<code>str</code>) The name of the tool to be executed.
- **tool_description** (<code>str</code>) The description of the tool.
- **tool_params** (<code>dict\[str, Any\]</code>) The parameters to be passed to the tool.
**Returns:**
- <code>bool</code> True if confirmation is needed, False if already asked with the same parameters.
#### update_after_confirmation
```python
update_after_confirmation(
tool_name: str,
tool_description: str,
tool_params: dict[str, Any],
confirmation_result: ConfirmationUIResult,
) -> None
```
Store the tool and parameters if the action was "confirm" to avoid asking again.
This method updates the internal state to remember that the user has already confirmed the execution of the
tool with the given parameters.
**Parameters:**
- **tool_name** (<code>str</code>) The name of the tool that was executed.
- **tool_description** (<code>str</code>) The description of the tool.
- **tool_params** (<code>dict\[str, Any\]</code>) The parameters that were passed to the tool.
- **confirmation_result** (<code>ConfirmationUIResult</code>) The result from the confirmation UI.
## strategies
### BlockingConfirmationStrategy
Confirmation strategy that blocks execution to gather user feedback.
#### __init__
```python
__init__(
*,
confirmation_policy: ConfirmationPolicy,
confirmation_ui: ConfirmationUI,
reject_template: str = REJECTION_FEEDBACK_TEMPLATE,
modify_template: str = MODIFICATION_FEEDBACK_TEMPLATE,
user_feedback_template: str = USER_FEEDBACK_TEMPLATE
) -> None
```
Initialize the BlockingConfirmationStrategy with a confirmation policy and UI.
**Parameters:**
- **confirmation_policy** (<code>ConfirmationPolicy</code>) The confirmation policy to determine when to ask for user confirmation.
- **confirmation_ui** (<code>ConfirmationUI</code>) The user interface to interact with the user for confirmation.
- **reject_template** (<code>str</code>) Template for rejection feedback messages. It should include a `{tool_name}` placeholder.
- **modify_template** (<code>str</code>) Template for modification feedback messages. It should include `{tool_name}` and `{final_tool_params}`
placeholders.
- **user_feedback_template** (<code>str</code>) Template for user feedback messages. It should include a `{feedback}` placeholder.
#### run
```python
run(
*,
tool_name: str,
tool_description: str,
tool_params: dict[str, Any],
tool_call_id: str | None = None,
confirmation_strategy_context: dict[str, Any] | None = None
) -> ToolExecutionDecision
```
Run the human-in-the-loop strategy for a given tool and its parameters.
**Parameters:**
- **tool_name** (<code>str</code>) The name of the tool to be executed.
- **tool_description** (<code>str</code>) The description of the tool.
- **tool_params** (<code>dict\[str, Any\]</code>) The parameters to be passed to the tool.
- **tool_call_id** (<code>str | None</code>) Optional unique identifier for the tool call. This can be used to track and correlate the decision with a
specific tool invocation.
- **confirmation_strategy_context** (<code>dict\[str, Any\] | None</code>) Optional dictionary for passing request-scoped resources. Useful in web/server environments
to provide per-request objects (e.g., WebSocket connections, async queues, Redis pub/sub clients)
that strategies can use for non-blocking user interaction.
**Returns:**
- <code>ToolExecutionDecision</code> A ToolExecutionDecision indicating whether to execute the tool with the given parameters, or a
feedback message if rejected.
#### run_async
```python
run_async(
*,
tool_name: str,
tool_description: str,
tool_params: dict[str, Any],
tool_call_id: str | None = None,
confirmation_strategy_context: dict[str, Any] | None = None
) -> ToolExecutionDecision
```
Async version of run. Calls the sync run() method by default.
**Parameters:**
- **tool_name** (<code>str</code>) The name of the tool to be executed.
- **tool_description** (<code>str</code>) The description of the tool.
- **tool_params** (<code>dict\[str, Any\]</code>) The parameters to be passed to the tool.
- **tool_call_id** (<code>str | None</code>) Optional unique identifier for the tool call.
- **confirmation_strategy_context** (<code>dict\[str, Any\] | None</code>) Optional dictionary for passing request-scoped resources.
**Returns:**
- <code>ToolExecutionDecision</code> A ToolExecutionDecision indicating whether to execute the tool with the given parameters.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the BlockingConfirmationStrategy to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> BlockingConfirmationStrategy
```
Deserializes the BlockingConfirmationStrategy from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Dictionary to deserialize from.
**Returns:**
- <code>BlockingConfirmationStrategy</code> Deserialized BlockingConfirmationStrategy.
## user_interfaces
### RichConsoleUI
Bases: <code>ConfirmationUI</code>
Rich console interface for user interaction.
#### __init__
```python
__init__(console: Console | None = None) -> None
```
Creates an instance of RichConsoleUI.
#### get_user_confirmation
```python
get_user_confirmation(
tool_name: str, tool_description: str, tool_params: dict[str, Any]
) -> ConfirmationUIResult
```
Get user confirmation for tool execution via rich console prompts.
**Parameters:**
- **tool_name** (<code>str</code>) The name of the tool to be executed.
- **tool_description** (<code>str</code>) The description of the tool.
- **tool_params** (<code>dict\[str, Any\]</code>) The parameters to be passed to the tool.
**Returns:**
- <code>ConfirmationUIResult</code> ConfirmationUIResult based on user input.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the RichConsoleConfirmationUI to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
### SimpleConsoleUI
Bases: <code>ConfirmationUI</code>
Simple console interface using standard input/output.
#### get_user_confirmation
```python
get_user_confirmation(
tool_name: str, tool_description: str, tool_params: dict[str, Any]
) -> ConfirmationUIResult
```
Get user confirmation for tool execution via simple console prompts.
**Parameters:**
- **tool_name** (<code>str</code>) The name of the tool to be executed.
- **tool_description** (<code>str</code>) The description of the tool.
- **tool_params** (<code>dict\[str, Any\]</code>) The parameters to be passed to the tool.
@@ -0,0 +1,355 @@
---
title: "Image Converters"
id: image-converters-api
description: "Various converters to transform image data from one format to another."
slug: "/image-converters-api"
---
## document_to_image
### DocumentToImageContent
Converts documents sourced from PDF and image files into ImageContents.
This component processes a list of documents and extracts visual content from supported file formats, converting
them into ImageContents that can be used for multimodal AI tasks. It handles both direct image files and PDF
documents by extracting specific pages as images.
Documents are expected to have metadata containing:
- The `file_path_meta_field` key with a valid file path that exists when combined with `root_path`
- A supported image format (MIME type must be one of the supported image types)
- For PDF files, a `page_number` key specifying which page to extract
### Usage example
```python
from haystack import Document
from haystack.components.converters.image.document_to_image import DocumentToImageContent
converter = DocumentToImageContent(
file_path_meta_field="file_path",
root_path="test/test_files",
detail="high",
size=(800, 600)
)
documents = [
Document(content="Optional description of apple.jpg", meta={"file_path": "images/apple.jpg"}),
Document(
content="Optional description of sample_pdf_1.pdf",
meta={"file_path": "pdf/sample_pdf_1.pdf", "page_number": 1}
)
]
result = converter.run(documents)
image_contents = result["image_contents"]
# [ImageContent(
# base64_image='/9j/4A...', mime_type='image/jpeg', detail='high', meta={'file_path': 'images/apple.jpg'}
# ),
# ImageContent(
# base64_image='/9j/4A...', mime_type='image/jpeg', detail='high',
# meta={'file_path': 'pdf/sample_pdf_1.pdf', 'page_number': 1})
# )]
```
#### __init__
```python
__init__(
*,
file_path_meta_field: str = "file_path",
root_path: str | None = None,
detail: Literal["auto", "high", "low"] | None = None,
size: tuple[int, int] | None = None
) -> None
```
Initialize the DocumentToImageContent component.
**Parameters:**
- **file_path_meta_field** (<code>str</code>) The metadata field in the Document that contains the file path to the image or PDF.
- **root_path** (<code>str | None</code>) The root directory path where document files are located. If provided, file paths in
document metadata will be resolved relative to this path. If None, file paths are treated as absolute paths.
- **detail** (<code>Literal['auto', 'high', 'low'] | None</code>) Optional detail level of the image (only supported by OpenAI). Can be "auto", "high", or "low".
This will be passed to the created ImageContent objects.
- **size** (<code>tuple\[int, int\] | None</code>) If provided, resizes the image to fit within the specified dimensions (width, height) while
maintaining aspect ratio. This reduces file size, memory usage, and processing time, which is beneficial
when working with models that have resolution constraints or when transmitting images to remote services.
#### run
```python
run(documents: list[Document]) -> dict[str, list[ImageContent | None]]
```
Convert documents with image or PDF sources into ImageContent objects.
This method processes the input documents, extracting images from supported file formats and converting them
into ImageContent objects.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) A list of documents to process. Each document should have metadata containing at minimum
a 'file_path_meta_field' key. PDF documents additionally require a 'page_number' key to specify which
page to convert.
**Returns:**
- <code>dict\[str, list\[ImageContent | None\]\]</code> Dictionary containing one key:
- "image_contents": ImageContents created from the processed documents. These contain base64-encoded image
data and metadata. The order corresponds to order of input documents.
**Raises:**
- <code>ValueError</code> If any document is missing the required metadata keys, has an invalid file path, or has an unsupported
MIME type. The error message will specify which document and what information is missing or incorrect.
## file_to_document
### ImageFileToDocument
Converts image file references into empty Document objects with associated metadata.
This component is useful in pipelines where image file paths need to be wrapped in `Document` objects to be
processed by downstream components such as the `LLMDocumentContentExtractor` or the
`SentenceTransformersDocumentImageEmbedder` (available in the `sentence-transformers-haystack` integration).
It does **not** extract any content from the image files, instead it creates `Document` objects with `None` as
their content and attaches metadata such as file path and any user-provided values.
### Usage example
```python
from haystack.components.converters.image import ImageFileToDocument
converter = ImageFileToDocument()
sources = ["image.jpg", "another_image.png"]
result = converter.run(sources=sources)
documents = result["documents"]
print(documents)
# [Document(id=..., meta: {'file_path': 'image.jpg'}),
# Document(id=..., meta: {'file_path': 'another_image.png'})]
```
#### __init__
```python
__init__(*, store_full_path: bool = False) -> None
```
Initialize the ImageFileToDocument component.
**Parameters:**
- **store_full_path** (<code>bool</code>) If True, the full path of the file is stored in the metadata of the document.
If False, only the file name is stored.
#### run
```python
run(
*,
sources: list[str | Path | ByteStream],
meta: dict[str, Any] | list[dict[str, Any]] | None = None
) -> dict[str, list[Document]]
```
Convert image files into empty Document objects with metadata.
This method accepts image file references (as file paths or ByteStreams) and creates `Document` objects
without content. These documents are enriched with metadata derived from the input source and optional
user-provided metadata.
**Parameters:**
- **sources** (<code>list\[str | Path | ByteStream\]</code>) List of file paths or ByteStream objects to convert.
- **meta** (<code>dict\[str, Any\] | list\[dict\[str, Any\]\] | None</code>) Optional metadata to attach to the documents.
This value can be a list of dictionaries or a single dictionary.
If it's a single dictionary, its content is added to the metadata of all produced documents.
If it's a list, its length must match the number of sources, as they are zipped together.
For ByteStream objects, their `meta` is added to the output documents.
**Returns:**
- <code>dict\[str, list\[Document\]\]</code> A dictionary containing:
- `documents`: A list of `Document` objects with empty content and associated metadata.
## file_to_image
### ImageFileToImageContent
Converts image files to ImageContent objects.
### Usage example
```python
from haystack.components.converters.image import ImageFileToImageContent
converter = ImageFileToImageContent()
sources = ["image.jpg", "another_image.png"]
image_contents = converter.run(sources=sources)["image_contents"]
print(image_contents)
# [ImageContent(base64_image='...',
# mime_type='image/jpeg',
# detail=None,
# meta={'file_path': 'image.jpg'}),
# ...]
```
#### __init__
```python
__init__(
*,
detail: Literal["auto", "high", "low"] | None = None,
size: tuple[int, int] | None = None
) -> None
```
Create the ImageFileToImageContent component.
**Parameters:**
- **detail** (<code>Literal['auto', 'high', 'low'] | None</code>) Optional detail level of the image (only supported by OpenAI). One of "auto", "high", or "low".
This will be passed to the created ImageContent objects.
- **size** (<code>tuple\[int, int\] | None</code>) If provided, resizes the image to fit within the specified dimensions (width, height) while
maintaining aspect ratio. This reduces file size, memory usage, and processing time, which is beneficial
when working with models that have resolution constraints or when transmitting images to remote services.
#### run
```python
run(
sources: list[str | Path | ByteStream],
meta: dict[str, Any] | list[dict[str, Any]] | None = None,
*,
detail: Literal["auto", "high", "low"] | None = None,
size: tuple[int, int] | None = None
) -> dict[str, list[ImageContent]]
```
Converts files to ImageContent objects.
**Parameters:**
- **sources** (<code>list\[str | Path | ByteStream\]</code>) List of file paths or ByteStream objects to convert.
- **meta** (<code>dict\[str, Any\] | list\[dict\[str, Any\]\] | None</code>) Optional metadata to attach to the ImageContent objects.
This value can be a list of dictionaries or a single dictionary.
If it's a single dictionary, its content is added to the metadata of all produced ImageContent objects.
If it's a list, its length must match the number of sources as they're zipped together.
For ByteStream objects, their `meta` is added to the output ImageContent objects.
- **detail** (<code>Literal['auto', 'high', 'low'] | None</code>) Optional detail level of the image (only supported by OpenAI). One of "auto", "high", or "low".
This will be passed to the created ImageContent objects.
If not provided, the detail level will be the one set in the constructor.
- **size** (<code>tuple\[int, int\] | None</code>) If provided, resizes the image to fit within the specified dimensions (width, height) while
maintaining aspect ratio. This reduces file size, memory usage, and processing time, which is beneficial
when working with models that have resolution constraints or when transmitting images to remote services.
If not provided, the size value will be the one set in the constructor.
**Returns:**
- <code>dict\[str, list\[ImageContent\]\]</code> A dictionary with the following keys:
- `image_contents`: A list of ImageContent objects.
## pdf_to_image
### PDFToImageContent
Converts PDF files to ImageContent objects.
### Usage example
```python
from haystack.components.converters.image import PDFToImageContent
converter = PDFToImageContent()
sources = ["file.pdf", "another_file.pdf"]
image_contents = converter.run(sources=sources)["image_contents"]
print(image_contents)
# [ImageContent(base64_image='...',
# mime_type='application/pdf',
# detail=None,
# meta={'file_path': 'file.pdf', 'page_number': 1}),
# ...]
```
#### __init__
```python
__init__(
*,
detail: Literal["auto", "high", "low"] | None = None,
size: tuple[int, int] | None = None,
page_range: list[str | int] | None = None
) -> None
```
Create the PDFToImageContent component.
**Parameters:**
- **detail** (<code>Literal['auto', 'high', 'low'] | None</code>) Optional detail level of the image (only supported by OpenAI). One of "auto", "high", or "low".
This will be passed to the created ImageContent objects.
- **size** (<code>tuple\[int, int\] | None</code>) If provided, resizes the image to fit within the specified dimensions (width, height) while
maintaining aspect ratio. This reduces file size, memory usage, and processing time, which is beneficial
when working with models that have resolution constraints or when transmitting images to remote services.
- **page_range** (<code>list\[str | int\] | None</code>) List of page numbers and/or page ranges to convert to images. Page numbers start at 1.
If None, all pages in the PDF will be converted. Pages outside the valid range (1 to number of pages)
will be skipped with a warning. For example, page_range=[1, 3] will convert only the first and third
pages of the document. It also accepts printable range strings, e.g.: ['1-3', '5', '8', '10-12']
will convert pages 1, 2, 3, 5, 8, 10, 11, 12.
#### run
```python
run(
sources: list[str | Path | ByteStream],
meta: dict[str, Any] | list[dict[str, Any]] | None = None,
*,
detail: Literal["auto", "high", "low"] | None = None,
size: tuple[int, int] | None = None,
page_range: list[str | int] | None = None
) -> dict[str, list[ImageContent]]
```
Converts files to ImageContent objects.
**Parameters:**
- **sources** (<code>list\[str | Path | ByteStream\]</code>) List of file paths or ByteStream objects to convert.
- **meta** (<code>dict\[str, Any\] | list\[dict\[str, Any\]\] | None</code>) Optional metadata to attach to the ImageContent objects.
This value can be a list of dictionaries or a single dictionary.
If it's a single dictionary, its content is added to the metadata of all produced ImageContent objects.
If it's a list, its length must match the number of sources as they're zipped together.
For ByteStream objects, their `meta` is added to the output ImageContent objects.
- **detail** (<code>Literal['auto', 'high', 'low'] | None</code>) Optional detail level of the image (only supported by OpenAI). One of "auto", "high", or "low".
This will be passed to the created ImageContent objects.
If not provided, the detail level will be the one set in the constructor.
- **size** (<code>tuple\[int, int\] | None</code>) If provided, resizes the image to fit within the specified dimensions (width, height) while
maintaining aspect ratio. This reduces file size, memory usage, and processing time, which is beneficial
when working with models that have resolution constraints or when transmitting images to remote services.
If not provided, the size value will be the one set in the constructor.
- **page_range** (<code>list\[str | int\] | None</code>) List of page numbers and/or page ranges to convert to images. Page numbers start at 1.
If None, all pages in the PDF will be converted. Pages outside the valid range (1 to number of pages)
will be skipped with a warning. For example, page_range=[1, 3] will convert only the first and third
pages of the document. It also accepts printable range strings, e.g.: ['1-3', '5', '8', '10-12']
will convert pages 1, 2, 3, 5, 8, 10, 11, 12.
If not provided, the page_range value will be the one set in the constructor.
**Returns:**
- <code>dict\[str, list\[ImageContent\]\]</code> A dictionary with the following keys:
- `image_contents`: A list of ImageContent objects.
@@ -0,0 +1,566 @@
---
title: "Joiners"
id: joiners-api
description: "Components that join list of different objects"
slug: "/joiners-api"
---
## answer_joiner
### JoinMode
Bases: <code>Enum</code>
Enum for AnswerJoiner join modes.
#### from_str
```python
from_str(string: str) -> JoinMode
```
Convert a string to a JoinMode enum.
### AnswerJoiner
Merges multiple lists of `Answer` objects into a single list.
Use this component to combine answers from different Generators into a single list.
Currently, the component supports only one join mode: `CONCATENATE`.
This mode concatenates multiple lists of answers into a single list.
### Usage example
In this example, AnswerJoiner merges answers from two different Generators:
```python
from haystack.components.builders import AnswerBuilder
from haystack.components.joiners import AnswerJoiner
from haystack.core.pipeline import Pipeline
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
query = "What's Natural Language Processing?"
messages = [ChatMessage.from_system("You are a helpful, respectful and honest assistant. Be super concise."),
ChatMessage.from_user(query)]
pipe = Pipeline()
pipe.add_component("llm_1", OpenAIChatGenerator())
pipe.add_component("llm_2", OpenAIChatGenerator())
pipe.add_component("aba", AnswerBuilder())
pipe.add_component("abb", AnswerBuilder())
pipe.add_component("joiner", AnswerJoiner())
pipe.connect("llm_1.replies", "aba")
pipe.connect("llm_2.replies", "abb")
pipe.connect("aba.answers", "joiner")
pipe.connect("abb.answers", "joiner")
results = pipe.run(data={"llm_1": {"messages": messages},
"llm_2": {"messages": messages},
"aba": {"query": query},
"abb": {"query": query}})
```
#### __init__
```python
__init__(
join_mode: str | JoinMode = JoinMode.CONCATENATE,
top_k: int | None = None,
sort_by_score: bool = False,
) -> None
```
Creates an AnswerJoiner component.
**Parameters:**
- **join_mode** (<code>str | JoinMode</code>) Specifies the join mode to use. Available modes:
- `concatenate`: Concatenates multiple lists of Answers into a single list.
- **top_k** (<code>int | None</code>) The maximum number of Answers to return.
- **sort_by_score** (<code>bool</code>) If `True`, sorts the documents by score in descending order.
If a document has no score, it is handled as if its score is -infinity.
#### run
```python
run(
answers: Variadic[list[AnswerType]], top_k: int | None = None
) -> dict[str, Any]
```
Joins multiple lists of Answers into a single list depending on the `join_mode` parameter.
**Parameters:**
- **answers** (<code>Variadic\[list\[AnswerType\]\]</code>) Nested list of Answers to be merged.
- **top_k** (<code>int | None</code>) The maximum number of Answers to return. Overrides the instance's `top_k` if provided.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- `answers`: Merged list of Answers
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> AnswerJoiner
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) The dictionary to deserialize from.
**Returns:**
- <code>AnswerJoiner</code> The deserialized component.
## branch
### BranchJoiner
A component that merges multiple input branches of a pipeline into a single output stream.
`BranchJoiner` receives multiple inputs of the same data type and forwards the first received value
to its output. This is useful for scenarios where multiple branches need to converge before proceeding.
### Common Use Cases:
- **Loop Handling:** `BranchJoiner` helps close loops in pipelines. For example, if a pipeline component validates
or modifies incoming data and produces an error-handling branch, `BranchJoiner` can merge both branches and send
(or resend in the case of a loop) the data to the component that evaluates errors. See "Usage example" below.
- **Decision-Based Merging:** `BranchJoiner` reconciles branches coming from Router components (such as
`ConditionalRouter`, `TextLanguageRouter`). Suppose a `TextLanguageRouter` directs user queries to different
Retrievers based on the detected language. Each Retriever processes its assigned query and passes the results
to `BranchJoiner`, which consolidates them into a single output before passing them to the next component, such
as a `PromptBuilder`.
### Example Usage:
```python
import json
from haystack import Pipeline
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.joiners import BranchJoiner
from haystack.components.validators import JsonSchemaValidator
from haystack.dataclasses import ChatMessage
# Define a schema for validation
person_schema = {
"type": "object",
"properties": {
"first_name": {"type": "string", "pattern": "^[A-Z][a-z]+$"},
"last_name": {"type": "string", "pattern": "^[A-Z][a-z]+$"},
"nationality": {"type": "string", "enum": ["Italian", "Portuguese", "American"]},
},
"required": ["first_name", "last_name", "nationality"]
}
# Initialize a pipeline
pipe = Pipeline()
# Add components to the pipeline
pipe.add_component("joiner", BranchJoiner(list[ChatMessage]))
pipe.add_component("generator", OpenAIChatGenerator(model="gpt-4.1-mini"))
pipe.add_component("validator", JsonSchemaValidator(json_schema=person_schema))
# And connect them
pipe.connect("joiner", "generator")
pipe.connect("generator.replies", "validator.messages")
pipe.connect("validator.validation_error", "joiner")
result = pipe.run(
data={
"generator": {"generation_kwargs": {"response_format": {"type": "json_object"}}},
"joiner": {"value": [ChatMessage.from_user("Create json from Peter Parker")]}}
)
print(json.loads(result["validator"]["validated"][0].text))
# >> {'first_name': 'Peter', 'last_name': 'Parker', 'nationality': 'American', 'name': 'Spider-Man', 'occupation':
# >> 'Superhero', 'age': 23, 'location': 'New York City'}
```
Note that `BranchJoiner` can manage only one data type at a time. In this case, `BranchJoiner` is created for
passing `list[ChatMessage]`. This determines the type of data that `BranchJoiner` will receive from the upstream
connected components and also the type of data that `BranchJoiner` will send through its output.
In the code example, `BranchJoiner` receives a looped back `list[ChatMessage]` from the `JsonSchemaValidator` and
sends it down to the `OpenAIChatGenerator` for re-generation. We can have multiple loopback connections in the
pipeline. In this instance, the downstream component is only one (the `OpenAIChatGenerator`), but the pipeline could
have more than one downstream component.
#### __init__
```python
__init__(type_: type) -> None
```
Creates a `BranchJoiner` component.
**Parameters:**
- **type\_** (<code>type</code>) The expected data type of inputs and outputs.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component into a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> BranchJoiner
```
Deserializes a `BranchJoiner` instance from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) The dictionary containing serialized component data.
**Returns:**
- <code>BranchJoiner</code> A deserialized `BranchJoiner` instance.
#### run
```python
run(**kwargs: Any) -> dict[str, Any]
```
Executes the `BranchJoiner`, selecting the first available input value and passing it downstream.
**Parameters:**
- \*\***kwargs** (<code>Any</code>) The input data. Must be of the type declared by `type_` during initialization.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with a single key `value`, containing the first input received.
## document_joiner
### JoinMode
Bases: <code>Enum</code>
Enum for join mode.
#### from_str
```python
from_str(string: str) -> JoinMode
```
Convert a string to a JoinMode enum.
### DocumentJoiner
Joins multiple lists of documents into a single list.
It supports different join modes:
- concatenate: Keeps the highest-scored document in case of duplicates.
- merge: Calculates a weighted sum of scores for duplicates and merges them.
- reciprocal_rank_fusion: Merges and assigns scores based on reciprocal rank fusion.
- distribution_based_rank_fusion: Merges and assigns scores based on scores distribution in each Retriever.
### Usage example:
```python
from haystack import Pipeline, Document
from haystack.components.embedders import OpenAITextEmbedder, OpenAIDocumentEmbedder
from haystack.components.joiners import DocumentJoiner
from haystack.components.retrievers import InMemoryBM25Retriever
from haystack.components.retrievers import InMemoryEmbeddingRetriever
from haystack.document_stores.in_memory import InMemoryDocumentStore
document_store = InMemoryDocumentStore()
docs = [Document(content="Paris"), Document(content="Berlin"), Document(content="London")]
embedder = OpenAIDocumentEmbedder()
docs_embeddings = embedder.run(docs)
document_store.write_documents(docs_embeddings['documents'])
p = Pipeline()
p.add_component(instance=InMemoryBM25Retriever(document_store=document_store), name="bm25_retriever")
p.add_component(
instance=OpenAITextEmbedder(),
name="text_embedder",
)
p.add_component(instance=InMemoryEmbeddingRetriever(document_store=document_store), name="embedding_retriever")
p.add_component(instance=DocumentJoiner(), name="joiner")
p.connect("bm25_retriever", "joiner")
p.connect("embedding_retriever", "joiner")
p.connect("text_embedder", "embedding_retriever")
query = "What is the capital of France?"
p.run(data={"query": query, "text": query, "top_k": 1})
```
#### __init__
```python
__init__(
join_mode: str | JoinMode = JoinMode.CONCATENATE,
weights: list[float] | None = None,
top_k: int | None = None,
sort_by_score: bool = True,
) -> None
```
Creates a DocumentJoiner component.
**Parameters:**
- **join_mode** (<code>str | JoinMode</code>) Specifies the join mode to use. Available modes:
- `concatenate`: Keeps the highest-scored document in case of duplicates.
- `merge`: Calculates a weighted sum of scores for duplicates and merges them.
- `reciprocal_rank_fusion`: Merges and assigns scores based on reciprocal rank fusion.
- `distribution_based_rank_fusion`: Merges and assigns scores based on scores
distribution in each Retriever.
- **weights** (<code>list\[float\] | None</code>) Assign importance to each list of documents to influence how they're joined.
This parameter is ignored for
`concatenate` or `distribution_based_rank_fusion` join modes.
Weight for each list of documents must match the number of inputs.
- **top_k** (<code>int | None</code>) The maximum number of documents to return.
- **sort_by_score** (<code>bool</code>) If `True`, sorts the documents by score in descending order.
If a document has no score, it is handled as if its score is -infinity.
#### run
```python
run(
documents: Variadic[list[Document]], top_k: int | None = None
) -> dict[str, Any]
```
Joins multiple lists of Documents into a single list depending on the `join_mode` parameter.
**Parameters:**
- **documents** (<code>Variadic\[list\[Document\]\]</code>) List of list of documents to be merged.
- **top_k** (<code>int | None</code>) The maximum number of documents to return. Overrides the instance's `top_k` if provided.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- `documents`: Merged list of Documents
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> DocumentJoiner
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) The dictionary to deserialize from.
**Returns:**
- <code>DocumentJoiner</code> The deserialized component.
## list_joiner
### ListJoiner
A component that joins multiple lists into a single flat list.
The ListJoiner receives multiple lists of the same type and concatenates them into a single flat list.
The output order respects the pipeline's execution sequence, with earlier inputs being added first.
Usage example:
```python
from haystack.components.builders import ChatPromptBuilder
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
from haystack import Pipeline
from haystack.components.joiners import ListJoiner
user_message = [ChatMessage.from_user("Give a brief answer the following question: {{query}}")]
feedback_prompt = """
You are given a question and an answer.
Your task is to provide a score and a brief feedback on the answer.
Question: {{query}}
Answer: {{response}}
"""
feedback_message = [ChatMessage.from_system(feedback_prompt)]
prompt_builder = ChatPromptBuilder(template=user_message)
feedback_prompt_builder = ChatPromptBuilder(template=feedback_message)
llm = OpenAIChatGenerator()
feedback_llm = OpenAIChatGenerator()
pipe = Pipeline()
pipe.add_component("prompt_builder", prompt_builder)
pipe.add_component("llm", llm)
pipe.add_component("feedback_prompt_builder", feedback_prompt_builder)
pipe.add_component("feedback_llm", feedback_llm)
pipe.add_component("list_joiner", ListJoiner(list[ChatMessage]))
pipe.connect("prompt_builder.prompt", "llm.messages")
pipe.connect("prompt_builder.prompt", "list_joiner")
pipe.connect("llm.replies", "list_joiner")
pipe.connect("llm.replies", "feedback_prompt_builder.response")
pipe.connect("feedback_prompt_builder.prompt", "feedback_llm.messages")
pipe.connect("feedback_llm.replies", "list_joiner")
query = "What is nuclear physics?"
ans = pipe.run(data={"prompt_builder": {"template_variables":{"query": query}},
"feedback_prompt_builder": {"template_variables":{"query": query}}})
print(ans["list_joiner"]["values"])
```
#### __init__
```python
__init__(list_type_: type | None = None) -> None
```
Creates a ListJoiner component.
**Parameters:**
- **list_type\_** (<code>type | None</code>) The expected type of the lists this component will join (e.g., list[ChatMessage]).
If specified, all input lists must conform to this type. If None, the component defaults to handling
lists of any type including mixed types.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> ListJoiner
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Dictionary to deserialize from.
**Returns:**
- <code>ListJoiner</code> Deserialized component.
#### run
```python
run(values: Variadic[list[Any]]) -> dict[str, list[Any]]
```
Joins multiple lists into a single flat list.
**Parameters:**
- **values** (<code>Variadic\[list\[Any\]\]</code>) The list to be joined.
**Returns:**
- <code>dict\[str, list\[Any\]\]</code> Dictionary with 'values' key containing the joined list.
## string_joiner
### StringJoiner
Component to join strings from different components to a list of strings.
### Usage example
```python
from haystack.components.joiners import StringJoiner
from haystack.components.builders import PromptBuilder
from haystack.core.pipeline import Pipeline
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
string_1 = "What's Natural Language Processing?"
string_2 = "What is life?"
pipeline = Pipeline()
pipeline.add_component("prompt_builder_1", PromptBuilder("Builder 1: {{query}}"))
pipeline.add_component("prompt_builder_2", PromptBuilder("Builder 2: {{query}}"))
pipeline.add_component("string_joiner", StringJoiner())
pipeline.connect("prompt_builder_1.prompt", "string_joiner.strings")
pipeline.connect("prompt_builder_2.prompt", "string_joiner.strings")
print(pipeline.run(data={"prompt_builder_1": {"query": string_1}, "prompt_builder_2": {"query": string_2}}))
# >> {"string_joiner": {"strings": ["Builder 1: What's Natural Language Processing?", "Builder 2: What is life?"]}}
```
#### run
```python
run(strings: Variadic[str]) -> dict[str, list[str]]
```
Joins strings into a list of strings
**Parameters:**
- **strings** (<code>Variadic\[str\]</code>) strings from different components
**Returns:**
- <code>dict\[str, list\[str\]\]</code> A dictionary with the following keys:
- `strings`: Merged list of strings
@@ -0,0 +1,501 @@
---
title: "Pipeline"
id: pipeline-api
description: "Arranges components and integrations in flow."
slug: "/pipeline-api"
---
## pipeline
### PipelineStreamHandle
Handle returned by `Pipeline.stream()`.
Async-iterable over `StreamingChunk`s produced by streaming components in the pipeline. After iteration ends,
`result` holds the final pipeline output dict.
By default, iteration cleans up automatically: if the consumer abandons iteration, the underlying pipeline task is
cancelled. `aclose()` is also available for explicit cleanup.
#### result
```python
result: dict[str, Any]
```
Final pipeline output dict, available only after a successful, complete run.
Raises a `RuntimeError` if the pipeline has not finished or was cancelled. If the pipeline failed, re-raises the
original exception.
#### aclose
```python
aclose() -> None
```
Cancel the underlying pipeline task.
Bounded by `_CLEANUP_TIMEOUT_SECONDS` so that components cannot block cleanup indefinitely.
### Pipeline
Bases: <code>PipelineBase</code>
Orchestration engine that runs components according to the execution graph.
Supports both a synchronous run path (`run`) and an asynchronous run path
(`run_async`, `run_async_generator`, `stream`).
#### run
```python
run(
data: dict[str, Any],
include_outputs_from: set[str] | None = None,
*,
break_point: Breakpoint | None = None,
pipeline_snapshot: PipelineSnapshot | None = None,
snapshot_callback: SnapshotCallback | None = None
) -> dict[str, Any]
```
Runs the Pipeline with given input data.
`run` executes synchronously and blocks the calling thread until the run completes. In an async context,
use `run_async` instead.
Usage:
```python
from haystack import Pipeline, Document
from haystack.components.builders.answer_builder import AnswerBuilder
from haystack.components.builders.chat_prompt_builder import ChatPromptBuilder
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.retrievers.in_memory import InMemoryBM25Retriever
from haystack.dataclasses import ChatMessage
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.utils import Secret
# Write documents to InMemoryDocumentStore
document_store = InMemoryDocumentStore()
document_store.write_documents([
Document(content="My name is Jean and I live in Paris."),
Document(content="My name is Mark and I live in Berlin."),
Document(content="My name is Giorgio and I live in Rome.")
])
retriever = InMemoryBM25Retriever(document_store=document_store)
prompt_template = """
Given these documents, answer the question.
Documents:
{% for doc in documents %}
{{ doc.content }}
{% endfor %}
Question: {{question}}
Answer:
"""
template = [ChatMessage.from_user(prompt_template)]
prompt_builder = ChatPromptBuilder(
template=template,
required_variables=["question", "documents"],
variables=["question", "documents"]
)
llm = OpenAIChatGenerator()
rag_pipeline = Pipeline()
rag_pipeline.add_component("retriever", retriever)
rag_pipeline.add_component("prompt_builder", prompt_builder)
rag_pipeline.add_component("llm", llm)
rag_pipeline.connect("retriever", "prompt_builder.documents")
rag_pipeline.connect("prompt_builder", "llm")
question = "Who lives in Paris?"
results = rag_pipeline.run(
{
"retriever": {"query": question},
"prompt_builder": {"question": question},
}
)
print(results["llm"]["replies"][0].text)
# Jean lives in Paris
```
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) A dictionary of inputs for the pipeline's components. Each key is a component name
and its value is a dictionary of that component's input parameters:
```
data = {
"comp1": {"input1": 1, "input2": 2},
}
```
For convenience, this format is also supported when input names are unique:
```
data = {
"input1": 1, "input2": 2,
}
```
- **include_outputs_from** (<code>set\[str\] | None</code>) Set of component names whose individual outputs are to be
included in the pipeline's output. For components that are
invoked multiple times (in a loop), only the last-produced
output is included.
- **break_point** (<code>Breakpoint | None</code>) A breakpoint that pauses execution before the specified component runs by raising a
`BreakpointException` carrying a `PipelineSnapshot` of the current pipeline state.
- **pipeline_snapshot** (<code>PipelineSnapshot | None</code>) A snapshot of a previously interrupted pipeline execution to resume from. Can be combined with
`break_point` to step through a pipeline: resume from the snapshot and pause again at the next
breakpoint. The `break_point` must target a different component or visit count than the one the
snapshot was created at, otherwise it would trigger again before any progress is made.
- **snapshot_callback** (<code>SnapshotCallback | None</code>) Optional callback function that is invoked when a pipeline snapshot is created.
The callback receives a `PipelineSnapshot` object and can return an optional string
(e.g., a file path or identifier).
If provided, the callback is used instead of the default file-saving behavior,
allowing custom handling of snapshots (e.g., saving to a database, sending to a remote service).
If not provided, the default behavior saves snapshots to a JSON file.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary where each entry corresponds to a component name
and its output. If `include_outputs_from` is `None`, this dictionary
will only contain the outputs of leaf components, i.e., components
without outgoing connections.
**Raises:**
- <code>ValueError</code> If invalid inputs are provided to the pipeline.
- <code>PipelineRuntimeError</code> If the Pipeline contains cycles with unsupported connections that would cause
it to get stuck and fail running.
Or if a Component fails or returns output in an unsupported type.
- <code>PipelineMaxComponentRuns</code> If a Component reaches the maximum number of times it can be run in this Pipeline.
- <code>PipelineBreakpointException</code> When a pipeline_breakpoint is triggered. Contains the component name, state, and partial results.
#### run_async_generator
```python
run_async_generator(
data: dict[str, Any],
include_outputs_from: set[str] | None = None,
concurrency_limit: int = 4,
) -> AsyncGenerator[dict[str, Any], None]
```
Executes the pipeline step by step asynchronously, yielding partial outputs when any component finishes.
Usage:
```python
from haystack import Document
from haystack.components.builders import ChatPromptBuilder
from haystack.dataclasses import ChatMessage
from haystack.utils import Secret
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.components.retrievers.in_memory import InMemoryBM25Retriever
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.builders.prompt_builder import PromptBuilder
from haystack import Pipeline
import asyncio
# Write documents to InMemoryDocumentStore
document_store = InMemoryDocumentStore()
document_store.write_documents([
Document(content="My name is Jean and I live in Paris."),
Document(content="My name is Mark and I live in Berlin."),
Document(content="My name is Giorgio and I live in Rome.")
])
prompt_template = [
ChatMessage.from_user(
'''
Given these documents, answer the question.
Documents:
{% for doc in documents %}
{{ doc.content }}
{% endfor %}
Question: {{question}}
Answer:
''')
]
# Create and connect pipeline components
retriever = InMemoryBM25Retriever(document_store=document_store)
prompt_builder = ChatPromptBuilder(template=prompt_template)
llm = OpenAIChatGenerator()
rag_pipeline = Pipeline()
rag_pipeline.add_component("retriever", retriever)
rag_pipeline.add_component("prompt_builder", prompt_builder)
rag_pipeline.add_component("llm", llm)
rag_pipeline.connect("retriever", "prompt_builder.documents")
rag_pipeline.connect("prompt_builder", "llm")
# Prepare input data
question = "Who lives in Paris?"
data = {
"retriever": {"query": question},
"prompt_builder": {"question": question},
}
# Process results as they become available
async def process_results():
async for partial_output in rag_pipeline.run_async_generator(
data=data,
include_outputs_from={"retriever", "llm"}
):
# Each partial_output contains the results from a completed component
if "retriever" in partial_output:
print("Retrieved documents:", len(partial_output["retriever"]["documents"]))
if "llm" in partial_output:
print("Generated answer:", partial_output["llm"]["replies"][0])
asyncio.run(process_results())
```
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Initial input data to the pipeline.
- **concurrency_limit** (<code>int</code>) The maximum number of components that are allowed to run concurrently.
- **include_outputs_from** (<code>set\[str\] | None</code>) Set of component names whose individual outputs are to be
included in the pipeline's output. For components that are
invoked multiple times (in a loop), only the last-produced
output is included.
**Returns:**
- <code>AsyncGenerator\[dict\[str, Any\], None\]</code> An async iterator containing partial (and final) outputs.
**Raises:**
- <code>ValueError</code> If invalid inputs are provided to the pipeline, or if `concurrency_limit` is less than 1.
- <code>PipelineMaxComponentRuns</code> If a component exceeds the maximum number of allowed executions within the pipeline.
- <code>PipelineRuntimeError</code> If the Pipeline contains cycles with unsupported connections that would cause
it to get stuck and fail running.
Or if a Component fails or returns output in an unsupported type.
#### run_async
```python
run_async(
data: dict[str, Any],
include_outputs_from: set[str] | None = None,
concurrency_limit: int = 4,
) -> dict[str, Any]
```
Provides an asynchronous interface to run the pipeline with provided input data.
This method allows the pipeline to be integrated into an asynchronous workflow, enabling non-blocking
execution of pipeline components.
Usage:
```python
import asyncio
from haystack import Document
from haystack.components.builders import ChatPromptBuilder
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.retrievers.in_memory import InMemoryBM25Retriever
from haystack import Pipeline
from haystack.dataclasses import ChatMessage
from haystack.document_stores.in_memory import InMemoryDocumentStore
# Write documents to InMemoryDocumentStore
document_store = InMemoryDocumentStore()
document_store.write_documents([
Document(content="My name is Jean and I live in Paris."),
Document(content="My name is Mark and I live in Berlin."),
Document(content="My name is Giorgio and I live in Rome.")
])
prompt_template = [
ChatMessage.from_user(
'''
Given these documents, answer the question.
Documents:
{% for doc in documents %}
{{ doc.content }}
{% endfor %}
Question: {{question}}
Answer:
''')
]
retriever = InMemoryBM25Retriever(document_store=document_store)
prompt_builder = ChatPromptBuilder(template=prompt_template)
llm = OpenAIChatGenerator()
rag_pipeline = Pipeline()
rag_pipeline.add_component("retriever", retriever)
rag_pipeline.add_component("prompt_builder", prompt_builder)
rag_pipeline.add_component("llm", llm)
rag_pipeline.connect("retriever", "prompt_builder.documents")
rag_pipeline.connect("prompt_builder", "llm")
# Ask a question
question = "Who lives in Paris?"
async def run_inner(data, include_outputs_from):
return await rag_pipeline.run_async(data=data, include_outputs_from=include_outputs_from)
data = {
"retriever": {"query": question},
"prompt_builder": {"question": question},
}
results = asyncio.run(run_inner(data, include_outputs_from={"retriever", "llm"}))
print(results["llm"]["replies"])
# [ChatMessage(_role=<ChatRole.ASSISTANT: 'assistant'>, _content=[TextContent(text='Jean lives in Paris.')],
# _name=None, _meta={'model': 'gpt-5-mini', 'index': 0, 'finish_reason': 'stop', 'usage':
# {'completion_tokens': 6, 'prompt_tokens': 69, 'total_tokens': 75,
# 'completion_tokens_details': CompletionTokensDetails(accepted_prediction_tokens=0,
# audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0), 'prompt_tokens_details':
# PromptTokensDetails(audio_tokens=0, cached_tokens=0)}})]
```
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) A dictionary of inputs for the pipeline's components. Each key is a component name
and its value is a dictionary of that component's input parameters:
```
data = {
"comp1": {"input1": 1, "input2": 2},
}
```
For convenience, this format is also supported when input names are unique:
```
data = {
"input1": 1, "input2": 2,
}
```
- **include_outputs_from** (<code>set\[str\] | None</code>) Set of component names whose individual outputs are to be
included in the pipeline's output. For components that are
invoked multiple times (in a loop), only the last-produced
output is included.
- **concurrency_limit** (<code>int</code>) The maximum number of components that should be allowed to run concurrently.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary where each entry corresponds to a component name
and its output. If `include_outputs_from` is `None`, this dictionary
will only contain the outputs of leaf components, i.e., components
without outgoing connections.
**Raises:**
- <code>ValueError</code> If invalid inputs are provided to the pipeline, or if `concurrency_limit` is less than 1.
- <code>PipelineRuntimeError</code> If the Pipeline contains cycles with unsupported connections that would cause
it to get stuck and fail running.
Or if a Component fails or returns output in an unsupported type.
- <code>PipelineMaxComponentRuns</code> If a Component reaches the maximum number of times it can be run in this Pipeline.
#### stream
```python
stream(
data: dict[str, Any],
*,
streaming_components: list[str] | None = None,
include_outputs_from: set[str] | None = None,
concurrency_limit: int = 4,
cancel_on_abandon: bool = True
) -> PipelineStreamHandle
```
Run the pipeline and return a handle that streams `StreamingChunk`s as they arrive.
Iterate the handle with `async for` to consume chunks; after iteration ends, `handle.result` holds the final
pipeline output dict (same as `run_async`). By default, if iteration is abandoned, the underlying pipeline task
is cancelled automatically. Pass `cancel_on_abandon=False` to instead let the pipeline run to completion.
For every async-capable component that exposes a `streaming_callback` input socket, a forwarder is injected at
runtime that pushes chunks onto the handle's queue. If a `streaming_callback` is provided at component init or
at runtime (inside `data`, e.g. `data={"llm": {"streaming_callback": cb}}`), it is also invoked for each chunk.
Async callbacks are preferred; a sync callback is accepted but will run synchronously on the event loop and
may block it.
Usage:
```python
import asyncio
from haystack.components.builders import ChatPromptBuilder
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack import Pipeline
from haystack.dataclasses import ChatMessage
pipe = Pipeline()
pipe.add_component(
"prompt_builder",
ChatPromptBuilder(template=[ChatMessage.from_user("Tell me about {{topic}}")]),
)
pipe.add_component("llm", OpenAIChatGenerator())
pipe.connect("prompt_builder.prompt", "llm.messages")
async def main():
handle = pipe.stream(data={"prompt_builder": {"topic": "Italy"}})
async for chunk in handle:
print(chunk.content, end="", flush=True)
return handle.result
result = asyncio.run(main())
print(result["llm"]["replies"])
```
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) A dictionary of inputs for the pipeline's components. Each key is a component name
and its value is a dictionary of that component's input parameters:
```
data = {
"comp1": {"input1": 1, "input2": 2},
}
```
For convenience, this format is also supported when input names are unique:
```
data = {
"input1": 1, "input2": 2,
}
```
- **streaming_components** (<code>list\[str\] | None</code>) Names of components to stream from. If `None` (default), every streaming-capable
component is forwarded. If a list, only the listed components are forwarded; unknown names or names of
components that do not support streaming raise `ValueError`.
- **include_outputs_from** (<code>set\[str\] | None</code>) Set of component names whose individual outputs are to be
included in the pipeline's output. For components that are
invoked multiple times (in a loop), only the last-produced
output is included.
- **concurrency_limit** (<code>int</code>) The maximum number of components that should be allowed to run concurrently.
- **cancel_on_abandon** (<code>bool</code>) If `True` (default), the underlying pipeline task is cancelled when iteration is
abandoned. If `False`, the pipeline runs to completion even when the consumer stops reading.
**Returns:**
- <code>PipelineStreamHandle</code> A `PipelineStreamHandle` that is async-iterable over `StreamingChunk`s. After iteration ends,
`handle.result` holds the final pipeline output dict (same shape as `run_async`).
**Raises:**
- <code>ValueError</code> If `streaming_components` contains unknown component names or components that do not support streaming,
or if invalid inputs are provided to the pipeline, or if `concurrency_limit` is less than 1.
- <code>PipelineRuntimeError</code> Surfaced during iteration. If the Pipeline contains cycles with unsupported connections that would cause
it to get stuck and fail running, or if a Component fails or returns output in an unsupported type.
- <code>PipelineMaxComponentRuns</code> Surfaced during iteration. If a Component reaches the maximum number of times it can be run in this
Pipeline.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,183 @@
---
title: "Query"
id: query-api
description: "Components for query processing and expansion."
slug: "/query-api"
---
## query_expander
### QueryExpander
A component that returns a list of semantically similar queries to improve retrieval recall in RAG systems.
The component uses a chat generator to expand queries. The chat generator is expected to return a JSON response
with the following structure:
```json
{"queries": ["expanded query 1", "expanded query 2", "expanded query 3"]}
```
### Usage example
```python
from haystack.components.generators.chat.openai import OpenAIChatGenerator
from haystack.components.query import QueryExpander
expander = QueryExpander(
chat_generator=OpenAIChatGenerator(model="gpt-4.1-mini"),
n_expansions=3
)
result = expander.run(query="green energy sources")
print(result["queries"])
# Output: ['alternative query 1', 'alternative query 2', 'alternative query 3', 'green energy sources']
# Note: Up to 3 additional queries + 1 original query (if include_original_query=True)
# To control total number of queries:
expander = QueryExpander(n_expansions=2, include_original_query=True) # Up to 3 total
# or
expander = QueryExpander(n_expansions=3, include_original_query=False) # Exactly 3 total
```
#### __init__
```python
__init__(
*,
chat_generator: ChatGenerator | None = None,
prompt_template: str | None = None,
n_expansions: int = 4,
include_original_query: bool = True
) -> None
```
Initialize the QueryExpander component.
**Parameters:**
- **chat_generator** (<code>ChatGenerator | None</code>) The chat generator component to use for query expansion.
If None, a default OpenAIChatGenerator with gpt-4.1-mini model is used.
- **prompt_template** (<code>str | None</code>) Custom [PromptBuilder](https://docs.haystack.deepset.ai/docs/promptbuilder)
template for query expansion. The template should instruct the LLM to return a JSON response with the
structure: `{"queries": ["query1", "query2", "query3"]}`. The template should include 'query' and
'n_expansions' variables.
- **n_expansions** (<code>int</code>) Number of alternative queries to generate (default: 4).
- **include_original_query** (<code>bool</code>) Whether to include the original query in the output.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> QueryExpander
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Dictionary with serialized data.
**Returns:**
- <code>QueryExpander</code> Deserialized component.
#### run
```python
run(query: str, n_expansions: int | None = None) -> dict[str, list[str]]
```
Expand the input query into multiple semantically similar queries.
The language of the original query is preserved in the expanded queries.
**Parameters:**
- **query** (<code>str</code>) The original query to expand.
- **n_expansions** (<code>int | None</code>) Number of additional queries to generate (not including the original).
If None, uses the value from initialization. Must be a positive integer.
**Returns:**
- <code>dict\[str, list\[str\]\]</code> Dictionary with "queries" key containing the list of expanded queries.
If include_original_query=True, the original query will be included in addition
to the n_expansions alternative queries.
**Raises:**
- <code>ValueError</code> If n_expansions is not positive (less than or equal to 0).
#### run_async
```python
run_async(query: str, n_expansions: int | None = None) -> dict[str, list[str]]
```
Asynchronously expand the input query into multiple semantically similar queries.
The language of the original query is preserved in the expanded queries.
This is the asynchronous version of the `run` method. It has the same parameters and return values
but can be used with `await` in an async code. If the chat generator only implements a synchronous
`run` method, it is executed in a thread to avoid blocking the event loop.
**Parameters:**
- **query** (<code>str</code>) The original query to expand.
- **n_expansions** (<code>int | None</code>) Number of additional queries to generate (not including the original).
If None, uses the value from initialization. Must be a positive integer.
**Returns:**
- <code>dict\[str, list\[str\]\]</code> Dictionary with "queries" key containing the list of expanded queries.
If include_original_query=True, the original query will be included in addition
to the n_expansions alternative queries.
**Raises:**
- <code>ValueError</code> If n_expansions is not positive (less than or equal to 0).
#### warm_up
```python
warm_up() -> None
```
Warm up the underlying chat generator.
#### warm_up_async
```python
warm_up_async() -> None
```
Warm up the underlying chat generator on the serving event loop.
#### close
```python
close() -> None
```
Release the underlying chat generator's resources.
#### close_async
```python
close_async() -> None
```
Release the underlying chat generator's async resources.
@@ -0,0 +1,514 @@
---
title: "Rankers"
id: rankers-api
description: "Reorders a set of Documents based on their relevance to the query."
slug: "/rankers-api"
---
## llm_ranker
### LLMRanker
Ranks documents for a query using a Large Language Model.
The LLM is expected to return a JSON object containing ranked document indices.
Usage example:
```python
from haystack import Document
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.rankers import LLMRanker
chat_generator = OpenAIChatGenerator(
model="gpt-4.1-mini",
generation_kwargs={
"temperature": 0.0,
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "document_ranking",
"schema": {
"type": "object",
"properties": {
"documents": {
"type": "array",
"items": {
"type": "object",
"properties": {"index": {"type": "integer"}},
"required": ["index"],
"additionalProperties": False,
},
}
},
"required": ["documents"],
"additionalProperties": False,
},
},
},
},
)
ranker = LLMRanker(chat_generator=chat_generator)
documents = [
Document(id="paris", content="Paris is the capital of France."),
Document(id="berlin", content="Berlin is the capital of Germany."),
]
result = ranker.run(query="capital of Germany", documents=documents)
print(result["documents"][0].id)
```
#### __init__
```python
__init__(
*,
chat_generator: ChatGenerator | None = None,
prompt: str = DEFAULT_PROMPT_TEMPLATE,
top_k: int = 10,
raise_on_failure: bool = False
) -> None
```
Initialize the LLMRanker component.
**Parameters:**
- **chat_generator** (<code>ChatGenerator | None</code>) The chat generator to use for reranking. If `None`, a default `OpenAIChatGenerator` configured for JSON
output is used.
- **prompt** (<code>str</code>) Custom prompt template for reranking. The prompt must include exactly the variables `query` and
`documents` and instruct the LLM to return ranked 1-based document indices as JSON.
- **top_k** (<code>int</code>) The maximum number of documents to return.
- **raise_on_failure** (<code>bool</code>) If `True`, raise when generation or response parsing fails. If `False`, log the failure and return the
input documents in fallback order.
#### warm_up
```python
warm_up() -> None
```
Warm up the underlying chat generator.
#### warm_up_async
```python
warm_up_async() -> None
```
Warm up the underlying chat generator on the serving event loop.
#### close
```python
close() -> None
```
Release the underlying chat generator's resources.
#### close_async
```python
close_async() -> None
```
Release the underlying chat generator's async resources.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize this component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> LLMRanker
```
Deserialize this component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) The dictionary representation of the component.
**Returns:**
- <code>LLMRanker</code> The deserialized component instance.
#### run
```python
run(
query: str, documents: list[Document], top_k: int | None = None
) -> dict[str, list[Document]]
```
Rank documents for a query using an LLM.
Before ranking, duplicate documents are removed.
**Parameters:**
- **query** (<code>str</code>) The query used for reranking.
- **documents** (<code>list\[Document\]</code>) Candidate documents to rerank.
- **top_k** (<code>int | None</code>) The maximum number of documents to return. Overrides the instance's `top_k` if provided.
**Returns:**
- <code>dict\[str, list\[Document\]\]</code> A dictionary with the ranked documents under the `documents` key.
#### run_async
```python
run_async(
query: str, documents: list[Document], top_k: int | None = None
) -> dict[str, list[Document]]
```
Asynchronously rank documents for a query using an LLM.
Before ranking, duplicate documents are removed.
This is the asynchronous version of the `run` method. It has the same parameters and return values
but can be used with `await` in an async code. If the chat generator only implements a synchronous
`run` method, it is executed in a thread to avoid blocking the event loop.
**Parameters:**
- **query** (<code>str</code>) The query used for reranking.
- **documents** (<code>list\[Document\]</code>) Candidate documents to rerank.
- **top_k** (<code>int | None</code>) The maximum number of documents to return. Overrides the instance's `top_k` if provided.
**Returns:**
- <code>dict\[str, list\[Document\]\]</code> A dictionary with the ranked documents under the `documents` key.
## lost_in_the_middle
### LostInTheMiddleRanker
A LostInTheMiddle Ranker.
Ranks documents based on the 'lost in the middle' order so that the most relevant documents are either at the
beginning or end, while the least relevant are in the middle.
LostInTheMiddleRanker assumes that some prior component in the pipeline has already ranked documents by relevance
and requires no query as input but only documents. It is typically used as the last component before building a
prompt for an LLM to prepare the input context for the LLM.
Lost in the Middle ranking lays out document contents into LLM context so that the most relevant contents are at
the beginning or end of the input context, while the least relevant is in the middle of the context. See the
paper ["Lost in the Middle: How Language Models Use Long Contexts"](https://arxiv.org/abs/2307.03172) for more
details.
Usage example:
```python
from haystack.components.rankers import LostInTheMiddleRanker
from haystack import Document
ranker = LostInTheMiddleRanker()
docs = [Document(content="Paris"), Document(content="Berlin"), Document(content="Madrid")]
result = ranker.run(documents=docs)
for doc in result["documents"]:
print(doc.content)
```
#### __init__
```python
__init__(
word_count_threshold: int | None = None, top_k: int | None = None
) -> None
```
Initialize the LostInTheMiddleRanker.
If 'word_count_threshold' is specified, this ranker includes all documents up until the point where adding
another document would exceed the 'word_count_threshold'. The last document that causes the threshold to
be breached will be included in the resulting list of documents, but all subsequent documents will be
discarded.
**Parameters:**
- **word_count_threshold** (<code>int | None</code>) The maximum total number of words across all documents selected by the ranker.
- **top_k** (<code>int | None</code>) The maximum number of documents to return.
#### run
```python
run(
documents: list[Document],
top_k: int | None = None,
word_count_threshold: int | None = None,
) -> dict[str, list[Document]]
```
Reranks documents based on the "lost in the middle" order.
Before ranking, documents are deduplicated by their id, retaining only the document with the highest score
if a score is present.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) List of Documents to reorder.
- **top_k** (<code>int | None</code>) The maximum number of documents to return.
- **word_count_threshold** (<code>int | None</code>) The maximum total number of words across all documents selected by the ranker.
**Returns:**
- <code>dict\[str, list\[Document\]\]</code> A dictionary with the following keys:
- `documents`: Reranked list of Documents
**Raises:**
- <code>ValueError</code> If any of the documents is not textual.
## meta_field
### MetaFieldRanker
Ranks Documents based on the value of their specific meta field.
The ranking can be performed in descending order or ascending order.
Usage example:
```python
from haystack import Document
from haystack.components.rankers import MetaFieldRanker
ranker = MetaFieldRanker(meta_field="rating")
docs = [
Document(content="Paris", meta={"rating": 1.3}),
Document(content="Berlin", meta={"rating": 0.7}),
Document(content="Barcelona", meta={"rating": 2.1}),
]
output = ranker.run(documents=docs)
docs = output["documents"]
assert docs[0].content == "Barcelona"
```
#### __init__
```python
__init__(
meta_field: str,
weight: float = 1.0,
top_k: int | None = None,
ranking_mode: Literal[
"reciprocal_rank_fusion", "linear_score"
] = "reciprocal_rank_fusion",
sort_order: Literal["ascending", "descending"] = "descending",
missing_meta: Literal["drop", "top", "bottom"] = "bottom",
meta_value_type: Literal["float", "int", "date"] | None = None,
) -> None
```
Creates an instance of MetaFieldRanker.
**Parameters:**
- **meta_field** (<code>str</code>) The name of the meta field to rank by.
- **weight** (<code>float</code>) In range [0,1].
0 disables ranking by a meta field.
0.5 ranking from previous component and based on meta field have the same weight.
1 ranking by a meta field only.
- **top_k** (<code>int | None</code>) The maximum number of Documents to return per query.
If not provided, the Ranker returns all documents it receives in the new ranking order.
- **ranking_mode** (<code>Literal['reciprocal_rank_fusion', 'linear_score']</code>) The mode used to combine the Retriever's and Ranker's scores.
Possible values are 'reciprocal_rank_fusion' (default) and 'linear_score'.
Use the 'linear_score' mode only with Retrievers or Rankers that return a score in range [0,1].
- **sort_order** (<code>Literal['ascending', 'descending']</code>) Whether to sort the meta field by ascending or descending order.
Possible values are `descending` (default) and `ascending`.
- **missing_meta** (<code>Literal['drop', 'top', 'bottom']</code>) What to do with documents that are missing the sorting metadata field.
Possible values are:
- 'drop' will drop the documents entirely.
- 'top' will place the documents at the top of the metadata-sorted list
(regardless of 'ascending' or 'descending').
- 'bottom' will place the documents at the bottom of metadata-sorted list
(regardless of 'ascending' or 'descending').
- **meta_value_type** (<code>Literal['float', 'int', 'date'] | None</code>) Parse the meta value into the data type specified before sorting.
This will only work if all meta values stored under `meta_field` in the provided documents are strings.
For example, if we specified `meta_value_type="date"` then for the meta value `"date": "2015-02-01"`
we would parse the string into a datetime object and then sort the documents by date.
The available options are:
- 'float' will parse the meta values into floats.
- 'int' will parse the meta values into integers.
- 'date' will parse the meta values into datetime objects.
- 'None' (default) will do no parsing.
#### run
```python
run(
documents: list[Document],
top_k: int | None = None,
weight: float | None = None,
ranking_mode: (
Literal["reciprocal_rank_fusion", "linear_score"] | None
) = None,
sort_order: Literal["ascending", "descending"] | None = None,
missing_meta: Literal["drop", "top", "bottom"] | None = None,
meta_value_type: Literal["float", "int", "date"] | None = None,
) -> dict[str, Any]
```
Ranks a list of Documents based on the selected meta field by:
1. Sorting the Documents by the meta field in descending or ascending order.
1. Merging the rankings from the previous component and based on the meta field according to ranking mode and
weight.
1. Returning the top-k documents.
Before ranking, documents are deduplicated by their id, retaining only the document with the highest score
if a score is present.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) Documents to be ranked.
- **top_k** (<code>int | None</code>) The maximum number of Documents to return per query.
If not provided, the top_k provided at initialization time is used.
- **weight** (<code>float | None</code>) In range [0,1].
0 disables ranking by a meta field.
0.5 ranking from previous component and based on meta field have the same weight.
1 ranking by a meta field only.
If not provided, the weight provided at initialization time is used.
- **ranking_mode** (<code>Literal['reciprocal_rank_fusion', 'linear_score'] | None</code>) (optional) The mode used to combine the Retriever's and Ranker's scores.
Possible values are 'reciprocal_rank_fusion' (default) and 'linear_score'.
Use the 'score' mode only with Retrievers or Rankers that return a score in range [0,1].
If not provided, the ranking_mode provided at initialization time is used.
- **sort_order** (<code>Literal['ascending', 'descending'] | None</code>) Whether to sort the meta field by ascending or descending order.
Possible values are `descending` (default) and `ascending`.
If not provided, the sort_order provided at initialization time is used.
- **missing_meta** (<code>Literal['drop', 'top', 'bottom'] | None</code>) What to do with documents that are missing the sorting metadata field.
Possible values are:
- 'drop' will drop the documents entirely.
- 'top' will place the documents at the top of the metadata-sorted list
(regardless of 'ascending' or 'descending').
- 'bottom' will place the documents at the bottom of metadata-sorted list
(regardless of 'ascending' or 'descending').
If not provided, the missing_meta provided at initialization time is used.
- **meta_value_type** (<code>Literal['float', 'int', 'date'] | None</code>) Parse the meta value into the data type specified before sorting.
This will only work if all meta values stored under `meta_field` in the provided documents are strings.
For example, if we specified `meta_value_type="date"` then for the meta value `"date": "2015-02-01"`
we would parse the string into a datetime object and then sort the documents by date.
The available options are:
-'float' will parse the meta values into floats.
-'int' will parse the meta values into integers.
-'date' will parse the meta values into datetime objects.
-'None' (default) will do no parsing.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following keys:
- `documents`: List of Documents sorted by the specified meta field.
**Raises:**
- <code>ValueError</code> If `top_k` is not > 0.
If `weight` is not in range [0,1].
If `ranking_mode` is not 'reciprocal_rank_fusion' or 'linear_score'.
If `sort_order` is not 'ascending' or 'descending'.
If `meta_value_type` is not 'float', 'int', 'date' or `None`.
## meta_field_grouping_ranker
### MetaFieldGroupingRanker
Reorders the documents by grouping them based on metadata keys.
The MetaFieldGroupingRanker can group documents by a primary metadata key `group_by`, and subgroup them with an optional
secondary key, `subgroup_by`.
Within each group or subgroup, it can also sort documents by a metadata key `sort_docs_by`.
The output is a flat list of documents ordered by `group_by` and `subgroup_by` values.
Any documents without a group are placed at the end of the list.
The proper organization of documents helps improve the efficiency and performance of subsequent processing by an LLM.
### Usage example
```python
from haystack.components.rankers import MetaFieldGroupingRanker
from haystack.dataclasses import Document
docs = [
Document(content="Javascript is a popular programming language", meta={"group": "42", "split_id": 7, "subgroup": "subB"}),
Document(content="Python is a popular programming language",meta={"group": "42", "split_id": 4, "subgroup": "subB"}),
Document(content="A chromosome is a package of DNA", meta={"group": "314", "split_id": 2, "subgroup": "subC"}),
Document(content="An octopus has three hearts", meta={"group": "11", "split_id": 2, "subgroup": "subD"}),
Document(content="Java is a popular programming language", meta={"group": "42", "split_id": 3, "subgroup": "subB"})
]
ranker = MetaFieldGroupingRanker(group_by="group",subgroup_by="subgroup", sort_docs_by="split_id")
result = ranker.run(documents=docs)
print(result["documents"])
# >>
# >> Document(id=d665bbc83e52c08c3d8275bccf4f22bf2bfee21c6e77d78794627637355b8ebc,
# >> content: 'Java is a popular programming language', meta: {'group': '42', 'split_id': 3, 'subgroup': 'subB'}),
# >> Document(id=a20b326f07382b3cbf2ce156092f7c93e8788df5d48f2986957dce2adb5fe3c2,
# >> content: 'Python is a popular programming language', meta: {'group': '42', 'split_id': 4, 'subgroup': 'subB'}),
# >> Document(id=ce12919795d22f6ca214d0f161cf870993889dcb146f3bb1b3e1ffdc95be960f,
# >> content: 'Javascript is a popular programming language', meta: {'group': '42', 'split_id': 7, 'subgroup': 'subB'}),
# >> Document(id=d9fc857046c904e5cf790b3969b971b1bbdb1b3037d50a20728fdbf82991aa94,
# >> content: 'A chromosome is a package of DNA', meta: {'group': '314', 'split_id': 2, 'subgroup': 'subC'}),
# >> Document(id=6d3b7bdc13d09aa01216471eb5fb0bfdc53c5f2f3e98ad125ff6b85d3106c9a3,
# >> content: 'An octopus has three hearts', meta: {'group': '11', 'split_id': 2, 'subgroup': 'subD'})
```
#### __init__
```python
__init__(
group_by: str,
subgroup_by: str | None = None,
sort_docs_by: str | None = None,
) -> None
```
Creates an instance of MetaFieldGroupingRanker.
**Parameters:**
- **group_by** (<code>[str</code>) The metadata key to aggregate the documents by.
- **subgroup_by** (<code>str | None</code>) The metadata key to aggregate the documents within a group that was created by the
`group_by` key.
- **sort_docs_by** (<code>str | None</code>) Determines which metadata key is used to sort the documents. If not provided, the
documents within the groups or subgroups are not sorted and are kept in the same order as
they were inserted in the subgroups.
#### run
```python
run(documents: list[Document]) -> dict[str, list[Document]]
```
Groups the provided list of documents based on the `group_by` parameter and optionally the `subgroup_by`.
Before grouping, documents are deduplicated by their id, retaining only the document with the highest score
if a score is present.
The output is a list of documents reordered based on how they were grouped.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) The list of documents to group.
**Returns:**
- <code>dict\[str, list\[Document\]\]</code> A dictionary with the following keys:
- documents: The list of documents ordered by the `group_by` and `subgroup_by` metadata values.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,908 @@
---
title: "Routers"
id: routers-api
description: "Routers is a group of components that route queries or Documents to other components that can handle them best."
slug: "/routers-api"
---
## conditional_router
### NoRouteSelectedException
Bases: <code>Exception</code>
Exception raised when no route is selected in ConditionalRouter.
### RouteConditionException
Bases: <code>Exception</code>
Exception raised when there is an error parsing or evaluating the condition expression in ConditionalRouter.
### ConditionalRouter
Routes data based on specific conditions.
You define these conditions in a list of dictionaries called `routes`.
Each dictionary in this list represents a single route. Each route has these four elements:
- `condition`: A Jinja2 string expression that determines if the route is selected.
- `output`: A Jinja2 expression defining the route's output value.
- `output_type`: The type of the output data (for example, `str`, `list[int]`).
- `output_name`: The name you want to use to publish `output`. This name is used to connect
the router to other components in the pipeline.
An optional field `output_passthrough` can be set to `True` to treat `output` as a variable name
instead of a Jinja2 template, passing the variable value directly. This is useful for routing
complex non-basic types (dataclasses, Pydantic models, etc.) without Jinja2 processing.
### Usage example
```python
from haystack.components.routers import ConditionalRouter
routes = [
{
"condition": "{{streams|length > 2}}",
"output": "{{streams}}",
"output_name": "enough_streams",
"output_type": list[int],
},
{
"condition": "{{streams|length <= 2}}",
"output": "{{streams}}",
"output_name": "insufficient_streams",
"output_type": list[int],
},
]
router = ConditionalRouter(routes)
# When 'streams' has more than 2 items, 'enough_streams' output will activate, emitting the list [1, 2, 3]
kwargs = {"streams": [1, 2, 3], "query": "Haystack"}
result = router.run(**kwargs)
assert result == {"enough_streams": [1, 2, 3]}
```
In this example, we configure two routes. The first route sends the 'streams' value to 'enough_streams' if the
stream count exceeds two. The second route directs 'streams' to 'insufficient_streams' if there
are two or fewer streams.
In the pipeline setup, the Router connects to other components using the output names. For example,
'enough_streams' might connect to a component that processes streams, while
'insufficient_streams' might connect to a component that fetches more streams.
Here is a pipeline that uses `ConditionalRouter` and routes the fetched `ByteStreams` to
different components depending on the number of streams fetched:
```python
from haystack import Pipeline
from haystack.dataclasses import ByteStream
from haystack.components.routers import ConditionalRouter
routes = [
{"condition": "{{count > 5}}",
"output": "Processing many items",
"output_name": "many_items",
"output_type": str,
},
{"condition": "{{count <= 5}}",
"output": "Processing few items",
"output_name": "few_items",
"output_type": str,
},
]
pipe = Pipeline()
pipe.add_component("router", ConditionalRouter(routes))
# Run with count > 5
result = pipe.run({"router": {"count": 10}})
print(result)
# >> {'router': {'many_items': 'Processing many items'}}
# Run with count <= 5
result = pipe.run({"router": {"count": 3}})
print(result)
# >> {'router': {'few_items': 'Processing few items'}}
```
### Passthrough routing for non-basic types
Without `output_passthrough`, the router renders `output` as a Jinja2 template, which converts
the value to its string representation. Custom types cannot survive that round-trip:
```python
# Without output_passthrough — the object is silently converted to a string
routes = [
{
"condition": "{{True}}",
"output": "{{query}}",
"output_name": "out",
"output_type": ParsedQuery,
}
]
router = ConditionalRouter(routes)
result = router.run(query=ParsedQuery(text="hello", intent="search", entities=[]))
# result["out"] == "ParsedQuery(text='hello', intent='search', entities=[])"
# ^^^ str, not ParsedQuery — the object was destroyed
```
Set `output_passthrough: True` to skip Jinja2 entirely and pass the value directly from kwargs:
```python
from haystack.components.routers import ConditionalRouter
from dataclasses import dataclass, field
@dataclass
class ParsedQuery:
text: str
intent: str # "search" | "chat"
entities: list[str] = field(default_factory=list)
routes = [
{
"condition": "{{query.intent == 'search'}}",
"output": "query", # variable name, not a Jinja2 template
"output_name": "search_query",
"output_type": ParsedQuery,
"output_passthrough": True,
},
{
"condition": "{{query.intent == 'chat'}}",
"output": "query",
"output_name": "chat_query",
"output_type": ParsedQuery,
"output_passthrough": True,
},
]
router = ConditionalRouter(routes)
query = ParsedQuery(text="What is Haystack?", intent="search", entities=["Haystack"])
result = router.run(query=query)
assert isinstance(result["search_query"], ParsedQuery) # type preserved
assert result["search_query"] is query # same object, no copying
```
#### __init__
```python
__init__(
routes: list[Route],
custom_filters: dict[str, Callable] | None = None,
unsafe: bool = False,
validate_output_type: bool = False,
optional_variables: list[str] | None = None,
) -> None
```
Initializes the `ConditionalRouter` with a list of routes detailing the conditions for routing.
**Parameters:**
- **routes** (<code>list\[Route\]</code>) A list of dictionaries, each defining a route.
Each route has these four elements:
- `condition`: A Jinja2 string expression that determines if the route is selected.
- `output`: A Jinja2 expression defining the route's output value, or a plain variable name
if `output_passthrough` is `True`.
- `output_type`: The type of the output data (for example, `str`, `list[int]`).
- `output_name`: The name you want to use to publish `output`. This name is used to connect
the router to other components in the pipeline.
- `output_passthrough` (optional): If `True`, treats `output` as a plain variable name and
passes the value directly from the input kwargs, skipping all Jinja2 processing. Useful
for routing complex non-basic types without template transformation.
Note: if the variable named in `output` is also listed in `optional_variables`, a missing
value at runtime will route `None` downstream rather than raising a `ValueError`.
- **custom_filters** (<code>dict\[str, Callable\] | None</code>) A dictionary of custom Jinja2 filters used in the condition expressions.
For example, passing `{"my_filter": my_filter_fcn}` where:
- `my_filter` is the name of the custom filter.
- `my_filter_fcn` is a callable that takes `my_var:str` and returns `my_var[:3]`.
`{{ my_var|my_filter }}` can then be used inside a route condition expression:
`"condition": "{{ my_var|my_filter == 'foo' }}"`.
- **unsafe** (<code>bool</code>) Enable execution of arbitrary code in the Jinja template.
This should only be used if you trust the source of the template as it can be lead to remote code execution.
- **validate_output_type** (<code>bool</code>) Enable validation of routes' output.
If a route output doesn't match the declared type a ValueError is raised running.
- **optional_variables** (<code>list\[str\] | None</code>) A list of variable names that are optional in your route conditions and outputs.
If these variables are not provided at runtime, they will be set to `None`.
This allows you to write routes that can handle missing inputs gracefully without raising errors.
Example usage with a default fallback route in a Pipeline:
```python
from haystack import Pipeline
from haystack.components.routers import ConditionalRouter
routes = [
{
"condition": '{{ path == "rag" }}',
"output": "{{ question }}",
"output_name": "rag_route",
"output_type": str
},
{
"condition": "{{ True }}", # fallback route
"output": "{{ question }}",
"output_name": "default_route",
"output_type": str
}
]
router = ConditionalRouter(routes, optional_variables=["path"])
pipe = Pipeline()
pipe.add_component("router", router)
# When 'path' is provided in the pipeline:
result = pipe.run(data={"router": {"question": "What?", "path": "rag"}})
assert result["router"] == {"rag_route": "What?"}
# When 'path' is not provided, fallback route is taken:
result = pipe.run(data={"router": {"question": "What?"}})
assert result["router"] == {"default_route": "What?"}
```
This pattern is particularly useful when:
- You want to provide default/fallback behavior when certain inputs are missing
- Some variables are only needed for specific routing conditions
- You're building flexible pipelines where not all inputs are guaranteed to be present
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> ConditionalRouter
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) The dictionary to deserialize from.
**Returns:**
- <code>ConditionalRouter</code> The deserialized component.
#### run
```python
run(**kwargs: Any) -> dict[str, Any]
```
Executes the routing logic.
Executes the routing logic by evaluating the specified boolean condition expressions for each route in the
order they are listed. The method directs the flow of data to the output specified in the first route whose
`condition` is True.
**Parameters:**
- **kwargs** (<code>Any</code>) All variables used in the `condition` expressed in the routes. When the component is used in a
pipeline, these variables are passed from the previous component's output.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary where the key is the `output_name` of the selected route and the value is the `output`
of the selected route.
**Raises:**
- <code>NoRouteSelectedException</code> If no `condition' in the routes is `True\`.
- <code>RouteConditionException</code> If there is an error parsing or evaluating the `condition` expression in the routes.
- <code>ValueError</code> If type validation is enabled and the route output doesn't match the declared type, or if
`output_passthrough` is `True` and the variable named in `output` is not found in kwargs.
## document_length_router
### DocumentLengthRouter
Categorizes documents based on the length of the `content` field and routes them to the appropriate output.
A common use case for DocumentLengthRouter is handling documents obtained from PDFs that contain non-text
content, such as scanned pages or images. This component can detect empty or low-content documents and route them to
components that perform OCR, generate captions, or compute image embeddings.
### Usage example
```python
from haystack.components.routers import DocumentLengthRouter
from haystack.dataclasses import Document
docs = [
Document(content="Short"),
Document(content="Long document "*20),
]
router = DocumentLengthRouter(threshold=10)
result = router.run(documents=docs)
print(result)
# {
# "short_documents": [Document(content="Short", ...)],
# "long_documents": [Document(content="Long document ...", ...)],
# }
```
#### __init__
```python
__init__(*, threshold: int = 10) -> None
```
Initialize the DocumentLengthRouter component.
**Parameters:**
- **threshold** (<code>int</code>) The threshold for the number of characters in the document `content` field. Documents where `content` is
None or whose character count is less than or equal to the threshold will be routed to the `short_documents`
output. Otherwise, they will be routed to the `long_documents` output.
To route only documents with None content to `short_documents`, set the threshold to a negative number.
#### run
```python
run(documents: list[Document]) -> dict[str, list[Document]]
```
Categorize input documents into groups based on the length of the `content` field.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) A list of documents to be categorized.
**Returns:**
- <code>dict\[str, list\[Document\]\]</code> A dictionary with the following keys:
- `short_documents`: A list of documents where `content` is None or the length of `content` is less than or
equal to the threshold.
- `long_documents`: A list of documents where the length of `content` is greater than the threshold.
## document_type_router
### DocumentTypeRouter
Routes documents by their MIME types.
DocumentTypeRouter is used to dynamically route documents within a pipeline based on their MIME types.
It supports exact MIME type matches and regex patterns.
MIME types can be extracted directly from document metadata or inferred from file paths using standard or
user-supplied MIME type mappings.
### Usage example
```python
from haystack.components.routers import DocumentTypeRouter
from haystack.dataclasses import Document
docs = [
Document(content="Example text", meta={"file_path": "example.txt"}),
Document(content="Another document", meta={"mime_type": "application/pdf"}),
Document(content="Unknown type")
]
router = DocumentTypeRouter(
mime_type_meta_field="mime_type",
file_path_meta_field="file_path",
mime_types=["text/plain", "application/pdf"]
)
result = router.run(documents=docs)
print(result)
```
Expected output:
```python
{
"text/plain": [Document(...)],
"application/pdf": [Document(...)],
"unclassified": [Document(...)]
}
```
#### __init__
```python
__init__(
*,
mime_types: list[str],
mime_type_meta_field: str | None = None,
file_path_meta_field: str | None = None,
additional_mimetypes: dict[str, str] | None = None
) -> None
```
Initialize the DocumentTypeRouter component.
**Parameters:**
- **mime_types** (<code>list\[str\]</code>) A list of MIME types or regex patterns to classify the input documents.
(for example: `["text/plain", "audio/x-wav", "image/jpeg"]`).
- **mime_type_meta_field** (<code>str | None</code>) Optional name of the metadata field that holds the MIME type.
- **file_path_meta_field** (<code>str | None</code>) Optional name of the metadata field that holds the file path. Used to infer the MIME type if
`mime_type_meta_field` is not provided or missing in a document.
- **additional_mimetypes** (<code>dict\[str, str\] | None</code>) Optional dictionary mapping MIME types to file extensions to enhance or override the standard
`mimetypes` module. Useful when working with uncommon or custom file types.
For example: `{"application/vnd.custom-type": ".custom"}`.
**Raises:**
- <code>ValueError</code> If `mime_types` is empty or if both `mime_type_meta_field` and `file_path_meta_field` are
not provided.
#### run
```python
run(documents: list[Document]) -> dict[str, list[Document]]
```
Categorize input documents into groups based on their MIME type.
MIME types can either be directly available in document metadata or derived from file paths using the
standard Python `mimetypes` module and custom mappings.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) A list of documents to be categorized.
**Returns:**
- <code>dict\[str, list\[Document\]\]</code> A dictionary where the keys are MIME types (or `"unclassified"`) and the values are lists of documents.
## file_type_router
### FileTypeRouter
Categorizes files or byte streams by their MIME types, helping in context-based routing.
FileTypeRouter supports both exact MIME type matching and regex patterns.
For file paths, MIME types come from extensions; byte streams use metadata.
Each entry in `mime_types` is matched against a source's MIME type by exact equality first,
falling back to regex `fullmatch` if equality misses. So `"image/svg+xml"` routes
`image/svg+xml` streams correctly via the equality check (without `+` being interpreted as a
regex quantifier), and patterns like `"audio/.*"` keep matching every audio subtype.
### Usage example
```python
from haystack.components.routers import FileTypeRouter
from pathlib import Path
# Exact MIME matching — `+`-containing IANA types like image/svg+xml work correctly
router = FileTypeRouter(mime_types=["text/plain", "application/pdf", "image/svg+xml"])
# Regex matching — catch every audio subtype
router_with_regex = FileTypeRouter(mime_types=[r"audio/.*", r"text/plain"])
sources = [Path("file.txt"), Path("document.pdf"), Path("song.mp3")]
print(router.run(sources=sources))
print(router_with_regex.run(sources=sources))
# Expected output:
# {'text/plain': [
# PosixPath('file.txt')], 'application/pdf': [PosixPath('document.pdf')], 'unclassified': [PosixPath('song.mp3')
# ]}
# {'audio/.*': [
# PosixPath('song.mp3')], 'text/plain': [PosixPath('file.txt')], 'unclassified': [PosixPath('document.pdf')
# ]}
```
#### __init__
```python
__init__(
mime_types: list[str],
additional_mimetypes: dict[str, str] | None = None,
raise_on_failure: bool = False,
) -> None
```
Initialize the FileTypeRouter component.
**Parameters:**
- **mime_types** (<code>list\[str\]</code>) A list of MIME types or regex patterns to classify the input files or byte streams.
(for example: `["text/plain", "audio/x-wav", "image/jpeg"]`).
- **additional_mimetypes** (<code>dict\[str, str\] | None</code>) A dictionary containing the MIME type to add to the mimetypes package to prevent unsupported or non-native
packages from being unclassified.
(for example: `{"application/vnd.openxmlformats-officedocument.wordprocessingml.document": ".docx"}`).
- **raise_on_failure** (<code>bool</code>) If True, raises FileNotFoundError when a file path doesn't exist.
If False (default), only emits a warning when a file path doesn't exist.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serializes the component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary with serialized data.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> FileTypeRouter
```
Deserializes the component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) The dictionary to deserialize from.
**Returns:**
- <code>FileTypeRouter</code> The deserialized component.
#### run
```python
run(
sources: list[str | Path | ByteStream],
meta: dict[str, Any] | list[dict[str, Any]] | None = None,
) -> dict[str, list[ByteStream | Path]]
```
Categorize files or byte streams according to their MIME types.
**Parameters:**
- **sources** (<code>list\[str | Path | ByteStream\]</code>) A list of file paths or byte streams to categorize.
- **meta** (<code>dict\[str, Any\] | list\[dict\[str, Any\]\] | None</code>) Optional metadata to attach to the sources.
When provided, the sources are internally converted to ByteStream objects and the metadata is added.
This value can be a list of dictionaries or a single dictionary.
If it's a single dictionary, its content is added to the metadata of all ByteStream objects.
If it's a list, its length must match the number of sources, as they are zipped together.
**Returns:**
- <code>dict\[str, list\[ByteStream | Path\]\]</code> A dictionary where the keys are MIME types and the values are lists of data sources.
Two extra keys may be returned: `"unclassified"` when a source's MIME type doesn't match any pattern
and `"failed"` when a source cannot be processed (for example, a file path that doesn't exist).
**Raises:**
- <code>TypeError</code> If a source is not a Path, str, or ByteStream.
## llm_messages_router
### LLMMessagesRouter
Routes Chat Messages to different connections using a generative Language Model to perform classification.
This component can be used with general-purpose LLMs and with specialized LLMs for moderation like Llama Guard.
### Usage example
```python
from haystack.components.generators.chat import HuggingFaceAPIChatGenerator
from haystack.components.routers.llm_messages_router import LLMMessagesRouter
from haystack.dataclasses import ChatMessage
# initialize a Chat Generator with a generative model for moderation
chat_generator = HuggingFaceAPIChatGenerator(
api_type="serverless_inference_api",
api_params={"model": "openai/gpt-oss-safeguard-20b", "provider": "groq"},
)
router = LLMMessagesRouter(chat_generator=chat_generator,
output_names=["unsafe", "safe"],
output_patterns=["unsafe", "safe"])
print(router.run([ChatMessage.from_user("How to rob a bank?")]))
# {
# 'chat_generator_text': 'unsafe\nS2',
# 'unsafe': [
# ChatMessage(
# _role=<ChatRole.USER: 'user'>,
# _content=[TextContent(text='How to rob a bank?')],
# _name=None,
# _meta={}
# )
# ]
# }
```
#### __init__
```python
__init__(
chat_generator: ChatGenerator,
output_names: list[str],
output_patterns: list[str],
system_prompt: str | None = None,
) -> None
```
Initialize the LLMMessagesRouter component.
**Parameters:**
- **chat_generator** (<code>ChatGenerator</code>) A ChatGenerator instance which represents the LLM.
- **output_names** (<code>list\[str\]</code>) A list of output connection names. These can be used to connect the router to other
components.
- **output_patterns** (<code>list\[str\]</code>) A list of regular expressions to be matched against the output of the LLM. Each pattern
corresponds to an output name. Patterns are evaluated in order.
When using moderation models, refer to the model card to understand the expected outputs.
- **system_prompt** (<code>str | None</code>) An optional system prompt to customize the behavior of the LLM.
For moderation models, refer to the model card for supported customization options.
**Raises:**
- <code>ValueError</code> If output_names and output_patterns are not non-empty lists of the same length.
#### warm_up
```python
warm_up() -> None
```
Warm up the underlying chat generator.
#### warm_up_async
```python
warm_up_async() -> None
```
Warm up the underlying chat generator on the serving event loop.
#### close
```python
close() -> None
```
Release the underlying chat generator's resources.
#### close_async
```python
close_async() -> None
```
Release the underlying chat generator's async resources.
#### run
```python
run(messages: list[ChatMessage]) -> dict[str, str | list[ChatMessage]]
```
Classify the messages based on LLM output and route them to the appropriate output connection.
**Parameters:**
- **messages** (<code>list\[ChatMessage\]</code>) A list of ChatMessages to be routed. Only user and assistant messages are supported.
**Returns:**
- <code>dict\[str, str | list\[ChatMessage\]\]</code> A dictionary with the following keys:
- "chat_generator_text": The text output of the LLM, useful for debugging.
- "output_names": Each contains the list of messages that matched the corresponding pattern.
- "unmatched": The messages that did not match any of the output patterns.
**Raises:**
- <code>ValueError</code> If messages is an empty list or contains messages with unsupported roles.
#### run_async
```python
run_async(messages: list[ChatMessage]) -> dict[str, str | list[ChatMessage]]
```
Asynchronously classify the messages based on LLM output and route them to the appropriate output connection.
This is the asynchronous version of the `run` method. It has the same parameters and return values
but can be used with `await` in an async code. If the chat generator only implements a synchronous
`run` method, it is executed in a thread to avoid blocking the event loop.
**Parameters:**
- **messages** (<code>list\[ChatMessage\]</code>) A list of ChatMessages to be routed. Only user and assistant messages are supported.
**Returns:**
- <code>dict\[str, str | list\[ChatMessage\]\]</code> A dictionary with the following keys:
- "chat_generator_text": The text output of the LLM, useful for debugging.
- "output_names": Each contains the list of messages that matched the corresponding pattern.
- "unmatched": The messages that did not match any of the output patterns.
**Raises:**
- <code>ValueError</code> If messages is an empty list or contains messages with unsupported roles.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize this component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> The serialized component as a dictionary.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> LLMMessagesRouter
```
Deserialize this component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) The dictionary representation of this component.
**Returns:**
- <code>LLMMessagesRouter</code> The deserialized component instance.
## metadata_router
### MetadataRouter
Routes documents or byte streams to different connections based on their metadata fields.
Specify the routing rules in the `init` method.
If a document or byte stream does not match any of the rules, it's routed to a connection named "unmatched".
### Usage examples
**Routing Documents by metadata:**
```python
from haystack import Document
from haystack.components.routers import MetadataRouter
docs = [Document(content="Paris is the capital of France.", meta={"language": "en"}),
Document(content="Berlin ist die Haupststadt von Deutschland.", meta={"language": "de"})]
router = MetadataRouter(rules={"en": {"field": "meta.language", "operator": "==", "value": "en"}})
print(router.run(documents=docs))
# {'en': [Document(id=..., content: 'Paris is the capital of France.', meta: {'language': 'en'})],
# 'unmatched': [Document(id=..., content: 'Berlin ist die Haupststadt von Deutschland.', meta: {'language': 'de'})]}
```
**Routing ByteStreams by metadata:**
```python
from haystack.dataclasses import ByteStream
from haystack.components.routers import MetadataRouter
streams = [
ByteStream.from_string("Hello world", meta={"language": "en"}),
ByteStream.from_string("Bonjour le monde", meta={"language": "fr"})
]
router = MetadataRouter(
rules={"english": {"field": "meta.language", "operator": "==", "value": "en"}},
output_type=list[ByteStream]
)
result = router.run(documents=streams)
# {'english': [ByteStream(...)], 'unmatched': [ByteStream(...)]}
```
#### __init__
```python
__init__(rules: dict[str, dict], output_type: type = list[Document]) -> None
```
Initializes the MetadataRouter component.
**Parameters:**
- **rules** (<code>dict\[str, dict\]</code>) A dictionary defining how to route documents or byte streams to output connections based on their
metadata. Keys are output connection names, and values are dictionaries of
[filtering expressions](https://docs.haystack.deepset.ai/docs/metadata-filtering) in Haystack.
For example:
```python
{
"edge_1": {
"operator": "AND",
"conditions": [
{"field": "meta.created_at", "operator": ">=", "value": "2023-01-01"},
{"field": "meta.created_at", "operator": "<", "value": "2023-04-01"},
],
},
"edge_2": {
"operator": "AND",
"conditions": [
{"field": "meta.created_at", "operator": ">=", "value": "2023-04-01"},
{"field": "meta.created_at", "operator": "<", "value": "2023-07-01"},
],
},
"edge_3": {
"operator": "AND",
"conditions": [
{"field": "meta.created_at", "operator": ">=", "value": "2023-07-01"},
{"field": "meta.created_at", "operator": "<", "value": "2023-10-01"},
],
},
"edge_4": {
"operator": "AND",
"conditions": [
{"field": "meta.created_at", "operator": ">=", "value": "2023-10-01"},
{"field": "meta.created_at", "operator": "<", "value": "2024-01-01"},
],
},
}
```
:param output_type: The type of the output produced. Lists of Documents or ByteStreams can be specified.
#### run
```python
run(
documents: list[Document] | list[ByteStream],
) -> dict[str, list[Document] | list[ByteStream]]
```
Routes documents or byte streams to different connections based on their metadata fields.
If a document or byte stream does not match any of the rules, it's routed to a connection named "unmatched".
**Parameters:**
- **documents** (<code>list\[Document\] | list\[ByteStream\]</code>) A list of `Document` or `ByteStream` objects to be routed based on their metadata.
**Returns:**
- <code>dict\[str, list\[Document\] | list\[ByteStream\]\]</code> A dictionary where the keys are the names of the output connections (including `"unmatched"`)
and the values are lists of `Document` or `ByteStream` objects that matched the corresponding rules.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize this component to a dictionary.
**Returns:**
- <code>dict\[str, Any\]</code> The serialized component as a dictionary.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> MetadataRouter
```
Deserialize this component from a dictionary.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) The dictionary representation of this component.
**Returns:**
- <code>MetadataRouter</code> The deserialized component instance.
@@ -0,0 +1,81 @@
---
title: "Samplers"
id: samplers-api
description: "Filters documents based on their similarity scores using top-p sampling."
slug: "/samplers-api"
---
## top_p
### TopPSampler
Implements top-p (nucleus) sampling for document filtering based on cumulative probability scores.
This component provides functionality to filter a list of documents by selecting those whose scores fall
within the top 'p' percent of the cumulative distribution. It is useful for focusing on high-probability
documents while filtering out less relevant ones based on their assigned scores.
Usage example:
```python
from haystack import Document
from haystack.components.samplers import TopPSampler
sampler = TopPSampler(top_p=0.95, score_field="similarity_score")
docs = [
Document(content="Berlin", meta={"similarity_score": -10.6}),
Document(content="Belgrade", meta={"similarity_score": -8.9}),
Document(content="Sarajevo", meta={"similarity_score": -4.6}),
]
output = sampler.run(documents=docs)
docs = output["documents"]
assert len(docs) == 1
assert docs[0].content == "Sarajevo"
```
#### __init__
```python
__init__(
top_p: float = 1.0,
score_field: str | None = None,
min_top_k: int | None = None,
) -> None
```
Creates an instance of TopPSampler.
**Parameters:**
- **top_p** (<code>float</code>) Float between 0 and 1 representing the cumulative probability threshold for document selection.
A value of 1.0 indicates no filtering (all documents are retained).
- **score_field** (<code>str | None</code>) Name of the field in each document's metadata that contains the score. If None, the default
document score field is used.
- **min_top_k** (<code>int | None</code>) If specified, the minimum number of documents to return. If the top_p selects
fewer documents, additional ones with the next highest scores are added to the selection.
#### run
```python
run(documents: list[Document], top_p: float | None = None) -> dict[str, Any]
```
Filters documents using top-p sampling based on their scores.
If the specified top_p results in no documents being selected (especially in cases of a low top_p value), the
method returns the document with the highest score.
**Parameters:**
- **documents** (<code>list\[Document\]</code>) List of Document objects to be filtered.
- **top_p** (<code>float | None</code>) If specified, a float to override the cumulative probability threshold set during initialization.
**Returns:**
- <code>dict\[str, Any\]</code> A dictionary with the following key:
- `documents`: List of Document objects that have been selected based on the top-p sampling.
**Raises:**
- <code>ValueError</code> If the top_p value is not within the range [0, 1].
@@ -0,0 +1,254 @@
---
title: "Skill Stores"
id: skill-stores-api
description: "Storage layers that discover skills and serve their content on demand."
slug: "/skill-stores-api"
---
## file_system/skill_store
### FileSystemSkillStore
SkillStore backed by a directory of skill sub-directories on the local filesystem.
Expected layout:
```
skills/
pdf-forms/
SKILL.md # frontmatter (name, description) + markdown instructions
reference/forms.md # optional bundled file
```
The skill catalog is built by reading the frontmatter of each `SKILL.md` on `warm_up`; bodies and bundled files
are read lazily when the agent calls the corresponding tool.
#### __init__
```python
__init__(skills_dir: str | Path) -> None
```
Initialize the store with the root directory to scan.
No filesystem access happens here; the directory is scanned lazily on first use (see `warm_up`), so the store
can be constructed cheaply.
**Parameters:**
- **skills_dir** (<code>str | Path</code>) Root directory that contains one sub-directory per skill.
#### warm_up
```python
warm_up() -> None
```
Scan `skills_dir` and build the skill catalog by reading each skill's `SKILL.md` frontmatter.
Only the frontmatter is read here; bodies and bundled files are read lazily when the corresponding method is
called. Idempotent: repeated calls after the first are no-ops.
**Raises:**
- <code>ValueError</code> If `skills_dir` does not exist, is not a directory, a skill's frontmatter is missing,
malformed, or missing a required field, or two skills share the same name.
#### list_skills
```python
list_skills() -> dict[str, SkillInfo]
```
Return all skills discovered on disk, warming up the store first if needed.
**Returns:**
- <code>dict\[str, SkillInfo\]</code> Mapping of skill name to its metadata.
**Raises:**
- <code>ValueError</code> If the skills directory is invalid or a skill's frontmatter is malformed.
#### load_skill
```python
load_skill(name: str) -> tuple[str, list[str]]
```
Read the named skill's instruction body and the manifest of its bundled files.
**Parameters:**
- **name** (<code>str</code>) Skill name as returned by `list_skills`.
**Returns:**
- <code>tuple\[str, list\[str\]\]</code> A tuple of (markdown body of the skill's `SKILL.md` with frontmatter stripped, sorted list of
POSIX-style paths relative to the skill directory for any bundled files). The file list is empty when
the skill bundles no extras.
**Raises:**
- <code>KeyError</code> If no skill with `name` exists.
#### read_skill_file
```python
read_skill_file(name: str, path: str) -> str | ImageContent | FileContent
```
Read a file bundled with the named skill, preventing path traversal outside the skill directory.
The return type depends on the file: text files are returned as a `str`, image files (PNG, JPEG, ...) as an
`ImageContent`, and PDFs as a `FileContent`, so a multimodal agent can pass them straight to the model.
**Parameters:**
- **name** (<code>str</code>) Skill name as returned by `list_skills`.
- **path** (<code>str</code>) Path of the file relative to the skill directory (e.g. `"reference/forms.md"`).
**Returns:**
- <code>str | ImageContent | FileContent</code> The file's text content (`str`), an `ImageContent` for images, or a `FileContent` for PDFs.
**Raises:**
- <code>KeyError</code> If no skill with `name` exists.
- <code>PermissionError</code> If `path` resolves outside the skill's directory (path-traversal attempt). The
message lists the readable files so the caller can retry with a valid path.
- <code>FileNotFoundError</code> If the file does not exist within the skill. The message lists the readable
files so the caller can retry with a valid path.
- <code>ValueError</code> If the file is binary but not a supported image or PDF (i.e. not UTF-8 text either).
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize this store to a dictionary for use with `from_dict`.
**Returns:**
- <code>dict\[str, Any\]</code> Dictionary representation of the store.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> FileSystemSkillStore
```
Deserialize a `FileSystemSkillStore` from its dictionary representation.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Dictionary representation of the store, as produced by `to_dict`.
**Returns:**
- <code>FileSystemSkillStore</code> A new `FileSystemSkillStore` instance.
## types/protocol
### SkillStore
Bases: <code>Protocol</code>
Protocol for a skill storage layer.
A `SkillStore` is responsible for discovering available skills and providing their content on demand. Implement
this protocol to back a `haystack.tools.SkillToolset` with any storage system — a local directory, a database,
a remote API, or an in-memory fixture.
Skills are identified by their `name`, which must be unique within a store. The `name` is the lookup key for every
method below; implementations resolve it to their own internal locator (a directory, a row id, an object key, ...).
Implementations may defer all I/O (filesystem reads, database connections, ...) until a method is actually called,
so a store can be constructed cheaply and only touch its backend on first use.
Skill content is text: instruction bodies and bundled files are returned as strings. Binary assets (images,
fonts, ...) are not supported.
#### list_skills
```python
list_skills() -> dict[str, SkillInfo]
```
Discover and return all available skills.
**Returns:**
- <code>dict\[str, SkillInfo\]</code> Mapping of skill name to its metadata.
#### load_skill
```python
load_skill(name: str) -> tuple[str, list[str]]
```
Return the named skill's instruction body and the manifest of its bundled files.
**Parameters:**
- **name** (<code>str</code>) Skill name as returned by `list_skills`.
**Returns:**
- <code>tuple\[str, list\[str\]\]</code> A tuple of (markdown body with frontmatter stripped, sorted list of POSIX-style paths relative
to the skill root for any bundled files). The file list is empty when the skill bundles no extras.
**Raises:**
- <code>KeyError</code> If no skill with `name` exists.
#### read_skill_file
```python
read_skill_file(name: str, path: str) -> str | ImageContent | FileContent
```
Read a file bundled with the named skill.
Implementations should return text files as a `str`, image files as an `ImageContent`, and PDFs as a
`FileContent`, so a multimodal agent can pass binary assets straight to the model.
**Parameters:**
- **name** (<code>str</code>) Skill name as returned by `list_skills`.
- **path** (<code>str</code>) Path of the file relative to the skill root (e.g. `"reference/forms.md"`).
**Returns:**
- <code>str | ImageContent | FileContent</code> The file's text content (`str`), an `ImageContent` for images, or a `FileContent` for PDFs.
**Raises:**
- <code>KeyError</code> If no skill with `name` exists.
- <code>FileNotFoundError</code> If the file does not exist within the skill.
#### to_dict
```python
to_dict() -> dict[str, Any]
```
Serialize this store to a dictionary for use with `from_dict`.
Implement both this method and `from_dict` to make your custom store serializable.
#### from_dict
```python
from_dict(data: dict[str, Any]) -> SkillStore
```
Deserialize a store from a dictionary produced by `to_dict`.
Implement both this method and `to_dict` to make your custom store serializable.
**Parameters:**
- **data** (<code>dict\[str, Any\]</code>) Dictionary as produced by `to_dict`.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,135 @@
---
title: "Validators"
id: validators-api
description: "Validators validate LLM outputs"
slug: "/validators-api"
---
## json_schema
### is_valid_json
```python
is_valid_json(s: str) -> bool
```
Check if the provided string is a valid JSON.
**Parameters:**
- **s** (<code>str</code>) The string to be checked.
**Returns:**
- <code>bool</code> `True` if the string is a valid JSON; otherwise, `False`.
### JsonSchemaValidator
Validates JSON content of `ChatMessage` against a specified [JSON Schema](https://json-schema.org/).
If JSON content of a message conforms to the provided schema, the message is passed along the "validated" output.
If the JSON content does not conform to the schema, the message is passed along the "validation_error" output.
In the latter case, the error message is constructed using the provided `error_template` or a default template.
These error ChatMessages can be used by LLMs in Haystack 2.x recovery loops.
Usage example:
```python
from haystack import Pipeline
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.joiners import BranchJoiner
from haystack.components.validators import JsonSchemaValidator
from haystack import component
from haystack.dataclasses import ChatMessage
@component
class MessageProducer:
@component.output_types(messages=list[ChatMessage])
def run(self, messages: list[ChatMessage]) -> dict:
return {"messages": messages}
p = Pipeline()
p.add_component("llm", OpenAIChatGenerator(generation_kwargs={"response_format": {"type": "json_object"}}))
p.add_component("schema_validator", JsonSchemaValidator())
p.add_component("joiner_for_llm", BranchJoiner(list[ChatMessage]))
p.add_component("message_producer", MessageProducer())
p.connect("message_producer.messages", "joiner_for_llm")
p.connect("joiner_for_llm", "llm")
p.connect("llm.replies", "schema_validator.messages")
p.connect("schema_validator.validation_error", "joiner_for_llm")
result = p.run(data={
"message_producer": {
"messages":[ChatMessage.from_user("Generate JSON for person with name 'John' and age 30")]},
"schema_validator": {
"json_schema": {
"type": "object",
"properties": {"name": {"type": "string"},
"age": {"type": "integer"}
}
}
}
})
print(result)
# >> {'schema_validator': {'validated': [ChatMessage(_role=<ChatRole.ASSISTANT: 'assistant'>,
# _content=[TextContent(text="\n{\n "name": "John",\n "age": 30\n}")],
# _name=None, _meta={'index': 0, 'finish_reason': 'stop', 'usage': {'completion_tokens': 17, 'prompt_tokens': 20,
# 'total_tokens': 37}})]}}
```
#### __init__
```python
__init__(
json_schema: dict[str, Any] | None = None, error_template: str | None = None
) -> None
```
Initialize the JsonSchemaValidator component.
**Parameters:**
- **json_schema** (<code>dict\[str, Any\] | None</code>) A dictionary representing the [JSON schema](https://json-schema.org/) against which
the messages' content is validated.
- **error_template** (<code>str | None</code>) A custom template string for formatting the error message in case of validation failure.
#### run
```python
run(
messages: list[ChatMessage],
json_schema: dict[str, Any] | None = None,
error_template: str | None = None,
) -> dict[str, list[ChatMessage]]
```
Validates the last of the provided messages against the specified json schema.
If it does, the message is passed along the "validated" output. If it does not, the message is passed along
the "validation_error" output.
**Parameters:**
- **messages** (<code>list\[ChatMessage\]</code>) A list of ChatMessage instances to be validated. The last message in this list is the one
that is validated.
- **json_schema** (<code>dict\[str, Any\] | None</code>) A dictionary representing the [JSON schema](https://json-schema.org/)
against which the messages' content is validated. If not provided, the schema from the component init
is used.
- **error_template** (<code>str | None</code>) A custom template string for formatting the error message in case of validation. If not
provided, the `error_template` from the component init is used.
**Returns:**
- <code>dict\[str, list\[ChatMessage\]\]</code> A dictionary with the following keys:
- "validated": A list of messages if the last message is valid.
- "validation_error": A list of messages if the last message is invalid.
**Raises:**
- <code>ValueError</code> If no JSON schema is provided or if the message content is not a dictionary or a list of
dictionaries.