A prompt template engine for LLM apps: validated variables, reusable few-shot blocks, and clean chat/message construction.
Project description
promptkit
A prompt template engine for LLM apps: validated variables, reusable few-shot blocks, and clean chat/message construction.
Part of the ragkit suite. Install with
pip install ragkit-promptkit, thenimport promptkit.
promptkit replaces scattered f-strings that silently break when a variable is missing. You define templates once, get up-front validation of required variables, compose few-shot prompts, and build OpenAI-style message lists without hand-assembling dicts. Zero third-party dependencies -- standard library only, Python 3.8+.
Install
pip install ragkit-promptkit
Local development (from promptkit/):
pip install -e .
Quick Start
Define a template, inspect its variables, and render it:
from promptkit import PromptTemplate
tmpl = PromptTemplate("Summarize the following {kind} in {n} sentences:\n\n{text}")
print(tmpl.variables) # {'kind', 'n', 'text'}
print(tmpl.render(kind="article", n=3, text="..."))
render() also accepts a single dict:
tmpl.render({"kind": "article", "n": 3, "text": "..."})
Missing variables are reported all at once
If a referenced variable has no value (and no default), you get a
MissingVariableError listing every missing name -- not just the first:
from promptkit import PromptTemplate, MissingVariableError
tmpl = PromptTemplate("{greeting}, {name}! Welcome to {place}.")
try:
tmpl.render(greeting="Hello")
except MissingVariableError as exc:
print(exc) # Missing required variable(s): 'name', 'place'
print(exc.missing) # ['name', 'place']
Extra/unknown keyword arguments are ignored, so you can safely pass a shared context dict to many templates.
Literal braces
Use {{ and }} for literal braces (same rules as str.format):
PromptTemplate('Return JSON like {{"score": {n}}}').render(n=5)
# Return JSON like {"score": 5}
Defaults and partial()
Provide defaults for optional variables, and use partial() to bake in some
values while leaving the rest open:
from promptkit import PromptTemplate
tmpl = PromptTemplate(
"You are a {tone} assistant. Answer: {question}",
defaults={"tone": "friendly"},
)
tmpl.render(question="What is Python?")
# "You are a friendly assistant. Answer: What is Python?"
# Bake in the tone, get a new reusable template:
sarcastic = tmpl.partial(tone="sarcastic")
sarcastic.render(question="What is Python?")
# "You are a sarcastic assistant. Answer: What is Python?"
An explicit value always overrides a default. partial() returns a new
template and never mutates the original.
Few-shot prompts
FewShotTemplate stitches a prefix, a list of rendered examples, and a
suffix (which usually holds the final user query):
from promptkit import FewShotTemplate
few = FewShotTemplate(
example_template="Q: {q}\nA: {a}",
examples=[
{"q": "2 + 2", "a": "4"},
{"q": "3 * 3", "a": "9"},
],
prefix="Solve the math problems.",
suffix="Q: {question}\nA:",
example_separator="\n\n",
)
# Add more examples dynamically:
few.add_example(q="10 - 4", a="6")
print(few.render(question="7 + 5"))
Output:
Solve the math problems.
Q: 2 + 2
A: 4
Q: 3 * 3
A: 9
Q: 10 - 4
A: 6
Q: 7 + 5
A:
Missing-variable validation applies across the prefix, examples, and suffix.
Chat prompts -> message dicts
ChatPromptTemplate builds OpenAI-style list[dict] message payloads. Each
message content is rendered with the same PromptTemplate rules, and missing
variables are aggregated across all messages:
from promptkit import ChatPromptTemplate, system, user, assistant
chat = ChatPromptTemplate.from_messages([
system("You are a helpful {role}."),
user("Explain {topic} to a {level} audience."),
])
messages = chat.render(role="tutor", topic="recursion", level="beginner")
# [
# {"role": "system", "content": "You are a helpful tutor."},
# {"role": "user", "content": "Explain recursion to a beginner audience."},
# ]
Pass messages straight to your LLM client. The system, user, and
assistant helpers just return (role, template) tuples. If you prefer typed
objects, chat.render_messages(...) returns Message(role, content) dataclass
instances (each has .to_dict()).
Prompt registry and versioning
PromptRegistry is a tiny in-memory store for named, versioned prompts. get()
returns the latest version by default:
from promptkit import PromptRegistry, PromptTemplate
registry = PromptRegistry()
registry.register(PromptTemplate("Summarize: {text}", name="summarize", version="1.0"))
registry.register(PromptTemplate("TL;DR the following:\n{text}", name="summarize", version="2.0"))
registry.list() # ['summarize']
registry.get("summarize") # v2.0 (latest)
registry.get("summarize", version="1.0") # the v1.0 template
latest = registry.get("summarize")
latest.render(text="...")
Versions are compared numerically when they look like dotted numbers
("1.0", "2.3"), falling back to string comparison otherwise.
API summary
| Object | Purpose |
|---|---|
PromptTemplate |
Single-string template with {var} placeholders, defaults, partial(), and .variables. |
FewShotTemplate |
Prefix + examples + suffix composition with add_example(). |
ChatPromptTemplate |
Renders (role, template) pairs to message dicts. |
Message |
dataclass(role, content) with .to_dict(). |
system / user / assistant |
Helpers returning (role, template) tuples. |
PromptRegistry |
In-memory register / get / list with versioning. |
MissingVariableError |
Raised with .missing listing every unresolved variable. |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ragkit_promptkit-0.1.0.tar.gz.
File metadata
- Download URL: ragkit_promptkit-0.1.0.tar.gz
- Upload date:
- Size: 12.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e3fd22f4fb1eed2e16452d2dbb94b595080dd3c87b72126376fe18a172153e6
|
|
| MD5 |
e55ce6076b9e59951a47a16f45c31db6
|
|
| BLAKE2b-256 |
354a33263999854c5398b782080fe1bdedb12e90851599916e1cbe65dfb772d9
|
Provenance
The following attestation bundles were made for ragkit_promptkit-0.1.0.tar.gz:
Publisher:
publish.yml on Meet2147/pythonLibraries
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ragkit_promptkit-0.1.0.tar.gz -
Subject digest:
4e3fd22f4fb1eed2e16452d2dbb94b595080dd3c87b72126376fe18a172153e6 - Sigstore transparency entry: 2244621216
- Sigstore integration time:
-
Permalink:
Meet2147/pythonLibraries@6fde7a37ee929e2e8cfd85031d173ee2d3bb73a2 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Meet2147
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6fde7a37ee929e2e8cfd85031d173ee2d3bb73a2 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file ragkit_promptkit-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ragkit_promptkit-0.1.0-py3-none-any.whl
- Upload date:
- Size: 9.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d1929bc280eaf17eb275aeecc53d6b6be51f302b7e8186fc6579370e72de344e
|
|
| MD5 |
3885350e1852a85d6348386f1af66daf
|
|
| BLAKE2b-256 |
3867338f08f2e67526463d417cbc634775a47269bd720ec762a1f101270b2d60
|
Provenance
The following attestation bundles were made for ragkit_promptkit-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on Meet2147/pythonLibraries
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ragkit_promptkit-0.1.0-py3-none-any.whl -
Subject digest:
d1929bc280eaf17eb275aeecc53d6b6be51f302b7e8186fc6579370e72de344e - Sigstore transparency entry: 2244621555
- Sigstore integration time:
-
Permalink:
Meet2147/pythonLibraries@6fde7a37ee929e2e8cfd85031d173ee2d3bb73a2 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Meet2147
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6fde7a37ee929e2e8cfd85031d173ee2d3bb73a2 -
Trigger Event:
workflow_dispatch
-
Statement type: