Haystack Builders 组件全解析:AnswerBuilder、PromptBuilder 与 ChatPromptBuilder 的答案提取与提示词构建实战
2026/9/15 12:30:55 网站建设 项目流程

Haystack Builders 组件全解析:AnswerBuilder、PromptBuilder 与 ChatPromptBuilder 的答案提取与提示词构建实战

【免费下载链接】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 官方 API 参考文档 builders_api.md 展开,结合仓库源码与测试用例深入讲解builders模块中三个核心组件:用于把 Generator 输出整理为结构化答案的AnswerBuilder,以及分别面向文本生成与对话生成场景的PromptBuilderChatPromptBuilder。读完本文,你将掌握这三个组件的全部初始化参数、run()调用方式、正则表达式用法、Jinja2 模板渲染机制,并能直接把它们接入 Haystack Pipeline,搭建带引用溯源的可信 RAG 应用。

一、Builders 组件在 Haystack 中的定位

在 Haystack 的 Pipeline 编排体系中,builders模块承担着"输入构造"与"输出整理"两类职责:

  • PromptBuilder / ChatPromptBuilder位于 Pipeline 的前半段,负责把检索结果、用户查询、系统指令等数据渲染成 Generator 真正消费的提示词(Prompt);
  • AnswerBuilder位于 Pipeline 的后半段,负责把 Generator 返回的原始文本回复,通过正则表达式清洗、抽取,并和检索文档关联,最终封装为统一的GeneratedAnswer对象。

源码目录 haystack/components/builders 下仅有三个文件,分别对应这三个组件,结构非常清晰:

haystack/components/builders/ ├── __init__.py ├── answer_builder.py ├── chat_prompt_builder.py └── prompt_builder.py

二、AnswerBuilder:把 Generator 回复加工成结构化答案

2.1 组件职责

AnswerBuilder将"查询(query)"和"Generator 的回复(replies)"转换为GeneratedAnswer对象。它的核心能力包括:

  • 使用自定义正则表达式从 Generator 回复中解析出答案文本;
  • 可选地将 Generator 输入侧的检索文档与元数据一并封装进答案;
  • 同时兼容非聊天型 Generator(返回字符串)与聊天型 Generator(返回ChatMessage对象)。

GeneratedAnswer定义于 haystack/dataclasses/answer.py,是一个 dataclass,包含四个字段:data(答案文本)、query(原查询)、documents(关联文档列表)、meta(元数据字典),并实现了to_dict()/from_dict()序列化方法,便于在 Pipeline 中流转与持久化。

2.2 初始化参数详解

AnswerBuilder.__init__的签名如下(见 answer_builder.py):

def __init__(pattern: str | None = None, reference_pattern: str | None = None, last_message_only: bool = False, *, return_only_referenced_documents: bool = True)
参数类型默认值说明
patternstr \| NoneNone用于从 Generator 回复中抽取答案文本的正则表达式。不指定时,整段回复作为答案。正则最多允许一个捕获组:有捕获组时用捕获组文本,无捕获组时用整个匹配文本
reference_patternstr \| NoneNone用于解析文档引用的正则。不指定时不做解析,所有文档都会返回。引用以输入文档的从 1 开始的索引表示,例如\[(\d+)\]可以在字符串"this is an answer[1]"中匹配出1。指定后,文档元数据中会新增referenced布尔键
last_message_onlyboolFalseFalse时所有消息都作为答案;为True时只取最后一条消息作为答案
return_only_referenced_documentsboolTruereference_pattern配合使用。为True时只返回回复中实际被引用的文档;为False时返回全部文档。未提供reference_pattern时该参数不生效

关于pattern的典型示例:

  • [^\n]+$:在字符串"this is an argument.\nthis is an answer"中匹配出"this is an answer"
  • Answer: (.*):在字符串"this is an argument. Answer: this is an answer"中匹配出"this is an answer"

版本差异提示:在当前仓库源码 answer_builder.py 中,__init__还新增了一个expand_reference_ranges: bool = False参数,用于把[6-10]这类区间引用展开为第 6~10 篇文档。它默认关闭以保持向后兼容,启用后会从默认引用模式\[(\d+)\]自动切换到更宽泛的模式\[(\d+(?:[,-]\d+)*)\](见源码中的DEFAULT_REFERENCE_PATTERNEXPANDED_REFERENCE_PATTERN常量)。

2.3 基本用法示例

最简单的用法,只做答案文本抽取:

