generated from datawhalechina/repo-template
-
Notifications
You must be signed in to change notification settings - Fork 199
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #19 from GoldWaterFall/chapter4
Chapter4
- Loading branch information
Showing
9 changed files
with
1,389 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--- | ||
comments: true | ||
--- | ||
## 4.1 Multi Agent 概念概述 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
--- | ||
comments: true | ||
--- | ||
|
||
# 4.第四章:智能体综述及多智能体框架介绍 | ||
|
||
# 前期准备 | ||
本章我们会介绍MetaGPT多智能体的开发流程,通过案例实现多智能体的开发 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
--- | ||
comments: true | ||
--- | ||
|
||
## 4.4 多智能体开发作业 | ||
|
||
### 基础作业 | ||
|
||
基于 env 或 team 设计一个你的多智能体团队,尝试让他们完成 你画我猜文字版 ,要求其中含有两个agent,其中一个agent负责接收来自用户提供的物体描述并转告另一个agent,另一个agent将猜测用户给出的物体名称,两个agent将不断交互直到另一个给出正确的答案 | ||
|
||
(也可以在系统之上继续扩展,比如引入一个agent来生成词语,而人类参与你画我猜的过程中) | ||
|
||
### 进阶作业 | ||
|
||
进阶作业只面向愿意深入探索MG潜力并检验自己学习成果的同学,只要完成基础作业视为学习完成。 | ||
|
||
如何检验mg的Agent开发学习程度呢?我认为对于本次学习,如果对于一个问题(过往交由人解决的)SOP可以将SOP迅速抽象成MG的Role和Action形式并且用多智能体协同完成,即达到了本次学习的目的。 重写babyagi是一个非常合适的任务。 babyagi是[yoheinakajima](https://twitter.com/yoheinakajima)的一个demo,他的主业是一位投资人,在2023年上半年AutoGPT爆火之际,完成了这个demo,实际上是这位投资人的日常任务规划优先级解决的一套SOP 以下是babyagi的实现流程 | ||
|
||
![homework](assets/images/homework.png) | ||
|
||
```python | ||
import openai | ||
import pinecone | ||
import time | ||
from collections import deque | ||
from typing import Dict, List | ||
|
||
#Set API Keys | ||
OPENAI_API_KEY = "" | ||
PINECONE_API_KEY = "" | ||
PINECONE_ENVIRONMENT = "us-east1-gcp" #Pinecone Environment (eg. "us-east1-gcp") | ||
|
||
#Set Variables | ||
YOUR_TABLE_NAME = "test-table" | ||
OBJECTIVE = "Solve world hunger." | ||
YOUR_FIRST_TASK = "Develop a task list." | ||
|
||
#Print OBJECTIVE | ||
print("\033[96m\033[1m"+"\n*****OBJECTIVE*****\n"+"\033[0m\033[0m") | ||
print(OBJECTIVE) | ||
|
||
# Configure OpenAI and Pinecone | ||
openai.api_key = OPENAI_API_KEY | ||
pinecone.init(api_key=PINECONE_API_KEY, environment=PINECONE_ENVIRONMENT) | ||
|
||
# Create Pinecone index | ||
table_name = YOUR_TABLE_NAME | ||
dimension = 1536 | ||
metric = "cosine" | ||
pod_type = "p1" | ||
if table_name not in pinecone.list_indexes(): | ||
pinecone.create_index(table_name, dimension=dimension, metric=metric, pod_type=pod_type) | ||
|
||
# Connect to the index | ||
index = pinecone.Index(table_name) | ||
|
||
# Task list | ||
task_list = deque([]) | ||
|
||
def add_task(task: Dict): | ||
task_list.append(task) | ||
|
||
def get_ada_embedding(text): | ||
text = text.replace("\n", " ") | ||
return openai.Embedding.create(input=[text], model="text-embedding-ada-002")["data"][0]["embedding"] | ||
|
||
def task_creation_agent(objective: str, result: Dict, task_description: str, task_list: List[str]): | ||
prompt = f"You are an task creation AI that uses the result of an execution agent to create new tasks with the following objective: {objective}, The last completed task has the result: {result}. This result was based on this task description: {task_description}. These are incomplete tasks: {', '.join(task_list)}. Based on the result, create new tasks to be completed by the AI system that do not overlap with incomplete tasks. Return the tasks as an array." | ||
response = openai.Completion.create(engine="text-davinci-003",prompt=prompt,temperature=0.5,max_tokens=100,top_p=1,frequency_penalty=0,presence_penalty=0) | ||
new_tasks = response.choices[0].text.strip().split('\n') | ||
return [{"task_name": task_name} for task_name in new_tasks] | ||
|
||
def prioritization_agent(this_task_id:int): | ||
global task_list | ||
task_names = [t["task_name"] for t in task_list] | ||
next_task_id = int(this_task_id)+1 | ||
prompt = f"""You are an task prioritization AI tasked with cleaning the formatting of and reprioritizing the following tasks: {task_names}. Consider the ultimate objective of your team:{OBJECTIVE}. Do not remove any tasks. Return the result as a numbered list, like: | ||
#. First task | ||
#. Second task | ||
Start the task list with number {next_task_id}.""" | ||
response = openai.Completion.create(engine="text-davinci-003",prompt=prompt,temperature=0.5,max_tokens=1000,top_p=1,frequency_penalty=0,presence_penalty=0) | ||
new_tasks = response.choices[0].text.strip().split('\n') | ||
task_list = deque() | ||
for task_string in new_tasks: | ||
task_parts = task_string.strip().split(".", 1) | ||
if len(task_parts) == 2: | ||
task_id = task_parts[0].strip() | ||
task_name = task_parts[1].strip() | ||
task_list.append({"task_id": task_id, "task_name": task_name}) | ||
|
||
def execution_agent(objective:str,task: str) -> str: | ||
#context = context_agent(index="quickstart", query="my_search_query", n=5) | ||
context=context_agent(index=YOUR_TABLE_NAME, query=objective, n=5) | ||
#print("\n*******RELEVANT CONTEXT******\n") | ||
#print(context) | ||
response = openai.Completion.create( | ||
engine="text-davinci-003", | ||
prompt=f"You are an AI who performs one task based on the following objective: {objective}. Your task: {task}\nResponse:", | ||
temperature=0.7, | ||
max_tokens=2000, | ||
top_p=1, | ||
frequency_penalty=0, | ||
presence_penalty=0 | ||
) | ||
return response.choices[0].text.strip() | ||
|
||
def context_agent(query: str, index: str, n: int): | ||
query_embedding = get_ada_embedding(query) | ||
index = pinecone.Index(index_name=index) | ||
results = index.query(query_embedding, top_k=n, | ||
include_metadata=True) | ||
#print("***** RESULTS *****") | ||
#print(results) | ||
sorted_results = sorted(results.matches, key=lambda x: x.score, reverse=True) | ||
return [(str(item.metadata['task'])) for item in sorted_results] | ||
|
||
# Add the first task | ||
first_task = { | ||
"task_id": 1, | ||
"task_name": YOUR_FIRST_TASK | ||
} | ||
|
||
add_task(first_task) | ||
# Main loop | ||
task_id_counter = 1 | ||
while True: | ||
if task_list: | ||
# Print the task list | ||
print("\033[95m\033[1m"+"\n*****TASK LIST*****\n"+"\033[0m\033[0m") | ||
for t in task_list: | ||
print(str(t['task_id'])+": "+t['task_name']) | ||
|
||
# Step 1: Pull the first task | ||
task = task_list.popleft() | ||
print("\033[92m\033[1m"+"\n*****NEXT TASK*****\n"+"\033[0m\033[0m") | ||
print(str(task['task_id'])+": "+task['task_name']) | ||
|
||
# Send to execution function to complete the task based on the context | ||
result = execution_agent(OBJECTIVE,task["task_name"]) | ||
this_task_id = int(task["task_id"]) | ||
print("\033[93m\033[1m"+"\n*****TASK RESULT*****\n"+"\033[0m\033[0m") | ||
print(result) | ||
|
||
# Step 2: Enrich result and store in Pinecone | ||
enriched_result = {'data': result} # This is where you should enrich the result if needed | ||
result_id = f"result_{task['task_id']}" | ||
vector = enriched_result['data'] # extract the actual result from the dictionary | ||
index.upsert([(result_id, get_ada_embedding(vector),{"task":task['task_name'],"result":result})]) | ||
|
||
# Step 3: Create new tasks and reprioritize task list | ||
new_tasks = task_creation_agent(OBJECTIVE,enriched_result, task["task_name"], [t["task_name"] for t in task_list]) | ||
|
||
for new_task in new_tasks: | ||
task_id_counter += 1 | ||
new_task.update({"task_id": task_id_counter}) | ||
add_task(new_task) | ||
prioritization_agent(this_task_id) | ||
|
||
time.sleep(1) # Sleep before checking the task list again | ||
``` | ||
|
||
以上是来自于babyagi仓库的源码,总行数140行涵盖prompt,同时任务为三个agent进行协同组织。 | ||
|
||
这个是babyagi的webui演示https://babyagi-ui.vercel.app/zh,同学们可以先体验一下了解一下babyagi的输入输出的workflow结合上图用MG进行重写。 其中MG已经抽象好了许多上层类,以及react的规划模式和actions列表。 思考部分: | ||
|
||
1. 什么是enrich | ||
2. 何时应该creat new task,何时应该排序任务优先级 | ||
3. 新的new task应该观察什么作为创建的依据(当前任务列表/目标/已完成的任务结果) | ||
4. 人类是否可以介入这个流程比如新任务的合入审核,任务执行时的拆解? | ||
|
||
你不一定要完全依据源码的逻辑进行重写,尝试找到更优秀的SOP. | ||
|
||
> Chroma/Weaviate 来存储和检索上下文的任务结果。该脚本根据 TABLE_NAME 变量中指定的表名创建 Chroma/Weaviate 集合。然后使用 Chroma/Weaviate 将任务结果以及任务名称和任何其他元数据存储在集合中。而向量数据库并不是本次学习的重点即便MG的example里有对向量检索进行支持,理论上loop的次数较少时是可以将上下文的任务结果完全的作为prompt的输入,所以在本次学习中可以将上下文的任务结果写入一个外部的txt或者直接在memory中调用的,学习者可以不使用向量数据库完成本次任务 |
Oops, something went wrong.