From 356ff8926e6d67770f6ff58f2eddf282025ed0e3 Mon Sep 17 00:00:00 2001 From: jinchihe Date: Tue, 19 Mar 2024 17:34:51 +0800 Subject: [PATCH 01/12] Correct bad URL in token_counter --- metagpt/utils/token_counter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metagpt/utils/token_counter.py b/metagpt/utils/token_counter.py index d639ccf32..0ba2daa89 100644 --- a/metagpt/utils/token_counter.py +++ b/metagpt/utils/token_counter.py @@ -229,7 +229,7 @@ def count_message_tokens(messages, model="gpt-3.5-turbo-0125"): else: raise NotImplementedError( f"num_tokens_from_messages() is not implemented for model {model}. " - f"See https://github.com/openai/openai-python/blob/main/chatml.md " + f"See https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken " f"for information on how messages are converted to tokens." ) num_tokens = 0 From 51ba2b393b18c6e223a76430147a1eab293f87ea Mon Sep 17 00:00:00 2001 From: yzlin Date: Tue, 19 Mar 2024 17:53:26 +0800 Subject: [PATCH 02/12] fix critical bug: human prior not injected --- metagpt/strategy/planner.py | 5 ++- metagpt/strategy/task_type.py | 7 ++++ tests/data/rsp_cache.json | 9 ++++- .../metagpt/roles/di/test_data_interpreter.py | 1 - tests/metagpt/strategy/test_planner.py | 37 +++++++++++++++++++ 5 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 tests/metagpt/strategy/test_planner.py diff --git a/metagpt/strategy/planner.py b/metagpt/strategy/planner.py index 0fc9cf77f..fbf784837 100644 --- a/metagpt/strategy/planner.py +++ b/metagpt/strategy/planner.py @@ -164,8 +164,9 @@ class Planner(BaseModel): code_written = "\n\n".join(code_written) task_results = [task.result for task in finished_tasks] task_results = "\n\n".join(task_results) - task_type_name = self.current_task.task_type.upper() - guidance = TaskType[task_type_name].value.guidance if hasattr(TaskType, task_type_name) else "" + task_type_name = self.current_task.task_type + task_type = TaskType.get_type(task_type_name) + guidance = task_type.guidance if task_type else "" # combine components in a prompt prompt = PLAN_STATUS.format( diff --git a/metagpt/strategy/task_type.py b/metagpt/strategy/task_type.py index 7c88817cc..d21705c16 100644 --- a/metagpt/strategy/task_type.py +++ b/metagpt/strategy/task_type.py @@ -71,3 +71,10 @@ class TaskType(Enum): @property def type_name(self): return self.value.name + + @classmethod + def get_type(cls, type_name): + for member in cls: + if member.type_name == type_name: + return member.value + return None diff --git a/tests/data/rsp_cache.json b/tests/data/rsp_cache.json index 8f0567c56..565241779 100644 --- a/tests/data/rsp_cache.json +++ b/tests/data/rsp_cache.json @@ -420,5 +420,12 @@ "user: \n## User Requirement\nRun data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.\n## Context\n\n## Current Plan\n[\n {\n \"task_id\": \"1\",\n \"dependent_task_ids\": [],\n \"instruction\": \"Perform exploratory data analysis on the sklearn Wine recognition dataset including summary statistics and a plot.\",\n \"task_type\": \"eda\",\n \"code\": \"import numpy as np\\nimport pandas as pd\\nimport matplotlib.pyplot as plt\\nfrom sklearn.datasets import load_wine\\n\\n# Load the wine dataset\\nwine = load_wine()\\nwine_df = pd.DataFrame(data=np.c_[wine['data'], wine['target']],\\n columns=wine['feature_names'] + ['target'])\\n\\n# Summary statistics for numerical features\\nnumerical_summary = wine_df.describe()\\n\\n# Summary statistics for categorical features\\ncategorical_summary = wine_df.select_dtypes(include=['object', 'category']).describe()\\n\\n# Correlation matrix for numerical features\\ncorrelation_matrix = wine_df.corr()\\n\\n# Plotting a histogram for each numerical feature\\nwine_df.hist(bins=15, figsize=(15, 10), layout=(4, 4))\\nplt.tight_layout()\\nplt.show()\\n\\n# Displaying the summary statistics\\nprint(\\\"Numerical Summary:\\\\n\\\", numerical_summary)\\nprint(\\\"\\\\nCategorical Summary:\\\\n\\\", categorical_summary)\\nprint(\\\"\\\\nCorrelation Matrix:\\\\n\\\", correlation_matrix)\\n\",\n \"result\": \"a successful run\",\n \"is_success\": true,\n \"is_finished\": true\n },\n {\n \"task_id\": \"2\",\n \"dependent_task_ids\": [\n \"1\"\n ],\n \"instruction\": \"Preprocess the dataset by splitting it into training and validation sets with a 80-20 split.\",\n \"task_type\": \"data preprocessing\",\n \"code\": \"from sklearn.model_selection import train_test_split\\n\\n# Split the data into training and validation sets\\nX_train, X_val, y_train, y_val = train_test_split(\\n wine.data, wine.target, test_size=0.2, random_state=42\\n)\\n\",\n \"result\": \"a successful run\",\n \"is_success\": true,\n \"is_finished\": true\n },\n {\n \"task_id\": \"3\",\n \"dependent_task_ids\": [\n \"2\"\n ],\n \"instruction\": \"Train a model using the training set to predict wine class.\",\n \"task_type\": \"model train\",\n \"code\": \"from sklearn.ensemble import RandomForestClassifier\\nfrom sklearn.metrics import accuracy_score\\n\\n# Initialize the model\\nmodel = RandomForestClassifier(random_state=42)\\n\\n# Train the model\\nmodel.fit(X_train, y_train)\\n\\n# Predict the validation set\\ny_pred = model.predict(X_val)\\n\\n# Calculate the accuracy\\naccuracy = accuracy_score(y_val, y_pred)\\nprint(f\\\"Validation Accuracy: {accuracy:.2f}\\\")\\n\",\n \"result\": \"a successful run\",\n \"is_success\": true,\n \"is_finished\": true\n },\n {\n \"task_id\": \"4\",\n \"dependent_task_ids\": [\n \"3\"\n ],\n \"instruction\": \"Evaluate the model on the validation set and show the validation accuracy.\",\n \"task_type\": \"model evaluate\",\n \"code\": \"\",\n \"result\": \"\",\n \"is_success\": false,\n \"is_finished\": false\n }\n]\n## Current Task\n{\"task_id\":\"4\",\"dependent_task_ids\":[\"3\"],\"instruction\":\"Evaluate the model on the validation set and show the validation accuracy.\",\"task_type\":\"model evaluate\",\"code\":\"\",\"result\":\"\",\"is_success\":false,\"is_finished\":false}\n\nassistant: # Since the model has already been trained and predictions have been made on the validation set,\n# we only need to evaluate the model using the predictions and the true labels from the validation set.\n\n# The accuracy has already been calculated and printed in the previous task.\n# However, to follow the task guidance and to ensure the output is only related to the current task,\n# we will calculate and print the validation accuracy again.\n\nvalidation_accuracy = accuracy_score(y_val, y_pred)\nprint(f\"Validation Accuracy: {validation_accuracy:.2f}\")\n\nuser: a successful runThis is a review. Please review output from metagpt.actions.di.execute_nb_code.ExecuteNbCode\nIf you want to change, add, delete a task or merge tasks in the plan, say 'change task task_id or current task, ... (things to change)' If you confirm the output from the current task and wish to continue, type: confirmIf you think user requirement has been fulfilled completedly, you can finish the process by typing: finish\nIf you want to terminate the process, type: exit\nPlease type your review below:\n": "confirm", "As a data scientist, you need to help user to achieve their goal step by step in a continuous Jupyter notebook. Since it is a notebook environment, don't use asyncio.run. Instead, use await if you need to call an async function.#SYSTEM_MSG_END#\n# User Requirement\nRun data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.\n\n# Plan Status\n\n\n# Tool Info\n\n\n# Constraints\n- Take on Current Task if it is in Plan Status, otherwise, tackle User Requirement directly.\n- Ensure the output new code is executable in the same Jupyter notebook as the previous executed code.\n- Always prioritize using pre-defined tools for the same functionality.\n\n# Output\nWhile some concise thoughts are helpful, code is absolutely required. Always output one and only one code block in your response. Output code in the following format:\n```python\nyour code\n```\n#MSG_SEP#Run data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.": "To achieve the user requirement, we will follow these steps:\n\n1. Load the Wine recognition dataset from `sklearn.datasets`.\n2. Perform a basic data analysis to understand the dataset.\n3. Visualize the data to gain insights.\n4. Split the dataset into training and validation sets.\n5. Train a classification model using the training set.\n6. Evaluate the model on the validation set and report the accuracy.\n\nLet's start by loading the dataset and performing the initial data analysis:\n\n```python\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.datasets import load_wine\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.metrics import accuracy_score\n\n# Load the wine dataset\nwine = load_wine()\nX = wine.data\ny = wine.target\nfeature_names = wine.feature_names\nclass_names = wine.target_names\n\n# Convert to a DataFrame for better visualization and analysis\nwine_df = pd.DataFrame(X, columns=feature_names)\nwine_df['target'] = y\n\n# Basic data analysis\nprint(wine_df.describe())\n\n# Plotting the data\n# Let's plot the distribution of alcohol content for each class\nfor class_idx, class_name in enumerate(class_names):\n plt.hist(wine_df[wine_df['target'] == class_idx]['alcohol'], label=class_name, alpha=0.5)\nplt.title('Alcohol content distribution by wine class')\nplt.xlabel('Alcohol content')\nplt.ylabel('Frequency')\nplt.legend()\nplt.show()\n\n# Split the dataset into training and validation sets (80% train, 20% validation)\nX_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)\n\n# Train a RandomForestClassifier\nmodel = RandomForestClassifier(random_state=42)\nmodel.fit(X_train, y_train)\n\n# Predict on the validation set\ny_pred = model.predict(X_val)\n\n# Calculate the accuracy on the validation set\naccuracy = accuracy_score(y_val, y_pred)\nprint(f'Validation accuracy: {accuracy:.2f}')\n```\n\nThis code will load the dataset, perform a basic analysis, plot the distribution of alcohol content for each wine class, split the data, train a RandomForestClassifier, and finally, evaluate its performance on the validation set.", "\n# User Requirement\nRun data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.\n# Context\n[user: Run data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy., assistant: import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.datasets import load_wine\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.metrics import accuracy_score\n\n# Load the wine dataset\nwine = load_wine()\nX = wine.data\ny = wine.target\nfeature_names = wine.feature_names\nclass_names = wine.target_names\n\n# Convert to a DataFrame for better visualization and analysis\nwine_df = pd.DataFrame(X, columns=feature_names)\nwine_df['target'] = y\n\n# Basic data analysis\nprint(wine_df.describe())\n\n# Plotting the data\n# Let's plot the distribution of alcohol content for each class\nfor class_idx, class_name in enumerate(class_names):\n plt.hist(wine_df[wine_df['target'] == class_idx]['alcohol'], label=class_name, alpha=0.5)\nplt.title('Alcohol content distribution by wine class')\nplt.xlabel('Alcohol content')\nplt.ylabel('Frequency')\nplt.legend()\nplt.show()\n\n# Split the dataset into training and validation sets (80% train, 20% validation)\nX_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, random_state=42)\n\n# Train a RandomForestClassifier\nmodel = RandomForestClassifier(random_state=42)\nmodel.fit(X_train, y_train)\n\n# Predict on the validation set\ny_pred = model.predict(X_val)\n\n# Calculate the accuracy on the validation set\naccuracy = accuracy_score(y_val, y_pred)\nprint(f'Validation accuracy: {accuracy:.2f}')\n, user: a successful run]\n\nOutput a json following the format:\n```json\n{\n \"thoughts\": str = \"Thoughts on current situation, reflect on how you should proceed to fulfill the user requirement\",\n \"state\": bool = \"Decide whether you need to take more actions to complete the user requirement. Return true if you think so. Return false if you think the requirement has been completely fulfilled.\"\n}\n```\n": "```json\n{\n \"thoughts\": \"The user has requested a data analysis on the sklearn Wine recognition dataset, including a plot and training a model to predict wine class with validation accuracy. The provided code snippet appears to fulfill the user's requirements. It loads the dataset, performs basic data analysis, creates a plot of alcohol content distribution by wine class, splits the data into training and validation sets, trains a RandomForestClassifier, predicts on the validation set, and prints the validation accuracy. Assuming the code runs successfully without errors, the user's requirements should be met.\",\n \"state\": false\n}\n```", - "\n## User Requirement:\nconduct feature engineering, add new features on the dataset\n\n## Task\nRecommend up to 5 tools from 'Available Tools' that can help solve the 'User Requirement'. \n\n## Available Tools:\n{'PolynomialExpansion': 'Add polynomial and interaction features from selected numeric columns to input DataFrame.', 'scrape_web_playwright': 'Asynchronously Scrape and save the HTML structure and inner text content of a web page using Playwright. ', 'FillMissingValue': 'Completing missing values with simple strategies.'}\n\n## Tool Selection and Instructions:\n- Select tools most relevant to completing the 'User Requirement'.\n- If you believe that no tools are suitable, indicate with an empty list.\n- Only list the names of the tools, not the full schema of each tool.\n- Ensure selected tools are listed in 'Available Tools'.\n- Output a json list of tool names:\n```json\n[\"tool_name1\", \"tool_name2\", ...]\n```\n": "```json\n[\"PolynomialExpansion\", \"FillMissingValue\"]\n```" + "\n## User Requirement:\nconduct feature engineering, add new features on the dataset\n\n## Task\nRecommend up to 5 tools from 'Available Tools' that can help solve the 'User Requirement'. \n\n## Available Tools:\n{'PolynomialExpansion': 'Add polynomial and interaction features from selected numeric columns to input DataFrame.', 'scrape_web_playwright': 'Asynchronously Scrape and save the HTML structure and inner text content of a web page using Playwright. ', 'FillMissingValue': 'Completing missing values with simple strategies.'}\n\n## Tool Selection and Instructions:\n- Select tools most relevant to completing the 'User Requirement'.\n- If you believe that no tools are suitable, indicate with an empty list.\n- Only list the names of the tools, not the full schema of each tool.\n- Ensure selected tools are listed in 'Available Tools'.\n- Output a json list of tool names:\n```json\n[\"tool_name1\", \"tool_name2\", ...]\n```\n": "```json\n[\"PolynomialExpansion\", \"FillMissingValue\"]\n```", + "As a data scientist, you need to help user to achieve their goal step by step in a continuous Jupyter notebook. Since it is a notebook environment, don't use asyncio.run. Instead, use await if you need to call an async function.#SYSTEM_MSG_END#\n# User Requirement\nRun data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.\n\n# Plan Status\n\n## Finished Tasks\n### code\n```python\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom sklearn.datasets import load_wine\nwine = load_wine()\nwine_df = pd.DataFrame(data=np.c_[wine['data'], wine['target']],\n columns=wine['feature_names'] + ['target'])\nnumerical_summary = wine_df.describe()\ncategorical_summary = wine_df.select_dtypes(include=['object', 'category']).describe()\ncorrelation_matrix = wine_df.corr()\nwine_df.hist(bins=15, figsize=(15, 10), layout=(4, 4))\nplt.tight_layout()\nplt.show()\nprint(\"Numerical Summary:\\n\", numerical_summary)\nprint(\"\\nCategorical Summary:\\n\", categorical_summary)\nprint(\"\\nCorrelation Matrix:\\n\", correlation_matrix)\n```\n\n### execution result\na successful run\n\n## Current Task\nPreprocess the dataset by splitting it into training and validation sets with a 80-20 split.\n\n## Task Guidance\nWrite complete code for 'Current Task'. And avoid duplicating code from 'Finished Tasks', such as repeated import of packages, reading data, etc.\nSpecifically, \nThe current task is about data preprocessing, please note the following:\n- Monitor data types per column, applying appropriate methods.\n- Ensure operations are on existing dataset columns.\n- Avoid writing processed data to files.\n- Avoid any change to label column, such as standardization, etc.\n- Prefer alternatives to one-hot encoding for categorical data.\n- Only encode or scale necessary columns to allow for potential feature-specific engineering tasks (like time_extract, binning, extraction, etc.) later.\n- Each step do data preprocessing to train, must do same for test separately at the same time.\n- Always copy the DataFrame before processing it and use the copy to process.\n\n\n\n# Tool Info\n\n\n# Constraints\n- Take on Current Task if it is in Plan Status, otherwise, tackle User Requirement directly.\n- Ensure the output new code is executable in the same Jupyter notebook as the previous executed code.\n- Always prioritize using pre-defined tools for the same functionality.\n\n# Output\nWhile some concise thoughts are helpful, code is absolutely required. Always output one and only one code block in your response. Output code in the following format:\n```python\nyour code\n```\n#MSG_SEP#\n# Latest Data Info\nLatest data info after previous tasks:\na successful run\n": "```python\nfrom sklearn.model_selection import train_test_split\n\n# Split the data into training and validation sets (80-20 split)\nX_train, X_val, y_train, y_val = train_test_split(\n wine_df.drop('target', axis=1), # features\n wine_df['target'], # target variable\n test_size=0.2, # 20% for validation\n random_state=42 # seed for reproducibility\n)\n\n# Output the shapes of the resulting data splits\nprint(f\"Training set shape: {X_train.shape}\")\nprint(f\"Validation set shape: {X_val.shape}\")\nprint(f\"Training target shape: {y_train.shape}\")\nprint(f\"Validation target shape: {y_val.shape}\")\n```", + "\n# Background\nCheck latest data info to guide subsequent tasks.\n\n## Finished Tasks\n```python\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom sklearn.datasets import load_wine\nwine = load_wine()\nwine_df = pd.DataFrame(data=np.c_[wine['data'], wine['target']],\n columns=wine['feature_names'] + ['target'])\nnumerical_summary = wine_df.describe()\ncategorical_summary = wine_df.select_dtypes(include=['object', 'category']).describe()\ncorrelation_matrix = wine_df.corr()\nwine_df.hist(bins=15, figsize=(15, 10), layout=(4, 4))\nplt.tight_layout()\nplt.show()\nprint(\"Numerical Summary:\\n\", numerical_summary)\nprint(\"\\nCategorical Summary:\\n\", categorical_summary)\nprint(\"\\nCorrelation Matrix:\\n\", correlation_matrix)\n\nfrom sklearn.model_selection import train_test_split\nX_train, X_val, y_train, y_val = train_test_split(\n wine_df.drop('target', axis=1),\n wine_df['target'],\n test_size=0.2,\n random_state=42\n)\nprint(f\"Training set shape: {X_train.shape}\")\nprint(f\"Validation set shape: {X_val.shape}\")\nprint(f\"Training target shape: {y_train.shape}\")\nprint(f\"Validation target shape: {y_val.shape}\")\n```end\n\n# Task\nCheck code in finished tasks, print key variables to guide your following actions.\nSpecifically, if it is a data analysis or machine learning task, print the the latest column information using the following code, with DataFrame variable from 'Finished Tasks' in place of df:\n```python\nfrom metagpt.tools.libs.data_preprocess import get_column_info\n\ncolumn_info = get_column_info(df)\nprint(\"column_info\")\nprint(column_info)\n```end\nOtherwise, print out any key variables you see fit. Return an empty string if you think there is no important data to check.\n\n# Constraints:\n- Your code is to be added to a new cell in jupyter.\n\n# Instruction\nOutput code following the format:\n```python\nyour code\n```\n": "```python\nfrom metagpt.tools.libs.data_preprocess import get_column_info\n\ncolumn_info = get_column_info(wine_df)\nprint(\"column_info\")\nprint(column_info)\n```", + "As a data scientist, you need to help user to achieve their goal step by step in a continuous Jupyter notebook. Since it is a notebook environment, don't use asyncio.run. Instead, use await if you need to call an async function.#SYSTEM_MSG_END#\n# User Requirement\nRun data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.\n\n# Plan Status\n\n## Finished Tasks\n### code\n```python\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom sklearn.datasets import load_wine\nwine = load_wine()\nwine_df = pd.DataFrame(data=np.c_[wine['data'], wine['target']],\n columns=wine['feature_names'] + ['target'])\nnumerical_summary = wine_df.describe()\ncategorical_summary = wine_df.select_dtypes(include=['object', 'category']).describe()\ncorrelation_matrix = wine_df.corr()\nwine_df.hist(bins=15, figsize=(15, 10), layout=(4, 4))\nplt.tight_layout()\nplt.show()\nprint(\"Numerical Summary:\\n\", numerical_summary)\nprint(\"\\nCategorical Summary:\\n\", categorical_summary)\nprint(\"\\nCorrelation Matrix:\\n\", correlation_matrix)\n\nfrom sklearn.model_selection import train_test_split\nX_train, X_val, y_train, y_val = train_test_split(\n wine_df.drop('target', axis=1),\n wine_df['target'],\n test_size=0.2,\n random_state=42\n)\nprint(f\"Training set shape: {X_train.shape}\")\nprint(f\"Validation set shape: {X_val.shape}\")\nprint(f\"Training target shape: {y_train.shape}\")\nprint(f\"Validation target shape: {y_val.shape}\")\n```\n\n### execution result\na successful run\n\na successful run\n\n## Current Task\nTrain a model using the training set to predict wine class.\n\n## Task Guidance\nWrite complete code for 'Current Task'. And avoid duplicating code from 'Finished Tasks', such as repeated import of packages, reading data, etc.\nSpecifically, \nThe current task is about training a model, please ensure high performance:\n- Keep in mind that your user prioritizes results and is highly focused on model performance. So, when needed, feel free to use models of any complexity to improve effectiveness, such as XGBoost, CatBoost, etc.\n- If non-numeric columns exist, perform label encode together with all steps.\n- Use the data from previous task result directly, do not mock or reload data yourself.\n- Set suitable hyperparameters for the model, make metrics as high as possible.\n\n\n\n# Tool Info\n\n\n# Constraints\n- Take on Current Task if it is in Plan Status, otherwise, tackle User Requirement directly.\n- Ensure the output new code is executable in the same Jupyter notebook as the previous executed code.\n- Always prioritize using pre-defined tools for the same functionality.\n\n# Output\nWhile some concise thoughts are helpful, code is absolutely required. Always output one and only one code block in your response. Output code in the following format:\n```python\nyour code\n```\n#MSG_SEP#\n# Latest Data Info\nLatest data info after previous tasks:\na successful run\n": "```python\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.metrics import accuracy_score\n\n# Initialize the RandomForestClassifier\nmodel = RandomForestClassifier(n_estimators=100, random_state=42)\n\n# Train the model on the training data\nmodel.fit(X_train, y_train)\n\n# Predict the wine classes on the validation set\ny_val_pred = model.predict(X_val)\n\n# Calculate the accuracy on the validation set\nval_accuracy = accuracy_score(y_val, y_val_pred)\n\nprint(f\"Validation Accuracy: {val_accuracy:.4f}\")\n```", + "As a data scientist, you need to help user to achieve their goal step by step in a continuous Jupyter notebook. Since it is a notebook environment, don't use asyncio.run. Instead, use await if you need to call an async function.#SYSTEM_MSG_END#\n# User Requirement\nRun data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.\n\n# Plan Status\n\n## Finished Tasks\n### code\n```python\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom sklearn.datasets import load_wine\nwine = load_wine()\nwine_df = pd.DataFrame(data=np.c_[wine['data'], wine['target']],\n columns=wine['feature_names'] + ['target'])\nnumerical_summary = wine_df.describe()\ncategorical_summary = wine_df.select_dtypes(include=['object', 'category']).describe()\ncorrelation_matrix = wine_df.corr()\nwine_df.hist(bins=15, figsize=(15, 10), layout=(4, 4))\nplt.tight_layout()\nplt.show()\nprint(\"Numerical Summary:\\n\", numerical_summary)\nprint(\"\\nCategorical Summary:\\n\", categorical_summary)\nprint(\"\\nCorrelation Matrix:\\n\", correlation_matrix)\n\nfrom sklearn.model_selection import train_test_split\nX_train, X_val, y_train, y_val = train_test_split(\n wine_df.drop('target', axis=1),\n wine_df['target'],\n test_size=0.2,\n random_state=42\n)\nprint(f\"Training set shape: {X_train.shape}\")\nprint(f\"Validation set shape: {X_val.shape}\")\nprint(f\"Training target shape: {y_train.shape}\")\nprint(f\"Validation target shape: {y_val.shape}\")\n\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.metrics import accuracy_score\nmodel = RandomForestClassifier(n_estimators=100, random_state=42)\nmodel.fit(X_train, y_train)\ny_val_pred = model.predict(X_val)\nval_accuracy = accuracy_score(y_val, y_val_pred)\nprint(f\"Validation Accuracy: {val_accuracy:.4f}\")\n```\n\n### execution result\na successful run\n\na successful run\n\na successful run\n\n## Current Task\nEvaluate the model on the validation set and show the validation accuracy.\n\n## Task Guidance\nWrite complete code for 'Current Task'. And avoid duplicating code from 'Finished Tasks', such as repeated import of packages, reading data, etc.\nSpecifically, \nThe current task is about evaluating a model, please note the following:\n- Ensure that the evaluated data is same processed as the training data. If not, remember use object in 'Done Tasks' to transform the data.\n- Use trained model from previous task result directly, do not mock or reload model yourself.\n\n\n\n# Tool Info\n\n\n# Constraints\n- Take on Current Task if it is in Plan Status, otherwise, tackle User Requirement directly.\n- Ensure the output new code is executable in the same Jupyter notebook as the previous executed code.\n- Always prioritize using pre-defined tools for the same functionality.\n\n# Output\nWhile some concise thoughts are helpful, code is absolutely required. Always output one and only one code block in your response. Output code in the following format:\n```python\nyour code\n```\n": "```python\n# Evaluate the model on the validation set and show the validation accuracy\nval_accuracy = accuracy_score(y_val, y_val_pred)\nprint(f\"Validation Accuracy: {val_accuracy:.4f}\")\n```", + "user: \n## User Requirement\nRun data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.\n## Context\n\n## Current Plan\n[\n {\n \"task_id\": \"1\",\n \"dependent_task_ids\": [],\n \"instruction\": \"Perform exploratory data analysis on the sklearn Wine recognition dataset including summary statistics and a plot.\",\n \"task_type\": \"eda\",\n \"code\": \"import numpy as np\\nimport pandas as pd\\nimport matplotlib.pyplot as plt\\nfrom sklearn.datasets import load_wine\\n\\n# Load the wine dataset\\nwine = load_wine()\\nwine_df = pd.DataFrame(data=np.c_[wine['data'], wine['target']],\\n columns=wine['feature_names'] + ['target'])\\n\\n# Summary statistics for numerical features\\nnumerical_summary = wine_df.describe()\\n\\n# Summary statistics for categorical features\\ncategorical_summary = wine_df.select_dtypes(include=['object', 'category']).describe()\\n\\n# Correlation matrix for numerical features\\ncorrelation_matrix = wine_df.corr()\\n\\n# Plotting a histogram for each numerical feature\\nwine_df.hist(bins=15, figsize=(15, 10), layout=(4, 4))\\nplt.tight_layout()\\nplt.show()\\n\\n# Displaying the summary statistics\\nprint(\\\"Numerical Summary:\\\\n\\\", numerical_summary)\\nprint(\\\"\\\\nCategorical Summary:\\\\n\\\", categorical_summary)\\nprint(\\\"\\\\nCorrelation Matrix:\\\\n\\\", correlation_matrix)\\n\",\n \"result\": \"a successful run\",\n \"is_success\": true,\n \"is_finished\": true\n },\n {\n \"task_id\": \"2\",\n \"dependent_task_ids\": [\n \"1\"\n ],\n \"instruction\": \"Preprocess the dataset by splitting it into training and validation sets with a 80-20 split.\",\n \"task_type\": \"data preprocessing\",\n \"code\": \"\",\n \"result\": \"\",\n \"is_success\": false,\n \"is_finished\": false\n },\n {\n \"task_id\": \"3\",\n \"dependent_task_ids\": [\n \"2\"\n ],\n \"instruction\": \"Train a model using the training set to predict wine class.\",\n \"task_type\": \"model train\",\n \"code\": \"\",\n \"result\": \"\",\n \"is_success\": false,\n \"is_finished\": false\n },\n {\n \"task_id\": \"4\",\n \"dependent_task_ids\": [\n \"3\"\n ],\n \"instruction\": \"Evaluate the model on the validation set and show the validation accuracy.\",\n \"task_type\": \"model evaluate\",\n \"code\": \"\",\n \"result\": \"\",\n \"is_success\": false,\n \"is_finished\": false\n }\n]\n## Current Task\n{\"task_id\":\"2\",\"dependent_task_ids\":[\"1\"],\"instruction\":\"Preprocess the dataset by splitting it into training and validation sets with a 80-20 split.\",\"task_type\":\"data preprocessing\",\"code\":\"\",\"result\":\"\",\"is_success\":false,\"is_finished\":false}\n\nuser: \n# Latest Data Info\nLatest data info after previous tasks:\na successful run\n\nassistant: from sklearn.model_selection import train_test_split\n\n# Split the data into training and validation sets (80-20 split)\nX_train, X_val, y_train, y_val = train_test_split(\n wine_df.drop('target', axis=1), # features\n wine_df['target'], # target variable\n test_size=0.2, # 20% for validation\n random_state=42 # seed for reproducibility\n)\n\n# Output the shapes of the resulting data splits\nprint(f\"Training set shape: {X_train.shape}\")\nprint(f\"Validation set shape: {X_val.shape}\")\nprint(f\"Training target shape: {y_train.shape}\")\nprint(f\"Validation target shape: {y_val.shape}\")\n\nuser: a successful runThis is a review. Please review output from metagpt.actions.di.execute_nb_code.ExecuteNbCode\nIf you want to change, add, delete a task or merge tasks in the plan, say 'change task task_id or current task, ... (things to change)' If you confirm the output from the current task and wish to continue, type: confirmIf you think user requirement has been fulfilled completedly, you can finish the process by typing: finish\nIf you want to terminate the process, type: exit\nPlease type your review below:\n": "confirm", + "user: \n## User Requirement\nRun data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.\n## Context\n\n## Current Plan\n[\n {\n \"task_id\": \"1\",\n \"dependent_task_ids\": [],\n \"instruction\": \"Perform exploratory data analysis on the sklearn Wine recognition dataset including summary statistics and a plot.\",\n \"task_type\": \"eda\",\n \"code\": \"import numpy as np\\nimport pandas as pd\\nimport matplotlib.pyplot as plt\\nfrom sklearn.datasets import load_wine\\n\\n# Load the wine dataset\\nwine = load_wine()\\nwine_df = pd.DataFrame(data=np.c_[wine['data'], wine['target']],\\n columns=wine['feature_names'] + ['target'])\\n\\n# Summary statistics for numerical features\\nnumerical_summary = wine_df.describe()\\n\\n# Summary statistics for categorical features\\ncategorical_summary = wine_df.select_dtypes(include=['object', 'category']).describe()\\n\\n# Correlation matrix for numerical features\\ncorrelation_matrix = wine_df.corr()\\n\\n# Plotting a histogram for each numerical feature\\nwine_df.hist(bins=15, figsize=(15, 10), layout=(4, 4))\\nplt.tight_layout()\\nplt.show()\\n\\n# Displaying the summary statistics\\nprint(\\\"Numerical Summary:\\\\n\\\", numerical_summary)\\nprint(\\\"\\\\nCategorical Summary:\\\\n\\\", categorical_summary)\\nprint(\\\"\\\\nCorrelation Matrix:\\\\n\\\", correlation_matrix)\\n\",\n \"result\": \"a successful run\",\n \"is_success\": true,\n \"is_finished\": true\n },\n {\n \"task_id\": \"2\",\n \"dependent_task_ids\": [\n \"1\"\n ],\n \"instruction\": \"Preprocess the dataset by splitting it into training and validation sets with a 80-20 split.\",\n \"task_type\": \"data preprocessing\",\n \"code\": \"from sklearn.model_selection import train_test_split\\n\\n# Split the data into training and validation sets (80-20 split)\\nX_train, X_val, y_train, y_val = train_test_split(\\n wine_df.drop('target', axis=1), # features\\n wine_df['target'], # target variable\\n test_size=0.2, # 20% for validation\\n random_state=42 # seed for reproducibility\\n)\\n\\n# Output the shapes of the resulting data splits\\nprint(f\\\"Training set shape: {X_train.shape}\\\")\\nprint(f\\\"Validation set shape: {X_val.shape}\\\")\\nprint(f\\\"Training target shape: {y_train.shape}\\\")\\nprint(f\\\"Validation target shape: {y_val.shape}\\\")\\n\",\n \"result\": \"a successful run\",\n \"is_success\": true,\n \"is_finished\": true\n },\n {\n \"task_id\": \"3\",\n \"dependent_task_ids\": [\n \"2\"\n ],\n \"instruction\": \"Train a model using the training set to predict wine class.\",\n \"task_type\": \"model train\",\n \"code\": \"\",\n \"result\": \"\",\n \"is_success\": false,\n \"is_finished\": false\n },\n {\n \"task_id\": \"4\",\n \"dependent_task_ids\": [\n \"3\"\n ],\n \"instruction\": \"Evaluate the model on the validation set and show the validation accuracy.\",\n \"task_type\": \"model evaluate\",\n \"code\": \"\",\n \"result\": \"\",\n \"is_success\": false,\n \"is_finished\": false\n }\n]\n## Current Task\n{\"task_id\":\"3\",\"dependent_task_ids\":[\"2\"],\"instruction\":\"Train a model using the training set to predict wine class.\",\"task_type\":\"model train\",\"code\":\"\",\"result\":\"\",\"is_success\":false,\"is_finished\":false}\n\nuser: \n# Latest Data Info\nLatest data info after previous tasks:\na successful run\n\nassistant: from sklearn.ensemble import RandomForestClassifier\nfrom sklearn.metrics import accuracy_score\n\n# Initialize the RandomForestClassifier\nmodel = RandomForestClassifier(n_estimators=100, random_state=42)\n\n# Train the model on the training data\nmodel.fit(X_train, y_train)\n\n# Predict the wine classes on the validation set\ny_val_pred = model.predict(X_val)\n\n# Calculate the accuracy on the validation set\nval_accuracy = accuracy_score(y_val, y_val_pred)\n\nprint(f\"Validation Accuracy: {val_accuracy:.4f}\")\n\nuser: a successful runThis is a review. Please review output from metagpt.actions.di.execute_nb_code.ExecuteNbCode\nIf you want to change, add, delete a task or merge tasks in the plan, say 'change task task_id or current task, ... (things to change)' If you confirm the output from the current task and wish to continue, type: confirmIf you think user requirement has been fulfilled completedly, you can finish the process by typing: finish\nIf you want to terminate the process, type: exit\nPlease type your review below:\n": "confirm", + "user: \n## User Requirement\nRun data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy.\n## Context\n\n## Current Plan\n[\n {\n \"task_id\": \"1\",\n \"dependent_task_ids\": [],\n \"instruction\": \"Perform exploratory data analysis on the sklearn Wine recognition dataset including summary statistics and a plot.\",\n \"task_type\": \"eda\",\n \"code\": \"import numpy as np\\nimport pandas as pd\\nimport matplotlib.pyplot as plt\\nfrom sklearn.datasets import load_wine\\n\\n# Load the wine dataset\\nwine = load_wine()\\nwine_df = pd.DataFrame(data=np.c_[wine['data'], wine['target']],\\n columns=wine['feature_names'] + ['target'])\\n\\n# Summary statistics for numerical features\\nnumerical_summary = wine_df.describe()\\n\\n# Summary statistics for categorical features\\ncategorical_summary = wine_df.select_dtypes(include=['object', 'category']).describe()\\n\\n# Correlation matrix for numerical features\\ncorrelation_matrix = wine_df.corr()\\n\\n# Plotting a histogram for each numerical feature\\nwine_df.hist(bins=15, figsize=(15, 10), layout=(4, 4))\\nplt.tight_layout()\\nplt.show()\\n\\n# Displaying the summary statistics\\nprint(\\\"Numerical Summary:\\\\n\\\", numerical_summary)\\nprint(\\\"\\\\nCategorical Summary:\\\\n\\\", categorical_summary)\\nprint(\\\"\\\\nCorrelation Matrix:\\\\n\\\", correlation_matrix)\\n\",\n \"result\": \"a successful run\",\n \"is_success\": true,\n \"is_finished\": true\n },\n {\n \"task_id\": \"2\",\n \"dependent_task_ids\": [\n \"1\"\n ],\n \"instruction\": \"Preprocess the dataset by splitting it into training and validation sets with a 80-20 split.\",\n \"task_type\": \"data preprocessing\",\n \"code\": \"from sklearn.model_selection import train_test_split\\n\\n# Split the data into training and validation sets (80-20 split)\\nX_train, X_val, y_train, y_val = train_test_split(\\n wine_df.drop('target', axis=1), # features\\n wine_df['target'], # target variable\\n test_size=0.2, # 20% for validation\\n random_state=42 # seed for reproducibility\\n)\\n\\n# Output the shapes of the resulting data splits\\nprint(f\\\"Training set shape: {X_train.shape}\\\")\\nprint(f\\\"Validation set shape: {X_val.shape}\\\")\\nprint(f\\\"Training target shape: {y_train.shape}\\\")\\nprint(f\\\"Validation target shape: {y_val.shape}\\\")\\n\",\n \"result\": \"a successful run\",\n \"is_success\": true,\n \"is_finished\": true\n },\n {\n \"task_id\": \"3\",\n \"dependent_task_ids\": [\n \"2\"\n ],\n \"instruction\": \"Train a model using the training set to predict wine class.\",\n \"task_type\": \"model train\",\n \"code\": \"from sklearn.ensemble import RandomForestClassifier\\nfrom sklearn.metrics import accuracy_score\\n\\n# Initialize the RandomForestClassifier\\nmodel = RandomForestClassifier(n_estimators=100, random_state=42)\\n\\n# Train the model on the training data\\nmodel.fit(X_train, y_train)\\n\\n# Predict the wine classes on the validation set\\ny_val_pred = model.predict(X_val)\\n\\n# Calculate the accuracy on the validation set\\nval_accuracy = accuracy_score(y_val, y_val_pred)\\n\\nprint(f\\\"Validation Accuracy: {val_accuracy:.4f}\\\")\\n\",\n \"result\": \"a successful run\",\n \"is_success\": true,\n \"is_finished\": true\n },\n {\n \"task_id\": \"4\",\n \"dependent_task_ids\": [\n \"3\"\n ],\n \"instruction\": \"Evaluate the model on the validation set and show the validation accuracy.\",\n \"task_type\": \"model evaluate\",\n \"code\": \"\",\n \"result\": \"\",\n \"is_success\": false,\n \"is_finished\": false\n }\n]\n## Current Task\n{\"task_id\":\"4\",\"dependent_task_ids\":[\"3\"],\"instruction\":\"Evaluate the model on the validation set and show the validation accuracy.\",\"task_type\":\"model evaluate\",\"code\":\"\",\"result\":\"\",\"is_success\":false,\"is_finished\":false}\n\nassistant: # Evaluate the model on the validation set and show the validation accuracy\nval_accuracy = accuracy_score(y_val, y_val_pred)\nprint(f\"Validation Accuracy: {val_accuracy:.4f}\")\n\nuser: a successful runThis is a review. Please review output from metagpt.actions.di.execute_nb_code.ExecuteNbCode\nIf you want to change, add, delete a task or merge tasks in the plan, say 'change task task_id or current task, ... (things to change)' If you confirm the output from the current task and wish to continue, type: confirmIf you think user requirement has been fulfilled completedly, you can finish the process by typing: finish\nIf you want to terminate the process, type: exit\nPlease type your review below:\n": "confirm" } \ No newline at end of file diff --git a/tests/metagpt/roles/di/test_data_interpreter.py b/tests/metagpt/roles/di/test_data_interpreter.py index d25e5a099..e5cc5b29b 100644 --- a/tests/metagpt/roles/di/test_data_interpreter.py +++ b/tests/metagpt/roles/di/test_data_interpreter.py @@ -25,7 +25,6 @@ async def test_interpreter(mocker, auto_run): @pytest.mark.asyncio async def test_interpreter_react_mode(mocker): mocker.patch("metagpt.actions.di.execute_nb_code.ExecuteNbCode.run", return_value=("a successful run", True)) - mocker.patch("builtins.input", return_value="confirm") requirement = "Run data analysis on sklearn Wine recognition dataset, include a plot, and train a model to predict wine class (20% as validation), and show validation accuracy." diff --git a/tests/metagpt/strategy/test_planner.py b/tests/metagpt/strategy/test_planner.py new file mode 100644 index 000000000..ff1c6da3f --- /dev/null +++ b/tests/metagpt/strategy/test_planner.py @@ -0,0 +1,37 @@ +from metagpt.schema import Plan, Task +from metagpt.strategy.planner import Planner +from metagpt.strategy.task_type import TaskType + +MOCK_TASK_MAP = { + "1": Task( + task_id="1", + instruction="test instruction for finished task", + task_type=TaskType.EDA.type_name, + dependent_task_ids=[], + code="some finished test code", + result="some finished test result", + is_finished=True, + ), + "2": Task( + task_id="2", + instruction="test instruction for current task", + task_type=TaskType.DATA_PREPROCESS.type_name, + dependent_task_ids=["1"], + ), +} +MOCK_PLAN = Plan( + goal="test goal", + tasks=list(MOCK_TASK_MAP.values()), + task_map=MOCK_TASK_MAP, + current_task_id="2", +) + + +def test_planner_get_plan_status(): + planner = Planner(plan=MOCK_PLAN) + status = planner.get_plan_status() + + assert "some finished test code" in status + assert "some finished test result" in status + assert "test instruction for current task" in status + assert TaskType.DATA_PREPROCESS.value.guidance in status # current task guidance From c9f60f344b8dabf221de48dcac531bf73814dd13 Mon Sep 17 00:00:00 2001 From: geekan Date: Tue, 19 Mar 2024 10:58:23 +0800 Subject: [PATCH 03/12] add arxiv reader --- examples/di/arxiv_reader.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 examples/di/arxiv_reader.py diff --git a/examples/di/arxiv_reader.py b/examples/di/arxiv_reader.py new file mode 100644 index 000000000..9395cf32a --- /dev/null +++ b/examples/di/arxiv_reader.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +@Time : 2024/01/15 +@Author : mannaandpoem +@File : imitate_webpage.py +""" +from metagpt.roles.di.data_interpreter import DataInterpreter + + +async def main(): + template = "https://arxiv.org/list/{tag}/pastweek?skip=0&show=300" + tags = ["cs.ai", "cs.cl", "cs.lg", "cs.se"] + urls = [template.format(tag=tag) for tag in tags] + prompt = f"""This is a collection of arxiv urls: '{urls}' . +Record each article, remove duplicates by title (they may have multiple tags), filter out papers related to +large language model / agent / , and pay attention to maintaining the original order as much as possible""" + di = DataInterpreter(react_mode="react", tools=["scrape_web_playwright"]) + + await di.run(prompt) + + +if __name__ == "__main__": + import asyncio + + asyncio.run(main()) From 29a492d03ea3b0f9a789ec87defa88dabf28e8dd Mon Sep 17 00:00:00 2001 From: geekan Date: Tue, 19 Mar 2024 19:22:34 +0800 Subject: [PATCH 04/12] update Install and Config in README --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 81b6a876f..40a404bb6 100644 --- a/README.md +++ b/README.md @@ -63,13 +63,19 @@ ### Pip installation > You can use conda like this: `conda create -n metagpt python=3.9 && conda activate metagpt` ```bash -pip install metagpt -# https://docs.deepwisdom.ai/main/en/guide/get_started/configuration.html -metagpt --init-config # it will create ~/.metagpt/config2.yaml, just modify it to your needs +pip install --upgrade metagpt +# or `pip install --upgrade git+https://github.com/geekan/MetaGPT.git` +# or `git clone https://github.com/geekan/MetaGPT && cd MetaGPT && pip install --upgrade -e .` ``` ### Configuration +You can init the config of MetaGPT by running the following command, or manually create `~/.metagpt/config2.yaml` file: +```bash +# Check https://docs.deepwisdom.ai/main/en/guide/get_started/configuration.html for more details +metagpt --init-config # it will create ~/.metagpt/config2.yaml, just modify it to your needs +``` + You can configure `~/.metagpt/config2.yaml` according to the [example](https://github.com/geekan/MetaGPT/blob/main/config/config2.example.yaml) and [doc](https://docs.deepwisdom.ai/main/en/guide/get_started/configuration.html): ```yaml From d9f92ee9a43817035d6f5e849abf1d8985ce5b21 Mon Sep 17 00:00:00 2001 From: geekan Date: Tue, 19 Mar 2024 19:30:14 +0800 Subject: [PATCH 05/12] update arxiv reader --- examples/di/arxiv_reader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/di/arxiv_reader.py b/examples/di/arxiv_reader.py index 9395cf32a..e376b0778 100644 --- a/examples/di/arxiv_reader.py +++ b/examples/di/arxiv_reader.py @@ -14,7 +14,7 @@ async def main(): urls = [template.format(tag=tag) for tag in tags] prompt = f"""This is a collection of arxiv urls: '{urls}' . Record each article, remove duplicates by title (they may have multiple tags), filter out papers related to -large language model / agent / , and pay attention to maintaining the original order as much as possible""" +large language model / agent / llm, and visualize the word count of the titles""" di = DataInterpreter(react_mode="react", tools=["scrape_web_playwright"]) await di.run(prompt) From 29386e6d2cbf7bf547cf8c2ad0556c7a711fdb37 Mon Sep 17 00:00:00 2001 From: geekan Date: Tue, 19 Mar 2024 19:30:31 +0800 Subject: [PATCH 06/12] update arxiv reader --- examples/di/arxiv_reader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/di/arxiv_reader.py b/examples/di/arxiv_reader.py index e376b0778..fab0e2e48 100644 --- a/examples/di/arxiv_reader.py +++ b/examples/di/arxiv_reader.py @@ -14,7 +14,7 @@ async def main(): urls = [template.format(tag=tag) for tag in tags] prompt = f"""This is a collection of arxiv urls: '{urls}' . Record each article, remove duplicates by title (they may have multiple tags), filter out papers related to -large language model / agent / llm, and visualize the word count of the titles""" +large language model / agent / llm, print top 100 and visualize the word count of the titles""" di = DataInterpreter(react_mode="react", tools=["scrape_web_playwright"]) await di.run(prompt) From 9e8a04ffeef3c8c638432a3ee864815b8cd6f97a Mon Sep 17 00:00:00 2001 From: geekan Date: Tue, 19 Mar 2024 19:33:22 +0800 Subject: [PATCH 07/12] update README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 40a404bb6..ced47960b 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,9 @@ ### Contact Information ## Citation -If you use MetaGPT or Data Interpreter in a research paper, please cite our work as follows: +To stay updated with the latest research and development, follow [MetaGPT_](https://twitter.com/MetaGPT_) on Twitter. + +To cite [MetaGPT](https://arxiv.org/abs/2308.00352) or [Data Interpreter](https://arxiv.org/abs/2402.18679) in publications, please use the following BibTeX entries. ```bibtex @misc{hong2023metagpt, From 416bc597734d6883dc4981d8dbf9348836bed84d Mon Sep 17 00:00:00 2001 From: geekan Date: Tue, 19 Mar 2024 19:36:13 +0800 Subject: [PATCH 08/12] update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ced47960b..0c6c80260 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,7 @@ ### Contact Information ## Citation -To stay updated with the latest research and development, follow [MetaGPT_](https://twitter.com/MetaGPT_) on Twitter. +To stay updated with the latest research and development, follow [@MetaGPT_](https://twitter.com/MetaGPT_) on Twitter. To cite [MetaGPT](https://arxiv.org/abs/2308.00352) or [Data Interpreter](https://arxiv.org/abs/2402.18679) in publications, please use the following BibTeX entries. From 32a86bdd4e1b4fda8010e261b435f899e3bf067f Mon Sep 17 00:00:00 2001 From: yzlin Date: Tue, 19 Mar 2024 20:26:36 +0800 Subject: [PATCH 09/12] update readme --- README.md | 60 +++++++++++++++++-------------------------------------- 1 file changed, 18 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 81b6a876f..027b3b243 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ # MetaGPT: The Multi-Agent Framework

