This commit is contained in:
Harrison Chase
2024-02-06 11:30:31 -08:00
parent b64f34e85f
commit b0b792f114
2 changed files with 174 additions and 21 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

+174 -21
View File
@@ -1,15 +1,51 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "d72fae4e-f7de-42b7-91ee-bdd0a57ae46c",
"metadata": {},
"source": [
"# Prompt Generator\n",
"\n",
"In this example we will create a chat bot that helps a user generate a prompt.\n",
"It will first collect requirements from the user, and then will generate the prompt (and refine it based on user input).\n",
"These are split into two separate states, and the LLM decides when to transition between them.\n",
"\n",
"A graphical representation of the system can be found below.\n",
"\n",
"![](imgs/prompt-generator.png)"
]
},
{
"cell_type": "markdown",
"id": "6d78b593-ba26-4c90-b2e2-83119e47679f",
"metadata": {},
"source": [
"## Gather information\n",
"\n",
"First, let's define the part of the graph that will gather user requirements. This will be an LLM call with a specific system message. It will have access to a tool that it can call when it is ready to generate the prompt."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "c0aa20b8-fe59-4c91-a06f-32002f142a41",
"execution_count": 6,
"id": "53216ab5-2cd3-48a4-8778-41ba10f72519",
"metadata": {},
"outputs": [],
"source": [
"from langgraph.graph import MessageGraph\n",
"from langchain_core.messages import SystemMessage\n",
"\n",
"from langchain_openai import ChatOpenAI\n",
"from langchain_core.pydantic_v1 import BaseModel, Field\n",
"from typing import List"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "5f795b78-004d-40ca-95d6-069f67e4f9c9",
"metadata": {},
"outputs": [],
"source": [
"template = \"\"\"Your job is to get information from a user about what type of prompt template they want to create.\n",
"\n",
"You should get the following information from them:\n",
@@ -21,35 +57,87 @@
"\n",
"If you are not able to discerne this info, ask them to clarify! Do not attempt to wildly guess.\n",
"\n",
"After you are able to discerne all the information, call the relevant tool\"\"\"\n",
"After you are able to discerne all the information, call the relevant tool\"\"\""
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "153a7c89-ec75-430e-96ac-6294d4e6ea2b",
"metadata": {},
"outputs": [],
"source": [
"llm = ChatOpenAI(temperature=0)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "8325ed0e-177a-4129-b4a4-cd54d527c634",
"metadata": {},
"outputs": [],
"source": [
"def get_messages_info(messages):\n",
" return [SystemMessage(content=template)] + messages\n",
"\n",
"from langchain_openai import ChatOpenAI\n",
"\n",
"llm = ChatOpenAI(temperature=0)\n",
"\n",
"from langchain_core.pydantic_v1 import BaseModel, Field\n",
"from typing import List\n",
"\n",
"\n",
"class PromptInstructions(BaseModel):\n",
" \"\"\"Instructions on how to prompt the LLM.\"\"\"\n",
" objective: str\n",
" variables: List[str]\n",
" constraints: List[str]\n",
" requirements: List[str]\n",
"\n",
" requirements: List[str]"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "95bb557a-47f2-46fd-adf7-9cf0e8ffe51c",
"metadata": {},
"outputs": [],
"source": [
"llm_with_tool = llm.bind_tools([PromptInstructions])\n",
"\n",
"chain = get_messages_info | llm_with_tool\n",
"chain = get_messages_info | llm_with_tool"
]
},
{
"cell_type": "markdown",
"id": "bb40630f-83c7-4283-a6dd-04231805a7ed",
"metadata": {},
"source": [
"## Generate Prompt\n",
"\n",
"We now set up the state that will generate the prompt.\n",
"This will require a separate system message, as well as a function to filter out all message PRIOR to the tool invocation (as that is when the previous state decided it was time to generate the prompt"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "5b6736fb-21d7-44d3-a3fe-460f15945654",
"metadata": {},
"outputs": [],
"source": [
"# Helper function for determining if tool was called\n",
"def _is_tool_call(msg):\n",
" return hasattr(msg, \"additional_kwargs\") and 'tool_calls' in msg.additional_kwargs\n",
"\n",
" return hasattr(msg, \"additional_kwargs\") and 'tool_calls' in msg.additional_kwargs"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "ca9a0234-bbeb-4bff-8276-8dde499c3390",
"metadata": {},
"outputs": [],
"source": [
"# New system prompt\n",
"prompt_system = \"\"\"Based on the following requirements, write a good prompt template:\n",
"\n",
"{reqs}\"\"\"\n",
"\n",
"# Function to get the messages for the prompt\n",
"# Will only get messages AFTER the tool call\n",
"def get_prompt_messages(messages):\n",
" tool_call = None\n",
" other_msgs = []\n",
@@ -59,10 +147,40 @@
" elif tool_call is not None:\n",
" other_msgs.append(m)\n",
" return [SystemMessage(content=prompt_system.format(reqs=tool_call))] + other_msgs\n",
" \n",
"\n",
"prompt_gen_chain = get_prompt_messages | llm\n",
" "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "3293d2d3-e060-4c98-8065-3696b049b5fc",
"metadata": {},
"outputs": [],
"source": [
"prompt_gen_chain = get_prompt_messages | llm"
]
},
{
"cell_type": "markdown",
"id": "8dbabda8-34f0-4eef-bce2-ad3ff505366b",
"metadata": {},
"source": [
"## Define the state logic\n",
"\n",
"This is the logic for what state the chatbot is in.\n",
"If the last message is a tool call, then we are in the state where the \"prompt creator\" (`prompt`) should respond.\n",
"Otherwise, if the last message is not a HumanMessage, then we know the human should respond next and so we are in the `END` state.\n",
"If the last message is a HumanMessage, then if there was a tool call previously we are in the `prompt` state.\n",
"Otherwise, we are in the \"info gathering\" (`info`) state."
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "74f29e15-20e2-420c-a450-84e929f16e4e",
"metadata": {},
"outputs": [],
"source": [
"def get_state(messages):\n",
" if _is_tool_call(messages[-1]):\n",
" return \"prompt\"\n",
@@ -74,6 +192,17 @@
" return \"info\""
]
},
{
"cell_type": "markdown",
"id": "b76bea78-07a5-418f-9b7c-71c376d4b6f7",
"metadata": {},
"source": [
"## Create the graph\n",
"\n",
"We can now the create the graph.\n",
"We will use a SqliteSaver to persist conversation history."
]
},
{
"cell_type": "code",
"execution_count": 2,
@@ -96,9 +225,19 @@
"graph = workflow.compile(checkpointer=memory)"
]
},
{
"cell_type": "markdown",
"id": "afcf523c-265d-45cf-a981-fc50c50c1738",
"metadata": {},
"source": [
"## Use the graph\n",
"\n",
"We can now use the created chatbot."
]
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 5,
"id": "25793988-45a2-4e65-b33c-64e72aadb10e",
"metadata": {},
"outputs": [
@@ -240,6 +379,20 @@
"---\n",
"\n"
]
},
{
"name": "stdin",
"output_type": "stream",
"text": [
"User (q/Q to quit): q\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"AI: Byebye\n"
]
}
],
"source": [