Skip to content

Releases: deepset-ai/haystack

v2.14.0-rc2

26 May 10:44

Choose a tag to compare

v2.14.0-rc2 Pre-release
Pre-release
v2.14.0-rc2

v2.14.0-rc1

23 May 15:01
37e249b

Choose a tag to compare

v2.14.0-rc1 Pre-release
Pre-release
v2.14.0-rc1

v2.13.2

09 May 05:21

Choose a tag to compare

⚡️ Enhancement Notes

  • Updated pipeline execution logic to use a new utility method _deepcopy_with_exceptions, which attempts to deep copy an object and safely falls back to the original object if copying fails. Additionally _deepcopy_with_exceptions skips deep-copying of Component, Tool, and Toolset instances when used as runtime parameters. This prevents errors and unintended behavior caused by trying to deepcopy objects that contain non-copyable attributes (e.g. Jinja2 templates, clients). Previously, standard deepcopy was used on inputs and outputs which occasionally lead to errors since certain Python objects cannot be deepcopied.

🐛 Bug Fixes

  • Make internal tool conversion in the HuggingFaceAPICompatibleChatGenerator compatible with huggingface_hub>=0.31.0. In the huggingface_hub library, arguments attribute of ChatCompletionInputFunctionDefinition has been renamed to parameters. Our implementation is compatible with both the legacy version and the new one.
  • The HuggingFaceAPIChatGenerator now checks the type of the arguments variable in the tool calls returned by the Hugging Face API. If arguments is a JSON string, it is parsed into a dictionary. Previously, the arguments type was not checked, which sometimes led to failures later in the tool workflow.

v2.13.1

24 Apr 14:42

Choose a tag to compare

Release Notes

v2.13.1

Bug Fixes

  • Update the __deepcopy__ of ComponentTool to gracefully handle NotImplementedError when trying to deepcopy attributes.
  • Fix an issue where OpenAIChatGenerator and OpenAIGenerator were not properly handling wrapped streaming responses from tools like Weave.
  • Move deserialize_tools_inplace back to original import path of from haystack.tools.tool import deserialize_tools_inplace.

v2.13.0

22 Apr 16:13
af72d61

Choose a tag to compare

⭐️ Highlights

Enhanced Agent Tracing and Async Support

Haystack's Agent got several improvements!

Agent Tracing
Agent tracing now provides deeper visibility into the agent's execution. For every call, the inputs and outputs of the ChatGenerator and ToolInvoker are captured and logged using dedicated child spans. This makes it easier to debug, monitor, and analyze how an agent operates step-by-step.

Below is an example of what the trace looks like in Langfuse:

Langfuse UI for tracing

# pip install langfuse-haystack
from haystack_integrations.components.connectors.langfuse.langfuse_connector import LangfuseConnector
from haystack.components.agents import Agent 
from haystack.components.generators.chat import OpenAIChatGenerator

tracer = LangfuseConnector("My Haystack Agent")
agent = Agent(
    system_prompt="You help provide the weather for cities" 
    chat_generator=OpenAIChatGenerator(),
    tools=[weather_tool],
) 

Async Support
Additionally, there's a new run_async method to enable built-in async support for Agent. Just use run_async instead of the run method. Here's an example of an async web search agent:

# set `SERPERDEV_API_KEY` and `OPENAI_API_KEY` as env variables
from haystack.components.agents import Agent 
from haystack.components.generators.chat import OpenAIChatGenerator 
from haystack.components.websearch import SerperDevWebSearch 
from haystack.dataclasses import ChatMessage 
from haystack.tools.component_tool import ComponentTool 

web_tool = ComponentTool(component=SerperDevWebSearch()) 

web_search_agent = Agent(     
    chat_generator=OpenAIChatGenerator(),
    tools=[web_tool],
) 

result = await web_search_agent.run_async(
    messages=[ChatMessage.from_user("Find information about Haystack by deepset")]
) 

New Toolset for Enhanced Tool Management

