mirror of
https://github.com/hwchase17/langchain.git
synced 2026-07-13 12:14:06 +00:00
254 lines
9.3 KiB
Plaintext
254 lines
9.3 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "d31df93e",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Getting Started\n",
|
|
"\n",
|
|
"This notebook walks through the different types of guards you can use. Guards are a set of directives that can be used to restrict the output of agents, chains, prompts, or really any function that outputs a string. "
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "d051c1da",
|
|
"metadata": {},
|
|
"source": [
|
|
"## @RestrictionGuard\n",
|
|
"RestrictionGuard is used to restrict output using an llm. By passing in a set of restrictions like \"the output must be in latin\" or \"The output must be about baking\" you can start to prevent your chain, agent, tool, or any llm generally from returning unpredictable content. "
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "54301321",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from langchain.llms import OpenAI\n",
|
|
"from langchain.guards import RestrictionGuard\n",
|
|
"\n",
|
|
"llm = OpenAI(temperature=0.9)\n",
|
|
"\n",
|
|
"text = \"What would be a good company name a company that makes colorful socks for romans?\"\n",
|
|
"\n",
|
|
"@RestrictionGuard(restrictions=['output must be in latin'], llm=llm, retries=0)\n",
|
|
"def sock_idea():\n",
|
|
" return llm(text)\n",
|
|
" \n",
|
|
"sock_idea()"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "fec1b8f4",
|
|
"metadata": {},
|
|
"source": [
|
|
"The restriction guard works by taking in a set of restrictions, an llm to use to judge the output on those descriptions, and an int, retries, which defaults to zero and allows a function to be called again if it fails to pass the guard.\n",
|
|
"\n",
|
|
"Restrictions should always be written in the form out 'the output must x' or 'the output must not x.'"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "4a899cdb",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"@RestrictionGuard(restrictions=['output must be about baking'], llm=llm, retries=1)\n",
|
|
"def baking_bot(user_input):\n",
|
|
" return llm(user_input)\n",
|
|
" \n",
|
|
"baking_bot(input(\"Ask me any question about baking!\"))"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "c5e9bb34",
|
|
"metadata": {},
|
|
"source": [
|
|
"The restriction guard works by taking your set of restrictions and prompting a provided llm to answer true or false whether a provided output violates those restrictions. Since it uses an llm, the results of the guard itself can be unpredictable. \n",
|
|
"\n",
|
|
"The restriction guard is good for moderation tasks that there are not other tools for, like moderating what type of content (baking, poetry, etc) or moderating what language.\n",
|
|
"\n",
|
|
"The restriction guard is bad at things llms are bad at. For example, the restriction guard is bad at moderating things dependent on math or individual characters (no words greater than 3 syllables, no responses more than 5 words, no responses that include the letter e)."
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "6bb0c1da",
|
|
"metadata": {},
|
|
"source": [
|
|
"## @StringGuard\n",
|
|
"\n",
|
|
"The string guard is used to restrict output that contains some percentage of a provided string. Common use cases may include preventing prompt leakage or preventing a list of derogatory words from being used. The string guard can also be used for things like preventing common outputs or preventing the use of protected words. \n",
|
|
"\n",
|
|
"The string guard takes a list of protected strings, a 'leniency' which is just the percent of a string that can show up before the guard is triggered (lower is more sensitive), and a number of retries.\n",
|
|
"\n",
|
|
"Unlike the restriction guard, the string guard does not rely on an llm so using it is computationally cheap and fast.\n",
|
|
"\n",
|
|
"For example, suppose we want to think of sock ideas but want unique names that don't already include the word 'sock':"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "ae046bff",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from langchain.prompts import PromptTemplate\n",
|
|
"from langchain.guards import StringGuard\n",
|
|
"from langchain.chains import LLMChain\n",
|
|
"\n",
|
|
"llm = OpenAI(temperature=0.9)\n",
|
|
"prompt = PromptTemplate(\n",
|
|
" input_variables=[\"product\"],\n",
|
|
" template=\"What is a good name for a company that makes {product}?\",\n",
|
|
")\n",
|
|
"\n",
|
|
"chain = LLMChain(llm=llm, prompt=prompt)\n",
|
|
"\n",
|
|
"@StringGuard(protected_strings=['sock'], leniency=1, retries=5)\n",
|
|
"def sock_idea():\n",
|
|
" return chain.run(\"colorful socks\")\n",
|
|
" \n",
|
|
"sock_idea()"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "fe5fd55e",
|
|
"metadata": {},
|
|
"source": [
|
|
"If we later decided that the word 'fuzzy' was also too generic, we could add it to protected strings:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "26b58788",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"@StringGuard(protected_strings=['sock', 'fuzzy'], leniency=1, retries=5)\n",
|
|
"def sock_idea():\n",
|
|
" return chain.run(\"colorful socks\")"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "c3ccb22e",
|
|
"metadata": {},
|
|
"source": [
|
|
"*NB: Leniency is set to 1 for this example so that only strings that include the whole word \"sock\" will violate the guard.*\n",
|
|
"\n",
|
|
"*NB: Capitalization does not count as a difference when checking differences in strings.*\n",
|
|
"\n",
|
|
"Suppose that we want to let users ask for sock company names but are afraid they may steal out super secret genius sock company naming prompt. The first thought may be to just add our prompt template to the protected strings. The problem, though, is that the leniency for our last 'sock' guard is too high: the prompt may be returned a little bit different and not be caught if the guard leniency is set to 100%. The solution is to just add two guards! The sock one will be checked first and then the prompt one. This can be done since all a guard does is look at the output of the function below it.\n",
|
|
"\n",
|
|
"For our prompt protecting string guard, we will set the leniency to 50%. If 50% of the prompt shows up in the answer, something probably went wrong!"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "aa5b8ef1",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"llm = OpenAI(temperature=0.9)\n",
|
|
"prompt = PromptTemplate(\n",
|
|
" input_variables=[\"description\"],\n",
|
|
" template=\"What is a good name for a company that makes {description} type of socks?\",\n",
|
|
")\n",
|
|
"\n",
|
|
"chain = LLMChain(llm=llm, prompt=prompt)\n",
|
|
"\n",
|
|
"@StringGuard(protected_strings=[prompt.template], leniency=.5, retries=5)\n",
|
|
"@StringGuard(protected_strings=['sock'], leniency=1, retries=5)\n",
|
|
"def sock_idea():\n",
|
|
" return chain.run(input(\"What type of socks does your company make?\"))"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "3535014e",
|
|
"metadata": {},
|
|
"source": [
|
|
"## @CustomGuard\n",
|
|
"\n",
|
|
"The custom guard allows you to easily turn any function into your own guard! The custom guard takes in a function and, like other guards, a number of retries. The function should take a string as input and return True if the string violates the guard and False if not. \n",
|
|
"\n",
|
|
"One use cases for this guard could be to create your own local classifier model to, for example, classify text as \"on topic\" or \"off topic.\" Or, you may have a model that determines sentiment. You could take these models and add them to a custom guard to ensure that the output of your llm, chain, or agent is exactly inline with what you want it to be.\n",
|
|
"\n",
|
|
"Here's an example of a simple guard that prevents jokes from being returned that are too long."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "2acaaf18",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from langchain import LLMChain, OpenAI, PromptTemplate\n",
|
|
"from langchain.guards import CustomGuard\n",
|
|
"\n",
|
|
"llm = OpenAI(temperature=0.9)\n",
|
|
"\n",
|
|
"prompt_template = \"Tell me a {adjective} joke\"\n",
|
|
"prompt = PromptTemplate(\n",
|
|
" input_variables=[\"adjective\"], template=prompt_template\n",
|
|
")\n",
|
|
"chain = LLMChain(llm=OpenAI(), prompt=prompt)\n",
|
|
"\n",
|
|
"def is_long(llm_output):\n",
|
|
" return len(llm_output) > 100\n",
|
|
"\n",
|
|
"@CustomGuard(guard_function=is_long, retries=1)\n",
|
|
"def call_chain():\n",
|
|
" return chain.run(adjective=\"political\")\n",
|
|
"\n",
|
|
"call_chain()"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.9.13"
|
|
},
|
|
"vscode": {
|
|
"interpreter": {
|
|
"hash": "f477efb0f3991ec3d5bbe3bccb06e84664f3f1037cc27215e8b02d2d22497b99"
|
|
}
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|