from haystack.components.builders import AnswerBuilder builder = AnswerBuilder(pattern="Answer: (.*)") builder.run(query="What's the answer?", replies=["This is an argument. Answer: This is the answer."])

2.4 带文档与引用模式的用法示例

下面的示例展示了reference_pattern的完整工作流:Generator 回复"The capital of France is Paris [2]."中的[2]表示引用了输入文档列表中的第 2 篇文档:

from haystack import Document from haystack.components.builders import AnswerBuilder replies = ["The capital of France is Paris [2]."] docs = [ Document(content="Berlin is the capital of Germany."), Document(content="Paris is the capital of France."), Document(content="Rome is the capital of Italy."), ] builder = AnswerBuilder(reference_pattern="\[(\d+)\]", return_only_referenced_documents=False) result = builder.run(query="What is the capital of France?", replies=replies, documents=docs)["answers"][0] print(f"Answer: {result.data}") print("References:") for doc in result.documents: if doc.meta["referenced"]: print(f"[{doc.meta['source_index']}] {doc.content}") print("Other sources:") for doc in result.documents: if not doc.meta["referenced"]: print(f"[{doc.meta['source_index']}] {doc.content}") # Answer: The capital of France is Paris # References: # [2] Paris is the capital of France. # Other sources: # [1] Berlin is the capital of Germany. # [3] Rome is the capital of Italy.

注意两点:答案文本本身仍保留原始回复(未用pattern抽取时),而[2]这样的引用标记会通过reference_pattern解析出来,并在每个文档副本的meta中写入referencedsource_index两个键。

2.5 run() 方法参数与返回值

@component.output_types(answers=list[GeneratedAnswer]) def run(query: str, replies: list[str] | list[ChatMessage], meta: list[dict[str, Any]] | None = None, documents: list[Document] | None = None, pattern: str | None = None, reference_pattern: str | None = None)
参数说明
query输入查询,即发送给 Generator 的提示词(会原样写入GeneratedAnswer.query
repliesGenerator 的输出,可以是字符串列表,也可以是ChatMessage对象列表
metaGenerator 返回的元数据列表(与replies一一对应)。不指定时答案不携带元数据
documents作为 Generator 输入的文档。指定后会被加入GeneratedAnswer,每份文档副本的meta中含source_index键(1 起始位置)。当提供reference_pattern时,还会额外写入referenced
pattern/reference_pattern与初始化同名参数含义一致,可在运行时覆盖初始化时的配置

返回值是字典{"answers": [...]},其中answersGeneratedAnswer对象列表。

2.6 源码级实现细节(印证文档行为)

阅读 answer_builder.py 可以确认以下实现事实:

  1. 答案抽取逻辑_extract_answer_string):先re.search(pattern, reply);无捕获组时取match.group(0)整体匹配;有捕获组时取match.group(1);完全没匹配到则返回空字符串。初始化或运行时传入的 pattern 若含多个捕获组_check_num_groups_in_regex会直接抛出ValueError

  2. 元数据合并:若meta为空,则用[{}] * len(replies)补齐;若len(replies) != len(meta)则抛ValueError。对于ChatMessage类型的回复,会取其.text作为答案文本、.meta与传入的meta合并,并统一在元数据中加入all_messages键(保存完整回复历史,方便下游追溯)。

  3. 文档引用解析_extract_reference_idxs):用re.findall收集所有引用索引并转为集合(去重)。注意引用是 1 起始的——源码对越界索引做了显式检查并记录 WARNING,注释明确说明这是为了防止[0]产生idx = -1时 Python 静默解析到最后一个文档的坑。

  4. 不修改输入文档:返回的文档副本通过dataclasses.replace(doc, meta=doc_meta)生成,原始输入文档的meta不会被改动。对应测试 test_answer_builder.py 中的test_run_does_not_mutate_input_documents_meta系列用例对此有专门断言。

  5. 区间引用展开(当前源码新增):expand_reference_ranges=True时支持[1-3,7-9]这类写法,并将超出文档数量的范围钳制到文档总数,防止类似[1-999999999]的异常引用造成内存爆炸;[3-1]这类倒序区间会被忽略。相关行为均有测试覆盖(见 test_answer_builder.py 中test_run_expands_reference_ranges_when_enabledtest_run_clamps_reference_range_to_number_of_documents等用例)。

  6. 聊天场景支持repliesChatMessage列表时,last_message_only控制是否只处理最后一条消息;测试test_conversation_history_with_last_message_only_true/false验证了两种模式下答案数量与all_messages元数据的正确性。