The new Toolset groups multiple Tool instances into a single manageable unit. It simplifies the passing of tools to components like ChatGenerator, ToolInvoker, or Agent, and supports filtering, serialization, and reuse.
Check out the MCPToolset for dynamic tool discovery from an MCP server.

from haystack.tools import Toolset
from haystack.components.agents import Agent
from haystack.components.generators.chat import OpenAIChatGenerator

math_toolset = Toolset([tool_one, tool_two, ...])
agent = Agent(
    chat_generator=OpenAIChatGenerator(model="gpt-4o-mini"),
    tools=math_toolset
)

@super_component decorator and new ready-made SuperComponents

Creating a custom SuperComponents just got even simpler. Now, all you need to do is define a class with a pipeline attribute and decorate it with @super_component. Haystack takes care of the rest!

Here's an example of building a custom HybridRetriever using the @super_component decorator:

# pip install haystack-ai datasets "sentence-transformers>=3.0.0"

from haystack import Document, Pipeline, super_component
from haystack.components.joiners import DocumentJoiner
from haystack.components.embedders import SentenceTransformersTextEmbedder
from haystack.components.retrievers import InMemoryBM25Retriever, InMemoryEmbeddingRetriever
from haystack.document_stores.in_memory import InMemoryDocumentStore
from datasets import load_dataset

@super_component
class HybridRetriever:
    def __init__(self, document_store: InMemoryDocumentStore, embedder_model: str = "BAAI/bge-small-en-v1.5"):
        embedding_retriever = InMemoryEmbeddingRetriever(document_store)
        bm25_retriever = InMemoryBM25Retriever(document_store)
        text_embedder = SentenceTransformersTextEmbedder(embedder_model)
        document_joiner = DocumentJoiner(join_mode="reciprocal_rank_fusion")

        self.pipeline = Pipeline()
        self.pipeline.add_component("text_embedder", text_embedder)
        self.pipeline.add_component("embedding_retriever", embedding_retriever)
        self.pipeline.add_component("bm25_retriever", bm25_retriever)
        self.pipeline.add_component("document_joiner", document_joiner)

        self.pipeline.connect("text_embedder", "embedding_retriever")
        self.pipeline.connect("bm25_retriever", "document_joiner")
        self.pipeline.connect("embedding_retriever", "document_joiner")

dataset = load_dataset("HaystackBot/medrag-pubmed-chunk-with-embeddings", split="train")
docs = [Document(content=doc["contents"], embedding=doc["embedding"]) for doc in dataset]
document_store = InMemoryDocumentStore()
document_store.write_documents(docs)

query = "What treatments are available for chronic bronchitis?"
result = HybridRetriever(document_store).run(text=query, query=query)
print(result)

New ready-made SuperComponents: MultiFileConverter, DocumentPreprocessor
There are also two ready-made SuperComponents, MultiFileConverter and DocumentPreprocessor, that encapsulate widely used common logic for indexing pipelines.

📚 Learn more about SuperComponents and get the full code example in the Tutorial: Creating Custom SuperComponents

⬆️ Upgrade Notes

  • The deprecated api, api_key, and api_params parameters for LLMEvaluator, ContextRelevanceEvaluator, and FaithfulnessEvaluator have been removed. By default, these components will continue to use OpenAI in JSON mode. To customize the LLM, use the chat_generator parameter with a ChatGenerator instance configured to return a response in JSON format. For example:
chat_generator=OpenAIChatGenerator(generation_kwargs={"response_format": {"type": "json_object"}})
  • The deprecated generator_api and generator_api_params initialization parameters of LLMMetadataExtractor and the LLMProvider enum have been removed. Use chat_generator instead to configure the underlying LLM. In order for the component to work, the LLM should be configured to return a JSON object. For example, if using OpenAI, you should initialize the LLMMetadataExtractor with
chat_generator=OpenAIChatGenerator(generation_kwargs={"response_format": {"type": "json_object"}})