## News -πŸš€ Mar. 14, 2024: Our Data Interpreter paper is on [arxiv](https://arxiv.org/abs/2402.18679). Check the [example](https://docs.deepwisdom.ai/main/en/DataInterpreter/) and [code](https://github.com/geekan/MetaGPT/tree/main/examples/di)! +πŸš€ Mar. 14, 2024: Our **Data Interpreter** paper is on [arxiv](https://arxiv.org/abs/2402.18679). Check the [example](https://docs.deepwisdom.ai/main/en/DataInterpreter/) and [code](https://github.com/geekan/MetaGPT/tree/main/examples/di)! πŸš€ Feb. 08, 2024: [v0.7.0](https://github.com/geekan/MetaGPT/releases/tag/v0.7.0) released, supporting assigning different LLMs to different Roles. We also introduced [Data Interpreter](https://github.com/geekan/MetaGPT/blob/main/examples/di/README.md), a powerful agent capable of solving a wide range of real-world problems. @@ -55,9 +55,9 @@ ## Software Company as Multi-Agent System

Software Company Multi-Agent Schematic (Gradually Implementing)

-## Install +## Get Started -### Pip installation +### Installation > Ensure that Python 3.9+ is installed on your system. You can check this by using: `python --version`. > You can use conda like this: `conda create -n metagpt python=3.9 && conda activate metagpt` @@ -68,6 +68,9 @@ # https://docs.deepwisdom.ai/main/en/guide/get_started/configuration.html metagpt --init-config # it will create ~/.metagpt/config2.yaml, just modify it to your needs ``` +For detailed installation guidance, please refer to [cli_install](https://docs.deepwisdom.ai/main/en/guide/get_started/installation.html#install-stable-version) + or [docker_install](https://docs.deepwisdom.ai/main/en/guide/get_started/installation.html#install-with-docker) + ### Configuration You can configure `~/.metagpt/config2.yaml` according to the [example](https://github.com/geekan/MetaGPT/blob/main/config/config2.example.yaml) and [doc](https://docs.deepwisdom.ai/main/en/guide/get_started/configuration.html): @@ -82,13 +85,13 @@ ### Configuration ### Usage -After installation, you can use it as CLI +After installation, you can use MetaGPT at CLI ```bash metagpt "Create a 2048 game" # this will create a repo in ./workspace ``` -or you can use it as library +or use it as library ```python from metagpt.software_company import generate_repo, ProjectRepo @@ -96,47 +99,19 @@ ### Usage print(repo) # it will print the repo structure with files ``` -detail installation please refer to [cli_install](https://docs.deepwisdom.ai/main/en/guide/get_started/installation.html#install-stable-version) - or [docker_install](https://docs.deepwisdom.ai/main/en/guide/get_started/installation.html#install-with-docker) +You can also use its [Data Interpreter](https://github.com/geekan/MetaGPT/tree/main/examples/di) -### Docker installation -
⏬ Step 1: Download metagpt image and prepare config2.yaml :: click to expand :: -
+```python +import asyncio +from metagpt.roles.di.data_interpreter import DataInterpreter -```bash -docker pull metagpt/metagpt:latest -mkdir -p /opt/metagpt/{config,workspace} -docker run --rm metagpt/metagpt:latest cat /app/metagpt/config/config2.yaml > /opt/metagpt/config/config2.yaml -vim /opt/metagpt/config/config2.yaml # Change the config +async def main(): + di = DataInterpreter() + await di.run("Run data analysis on sklearn Iris dataset, include a plot") + +asyncio.run(main()) # or await main() in a jupyter notebook setting ``` -
-
- -
⏬ Step 2: Run metagpt container :: click to expand :: -
- -```bash -docker run --name metagpt -d \ - --privileged \ - -v /opt/metagpt/config/config2.yaml:/app/metagpt/config/config2.yaml \ - -v /opt/metagpt/workspace:/app/metagpt/workspace \ - metagpt/metagpt:latest -``` - -
-
- -
⏬ Step 3: Use metagpt :: click to expand :: -
- -```bash -docker exec -it metagpt /bin/bash -$ metagpt "Create a 2048 game" # this will create a repo in ./workspace -``` - -
-
### QuickStart & Demo Video - Try it on [MetaGPT Huggingface Space](https://huggingface.co/spaces/deepwisdom/MetaGPT) @@ -156,6 +131,7 @@ ## Tutorial - πŸ§‘β€πŸ’» Contribution - [Develop Roadmap](docs/ROADMAP.md) - πŸ”– Use Cases + - [Data Interpreter](https://docs.deepwisdom.ai/main/en/guide/use_cases/agent/interpreter/intro.html) - [Debate](https://docs.deepwisdom.ai/main/en/guide/use_cases/multi_agent/debate.html) - [Researcher](https://docs.deepwisdom.ai/main/en/guide/use_cases/agent/researcher.html) - [Recepit Assistant](https://docs.deepwisdom.ai/main/en/guide/use_cases/agent/receipt_assistant.html) From f91334deafc38f33b05deb43f1a0dc6102b7c8d1 Mon Sep 17 00:00:00 2001 From: shenchucheng Date: Tue, 19 Mar 2024 23:31:05 +0800 Subject: [PATCH 10/12] fix text ut error --- tests/metagpt/utils/test_text.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/metagpt/utils/test_text.py b/tests/metagpt/utils/test_text.py index c9a9753be..319a4ebe0 100644 --- a/tests/metagpt/utils/test_text.py +++ b/tests/metagpt/utils/test_text.py @@ -22,7 +22,7 @@ def _paragraphs(n): @pytest.mark.parametrize( "msgs, model_name, system_text, reserved, expected", [ - (_msgs(), "gpt-3.5-turbo", "System", 1500, 1), + (_msgs(), "gpt-3.5-turbo-0613", "System", 1500, 1), (_msgs(), "gpt-3.5-turbo-16k", "System", 3000, 6), (_msgs(), "gpt-3.5-turbo-16k", "Hello," * 1000, 3000, 5), (_msgs(), "gpt-4", "System", 2000, 3), @@ -32,22 +32,23 @@ def _paragraphs(n): ], ) def test_reduce_message_length(msgs, model_name, system_text, reserved, expected): - assert len(reduce_message_length(msgs, model_name, system_text, reserved)) / (len("Hello,")) / 1000 == expected + length = len(reduce_message_length(msgs, model_name, system_text, reserved)) / (len("Hello,")) / 1000 + assert length == expected @pytest.mark.parametrize( "text, prompt_template, model_name, system_text, reserved, expected", [ - (" ".join("Hello World." for _ in range(1000)), "Prompt: {}", "gpt-3.5-turbo", "System", 1500, 2), + (" ".join("Hello World." for _ in range(1000)), "Prompt: {}", "gpt-3.5-turbo-0613", "System", 1500, 2), (" ".join("Hello World." for _ in range(1000)), "Prompt: {}", "gpt-3.5-turbo-16k", "System", 3000, 1), (" ".join("Hello World." for _ in range(4000)), "Prompt: {}", "gpt-4", "System", 2000, 2), (" ".join("Hello World." for _ in range(8000)), "Prompt: {}", "gpt-4-32k", "System", 4000, 1), - (" ".join("Hello World" for _ in range(8000)), "Prompt: {}", "gpt-3.5-turbo", "System", 1000, 8), + (" ".join("Hello World" for _ in range(8000)), "Prompt: {}", "gpt-3.5-turbo-0613", "System", 1000, 8), ], ) def test_generate_prompt_chunk(text, prompt_template, model_name, system_text, reserved, expected): - ret = list(generate_prompt_chunk(text, prompt_template, model_name, system_text, reserved)) - assert len(ret) == expected + chunk = len(list(generate_prompt_chunk(text, prompt_template, model_name, system_text, reserved))) + assert chunk == expected @pytest.mark.parametrize( From 21c5d1955bf552612d0184e684ceb39235972067 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 20 Mar 2024 14:27:11 +0800 Subject: [PATCH 11/12] Update process for "Fix bug" --- metagpt/roles/engineer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/metagpt/roles/engineer.py b/metagpt/roles/engineer.py index 329b21553..9d8f6884f 100644 --- a/metagpt/roles/engineer.py +++ b/metagpt/roles/engineer.py @@ -240,8 +240,8 @@ class Engineer(Role): async def _think(self) -> Action | None: if not self.src_workspace: self.src_workspace = self.git_repo.workdir / self.git_repo.workdir.name - write_plan_and_change_filters = any_to_str_set([WriteTasks]) - write_code_filters = any_to_str_set([WriteTasks, WriteCodePlanAndChange, SummarizeCode, FixBug]) + write_plan_and_change_filters = any_to_str_set([WriteTasks, FixBug]) + write_code_filters = any_to_str_set([WriteTasks, WriteCodePlanAndChange, SummarizeCode]) summarize_code_filters = any_to_str_set([WriteCode, WriteCodeReview]) if not self.rc.news: return None From f6a11d508904e6a56a9e35895abfeb439f5c4110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8E=98=E6=9D=83=20=E9=A9=AC?= Date: Wed, 20 Mar 2024 17:34:30 +0800 Subject: [PATCH 12/12] fixbug: #1016 --- metagpt/actions/di/write_analysis_code.py | 4 +-- metagpt/provider/base_llm.py | 22 +++++++++++++++++ metagpt/provider/google_gemini_api.py | 30 +++++++++++++++++++++++ metagpt/provider/openai_api.py | 9 ++----- metagpt/utils/common.py | 23 ----------------- tests/mock/mock_llm.py | 3 +-- 6 files changed, 57 insertions(+), 34 deletions(-) diff --git a/metagpt/actions/di/write_analysis_code.py b/metagpt/actions/di/write_analysis_code.py index 185926e31..711e56d39 100644 --- a/metagpt/actions/di/write_analysis_code.py +++ b/metagpt/actions/di/write_analysis_code.py @@ -18,7 +18,7 @@ from metagpt.prompts.di.write_analysis_code import ( STRUCTUAL_PROMPT, ) from metagpt.schema import Message, Plan -from metagpt.utils.common import CodeParser, process_message, remove_comments +from metagpt.utils.common import CodeParser, remove_comments class WriteAnalysisCode(Action): @@ -50,7 +50,7 @@ class WriteAnalysisCode(Action): ) working_memory = working_memory or [] - context = process_message([Message(content=structual_prompt, role="user")] + working_memory) + context = self.llm.format_msg([Message(content=structual_prompt, role="user")] + working_memory) # LLM call if use_reflection: diff --git a/metagpt/provider/base_llm.py b/metagpt/provider/base_llm.py index 71308930a..601980d5e 100644 --- a/metagpt/provider/base_llm.py +++ b/metagpt/provider/base_llm.py @@ -73,6 +73,28 @@ class BaseLLM(ABC): def _system_msg(self, msg: str) -> dict[str, str]: return {"role": "system", "content": msg} + def format_msg(self, messages: Union[str, Message, list[dict], list[Message], list[str]]) -> list[dict]: + """convert messages to list[dict].""" + from metagpt.schema import Message + + if not isinstance(messages, list): + messages = [messages] + + processed_messages = [] + for msg in messages: + if isinstance(msg, str): + processed_messages.append({"role": "user", "content": msg}) + elif isinstance(msg, dict): + assert set(msg.keys()) == set(["role", "content"]) + processed_messages.append(msg) + elif isinstance(msg, Message): + processed_messages.append(msg.to_dict()) + else: + raise ValueError( + f"Only support message type are: str, Message, dict, but got {type(messages).__name__}!" + ) + return processed_messages + def _system_msgs(self, msgs: list[str]) -> list[dict[str, str]]: return [self._system_msg(msg) for msg in msgs] diff --git a/metagpt/provider/google_gemini_api.py b/metagpt/provider/google_gemini_api.py index 09e554205..7370747a5 100644 --- a/metagpt/provider/google_gemini_api.py +++ b/metagpt/provider/google_gemini_api.py @@ -18,6 +18,7 @@ from metagpt.configs.llm_config import LLMConfig, LLMType from metagpt.logs import log_llm_stream from metagpt.provider.base_llm import BaseLLM from metagpt.provider.llm_provider_registry import register_provider +from metagpt.schema import Message class GeminiGenerativeModel(GenerativeModel): @@ -61,6 +62,35 @@ class GeminiLLM(BaseLLM): def _assistant_msg(self, msg: str) -> dict[str, str]: return {"role": "model", "parts": [msg]} + def _system_msg(self, msg: str) -> dict[str, str]: + return {"role": "user", "parts": [msg]} + + def format_msg(self, messages: Union[str, Message, list[dict], list[Message], list[str]]) -> list[dict]: + """convert messages to list[dict].""" + from metagpt.schema import Message + + if not isinstance(messages, list): + messages = [messages] + + # REF: https://ai.google.dev/tutorials/python_quickstart + # As a dictionary, the message requires `role` and `parts` keys. + # The role in a conversation can either be the `user`, which provides the prompts, + # or `model`, which provides the responses. + processed_messages = [] + for msg in messages: + if isinstance(msg, str): + processed_messages.append({"role": "user", "parts": [msg]}) + elif isinstance(msg, dict): + assert set(msg.keys()) == set(["role", "parts"]) + processed_messages.append(msg) + elif isinstance(msg, Message): + processed_messages.append({"role": "user" if msg.role == "user" else "model", "parts": [msg.content]}) + else: + raise ValueError( + f"Only support message type are: str, Message, dict, but got {type(messages).__name__}!" + ) + return processed_messages + def _const_kwargs(self, messages: list[dict], stream: bool = False) -> dict: kwargs = {"contents": messages, "generation_config": GenerationConfig(temperature=0.3), "stream": stream} return kwargs diff --git a/metagpt/provider/openai_api.py b/metagpt/provider/openai_api.py index b4f99e69f..2fb64dc85 100644 --- a/metagpt/provider/openai_api.py +++ b/metagpt/provider/openai_api.py @@ -29,12 +29,7 @@ from metagpt.logs import log_llm_stream, logger from metagpt.provider.base_llm import BaseLLM from metagpt.provider.constant import GENERAL_FUNCTION_SCHEMA from metagpt.provider.llm_provider_registry import register_provider -from metagpt.utils.common import ( - CodeParser, - decode_image, - log_and_reraise, - process_message, -) +from metagpt.utils.common import CodeParser, decode_image, log_and_reraise from metagpt.utils.cost_manager import CostManager from metagpt.utils.exceptions import handle_exception from metagpt.utils.token_counter import ( @@ -150,7 +145,7 @@ class OpenAILLM(BaseLLM): async def _achat_completion_function( self, messages: list[dict], timeout: int = 3, **chat_configs ) -> ChatCompletion: - messages = process_message(messages) + messages = self.format_msg(messages) kwargs = self._cons_kwargs(messages=messages, timeout=timeout, **chat_configs) rsp: ChatCompletion = await self.aclient.chat.completions.create(**kwargs) self._update_costs(rsp.usage) diff --git a/metagpt/utils/common.py b/metagpt/utils/common.py index e9cef69a4..7493712c2 100644 --- a/metagpt/utils/common.py +++ b/metagpt/utils/common.py @@ -802,29 +802,6 @@ def decode_image(img_url_or_b64: str) -> Image: return img -def process_message(messages: Union[str, Message, list[dict], list[Message], list[str]]) -> list[dict]: - """convert messages to list[dict].""" - from metagpt.schema import Message - - # ε…¨ιƒ¨θ½¬ζˆlist - if not isinstance(messages, list): - messages = [messages] - - # 转成list[dict] - processed_messages = [] - for msg in messages: - if isinstance(msg, str): - processed_messages.append({"role": "user", "content": msg}) - elif isinstance(msg, dict): - assert set(msg.keys()) == set(["role", "content"]) - processed_messages.append(msg) - elif isinstance(msg, Message): - processed_messages.append(msg.to_dict()) - else: - raise ValueError(f"Only support message type are: str, Message, dict, but got {type(messages).__name__}!") - return processed_messages - - def log_and_reraise(retry_state: RetryCallState): logger.error(f"Retry attempts exhausted. Last exception: {retry_state.outcome.exception()}") logger.warning( diff --git a/tests/mock/mock_llm.py b/tests/mock/mock_llm.py index b4cdfa0cf..c4262e080 100644 --- a/tests/mock/mock_llm.py +++ b/tests/mock/mock_llm.py @@ -8,7 +8,6 @@ from metagpt.provider.azure_openai_api import AzureOpenAILLM from metagpt.provider.constant import GENERAL_FUNCTION_SCHEMA from metagpt.provider.openai_api import OpenAILLM from metagpt.schema import Message -from metagpt.utils.common import process_message OriginalLLM = OpenAILLM if config.llm.api_type == LLMType.OPENAI else AzureOpenAILLM @@ -105,7 +104,7 @@ class MockLLM(OriginalLLM): return rsp async def aask_code(self, messages: Union[str, Message, list[dict]], **kwargs) -> dict: - msg_key = json.dumps(process_message(messages), ensure_ascii=False) + msg_key = json.dumps(self.format_msg(messages), ensure_ascii=False) rsp = await self._mock_rsp(msg_key, self.original_aask_code, messages, **kwargs) return rsp