Cookbook
On this page
Practical recipes, each grounded in what the implementation actually supports.
Recipe: Deterministic prompts for testing
Disable caching and auto-detection so build() output is a pure function of its explicit arguments:
engine = PromptEngine(enable_cache=False, enable_auto_detect=False)
prompt = engine.build(query="What is RAG?", strategy="simple", prompt_type="qa")
Recipe: Observability dashboard feed
def snapshot(engine: PromptEngine) -> dict:
return {
"metrics": engine.metrics,
"recent_traces": engine.get_trace_log(last_n=50),
}
Feed snapshot(engine) into your metrics pipeline on a timer. See api/prompt_engine for the exact shape.
Recipe: Quality feedback loop
prompt = engine.build(query=q, documents=docs, trace_id=str(uuid.uuid4()))
response = llm.chat(prompt.to_messages())
# ... collect a quality signal (user thumbs-up/down, automated eval, etc.) ...
engine.record_feedback(trace_id=prompt.trace_id, quality_score=1.0 if thumbs_up else 0.0)
# Periodically:
suggested = engine.adaptive_strategy_for(PromptType.QA)
if suggested:
logger.info("Adaptive suggestion for QA: %s", suggested.value)
Remember: adaptive_strategy_for only returns a suggestion once 5+ feedback entries exist for that prompt_type, and you must manually pass its result into future build(strategy=...) calls — nothing applies it automatically (see api/prompt_engine.md#adaptive-feedback).
Recipe: Strict grounding for compliance-sensitive answers
prompt = engine.build(
query=user_query,
documents=retrieved_docs,
enable_guardrails=True,
enable_citations=True,
enable_uncertainty=True,
output_format="citation",
)
This combination applies GROUNDING, NO_FABRICATION, UNCERTAINTY, CITE_SOURCES, PII_PROTECTION, STAY_ON_TOPIC, SAFE_OUTPUT, and CONCISE (see the selection table in api/guardrails), plus the citation-format instruction requiring a trailing Sources section.
Recipe: Agent / tool-use prompts
prompt = engine.build(
query="Find me a flight to Cairo next Tuesday under $500.",
prompt_type="agent",
extra={"tools": [
{"name": "search_flights", "description": "Search flights by route/date/budget",
"parameters": {"origin": "string", "destination": "string", "date": "string", "max_price": "number"}},
]},
)
prompt_type="agent" defaults to strategy=REACT (see api/builder.md#default-strategy-table), and ReActStrategy renders an ## Available Tools section only when extra["tools"] is present (see api/strategies).
Recipe: Batch processing many queries efficiently
engine = PromptEngine(enable_cache=True, max_cache_size=1000) # raise cache ceiling for a large batch
prompts = [engine.build(query=q, documents=retrieve(q)) for q in queries]
Caching helps most when the same (query, doc-snippet, type, strategy, format, language) combination recurs — see the cache-key composition caveat in api/prompt_engine (document metadata and conversation history are not part of the key).
Recipe: Comparing two system-prompt strategies before shipping
See the dedicated A/B Testing tutorial.
Recipe: Keeping prompts within a hard model context window
from zerda.prompt.optimizer import PromptOptimizer
# strategies build their own PromptOptimizer() internally with defaults;
# if you need a different cap, apply a second pass yourself:
opt = PromptOptimizer(max_total_tokens=4000)
system, user, saved, notes = opt.optimize(prompt.system_prompt, prompt.user_prompt)
Strategies always construct a default-configured PromptOptimizer() internally (see api/strategies.md#basestrategy) — there's no way to pass optimizer settings through PromptEngine.build(). If you need a non-default max_total_tokens, re-run optimization yourself as shown, or lower max_context_tokens on the request to reduce how much context is assembled in the first place.