news 2026/9/14 18:54:52

Haystack Agent Pack 实战指南:构建 Advanced RAG 与 Deep Research Agent

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Haystack Agent Pack 实战指南:构建 Advanced RAG 与 Deep Research Agent

Haystack Agent Pack 实战指南:构建 Advanced RAG 与 Deep Research Agent

【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack

本篇技术文章围绕 Haystack Agent Pack 集成包展开:它是构建在 HaystackAgent组件之上的一套「开箱即用」Agent 工厂,提供 Advanced RAG Agent(基于文档库的检索增强问答)与 Deep Research Agent(多子研究者并行深度调研)两种预制 Agent。读完本文,你将掌握两个工厂函数的完整参数语义、Agent Pack 对文档库元数据内省接口的依赖关系、FetchDocumentsByFilterTool等工具的内部行为,以及BackupAnswerHook这类钩子如何与 Haystack Agent 的after_run钩子点配合,保证 Agent 运行在步数耗尽时也能产出兜底答案。

Agent Pack 的定位与源码边界

Agent Pack 是独立发布的集成包(haystack_integrations.agent_pack命名空间),不在本仓库haystack/核心源码树内,本仓库中它的存在体现为 API 参考文档 agent_pack.md。它的全部能力都建立在本仓库提供的基础设施之上:

  • Agent组件:实现于 agent.py,提供带工具调用循环、状态管理(State)与钩子点的 Agent 运行时;
  • Tool/Toolset:Agent Pack 的检索与元数据工具均以Tool为基类,并以DocumentStoreToolset形式成组交付;
  • Hook协议:实现于 protocol.py,定义before_runbefore_llmbefore_toolafter_toolon_exitafter_run六个钩子点(见 HookPoint 定义),Agent Pack 的BackupAnswerHook正是注册在after_run钩子点上。

理解这层基础,才能理解 Agent Pack 各参数的设计意图。

Agent 运行循环:Agent Pack 各参数的作用点

从源码看,Agent.run的核心是一个受max_agent_steps约束的循环(run 方法实现):

before_run 钩子 └─ while counter < max_agent_steps: 调用 LLM → 执行模型请求的工具调用 → counter += 1 (任一步满足退出条件则 break) 若循环耗尽步数未 break → exit_reason 置为 "max_agent_steps" after_run 钩子 返回状态中的公开输出(messages、last_message、step_count、token_usage、tool_call_counts、exit_reason 等)

两个关键点与 Agent Pack 直接相关:

  1. max_agent_steps是循环的硬上限。当 Agent 在步数耗尽时停在工具调用或工具结果上(没有助手文本答案)时,源码会把exit_reason设为"max_agent_steps"(见 循环耗尽分支),随后仍会执行AFTER_RUN钩子——这就是BackupAnswerHook能介入的唯一时机;
  2. clone支持以覆盖参数方式派生新 Agent(clone 实现):它通过内省__init__签名取出当前实例的所有参数,再用传入的 overrides 替换,因此agent.clone(tools=[*agent.tools, my_tool])这类写法可以安全地给 Agent Pack 返回的预制 Agent 追加工具或钩子而不改动原对象。Agent Pack 文档中「进一步定制」的推荐做法即基于此。

Advanced RAG Agent:create_advanced_rag_agent

函数签名

create_advanced_rag_agent( *, document_store: DocumentStore, retriever: TextRetriever | Pipeline | None = None, retrieval_pipeline_input_mapping: dict[str, list[str]] | None = None, retrieval_pipeline_output_mapping: dict[str, str] | None = None, llm: ChatGenerator | None = None, backup_answer_llm: ChatGenerator | None = None, system_prompt: str | None = None, max_agent_steps: int = 20, max_fetched_docs: int = 10, ) -> Agent

其设计目标与普通 RAG 管线不同:Agent 回答问题时不靠开发者预先假设文档库中有哪些元数据字段,而是可以先内省文档库(字段、取值、数值范围),在元数据确实有助于缩小检索范围时动态构造 Haystack filter;当元数据帮不上忙时,仍可直接做无过滤的相关性检索。答案中对引用文档以 id 前 8 个字符标注,例如[doc a1b2c3d4]

参数说明