三、PromptBuilder:面向文本 Generator 的提示词渲染

3.1 组件职责

PromptBuilder使用Jinja2 模板语法渲染提示词,填充模板中的变量后交给 Generator 使用。模板中的变量默认即组件的输入;未提供时会在渲染结果中以空字符串填充(版本 2.23 文档行为),以便你可以随时在 Pipeline 运行时替换模板做提示词工程。

3.2 初始化参数详解

def __init__(template: str, required_variables: list[str] | Literal["*"] | None = None, variables: list[str] | None = None)
参数类型说明
templatestr使用 Jinja2 语法的提示词模板,例如"Summarize this document: {{ documents[0].content }}\nSummary:"。模板中的变量是 PromptBuilder 的输入,默认均为可选(v2.23)
required_variableslist[str] \| "*" \| None必须作为输入提供的变量列表;未提供则抛异常。设为"*"表示模板中所有变量都必须提供。可选
variableslist[str] \| None显式声明模板输入变量,替代从template自动推断的结果。例如提示词工程中你想在默认模板之外预留更多变量,可以在这里声明

3.3 独立使用示例

下面的示例渲染后得到的提示词为"Translate the following context to Spanish. Context: I can't speak Spanish.; Translation:"

from haystack.components.builders import PromptBuilder template = "Translate the following context to {{ target_language }}. Context: {{ snippet }}; Translation:" builder = PromptBuilder(template=template) builder.run(target_language="spanish", snippet="I can't speak spanish.")

3.4 在 Pipeline 中使用(RAG 场景)

官方文档给出了一个典型的 RAG Pipeline:PromptBuilder把检索文档与查询渲染进提示词,再交给OpenAIGenerator

from haystack import Pipeline, Document from haystack.utils import Secret from haystack.components.generators import OpenAIGenerator from haystack.components.builders.prompt_builder import PromptBuilder # in a real world use case documents could come from a retriever, web, or any other source documents = [Document(content="Joe lives in Berlin"), Document(content="Joe is a software engineer")] prompt_template = """ Given these documents, answer the question. Documents: {% for doc in documents %} {{ doc.content }} {% endfor %} Question: {{query}} Answer: """ p = Pipeline() p.add_component(instance=PromptBuilder(template=prompt_template), name="prompt_builder") p.add_component(instance=OpenAIGenerator(api_key=Secret.from_env_var("OPENAI_API_KEY")), name="llm") p.connect("prompt_builder", "llm") question = "Where does Joe live?" result = p.run({"prompt_builder": {"documents": documents, "query": question}}) print(result)

3.5 运行时更换模板(提示词工程)

无需重建 Pipeline,直接在run时传入新模板即可:

documents = [ Document(content="Joe lives in Berlin", meta={"name": "doc1"}), Document(content="Joe is a software engineer", meta={"name": "doc1"}), ] new_template = """ You are a helpful assistant. Given these documents, answer the question. Documents: {% for doc in documents %} Document {{ loop.index }}: Document name: {{ doc.meta['name'] }} {{ doc.content }} {% endfor %} Question: {{ query }} Answer: """ p.run({ "prompt_builder": { "documents": documents, "query": question, "template": new_template, }, })

这里使用了 Jinja2 的loop.indexdoc.meta['name']语法,演示了模板中访问文档元数据的能力。官方文档提示:在测试提示词时,如果要在默认模板之外引入更多变量,可以把新变量通过variables参数传给初始化。

3.6 运行时覆盖变量:template_variables

template_variables参数可以在run时覆盖 Pipeline 传入的变量(包括documents等),例如把回答语言从模板默认值改为德语:

language_template = """ You are a helpful assistant. Given these documents, answer the question. Documents: {% for doc in documents %} Document {{ loop.index }}: Document name: {{ doc.meta['name'] }} {{ doc.content }} {% endfor %} Question: {{ query }} Please provide your answer in {{ answer_language | default('English') }} Answer: """ p.run({ "prompt_builder": { "documents": documents, "query": question, "template": language_template, "template_variables": {"answer_language": "German"}, }, })

注意:language_template引入了模板中未绑定任何 Pipeline 变量的answer_language,借助 Jinja2 的default过滤器,未覆盖时默认是'English',这里被template_variables覆盖为'German'

3.7 run() 方法与源码实现

