Welcome to Pydantic Prompter
Pydantic Prompter is a lightweight tool designed for effortlessly constructing prompts and obtaining Pydantic objects as outputs.
Seamlessly call LLMs like functions in Python with Pydantic Prompter. It handles prompt creation and output parsing to custom models for providers like Cohere, Bedrock, and OpenAI. Get OpenAi function calling API capabilities for any LLM. Structured text generation with less code.
The design of the library's API draws inspiration by DeclarAI. Other alternatives Outlines and Jsonformer
Why should you use Pydantic Prompter
💻 Seamless LLM Integration: Pydantic Prompter supported multiple LLM providers, including Cohere, Bedrock, and OpenAI, right out of the box. This meant we could easily switch between providers without modifying our code, ensuring flexibility and portability.
📦 Structured Outputs: By leveraging Pydantic models, Pydantic Prompter automatically parsed the LLM's output into structured Python objects. Manual parsing became a thing of the past, and we enjoyed consistently formatted data that was a breeze to work with.
✍️ Easy Prompt Engineering: Crafting effective prompts is an art, and Pydantic Prompter made us all masters. By defining prompts using Python classes and string interpolation, we created readable, maintainable, and reusable prompts.
🔧 Reusable Components: Pydantic Prompter encouraged a modular approach, allowing us to define reusable prompt components such as instructions, examples, and constraints. This promoted code reuse and made maintaining our code effortless.
🐛 Logging and Debugging: Built-in logging and debugging features meant we could quickly identify and resolve any issues, ensuring a smooth and efficient development process, free of bugs and errors.
Install
OpenAI
Bedrock
Cohere
Usage
Basic usage
To utilize Pydantic Prompter with Jinja2 templates, follow the example below:
from pydantic_prompter import Prompter
from pydantic import BaseModel, Field
from typing import List
import os
os.environ["OPENAI_API_KEY"] = "sk-...."
class RecommendedEntry(BaseModel):
id: str
name: str
reason: str = Field(description="Why this entry fits the query", default="")
class RecommendationResults(BaseModel):
title: str
entries: List[RecommendedEntry]
@Prompter(llm="openai", jinja=True, model_name="gpt-3.5-turbo-16k")
def rank_recommendation(entries, query) -> RecommendationResults:
"""
- system: You are a movie ranking expert
- user: |
Which of the following JSON entries fit best to the query.
order by best fit descending
Base your answer ONLY on the given JSON entries
- user: >
The JSON entries:
{{ entries }}
- user: "query: {{ query }}"
"""
my_entries = (
'[{"text": "Description: Four everyday suburban guys come together as a ....'
)
print(rank_recommendation(entries=my_entries, query="Romantic comedy"))
# >>> title='Romantic Comedy' entries=[RecommendedEntry(id='2312973', \
# name='The Ugly Truth', reason='Romantic comedy genre')]
# ==Debug you query==
print(rank_recommendation.build_string(entries=my_entries, query="Romantic comedy"))
# >>> system: You are a movie ranking expert
# user: Which of the following JSON entries fit best to the query.
# order by best fit descending
# Base your answer ONLY on the given JSON entries
# user: The JSON entries: [{"text": "Description: Four everyday suburban guys come together as a ....
# user: query: Romantic comedy
Simple string formatting
For injecting conversation history through straightforward string formatting, refer to this example:
from pydantic import BaseModel
from pydantic_prompter import Prompter
class QueryGPTResponse(BaseModel):
google_like_search_term: str
@Prompter(llm="openai", model_name="gpt-3.5-turbo")
def search_query(history) -> QueryGPTResponse:
"""
{history}
- user: |
Generate a Google-like search query text
encompassing all previous chat questions and answers
"""
history = """
- user: Hi
- assistant: what genre do you want to watch?
- user: Comedy
- assistant: do you want a movie or series?
- user: Movie
"""
res = search_query.build_string(history=history)
print(res)
# >>> assistant: what genre do you want to watch?
# user: Comedy
# assistant: do you want a movie or series?
# user: Movie
# user: Generate a Google-like search query text
# encompassing all previous chat questions and answers
Jinja2 advance usage
For more advanced usage involving Jinja2 loops to inject conversation history, consider the following code snippet:
from pydantic import BaseModel
from pydantic_prompter import Prompter
class QueryGPTResponse(BaseModel):
google_like_search_term: str
@Prompter(llm="openai", jinja=True, model_name="gpt-3.5-turbo")
def search_query(history) -> QueryGPTResponse:
"""
{%- for line in history %}
{{ line }}
{% endfor %}
- user: |
Generate a Google-like search query text
encompassing all previous chat questions and answers
"""
history = [
"- user: Hi"
"- assistant: what genre do you want to watch?",
"- user: Comedy",
"- assistant: do you want a movie or series?",
"- user: Movie",
]
res = search_query.build_string(history=history)
print(res)
# >>> assistant: what genre do you want to watch?
# user: Comedy
# assistant: do you want a movie or series?
# user: Movie
# user: Generate a Google-like search query text
# encompassing all previous chat questions and answers
Simple typings
Use int
, float
, bool
or str
from pydantic_prompter import Prompter
import os
os.environ["AWS_DEFAULT_REGION"] = "us-east-1"
os.environ["AWS_ACCESS_KEY_ID"] = "..."
os.environ["AWS_SECRET_ACCESS_KEY"] = "..."
os.environ["AWS_SESSION_TOKEN"] = "..."
@Prompter(llm="cohere", model_name="command")
def me_and_mu_children(name) -> int:
"""
- user: hi, my name is {name} and my children are called, aa, bb, cc, dd, ee
- user: |
how many children do I have?
"""
print(me_and_mu_children(name="Zud"))
# >>> 5
Best practices
When using Pydantic Prompter, it is recommended to explicitly specify the parameter name you wish to retrieve, as demonstrated in the example below, where title is explicitly mentioned:
class RecommendationTitleResponse(BaseModel):
title: str = Field(description="4 to 6 words title")
@Prompter(llm="openai", jinja=True, model_name="gpt-3.5-turbo-16k")
def recommendation_title(json_entries) -> RecommendationTitleResponse:
"""
- user: >
Based on the JSON entries, suggest a minimum 4 words and maximum 6 words title
- user: >
The JSON entries:
{{ json_entries }}
"""
class BaseResponse(BaseModel):
text: str = Field(description="4 to 6 words text")
@Prompter(llm="openai", jinja=True, model_name="gpt-3.5-turbo-16k")
def recommendation_title(json_entries) -> BaseResponse:
"""
...
"""
Debugging and logging
You can view info and/or debugging logging using the following snippet:
Resulting