文档API 参考📓 教程🧑‍🍳 食谱🤝 集成💜 Discord🎨 Studio
文档

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 是一个数据类,包含消息内容、角色(谁生成了消息,例如 userassistantsystemtool),以及可选的元数据。

构建器会在模板中查找占位符并识别所需的变量。您也可以手动列出这些变量。在运行时,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_variablesvariables 用于指定输入类型和必需变量

  • 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 提供两个主要功能:

  1. 一个now 标签,让您可以访问当前时间,
  2. 通过 Python 的 datetime 模块进行日期/时间格式化。

要使用 Jinja2 TimeExtension,您需要安装一个依赖项,命令为

pip install arrow>=1.3.0

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 的高级提示定制