Dynamiq
LLMs

Prompts & Messages

Build Prompt and Message objects with Jinja templating, send images and files with VisionMessage, and attach tools and response schemas.

A Prompt is an ordered list of messages plus optional tool definitions and a response schema. Message content is a Jinja template, so the same prompt object serves every request — you pass the variables as input_data at run time. Everything on this page is imported from dynamiq.prompts.

Messages and roles

A Message has content and a role — one of user, system, assistant, or tool (the MessageRole enum, plain strings also work):

from dynamiq.prompts import Message, MessageRole, Prompt

prompt = Prompt(
    messages=[
        Message(role=MessageRole.SYSTEM, content="You are a concise technical writer."),
        Message(role=MessageRole.USER, content="Explain {{topic}} to a {{audience}}."),
    ]
)

Assistant messages can carry tool_calls, and tool messages take tool_call_id and name, following the OpenAI function-calling protocol — you only need these when replaying a tool-use conversation manually.

Jinja templating

{{variable}} placeholders are rendered with the keyword arguments you pass at execution time. The LLM node validates inputs against the template, so a missing variable fails fast with the expected parameter names:

from dynamiq.connections import OpenAI as OpenAIConnection
from dynamiq.nodes.llms import OpenAI
from dynamiq.prompts import Message, Prompt

prompt = Prompt(
    messages=[Message(role="user", content="Explain {{topic}} to a {{audience}}.")]
)
print(prompt.get_required_parameters())  # {'topic', 'audience'}

llm = OpenAI(connection=OpenAIConnection(), model="gpt-4o-mini", prompt=prompt)
result = llm.run(input_data={"topic": "vector search", "audience": "PM"})
print(result.output["content"])

Anything Jinja supports works inside content — conditionals, loops, filters:

from dynamiq.prompts import Message, Prompt

prompt = Prompt(
    messages=[
        Message(
            role="user",
            content=(
                "Answer using only these documents:\n"
                "{% for doc in documents %}- {{ doc }}\n{% endfor %}"
                "Question: {{question}}"
            ),
        )
    ]
)

Set static=True on a message to skip template rendering entirely — useful when the content legitimately contains {{ }} sequences (code samples, user-provided text) that must not be interpreted:

from dynamiq.prompts import Message

raw = Message(role="system", content="Literal braces: {{not_a_variable}}", static=True)

Utilities

  • prompt.get_required_parameters() returns the set of variables across all non-static messages.
  • prompt.count_tokens(model="gpt-4o-mini") counts prompt tokens for a given model.

Vision inputs

To send images or files, use a VisionMessage whose content is a list of typed parts: VisionMessageTextContent, VisionMessageImageContent, and VisionMessageFileContent. Image URLs are templates too, and they accept more than strings — if the rendered variable is bytes or io.BytesIO, Dynamiq detects the file type and converts it to a base64 data URL automatically.

from dynamiq.connections import OpenAI as OpenAIConnection
from dynamiq.nodes.llms import OpenAI
from dynamiq.prompts import (
    Prompt,
    VisionMessage,
    VisionMessageImageContent,
    VisionMessageImageURL,
    VisionMessageTextContent,
)

prompt = Prompt(
    messages=[
        VisionMessage(
            role="user",
            content=[
                VisionMessageTextContent(text="{{user_message}}"),
                VisionMessageImageContent(
                    image_url=VisionMessageImageURL(url="{{img_url}}")
                ),
            ],
        )
    ]
)

llm = OpenAI(connection=OpenAIConnection(), model="gpt-4o-mini", prompt=prompt)
result = llm.run(
    input_data={
        "user_message": "What is in this image?",
        "img_url": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg",
    }
)
print(result.output["content"])
import io

from dynamiq.connections import OpenAI as OpenAIConnection
from dynamiq.nodes.llms import OpenAI
from dynamiq.prompts import Prompt, VisionMessage, VisionMessageImageContent

with open("photo.jpg", "rb") as f:
    image = io.BytesIO(f.read())

prompt = Prompt(
    messages=[
        VisionMessage(
            content=[VisionMessageImageContent(image_url={"url": "{{image}}"})]
        )
    ]
)

llm = OpenAI(connection=OpenAIConnection(), model="gpt-4o-mini")
# Bytes / BytesIO inputs are base64-encoded into a data URL automatically.
result = llm.run(input_data={"image": image}, prompt=prompt)
print(result.output["content"])

VisionMessageImageURL also takes a detail level (auto, high, or low) for providers that support it. For non-image documents such as PDFs, use VisionMessageFileContent with file.file_data set to a base64 data URL (bytes variables are converted the same way); check llm.is_pdf_input_supported first — see LLM Providers.

If a VisionMessage ends up containing only a single text part after rendering, it is sent as a plain text message — so a prompt with optional image inputs degrades gracefully.

Tools and response format

A Prompt can carry function-calling tools and a structured-output response_format alongside its messages. Values set directly on the LLM node take precedence over the prompt's:

from dynamiq.connections import OpenAI as OpenAIConnection
from dynamiq.nodes.llms import OpenAI
from dynamiq.prompts import Message, Prompt

prompt = Prompt(
    messages=[Message(role="user", content="Extract the city from: {{text}}")],
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "city_extraction",
            "schema": {
                "type": "object",
                "properties": {"city": {"type": "string"}},
                "required": ["city"],
                "additionalProperties": False,
            },
        },
    },
)

llm = OpenAI(connection=OpenAIConnection(), model="gpt-4o-mini", prompt=prompt)
result = llm.run(input_data={"text": "Our office in Milan opens at 9."})
print(result.output["content"])  # {"city": "Milan"}

When the model calls a tool instead of answering, the node output includes tool_calls with each call's function name and JSON-parsed arguments.

Per-call prompts

The prompt attached to the node is just a default. run() and execute() accept a prompt= argument, so one configured node can serve many prompts:

from dynamiq.connections import OpenAI as OpenAIConnection
from dynamiq.nodes.llms import OpenAI
from dynamiq.prompts import Message, Prompt

llm = OpenAI(connection=OpenAIConnection(), model="gpt-4o-mini")

summarize = Prompt(messages=[Message(role="user", content="Summarize: {{text}}")])
translate = Prompt(messages=[Message(role="user", content="Translate to French: {{text}}")])

print(llm.run(input_data={"text": "Dynamiq is an orchestration framework."}, prompt=summarize).output["content"])
print(llm.run(input_data={"text": "Good morning"}, prompt=translate).output["content"])

Next steps

On this page