⭐️ Highlights
增强复杂代理系统
我们通过改进消息处理和流式传输支持,增强了代理工作流程。 Agent 组件现在返回一个 last_message 输出,以便快速访问最后一条消息,并且可以使用 streaming_callback 实时发出工具结果。您可以使用更新的 print_streaming_chunk 或编写自己的回调函数来在流式传输期间启用 ToolCall 详细信息。
from haystack.components.websearch import SerperDevWebSearch
from haystack.components.agents import Agent
from haystack.components.generators.utils import print_streaming_chunk
from haystack.tools import tool, ComponentTool
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
web_search = ComponentTool(name="web_search", component=SerperDevWebSearch(top_k=5))
wiki_search = ComponentTool(name="wiki_search", component=SerperDevWebSearch(top_k=5, allowed_domains=["https://www.wikipedia.org/"]))
research_agent = Agent(
chat_generator=OpenAIChatGenerator(model="gpt-4o-mini"),
system_prompt="""
You are a research agent that can find information on web or specifically on wikipedia.
Use wiki_search tool if you need facts and use web_search tool for latest news on topics.
Use one tool at a time, use the other tool if the retrieved information is not enough.
Summarize the retrieved information before returning response to the user.
""",
tools=[web_search, wiki_search],
streaming_callback=print_streaming_chunk
)
result = research_agent.run(messages=[ChatMessage.from_user("Can you tell me about Florence Nightingale's life?")])
使用 print_streaming_chunk 函数启用流式传输看起来像这样
[TOOL CALL]
Tool: wiki_search
Arguments: {"query":"Florence Nightingale"}
[TOOL RESULT]
{'documents': [{'title': 'List of schools in Nottinghamshire', 'link': 'https://www.wikipedia.org/wiki/List_of_schools_in_Nottinghamshire', 'position': 1, 'id': 'a6d0fe00f1e0cd06324f80fb926ba647878fb7bee8182de59a932500aeb54a5b', 'content': 'The Florence Nightingale Academy, Eastwood; The Flying High Academy, Mansfield; Forest Glade Primary School, Sutton-in-Ashfield; Forest Town Primary School ...', 'blob': None, 'score': None, 'embedding': None, 'sparse_embedding': None}], 'links': ['https://www.wikipedia.org/wiki/List_of_schools_in_Nottinghamshire']}
...
打印 last_message
print("Final Answer:", result["last_message"].text)
>>> Final Answer: Florence Nightingale (1820-1910) was a pioneering figure in nursing and is often hailed as the founder of modern nursing. She was born...
此外,AnswerBuilder 将所有生成的_消息_存储在 GeneratedAnswer 的 all_messages 元字段中,并支持新的 last_message_only 模式,适用于只需要处理最后一条_消息_的轻量级流程。
使用 SuperComponents 可视化 Pipelines
我们扩展了 pipeline.draw() 和 pipeline.show(),它们将 pipeline 图保存为图像文件或在 Jupyter notebooks 中显示它们。您现在可以传递 super_component_expansion=True 来展开任何 SuperComponents 并绘制更详细的可视化。
以下是包含 MultiFileConverter 和 DocumentPreprocssor SuperComponents 的 pipeline 的示例。在安装 pip install haystack-ai pypdf markdown-it-py mdit_plain trafilatura python-pptx python-docx jq openpyxl tabulate pandas 所需的所有支持的文件格式的依赖项后,您可以运行
from pathlib import Path
from haystack import Pipeline
from haystack.components.converters import MultiFileConverter
from haystack.components.preprocessors import DocumentPreprocessor
from haystack.components.writers import DocumentWriter
from haystack.document_stores.in_memory import InMemoryDocumentStore
document_store = InMemoryDocumentStore()
pipeline = Pipeline()
pipeline.add_component("converter", MultiFileConverter())
pipeline.add_component("preprocessor", DocumentPreprocessor())
pipeline.add_component("writer", DocumentWriter(document_store = document_store))
pipeline.connect("converter", "preprocessor")
pipeline.connect("preprocessor", "writer")
# expanded pipeline that shows all components
path = Path("expanded_pipeline.png")
pipeline.draw(path=path, super_component_expansion=True)
# original pipeline
path = Path("original_pipeline.png")
pipeline.draw(path=path)
SentenceTransformersSimilarityRanker 支持 PyTorch、ONNX 和 OpenVINO
我们添加了一个新的 SentenceTransformersSimilarityRanker 组件,它使用 Sentence Transformers 库根据文档与查询的语义相似度对文档进行排序。此组件将替换可能在未来版本中弃用的旧 TransformersSimilarityRanker 组件,并在弃用期结束后移除。 SentenceTransformersSimilarityRanker 还允许选择不同的推理后端:PyTorch、ONNX 和 OpenVINO。例如,在安装 sentence-transformers>=4.1.0 后,您可以运行
from haystack.components.rankers import SentenceTransformersSimilarityRanker
from haystack.utils.device import ComponentDevice
onnx_ranker = SentenceTransformersSimilarityRanker(
model="sentence-transformers/all-MiniLM-L6-v2",
token=None,
device=ComponentDevice.from_str("cpu"),
backend="onnx",
)
onnx_ranker.warm_up()
docs = [Document(content="Berlin"), Document(content="Sarajevo")]
output = onnx_ranker.run(query="City in Germany", documents=docs)
ranked_docs = output["documents"]
⬆️ 升级说明
- 我们将
py.typed文件添加到 Haystack 中,以便下游项目可以使用类型信息,这符合 PEP 561。这意味着 Haystack 的类型提示现在将对依赖它的项目中的类型检查器可见。Haystack 主要使用 mypy(而不是 pyright)进行类型检查,尽管我们付出了努力,但某些类型信息可能不完整或不可靠。如果您在自己的项目中使用静态类型检查,您可能会注意到一些变化:以前,Haystack 的类型实际上被视为Any,但现在将提供并强制执行实际的类型信息。我们将在下一个版本中继续改进类型。 - 已移除弃用的
deserialize_tools_inplace实用函数。请使用deserialize_tools_or_toolset_inplace,并像这样导入:from haystack.tools import deserialize_tools_or_toolset_inplace。
🚀 新功能
-
向
ToolInvoker类添加了run_async方法,以允许异步调用工具。 -
Agent 现在也可以通过
run_async方法流式传输工具结果。 -
引入了
serialize_value和deserialize_value实用方法,以实现跨模块的_一致_值(反)序列化。 -
将
State类移动到agents.state模块,并添加了序列化和反序列化功能。 -
为 ConditionalRouter 添加了对多个输出的支持
-
实现 OpenAI 使用数据的 JSON 安全序列化,将_token_计数和详细信息(如 CompletionTokensDetails 和 PromptTokensDetails)转换为普通字典。
-
添加了一个新的
SentenceTransformersSimilarityRanker组件,它使用 Sentence Transformers 库根据文档与查询的语义相似度对文档进行排序。此组件是对旧TransformersSimilarityRanker组件的替代,该组件可能在未来版本中被弃用,并在弃用期结束后移除。SentenceTransformersSimilarityRanker还允许选择不同的推理后端:PyTorch、ONNX 和 OpenVINO。要使用SentenceTransformersSimilarityRanker,您需要安装sentence-transformers>=4.1.0。 -
向
ToolInvoker添加了streaming_callback参数,以启用工具结果的流式传输。请注意,tool_result 仅在工具执行完成后发出,并且不会增量流式传输。 -
更新
print_streaming_chunk以打印 ToolCall 信息(如果存在于块的元数据中)。 -
更新
Agent以将streaming_callback转发给ToolInvoker,以便在工具调用期间发出工具结果。 -
增强 SuperComponent 的类型兼容性检查,以返回检测到的两个输入类型之间的公共类型。
⚡️ 增强说明
-
在使用 HuggingFaceAPIChatGenerator 进行流式传输时,返回的 ChatMessage 现在在其元数据中包含 prompt _token_数和 completion _token_数。在内部,HuggingFaceAPIChatGenerator 请求一个包含使用数据的额外流式传输块。然后,它处理使用流式传输块,将使用元数据添加到返回的 ChatMessage 中。
-
我们现在有一个 TextEmbedder 的协议。该协议使得创建需要任何 TextEmbedder 作为 init 参数的自定义组件或 SuperComponents 更加容易。
-
我们添加了一个
Component签名验证方法,该方法详细说明了run和run_async方法签名之间的不匹配。这使用户可以轻松调试自定义组件。 -
增强了 AnswerBuilder 组件的两个面向代理的功能
- 所有生成的_消息_现在都存储在 GeneratedAnswer 对象 的
meta字段下的all_messages键中,从而提高了可追溯性和调试能力。 - 添加了一个新的
last_message_only参数,当设置为True时,它只处理回复中的最后一条_消息_,同时仍将完整的对话历史保存在元数据中。这对于只需要处理最后_一条_响应的代理工作流程特别有用。
- 所有生成的_消息_现在都存储在 GeneratedAnswer 对象 的
-
已进行多项改进,以便 Agent 组件可以直接用在 ComponentTool 中,从而能够直接构建多代理系统。这些改进包括
- 在 Agent 的输出中添加一个
last_message字段,该字段返回最后生成的 ChatMessage。 - 改进
ToolInvoker中的_default_output_handler,使其首先尝试序列化工具结果中的输出,然后再将其转换为字符串。这对于在字符串化 ChatMessage 等数据类时获得更好的表示尤为重要。
- 在 Agent 的输出中添加一个
-
向
component装饰器添加了类型提示。这改善了对 Pyright/Pylance 的支持,使 VSCode 等 IDE 能够显示组件的文档字符串。 -
更新了 pipeline 执行逻辑,使用新的实用方法
_deepcopy_with_exceptions,该方法尝试深度复制对象,并在复制失败时安全地回退到原始对象。此外,当Component、Tool和Toolset实例用作运行时参数时,_deepcopy_with_exceptions会跳过对它们的深度复制。这可以防止由于尝试深度复制包含不可复制属性(例如 Jinja2 模板、客户端)的对象而导致的错误和意外行为。以前,对输入和输出使用了标准的deepcopy,由于某些 Python 对象无法深度复制,这有时会导致错误。 -
使用 Pydantic 的 model_json_schema 重构了 ComponentTool 参数的 JSON Schema 生成,从而支持了更广泛的类型(例如 Union、Enum、Dict 等)。我们还在调用 model_json_schema 之前将数据类转换为 Pydantic 模型,以保留 schema 中参数的文档字符串描述。这意味着 ChatMessage、Document 等数据类现在具有正确定义的 JSON schema。
-
Pipeline的draw()和show()方法现在有一个额外的布尔参数super_component_expansion,当设置为True并且 pipeline 包含 SuperComponents 时,可视化图将显示 super-components 的内部结构,就像它们是 pipeline 的一部分组件一样,而不是一个带有 SuperComponent 名称的“黑盒子”。 -
改进了
@component和Component协议的类型注解。类型检查器现在可以确保@component类提供兼容的run()方法,其必需的返回类型已从Dict[str, Any](不变)更改为Mapping[str, Any],以允许将TypedDict用于输出类型。 -
- 更新了 ToolInvoker 中的 StreamingChunk 构建,以流式传输带有 finish reason 的块。这在使用 print_streaming_chunk 实用方法时很有用
- 更新 print_streaming_chunk 以更好地格式化 _消息_,尤其是在与 Agent 一起使用时。
- 还更新为与当前版本的 AWS Bedrock 集成兼容,方法是处理 ChoiceDeltaToolCall 的 dict 表示形式
-
ComponentTool 在包装 SuperComponent 时,现在可以保留并合并来自底层 pipeline 组件的文档字符串。当 ComponentTool 与 SuperComponent 一起使用时,会进行两项关键改进
- 参数描述现在从包装管道中的原始组件中提取。当一个输入映射到多个组件时,参数描述将从所有映射的组件中合并,提供关于参数如何在整个管道中使用的全面信息。
- 组件的总体描述现在是从所有底层组件的描述生成的,而不是使用通用的 SuperComponent 描述。这有助于 LLM 理解组件实际做什么,而不是仅仅看到“使用提供的输入运行包装的管道”。
这些更改使得 SuperComponents 在 LLM 函数调用方面更加有用,因为 LLM 将获得有关组件目的及其参数的详细信息。
-
向
SentenceTransformersDocumentEmbedder和SentenceTransformersTextEmbedder添加了local_files_only参数,以允许在离线模式下加载模型。 -
更新了
DocumentRecallEvaluator。现在,在MULTI_HIT模式下,除法是针对唯一真实文档进行的,而不是针对总真实文档数。我们还添加了空值检查。如果没有检索到文档或所有文档的内容都为空字符串,我们将返回 0.0 并记录警告。同样,如果没有真实文档或所有文档的内容都为空字符串,我们将返回 0.0 并记录警告。
⚠️ 弃用说明
- 弃用了
dataclasses模块中的State类。鼓励用户迁移到新版本的State,该版本现在位于agents.state模块中。已添加弃用警告以指导此迁移。
🔒 安全说明
- 使 SentenceSplitter 中的 QUOTE_SPANS_RE 正则表达式变为 ReDoS 安全。这可以防止对恶意输入的潜在回溯。
🐛 Bug 修复
- 修复了 SentenceSplitter 组件内使用的 QUOTE_SPANS_RE 正则表达式中潜在的 ReDoS 问题。
- 将 OpenAITextEmbedder 和 OpenAIDocumentEmbedder 的 to_dict 方法添加了 init 参数 timeout 和 max_retries。这确保了在使用这些组件的 to_dict 方法时,这些值能够被正确序列化。
- 在 LoggingTracer 中使用 coerce_tag_value 来序列化标签值
- 更新 ComponentTool 的
__deepcopy__以优雅地处理尝试深度复制属性时发生的 NotImplementedError。 - 修复了 OpenAIChatGenerator 和 OpenAIGenerator 在包装来自 Weave 等工具的流式响应时未正确处理的问题。
- 修复了
RecursiveDocumentSplitter中当split_text长于split_length并触发递归分块时出现的 bug。 - 使 HuggingFaceAPICompatibleChatGenerator 中的内部工具转换与
huggingface_hub>=0.31.0兼容。在 huggingface_hub 库中,ChatCompletionInputFunctionDefinition的arguments属性已重命名为parameters。我们的实现同时兼容旧版本和新版本。 HuggingFaceAPIChatGenerator现在会检查 Hugging Face API 返回的工具调用中arguments变量的类型。如果arguments是 JSON 字符串,则将其解析为字典。以前,arguments的类型未被检查,这有时会导致后续的工具工作流程失败。- 将 deserialize_tools_inplace 移回原始导入路径:from haystack.tools.tool import deserialize_tools_inplace。
- 为了在 AsyncPipeline 与仅具有同步 run 方法的组件一起使用时正确保留上下文,我们使用 contextvars.copy_context() 复制上下文,并使用
ctx.run(...)运行组件,以便保留活动跟踪 span 等上下文。现在这意味着如果您的组件 1) 仅具有同步 run 方法,并且 2) 它向跟踪器记录了内容,那么该跟踪将被正确地嵌套在父上下文中。 - 修复了
LLMMetadataExtractor在处理Document对象且内容为None或空字符串时发生的错误。该组件现在可以优雅地处理这些情况,将这些文档标记为失败并在其元数据中提供相应的错误消息,而无需尝试 LLM 调用。 - 修复了 ComponentTool 使用的 component_invoker 在将 ChatMessage 等数据类直接传递给
component_tool.invoke(...)时能够正常工作的问题。以前这会引发错误或静默跳过您的输入。
💙 非常感谢所有为本次发布做出贡献的人!
- @Amnah199 @anakin87 @davidsbatista @denisw @dfokina @jantrienes @mdrazak2001 @medsriha @mpangrazzi @sjrl @vblagoje @wsargent @YassinNouh21
特别感谢并祝贺我们的首次贡献者!
