ChatPromptBuilder
该组件通过处理聊天消息来动态构建提示。
| pipeline 中的最常见位置 | 在 Generator 之前 |
| 必需的初始化变量 | "template": 一个 ChatMessage 对象列表或一个特殊字符串模板。需要在初始化或运行时提供。 |
| 强制运行变量 | “**kwargs”: 任何用于渲染提示模板的字符串。有关更多详细信息,请参阅 Variables 部分。 |
| 输出变量 | “prompt”: 一个动态构建的提示 |
| API 参考 | Builders (构建器) |
| GitHub 链接 | https://github.com/deepset-ai/haystack/blob/main/haystack/components/builders/chat_prompt_builder.py |
概述
该ChatPromptBuilder 组件使用静态或动态模板创建提示,这些模板使用 Jinja2 语法编写,通过处理聊天消息列表或特殊字符串模板。模板包含占位符,例如{{ variable }},在运行时提供的这些值会填充这些占位符。您可以在初始化时为静态提示使用它,也可以在运行时动态更改模板和变量。
要使用它,首先提供一个ChatMessage 对象列表或一个特殊字符串作为模板。
ChatMessage 是一个数据类,包含消息内容、角色(谁生成了消息,例如 user, assistant, system, tool),以及可选的元数据。
构建器会在模板中查找占位符并识别所需的变量。您也可以手动列出这些变量。在运行时,run 方法会获取模板和变量,填充占位符,并返回完成的提示。如果所需的变量丢失。如果模板无效,构建器将引发错误。
例如,您可以创建一个简单的翻译提示
template = [ChatMessage.from_user("Translate to {{ target_language }}: {{ text }}")]
builder = ChatPromptBuilder(template=template)
result = builder.run(target_language="French", text="Hello, how are you?")
您也可以在运行时用一个新模板替换现有模板
new_template = [ChatMessage.from_user("Summarize in {{ target_language }}: {{ content }}")]
result = builder.run(template=new_template, target_language="English", content="A detailed paragraph.")
变量
初始化模板中找到的模板变量用作组件的输入类型。如果没有设置required_vairables,则所有变量默认都视为可选。在这种情况下,任何缺失的变量都会被替换为空字符串,这可能会导致意外行为,尤其是在复杂的管道中。
使用required_variables 和variables 用于指定输入类型和必需变量
-
required_variables- 定义了组件运行时必须提供的模板变量。
- 如果缺少任何必需的变量,组件将引发错误并停止执行。
- 您可以
- 传递必需变量名列表(例如
["name"]),或 - 使用
"*"将模板中的所有变量标记为必需。
- 传递必需变量名列表(例如
-
variables- 列出了模板中可能出现的所有变量,无论是必需的还是可选的。
- 未提供的可选变量在渲染的提示中会被替换为空字符串。
- 这允许在不引发错误的情况下构建部分提示,除非变量被标记为必需。
在下面的示例中,只有 *name* 是运行组件必需的,而 *topic* 只是一个可选变量
template = [ChatMessage.from_user("Hello, {{ name }}. How can I assist you with {{ topic }}?")]
builder = ChatPromptBuilder(template=template, required_variables=["name"], variables=["name", "topic"])
result = builder.run(name="Alice")
# Output: "Hello, Alice. How can I assist you with ?"
组件仅等待必需的输入后才运行。
角色
ChatMessage 代表对话中的一条消息,并且可以具有构建聊天消息的三个类方法之一from_user, from_system,或from_assistant. from_user 消息是由用户提供的输入,例如查询或请求。from_system 消息提供上下文或指令来指导 LLM 的行为,例如为对话设定语气或目的。from_assistant 定义了 LLM 的预期或实际响应。
以下是角色在ChatPromptBuilder:
system_message = ChatMessage.from_system("You are an assistant helping tourists in {{ language }}.")
user_message = ChatMessage.from_user("What are the best places to visit in {{ city }}?")
assistant_message = ChatMessage.from_assistant("The best places to visit in {{ city }} include the Eiffel Tower, Louvre Museum, and Montmartre.")
字符串模板
而不是一个ChatMessage 对象列表,您也可以将模板表示为一个特殊字符串。
这种模板格式允许您使用 Jinja2 语法定义ChatMessage 序列。每个{% message %} 块定义了一条具有特定角色的消息,您可以使用{{ variables }}.
与使用ChatMessages 列表相比,此格式更灵活,并允许将结构化部分(如图像)包含在模板化ChatMessage 中;要更好地理解此用例,请查看用法部分下面的多模态示例。
Jinja2 时间扩展
PromptBuilder 支持 Jinja2 TimeExtension,它允许您处理 datetime 格式。
Time Extension 提供两个主要功能:
- 一个
now标签,让您可以访问当前时间, - 通过 Python 的 datetime 模块进行日期/时间格式化。
要使用 Jinja2 TimeExtension,您需要安装一个依赖项,命令为
pip install arrow>=1.3.0
该now 标签
now 标签该now 标签创建一个表示当前时间的 datetime 对象,然后您可以将其存储在一个变量中
{% now 'utc' as current_time %}
The current UTC time is: {{ current_time }}
您可以指定不同的时区
{% now 'America/New_York' as ny_time %}
The time in New York is: {{ ny_time }}
如果您不指定时区,则将使用系统的本地时区。
{% now as local_time %}
Local time: {{ local_time }}
日期格式化
您可以使用 Python 的strftime 语法格式化 datetime 对象。
{% now as current_time %}
Formatted date: {{ current_time.strftime('%Y-%m-%d %H:%M:%S') }}
常见格式代码为:
%Y: 4 位年份(例如,2025)%m: 月份(01-12)%d: 日期(01-31)%H: 小时(24 小时制,00-23)%M: 分钟(00-59)%S: 秒(00-59)
示例
from haystack.components.builders.chat_prompt_builder import ChatPromptBuilder
from haystack.dataclasses import ChatMessage
template = [
ChatMessage.from_user("Current date is: {% now 'UTC' %}"),
ChatMessage.from_assistant("Thank you for providing the date"),
ChatMessage.from_user("Yesterday was: {% now 'UTC' - 'days=1' %}"),
]
builder = ChatPromptBuilder(template=template)
result = builder.run()["prompt"]
now = f"Current date is: {arrow.now('UTC').strftime('%Y-%m-%d %H:%M:%S')}"
yesterday = f"Yesterday was: {(arrow.now('UTC').shift(days=-1)).strftime('%Y-%m-%d %H:%M:%S')}"
用法
单独使用
使用静态模板
from haystack.components.builders import ChatPromptBuilder
from haystack.dataclasses import 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.")
使用特殊字符串模板
from haystack.components.builders import ChatPromptBuilder
from haystack.dataclasses import ChatMessage
template = """
{% message role="user" %}
Hello, my name is {{name}}!
{% endmessage %}
"""
builder = ChatPromptBuilder(template=template)
result = builder.run(name="John")
assert result["prompt"] == [ChatMessage.from_user("Hello, my name is John!")]
在 ChatMessage 中指定名称和元数据
from haystack.components.builders import ChatPromptBuilder
from haystack.dataclasses import ChatMessage
template = """
{% message role="user" name="John" meta={"key": "value"} %}
Hello from {{country}}!
{% endmessage %}
"""
builder = ChatPromptBuilder(template=template)
result = builder.run(country="Italy")
assert result["prompt"] == [ChatMessage.from_user("Hello from Italy!", name="John", meta={"key": "value"})]
具有不同角色的多个 ChatMessages
from haystack.components.builders import ChatPromptBuilder
from haystack.dataclasses import ChatMessage
template = """
{% message role="system" %}
You are a {{adjective}} assistant.
{% endmessage %}
{% message role="user" %}
Hello, my name is {{name}}!
{% endmessage %}
{% message role="assistant" %}
Hello, {{name}}! How can I help you today?
{% endmessage %}
"""
builder = ChatPromptBuilder(template=template)
result = builder.run(name="John", adjective="helpful")
assert result["prompt"] == [
ChatMessage.from_system("You are a helpful assistant."),
ChatMessage.from_user("Hello, my name is John!"),
ChatMessage.from_assistant("Hello, John! How can I help you today?"),
]
在运行时覆盖静态模板
from haystack.components.builders import ChatPromptBuilder
from haystack.dataclasses import 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.")
summary_template = [ChatMessage.from_user("Translate to {{ target_language }} and summarize. Context: {{ snippet }}; Summary:")]
builder.run(target_language="spanish", snippet="I can't speak spanish.", template=summary_template)
多模态
该| templatize_part 过滤器在下面的示例中告诉模板引擎将结构化(非文本)对象(例如图像)插入到消息内容中。这些对象与纯文本的处理方式不同,并且在最终的ChatMessage.
from haystack.components.builders import ChatPromptBuilder
from haystack.dataclasses import ChatMessage, ImageContent
template = """
{% 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 %}
"""
builder = ChatPromptBuilder(template=template)
images = [
ImageContent.from_file_path("apple.jpg"),
ImageContent.from_file_path("kiwi.jpg"),
]
result = builder.run(user_name="John", images=images)
assert result["prompt"] == [
ChatMessage.from_user(
content_parts=["Hello! I am John. What's the difference between the following images?",
*images]
)
]
在 pipeline 中
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()
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)
然后,您可以询问该地的天气预报。的ChatPromptBuilder 会用新的day_count 变量填充模板,并再次将其传递给 LLM。
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()
pipe = Pipeline()
pipe.add_component("prompt_builder", prompt_builder)
pipe.add_component("llm", llm)
pipe.connect("prompt_builder.prompt", "llm.messages")
location = "Berlin"
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)
其他参考资料
🧑🍳 食谱:Anthropic 的高级提示定制
更新于 3 个月前
