构建自然语言与大语言模型(LLM)流水线——deepset 出品的 Haystack 入门介绍

0 阅读2分钟

在上一章中,我们概览了 LLM 领域中的前沿模式:从提示工程(prompt engineering)到上下文工程(context engineering),从 LLM 向小模型(SLM)与推理模型(reasoning models)的演进,并提出了一种混合架构,用来结合 AI 版图中两家关键开源参与者的优势——deepset 的 Haystack 与 LangChain 的 LangGraph。我们通过一个拟议的混合架构,对二者各自的优势进行了映射:由一个有状态的编排层(LangGraph)来调度一组可靠、可审计的工具层(Haystack)。这种关注点分离(separation of concerns),正是构建复杂、可投入生产的 AI 系统的关键。

本章将开始深入探讨,如何使用 Haystack 2.0 来构建这一工具层。尽管 Haystack 也提供了自己的智能体(agentic)能力,我们也会对其进行概述,以说明在什么情况下这种方式已经足够,但在本书的方法框架中,我们更关注它作为一个“以 Pipeline 为中心”的引擎所扮演的角色。它真正的优势,在于构建健壮、可度量、可部署的数据流 Pipeline,而这些 Pipeline 正是高级 Agent 的基础设施。

在我们构建高级 RAG 系统(第 4 章),或者构建以微服务形式部署、供 Agent 调用的定制化 RAG 与 NLP Pipeline(第 7 章和第 8 章)之前,首先必须掌握这个框架的基本“物理规律”。本章将介绍这些核心构件:组件(components)、Pipeline,以及将它们绑定在一起的数据协议(data protocols)。

本章将涵盖以下主题:

  • deepset 概览
  • Haystack 演进后的 LLM 编排框架
  • Haystack 2.0 的关键构建块:从组件到 Agent
  • 关键特性与优势
  • 使用场景与应用
  • 深入解析 Haystack 的架构
  • 如何将 Haystack 融入你的工作流

技术要求

我们将沿用第 2 章中介绍的同一套技术环境。本章的 Jupyter Notebook 可在以下代码仓库中的 ch3/ 目录下找到:
https://github.com/PacktPublishing/Building-Natural-Language-and-LLM-Pipelines

本章配有一个专用的 pyproject.toml 文件。建议你在一个独立的 VS Code 窗口中打开 ch3 文件夹,并安装依赖:

$ cd ch3/
$ uv sync
$ source .venv/bin/activate

要将该虚拟环境激活为 Jupyter Notebook 的内核,请点击 Select Kernel,然后点击 Python Environments,再选择指向该文件夹虚拟环境的路径,即名为 rag-with-haystack-ch3 的环境,或者虚拟环境的相对路径 .venv/bin/python

我们会逐步引入这些 Notebook,因此你可以根据提供的 URL,通过相对路径选择对应讨论到的 Notebook。

deepset 概览

deepset 由 Milos Rusic、Malte Pietsch 和 Timo Möller 于 2018 年创立,正值 BERT 模型兴起之时,其目标是构建可扩展的 NLP 工具。最初,deepset 主要聚焦于开源微调,通过其 FARM 框架以及诸如 roberta-base-squad2 这类流行的 Hugging Face 模型来推进这一方向。到 2021 年,FARM 的核心特性被合并进 deepset 的旗舰框架 Haystack 中。

随着行业从面向特定任务的微调,逐步转向通用型 LLM,deepset 也顺势完成了对框架的彻底重构。其成果就是 Haystack 2.0:一个专门为生成式 AI 时代设计的平台。Haystack 2.0 不再局限于简单的信息抽取,而是通过编排基于 API 的 LLM 来构建复杂的 RAG 系统与自主 Agent。这一演进使 Haystack 从一个专用的 NLP 工具,转变为一个面向现代 AI 开发的通用平台。

Haystack 演进后的 LLM 编排框架

Haystack 2.0 代表着一次根本性的范式转移:它从一个专用搜索框架,演进为一个适用于现代 AI 工程的通用型、高度模块化工具箱。其核心理念建立在三个支柱之上:原生 Python(Python-native)显式(explicit) 、以及 模块化(modular) 。通过摆脱受限的、预定义的结构,Haystack 将自己定位为一个健壮、对开发者友好的框架,能够编排当前这一代 LLM 应用所需要的复杂、生产级工作流。

其中最重要的进步,是采用了显式有向图(directed graph, DG)架构。开发者不再依赖隐式的数据传递;相反,他们需要显式地实例化一个 Pipeline 对象,添加 Component 实例,并通过连接带类型的 socket 来严格定义数据流向。这种透明性使得复杂的非线性工作流成为可能,例如条件路由(如“如果查询是德语,就路由到模型 A”)和并行处理分支(如“同时执行关键词检索与向量检索”),同时也让整个系统可以被标准的 Python 调试工具完全看清。

这次架构层面的重构,是对 Agent 化工作流与复杂 RAG 工作流需求的一种战略性回应。尽管该框架原生支持 Agent 与循环(loops),但对我们而言,它最大的优势在于其可靠性。通过围绕一个具备严格契约的显式有向图重建基础设施,Haystack 为构建高级 Agent 所依赖的确定性工具,提供了一个稳定的平台。它对透明性的强调,为那些优先考虑可调试性与稳定性的工程团队,提供了一个极具吸引力的替代方案。

这种清晰、以开发者为中心的设计哲学,也是对早期版本局限性的直接回应。为了更充分地理解这次演进的分量,下面的表格对 Haystack 1.x 与 Haystack 2.x 的核心范式做了直接对比。

表 3.1 —— Haystack 1.x 与 Haystack 2.0:一次范式迁移

特性Haystack 1.x(旧版)Haystack 2.x(当前版)
Pipeline 定义方式使用 YAML 文件,或使用带有隐式节点命名的 Pipeline()使用纯 Python 中的 Pipeline() 类,并通过显式的 .add_component().connect() 方法定义
Component 定义方式基于类定义,需要继承 BaseComponent基于装饰器定义,只需在标准 Python 类上添加简单的 @component 装饰器
数据流通过组件之间隐式传递字典,难以追踪通过组件输入/输出显式定义、且带类型的输入/输出 socket,强制形成清晰的数据契约
调试方式往往需要了解框架内部机制,且不够透明原生 Python 调试;可通过 .draw() 方法可视化 Pipeline,查看准确的图结构与数据流
核心抽象线性节点序列,复杂逻辑难以表达有向无环图(DAG),原生支持分支、合并与循环,适合复杂、非线性工作流
主要关注点抽取式问答与语义检索通用型 LLM 编排,包括高级 RAG、Agent,以及任意自定义多步工作流

表 3.1 可以看作理解本章其余内容的一把“罗塞塔石碑”。它突出了那些经过深思熟虑的设计决策,正是这些决策使 Haystack 2.0 成为一个更强大、更透明、也更适合开发者的框架,以适应当下生成式 AI 的时代。

Haystack 2.0 的关键构建块:从组件到 Agent

Haystack 2.0 引入了一套清晰的抽象层级,使开发者能够以结构化、可复用的方式,构建复杂度不断提升的应用。这一层级从最原子的工作单元——组件(component)——开始,一直扩展到 Agent。理解这些构建块,是掌握该框架的基础。

Components —— 最原子的工作单元

Haystack 2.0 的最底层基础是组件。组件是一个自包含的 Python 类,用于在 Pipeline 中执行某一个单一、明确的任务。这个任务可以是清洗一段文本、将一个查询嵌入为向量、从数据库中检索文档,或调用 LLM 进行生成。

一个用于探索组件的 Jupyter Notebook 位于:
https://github.com/PacktPublishing/Building-Natural-Language-and-LLM-Pipelines/blob/main/ch3/jupyter-notebooks/components.ipynb

该 Notebook 展示了如何初始化并使用已有组件。Haystack 2.0 的一个关键架构选择,在于它定义自定义组件的方式。所有组件都遵循同一种模式,而正是这种模式,使得已有组件和自定义组件都可以顺利地被纳入 Pipeline 中。

创建一个组件极其简单,也非常符合 Python 的风格,其定义依赖两个关键特性:

  • @component 装饰器:任何 Python 类,只需在类定义上方添加 @component 装饰器,就可以被转换为一个 Haystack 组件。这个装饰器会将该类注册到 Haystack 框架中,并表明它可以在 Pipeline 中使用。
  • run() 方法:每个组件都必须有一个 run() 方法。这是组件逻辑的入口点,组件的主要任务就在这里执行。

Haystack 2.0 中组件之所以如此健壮,一个关键原因在于其带类型的输入/输出 socket 概念。这些 socket 通过在 run 方法签名上使用 @component.output 装饰器来定义。Socket 充当了组件的显式连接点,明确规定该组件期望接收什么类型的数据,以及会产出什么类型的数据。比如,一个检索器组件可能会有一个名为 query 的输入 socket,期望接收 str 类型;同时有一个名为 documents 的输出 socket,产出 List 类型的数据。这种显式契约在 Pipeline 内部强制执行类型安全,使数据流变得透明,也让 IDE 能够提供更好的自动补全与错误检查。这相较于 Haystack 1.x 中隐式传递字典的方式,是一次显著提升;后者常常会导致运行时错误,并带来艰难的调试过程。

一个用于探索自定义组件定义方式的 Jupyter Notebook 位于:
https://github.com/PacktPublishing/Building-Natural-Language-and-LLM-Pipelines/blob/main/ch3/jupyter-notebooks/your-first-custom-component.ipynb

在这个 Notebook 中,我们定义了一个 prefixer 文档组件,它会根据用户提供的前缀字符串,为每个文档添加注释性前缀。

Pipelines —— 将组件编排为图

组件负责执行单个任务,而 Pipeline 则负责将它们编排成一个连贯的工作流。正如前面所述,Haystack 2.0 的 Pipeline 是一个有向图(DG):组件是图中的节点,组件 socket 之间的连接则是边。

在 Python 中构建一个 Pipeline,是一个显式的三步过程:

  1. 实例化 Pipeline:
pipe = Pipeline()

2. 添加组件实例:
组件以唯一名称加入 Pipeline。例如:

pipe.add_component(
    name="retriever",
    instance=InMemoryEmbeddingRetriever(document_store)
)
pipe.add_component(name="generator", instance=OpenAIGenerator())

3. 连接组件:
通过将一个组件的输出 socket 连接到另一个组件的输入 socket,来定义数据流:

pipe.connect("retriever.documents", "generator.documents")

这种显式的 connect 语法,是 Haystack 2.0 透明性的基石。它彻底消除了数据如何在系统中流动的歧义。此外,框架还提供了一个关键的调试与可视化工具:.draw() 方法。调用 pipe.draw("my_pipeline.png") 会生成一张图片,以可视化方式展示 Pipeline 的图结构,包含全部组件及其连接关系。图 3.1 展示了前述示例中该 Pipeline 的 Mermaid 图。这是一个简单的 RAG Pipeline:它通过引入虚拟文档(dummy documents)作为依据,为 LLM 提供 grounding,从而增强模型能力。

image.png

图 3.1 —— 一个 Prompt 的 Mermaid 图

一个用于探索简单 Pipeline 及其可视化的 Jupyter Notebook 位于:
https://github.com/PacktPublishing/Building-Natural-Language-and-LLM-Pipelines/blob/main/ch3/jupyter-notebooks/your-first-pipeline.ipynb

显式连接组件、并将其可视化为图的能力,是透明性上的巨大跃升。然而,随着这些图变得越来越复杂,你会经常发现自己在反复搭建相同的模式。Haystack 为此提供了一个强大的抽象机制。

SuperComponents —— 封装并复用复杂性

随着 Pipeline 逐渐复杂,一些组件连接模式会反复出现。例如,一个标准的文档索引工作流,通常总是由文件转换器、文档清洗器、文档切分器、嵌入器和文档写入器按顺序连接而成。如果在每一个新 Pipeline 中都重复搭建这样一个子图,不仅繁琐,而且容易出错。

为了解决这个问题,Haystack 2.0 引入了 SuperComponent 的概念。SuperComponent 本质上是一个预打包、可复用的 Pipeline,它在更大的 Pipeline 中可以被当作一个单独的组件来使用。它将由多个组件组成的复杂子图封装起来,只向外暴露必要的输入和输出 socket。

例如,前面描述的整个索引工作流,就可以被封装成一个单独的 IndexingSupercomponent。这个 SuperComponent 可以只暴露一个简单的输入 socket(如 file_paths)和一个输出 socket(如 documents_written_count)。

开发者随后只需要一行代码,就能将其加入更大的 Pipeline 中:

pipe.add_component(
    name="indexer",
    instance=IndexingSupercomponent()),

这极大地简化了主 Pipeline 的定义,同时促进了清晰、模块化的设计。SuperComponent 是管理复杂性、以及构建高层可复用功能库的强大工具。我们先看一个更简单的模式,正如配套 Notebook 中展示的那样:我们定义了一个预处理 Pipeline,用于清洗文档并将其切分为多个 chunk。

