mirror of
https://github.com/james-m-jordan/openai-cookbook.git
synced 2025-05-09 19:32:38 +00:00
382 lines
12 KiB
Plaintext
382 lines
12 KiB
Plaintext
![]() |
{
|
||
|
"cells": [
|
||
|
{
|
||
|
"attachments": {},
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"# Redis as a Context Store with OpenAI Chat\n",
|
||
|
"This notebook demonstrates how to use Redis as high-speed context memory with ChatGPT.\n",
|
||
|
"\n",
|
||
|
"## Prerequisites\n",
|
||
|
"* Redis instance with the Redis Search and Redis JSON modules\n",
|
||
|
"* Redis-py client lib\n",
|
||
|
"* OpenAI Python client lib\n",
|
||
|
"* OpenAI API key\n",
|
||
|
"\n",
|
||
|
"## Installation\n",
|
||
|
"Install Python modules necessary for the examples."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"vscode": {
|
||
|
"languageId": "shellscript"
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"! pip install -r requirements.txt"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"attachments": {},
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## OpenAI API Key\n",
|
||
|
"Create a .env file and add your OpenAI key to it"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": null,
|
||
|
"metadata": {
|
||
|
"vscode": {
|
||
|
"languageId": "shellscript"
|
||
|
}
|
||
|
},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"OPENAI_API_KEY=your_key"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"attachments": {},
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## OpenAI Setup\n",
|
||
|
"Key load + helper function for chat completion"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 6,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"import openai\n",
|
||
|
"import os\n",
|
||
|
"from dotenv import load_dotenv\n",
|
||
|
"\n",
|
||
|
"load_dotenv()\n",
|
||
|
"openai.api_key = os.getenv(\"OPENAI_API_KEY\")\n",
|
||
|
"\n",
|
||
|
"def get_completion(prompt, model=\"gpt-3.5-turbo\"):\n",
|
||
|
" messages = [{\"role\": \"user\", \"content\": prompt}]\n",
|
||
|
" response = openai.ChatCompletion.create(\n",
|
||
|
" model=model,\n",
|
||
|
" messages=messages,\n",
|
||
|
" temperature=0, \n",
|
||
|
" )\n",
|
||
|
" return response.choices[0].message[\"content\"]"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"attachments": {},
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## Experiment - Chat Completion on a Topic outside of the Model's Knowledge Cutoff Date\n",
|
||
|
"Gpt-3.5-turbo was trained on data up to Sep 2021. Let's ask it a question about something that is beyond that date. In this case, the FTX/Sam Bankman-Fried scandal."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 7,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"name": "stdout",
|
||
|
"output_type": "stream",
|
||
|
"text": [
|
||
|
"As an AI language model, I cannot provide a personal opinion. However, FTX has been recognized as one of the fastest-growing cryptocurrency exchanges and has received positive reviews for its user-friendly interface, low fees, and innovative products. Additionally, Sam Bankman-Fried has been praised for his leadership and strategic decision-making, including FTX's recent acquisition of Blockfolio. Overall, FTX appears to be a well-managed company.\n"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"prompt = \"Is Sam Bankman-Fried's company, FTX, considered a well-managed company?\"\n",
|
||
|
"response = get_completion(prompt)\n",
|
||
|
"print(response)"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"attachments": {},
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## Hallucinations\n",
|
||
|
"An unfortunate behavior of these AI systems is the system will provide a confident-sounding response - even when the system is not confident with its result. This degenerative behavior has been termed 'hallucination'. One way to mitigate hallucinations is prompt re-engineering, as seen below."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 8,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"name": "stdout",
|
||
|
"output_type": "stream",
|
||
|
"text": [
|
||
|
"Unknown.\n"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"prompt =\"Is Sam Bankman-Fried's company, FTX, considered a well-managed company? If you don't know for certain, say unknown.\"\n",
|
||
|
"response = get_completion(prompt)\n",
|
||
|
"print(response)"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"attachments": {},
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## Additional Context\n",
|
||
|
"Another way to combat hallucinations is to give the system more information such that it can make intelligent decisions vs guessing. We'll use Redis as the source for that additional context. We'll pull in business news articles from after the GPT knowledge cut-off date such that the system will have a better understanding of how FTX was actually managed.\n",
|
||
|
"\n",
|
||
|
"To complete the 'hallucination' metaphor, we can say Redis is acting as an anti-psychotic medication. "
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"attachments": {},
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## Start the Redis Stack Docker container"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 11,
|
||
|
"metadata": {
|
||
|
"vscode": {
|
||
|
"languageId": "shellscript"
|
||
|
}
|
||
|
},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"name": "stdout",
|
||
|
"output_type": "stream",
|
||
|
"text": [
|
||
|
"\u001b[1A\u001b[1B\u001b[0G\u001b[?25l[+] Running 0/0\n",
|
||
|
" ⠋ Network redisqna_default Creating \u001b[34m0.1s \u001b[0m\n",
|
||
|
"\u001b[?25h\u001b[1A\u001b[1A\u001b[0G\u001b[?25l\u001b[34m[+] Running 1/1\u001b[0m\n",
|
||
|
" \u001b[32m✔\u001b[0m Network redisqna_default \u001b[32mCreated\u001b[0m \u001b[34m0.1s \u001b[0m\n",
|
||
|
" ⠿ Container redisqna-redis-1 Starting \u001b[34m0.1s \u001b[0m\n",
|
||
|
"\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Running 1/2\n",
|
||
|
" \u001b[32m✔\u001b[0m Network redisqna_default \u001b[32mCreated\u001b[0m \u001b[34m0.1s \u001b[0m\n",
|
||
|
" ⠿ Container redisqna-redis-1 Starting \u001b[34m0.2s \u001b[0m\n",
|
||
|
"\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l[+] Running 1/2\n",
|
||
|
" \u001b[32m✔\u001b[0m Network redisqna_default \u001b[32mCreated\u001b[0m \u001b[34m0.1s \u001b[0m\n",
|
||
|
" ⠿ Container redisqna-redis-1 Starting \u001b[34m0.3s \u001b[0m\n",
|
||
|
"\u001b[?25h\u001b[1A\u001b[1A\u001b[1A\u001b[0G\u001b[?25l\u001b[34m[+] Running 2/2\u001b[0m\n",
|
||
|
" \u001b[32m✔\u001b[0m Network redisqna_default \u001b[32mCreated\u001b[0m \u001b[34m0.1s \u001b[0m\n",
|
||
|
" \u001b[32m✔\u001b[0m Container redisqna-redis-1 \u001b[32mStarted\u001b[0m \u001b[34m0.4s \u001b[0m\n",
|
||
|
"\u001b[?25h"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"! docker compose up -d"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"attachments": {},
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## Connect Redis client"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 12,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/plain": [
|
||
|
"True"
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 12,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"from redis import from_url\n",
|
||
|
"\n",
|
||
|
"REDIS_URL = 'redis://localhost:6379'\n",
|
||
|
"client = from_url(REDIS_URL)\n",
|
||
|
"client.ping()"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"attachments": {},
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## Create Index"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 13,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"text/plain": [
|
||
|
"b'OK'"
|
||
|
]
|
||
|
},
|
||
|
"execution_count": 13,
|
||
|
"metadata": {},
|
||
|
"output_type": "execute_result"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"from redis.commands.search.field import TextField, VectorField\n",
|
||
|
"from redis.commands.search.indexDefinition import IndexDefinition, IndexType\n",
|
||
|
"\n",
|
||
|
"schema = [ VectorField('$.vector', \n",
|
||
|
" \"FLAT\", \n",
|
||
|
" { \"TYPE\": 'FLOAT32', \n",
|
||
|
" \"DIM\": 1536, \n",
|
||
|
" \"DISTANCE_METRIC\": \"COSINE\"\n",
|
||
|
" }, as_name='vector' ),\n",
|
||
|
" TextField('$.content', as_name='content')\n",
|
||
|
" ]\n",
|
||
|
"idx_def = IndexDefinition(index_type=IndexType.JSON, prefix=['doc:'])\n",
|
||
|
"client.ft('idx').create_index(schema, definition=idx_def)"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"attachments": {},
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## Load Data Files into Redis as JSON Objects with Text and Vector Fields"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 14,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"import os\n",
|
||
|
"import openai\n",
|
||
|
"\n",
|
||
|
"directory = './assets/'\n",
|
||
|
"model='text-embedding-ada-002'\n",
|
||
|
"i = 1\n",
|
||
|
"for file in os.listdir(directory):\n",
|
||
|
" with open(os.path.join(directory, file)) as f:\n",
|
||
|
" content = f.read()\n",
|
||
|
" vector = openai.Embedding.create(input = [content], model = model)['data'][0]['embedding']\n",
|
||
|
" client.json().set(f'doc:{i}', '$', {'content': content, 'vector': vector})\n",
|
||
|
" i += 1"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"attachments": {},
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## Embed the Question and Perform VSS to find the most relevant document"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 15,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"from redis.commands.search.query import Query\n",
|
||
|
"import numpy as np\n",
|
||
|
"\n",
|
||
|
"vec = np.array(openai.Embedding.create(input = [prompt], model = model)['data'][0]['embedding'], dtype=np.float32).tobytes()\n",
|
||
|
"q = Query('*=>[KNN 1 @vector $query_vec AS vector_score]')\\\n",
|
||
|
" .sort_by('vector_score')\\\n",
|
||
|
" .return_fields('content')\\\n",
|
||
|
" .dialect(2) \n",
|
||
|
"params = {\"query_vec\": vec}\n",
|
||
|
"\n",
|
||
|
"context = client.ft('idx').search(q, query_params=params).docs[0].content"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"attachments": {},
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## Repeat the Question to OpenAI with context\n",
|
||
|
"Now that we have relevant context, add that to the prompt to OpenAI and get a very different response."
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 16,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"name": "stdout",
|
||
|
"output_type": "stream",
|
||
|
"text": [
|
||
|
"No, Sam Bankman-Fried's company FTX is not considered a well-managed company as it has filed for bankruptcy and owes as much as $8 billion to its creditors. The collapse of FTX has destabilized the crypto industry, and the company is already the target of investigations by the Securities and Exchange Commission and the Justice Department. FTX was widely viewed as one of the most stable and responsible companies in the freewheeling, loosely regulated crypto industry, but its risky practices have become pervasive in crypto, leading to a reckoning.\n"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"prompt = f\"\"\"\n",
|
||
|
"Using the information delimited by triple backticks, answer this question: Is Sam Bankman-Fried's company, FTX, considered a well-managed company?\n",
|
||
|
"\n",
|
||
|
"Context: ```{context}```\n",
|
||
|
"\"\"\"\n",
|
||
|
"\n",
|
||
|
"response = get_completion(prompt)\n",
|
||
|
"print(response)"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"metadata": {
|
||
|
"kernelspec": {
|
||
|
"display_name": ".venv",
|
||
|
"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.10.6"
|
||
|
},
|
||
|
"orig_nbformat": 4
|
||
|
},
|
||
|
"nbformat": 4,
|
||
|
"nbformat_minor": 2
|
||
|
}
|