PromptBuilder

PromptBuilder

파이프라인에서 Generator 앞에 두고, 프롬프트 템플릿을 렌더링해 변숫값을 채워 넣는 컴포넌트가 PromptBuilder예요.

항목 내용
파이프라인에서의 위치 질의(querying) 파이프라인에서 Generator
필수 init 변수 template: Jinja2 문법을 쓰는 프롬프트 템플릿 문자열
필수 run 변수 **kwargs: 프롬프트 템플릿을 렌더링하는 데 쓸 문자열들. Variables 섹션 참고
출력 변수 prompt: 렌더링된 프롬프트 템플릿을 나타내는 문자열
API 레퍼런스 Builders
GitHub 링크 https://github.com/deepset-ai/haystack/blob/main/haystack/components/builders/prompt_builder.py
패키지명 haystack-ai

출처: 공식문서

개요 (Overview)

PromptBuilder는 프롬프트 템플릿으로 초기화된 뒤, 키워드 인자(kwargs)로 넘어온 값을 채워 넣어 템플릿을 렌더링해요. kwargs를 쓰면 변수 개수에 제한 없이 전달할 수 있어서, 템플릿에 등장하는 모든 변수에 원하는 값을 지정할 수 있어요. 템플릿 안의 모든 변수에는 kwargs를 통해 값을 반드시 제공해야 하죠.

초기화 시 PromptBuilder에 넘기는 템플릿은 Jinja2 템플릿 언어 규칙을 따라야 해요.

변수 (Variables)

init 템플릿에서 발견되는 템플릿 변수들은 컴포넌트의 입력 타입으로 사용돼요. 기본적으로 required_variables 값이 "*"로 설정돼서 템플릿의 모든 변수가 필수가 돼요. 런타임에 하나라도 빠지면 컴포넌트는 에러를 내고 실행을 멈춰요.

required_variablesvariables로 입력 타입과 필수 변수를 지정할 수 있어요.

  • required_variables

    • 컴포넌트가 실행될 때 반드시 제공돼야 하는 템플릿 변수를 정의해요.
    • 필수 변수가 하나라도 없으면 에러를 내고 실행을 멈춰요.
    • 지정 방법은 다양해요:
      • "*"(기본값)를 쓰면 템플릿의 모든 변수를 필수로, 또는
      • 필수 변수 이름 목록(예: ["query"])을 넘기면 그 변수들만 필수로 만들고 나머지는 선택으로, 또는
      • 빈 목록([])이나 None을 넘기면 모든 변수를 선택으로 만들어요. None을 명시하면 경고 로그가 찍히는데, 빠진 변수를 조용히 빈 문자열로 대체하면 특히 복잡한 파이프라인에서 예상치 못한 동작이 생길 수 있어서예요.
  • variables

    • 필수든 선택이든 템플릿에 등장할 수 있는 모든 변수를 나열해요.
    • 제공되지 않은 선택 변수는 렌더링된 프롬프트에서 빈 문자열로 대체돼요.
    • 덕분에 어떤 변수가 필수로 표시돼 있지 않은 한, 오류 없이 부분 프롬프트를 만들 수 있어요.
from haystack.components.builders import PromptBuilder

# All variables required (the default, equivalent to required_variables="*")
builder = PromptBuilder(
    template="Hello {{name}}! {{greeting}}",
)

# Some variables required
builder = PromptBuilder(
    template="Hello {{name}}! {{greeting}}",
    required_variables=["name"],  # 'greeting' becomes optional
)

# All variables optional (missing ones default to empty string)
builder = PromptBuilder(
    template="Hello {{name}}! {{greeting}}",
    required_variables=[],  # explicit None also works but logs a warning
)

컴포넌트는 필수 입력만 갖춰지면 바로 실행돼요.

Jinja2 시간 확장 (Time Extension)

PromptBuilder는 Jinja2 TimeExtension을 지원해서 datetime 형식을 다룰 수 있어요.

시간 확장은 크게 두 가지 기능을 제공해요.

  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 }}