🚀 New Features

  • Add run_async for OpenAITextEmbedder.
  • Add run_async method to HuggingFaceAPIDocumentEmbedder. This method enriches Documents with embeddings. It supports the same parameters as the run method. It returns a coroutine that can be awaited.
  • Support custom HTTP client configuration via http_client_kwargs (proxy, SSL) for:
    • AzureOpenAIGenerator, OpenAIGenerator and DALLEImageGenerator
    • OpenAIDocumentEmbedder and OpenAITextEmbedder
    • RemoteWhisperTranscriber
  • OpenAIChatGenerator and AzureOpenAIChatGenerator now support custom HTTP client config via http_client_kwargs, enabling proxy and SSL setup.
  • Introduced the Toolset class, allowing for the grouping and management of related tool functionalities. This new abstraction supports dynamic tool loading and registration.
  • We have added internal tracing support to Agent. It is now possible to track the internal loops within the agent by viewing the inputs and outputs each time the ChatGenerator and ToolInvoker is called.
  • The HuggingFaceAPITextEmbedder now also has support for a run() method in an asynchronous way, i.e., run_async.
  • Add a run_async to the Agent, which calls the run_async of the underlying ChatGenerator if available.
  • SuperComponents now support mapping nonleaf pipelines outputs to the SuperComponents output when specifying them in output_mapping.
  • AzureOpenAITextEmbedder and AzureOpenAIDocumentEmbedder now support custom HTTP client config via http_client_kwargs, enabling proxy and SSL setup.
  • The AzureOpenAIDocumentEmbedder component now inherits from the OpenAIDocumentEmbedder component, enabling asynchronous usage.
  • The AzureOpenAITextEmbedder component now inherits from the OpenAITextEmbedder component, enabling asynchronous usage.
  • Added async support to the OpenAIDocumentEmbedder component.
  • Agent now supports a List of Tools or a Toolset as input.

⚡️ Enhancement Notes

  • Added component_name and component_type attributes to PipelineRuntimeError.
    • Moved error message creation to within PipelineRuntimeError
    • Created a new subclass of PipelineRuntimeError called PipelineComponentsBlockedError for the specific case where the pipeline cannot run since no components are unblocked.
  • The ChatGenerator Protocol no longer requires to_dict and from_dict methods.

⚠️ Deprecation Notes

  • The utility function deserialize_tools_inplace has been deprecated and will be removed in Haystack 2.14.0. Use deserialize_tools_or_toolset_inplace instead.

🐛 Bug Fixes

  • OpenAITextEmbedder no longer replaces newlines with spaces in the text to embed. This was only required for the discontinued v1 embedding models.
  • OpenAIDocumentEmbedder and AzureOpenAIDocumentEmbedder no longer replace newlines with spaces in the text to embed. This was only required for the discontinued v1 embedding models.
  • Fix ChatMessage.from_dict to handle cases where optional fields like name and meta are missing.
  • Make Document's first-level fields to take precedence ove...
Read more

v2.13.0-rc2

22 Apr 12:29
408729c

Choose a tag to compare

v2.13.0-rc2 Pre-release
Pre-release
v2.13.0-rc2

v2.13.0-rc1

22 Apr 10:08
5d3ec43

Choose a tag to compare

v2.13.0-rc1 Pre-release
Pre-release
v2.13.0-rc1

v2.12.2

14 Apr 13:56

Choose a tag to compare

🐛 Bug Fixes

  • Fix ChatMessage.from_dict to handle cases where optional fields like name and meta are missing.
  • Make Document's first-level fields to take precedence over meta fields when flattening the dictionary representation.

v2.12.1

10 Apr 07:37

Choose a tag to compare

🐛 Bug Fixes

  • In Agent we make sure state_schema is always initialized to have 'messages'. Previously this was only happening at run time which is why pipeline.connect failed because output types are set at init time. Now the Agent correctly sets everything in state_schema (including messages by default) at init time.
  • In AsyncPipline the span tag name is updated from hasytack.component.outputs to haystack.component.output. This matches the tag name used in Pipeline and is the tag name expected by our tracers.

v2.12.0

02 Apr 10:30

Choose a tag to compare

⭐️ Highlights

Agent Component with State Management

The Agent component enables tool-calling functionality with provider-agnostic chat model support and can be used as a standalone component or within a pipeline.
With SERPERDEV_API_KEY and OPENAI_API_KEY defined, a Web Search Agent is as simple as:

from haystack.components.agents import Agent 
from haystack.components.generators.chat import OpenAIChatGenerator 
from haystack.components.websearch import SerperDevWebSearch 
from haystack.dataclasses import ChatMessage 
from haystack.tools.component_tool import ComponentTool 

web_tool = ComponentTool(     
    component=SerperDevWebSearch(), 
) 

agent = Agent(     
    chat_generator=OpenAIChatGenerator(),
    tools=[web_tool],
) 

result = agent.run(
    messages=[ChatMessage.from_user("Find information about Haystack by deepset")]
) 

The Agent supports streaming responses, customizable exit conditions, and a flexible state management system that enables tools to share and modify data during execution:

agent = Agent(
    chat_generator=OpenAIChatGenerator(),
    tools=[web_tool, weather_tool],
    exit_conditions=["text", "weather_tool"],
    state_schema = {...},
    streaming_callback=streaming_callback,
)

SuperComponent for Reusable Pipelines

SuperComponent allows you to wrap complex pipelines into reusable components. This makes it easy to reuse them across your applications. Just initialize a SuperComponent with a pipeline:

from haystack import Pipeline, SuperComponent

with open("pipeline.yaml", "r") as file:
  pipeline = Pipeline.load(file)

super_component = SuperComponent(pipeline)

That's not all! To show the benefits, there are three ready-made SuperComponents in haystack-experimental.
For example, there is a MultiFileConverter that wraps a pipeline with converters for CSV, DOCX, HTML, JSON, MD, PPTX, PDF, TXT, and XSLX. After installing the integration dependencies pip install pypdf markdown-it-py mdit_plain trafilatura python-pptx python-docx jq openpyxl tabulate pandas, you can run with any of the supported file types as input:

from haystack_experimental.super_components.converters import MultiFileConverter

converter = MultiFileConverter()
converter.run(sources=["test.txt", "test.pdf"], meta={})

Here's an example of creating a custom SuperComponent from any Haystack pipeline:

from haystack import Pipeline, SuperComponent
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.builders import ChatPromptBuilder
from haystack.components.retrievers import InMemoryBM25Retriever
from haystack.dataclasses.chat_message import ChatMessage
from haystack.document_stores.in_memory import InMemoryDocumentStore
from haystack.dataclasses import Document

document_store = InMemoryDocumentStore()
documents = [
    Document(content="Paris is the capital of France."),
    Document(content="London is the capital of England."),
]
document_store.write_documents(documents)

prompt_template = [
    ChatMessage.from_user(
    '''
    According to the following documents:
    {% for document in documents %}
    {{document.content}}
    {% endfor %}
    Answer the given question: {{query}}
    Answer:
    '''
    )
]
prompt_builder = ChatPromptBuilder(template=prompt_template, required_variables="*")

pipeline = Pipeline()
pipeline.add_component("retriever", InMemoryBM25Retriever(document_store=document_store))
pipeline.add_component("prompt_builder", prompt_builder)
pipeline.add_component("llm", OpenAIChatGenerator())
pipeline.connect("retriever.documents", "prompt_builder.documents")
pipeline.connect("prompt_builder.prompt", "llm.messages")

# Create a super component with simplified input/output mapping
wrapper = SuperComponent(
    pipeline=pipeline,
    input_mapping={
        "query": ["retriever.query", "prompt_builder.query"],
    },
    output_mapping={"llm.replies": "replies"}
)

# Run the pipeline with simplified interface
result = wrapper.run(query="What is the capital of France?")
print(result)
# {'replies': [ChatMessage(_role=<ChatRole.ASSISTANT: 'assistant'>,
#  _content=[TextContent(text='The capital of France is Paris.')],...)

⬆️ Upgrade Notes

  • Updated ChatMessage serialization and deserialization. ChatMessage.to_dict() now returns a dictionary with the keys: role, content, meta, and name. ChatMessage.from_dict() supports this format and maintains compatibility with older formats.

    If your application consumes the result of ChatMessage.to_dict(), update your code to handle the new format. No changes are needed if you're using ChatPromptBuilder in a Pipeline.

  • LLMEvaluator, ContextRelevanceEvaluator, and FaithfulnessEvaluator now internally use a ChatGenerator instance instead of a Generator instance. The public attribute generator has been replaced with _chat_generator.

  • to_pandas, comparative_individual_scores_report and score_report were removed from EvaluationRunResult, please use detailed_report, comparative_detailed_report and aggregated_report instead.

🚀 New Features

  • Treat bare types (e.g., List, Dict) as generic types with Any arguments during type compatibility checks.
  • Add compatibility for Callable types.
  • Adds outputs_to_string to Tool and ComponentTool to allow users to customize how the output of a Tool should be converted into a string so that it can be provided back to the ChatGenerator in a ChatMessage. If outputs_to_string is not provided, a default converter is used within ToolInvoker. The default handler uses the current default behavior.
  • Added a new parameter split_mode to the CSVDocumentSplitter component to control the splitting mode. The new parameter can be set to row-wise to split the CSV file by rows. The default value is threshold, which is the previous behavior.
  • We added a new retrieval technique, AutoMergingRetriever which together with the HierarchicalDocumentSplitter implement a auto-merging retrieval technique.
  • Add run_async method to HuggingFaceLocalChatGenerator. This method internally uses ThreadPoolExecutor to return coroutines that can be awaited.
  • Introduced asynchronous functionality and HTTP/2 support in the LinkContentFetcher component, thus improving content fetching in several aspects.
  • The DOCXToDocument component now has the option to include extracted hyperlink addresses in the output Documents. It accepts a link_format parameter that can be set to "markdown" or "plain". By default, no hyperlink addresses are extracted as before.
  • Added a new parameter azure_ad_token_provider to all Azure OpenAI components: AzureOpenAIGenerator, AzureOpenAIChatGenerator, AzureOpenAITextEmbedder and AzureOpenAIDocumentEmbedder. This parameter optionally accepts a callable that returns a bearer token, enabling authentication via Azure AD.
    • Introduced the utility function default_azure_token_provider in haystack/utils/azure.py. This function provides a default token provider that is serializable by Haystack. Users can now pass default_azure_token_provider as the azure_ad_token_provider or implement a custom token provider.
  • Users can now work with date and time in the ChatPromptBuilder. In the same way as the PromptBuilder, the ChatPromptBuilder now supports arrow to work with datetime.
  • Introduce new State dataclass with a customizable schema for managing Agent state. Enhance error logging of Tool and extend the ToolInvoker component to work with newly introduced State.
  • The RecursiveDocumentSplitter now supports splitting by number of tokens. Setting "split_unit" to "token" will use a hard-coded tiktoken tokenizer (o200k_base) and requires having tiktoken installed.

⚡️ Enhancement Notes

  • LLMEvaluator, ContextRelevanceEvaluator, and FaithfulnessEvaluator now accept a chat_generator initialization parameter, consisting of ChatGenerator instance pre-configured to return a JSON object. Previously, these components only supported OpenAI and LLMs with OpenAI-compatible APIs. Regardless of whether the evaluator components are initialized with api, api_key, and api_params or the new chat_generator parameter, the serialization format will now only include chat_generator in preparation for the future removal of api, api_key, and api_params.
  • Improved error handling for component run failures by raising a runtime error that includes the component's name and type.
  • When using Haystack's Agent, the messages are stored and accumula...
Read more