@component.output_types(prompt=str) def run(template: str | None = None, template_variables: dict[str, Any] | None = None, **kwargs)
  • template:可选,覆盖初始化时的默认模板;为None时使用默认模板;
  • template_variables:可选字典,覆盖 Pipeline 变量;
  • kwargs:用于渲染提示词的 Pipeline 变量;
  • 返回{"prompt": <渲染后的文本>};缺少必需变量时抛ValueError

源码层面(见 prompt_builder.py):

  • 模板在初始化时通过HaystackSandboxedEnvironment编译(该沙箱环境定义于 haystack/utils/jinja2_sandbox.py,并尝试加载可选的Jinja2TimeExtension,未安装arrow依赖时静默降级);
  • 变量通过_extract_template_variables_and_assignments从模板中自动推断(排除{% set %}赋值产生的变量);
  • 每个变量调用component.set_input_type注册为组件输入,可选变量会带上默认值"",这正是"未提供的可选变量渲染为空字符串"的实现机制;
  • run时先合并kwargstemplate_variables(后者优先),再经_validate_variables校验必需变量,缺失则抛出带变量清单的ValueError,最后compiled_template.render(...)输出结果;
  • to_dict()通过default_to_dict序列化模板与参数,保证组件可以存入 YAML/JSON 配置并在反序列化后恢复。

四、ChatPromptBuilder:面向聊天 Generator 的提示词渲染

4.1 组件职责

ChatPromptBuilder使用 Jinja2 语法把聊天提示词模板渲染为一组ChatMessage消息。模板可以是:

  • ChatMessage对象列表(静态模板);
  • 特殊格式的字符串模板(支持{% message %}标签与图片等富内容)。

它支持静态/动态模板,并且可以在每次 Pipeline 运行时更新模板。模板变量默认可选(v2.23 文档),未提供时以空字符串填充;可通过variablesrequired_variables声明输入类型与必需变量。

4.2 静态 ChatMessage 模板示例

template = [ChatMessage.from_user("Translate to {{ target_language }}. Context: {{ snippet }}; Translation:")] builder = ChatPromptBuilder(template=template) builder.run(target_language="spanish", snippet="I can't speak spanish.")

4.3 运行时覆盖静态模板

初始化时给定模板,运行时传入新的template覆盖它:

template = [ChatMessage.from_user("Translate to {{ target_language }}. Context: {{ snippet }}; Translation:")] builder = ChatPromptBuilder(template=template) builder.run(target_language="spanish", snippet="I can't speak spanish.") msg = "Translate to {{ target_language }} and summarize. Context: {{ snippet }}; Summary:" summary_template = [ChatMessage.from_user(msg)] builder.run(target_language="spanish", snippet="I can't speak spanish.", template=summary_template)

4.4 动态模板:在 Pipeline 中按需传入模板与变量

官方文档给出了一个"不初始化模板参数、每次运行都传入不同模板"的动态示例。ChatPromptBuilder()不传模板,模板与变量全部在pipe.run时通过template_variablestemplate传入:

from haystack.components.builders import ChatPromptBuilder from haystack.components.generators.chat import OpenAIChatGenerator from haystack.dataclasses import ChatMessage from haystack import Pipeline # no parameter init, we don't use any runtime template variables prompt_builder = ChatPromptBuilder() llm = OpenAIChatGenerator(model="gpt-5-mini") pipe = Pipeline() pipe.add_component("prompt_builder", prompt_builder) pipe.add_component("llm", llm) pipe.connect("prompt_builder.prompt", "llm.messages") location = "Berlin" language = "English" system_message = ChatMessage.from_system("You are an assistant giving information to tourists in {{language}}") messages = [system_message, ChatMessage.from_user("Tell me about {{location}}")] res = pipe.run(data={"prompt_builder": {"template_variables": {"location": location, "language": language}, "template": messages}}) print(res) # >> {'llm': {'replies': [ChatMessage(...)]}}

第二次运行换成天气模板并引入新变量day_count

messages = [system_message, ChatMessage.from_user("What's the weather forecast for {{location}} in the next {{day_count}} days?")] res = pipe.run(data={"prompt_builder": {"template_variables": {"location": location, "day_count": "5"}, "template": messages}}) print(res) # >> {'llm': {'replies': [ChatMessage(...)]}}

这个例子展示了聊天场景的核心优势:系统消息与用户消息可以在同一次运行中携带不同的模板变量,且模板整体可按需更换,非常适合多轮对话应用。

4.5 字符串模板:支持图片等多模态内容

字符串模板配合{% message %}标签可以构造多角色消息,配合templatize_part过滤器还能嵌入图片:

