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
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:
@@ -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.
|
||||
Reference in New Issue
Block a user