Python
Explore reference template implementations in Python
Templates are predefined structures used to create consistent outputs. In the context of AI applications, prompt templates provide structured guidance for language models to generate targeted responses. They include placeholders that can be filled with specific information at runtime.
The Framework implements this functionality through the PromptTemplate class, which uses Mustache-style syntax (via the chevron library) for variable substitution. The implementation adds type safety and validation using Pydantic or Zod schemas.
At its core, the PromptTemplate class:
Create templates with basic variable substitution and type validation.
import sysimport traceback
from pydantic import BaseModel
from beeai_framework.errors import FrameworkErrorfrom beeai_framework.template import PromptTemplate
def main() -> None: class UserMessage(BaseModel): label: str input: str
template: PromptTemplate[UserMessage] = PromptTemplate( schema=UserMessage, template="""{{label}}: {{input}}""", )
prompt = template.render(label="Query", input="What interesting things happened on this day in history?")
print(prompt)
if __name__ == "__main__": try: main() except FrameworkError as e: traceback.print_exc() sys.exit(e.explain())import { PromptTemplate } from "beeai-framework/template";import { z } from "zod";
const greetTemplate = new PromptTemplate({ template: `Hello {{name}}`, schema: z.object({ name: z.string(), }),});
const output = greetTemplate.render({ name: "Alex",});console.log(output); // Hello Alex!This example creates a simple template that formats a user message with a label and input text. The Pydantic model or Zod schema ensures type safety for the template variables.
Add dynamic content to templates using custom functions.
import sysimport tracebackfrom datetime import UTC, datetimefrom typing import Any
from pydantic import BaseModel
from beeai_framework.errors import FrameworkErrorfrom beeai_framework.template import PromptTemplate
def main() -> None: class AuthorMessage(BaseModel): text: str author: str | None = None created_at: str | None = None
def format_meta(data: dict[str, Any]) -> str: if data.get("author") is None and data.get("created_at") is None: return ""
author = data.get("author") or "anonymous" created_at = data.get("created_at") or datetime.now(UTC).strftime("%A, %B %d, %Y at %I:%M:%S %p")
return f"\nThis message was created at {created_at} by {author}."
template: PromptTemplate[AuthorMessage] = PromptTemplate( schema=AuthorMessage, functions={ "format_meta": lambda data: format_meta(data), }, template="""Message: {{text}}{{format_meta}}""", )
# Message: Hello from 2024! # This message was created at 2024-01-01T00:00:00+00:00 by John. message = template.render( text="Hello from 2024!", author="John", created_at=datetime(2024, 1, 1, tzinfo=UTC).isoformat() ) print(message)
# Message: Hello from the present! message = template.render(text="Hello from the present!") print(message)
if __name__ == "__main__": try: main() except FrameworkError as e: traceback.print_exc() sys.exit(e.explain())import { PromptTemplate } from "beeai-framework/template";import { z } from "zod";
const messageTemplate = new PromptTemplate({ schema: z .object({ text: z.string(), author: z.string().optional(), createdAt: z.string().datetime().optional(), }) .passthrough(), functions: { formatMeta: function () { if (!this.author && !this.createdAt) { return ""; }
const author = this.author || "anonymous"; const createdAt = this.createdAt || new Date().toISOString();
return `\nThis message was created at ${createdAt} by ${author}.`; }, }, template: `Message: {{text}}{{formatMeta}}`,});
// Message: Hello from 2024!// This message was created at 2024-01-01T00:00:00.000Z by John.console.log( messageTemplate.render({ text: "Hello from 2024!", author: "John", createdAt: new Date("2024-01-01").toISOString(), }),);
// Message: Hello from the present!console.log( messageTemplate.render({ text: "Hello from the present!", }),);This example demonstrates how to add custom functions to templates:
format_meta function returns the date and author in a readable stringHandle complex nested data structures in templates with proper type validation.
import sysimport traceback
from pydantic import BaseModel
from beeai_framework.errors import FrameworkErrorfrom beeai_framework.template import PromptTemplate
def main() -> None: class Response(BaseModel): duration: int
class ExpectedDuration(BaseModel): expected: int responses: list[Response]
template: PromptTemplate[ExpectedDuration] = PromptTemplate( schema=ExpectedDuration, template="""Expected Duration: {{expected}}ms; Retrieved: {{#responses}}{{duration}}ms {{/responses}}""", defaults={"expected": 5}, )
# Expected Duration: 5ms; Retrieved: 3ms 5ms 6ms output = template.render(responses=[Response(duration=3), Response(duration=5), Response(duration=6)]) print(output)
if __name__ == "__main__": try: main() except FrameworkError as e: traceback.print_exc() sys.exit(e.explain())import { PromptTemplate } from "beeai-framework/template";import { z } from "zod";
const template = new PromptTemplate({ template: `Expected Duration: {{expected}}ms; Retrieved: {{#responses}}{{duration}}ms {{/responses}}`, schema: z.object({ expected: z.number(), responses: z.array(z.object({ duration: z.number() })), }), defaults: { expected: 5, },});
const output = template.render({ expected: undefined, // default value will be used responses: [{ duration: 3 }, { duration: 5 }, { duration: 6 }],});console.log(output); // Expected Duration: 5ms; Retrieved: 3ms 5ms 6msThis example shows how to work with nested objects in templates. The Mustache syntax allows for iterating through the responses array and accessing properties of each object.
Process collections of data within templates for dynamic list generation.
import sysimport traceback
from pydantic import BaseModel, Field
from beeai_framework.errors import FrameworkErrorfrom beeai_framework.template import PromptTemplate
def main() -> None: class ColorsObject(BaseModel): colors: list[str] = Field(..., min_length=1)
template: PromptTemplate[ColorsObject] = PromptTemplate( schema=ColorsObject, template="""Colors: {{#colors}}{{.}}, {{/colors}}""", )
# Colors: Green, Yellow, output = template.render(colors=["Green", "Yellow"]) print(output)
if __name__ == "__main__": try: main() except FrameworkError as e: traceback.print_exc() sys.exit(e.explain())import { PromptTemplate } from "beeai-framework/template";import { z } from "zod";
const template = new PromptTemplate({ schema: z.object({ colors: z.array(z.string()).min(1), }), template: `Colors: {{#trim}}{{#colors}}{{.}},{{/colors}}{{/trim}}`,});
const output = template.render({ colors: ["Green", "Yellow"],});console.log(output); // Colors: Green,YellowThis example demonstrates how to iterate over arrays in templates using Mustache’s section syntax.
Source: python/examples/templates/arrays.py
The fork() method allows you to create new templates based on existing ones, with customizations.
Template forking is useful for:
import sysimport tracebackfrom typing import Any
from pydantic import BaseModel
from beeai_framework.errors import FrameworkErrorfrom beeai_framework.template import PromptTemplate, PromptTemplateInput
def main() -> None: class OriginalSchema(BaseModel): name: str objective: str
original: PromptTemplate[OriginalSchema] = PromptTemplate( schema=OriginalSchema, template="""You are a helpful assistant called {{name}}. Your objective is to {{objective}}.""", )
def customizer(temp_input: PromptTemplateInput[Any]) -> PromptTemplateInput[Any]: new_temp = temp_input.model_copy() new_temp.template = f"""{temp_input.template} Your answers must be concise.""" new_temp.defaults["name"] = "Bee" return new_temp
modified = original.fork(customizer=customizer)
# You are a helpful assistant called Bee. Your objective is to fulfill the user needs. Your answers must be concise. prompt = modified.render(objective="fulfill the user needs") print(prompt)
if __name__ == "__main__": try: main() except FrameworkError as e: traceback.print_exc() sys.exit(e.explain())This example shows how to create a new template based on an existing one.
Source: python/examples/templates/forking.py
Provide default values for template variables that can be overridden at runtime.
The framework’s agents use specialized templates to structure their behavior. You can customize these templates to alter how agents operate:
import sysimport traceback
from beeai_framework.agents.react.runners.default.prompts import ( SystemPromptTemplate, ToolDefinition,)from beeai_framework.errors import FrameworkErrorfrom beeai_framework.tools.weather import OpenMeteoToolfrom beeai_framework.utils.strings import to_json
def main() -> None: tool = OpenMeteoTool()
tool_def = ToolDefinition( name=tool.name, description=tool.description, input_schema=to_json(tool.input_schema.model_json_schema()), )
# Render the granite system prompt prompt = SystemPromptTemplate.render( instructions="You are a helpful AI assistant!", tools=[tool_def], tools_length=1 )
print(prompt)
if __name__ == "__main__": try: main() except FrameworkError as e: traceback.print_exc() sys.exit(e.explain())This example demonstrates how to create a system prompt for an agent with tool definitions, which enables the agent to use external tools like weather data retrieval.
Source: python/examples/templates/system_prompt.py