参数类型说明
document_storeDocumentStore元数据内省工具与fetch_documents_by_filter工具操作的文档库。必须实现元数据内省方法(get_metadata_fields_infoget_metadata_field_unique_valuesget_metadata_field_min_max),否则无法工作。
retrieverTextRetriever \| Pipeline \| None实际必填。成为search_documents工具。可传满足TextRetriever协议的独立检索组件(即run方法接受queryfilters,如InMemoryBM25Retriever,或用TextEmbeddingRetriever包装的向量检索器),也可以传自定义检索Pipeline(如 embedder -> retriever 或混合检索)。应基于相关性打分检索(关键词或向量)——无打分的直接取回已由内置fetch_documents_by_filter工具覆盖。
retrieval_pipeline_input_mappingdict[str, list[str]] \| NoneretrieverPipeline时必填:把工具输入映射到管线输入 socket,键必须恰好为"query""filters",例如{"query": ["embedder.text"], "filters": ["retriever.filters"]}
retrieval_pipeline_output_mappingdict[str, str] \| NoneretrieverPipeline时可选:把管线输出 socket 映射到工具输出,例如{"retriever.documents": "documents"}
llmChatGenerator \| None驱动 Agent 循环的 LLM。默认OpenAIResponsesChatGenerator("gpt-5.4"),低推理强度。
backup_answer_llmChatGenerator \| None内置BackupAnswerHook在运行被max_agent_steps截断时撰写兜底答案所用的 LLM。默认是另一个独立的OpenAIResponsesChatGenerator("gpt-5.4"),低推理强度。
system_promptstr \| None覆盖预制的系统提示词。
max_agent_stepsintAgent 循环最大步数(默认 20)。若循环在该上限前被截断且尚未写出答案,after_run钩子(BackupAnswerHook)会额外发起一次 LLM 调用,基于已收集的证据尽力给出答案,从而保证last_message始终携带文本答案。
max_fetched_docsintfetch_documents_by_filter单次取回展示给 Agent 的文档数上限(默认 10)。过滤取回不受检索器top_k约束,因此用它来封顶工具结果;而打分检索的search_documents则由检索组件自身配置的top_k限制。

返回值与调用方式

工厂函数返回一个Agent。调用方式:

agent = create_advanced_rag_agent(document_store=doc_store, retriever=retriever) result = agent.run(messages=[ChatMessage.from_user(question)]) answer = result["last_message"] # ChatMessage,答案文本(含 [doc xxxxxxxx] 引用) docs = result["documents"] # 本次运行中取回的全部文档:按 id 去重、按首次取回顺序排列 # 同时还有标准 Agent 输出:messages、step_count、token_usage、tool_call_counts

这些标准输出与源码中Agent的运行元数据状态键一一对应(step_counttoken_usagetool_call_counts等,见 运行元数据定义),exit_reason可用于判断本次运行是正常以文本退出("text")还是被步数耗尽截断("max_agent_steps")。

需要追加工具或钩子时,使用Agent.clone

agent = agent.clone(tools=[*agent.tools, my_tool])

文档库元数据内省接口

Advanced RAG Agent 对document_store的要求是本仓库核心能力的一个体现:文档库需要实现元数据内省方法。以内置的InMemoryDocumentStore为例(document_store.py):

方法作用实现要点
get_metadata_fields_info返回库中所有元数据字段及其类型类型从存储值推断:boolbooleanintintfloatfloat、其余 →keyword
get_metadata_field_min_max返回某元数据字段的最小/最大值支持带或不带meta.前缀的字段名;无可比较值时返回{"min": None, "max": None}
get_metadata_field_unique_values返回某字段的去重取值支持search_term子串匹配、from_/size分页,并支持filters限定参与统计的文档
count_documents_by_filter统计命中过滤条件的文档数FetchDocumentsByFilterTool的拒绝机制依赖此方法

这套接口的实际意义:Agent 可以先调用list_metadata_fields知道「库里有哪些字段、什么类型」,再调用get_metadata_field_valuesget_metadata_field_range知道「字段里有哪些值、数值范围多大」,最后据此写出合法的 Haystack filter 传给search_documentsfetch_documents_by_filter,避免了传统 RAG 中「开发者必须提前硬编码元数据假设」的脆弱性。其他集成文档库(pgvector、qdrant、weaviate 等)在各自参考文档中也声明了对应的内省方法支持。

Advanced RAG 的四个工具与 DocumentStoreToolset

三个元数据内省工具

三者均为Tool基类的子类,构造时都接收一个document_store,并在 store 未实现相应内省方法时抛出ValueError,且都提供to_dict/from_dict序列化方法:

  1. ListMetadataFieldsTool:列出文档库所有元数据字段及类型,依赖get_metadata_fields_info
  2. GetMetadataFieldValuesTool:返回某元数据字段的去重取值,依赖get_metadata_field_unique_values
  3. GetMetadataFieldRangeTool:返回某元数据字段的最小/最大值,依赖get_metadata_field_min_max

FetchDocumentsByFilterTool

这是与打分检索互补的「直接取回」工具,按元数据 filter 从文档库取文档,不做相关性排序——适合「已知确切标题或源文件」这类按身份取回的场景,无需走相关性搜索。