날짜 포맷 (Date Formatting)

datetime 객체는 Python의 strftime 문법으로 포맷할 수 있어요.

{% now as current_time %}
Formatted date: {{ current_time.strftime('%Y-%m-%d %H:%M:%S') }}

자주 쓰는 포맷 코드는 이러해요.

  • %Y: 4자리 연도 (예: 2025)
  • %m: 0으로 채운 월 (01-12)
  • %d: 0으로 채운 일 (01-31)
  • %H: 0으로 채운 시(24시간제) (00-23)
  • %M: 0으로 채운 분 (00-59)
  • %S: 0으로 채운 초 (00-59)

예시

from haystack.components.builders import PromptBuilder

# Define template using Jinja-style formatting
template = """
Current date is: {% now 'UTC' %}
Thank you for providing the date
Yesterday was: {% now 'UTC' - 'days=1' %}
"""

builder = PromptBuilder(template=template)

result = builder.run()["prompt"]

사용법 (Usage)

단독으로 쓰기

아래는 PromptBuilder로 프롬프트 템플릿을 렌더링하고 target_languagesnippet을 채워 넣는 예시예요. PromptBuilderTranslate 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.")

파이프라인에서 쓰기

아래는 RAG 파이프라인 예시예요. PromptBuilder로 커스텀 프롬프트 템플릿을 렌더링하고, 검색된 문서 내용과 질문으로 채워 넣은 뒤 그 프롬프트를 Generator로 보내요.

from haystack import Pipeline, Document
from haystack.utils import Secret
from haystack.components.generators.chat import OpenAIChatGenerator
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.\nDocuments:
    {% for doc in documents %}
        {{ doc.content }}
    {% endfor %}

    \nQuestion: {{query}}
    \nAnswer:
    """
p = Pipeline()
p.add_component(instance=PromptBuilder(template=prompt_template), name="prompt_builder")
p.add_component(
    instance=OpenAIChatGenerator(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)

런타임에 템플릿 바꾸기 (프롬프트 엔지니어링)

PromptBuilder는 기존 파이프라인의 프롬프트 템플릿을 바꿔 끼울 수 있게 해줘요. 아래 예시는 앞 섹션의 기존 파이프라인 위에 새 프롬프트 템플릿을 넣어 호출하는 모습이에요.

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,
        },
    },
)

기본 템플릿과 다른 변수를 프롬프트 엔지니어링 때 쓰고 싶다면, PromptBuildervariables init 파라미터를 그에 맞게 설정하면 돼요.

런타임에 변수 덮어쓰기

변숫값을 덮어쓰고 싶다면 런타임에 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_variablesdocuments 같은 파이프라인 변수도 덮어쓸 수 있어요.

YAML에서 쓰기

아래는 앞서 본 RAG 파이프라인의 YAML 표현이에요. 검색된 문서 내용과 질문으로 커스텀 프롬프트 템플릿을 렌더링한 뒤, 그 프롬프트를 생성기로 보내요.

components:
  llm:
    init_parameters:
      api_base_url: null
      api_key:
        env_vars:
        - OPENAI_API_KEY
        strict: true
        type: env_var
      generation_kwargs: {}
      http_client_kwargs: null
      max_retries: null
      model: gpt-5-mini
      organization: null
      streaming_callback: null
      timeout: null
      tools: null
      tools_strict: false
    type: haystack.components.generators.chat.openai.OpenAIChatGenerator
  prompt_builder:
    init_parameters:
      required_variables: '*'
      template: "\n    Given these documents, answer the question.\nDocuments:\n \
          \   {% for doc in documents %}\n        {{ doc.content }}\n    {% endfor %}\n\
        \n    \nQuestion: {{query}}\n    \nAnswer:\n    "
      variables: null
    type: haystack.components.builders.prompt_builder.PromptBuilder
connection_type_validation: true
connections:
- receiver: llm.messages
  sender: prompt_builder.prompt
max_runs_per_component: 100
metadata: {}

더 알아보기 (Learn more)

🧑‍🍳 쿡북: