2.7 KiB
2.7 KiB
Dotprompt — Genkit Python
What it is
.prompt files combine YAML frontmatter (model config, schemas) with Handlebars templates. Keeps prompt logic out of Python code and makes variants easy.
File format
---
model: googleai/gemini-flash-latest
input:
schema:
food: string
ingredients?(array): string # ? = optional
output:
schema: Recipe # references a schema registered with ai.define_schema()
format: json
---
You are a chef. Generate a recipe for {{food}}.
{{#if ingredients}}
Include these ingredients:
{{list ingredients}}
{{/if}}
Place .prompt files in a prompts/ directory and point prompt_dir at it.
Python setup
from pathlib import Path
from pydantic import BaseModel
from genkit import Genkit
from genkit.plugins.google_genai import GoogleAI
ai = Genkit(
plugins=[GoogleAI()],
model='googleai/gemini-flash-latest',
prompt_dir=Path(__file__).resolve().parent.parent / 'prompts',
)
# Register Pydantic models referenced in .prompt output.schema
class Recipe(BaseModel):
title: str
steps: list[str]
ai.define_schema('Recipe', Recipe)
Calling a prompt
# Non-streaming — double-call syntax: ai.prompt('name')(input={...})
response = await ai.prompt('recipe')(input={'food': 'banana bread'})
result = Recipe.model_validate(response.output)
# Variant (recipe.robot.prompt file)
response = await ai.prompt('recipe', variant='robot')(input={'food': 'banana bread'})
Streaming from a prompt
from genkit import ActionRunContext
@ai.flow()
async def tell_story(subject: str, ctx: ActionRunContext) -> str:
result = ai.prompt('story').stream(input={'subject': subject})
full = ''
async for chunk in result.stream:
if chunk.text:
ctx.send_chunk(chunk.text)
full += chunk.text
return full
Note: .stream(input={...}) not ai.generate_stream(...) — different call shape for prompts.
Render without generating (for LLM-judge evals)
rendered = await ai.prompt('my_prompt').render(input={'key': 'value'})
response = await ai.generate(model='googleai/gemini-flash-latest', messages=rendered.messages)
Helpers
Register Python functions callable inside Handlebars templates:
def list_helper(data: object, *args, **kwargs) -> str:
if not isinstance(data, list):
return ''
return '\n'.join(f'- {item}' for item in data)
ai.define_helper('list', list_helper)
Then use {{list ingredients}} in your .prompt file.
Variants
Name the file <name>.<variant>.prompt — e.g. recipe.robot.prompt.
Call with ai.prompt('recipe', variant='robot').
Partials
Use {{>partial_name param=value}} in templates. Partial files are named _partial_name.prompt.