__init__( document_store: DocumentStore, max_docs: int = 10, max_fetch_factor: int = 10, )
  • document_store:取文档的文档库;
  • max_docs:每次取回展示给 Agent 的文档数上限。过滤取回没有检索器top_k约束,因此用此值封顶工具结果。LLM 可通过工具的可选max_docs输入请求更少的文档,但不能超过该上限;
  • max_fetch_factor:允许命中的文档数达到max_docs的多少倍后直接拒绝取回(前提是 store 支持count_documents_by_filter)。拒绝会以错误形式呈现给 LLM,提示其收窄 filter 后重试,避免一次取回过多无关文档。

行为上的两个细节值得注意:

  • 阅读顺序重排:取回的文档先按父文件分组(依次尝试file_name/file_path/source_id元数据),再按文件内位置排序(依次尝试split_id/split_idx_start/page_number),使用文档实际携带的字段;
  • 分页:命中集大于max_docs时分页返回,每次返回一页加总命中数,工具提供offset输入继续下一页。

DocumentStoreToolset

DocumentStoreToolset(继承Toolset)把上述三个内省工具与FetchDocumentsByFilterTool打包为一个对象,可直接交给Agent(或与检索工具组合):

DocumentStoreToolset(document_store: DocumentStore, max_fetched_docs: int = 10)

构造时要求 store 实现全部三个内省方法;max_fetched_docsFetchDocumentsByFilterTool.max_docs的取值。同样提供to_dict/from_dict序列化。

BackupAnswerHook:步数耗尽时的兜底答案

BackupAnswerHook是 Advanced RAG Agent 内置在after_run钩子点上的钩子,解决的问题很具体:Agent 耗尽max_agent_steps时,运行可能停在一个工具调用或工具结果上而非助手文本答案上,此时只有after_run钩子会执行。该钩子检测到这一情形后,对当前对话发起一次 LLM 调用,基于已收集的证据撰写一个尽力而为的最终答案并追加到对话中。

其 API 面如下:

__init__(chat_generator: ChatGenerator) # 撰写兜底答案的 LLM warm_up() # Agent warm_up 时调用,准备生成器 close() # Agent close 时调用,释放生成器资源 to_dict() / from_dict(data) # 序列化/反序列化 run(state: State) -> None # 运行结束无答案时追加尽力而为的最终答案

对照本仓库源码可以确认其生命周期机制:Agent.warm_up会依次预热工具、钩子和聊天生成器(warm_up 实现),Agent.close会关闭钩子与生成器(close 实现);Hook 协议明确允许钩子实现可选的warm_up/close生命周期方法,由 Agent 统一调用。这也解释了为什么create_advanced_rag_agentbackup_answer_llm独立于主llm:兜底答案的生成器在 Agent 生命周期中独立预热与释放。

Deep Research Agent:create_deep_research_agent

函数签名

create_deep_research_agent( *, llm: ChatGenerator | None = None, system_prompt: str | None = None, max_agent_steps: int = 8, brief_llm: ChatGenerator | None = None, researcher_llm: ChatGenerator | None = None, search_tool: Tool | None = None, page_summary_llm: ChatGenerator | None = None, report_llm: ChatGenerator | None = None, max_researcher_steps: int = 20, max_concurrent_researchers: int = 5, max_subtopics: int = 5, max_page_chars: int = 50000, ) -> Agent

这是一个「规划者 + 多个并行子研究者」的调研 Agent:顶层 LLM 负责规划调查并委派子问题,每个子研究者各自运行自己的「搜索/阅读/思考」循环。同样支持用Agent.clone定制(agent.clone(tools=[*agent.tools, my_tool]))。

参数说明

参数类型说明
llmChatGenerator \| None规划调查并委派子问题的 LLM。默认OpenAIResponsesChatGenerator("gpt-5.4")
system_promptstr \| None覆盖预制系统提示词。其中的{{ max_subtopics }}会被替换为max_subtopics的实际值。
max_agent_stepsintAgent 循环最大步数(默认 8),对应「反思 -> 委派」的轮数。
brief_llmChatGenerator \| None把用户查询改写成聚焦研究简报的 LLM。默认OpenAIResponsesChatGenerator("gpt-5.4")
researcher_llmChatGenerator \| None驱动每个子研究者「搜索/阅读/思考」循环的 LLM。默认OpenAIResponsesChatGenerator("gpt-5.4-mini")
search_toolTool \| None每个子研究者使用的网络搜索工具。默认TavilyWebSearchTool(top_k=10),需要安装tavily-haystack。预制研究者提示词中把该工具称为web_search
page_summary_llmChatGenerator \| Noneread_url工具内部用于针对问题摘要所抓网页的 LLM。默认OpenAIResponsesChatGenerator("gpt-5.4-mini")
report_llmChatGenerator \| None把研究简报加收集到的笔记整合成最终报告的 LLM。默认OpenAIResponsesChatGenerator("gpt-5.4")
max_researcher_stepsint每个子研究者 Agent 循环的最大步数(默认 20)。
max_concurrent_researchersint同时运行的子研究者数量上限(默认 5)。
max_subtopicsintAgent 可委派的子问题数量上限,即调研广度(默认 5)。
max_page_charsint摘要前送入摘要器的原始网页字符数上限(默认 50000)。

