Files
deepset-ai--haystack/docs-website/reference/haystack-api/joiners_api.md
T
wehub-resource-sync c56bef871b
Sync docs with Docusaurus / sync (push) Waiting to run
Tests / Check if changed (push) Waiting to run
Tests / format (push) Blocked by required conditions
Tests / check-imports (push) Blocked by required conditions
Tests / Unit / macos-latest (push) Blocked by required conditions
Tests / Unit / ubuntu-latest (push) Blocked by required conditions
Tests / Unit / windows-latest (push) Blocked by required conditions
Tests / mypy (push) Blocked by required conditions
Tests / Integration / ubuntu-latest (push) Blocked by required conditions
Tests / Integration / macos-latest (push) Blocked by required conditions
Tests / Integration / windows-latest (push) Blocked by required conditions
Tests / notify-slack-on-failure (push) Blocked by required conditions
Tests / Mark tests as completed (push) Blocked by required conditions
Docker image release / Build base image (push) Waiting to run
CodeQL / Analyze (python) (push) Has been cancelled
Update Platform Components Table / update (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:22:28 +08:00

567 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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