Un système de gestion rapide validé et validé pour les LLM qui attrape tôt les erreurs, applique la sécurité de type et fournit un moyen structuré de gérer les invites. Utilise des modèles pydantes pour la validation variable et les modèles Jinja2 pour le rendu rapide.
Remarque : Cette bibliothèque est en début de développement et sujet à changement.
J'ai toujours trouvé difficile de gérer des invites dynamiques pour les LLM. Le processus est sujet aux erreurs, avec des problèmes souvent découverts uniquement lors de l'exécution. Typed-Prumpt vise à résoudre ce problème en fournissant un moyen structuré et sécurisé de gérer les invites qui attrape les erreurs tôt et applique la sécurité de type.
Avertissement : Il s'agit d'un projet personnel pour résoudre les reproches que j'ai eues dans le passé et non affiliés à aucune organisation. C'est un travail en cours et sujet à changement.
J'ajouterai plus de fonctionnalités et d'exemples à l'avenir. Si vous avez des suggestions ou des commentaires, n'hésitez pas à ouvrir un problème!
from typed_prompt import BasePrompt
from pydantic import BaseModel
from typing import Optional
# Define your variables
class UserVars ( BaseModel ):
name : str
expertise : str
# This works - all template variables are defined
class ValidPrompt ( BasePrompt [ UserVars ]):
"""Helping {{name}} with {{expertise}} level knowledge."""
prompt_template : str = "Explain {{topic}} to me"
variables : UserVars
def render ( self , * , topic : str , ** extra_vars ) -> RenderOutput :
extra_vars [ "topic" ] = topic
return super (). render ( ** extra_vars )
# This fails immediately - 'unknown_var' not defined
class InvalidPrompt ( BasePrompt [ UserVars ]):
prompt_template : str = "What is {{unknown_var}}?" # ValueError!
variables : UserVars
# This fails - 'expertise' defined but never used
class UnusedVarPrompt ( BasePrompt [ UserVars ]):
prompt_template : str = "Hello {{name}}" # ValueError!
variables : UserVars from typing import Union
class TemplateVars ( BaseModel ):
user_type : Union [ "expert" , "beginner" ]
name : str
preferences : Optional [ dict ] = None
class ConditionalPrompt ( BasePrompt [ TemplateVars ]):
"""{% if user_type == 'expert' %}
Technical advisor for {{name}}
{% else %}
Friendly helper for {{name}}
{% endif %}"""
prompt_template : str = """
{% if preferences %}
Considering your preferences: {% for k, v in preferences.items() %}
- {{k}}: {{v}}{% endfor %}
{% endif %}
How can I help with {{topic}}?
"""
variables : TemplateVars
def render ( self , * , topic : str , ** extra_vars ) -> RenderOutput :
extra_vars [ "topic" ] = topic
return super (). render ( ** extra_vars ) from typed_prompt import RenderOutput
from pydantic import BaseModel , Field
class MyConfig ( BaseModel ):
temperature : float = Field ( default = 0.7 , ge = 0 , le = 2 )
model : str = Field ( default = "gpt-4" )
class MyPrompt ( BasePrompt [ UserVars ]):
"""Assistant for {{name}}"""
prompt_template : str = "Help with {{topic}}"
variables : UserVars
config : MyConfig = Field ( default_factory = MyConfig )
def render ( self , * , topic : str , ** extra_vars ) -> RenderOutput :
extra_vars [ "topic" ] = topic
return super (). render ( ** extra_vars )
# Use custom config
prompt = MyPrompt (
variables = UserVars ( name = "Alice" , expertise = "intermediate" ),
config = MyConfig ( temperature = 0.9 , model = "gpt-3.5-turbo" )
)Remarque : L'utilisation de aucune comme valeur pour les variables facultatives rendra comme
Nonedans l'invite. Eg "Exemple de test{{var}}rendra commeTest example NonesivarestNone. C'est le comportement par défaut de Jinja. Par conséquent, vous devez gérer cela dans votre modèle Jinja2. Eg{{if var}}ou{{var | default('default value')}}ou cependant vous voulez le gérer.
La bibliothèque valide vos modèles d'invite pendant la définition de la classe:
Toutes les variables sont validées à travers le pydontique:
Joindre une configuration personnalisée aux invites:
Considérez cet exemple:
# Without typed-prompt
def create_prompt ( user_data ):
template = "Hello {{username}}, your level is {{level}}"
# Error only discovered when rendering with wrong data
return template . format ( ** user_data ) # KeyError at runtime!
# With typed-prompt
class UserPrompt ( BasePrompt [ UserVars ]):
prompt_template : str = "Hello {{unknown_var}}" # Error immediately!
variables : UserVarsLa bibliothèque attrape les erreurs de modèle au moment de la définition.
uv add tpyed-promptou
pip install typed-promptPour plus d'exemples et de documentation détaillée, consultez le répertoire des exemples.
Pour exécuter les exemples:
uv run python examples/user.pyTyped-Prumpt utilise une structure invite en deux parties qui correspond aux modèles d'interaction LLM courants:
Invite du système : fournit un contexte ou des instructions pour le modèle d'IA. Vous pouvez définir cela de deux manières:
system_prompt_template Invite utilisateur : contient le modèle d'invite réel qui sera envoyé au modèle. Ceci est toujours défini dans l'attribut de classe prompt_template .
Les variables dans les produits dactylographiques sont gérées par trois mécanismes complémentaires:
Modèle de variables : un modèle pydante qui définit les variables de base dont votre invite a besoin:
class UserVariables ( BaseModel ):
name : str
age : int
occupation : Optional [ str ] = NoneParamètres de la méthode de rendu : les variables supplémentaires peuvent être définies comme des arguments de mots clés uniquement dans une méthode de rendu personnalisée:
def render ( self , * , learning_topic : str , ** extra_vars ) -> RenderOutput :
extra_vars [ "learning_topic" ] = learning_topic
return super (). render ( ** extra_vars )Variables supplémentaires : les variables uniques peuvent être transmises directement à la méthode de rendu.
La bibliothèque effectue une validation complète pour attraper tôt les problèmes communs:
Pour les invites complexes, vous pouvez charger des modèles à partir de fichiers externes:
class ComplexPrompt ( BasePrompt [ ComplexVariables ]):
system_prompt_template = Path ( "templates/system_prompt.j2" ). read_text ()
prompt_template : str = Path ( "templates/user_prompt.j2" ). read_text ()Remarque : Avec des moteurs de modèles comme Jinja2, vous pouvez normalement des modèles de rechargement à chaud, mais cela n'est pas pris en charge dans le produit dactylographié car les modèles sont validés au moment de la définition de la classe.
La classe fondamentale pour créer des invites structurées.
T : Une sous-classe Pydant Basemodel définissant la structure des variables de modèle system_prompt_template : Facultatif [Str] - Modèle d'invite systèmeprompt_template : Str - Modèle d'invite utilisateurvariables : T - Instance du modèle de variables render(**extra_vars) -> RenderOutput : rend les deux invites avec des variables fourniesUn nom nommé offrant un accès structuré aux invites rendues:
system_prompt : Facultatif [Str] - l'invite du système renduuser_prompt : str - l'invite utilisateur rendu Structurez vos modèles pour une lisibilité et une maintenabilité maximales:
Utilisez les docstrings pour les invites système : lorsque cela est possible, définissez les invites du système dans les docstrings de classe pour une meilleure organisation de code:
class UserPrompt ( BasePrompt [ UserVariables ]):
"""You are having a conversation with {{name}}, a {{age}}-year-old {{occupation}}."""
prompt_template : str = "What would you like to discuss?"Modèles complexes séparés : pour les modèles plus longs, utilisez des fichiers externes:
system_prompt_template = Path ( "templates/system_prompt.j2" ). read_text ()Utilisez la syntaxe conditionnelle de Jinja2 pour le contenu dynamique:
class DynamicPrompt ( BasePrompt [ Variables ]):
prompt_template : str = """
{% if expert_mode %}
Provide a detailed technical explanation of {{topic}}
{% else %}
Explain {{topic}} in simple terms
{% endif %}
""" Les contributions sont les bienvenues!
Ce projet est autorisé en vertu de la licence MIT - voir le fichier de licence pour plus de détails.
Les options ne rendront toujours pas comme None dans l'invite.
Rendez Jinja2 Facultatif, (pour des modèles très simples, utilisez simplement la format de chaîne par exemple f"Hello {name}" ). Peut-être que devrait avoir commencé à plus simple lol.
OUTPUT OBJECTIF OUVERTES MESSAGES COMPATIBLES.
La possibilité de définir, pas seulement une invite de système et une seule invite, mais des chaînes invites. par exemple system_prompt -> user_prompt -> assistant_response -> user_prompt -> assistant_response -> ...