chatpromptbuilder.mdx
  1  ---
  2  title: "ChatPromptBuilder"
  3  id: chatpromptbuilder
  4  slug: "/chatpromptbuilder"
  5  description: "This component constructs prompts dynamically by processing chat messages."
  6  ---
  7  
  8  # ChatPromptBuilder
  9  
 10  This component constructs prompts dynamically by processing chat messages.
 11  
 12  <div className="key-value-table">
 13  
 14  |  |  |
 15  | --- | --- |
 16  | **Most common position in a pipeline** | Before a [Generator](../generators.mdx)                                                                                                         |
 17  | **Mandatory init variables**           | `template`: A list of [`ChatMessage`](../../concepts/data-classes/chatmessage.mdx) objects or a special string template. Needs to be provided either during init or run. |
 18  | **Mandatory run variables**            | `**kwargs`: Any strings that should be used to render the prompt template. See [Variables](#variables) section for more details.             |
 19  | **Output variables**                   | `prompt`: A dynamically constructed prompt                                                                                                     |
 20  | **API reference**                      | [Builders](/reference/builders-api)                                                                                                                   |
 21  | **GitHub link**                        | https://github.com/deepset-ai/haystack/blob/main/haystack/components/builders/chat_prompt_builder.py                                         |
 22  
 23  </div>
 24  
 25  ## Overview
 26  
 27  The `ChatPromptBuilder` component creates prompts using static or dynamic templates written in [Jinja2](https://palletsprojects.com/p/jinja/) syntax, by processing a list of chat messages or a special string template. The templates contain placeholders like `{{ variable }}` that are filled with values provided during runtime. You can use it for static prompts set at initialization or change the templates and variables dynamically while running.
 28  
 29  To use it, start by providing a list of `ChatMessage` objects or a special string as the template.
 30  
 31  [`ChatMessage`](../../concepts/data-classes/chatmessage.mdx) is a data class that includes message content, a role (who generated the message, such as `user`, `assistant`, `system`, `tool`), and optional metadata.
 32  
 33  The builder looks for placeholders in the template and identifies the required variables. You can also list these variables manually. During runtime, the `run` method takes the template and the variables, fills in the placeholders, and returns the completed prompt. If required variables are missing. If the template is invalid, the builder raises an error.
 34  
 35  For example, you can create a simple translation prompt:
 36  
 37  ```python
 38  template = [ChatMessage.from_user("Translate to {{ target_language }}: {{ text }}")]
 39  builder = ChatPromptBuilder(template=template)
 40  result = builder.run(target_language="French", text="Hello, how are you?")
 41  ```
 42  
 43  Or you can also replace the template at runtime with a new one:
 44  
 45  ```python
 46  new_template = [
 47      ChatMessage.from_user("Summarize in {{ target_language }}: {{ content }}"),
 48  ]
 49  result = builder.run(
 50      template=new_template,
 51      target_language="English",
 52      content="A detailed paragraph.",
 53  )
 54  ```
 55  
 56  ### Variables
 57  
 58  The template variables found in the init template are used as input types for the component. If there are no `required_vairables` set, all variables are considered optional by default. In this case, any missing variables are replaced with empty strings, which can lead to unintended behavior, especially in complex pipelines.
 59  
 60  Use `required_variables` and `variables` to specify the input types and required variables:
 61  
 62  - `required_variables`
 63    - Defines which template variables must be provided when the component runs.
 64    - If any required variable is missing, the component raises an error and halts execution.
 65    - You can:
 66      - Pass a list of required variable names (such as `["name"]`), or
 67      - Use `"*"` to mark all variables in the template as required.
 68  
 69  - `variables`
 70    - Lists all variables that can appear in the template, whether required or optional.
 71    - Optional variables that aren't provided are replaced with an empty string in the rendered prompt.
 72    - This allows partial prompts to be constructed without errors, unless a variable is marked as required.
 73  
 74  In the example below, only _name_ is required to run the component, while _topic_ is only an optional variable:
 75  
 76  ```python
 77  template = [
 78      ChatMessage.from_user("Hello, {{ name }}. How can I assist you with {{ topic }}?"),
 79  ]
 80  
 81  builder = ChatPromptBuilder(
 82      template=template,
 83      required_variables=["name"],
 84      variables=["name", "topic"],
 85  )
 86  
 87  result = builder.run(name="Alice")
 88  ## Output: "Hello, Alice. How can I assist you with ?"
 89  ```
 90  
 91  The component only waits for the required inputs before running.
 92  
 93  ### Roles
 94  
 95  A [`ChatMessage`](../../concepts/data-classes/chatmessage.mdx) represents a single message in the conversation and can have one of three class methods that build the chat messages: `from_user`, `from_system`, or `from_assistant`. `from_user` messages are inputs provided by the user, such as a query or request. `from_system` messages provide context or instructions to guide the LLM’s behavior, such as setting a tone or purpose for the conversation. `from_assistant` defines the expected or actual response from the LLM.
 96  
 97  Here’s how the roles work together in a `ChatPromptBuilder`:
 98  
 99  ```python
100  system_message = ChatMessage.from_system(
101      "You are an assistant helping tourists in {{ language }}.",
102  )
103  
104  user_message = ChatMessage.from_user("What are the best places to visit in {{ city }}?")
105  
106  assistant_message = ChatMessage.from_assistant(
107      "The best places to visit in {{ city }} include the Eiffel Tower, Louvre Museum, and Montmartre.",
108  )
109  ```
110  
111  ### String Templates
112  
113  Instead of a list of `ChatMessage` objects, you can also express the template as a special string.
114  
115  This template format allows you to define `ChatMessage` sequences using Jinja2 syntax. Each `{% message %}` block defines a single message with a specific role, and you can insert dynamic content using `{{ variables }}`.
116  
117  Compared to using a list of `ChatMessage`s, this format is more flexible and allows including structured parts like images in the templatized `ChatMessage`; to better understand this use case, check out the [multimodal example](#multimodal) in the Usage section below.
118  
119  ### Jinja2 Time Extension
120  
121  `PromptBuilder` supports the Jinja2 TimeExtension, which allows you to work with datetime formats.
122  
123  The Time Extension provides two main features:
124  
125  1. A `now` tag that gives you access to the current time,
126  2. Date/time formatting capabilities through Python's datetime module.
127  
128  To use the Jinja2 TimeExtension, you need to install a dependency with:
129  
130  ```shell
131  pip install arrow>=1.3.0
132  ```
133  
134  #### The `now` Tag
135  
136  The `now` tag creates a datetime object representing the current time, which you can then store in a variable:
137  
138  ```jinja2
139  {% now 'utc' as current_time %}
140  The current UTC time is: {{ current_time }}
141  ```
142  
143  You can specify different timezones:
144  
145  ```jinja2
146  {% now 'America/New_York' as ny_time %}
147  The time in New York is: {{ ny_time }}
148  ```
149  
150  If you don't specify a timezone, your system's local timezone will be used:
151  
152  ```jinja2
153  {% now as local_time %}
154  Local time: {{ local_time }}
155  ```
156  
157  #### Date Formatting
158  
159  You can format the datetime objects using Python's `strftime` syntax:
160  
161  ```jinja2
162  {% now as current_time %}
163  Formatted date: {{ current_time.strftime('%Y-%m-%d %H:%M:%S') }}
164  ```
165  
166  The common format codes are:
167  
168  - `%Y`: 4-digit year (for example, 2025)
169  - `%m`: Month as a zero-padded number (01-12)
170  - `%d`: Day as a zero-padded number (01-31)
171  - `%H`: Hour (24-hour clock) as a zero-padded number (00-23)
172  - `%M`: Minute as a zero-padded number (00-59)
173  - `%S`: Second as a zero-padded number (00-59)
174  
175  #### Example
176  
177  ```python
178  from haystack.components.builders.chat_prompt_builder import ChatPromptBuilder
179  from haystack.dataclasses import ChatMessage
180  
181  template = [
182      ChatMessage.from_user("Current date is: {% now 'UTC' %}"),
183      ChatMessage.from_assistant("Thank you for providing the date"),
184      ChatMessage.from_user("Yesterday was: {% now 'UTC' - 'days=1' %}"),
185  ]
186  builder = ChatPromptBuilder(template=template)
187  
188  result = builder.run()["prompt"]
189  ```
190  
191  ## Usage
192  
193  ### On its own
194  
195  #### With static template
196  
197  ```python
198  from haystack.components.builders import ChatPromptBuilder
199  from haystack.dataclasses import ChatMessage
200  
201  template = [
202      ChatMessage.from_user(
203          "Translate to {{ target_language }}. Context: {{ snippet }}; Translation:",
204      ),
205  ]
206  builder = ChatPromptBuilder(template=template)
207  builder.run(target_language="spanish", snippet="I can't speak spanish.")
208  ```
209  
210  #### With special string template
211  
212  ```python
213  from haystack.components.builders import ChatPromptBuilder
214  from haystack.dataclasses import ChatMessage
215  
216  template = """
217  {% message role="user" %}
218  Hello, my name is {{name}}!
219  {% endmessage %}
220  """
221  
222  builder = ChatPromptBuilder(template=template)
223  result = builder.run(name="John")
224  
225  assert result["prompt"] == [ChatMessage.from_user("Hello, my name is John!")]
226  ```
227  
228  #### Specifying name and meta in a ChatMessage
229  
230  ```python
231  from haystack.components.builders import ChatPromptBuilder
232  from haystack.dataclasses import ChatMessage
233  
234  template = """
235  {% message role="user" name="John" meta={"key": "value"} %}
236  Hello from {{country}}!
237  {% endmessage %}
238  """
239  
240  builder = ChatPromptBuilder(template=template)
241  result = builder.run(country="Italy")
242  assert result["prompt"] == [
243      ChatMessage.from_user("Hello from Italy!", name="John", meta={"key": "value"}),
244  ]
245  ```
246  
247  #### Multiple ChatMessages with different roles
248  
249  ```python
250  from haystack.components.builders import ChatPromptBuilder
251  from haystack.dataclasses import ChatMessage
252  
253  template = """
254  {% message role="system" %}
255  You are a {{adjective}} assistant.
256  {% endmessage %}
257  
258  {% message role="user" %}
259  Hello, my name is {{name}}!
260  {% endmessage %}
261  
262  {% message role="assistant" %}
263  Hello, {{name}}! How can I help you today?
264  {% endmessage %}
265  """
266  
267  builder = ChatPromptBuilder(template=template)
268  result = builder.run(name="John", adjective="helpful")
269  assert result["prompt"] == [
270      ChatMessage.from_system("You are a helpful assistant."),
271      ChatMessage.from_user("Hello, my name is John!"),
272      ChatMessage.from_assistant("Hello, John! How can I help you today?"),
273  ]
274  ```
275  
276  #### Overriding static template at runtime
277  
278  ```python
279  from haystack.components.builders import ChatPromptBuilder
280  from haystack.dataclasses import ChatMessage
281  
282  template = [
283      ChatMessage.from_user(
284          "Translate to {{ target_language }}. Context: {{ snippet }}; Translation:",
285      ),
286  ]
287  builder = ChatPromptBuilder(template=template)
288  builder.run(target_language="spanish", snippet="I can't speak spanish.")
289  
290  summary_template = [
291      ChatMessage.from_user(
292          "Translate to {{ target_language }} and summarize. Context: {{ snippet }}; Summary:",
293      ),
294  ]
295  builder.run(
296      target_language="spanish",
297      snippet="I can't speak spanish.",
298      template=summary_template,
299  )
300  ```
301  
302  #### Multimodal
303  
304  The `| templatize_part` filter in the example below tells the template engine to insert structured (non-text) objects, such as images, into the message content. These are treated differently from plain text and are rendered as special content parts in the final `ChatMessage`.
305  
306  ```python
307  from haystack.components.builders import ChatPromptBuilder
308  from haystack.dataclasses import ChatMessage, ImageContent
309  
310  template = """
311  {% message role="user" %}
312  Hello! I am {{user_name}}. What's the difference between the following images?
313  {% for image in images %}
314  {{ image | templatize_part }}
315  {% endfor %}
316  {% endmessage %}
317  """
318  builder = ChatPromptBuilder(template=template)
319  images = [
320      ImageContent.from_file_path("apple.jpg"),
321      ImageContent.from_file_path("kiwi.jpg"),
322  ]
323  result = builder.run(user_name="John", images=images)
324  
325  assert result["prompt"] == [
326      ChatMessage.from_user(
327          content_parts=[
328              "Hello! I am John. What's the difference between the following images?",
329              *images,
330          ],
331      ),
332  ]
333  ```
334  
335  ### In a pipeline
336  
337  ```python
338  from haystack.components.builders import ChatPromptBuilder
339  from haystack.components.generators.chat import OpenAIChatGenerator
340  from haystack.dataclasses import ChatMessage
341  from haystack import Pipeline
342  from haystack.utils import Secret
343  
344  ## no parameter init, we don't use any runtime template variables
345  prompt_builder = ChatPromptBuilder()
346  llm = OpenAIChatGenerator()
347  
348  pipe = Pipeline()
349  pipe.add_component("prompt_builder", prompt_builder)
350  pipe.add_component("llm", llm)
351  pipe.connect("prompt_builder.prompt", "llm.messages")
352  
353  location = "Berlin"
354  language = "English"
355  system_message = ChatMessage.from_system(
356      "You are an assistant giving information to tourists in {{language}}",
357  )
358  messages = [system_message, ChatMessage.from_user("Tell me about {{location}}")]
359  
360  res = pipe.run(
361      data={
362          "prompt_builder": {
363              "template_variables": {"location": location, "language": language},
364              "template": messages,
365          },
366      },
367  )
368  print(res)
369  ```
370  
371  Then, you could ask about the weather forecast for the said location. The `ChatPromptBuilder` fills in the template with the new `day_count` variable and passes it to an LLM once again:
372  
373  ```python
374  from haystack.components.builders import ChatPromptBuilder
375  from haystack.components.generators.chat import OpenAIChatGenerator
376  from haystack.dataclasses import ChatMessage
377  from haystack import Pipeline
378  from haystack.utils import Secret
379  
380  ## no parameter init, we don't use any runtime template variables
381  prompt_builder = ChatPromptBuilder()
382  llm = OpenAIChatGenerator()
383  
384  pipe = Pipeline()
385  pipe.add_component("prompt_builder", prompt_builder)
386  pipe.add_component("llm", llm)
387  pipe.connect("prompt_builder.prompt", "llm.messages")
388  
389  location = "Berlin"
390  
391  messages = [
392      system_message,
393      ChatMessage.from_user(
394          "What's the weather forecast for {{location}} in the next {{day_count}} days?",
395      ),
396  ]
397  res = pipe.run(
398      data={
399          "prompt_builder": {
400              "template_variables": {"location": location, "day_count": "5"},
401              "template": messages,
402          },
403      },
404  )
405  
406  print(res)
407  ```
408  
409  ## Additional References
410  
411  🧑‍🍳 Cookbook: [Advanced Prompt Customization for Anthropic](https://haystack.deepset.ai/cookbook/prompt_customization_for_anthropic)