mirror of
https://github.com/run-llama/llama-lab.git
synced 2026-07-01 20:14:02 -04:00
add conversational agents (#17)
This commit is contained in:
@@ -70,6 +70,20 @@ Summarize the financial news from the past week.
|
||||
|
||||
```
|
||||
|
||||
### Conversational Agents
|
||||
|
||||
This is a fun conversational simulator between different agents. You can choose
|
||||
to provide some details about the context/setting, and watch as the conversation
|
||||
between different agents evolves.
|
||||
|
||||
A sample notebook is provided in the `convo_agents` folder. Usage:
|
||||
|
||||
```bash
|
||||
cd convo_agents
|
||||
|
||||
jupyter notebook ConvoAgents.ipynb
|
||||
```
|
||||
|
||||
## Ecosystem
|
||||
|
||||
Llama Lab is part of the broader Llama ecosystem.
|
||||
|
||||
@@ -0,0 +1,334 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "b6d25ba0-18f8-41e2-ba3a-62998051e87f",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/Users/jerryliu/Programming/llama-lab/convo_agents/.venv/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
|
||||
" from .autonotebook import tqdm as notebook_tqdm\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import logging\n",
|
||||
"import sys\n",
|
||||
"\n",
|
||||
"logging.basicConfig(stream=sys.stdout, level=logging.CRITICAL)\n",
|
||||
"logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))\n",
|
||||
"logger = logging.getLogger()\n",
|
||||
"logger.disabled = True\n",
|
||||
"\n",
|
||||
"from convo_agents import ConvoAgent, run_conversation_loop\n",
|
||||
"from llama_index import LLMPredictor, ServiceContext, GPTListIndex\n",
|
||||
"from langchain.chat_models import ChatOpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "00a03b81-6b7d-4083-b1ba-6adcbccbb0c7",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# llm_predictor = LLMPredictor(llm=ChatOpenAI(temperature=0, model_name=\"gpt-3.5-turbo\"))\n",
|
||||
"llm_predictor = LLMPredictor(llm=ChatOpenAI(temperature=0, model_name=\"gpt4\"))\n",
|
||||
"service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "16ab0602-a656-4a78-89dd-a8ef89eb8daf",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Casual Date Conversation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "4c6794c5-3ca5-4bda-9e75-237ce356991c",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"alice_user_prefix_tmpl = (\n",
|
||||
" \"Your name is {name}. \"\n",
|
||||
" \"You are on a first date with another person named Bob. \"\n",
|
||||
" \"We provide conversation context between you and Bob below. \"\n",
|
||||
")\n",
|
||||
"bob_user_prefix_tmpl = (\n",
|
||||
" \"Your name is {name}. \"\n",
|
||||
" \"You are on a first date with another person named Alice. \"\n",
|
||||
" \"We provide conversation context between you and Alice below. \"\n",
|
||||
")\n",
|
||||
"alice = ConvoAgent.from_defaults(\n",
|
||||
" name=\"Alice\", \n",
|
||||
" service_context=service_context, \n",
|
||||
" user_prefix_tmpl=alice_user_prefix_tmpl,\n",
|
||||
" lt_memory=GPTListIndex([])\n",
|
||||
" \n",
|
||||
")\n",
|
||||
"bob = ConvoAgent.from_defaults(\n",
|
||||
" name=\"Bob\", \n",
|
||||
" service_context=service_context,\n",
|
||||
" user_prefix_tmpl=bob_user_prefix_tmpl,\n",
|
||||
" lt_memory=GPTListIndex([])\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "81791984-738c-4332-8e00-479d10434399",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Alice: Nice to meet you, Bob!\n",
|
||||
"Bob: Nice to meet you too, Alice!\n",
|
||||
"Alice: So, what do you like to do for fun?\n",
|
||||
"Bob: I enjoy spending time outdoors, going for hikes, playing sports, and exploring new places. I also like to spend time with friends and family, playing board games, watching movies, and cooking.\n",
|
||||
"Alice: Wow, that sounds like a lot of fun! What's your favorite activity to do with friends and family?\n",
|
||||
"Bob: My favorite activity to do with friends and family is definitely playing board games. We always have a great time and lots of laughs!\n",
|
||||
"Alice: That sounds like a great way to bond and have fun! What's your favorite board game to play?\n",
|
||||
"Bob: My favorite board game to play is Monopoly. I love the strategy involved and the competition between players.\n",
|
||||
"Alice: That sounds like a lot of fun! Have you ever won a game of Monopoly?\n",
|
||||
"Bob: Yes, I have won a few games of Monopoly! It's always a great feeling when you come out on top.\n",
|
||||
"Alice: That must be a great feeling! What strategies do you use when playing Monopoly?\n",
|
||||
"Bob: When playing Monopoly, I like to focus on building up my properties and collecting rent. I also try to stay aware of what other players are doing and adjust my strategy accordingly.\n",
|
||||
"Alice: That sounds like a great strategy! Do you have any tips for other players who are just starting out with Monopoly?\n",
|
||||
"Bob: Sure! My biggest tip for new players is to focus on building up their properties and collecting rent. That way, they can start to accumulate money and build a strong foundation for their game.\n",
|
||||
"Alice: That's great advice! Do you have any other tips for new players?\n",
|
||||
"Bob: Another tip for new players is to try to stay aware of what other players are doing and adjust their strategy accordingly. That way, they can stay one step ahead of their opponents.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"KeyboardInterrupt\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"run_conversation_loop(alice, bob)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2064a38b-82c0-4dab-8886-eeb2fe357ad3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Doctor Conversation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "86169549-0b98-4d09-adc5-e6a8ffb19c31",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"alice_user_prefix_tmpl = (\n",
|
||||
" \"Your name is {name}. \"\n",
|
||||
" \"You are a patient who is seeing the doctor, and are getting the results of a blood pressure checkup. \"\n",
|
||||
" \"We provide conversation context between you and the doctor below. \"\n",
|
||||
"\n",
|
||||
")\n",
|
||||
"bob_user_prefix_tmpl = (\n",
|
||||
" \"Your name is {name}. \"\n",
|
||||
" \"You are a doctor; you are describing the results of a blood pressure test to the patient. \"\n",
|
||||
" \"We provide conversation context between you and the patient below. \"\n",
|
||||
")\n",
|
||||
"alice = ConvoAgent.from_defaults(\n",
|
||||
" name=\"Alice\", \n",
|
||||
" service_context=service_context, \n",
|
||||
" user_prefix_tmpl=alice_user_prefix_tmpl,\n",
|
||||
" lt_memory=GPTListIndex([])\n",
|
||||
")\n",
|
||||
"bob = ConvoAgent.from_defaults(\n",
|
||||
" name=\"Bob\", \n",
|
||||
" service_context=service_context,\n",
|
||||
" user_prefix_tmpl=bob_user_prefix_tmpl,\n",
|
||||
" lt_memory=GPTListIndex([])\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a2a3d69c-4470-43d0-95da-45f6670e3cef",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"run_conversation_loop(\n",
|
||||
" alice, \n",
|
||||
" bob,\n",
|
||||
" \"So, you're telling me that my blood pressure is too high?\",\n",
|
||||
" \"Yes\"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6dea734b-3324-4143-9026-6a170833ddcb",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Programming Interview Question"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "0debff8a-812a-4619-970c-d05aa56ffd9b",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"alice_user_prefix_tmpl = (\n",
|
||||
" \"Your name is {name}. \"\n",
|
||||
" \"You are interviewing for a software engineering job at Google, and you are speaking to the interviewer. \"\n",
|
||||
" \"We provide conversation context between you and the interviewer below. \"\n",
|
||||
" \"You want to ask fewer questions and get started on implementation sooner. \"\n",
|
||||
"\n",
|
||||
")\n",
|
||||
"bob_user_prefix_tmpl = (\n",
|
||||
" \"Your name is {name}. \"\n",
|
||||
" \"You are an engineering manager at Google, and plan to ask technical interview questions to a candidate. \"\n",
|
||||
" \"You want to ask the candidate to write code to perform binary search over a sorted list of numbers. \"\n",
|
||||
" \"If the candidate is implementing an incorrect solution, you want to critique their approach. \"\n",
|
||||
" \"We provide conversation context between you and the interviewee below. \"\n",
|
||||
")\n",
|
||||
"alice = ConvoAgent.from_defaults(\n",
|
||||
" name=\"Alice\", \n",
|
||||
" service_context=service_context, \n",
|
||||
" user_prefix_tmpl=alice_user_prefix_tmpl,\n",
|
||||
" lt_memory=GPTListIndex([])\n",
|
||||
")\n",
|
||||
"bob = ConvoAgent.from_defaults(\n",
|
||||
" name=\"Bob\", \n",
|
||||
" service_context=service_context,\n",
|
||||
" user_prefix_tmpl=bob_user_prefix_tmpl,\n",
|
||||
" lt_memory=GPTListIndex([])\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "9bf1133a-9934-413e-86dd-1e959080e33d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Alice: Could you tell me more about the programming question? I'm eager to get started on implementation.\n",
|
||||
"Bob: The question is to write a program to perform binary search over a sorted list of numbers. Can you explain your approach to solving this problem?\n",
|
||||
"Alice: Sure, my approach would be to use a loop to iterate through the list of numbers and compare each number to the target number. If the number is equal to the target number, the loop can return the index of the number. If the number is greater than the target number, the loop can move to the next number in the list. If the number is less than the target number, the loop can break and return the index of the number.\n",
|
||||
"Bob: That's a good approach, but it won't work for binary search. Binary search requires that the list of numbers is sorted, so you need to use a different approach. Can you explain a different approach you could take to solve this problem?\n",
|
||||
"Alice: Yes, I understand that binary search requires the list of numbers to be sorted. A different approach I could take is to use a divide and conquer algorithm to find the target number. The algorithm would divide the list of numbers into two halves, compare the target number to the middle number of the list, and then recursively search the half that contains the target number. This approach would be more efficient than the loop approach, as it would reduce the number of comparisons needed to find the target number.\n",
|
||||
"Bob: That's a great approach, Alice. Can you explain how you would implement the divide and conquer algorithm in code?\n",
|
||||
"Alice: Sure, I can explain how I would implement the divide and conquer algorithm in code. I would start by creating a function that takes in the list of numbers and the target number as parameters. Then, I would use a while loop to iterate through the list of numbers and compare each number to the target number. If the number is equal to the target number, the loop can return the index of the number. If the number is greater than the target number, the loop can move to the next number in the list. If the number is less than the target number, the loop can break and return the index of the number. Then, I would create a recursive function that takes in the list of numbers and the target number as parameters. This function would divide the list of numbers into two halves, compare the target number to the middle number of the list, and then recursively search the half that contains the target number. Finally, I would call the recursive function from the while loop to perform the binary search.\n",
|
||||
"Bob: That's a great explanation, Alice. Can you provide an example of how this code would work with a specific list of numbers and target number?\n",
|
||||
"Alice: Sure, I can provide an example. Let's say the list of numbers is [1, 3, 5, 7, 9] and the target number is 5. The while loop would iterate through the list of numbers and compare each number to the target number. When it reaches the number 5, it would return the index of the number, which is 2. Then, the recursive function would divide the list of numbers into two halves, [1, 3] and [5, 7, 9], and compare the target number to the middle number of the list, which is 5. Since the target number is equal to the middle number, the recursive function would return the index of the number, which is 2. Finally, the recursive function would be called from the while loop to perform the binary search, and the result would be the index of the number 5, which is 2.\n",
|
||||
"Bob: That's a great example, Alice. Can you explain how you would optimize the code to make it more efficient?\n",
|
||||
"Alice: To optimize the code, I would use a binary search tree instead of a loop. A binary search tree is a data structure that stores data in a hierarchical structure, allowing for faster searches. By using a binary search tree, the time complexity of the algorithm would be reduced from O(n) to O(log n). Additionally, I would use a recursive approach to traverse the tree, which would further reduce the time complexity of the algorithm.\n",
|
||||
"Bob: That's a great explanation, Alice. Can you provide an example of how this code would work with a specific list of numbers and target number?\n",
|
||||
"Alice: Sure, I can provide an example. Let's say the list of numbers is [1, 3, 5, 7, 9] and the target number is 5. The binary search tree would be constructed by inserting each number in the list into the tree. Then, the tree would be traversed using a recursive approach to find the target number. When the target number is found, the index of the number would be returned. In this case, the index of the number 5 would be 2.\n",
|
||||
"Bob: Great work, Alice. Can you explain how you would test the code to make sure it works correctly?\n",
|
||||
"Alice: Sure, I can explain how I would test the code. I would start by creating a test suite that contains a set of test cases. Each test case would contain a list of numbers and a target number. I would then run the code on each test case and compare the output of the code to the expected output. If the output of the code matches the expected output, then the code is working correctly. Additionally, I would use a debugger to step through the code and make sure that each line of code is executing correctly.\n",
|
||||
"Bob: That's great, Alice. Can you explain how you would optimize the code to make it more efficient?\n",
|
||||
"Alice: Sure, I can explain how I would optimize the code to make it more efficient. I would start by using a binary search tree instead of a loop. A binary search tree is a data structure that stores data in a hierarchical structure, allowing for faster searches. By using a binary search tree, the time complexity of the algorithm would be reduced from O(n) to O(log n). Additionally, I would use a recursive approach to traverse the tree, which would further reduce the time complexity of the algorithm.\n",
|
||||
"Bob: That's a great approach, Alice. Can you provide an example of how this code would work with a specific list of numbers and target number?\n",
|
||||
"Alice: Sure, I can provide an example. Let's say the list of numbers is [1, 3, 5, 7, 9] and the target number is 5. The binary search tree would be constructed by inserting each number in the list into the tree. Then, the tree would be traversed using a recursive approach to find the target number. When the target number is found, the index of the number would be returned. In this case, the index of the number 5 would be 2.\n",
|
||||
"Bob: That's great, Alice. Can you explain how you would test the code to make sure it works correctly?\n",
|
||||
"Alice: Sure, I can explain how I would test the code. I would start by creating a test suite that contains a set of test cases. Each test case would contain a list of numbers and a target number. I would then run the code on each test case and compare the output of the code to the expected output. If the output of the code matches the expected output, then the code is working correctly. Additionally, I would use a debugger to step through the code and make sure that each line of code is executing correctly.\n",
|
||||
"Bob: That's great, Alice. Can you explain how you would optimize the code to make it more efficient?\n",
|
||||
"Alice: Sure, I can explain how I would optimize the code to make it more efficient. I would start by using a binary search tree instead of a loop. A binary search tree is a data structure that stores data in a hierarchical structure, allowing for faster searches. By using a binary search tree, the time complexity of the algorithm would be reduced from O(n) to O(log n). Additionally, I would use a recursive approach to traverse the tree, which would further reduce the time complexity of the algorithm. I would also look for opportunities to reduce the number of comparisons needed to find the target number, such as using a pre-sorted list or using a hash table to store the data. Finally, I would look for ways to reduce the amount of memory used by the algorithm, such as using a linked list instead of an array.\n",
|
||||
"Bob: That's great, Alice. Can you provide an example of how this code would work with a specific list of numbers and target number?\n",
|
||||
"Alice: Sure, I can provide an example. Let's say the list of numbers is [2, 4, 6, 8, 10] and the target number is 8. The binary search tree would be constructed by inserting each number in the list into the tree. Then, the tree would be traversed using a recursive approach to find the target number. When the target number is found, the index of the number would be returned. In this case, the index of the number 8 would be 3.\n",
|
||||
"Bob: That's great, Alice. Can you explain how you would debug the code if it is not working correctly?\n",
|
||||
"Alice: Sure, I can explain how I would debug the code if it is not working correctly. I would start by using a debugger to step through the code line by line and look for any errors or unexpected behavior. I would also use the test suite to identify any test cases that are not producing the expected output. Additionally, I would use print statements to log the values of variables at different points in the code to help identify any issues. Finally, I would look for any logical errors in the code that could be causing the unexpected behavior.\n",
|
||||
"Bob: That's great, Alice. Can you explain how you would optimize the code to make it more efficient?\n",
|
||||
"Alice: Sure, I can explain how I would optimize the code to make it more efficient. I would start by using a binary search tree instead of a loop. A binary search tree is a data structure that stores data in a hierarchical structure, allowing for faster searches. By using a binary search tree, the time complexity of the algorithm would be reduced from O(n) to O(log n). Additionally, I would use a recursive approach to traverse the tree, which would further reduce the time complexity of the algorithm. I would also look for opportunities to reduce the number of comparisons needed to find the target number, such as using a pre-sorted list or using a hash table to store the data. Finally, I would look for ways to reduce the amount of memory used by the algorithm, such as using a linked list instead of an array.\n",
|
||||
"Bob: That's great, Alice. Can you provide an example of how this code would work with a specific list of numbers and target number?\n",
|
||||
"Alice: Sure, I can provide an example. Let's say the list of numbers is [3, 5, 7, 9, 11] and the target number is 9. The binary search tree would be constructed by inserting each number in the list into the tree. Then, the tree would be traversed using a recursive approach to find the target number. When the target number is found, the index of the number would be returned. In this case, the index of the number 9 would be 3.\n",
|
||||
"Bob: That's great, Alice. Can you explain how you would optimize the code further to make it even more efficient?\n",
|
||||
"Alice: Sure, I can explain how I would optimize the code further to make it even more efficient. I would look for ways to reduce the number of comparisons needed to find the target number, such as using a pre-sorted list or using a hash table to store the data. Additionally, I would look for opportunities to optimize the code by using more efficient algorithms, such as using a divide and conquer approach instead of a linear search. I would also look for ways to optimize the code by using more efficient data structures, such as using a binary search tree instead of a linked list. Finally, I would look for ways to optimize the code by using parallel processing, such as using multiple threads to process the data in parallel.\n",
|
||||
"Bob: That's great, Alice. Can you provide an example of how this code would work with a specific list of numbers and target number?\n",
|
||||
"Alice: Sure, I can provide an example. Let's say the list of numbers is [1, 3, 5, 7, 9] and the target number is 5. The binary search tree would be constructed by inserting each number in the list into the tree. Then, the tree would be traversed using a recursive approach to find the target number. When the target number is found, the index of the number would be returned. In this case, the index of the number 5 would be 2.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"KeyboardInterrupt\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"run_conversation_loop(\n",
|
||||
" alice,\n",
|
||||
" bob,\n",
|
||||
" \"I'm ready to begin.\",\n",
|
||||
" \"Great, let's start with a simple programming question. \"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2d19817f-01c7-4b22-a467-f8144a80ca5d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "convo_agents",
|
||||
"language": "python",
|
||||
"name": "convo_agents"
|
||||
},
|
||||
"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.10"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
"""Run Llama conversation agents.
|
||||
|
||||
The goal of this is to simulate conversation between two agents.
|
||||
|
||||
"""
|
||||
|
||||
from llama_index import (
|
||||
GPTSimpleVectorIndex, GPTListIndex, Document, ServiceContext
|
||||
)
|
||||
from llama_index.indices.base import BaseGPTIndex
|
||||
from llama_index.data_structs import Node
|
||||
from llama_index.prompts.prompts import QuestionAnswerPrompt
|
||||
from collections import deque
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Optional, Dict
|
||||
|
||||
|
||||
def format_text(text: str, user: str) -> str:
|
||||
return user + ": " + text
|
||||
|
||||
|
||||
DEFAULT_USER_PREFIX_TMPL = (
|
||||
"Your name is {name}. "
|
||||
"We provide conversation context between you and other users below. "\
|
||||
"You are on a date with someone else. \n"
|
||||
# "The user is the plaintiff and the other user is the defendant."
|
||||
)
|
||||
DEFAULT_PROMPT_TMPL = (
|
||||
"---------------------\n"
|
||||
"{context_str}"
|
||||
"\n---------------------\n"
|
||||
"Given the context information, perform the following task.\n"
|
||||
"Task: {query_str}\n"
|
||||
"You: "
|
||||
# "Here's an example:\n"
|
||||
# "Previous line: Hi Bob, good to meet you!\n"
|
||||
# "You: Good to meet you too!\n\n"
|
||||
# "Previous line: {query_str}\n"
|
||||
# "You: "
|
||||
)
|
||||
DEFAULT_PROMPT = QuestionAnswerPrompt(DEFAULT_PROMPT_TMPL)
|
||||
|
||||
|
||||
|
||||
class ConvoAgent(BaseModel):
|
||||
|
||||
name: str
|
||||
st_memory: deque
|
||||
lt_memory: BaseGPTIndex
|
||||
lt_memory_query_kwargs: Dict = Field(default_factory=dict)
|
||||
service_context: ServiceContext
|
||||
st_memory_size: int = 10
|
||||
# qa_prompt: QuestionAnswerPrompt = DEFAULT_PROMPT
|
||||
user_prefix_tmpl: str = DEFAULT_USER_PREFIX_TMPL
|
||||
qa_prompt_tmpl: str = DEFAULT_PROMPT_TMPL
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
@classmethod
|
||||
def from_defaults(
|
||||
cls,
|
||||
name: Optional[str] = None,
|
||||
st_memory: Optional[deque] = None,
|
||||
lt_memory: Optional[BaseGPTIndex] = None,
|
||||
service_context: Optional[ServiceContext] = None,
|
||||
**kwargs
|
||||
) -> "ConvoAgent":
|
||||
name = name or "Agent"
|
||||
st_memory = st_memory or deque()
|
||||
lt_memory = lt_memory or GPTSimpleVectorIndex([])
|
||||
service_context = service_context or ServiceContext.from_defaults()
|
||||
return cls(
|
||||
name=name,
|
||||
st_memory=st_memory,
|
||||
lt_memory=lt_memory,
|
||||
service_context=service_context,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
def add_message(self, message: str, user: str) -> None:
|
||||
"""Add message from another user."""
|
||||
fmt_message = format_text(message, user)
|
||||
self.st_memory.append(fmt_message)
|
||||
while len(self.st_memory) > self.st_memory_size:
|
||||
self.st_memory.popleft()
|
||||
self.lt_memory.insert(Document(fmt_message))
|
||||
|
||||
def generate_message(self, prev_message: Optional[str] = None) -> str:
|
||||
"""Generate a new message."""
|
||||
# if prev_message is None, get previous message using short-term memory
|
||||
if prev_message is None:
|
||||
prev_message = self.st_memory[-1]
|
||||
|
||||
st_memory_text = "\n".join([l for l in self.st_memory])
|
||||
summary_response = self.lt_memory.query(
|
||||
f"Tell me a bit more about any context that's relevant "
|
||||
f"to the current messages: \n{st_memory_text}",
|
||||
# similarity_top_k=10,
|
||||
response_mode="compact",
|
||||
**self.lt_memory_query_kwargs
|
||||
)
|
||||
|
||||
# add both the long-term memory summary and the short-term conversation
|
||||
list_builder = GPTListIndex([])
|
||||
list_builder.insert_nodes([Node(str(summary_response))])
|
||||
list_builder.insert_nodes([Node(st_memory_text)])
|
||||
|
||||
# question-answer prompt
|
||||
full_qa_prompt_tmpl = (
|
||||
self.user_prefix_tmpl.format(name=self.name) + "\n" +
|
||||
self.qa_prompt_tmpl
|
||||
)
|
||||
qa_prompt = QuestionAnswerPrompt(full_qa_prompt_tmpl)
|
||||
|
||||
response = list_builder.query(
|
||||
"Generate the next message in the conversation.",
|
||||
text_qa_template=qa_prompt,
|
||||
response_mode="compact"
|
||||
)
|
||||
return str(response)
|
||||
|
||||
|
||||
def run_conversation_loop(
|
||||
alice: ConvoAgent,
|
||||
bob: ConvoAgent,
|
||||
alice_starter: Optional[str] = None,
|
||||
bob_starter: Optional[str] = None
|
||||
) -> None:
|
||||
"""Run conversation loop."""
|
||||
alice_starter = alice_starter or "Hi, my name is Alice!"
|
||||
bob_starter = bob_starter or "Hi, my name is Bob!"
|
||||
|
||||
alice.add_message(alice_starter, "Alice")
|
||||
bob.add_message(alice_starter, "Alice")
|
||||
|
||||
alice.add_message(bob_starter, "Bob")
|
||||
bob.add_message(bob_starter, "Bob")
|
||||
|
||||
# run conversation loop
|
||||
num_iterations = 100
|
||||
current_user = "Alice"
|
||||
for _ in range(num_iterations):
|
||||
|
||||
agent = alice if current_user == "Alice" else bob
|
||||
new_message = agent.generate_message()
|
||||
|
||||
message_to_print = format_text(new_message, current_user)
|
||||
print(message_to_print)
|
||||
|
||||
alice.add_message(new_message, current_user)
|
||||
bob.add_message(new_message, current_user)
|
||||
|
||||
current_user = "Alice" if current_user == "Bob" else "Bob"
|
||||
@@ -0,0 +1 @@
|
||||
llama-index==0.5.22
|
||||
Reference in New Issue
Block a user