返回值

result = agent.run(messages=[ChatMessage.from_user(question)]) # result["report"] # str,最终 markdown 报告(主要输出) # result["brief"] # str,研究简报(中间产物) # result["notes"] # list[str],子研究者收集的研究笔记(中间产物) # 另含标准 Agent 输出:messages、last_message、step_count、token_usage、tool_call_counts

使用建议与适用前提

结合参考文档与核心源码,落地时有几点值得注意:

  1. 文档库选型:Advanced RAG Agent 要求文档库实现三个元数据内省方法。InMemoryDocumentStore已完整实现(见上节),生产环境应选择同样声明支持这些方法的集成文档库;
  2. 检索路径分工:把「按相关性找」交给search_documents(受top_k控制),把「按条件精确取」交给fetch_documents_by_filter(受max_fetched_docsmax_fetch_factor保护),避免把无打分的过滤取回当作检索手段;
  3. 步数预算:Advanced RAG 默认 20 步、Deep Research 顶层默认 8 步 + 每子研究者 20 步,均可通过参数调整。步数耗尽时 Advanced RAG 有BackupAnswerHook兜底,但兜底答案质量受限于已收集证据,仍应把预算设得合理;
  4. 依赖前提:本文所有默认模型名(如gpt-5.4)与TavilyWebSearchTool依赖均以 version-2.21 参考文档描述为准,实际部署前需确认所用集成包版本中这些默认值是否变化;deep_research_agent的默认搜索工具需要额外安装tavily-haystack
  5. 定制入口:两个工厂返回的都是标准Agent,任何超出工厂参数的需求(加工具、加钩子、换提示词)都应通过Agent.clone或直接把 Agent 嵌入Pipeline解决,这与 Agent 组件文档 所描述的组件化扩展方式一致。

小结

Agent Pack 在 Haystack 的Agent运行时(工具循环、State、钩子点、clone)之上提供了两种可直接投产的 Agent 形态:Advanced RAG Agent 通过元数据内省工具让检索条件「可发现」而非「硬编码」,并用BackupAnswerHook保证步数耗尽时仍有答案;Deep Research Agent 则以「简报 -> 并行子研究者 -> 报告」的多 LLM 分工结构实现可配置的调研广度与并发。两者均以标准Agent对象返回,天然融入 Haystack 的管线与序列化体系。

【免费下载链接】haystackOpen-source AI orchestration framework for building context-engineered, production-ready LLM applications. Design modular pipelines and agent workflows with explicit control over retrieval, routing, memory, and generation. Built for scalable agents, RAG, multimodal applications, semantic search, and conversational systems.项目地址: https://gitcode.com/GitHub_Trending/ha/haystack

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 18:54:14

HoRain云--Python asyncio 异步编程实战:从协程到高并发爬虫

1. 同步 vs 异步同步爬虫按顺序请求&#xff0c;耗时累加。异步爬虫在等待网络响应时切换任务&#xff0c;大幅提升吞吐量。2. 协程基础python复制下载import asyncioasync def hello():print("Hello")await asyncio.sleep(1)print("World")asyncio.run(he…

作者头像 李华
网站建设 2026/9/14 18:52:19

两阶段鲁棒优化在微电网调度中的Matlab实现

1. 项目概述&#xff1a;两阶段鲁棒微网优化调度的核心逻辑 微电网作为分布式能源系统的关键载体&#xff0c;其调度优化一直面临风光出力波动、负荷变化等不确定性的挑战。传统随机规划方法依赖精确概率分布&#xff0c;而鲁棒优化则通过构建不确定性集合来规避风险。两阶段鲁…

作者头像 李华
网站建设 2026/9/14 18:51:34

固态电解质智能热闸:高温断路冷却自恢复的电池安全新策略

前几天九章算AM上有一条关于大连理工大学胡方圆教授团队的解读&#xff0c;标题叫“动态防护新策略”&#xff0c;说的是给固态电解质装一个智能“热闸”&#xff1a;高温下离子通道自动断路&#xff0c;冷却后自动恢复。粗看像实验室里的花活&#xff0c;细想其实是在回应电池…

作者头像 李华