Custom templates¶
Prompt templates that automatically bind to a database are built on top of a specialized kind of prompt template in LangChain called DependencyfulPromptTemplate
. This kind of prompt has two abilities:
- it retain "dependencies" (such as a database connection) throughout its lifetime;
- it admits named arguments to the
format
method that will be routed to its own "getter" function, instead of directly replacing the placeholder variables in the prompt string.
The Cassandra-backed prompt template then builds a certain DependencyfulPromptTemplate
bound to the Cassandra database in the right way. Thanks to metadata inspection, detailed knowledge about the DB schema is not provided explicitly when creating the prompt, as was shown earlier.
As another example, the Feast template (shown in a later page) builds a different DependencyfulPromptTemplate
which "knows" how to connect to Feast and retrieve the needed information to later fill the template string.
Customization¶
However, sometimes one may need to go beyond the ready-made templates and build a custom prompt. This page shows how this is done.
Let's build a mock "account balance checker" that associates a current balance to each user (a key-value store), but it also keeps a counter of how many times a certain balance is accessed.
class Balancer():
def __init__(self, accounts):
self.accounts = accounts
self._accesses = {}
def read(self, user):
if user in self.accounts:
self._accesses[user] = self._accesses.get(user, 0) + 1
return self.accounts[user]
def accesses(self):
return self._accesses
bal0 = Balancer({'Rita': 100, 'Otto': 40, 'Anna': 150})
bal0.read('Rita')
bal0.read('Rita')
bal0.read('Anna')
print(bal0.accesses())
{'Rita': 2, 'Anna': 1}
Ok, now let's create another balancer for use in the template:
myBalance = Balancer({'Katie': 1000, 'Gil': 800, 'Hugh': 1200})
Template creation¶
The template string¶
from langchain.prompts import PromptTemplate, StringPromptTemplate
balancePrompt = ("Hello. Your balance is {balance}. "
"You have {unreads} unread message(s).")
Dependencies¶
This template will have a single dependency, the Balancer
instance itself:
dependencyDict = {'balancer': myBalance}
Getter¶
We need a "getter" function, which will be called in the format
method of the template and whose first argument is the dict of dependencies (in this case the Balancer
instance), followed by any other keyword argument.
The getter must return a dict with values for all variables in the above PromptTemplate
that will be retrieved from the storage dependency, i.e. not supplied directly at format
time:
def balanceGetter(deps, **kwargs):
userName = kwargs['user_name']
balancer = deps['balancer']
return {'balance': balancer.read(userName)}
from langchain.prompts import DependencyfulPromptTemplate
myCustomTemplate = DependencyfulPromptTemplate(
template=balancePrompt,
dependencies=dependencyDict,
getter=balanceGetter,
input_variables=["user", "user_name"],
forceGetterArguments=["user_name"],
)
Rendering¶
myCustomTemplate.format(user_name='Gil', unreads=123)
'Hello. Your balance is 800. You have 123 unread message(s).'
myCustomTemplate.format(user_name='Gil', unreads=456)
'Hello. Your balance is 800. You have 456 unread message(s).'
myCustomTemplate.format(user_name='Katie', unreads=789)
'Hello. Your balance is 1000. You have 789 unread message(s).'
myBalance.accesses()
{'Gil': 2, 'Katie': 1}