将 Generator 的输出提取为 Answer 格式,并构建提示。
模块 answer_builder
AnswerBuilder
将查询和 Generator 的回复转换为一个GeneratedAnswer 对象。
AnswerBuilder 使用自定义正则表达式解析 Generator 的回复。请查看下面的用法示例,了解其工作原理。可选地,它还可以从 Generator 获取文档和元数据,添加到GeneratedAnswer 对象中。AnswerBuilder 可以与非聊天和聊天 Generator 一起使用。
使用示例
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."])
AnswerBuilder.__init__
def __init__(pattern: Optional[str] = None,
reference_pattern: Optional[str] = None,
last_message_only: bool = False)
创建 AnswerBuilder 组件的实例。
参数:
pattern: 用于从 Generator 中提取答案文本的正则表达式模式。如果未指定,则整个响应将用作答案。正则表达式最多可以有一个捕获组。如果存在,捕获组文本将用作答案。如果不存在捕获组,则整个匹配项将用作答案。示例:[^\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"。reference_pattern: 用于解析文档引用的正则表达式模式。如果未指定,则不进行解析,所有文档都将被引用。引用需要指定为输入文档的索引,并从 [1] 开始。示例:\[(\d+)\]在字符串 "this is an answer[1]" 中找到 "1"。last_message_only: 如果为 False(默认值),则所有消息都将用作答案。如果为 True,则仅使用最后一条消息作为答案。
AnswerBuilder.run
@component.output_types(answers=list[GeneratedAnswer])
def run(query: str,
replies: Union[list[str], list[ChatMessage]],
meta: Optional[list[dict[str, Any]]] = None,
documents: Optional[list[Document]] = None,
pattern: Optional[str] = None,
reference_pattern: Optional[str] = None)
将 Generator 的输出转换为GeneratedAnswer 对象,使用正则表达式。
参数:
query: 用作 Generator 提示的输入查询。replies: Generator 的输出。可以是字符串列表或ChatMessage对象列表。meta: Generator 返回的元数据。如果未指定,则生成的答案将不包含任何元数据。documents: 用作 Generator 输入的文档。如果指定,它们将被添加到GeneratedAnswer对象中。如果同时指定了documents和reference_pattern,则从输入文档中提取 Generator 输出中引用的文档,并将其添加到GeneratedAnswer对象中。pattern: 用于从 Generator 中提取答案文本的正则表达式模式。如果未指定,则整个响应将用作答案。正则表达式最多可以有一个捕获组。如果存在,捕获组文本将用作答案。如果不存在捕获组,则整个匹配项将用作答案。示例:[^\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"。reference_pattern: 用于解析文档引用的正则表达式模式。如果未指定,则不进行解析,所有文档都将被引用。引用需要指定为输入文档的索引,并从 [1] 开始。示例:\[(\d+)\]在字符串 "this is an answer[1]" 中找到 "1"。
返回值:
包含以下键的字典
answers: 从 Generator 输出接收到的答案。
模块 prompt_builder
PromptBuilder
渲染一个提示,填充任何变量,以便将其发送给 Generator。
该提示使用 Jinja2 模板语法。默认模板中的变量是 PromptBuilder 的输入,并且都是可选的。如果未提供,它们将在渲染的提示中被替换为空字符串。要尝试不同的提示,您可以在运行时通过为每个管道运行调用提供模板来替换提示模板。
使用示例
单独使用
此示例使用 PromptBuilder 渲染提示模板,并使用target_language 和snippet 进行填充。PromptBuilder 返回一个提示,其中包含字符串 "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.")
在 Pipeline 中
这是 RAG 管道的一个示例,其中 PromptBuilder 渲染自定义提示模板,并使用检索到的文档内容和查询对其进行填充。然后将渲染的提示发送给 Generator。
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)
在运行时更改模板(提示工程)
您可以更改现有管道的提示模板,如本示例所示
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,
},
})
为了在测试提示时替换默认模板中的变量,请在variables 参数中提供新的变量。
在运行时覆盖变量
要覆盖变量的值,请在运行时使用template_variables
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 引入了一个变量answer_language,它未绑定到任何管道变量。如果未另行设置,则默认值为 'English'。此示例将其值覆盖为 'German'。使用template_variables 来覆盖管道变量(例如文档)以及其他变量。
PromptBuilder.__init__
def __init__(template: str,
required_variables: Optional[Union[list[str],
Literal["*"]]] = None,
variables: Optional[list[str]] = None)
构造一个 PromptBuilder 组件。
参数:
template: 一个使用 Jinja2 语法的提示模板,用于添加变量。例如:"Summarize this document: {{ documents[0].content }}\nSummary:"它用于渲染提示。默认模板中的变量是 PromptBuilder 的输入,并且除非另有明确说明,否则都是可选的。如果未提供可选变量,则在渲染的提示中将其替换为空字符串。required_variables: 必须作为 PromptBuilder 输入提供的变量列表。如果未提供列为必需的变量,则会引发异常。如果设置为 "*",则提示中找到的所有变量都是必需的。可选。variables: 用于提示模板的输入变量列表,而不是从template参数推断出的变量。例如,要在提示工程中使用比默认模板中存在的变量更多的变量,可以在此处提供它们。
PromptBuilder.to_dict
def to_dict() -> dict[str, Any]
返回组件的字典表示。
返回值:
组件的序列化字典表示。
PromptBuilder.run
@component.output_types(prompt=str)
def run(template: Optional[str] = None,
template_variables: Optional[dict[str, Any]] = None,
**kwargs)
使用提供的变量渲染提示模板。
它应用模板变量来渲染最终的提示。您可以通过管道 kwargs 提供变量。为了覆盖默认模板,您可以设置template 参数。为了覆盖管道 kwargs,您可以设置template_variables 参数。
参数:
template: 一个可选的字符串模板,用于覆盖 PromptBuilder 的默认模板。如果为 None,则使用初始化时提供的默认模板。template_variables: 一个可选的模板变量字典,用于覆盖管道变量。kwargs: 用于渲染提示的管道变量。
引发:
ValueError: 如果未提供任何必需的模板变量。
返回值:
包含以下键的字典
prompt: 渲染提示模板后更新的提示文本。
模块 chat_prompt_builder
ChatPromptBuilder
使用 Jinja2 语法从模板渲染聊天提示。
模板可以是ChatMessage 对象列表,或一个特殊字符串,如用法示例所示。
它使用静态或动态模板构建提示,您可以在每次管道运行时更新这些模板。
模板中的模板变量是可选的,除非另有说明。如果未提供可选变量,则默认为空字符串。使用variable 和required_variables 来定义输入类型和必需变量。
使用示例
静态 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.")
在运行时覆盖静态 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.")
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)
动态 ChatMessage 提示模板
from haystack.components.builders import ChatPromptBuilder
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
from haystack import Pipeline
from haystack.utils import Secret
# no parameter init, we don't use any runtime template variables
prompt_builder = ChatPromptBuilder()
llm = OpenAIChatGenerator(api_key=Secret.from_token("<your-api-key>"), model="gpt-4o-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(_role=<ChatRole.ASSISTANT: 'assistant'>, _content=[TextContent(text=
"Berlin is the capital city of Germany and one of the most vibrant
and diverse cities in Europe. Here are some key things to know...Enjoy your time exploring the vibrant and dynamic
capital of Germany!")], _name=None, _meta={'model': 'gpt-4o-mini',
'index': 0, 'finish_reason': 'stop', 'usage': {'prompt_tokens': 27, 'completion_tokens': 681, 'total_tokens':
708}})]}}
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(_role=<ChatRole.ASSISTANT: 'assistant'>, _content=[TextContent(text=
"Here is the weather forecast for Berlin in the next 5
days:\n\nDay 1: Mostly cloudy with a high of 22°C (72°F) and...so it's always a good idea to check for updates
closer to your visit.")], _name=None, _meta={'model': 'gpt-4o-mini',
'index': 0, 'finish_reason': 'stop', 'usage': {'prompt_tokens': 37, 'completion_tokens': 201,
'total_tokens': 238}})]}}
字符串提示模板
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("apple.jpg"), ImageContent.from_file_path("orange.jpg")]
builder = ChatPromptBuilder(template=template)
builder.run(user_name="John", images=images)
ChatPromptBuilder.__init__
def __init__(template: Optional[Union[list[ChatMessage], str]] = None,
required_variables: Optional[Union[list[str],
Literal["*"]]] = None,
variables: Optional[list[str]] = None)
构造一个 ChatPromptBuilder 组件。
参数:
template: 一个ChatMessage对象列表或一个字符串模板。该组件查找 Jinja2 模板语法,并使用提供的变量渲染提示。在init方法或run方法中提供模板。required_variables: 必须作为 ChatPromptBuilder 输入提供的变量列表。如果未提供列为必需的变量,则会引发异常。如果设置为 "*",则提示中找到的所有变量都是必需的。可选。variables: 用于提示模板的输入变量列表,而不是从template参数推断出的变量。例如,要在提示工程中使用比默认模板中存在的变量更多的变量,可以在此处提供它们。
ChatPromptBuilder.run
@component.output_types(prompt=list[ChatMessage])
def run(template: Optional[Union[list[ChatMessage], str]] = None,
template_variables: Optional[dict[str, Any]] = None,
**kwargs)
使用提供的变量渲染提示模板。
它应用模板变量来渲染最终的提示。您可以通过管道 kwargs 提供变量。要覆盖默认模板,您可以设置template 参数。要覆盖管道 kwargs,您可以设置template_variables 参数。
参数:
template: 一个可选的ChatMessage对象列表或字符串模板,用于覆盖 ChatPromptBuilder 的默认模板。如果为None,则使用初始化时提供的默认模板。template_variables: 一个可选的模板变量字典,用于覆盖管道变量。kwargs: 用于渲染提示的管道变量。
引发:
ValueError: 如果chat_messages为空或包含非实例的元素ChatMessage.
返回值:
包含以下键的字典
prompt: 渲染模板后更新的ChatMessage对象列表。
ChatPromptBuilder.to_dict
def to_dict() -> dict[str, Any]
返回组件的字典表示。
返回值:
组件的序列化字典表示。
ChatPromptBuilder.from_dict
@classmethod
def from_dict(cls, data: dict[str, Any]) -> "ChatPromptBuilder"
从字典反序列化此组件。
参数:
data: 要反序列化并创建组件的字典。
返回值:
反序列化后的组件。