from haystack.components.builders import ChatPromptBuilder from haystack.dataclasses.image_content import ImageContent template = """ {% message role="system" %} You are a helpful assistant. {% endmessage %} {% message role="user" %} Hello! I am {{user_name}}. What's the difference between the following images? {% for image in images %} {{ image | templatize_part }} {% endfor %} {% endmessage %} """ images = [ImageContent.from_file_path("test/test_files/images/apple.jpg"), ImageContent.from_file_path("test/test_files/images/haystack-logo.png")] builder = ChatPromptBuilder(template=template) builder.run(user_name="John", images=images)

{% message role="system" %}...{% endmessage %}定义了消息角色边界;templatize_part过滤器把ImageContent序列化为消息内容的一部分,使多模态提示词(图片 + 文本)得以构造。需要说明的是,示例中的图片路径指向 Haystack 仓库内的测试资源目录test/test_files/images/,实际使用时应替换为你自己的图片路径。

4.6 初始化与 run 方法

def __init__(template: list[ChatMessage] | str | None = None, required_variables: list[str] | Literal["*"] | None = None, variables: list[str] | None = None)
参数说明
templateChatMessage列表或字符串模板。组件会查找 Jinja2 模板语法并用变量渲染;模板可以在initrun时提供
required_variables必须提供的变量列表;缺失则抛异常。设为"*"表示模板中所有变量都必需。可选
variables显式声明模板输入变量,替代从模板自动推断的结果
@component.output_types(prompt=list[ChatMessage]) def run(template: list[ChatMessage] | str | None = None, template_variables: dict[str, Any] | None = None, **kwargs)
  • template:覆盖默认模板;None时使用初始化模板;
  • template_variables:字典,覆盖 Pipeline 变量;
  • kwargs:渲染提示词所用的 Pipeline 变量;
  • 返回{"prompt": <渲染后的 ChatMessage 列表>}
  • 异常:当chat_messages为空或包含非ChatMessage元素时抛ValueError

4.7 源码级实现细节

阅读 chat_prompt_builder.py 可以印证:

  1. 沙箱渲染环境:组件使用HaystackSandboxedEnvironment并注册ChatMessageExtension(定义于 haystack/utils/jinja2_chat_extension.py),该扩展负责解析{% message %}标签与templatize_part过滤器;若已安装arrow,还会附加Jinja2TimeExtension(对应源码顶部的LazyImport延迟导入)。

  2. 变量推断:仅从USERSYSTEM角色的消息文本中推断模板变量;若这类消息缺少文本会抛ValueError;若在 ChatMessage 列表模板中使用templatize_part过滤器会抛出专门的FILTER_NOT_ALLOWED_ERROR_MESSAGE(该过滤器只允许出现在字符串模板中)。

  3. 字符串模板渲染_render_chat_messages_from_str_template):字符串模板渲染后会按行解析——每一行是一个 JSON 序列化的ChatMessage(由ChatMessageExtension生成),最终通过ChatMessage.from_dict还原为消息对象。

  4. 不修改原始消息:对USER/SYSTEM消息渲染时使用dataclasses.replace(message, _content=[TextContent(text=rendered_text)])生成副本,避免原地修改传入的ChatMessage

  5. 序列化to_dict()会把ChatMessage列表转为字典列表后交给default_to_dictfrom_dict()则把字典还原为ChatMessage对象,保证组件可被 YAML/JSON 配置系统完整存取。

五、三个组件的选型对比

维度PromptBuilderChatPromptBuilderAnswerBuilder
输入模板字符串(Jinja2)ChatMessage列表或字符串无需模板
输出str提示词list[ChatMessage]list[GeneratedAnswer]
典型对接非聊天 Generator(如OpenAIGenerator聊天 Generator(如OpenAIChatGenerator,输出端口messagesGenerator 输出后处理
核心能力变量填充、运行时换模板、必需变量校验多角色消息渲染、多模态内容(图片)、运行时换模板正则抽取答案、引用文档溯源、元数据装配
所在位置Pipeline 前半段Pipeline 前半段Pipeline 后半段

一条非常自然的组合链路是:Retriever → PromptBuilder(渲染检索上下文) → Generator(生成带引用的回复) → AnswerBuilder(抽取答案并绑定引用文档)。PromptBuilder/ChatPromptBuilder 负责"喂进去",AnswerBuilder 负责"取出来",三者配合即可构建一个带引用溯源的端到端 RAG 应用。

六、实战:组合出一个带引用的 RAG Pipeline

结合官方示例与源码行为,下面给出一个整合三个组件的完整思路(关键代码可直接运行):

from haystack import Pipeline, Document from haystack.utils import Secret from haystack.components.builders import PromptBuilder, AnswerBuilder from haystack.components.generators import OpenAIGenerator documents = [ Document(content="Berlin is the capital of Germany."), Document(content="Paris is the capital of France."), Document(content="Rome is the capital of Italy."), ] prompt_template = """ Given these documents, answer the question. Cite sources as [1], [2], ... Documents: {% for doc in documents %} [{{ loop.index }}] {{ doc.content }} {% endfor %} Question: {{ query }} Answer: """ pipeline = Pipeline() pipeline.add_component("prompt_builder", PromptBuilder(template=prompt_template)) pipeline.add_component( "llm", OpenAIGenerator(api_key=Secret.from_env_var("OPENAI_API_KEY"), generation_kwargs={"temperature": 0}), ) pipeline.add_component( "answer_builder", AnswerBuilder(pattern=r"Answer: (.*)", reference_pattern=r"\[(\d+)\]"), ) pipeline.connect("prompt_builder.prompt", "llm.prompt") pipeline.connect("llm.replies", "answer_builder.replies") pipeline.connect("prompt_builder.documents", "answer_builder.documents") result = pipeline.run({ "prompt_builder": {"documents": documents, "query": "What is the capital of France?"}, "answer_builder": {"query": "What is the capital of France?"}, }) answer = result["answer_builder"]["answers"][0] print(answer.data) # 答案文本(已按 pattern 抽取) for doc in answer.documents: print(doc.meta["source_index"], doc.meta["referenced"], doc.content)

要点说明:

  • 提示词模板中把文档编号[{{ loop.index }}]渲染进上下文,引导模型在回答中引用[1]/[2]这类编号;
  • AnswerBuilderreference_pattern=r"\[(\d+)\]"负责把这些编号还原为输入文档索引;
  • 通过pipeline.connect("prompt_builder.documents", "answer_builder.documents")把同一份文档列表同时喂给渲染与答案装配两端,source_indexreferenced即能正确对应。

七、常见错误与规避建议

结合源码中的校验逻辑与测试用例(test_answer_builder.py、test_prompt_builder.py、test_chat_prompt_builder.py),以下是高频踩坑点:

  1. pattern 含多个捕获组AnswerBuilder(pattern=r"Answer: (.*), (.*)")会直接抛ValueError("contains multiple capture groups")。正则最多保留一个捕获组。
  2. meta 与 replies 长度不一致runmeta列表长度必须等于replies长度,否则抛ValueError
  3. 引用越界或 0 引用:引用是 1 起始的,[0]或超出文档数量的引用会被跳过并打印 WARNING,而非报错或静默取错文档。
  4. 必需变量缺失:配置了required_variables(或当前源码默认"*")后,若run时未提供对应变量,PromptBuilder/ChatPromptBuilder会抛出包含缺失变量清单的ValueError
  5. ChatPromptBuilder 空模板或非法元素:模板为空或列表内含非ChatMessage元素时抛ValueError
  6. USER/SYSTEM 消息缺文本:列表模板中这类角色消息必须含文本,否则抛ValueErrortemplatize_part过滤器只能用于字符串模板。

八、小结

builders模块是 Haystack 提示词链路中承上启下的关键组件:

  • PromptBuilder用 Jinja2 模板为文本 Generator 渲染提示词,支持运行时换模板与变量覆盖;
  • ChatPromptBuilder在聊天场景下渲染多角色消息,并支持字符串模板、图片等多模态内容;
  • AnswerBuilder用正则从 Generator 回复中抽取答案,通过引用模式把检索文档绑定进GeneratedAnswer,实现可追溯、可展示引用来源的答案输出。

三个组件的实现都遵循 Haystack 组件协议(@component装饰器、output_typesto_dict/from_dict序列化),因此可以无缝嵌入 Pipeline、SuperComponent 与 YAML 配置系统。想进一步深入源码,可阅读 answer_builder.py、prompt_builder.py、chat_prompt_builder.py 三个实现文件,以及对应的三份测试文件;GeneratedAnswer数据结构定义于 haystack/dataclasses/answer.py,模板渲染的沙箱与扩展机制位于 haystack/utils/jinja2_sandbox.py 与 haystack/utils/jinja2_chat_extension.py。

【免费下载链接】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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询