一个用于探索 SuperComponents 的 Jupyter Notebook 位于:
https://github.com/PacktPublishing/Building-Natural-Language-and-LLM-Pipelines/blob/main/ch3/jupyter-notebooks/supercomponents.ipynb

预处理 Pipeline 的 Mermaid 图见图 3.2。

image.png

图 3.2 —— 预处理 Pipeline 的 Mermaid 图

在该 Notebook 中,我们将这个预处理 Pipeline 抽象为一个 preprocessor SuperComponent,然后将它连接到我们在自定义组件 Notebook 中见过的 prefixer 自定义组件上:
https://github.com/PacktPublishing/Building-Natural-Language-and-LLM-Pipelines/blob/main/ch3/jupyter-notebooks/your-first-custom-component.ipynb

最终的 Pipeline 定义中只包含两个组件:preprocessor SuperComponent 和 prefixer 组件。图 3.3 非常清晰地展示了这一点:在可视化后的最终 Pipeline 结构中,预处理 Pipeline 已被抽象为一个单独的 preprocessor 组件。

image.png

图 3.3 —— 预处理 SuperComponent 与 prefixer 自定义组件的 Mermaid 图

Agents 与 Tools —— 让 LLM 驱动推理

工具(tool)本质上是对一个 Haystack 组件,或者一个被抽象为 SuperComponent 的完整 Pipeline,进行语义包装(semantic wrapper)。它为底层的确定性逻辑赋予了以下元信息:

  • 名称(Name) :一个简短且唯一的标识符(例如 internal_knowledge_search
  • 描述(Description) :用自然语言解释该工具的能力、输入和输出(例如“搜索内部知识库。输入是一个字符串查询”)

当一个 Agent 运行时,它会进入一个推理循环。它会检查可用工具的描述,制定计划,选择合适的工具,生成输入,并执行该工具。工具的输出(即 observation,观察结果)会被再度反馈给 Agent,以继续后续推理。

这一架构形成了一个严格的层级体系:

Component → Pipeline → SuperComponent → Tool → Agent

接下来我们来分析这一层级结构的优缺点。

优势(可靠性)
这一层级确保了 Agent 的 action 步骤,背后依托的是一个健壮、类型安全的执行引擎。由于 Tool 是对一个经过验证的 Haystack Pipeline 的封装,因此 Agent 所编排的是可靠、确定性的工作单元,而不是脆弱的脚本。

劣势(上下文不透明)
正如我们在第 2 章中所探讨的,当前的上下文工程要求对 Agent 的状态与记忆进行精确控制,以防止上下文腐化(context rot)。而 Haystack 的 Agent 组件将推理循环封装在内部。这样的黑盒方式隐藏了状态,使得实现高级记忆整理策略,或像 LangGraph 那样的复杂状态管理,变得相当困难。

关键特性与优势

Haystack 2.0 在架构上的演进,带来了一整套特性,使其成为现代 AI 技术栈中“工具层(tool layer)”的理想引擎。这些优势直接来源于它的核心设计原则:显式图结构、类型化契约,以及模块化

透明性与可调试性(Transparency and debuggability)
这是面向生产工程最重要的优势。通过要求在带类型的组件 socket 之间建立显式连接,该框架消除了“不透明数据传递”所带来的歧义。开发者可以准确看到数据从哪里来、流向哪里。.draw() 方法进一步强化了这一点:它能够渲染出 Pipeline 的真实图结构,使调试不再是“猜哪里出了问题”,而变成一项标准的可检查任务。

通过有向图获得灵活性(Flexibility via DGs)
采用有向图(DG)抽象之后,系统就可以承载任意复杂度的工作流。简单的 RAG Pipeline 通常是线性的,但该框架原生支持非线性模式,例如条件路由(如“如果是 PDF,则使用 OCR;如果是纯文本,则跳过”)以及并行分支。这让你可以构建出能够优雅处理边界情况的健壮数据处理逻辑,而不是一遇到异常输入就中断。

可扩展性与部署能力(Scalability and deployment)
deepset 推出了 Hayhooks,这是一个配套框架,用于通过序列化并加载序列化后的 Pipeline,将 Haystack Pipeline 部署为 REST 端点。这样一来,Haystack 就成为了理想的能力提供者(capability provider):你可以构建复杂而确定性的工具,并让它们以独立微服务的形式运行。

支持 Agent 的架构(Agent-supporting architecture)
Haystack 2.0 的架构就是为了服务于 Agent 系统的后端而设计的。对内,它通过 SuperComponent 和 Tool 抽象,使你能够把任意组件——或者一个完整而复杂的 RAG Pipeline——封装成一个具有清晰描述、可被调用的能力单元。对外,当它与 Hayhooks 结合后,这些 Pipeline 就可以变成工具,并通过 Model Context Protocol(MCP) ——一个用于连接 AI 应用与外部系统的开源标准——被其他框架构建的 Agent 轻松消费。

可扩展性(Extensibility)
正如本章已经介绍的,以及我们将在第 5 章及后续章节中进一步看到的那样,创建能够与现有组件连接、并作为 Haystack Pipeline 一部分运行的自定义组件,路径非常直接。@component 装饰器为封装自定义逻辑提供了一个极简接口。这样低门槛的接入方式,鼓励采用微组件(micro-component)设计模式:将特定逻辑封装为可复用的小模块,而不是堆叠成庞大、难以维护的单体脚本。

完整生态(Comprehensive ecosystem)
Haystack 能够无缝集成到更广泛的 MLOps 生态中,从而避免厂商锁定(vendor lock-in)。它支持所有主流模型提供商(OpenAI、Hugging Face、Cohere、Azure、Google 和 Amazon),同时也提供与生产级向量数据库(Pinecone、Weaviate、Qdrant)以及评测框架(Ragas、DeepEval)的集成能力。

这些特性使 Haystack 成为一个健壮、灵活、可扩展的解决方案,能够用于构建 RAG 与数据处理工作流,并将其作为 Agent 系统的一部分来使用。接下来,我们来看看基于这些特性,能够落地哪些实际应用,以及常见的构建模式。

使用场景与应用

本节将从实用角度出发,介绍如何构建 2025 年 RAG 与 Agent 应用中最常见的一些模式,并展示如何将高层概念映射到具体的 Haystack 组件与 Pipeline 上。关注点将从“构建某一种单一系统”,转向“如何组合组件,以构建适配特定需求的解决方案”。

构建 RAG Pipeline

RAG 是现代 LLM 应用的基石。它使模型能够基于私有知识库来回答问题,从而减少幻觉,并提供最新、且有依据(grounded)的信息。Haystack 2.0 非常擅长构建 RAG 系统,它提供了从基础方案到最先进混合检索 Pipeline 所需的一整套组件。

在构建 RAG 系统时,一个关键概念是将关注点划分为两条不同的 Pipeline:索引 Pipeline(indexing pipeline)查询 Pipeline(query pipeline)

索引 Pipeline
这一过程负责你的知识库摄取(ingestion)与标准化(normalization)。它将原始输入——从非结构化 PDF、音频,到结构化 JSON——转换为可检索的向量,并存储到 DocumentStore 中。传统上,它通常被视作一个离线批处理任务;但借助 Haystack 2.0 的自定义组件架构,这类 Pipeline 也可以实时运行,例如通过自定义 consumer 组件,直接从 Kafka 这类事件流中触发摄取流程。

查询 Pipeline
这是一条在线、实时的 Pipeline,负责回答请求。它接收输入查询,从 DocumentStore 中检索相关的、有 grounding 的上下文,然后使用 LLM 来综合生成答案。尽管它经常直接由用户触发,但在我们的架构中,这条 Pipeline 更常作为一个“搜索工具”供 Agent 调用。其复杂度取决于所采用的策略;下面我们来看三种最常见的场景:语义检索、词法检索,以及混合检索

在构建现代 RAG 系统时,最重要的架构决策之一,就是如何进行检索。当前最有效的方法是混合检索(hybrid retrieval) 。这种策略将不同检索方式结合起来,以构建一个既强大又灵活的系统。

要理解为什么混合检索是必要的,我们首先要看看单一检索方法的局限性。用户查询可能从宽泛的概念性问题,一直到非常具体、字面精确的信息请求。一个健壮的 RAG 系统,必须能够有效覆盖这一整个范围。

语义检索:稀疏检索器(BM25)

传统搜索系统依赖基于关键词的检索,也就是稀疏检索(sparse retrieval) 。其中最常见的算法就是 BM25。这类系统的工作方式,是将用户查询中的精确词项与文档集合中的词项进行匹配。

优势:
稀疏检索速度快、效率高,而且当用户查询与源文档使用完全相同的措辞时,效果很好。它尤其适合查找包含特定产品编号、错误信息或唯一名称的文档。

劣势:
它最大的弱点是词汇不匹配问题(vocabulary mismatch problem) 。例如,如果用户搜索 “AI safety concerns”,稀疏检索器可能会漏掉一份谈论 “risks of artificial intelligence” 的关键文档,仅仅因为两者使用的关键词并不完全一致。换句话说,这类系统知道“词是什么”,却不知道“词是什么意思”。

稀疏检索器是传统搜索的基础。最流行的算法 BM25,本质上通过统计关键词来工作。它根据查询词在文档中的出现情况对文档排序,并使用一套更精细的加权机制来考虑词频与文档长度。

BM25 的主要优势在于:它简单却有效,而且无需任何模型训练即可开箱即用。在法律检索、技术文档等“精确措辞至关重要”的场景中,它表现尤为出色。它的主要弱点,则在于无法理解同义词或概念关系,因此一旦面对语言表达的多样性,就会显得脆弱。接下来我们看看另一种替代方案:稠密检索

词法检索:稠密检索器(Embeddings)

为了解决词汇不匹配问题,人们提出了稠密检索(dense retrieval) 。这种技术使用嵌入模型(embedding model),将查询与文档都转换为数值向量,也就是 embeddings。这些向量承载了文本的语义信息。系统随后会查找那些向量表示与查询向量最接近的文档。

优势:
稠密检索非常擅长理解细微语义、上下文以及用户意图。即便关键词完全不同,它也能够找到在概念上相关的文档。

劣势:
在捕捉广义语义的过程中,稠密检索有时会忽略某些具体、字面的词项。例如,搜索一个精确的错误代码,如 HTTP 404,系统可能返回的是关于一般 Web 服务器错误的文档,而不是那个真正包含该关键字符串的唯一文档。

稠密检索器把重点从“匹配关键词”转移到了“理解含义”。它们使用基于 Transformer 的模型,将文本转换为稠密向量表示。检索的过程,也就变成了在高维空间中,寻找与查询向量在几何上最接近的文档向量。

这类检索器能力很强,但也需要更多计算资源。对全部文档进行初始 embedding 本身,就是一个开销不小的前置任务。不过,它们最关键的优势,在于能够把握概念相似性,并克服词汇不匹配问题。为了在数百万文档规模上高效检索,它们通常会结合专用向量数据库,以及近似最近邻(ANN)算法来使用。

表 3.2 对这两类检索方法做了总结性对比。

表 3.2 —— 稀疏检索 vs 稠密检索
特性稀疏(BM25)稠密(Embeddings)
核心原理词项级匹配(加权关键词计数)语义概念匹配(向量邻近性)
表示形式高维稀疏向量(倒排索引)低维稠密向量
优势对关键词精度高,计算成本低,无需训练可处理同义词与概念,理解语义结构,对词汇不匹配更鲁棒
劣势词汇不匹配,不理解语义,脆弱可能漏掉特定关键词,计算成本高,需要训练数据
计算特征建索引快;查询极快建索引慢(需生成 embedding);查询快(借助 ANN)
适用场景法律检索、产品代码、带特定术语或专名的查询通用问答、主题探索、概念型检索

正如你所看到的,稀疏检索与稠密检索的弱点是互补的。一个方法失效的地方,另一个方法往往可以奏效。这也正是为什么最健壮的 RAG 系统会将两者的优势结合起来。一个最先进的系统,必须既能够处理“机器意识的哲学含义是什么?”这样的概念型查询,也能够处理“找出提到 ‘Project Chimera’ 和 ‘Q3 2023’ 的文档”这样的精确查询,而且两者都要处理得同样出色。

因此,混合检索并不只是一次技术升级;它是构建适应人类多样化信息查询方式的系统时,一项核心设计原则。接下来我们就深入看这一技术。

混合检索

当你理解了各个单独组件之后,下一步就是设计一个能够融合它们结果的系统。为此主要有两种架构模式:一种是由你掌控、更加灵活的 Pipeline 模式;另一种是集成在数据库内部的、更加流线化的模式。

最常见、也最灵活的,是 Pipeline 模式。在这种模式中,应用代码通过一系列步骤来编排整个过程:

并行召回(Parallel fetch)
用户查询会同时发送给稀疏检索器(如 BM25)和稠密检索器。每个检索器都返回自己排序后的候选文档列表。

融合(Fusion)
将两份结果列表合并为一个结果集。最简单的方法是把两份列表合起来并去重。更高级、也更有效的方法是 Reciprocal Rank Fusion(RRF) ,它根据文档在各自列表中的排名位置来重新排序,从而避免了直接比较两种不同打分体系这一复杂问题。

重排(Reranking)
合并后的候选列表会被送入一个最终的 reranker 模型(通常是类似 BAAI/bge-reranker-base 这样的 Transformer 模型)。这通常是一个 cross-encoder:它将查询和每篇文档一起输入,从而给出更精确的相关性评分。这个步骤计算成本较高,但至关重要,因为它负责从候选集中筛出最相关的结果,再把这些结果传递给语言模型。

这个过程中的每一步,都可以映射为 Pipeline 中的一个组件,如相关示意图所示。下一节我们来看,这一过程是如何具体映射的。

构建高级 RAG Pipeline

这个示例采用的是客户端侧融合(client-side fusion) 模式,展示了 Haystack 的模块化架构如何让组件组合变得简单。整个 Pipeline 被设置为一个图:用户查询沿着两条并行分支流动,一条用于稀疏检索,另一条用于稠密检索。随后,两边结果被合并,经过重排以提高精度,最后发送给生成器来构造答案。

稀疏检索分支(Sparse retrieval branch)
这是关键词精确匹配引擎。它执行 BM25 检索,以找到那些包含查询中精确词项的文档。

稠密检索分支(Dense retrieval branch)
这一分支负责语义检索。Embedder 组件将查询转化为向量,基于 embedding 的检索器则利用这个向量,找到在概念上相近的文档。

融合组件(Fusion component)
该组件接收两条分支返回的文档列表,将它们合并,并去除重复项。

重排组件(Re-ranking component)
这是精度引擎。它使用 cross-encoder 模型,将查询与每个候选文档一起编码,从而生成一个最终的、高精度的相关性排序结果。

生成阶段(Generation stage)
最终得到的高质量文档列表,会先通过 prompt builder 组件组织成 Prompt,然后发送给 LLM generator 组件,由 LLM 对这些信息进行综合并生成最终答案。

下一章中,我们会更深入地探讨:如何导入和初始化这些现成组件,并将它们连接成 Pipeline。现在,我们来看另一个 Haystack 2.0 特别适合的使用场景:Agent 应用与 Agentic RAG

开发 Agent 系统

Haystack 2.0 中 Agent 与 Tool 的引入,代表着应用开发方式的一次根本性转变——无论你选择哪种架构模式。它将开发者的角色,从“为人类严格搭建 Pipeline 的构建者”,转变为“为 Agent 提供能力的提供者(capability provider)”。

对于使用 Haystack 原生 Agent 能力的开发者来说,这种转变意味着:你可以创建一组健壮、描述清晰的工具,然后把动态编排这些工具的工作,交给框架内部由 LLM 驱动的单 Agent 或多 Agent 系统。这种方式简化了复杂性,使系统能够处理那些事先未预料到的查询,而无需为每个边界场景显式重新编程。

而对于偏好 LangGraph 那种细粒度状态控制的开发者来说,通过将 Haystack Pipeline 序列化,并借助 Hayhooks 或 MCP Server 进行部署,你就把 Haystack 从一个本地库,转变为了一个由确定性微服务构成的健壮引擎。

在这两种架构里,结果其实是一样的:你都在构建一组可靠、自治、可被推理引擎发现并调用的“智能能力单元”。

不过,这种转变也带来了新的挑战与机会。调试不再只是检查组件之间的数据流;它还包括分析 LLM 的推理轨迹(reasoning trace,也就是一连串思考与工具选择),以理解它为什么会以某种方式行动。Prompt Engineering 的艺术也随之扩展:它不再只是为最终答案生成编写一个好 Prompt,而是还要为工具撰写清晰、有效的描述,以便正确引导 Agent 的推理过程。

将 RAG 作为工具

Haystack 2.0 的可组合性(composability),让它可以非常轻松地从 Pipeline 过渡到 Agent。前一节中构建的那个最先进的混合 RAG Pipeline,可以整体封装成一个单独的工具。做法是创建一个 Tool 实例,并向其提供以下信息:

  • Nameinternal_knowledge_search
  • Description:使用此工具搜索我们的公司内部文档数据库。它是获取产品信息、内部政策以及历史项目数据的最佳来源。输入应是一个清晰、具体的问题。
  • Instancehybrid_rag_pipeline 对象本身。

这样一来,原本复杂的、多步骤的混合检索过程,就被抽象成了一个可供 Agent 调用的单一能力。我们还可以在此基础上,进一步扩展为多工具的 Agent 系统。

构建多工具 Agent

当 Agent 拥有多个彼此不同的工具时,它的真正威力才会显现。比如,我们可以再创建第二个工具,用于搜索实时 Web:

首先,使用 Serper Web Search 组件构建一个简单 Pipeline;它集成了一个低成本的 Google Search API。
然后,将该 Pipeline 再封装成另一个工具:

  • Nameweb_search
  • Description:使用此工具从公共互联网获取最新信息。它最适合用于当前事件、竞品新闻,或不特定于我们公司的通识性问题。
  • Instanceweb_search_pipeline 对象。

当这个 Agent 接收到一个复杂查询,例如:

“总结我们的内部 Q3 业绩报告,并将我们核心产品的功能与头号竞争对手的最新版本做对比。”

它就可以这样进行推理:

Thought:
这个查询包含两部分。第一部分涉及内部报告。internal_knowledge_search 工具的描述表明,它最适合处理这类任务。

Action:
Agent 使用输入 Q3 performance report 调用 internal_knowledge_search 工具。

Observation:
它从 RAG Pipeline 中得到了该报告的摘要。

Thought:
现在我需要找到关于竞争对手最新版本的信息。这是外部的、近期的信息。web_search 工具最适合处理。

Action:
Agent 使用输入 competitor X latest product release features 调用 web_search 工具。

Observation:
它收到了一个 Web 搜索结果列表。

Thought:
现在我已经拥有了所需的全部信息。接下来我会把内部报告摘要与竞争对手功能列表综合起来,生成最终答案。

Final answer:
Agent 生成一份综合性的回答,完整覆盖用户原始查询中的两部分需求。

这种方法还可以进一步推广到 Haystack 之外:你可以在设计 Agent 系统时,让多 Agent 系统中的每个 Agent,都配对一个或多个以 REST 端点形式部署、或通过 MCP Server 提供服务的 Haystack Pipeline。

接下来,我们将看看:如何在你的 RAG、高级 RAG 与 Agentic RAG 工作流中,具体引入 Haystack。要把 Pipeline 构建成可靠的工具或可部署端点,你必须先牢牢掌握 Haystack 所提供的那些现成、可直接使用的组件。

深入解析 Haystack 2.0 的架构

本节将对 Haystack 2.0 中可用的数据结构以及现成组件(ready-made components)做一个全面概览。其关键数据结构包括:用于表示文档、以存储文本的 Python 对象;用于存储图像、音频和基于 HTML 数据的字节流对象(byte stream objects);以及用于表示人与 LLM 之间聊天消息的对象。随后,这些数据结构可以通过文档存储(document stores)来组织和管理,并借助 Haystack 预定义组件与自定义组件进行处理。

我们将先从组件与 Pipeline 背后的基础构建块开始:数据类(data classes)

数据类

在深入组件之前,首先必须理解在它们之间流动的核心数据结构。Haystack 提供了一组定义良好的数据类,用于表示在 Pipeline 中被处理的对象:

Document
这是最基础的数据类。它封装了一段可被处理和存储的数据。一个 Document 对象可以包含文本(content)或二进制数据(blob),同时还可以携带唯一 ID、自定义元数据、相关性分数、稠密向量 embedding,以及用于混合检索场景的 sparse_embedding

ByteStream
用于表示尚未转换为文本之前的原始二进制数据,例如图像或 PDF 文件。它包含字节形式的数据,以及关联的元数据,其中包括 mime_type(例如 image/png)。

ChatMessage
用于构建对话式应用与 Agent。与简单的文本字符串不同,ChatMessage 是一种结构化对象,可以包含多模态内容,包括文本、图像(ImageContent)、工具调用(ToolCall)以及工具调用结果(ToolCallResult)。它还会显式定义发送方角色(userassistantsystemtool)。

StreamingChunk
这是一个用于处理实时响应的专用类。它封装了一段流式内容中的单个片段(例如一个 token),并附带相关元数据以及可能的工具调用增量(tool call deltas),从而支持流畅、低延迟的用户体验。

Answer
这是一组用于表示 Pipeline 最终输出结果的类:

  • GeneratedAnswer:表示由 LLM 生成的答案,包含答案字符串,以及用于生成该答案的源 Document 对象列表。
  • ExtractedAnswer:用于抽取式问答系统,表示从源文档中直接抽取出的某一段特定文本片段。

这些核心数据类(DocumentByteStreamChatMessageStreamingChunkAnswer)构成了 Haystack Pipeline 的“生命线”。它们代表了在组件之间严格流动的标准化信息。在任何 RAG 系统中,最关键的组件之一,就是负责承载这些文档的那一层。

文档存储(Document stores)

DocumentStore 是用于存放 Document 对象、供后续检索使用的数据库后端。Haystack 的架构清晰地区分了存储层(DocumentStore)访问层(retriever)DocumentStore 在 Pipeline 外部进行配置和管理,而在 Pipeline 内部,则通过对应的 retriever 组件从中取回数据。

Haystack 支持多种文档存储方案,包括适合快速原型开发的内存型选项,以及多种生产级向量数据库:

内存型:
(原文此处为分类项,后文承接具体类型)

向量数据库:
ChromaDocumentStorePineconeDocumentStoreWeaviateDocumentStoreQdrantDocumentStoreMilvusDocumentStore

传统搜索引擎:
ElasticsearchDocumentStoreOpenSearchDocumentStore

其他数据库:
AstraDocumentStore(Cassandra)、MongoDBAtlasDocumentStore 以及 Neo4jDocumentStore(图数据库)

如何选择合适的 DocumentStore,是一个关键的架构决策,取决于你的项目规模以及既有基础设施。在定义了数据类与存储层之后,我们就可以来考察那些真正执行工作的各类组件了。支持的 DocumentStore 列表可在其 integrations 页面中查看。Haystack 也支持创建自定义文档存储,相关指南同样已提供。

组件类别

接下来我们看看 Haystack 2.0 中已有的组件。这些组件构成了搭建任意 Pipeline 或 Agent 的基本积木。它们会根据在典型端到端工作流中的功能,被组织为若干逻辑类别,如图 3.4 所示。

image.png

预定义组件(pre-defined components)可以分为以下几类:数据预处理组件、Embedding 组件、检索组件、LLM 生成组件、路由组件,以及 Agentic 功能组件。同时,我们还可以通过自定义组件扩展 Haystack 的能力。第 5 章中我们将对此做深入探讨。下面先展开介绍几个关键组件类别。

数据预处理组件

这些组件通常出现在索引 Pipeline 的最前面,负责摄取原始数据,并将其整理为可供 embedding 和存储使用的形式。

文件转换器(File converters)

Web 组件:
该组件从一组 Web URL 中抓取内容,并返回 ByteStream 对象。

预处理组件(Preprocessing components):
用于准备数据,例如规范化空白字符、移除页眉页脚、清理文档中的空行,或将文档切分成更小的片段。

音频组件(Audio components):
用于将音频文件转写为文本。

这些转换器和预处理组件,是任何 RAG Pipeline 中“摄取(ingestion)”阶段的核心。一旦文档被清洗并切分完毕,下一步就是把它们的语义信息转换为数据库可检索的形式。

数据 Embedding 组件

Embedder 是一类使用深度学习模型将文本转换为数值向量表示的组件。Haystack 为文档 embedding(用于索引)和查询 embedding(用于搜索)分别提供不同组件,因为有些模型在这两类任务上的最优设置并不相同。

OpenAI:
OpenAIDocumentEmbedder

Sentence Transformers:
SentenceTransformersDocumentEmbedderSentenceTransformersTextEmbedder。这两个组件可以加载 Hugging Face Hub 上任意兼容的模型,因此具有极高的灵活性。

其他提供商:
Haystack 正在不断扩展与其他 embedding 模型提供商的集成,例如 Cohere 与 Hugging Face。完整列表可在官方文档中查看。

Embedder 组件负责为索引与搜索创建向量表示。文档在处理并完成 embedding 之后,就需要被写入 DocumentStore

DocumentWriter
这是大多数索引 Pipeline 中的最后一步。它接收一个 Document 对象列表,并将其写入指定的 DocumentStore。它还提供了处理重复文档的策略(例如跳过、覆盖或报错)。它承担了索引 Pipeline 的最终写入步骤。

接下来我们进入查询 Pipeline 使用的组件,从负责取回数据的那一类开始。

数据检索组件

Retriever 是任何搜索或 RAG 应用的核心。它负责根据查询,从 DocumentStore 中取回一小批相关文档。它既支持基于 embedding 的搜索,也支持基于关键词的搜索。Haystack 2.0 支持适配多种数据库提供商的 retriever。完整的 retriever 列表可在官方文档中查看。

Retriever 完成的是“第一轮召回”这一关键步骤,即找出一批可能相关的文档。而在高级 RAG Pipeline 中,这批初始结果通常还需要进一步优化,以提升最终质量。

虽然 retriever 负责抓取相关信息,但 ranker 则用于通过重新排序 retriever 返回的文档,进一步提升搜索结果的质量。它是高级 RAG Pipeline 中的关键组件之一。Ranker 帮助确保最相关的文档能够被传递到最后阶段。这个最后阶段,则是构建 Prompt 并调用 LLM 生成最终答案。支持的 ranker 完整列表同样可在官方文档中查看。

接下来,我们转向那些让 LLM 能够利用检索到的上下文增强回答能力的组件。

LLM 生成组件

这类组件负责与 LLM 交互以生成文本,并负责构建引导 LLM 的 Prompt。

Generators:
包括 OpenAIGeneratorHuggingFaceTGIGeneratorAnthropicGenerator。这些组件负责向不同的 LLM 提供商发起 API 调用,接收 Prompt,并返回生成出的文本响应。支持的提供商完整列表可在官方文档中查看。

Builders:
这类组件帮助我们围绕 Pipeline 构造高质量 Prompt。

  • PromptBuilder:一个灵活的组件,用于基于模板创建 Prompt。它可以把查询、检索到的文档等变量填入预定义的 Prompt 结构中,从而保证 Prompt 的一致性与有效性。
  • AnswerBuilder:一个工具型组件,用于从 generator 输出的原始文本中解析出结构化的 Answer 对象,通常会借助正则表达式。
  • ChatPromptBuilder:一种专门面向聊天类应用的 builder。

这些组件共同承担了 RAG Pipeline 中最后的“生成”环节。为了构建更复杂、非线性的工作流——例如我们前面讨论过的混合检索 Pipeline——Haystack 还提供了处理逻辑与控制流的组件。

路由组件

这类组件对于构建由 DG 架构支持的复杂、非线性 Pipeline 至关重要。Router 是一组用于将查询或文档路由到最适合处理它们的其他组件的组件;而 Joiner 则允许我们对文档、数据结构,甚至整个 Pipeline 进行合并。

  • Joiners
  • Routers

Router 与 Joiner 就像是实现复杂 DAG 的“管道系统(plumbing)”。最后,还有一类更高层的组件,用来支撑我们前面讨论过的、基于推理的动态系统,也就是 Agentic 工作流。

Agentic 组件

这是用于构建 Agent 系统的高层组件:

Agent
核心推理引擎。它接收一个查询和一个工具列表,并通过编排这些工具来生成答案。

ToolInvoker
用于执行由语言模型准备好的工具调用。

这些组件共同构成了一整套完整工具箱,使你能够从简单搜索一路构建到复杂 Agent 系统。当我们已经清楚理解所有可用构建块之后,接下来就可以为如何在自己的项目中使用它们,勾勒出一套结构化流程。

将 Haystack 融入你的工作流

将 Haystack 2.0 这样的框架集成到你的项目中,需要采取一种结构化的方法。本节将提供一份分步骤指南,帮助你从初始评估,一路推进到 NLP 应用的设计与排障。

评估你当前的数据系统

在编写任何代码之前,第一步是对项目需求与现有基础设施做一次彻底评估。这一基础性分析将指导你的设计决策,并确保集成过程更加顺畅:

明确 NLP 目标:
清晰说明你想要实现什么。你是在为内部文档构建一个问答系统,为客户支持构建一个聊天机器人,还是在构建一个用于自动化业务流程的自主 Agent?你的目标将决定你需要构建的 Pipeline 复杂度。

评估数据源:
识别你的数据类型与来源。它们是存放在数据库中的结构化数据,还是散落在 PDF、Word 文档和 HTML 文件中的非结构化文本?理解你的数据版图,对于选择合适的转换器与预处理组件至关重要。

评估基础设施与兼容性:
考虑你的部署环境。应用将运行在本地(on-premises)还是云上?梳理你现有的数据库系统,并检查它们与 Haystack DocumentStore 集成方案之间的兼容性。如果你计划使用 Pinecone 或 Weaviate 这类向量数据库,要确保你的基础设施能够支持它们。

考虑数据动态性与治理:
你的数据更新频率如何?一个建立在静态季度报告之上的系统,与一个需要处理实时数据流的系统,在索引策略上会完全不同。此外,还需要评估数据的敏感性。预先建立清晰的数据治理与安全流程,对于管理敏感信息、规划成本以及维护用户信任都至关重要。

这一步的初始评估,对于界定项目范围与技术要求至关重要。一旦你明确了目标,并理解了数据状况,就可以开始设计 Pipeline 本身了。

使用 Haystack 2.0 设计你的 NLP Pipeline

当你已经清楚理解自身需求后,就可以开始设计 Pipeline。Haystack 2.0 显式、基于图的特性,非常适合采用“先可视化、后编码”的设计方式。

以下步骤可以帮助你把项目目标落到 Haystack 2.0 框架中:

先画出图:
在写代码之前,先在白板上或制图工具中画出你期望的工作流。把每一个处理步骤表示为一个节点(即一个组件),再用箭头表示它们之间的数据流向。这样的可视化表示有助于厘清逻辑,并识别所需组件。比如,一个混合 RAG 查询 Pipeline 的草图,会画出查询被拆分为两条并行的 retriever 路径,然后在 joiner 处合并,再流经 ranker,最后进入 generator。

将草图翻译为代码:
有了可视化图作为指导,将其转换为一个 Haystack Pipeline 对象就会变得相对直接:

  • 实例化或定义图中的每个节点 / 组件
  • 实例化 Pipeline
  • 针对草图中的每个节点,使用 pipe.add_component() 添加对应组件实例
  • 针对草图中的每条箭头,使用 pipe.connect() 将组件 socket 连接起来

使用 .draw() 验证:
在代码中定义完 Pipeline 后,立刻运行 pipe.draw("pipeline_design.png")。将生成的图像与你最初的草图进行对比。这个简单的验证步骤可以尽早发现连接逻辑中的错误,并确保代码准确反映了你的设计意图。

这种“可视化优先、迭代推进”的设计过程,有助于确保代码与预期逻辑保持一致。对于刚接触 Haystack 2.0 的团队来说,一开始就挑战全部复杂性可能会令人望而生畏,因此更推荐采用渐进式开发路径。

推荐的开发路线图

对于刚接触 Haystack 2.0 的开发者来说,循序渐进地增加复杂度会更有帮助。推荐的学习路径如下:

构建索引 Pipeline:
先聚焦于数据准备。创建一条能够顺利接收原始源文件、对其进行处理、生成 embedding,并将结果写入所选 DocumentStore 的 Pipeline。把这一部分做好,是任何 RAG 系统成功的基础。

构建一个朴素的语义 RAG Pipeline:
当数据已经完成索引后,构建最简单可行的查询 Pipeline:对查询做 embedding、通过向量相似度检索文档,并生成答案。这样你就会得到一个端到端可工作的基线系统。

增强为混合 RAG Pipeline:
在基线之上,通过实现混合检索策略来提升系统能力。增加一条并行的 BM25 检索路径,将结果合并,再加入 reranker,以提升送入 LLM 的上下文质量。到了这个阶段,你就拥有了一个达到业界先进水平的 RAG 系统。

评估朴素方案与混合方案的质量差异:
一种常见做法是使用 Ragas 这类框架:先从知识库中生成知识图谱,再构造人物画像(personas),并选择查询策略来生成问答对,然后再将这些问答对与 RAG Pipeline 的实际回答进行系统性评估。我们会在实战项目中把这一部分纳入进去。

进阶为可供 Agent 调用的工具:
最后一步,是将你的高级混合 RAG Pipeline 封装成一个工具。你可以先在本地把它交给一个标准 Haystack Agent 进行验证。验证通过后,迈向生产环境的最终一步——也是本书架构层面的重点——就是:将该 Pipeline 序列化,通过 Hayhooks 部署为一个 REST 微服务,然后把这个端点交给像 LangGraph 这样的有状态编排器。

这种增量式方法,使你能够从数据索引一直到完全可用的 Agent,逐步构建并验证系统的每一个部分。和任何复杂软件一样,在这个过程中你几乎一定会遇到问题。

常见问题排查

即使系统设计得再好,问题也依然会出现。高效排障,是构建健壮应用的关键。表 3.3 总结了常见问题及其可能的修复方式。

表 3.3 —— 常见错误、可能原因与可能修复方式

常见问题可能原因可能的修复方式
数据摄取与处理错误文件路径不正确,或预处理组件中的 chunk size 配置不合理密切关注 converter 与 preprocessor 组件的日志,定位错误来源。确保文件路径正确,并调整 chunk size。
Pipeline 连接错误:PipelineConnectError尝试连接数据类型不兼容的 socket,或连接了一个不存在的 socket使用 .draw() 方法对连接关系进行可视化检查,并确保它们与组件定义一致。
模型与性能瓶颈较重的模型(如 embedder、ranker)在处理前未初始化,或者 LLM 生成本身延迟较高在处理请求前,对重型组件调用 warm_up() 方法。对于 LLM 延迟问题,可考虑使用 streaming 来改善用户体验。
Agent 行为异常工具描述措辞不佳或含义模糊,导致 Agent 推理被误导在日志中检查 Agent 的推理轨迹(thoughts、tool selections 和 observations)。优化定义工具能力的自然语言提示。
数据安全与隐私风险将 API key / 凭据硬编码,或忽视了数据驻留与合规要求通过环境变量或密钥管理系统安全管理凭据。在使用云端提供商时,务必注意合规要求。

能够有效调试确定性 Pipeline动态 Agent,是构建可靠应用的一项关键技能。最后,所有开发工作的一个根本前提,是确保数据的安全与隐私。遵循这些排障与安全最佳实践,将帮助你构建健壮、可投入生产的系统。

下面,让我们通过总结本章内容来收尾。

小结

本章中,我们介绍了 deepset 及其旗舰开源框架 Haystack。我们回顾了它的发展历程:从以 BERT 等可微调模型为核心、依托 FARM 等框架的时代起步,到彻底完成架构重生,演进为面向现代 LLM 生态而设计的 Haystack 2.0。

我们重点聚焦于 Haystack 2.0,认为它是一个用于构建端到端 NLP 应用的一流 Python 包。我们也看到,它的能力远不止简单搜索,而是足以支撑复杂问答系统、高级 RAG Pipeline,以及动态、自主 Agent 的构建。Haystack 2.0 的核心力量,来自其全新的构建块:

Components:
使用 @component 装饰的简单、可复用 Python 类,每个类只执行一个单一且定义明确的任务。

Pipelines:
显式的、Python 原生的 DAG,用于将组件编排成复杂、非线性的工作流。

SuperComponents:
一种预打包、可复用的 Pipeline,在更大的 Pipeline 中可以被当作单一组件来使用。

Agents 与 tools:
最高层次的抽象。由 LLM 驱动的 Agent,会从一组可用工具(被包装后的组件或 Pipeline)中动态做出选择,并通过推理逐步走向解决方案。

我们还探讨了如何在真实工作流中引入 Haystack:从全面评估数据与基础设施需求开始,到详细说明一种实用的、可视化优先的 Pipeline 设计方法,再到给出一条清晰的开发路线图——从基础索引 Pipeline,一直走到多工具 Agent 的部署。

通过这一整套全面梳理,我们了解到:Haystack 2.0 为那些希望构建下一代 LLM 驱动应用的开发者,提供了一个透明、灵活而强大的基础。在下一章中,我们将进一步深入到具体实现层面,把这些组件真正组装成可运行的 Pipeline,并通过动手代码示例来探索常见使用场景。

延伸阅读

Jiao, X., Yin, Y., Shang, L., Jiang, X., Chen, X., Li, L., Wang, F., & Liu, Q. (2020). TinyBERT: Distilling BERT for Natural Language Understanding.
aclanthology.org/2020.findin…

Devlin, J., Chang, M.-W., Lee, K., & Toutanova, K. (2019). BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding.
arxiv.org/abs/1810.04…

Wiggers, K. (2022, April 28). Deepset raises $14M to help companies build NLP apps. TechCrunch.
techcrunch.com/2022/04/28/…

Liu, Y., Ott, M., Goyal, N., Du, J., Joshi, M., Chen, D., Levy, O., Lewis, M., Zettlemoyer, L., & Stoyanov, V. (2019). RoBERTa: A Robustly Optimized BERT Pretraining Approach. arXiv:1907.11692.
arxiv.org/abs/1907.11…

Model Context Protocol (MCP). What is the Model Context Protocol (MCP)?
modelcontextprotocol.io/docs/gettin…

Sourcely. (2025, June). BM25 and Its Role in Document Relevance Scoring.
www.sourcely.net/resources/b…