From b3707c7a09e19e44ddac6701add262616205deda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BC=9F=E9=9F=AC?= Date: Fri, 26 Jul 2024 18:18:03 +0800 Subject: [PATCH 1/8] Refine the teamleader instruction. Adding a 'User Requirements' section between the 'Example' and 'Instruct' sections. --- metagpt/environment/mgx/mgx_env.py | 2 +- metagpt/prompts/di/role_zero.py | 18 +++++++++++------- metagpt/prompts/di/team_leader.py | 8 ++++---- metagpt/roles/architect.py | 12 ++++++++++-- metagpt/roles/di/role_zero.py | 1 + metagpt/roles/product_manager.py | 14 +++++++++++--- metagpt/tools/libs/editor.py | 2 +- .../test_rolezero_context_builder.py | 2 +- 8 files changed, 40 insertions(+), 19 deletions(-) diff --git a/metagpt/environment/mgx/mgx_env.py b/metagpt/environment/mgx/mgx_env.py index 3a492b3ac..8347e4f44 100644 --- a/metagpt/environment/mgx/mgx_env.py +++ b/metagpt/environment/mgx/mgx_env.py @@ -91,7 +91,7 @@ class MGXEnv(Environment): async def reply_to_human(self, content: str, sent_from: Role = None) -> str: # NOTE: Can be overwritten in remote setting - return "The monitor has verified the message, confirmation acknowledged. Refrain from resending duplicate messages." + return "Human has received and confirmed the message. Refrain from resending duplicate messages. Jsut move the plan to the next task." def message_within_software_sop(self, message: Message) -> bool: # Engineer, QaEngineer can be end of the SOP. Their msg requires routing outside. diff --git a/metagpt/prompts/di/role_zero.py b/metagpt/prompts/di/role_zero.py index d3f978c15..375e7f256 100644 --- a/metagpt/prompts/di/role_zero.py +++ b/metagpt/prompts/di/role_zero.py @@ -10,7 +10,7 @@ Note: 4. Don't forget to append task first when all existing tasks are finished and new tasks are required. 5. Avoid repeating tasks you have already completed. And end loop when all requirements are met. """ -# To ensure compatibility with hard-coded experience, do not add any other content between "# Example" and "# Instruction". +# To ensure compatibility with hard-coded experience, do not add any other content between "# Example" and "# User Requirements". CMD_PROMPT = """ # Latest Observation {latest_observation} @@ -39,6 +39,9 @@ Special Command: Use {{"command_name": "end"}} to do nothing or indicate complet # Example {example} +# User Requirements +{user_requirements} + # Instruction {instruction} @@ -50,10 +53,9 @@ In your response, include at least one command. # Your commands in a json array, in the following output format with correct command_name and args. If there is nothing to do, use the pass or end command: Some text indicating your thoughts before JSON is required, such as what tasks have been completed, what tasks are next, how you should update the plan status, respond to inquiry, or seek for help. Then a json array of commands. You must output ONE and ONLY ONE json array. DON'T output multiple json arrays with thoughts between them. -Output should adhere to the following format. -Firstly, describe the actions you have taken recently. -Secondly, describe the messages you have received recently, with a particular emphasis on messages from users. -Thirdly, describe your current task . Review the histroy, if you find that the current task is identical to a previously completed one, it indicates that the current task has already been accomplished. If all tasks are finished and current task is empty, use the end command to terminate. +Firstly, pay attention to User Requirements and it's constraints. Provide a complete description of the User Requirements and the current task. +Secondly, pay attention to the Latest Observation, describing what the latest observation is and any relevant messages. +Thirdly, if you find that the current task is identical to a previously completed one, it indicates that the current task has already been accomplished. Then, articulate your thoughts and list the commands, adhering closely to the instructions provided. ```json [ @@ -64,8 +66,9 @@ Then, articulate your thoughts and list the commands, adhering closely to the in ... ] ``` -Notice: your output JSON data must be a command list. Notice: your output JSON data section must start with **```json [** +Notice: Your answer must start with an ordinal number. +Notice: The response and arguments must be in the language specified in the User Requirements. """ JSON_REPAIR_PROMPT = """ @@ -78,10 +81,11 @@ JSON_REPAIR_PROMPT = """ ``` Do not use escape characters in json data, particularly within file paths. Help check if there are any formatting issues with the JSON data? If so, please help format it. -If no issues are detected, the original json data should be returned unchanged. +If no issues are detected, the original json data should be returned unchanged. Do not omit any information. Output the JSON data in a format that can be loaded by the json.loads() function. """ + QUICK_THINK_PROMPT = """ Decide if the latest user message previously is a quick question. Quick questions include common-sense, logical, math, multiple-choice questions, greetings, or casual chat that you can answer directly. diff --git a/metagpt/prompts/di/team_leader.py b/metagpt/prompts/di/team_leader.py index acd44d56c..f3d677d45 100644 --- a/metagpt/prompts/di/team_leader.py +++ b/metagpt/prompts/di/team_leader.py @@ -15,8 +15,8 @@ You should use TeamLeader.publish_team_message to team members, asking them to s Pay close attention to new user message, review the conversation history, use RoleZero.reply_to_human to respond to the user directly, DON'T ask your team members. Pay close attention to messages from team members. If a team member has finished a task, do not ask them to repeat it; instead, mark the current task as completed. Note: -1. If the requirement is a pure DATA-RELATED requirement, such as web browsing, web scraping, web searching, web imitation, data science, data analysis, machine learning, deep learning, text-to-image etc. DON'T decompose it, assign a single task with the original user requirement as instruction directly to Data Analyst. -2. If the requirement is developing a software, game, app, or website, excluding the above data-related tasks, you should decompose the requirement into multiple tasks and assign them to different team members based on their expertise, usually the sequence of Product Manager -> Architect -> Project Manager -> Engineer -> (optional: QaEngine if present) -> (optional: DataAnalyst if user requests deployment), each assigned ONE task. When publishing message to Product Manager, you should directly copy the full original user requirement. +1. If the requirement is a pure DATA-RELATED requirement, such as bug fixes, issue reporting, environment setup, terminal operations, pip install, web browsing, web scraping, web searching, web imitation, data science, data analysis, machine learning, deep learning, text-to-image etc. DON'T decompose it, assign a single task with the original user requirement as instruction directly to Data Analyst. +2. If the requirement is developing a software, game, app, or website, excluding the above data-related tasks, you should decompose the requirement into multiple tasks and assign them to different team members based on their expertise. The software default development process has four steps: creating a Product Requirement Document (PRD) by the Product Manager, writing a System Design by the Architect, creating tasks by the Project Manager, and coding by the Engineer. You may choose to execute any of these steps. When publishing message to Product Manager, you should directly copy the full original user requirement. 3. If the requirement contains both DATA-RELATED part mentioned in 1 and software development part mentioned in 2, you should decompose the software development part and assign them to different team members based on their expertise, and assign the DATA-RELATED part to Data Analyst David directly. 4. If the requirement is a common-sense, logical, or math problem, you should respond directly without assigning any task to team members. 5. If you think the requirement is not clear or ambiguous, you should ask the user for clarification immediately. Assign tasks only after all info is clear. @@ -24,8 +24,8 @@ Note: 7. If the requirement is writing a TRD and software framework, you should assign it to Architect. When publishing message to Architect, you should directly copy the full original user requirement. 8. If the receiver message reads 'from {{team member}} to {{\'\'}}, it indicates that someone has completed the current task. Note this in your thoughts. 9. Do not use the 'end' command when the current task remains unfinished; instead, use the 'finish_current_task' command to indicate completion before switching to the next task. -10. If you have made a plan, simply follow it without creating a new one. -11. Do not use escape characters in json data, particularly within file paths. +10. Do not use escape characters in json data, particularly within file paths. +11. Analyze the capabilities of team members and assign tasks to them based on user Requirements. If the requirements ask to ignore certain tasks, follow the requirements. """ QUICK_THINK_SYSTEM_PROMPT = """ diff --git a/metagpt/roles/architect.py b/metagpt/roles/architect.py index f640d4a87..c14a424da 100644 --- a/metagpt/roles/architect.py +++ b/metagpt/roles/architect.py @@ -11,6 +11,14 @@ from metagpt.roles.di.role_zero import RoleZero from metagpt.tools.libs.software_development import write_trd_and_framework from metagpt.utils.common import tool2name +ARCHITECT_INSTRUCTION = """ +Use WriteDesign tool to write a system design document if a system design is required;Use `write_trd_and_framework` tool to write a software framework if a software framework is required; + +Note: +1. When you think, just analyze which tool you should use, and then provide your answer. And your output should contain firstly, secondly, ... +2. The automated tools at your disposal will generate a document that perfectly meets your requirements. There is no need to do it manually. +""" + class Architect(RoleZero): """ @@ -25,13 +33,13 @@ class Architect(RoleZero): name: str = "Bob" profile: str = "Architect" - goal: str = "design a concise, usable, complete software system" + goal: str = "design a concise, usable, complete software system. Create a System Design Document." constraints: str = ( "make sure the architecture is simple enough and use appropriate open source " "libraries. Use same language as user requirement" ) - instruction: str = """Use WriteDesign tool to write a system design document if a system design is required; Use `write_trd_and_framework` tool to write a software framework if a software framework is required;""" + instruction: str = ARCHITECT_INSTRUCTION max_react_loop: int = 1 # FIXME: Read and edit files requires more steps, consider later tools: list[str] = [ "Editor:write,read,write_content", diff --git a/metagpt/roles/di/role_zero.py b/metagpt/roles/di/role_zero.py index 40c03ccad..27bbb76b9 100644 --- a/metagpt/roles/di/role_zero.py +++ b/metagpt/roles/di/role_zero.py @@ -156,6 +156,7 @@ class RoleZero(Role): current_task=current_task, instruction=instruction, latest_observation=memory[-1].content, + user_requirements=self.planner.plan, ) memory = await self.parse_browser_actions(memory) req = self.llm.format_msg(memory + [UserMessage(content=prompt)]) diff --git a/metagpt/roles/product_manager.py b/metagpt/roles/product_manager.py index 7933e74b8..4a86e39f1 100644 --- a/metagpt/roles/product_manager.py +++ b/metagpt/roles/product_manager.py @@ -15,6 +15,14 @@ from metagpt.roles.role import RoleReactMode from metagpt.utils.common import any_to_name, any_to_str, tool2name from metagpt.utils.git_repository import GitRepository +PRODUCTMANAGER_INSTRUCTION = """ +Use WritePRD tool to write PRD if a PRD is required; +Use `Pic2Txt` tool to write out an intact textual user requirements if an intact textual user requiremnt is required given some images alongside the contextual textual descriptions; + +Note: +1. Consider which tools you need in your thoughts. +""" + class ProductManager(RoleZero): """ @@ -29,13 +37,13 @@ class ProductManager(RoleZero): name: str = "Alice" profile: str = "Product Manager" - goal: str = "efficiently create a successful product that meets market demands and user expectations" + goal: str = "efficiently create a successful product that meets market demands and user expectations. Create a Product Requirement Document.." constraints: str = "utilize the same language as the user requirements for seamless communication" todo_action: str = any_to_name(WritePRD) - instruction: str = """Use WritePRD tool to write PRD if a PRD is required, users may asks for a software without mentioning PRD, but you should output the PRD of that software; Use `Pic2Txt` tool to write out an intact textual user requirements if an intact textual user requiremnt is required given some images alongside the contextual textual descriptions""" + instruction: str = """Use WritePRD tool to write PRD if a PRD is required; Use `Pic2Txt` tool to write out an intact textual user requirements if an intact textual user requiremnt is required given some images alongside the contextual textual descriptions;""" max_react_loop: int = 1 # FIXME: Read and edit files requires more steps, consider later - tools: list[str] = ["RoleZero", "WritePRD", Pic2Txt.__name__] + tools: list[str] = ["Editor:write,read,write_content", "RoleZero", "WritePRD", Pic2Txt.__name__] def __init__(self, **kwargs) -> None: super().__init__(**kwargs) diff --git a/metagpt/tools/libs/editor.py b/metagpt/tools/libs/editor.py index 4c6d2b1dc..ca0fbbae5 100644 --- a/metagpt/tools/libs/editor.py +++ b/metagpt/tools/libs/editor.py @@ -36,7 +36,7 @@ class Editor: with open(path, "w", encoding="utf-8") as f: f.write(content) # self.resource.report(path, "path") - return f"The writing/coding the of the file {os.path.basename(path)}' is now completed. The file '{os.path.basename(path)}' has been successfully created." + return f"Writing/coding the of the file {os.path.basename(path)}' has been completed. The file '{os.path.basename(path)}' has been successfully created." def read(self, path: str) -> FileBlock: """Read the whole content of a file. Using absolute paths as the argument for specifying the file location.""" diff --git a/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py b/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py index b7182602d..9e7e628d5 100644 --- a/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py +++ b/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py @@ -34,7 +34,7 @@ class TestRoleZeroContextBuilder: result = context_builder.replace_example_content("Original text", "New example content") assert result == "Replaced content" context_builder.replace_content_between_markers.assert_called_once_with( - "Original text", "# Example", "# Instruction", "New example content" + "Original text", "# Example", "# User Requirements", "New example content" ) def test_replace_content_between_markers(self): From 97d484e493c6409cf906965091cd028c1f91c834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BC=9F=E9=9F=AC?= Date: Fri, 26 Jul 2024 19:04:07 +0800 Subject: [PATCH 2/8] Add the default programming languages (HTML, CSS, and JavaScript) to the team leader's instruction --- metagpt/prompts/di/team_leader.py | 3 ++- metagpt/roles/product_manager.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/metagpt/prompts/di/team_leader.py b/metagpt/prompts/di/team_leader.py index f3d677d45..0952f3d35 100644 --- a/metagpt/prompts/di/team_leader.py +++ b/metagpt/prompts/di/team_leader.py @@ -16,7 +16,7 @@ Pay close attention to new user message, review the conversation history, use Ro Pay close attention to messages from team members. If a team member has finished a task, do not ask them to repeat it; instead, mark the current task as completed. Note: 1. If the requirement is a pure DATA-RELATED requirement, such as bug fixes, issue reporting, environment setup, terminal operations, pip install, web browsing, web scraping, web searching, web imitation, data science, data analysis, machine learning, deep learning, text-to-image etc. DON'T decompose it, assign a single task with the original user requirement as instruction directly to Data Analyst. -2. If the requirement is developing a software, game, app, or website, excluding the above data-related tasks, you should decompose the requirement into multiple tasks and assign them to different team members based on their expertise. The software default development process has four steps: creating a Product Requirement Document (PRD) by the Product Manager, writing a System Design by the Architect, creating tasks by the Project Manager, and coding by the Engineer. You may choose to execute any of these steps. When publishing message to Product Manager, you should directly copy the full original user requirement. +2. If the requirement is developing a software, game, app, or website, excluding the above data-related tasks, you should decompose the requirement into multiple tasks and assign them to different team members based on their expertise. The software default development process has four steps: creating a Product Requirement Document (PRD) by the Product Manager -> writing a System Design by the Architect -> creating tasks by the Project Manager -> coding by the Engineer. You may choose to execute any of these steps. When publishing message to Product Manager, you should directly copy the full original user requirement. 3. If the requirement contains both DATA-RELATED part mentioned in 1 and software development part mentioned in 2, you should decompose the software development part and assign them to different team members based on their expertise, and assign the DATA-RELATED part to Data Analyst David directly. 4. If the requirement is a common-sense, logical, or math problem, you should respond directly without assigning any task to team members. 5. If you think the requirement is not clear or ambiguous, you should ask the user for clarification immediately. Assign tasks only after all info is clear. @@ -26,6 +26,7 @@ Note: 9. Do not use the 'end' command when the current task remains unfinished; instead, use the 'finish_current_task' command to indicate completion before switching to the next task. 10. Do not use escape characters in json data, particularly within file paths. 11. Analyze the capabilities of team members and assign tasks to them based on user Requirements. If the requirements ask to ignore certain tasks, follow the requirements. +12. If the requirement is to develop software and does not specify a programming language, use the default web technologies: HTML (`*.html`), CSS (`*.css`), and JavaScript (`*.js`). You must add this to the requirements. """ QUICK_THINK_SYSTEM_PROMPT = """ diff --git a/metagpt/roles/product_manager.py b/metagpt/roles/product_manager.py index 4a86e39f1..f0edf0bf9 100644 --- a/metagpt/roles/product_manager.py +++ b/metagpt/roles/product_manager.py @@ -43,7 +43,7 @@ class ProductManager(RoleZero): instruction: str = """Use WritePRD tool to write PRD if a PRD is required; Use `Pic2Txt` tool to write out an intact textual user requirements if an intact textual user requiremnt is required given some images alongside the contextual textual descriptions;""" max_react_loop: int = 1 # FIXME: Read and edit files requires more steps, consider later - tools: list[str] = ["Editor:write,read,write_content", "RoleZero", "WritePRD", Pic2Txt.__name__] + tools: list[str] = ["RoleZero", "WritePRD", Pic2Txt.__name__] def __init__(self, **kwargs) -> None: super().__init__(**kwargs) From 9e4756c841bf97adc5ae6317ef90914a2e913a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BC=9F=E9=9F=AC?= Date: Fri, 26 Jul 2024 19:11:06 +0800 Subject: [PATCH 3/8] change teamleader's instruction --- metagpt/prompts/di/team_leader.py | 3 +-- metagpt/tools/libs/editor.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/metagpt/prompts/di/team_leader.py b/metagpt/prompts/di/team_leader.py index 0952f3d35..1b7a8209e 100644 --- a/metagpt/prompts/di/team_leader.py +++ b/metagpt/prompts/di/team_leader.py @@ -15,8 +15,7 @@ You should use TeamLeader.publish_team_message to team members, asking them to s Pay close attention to new user message, review the conversation history, use RoleZero.reply_to_human to respond to the user directly, DON'T ask your team members. Pay close attention to messages from team members. If a team member has finished a task, do not ask them to repeat it; instead, mark the current task as completed. Note: -1. If the requirement is a pure DATA-RELATED requirement, such as bug fixes, issue reporting, environment setup, terminal operations, pip install, web browsing, web scraping, web searching, web imitation, data science, data analysis, machine learning, deep learning, text-to-image etc. DON'T decompose it, assign a single task with the original user requirement as instruction directly to Data Analyst. -2. If the requirement is developing a software, game, app, or website, excluding the above data-related tasks, you should decompose the requirement into multiple tasks and assign them to different team members based on their expertise. The software default development process has four steps: creating a Product Requirement Document (PRD) by the Product Manager -> writing a System Design by the Architect -> creating tasks by the Project Manager -> coding by the Engineer. You may choose to execute any of these steps. When publishing message to Product Manager, you should directly copy the full original user requirement. +1. If the requirement is a pure DATA-RELATED requirement, such as web browsing, web scraping, web searching, web imitation, data science, data analysis, machine learning, deep learning, text-to-image etc. DON'T decompose it, assign a single task with the original user requirement as instruction directly to Data Analyst. 3. If the requirement contains both DATA-RELATED part mentioned in 1 and software development part mentioned in 2, you should decompose the software development part and assign them to different team members based on their expertise, and assign the DATA-RELATED part to Data Analyst David directly. 4. If the requirement is a common-sense, logical, or math problem, you should respond directly without assigning any task to team members. 5. If you think the requirement is not clear or ambiguous, you should ask the user for clarification immediately. Assign tasks only after all info is clear. diff --git a/metagpt/tools/libs/editor.py b/metagpt/tools/libs/editor.py index ca0fbbae5..b964a2741 100644 --- a/metagpt/tools/libs/editor.py +++ b/metagpt/tools/libs/editor.py @@ -36,7 +36,7 @@ class Editor: with open(path, "w", encoding="utf-8") as f: f.write(content) # self.resource.report(path, "path") - return f"Writing/coding the of the file {os.path.basename(path)}' has been completed. The file '{os.path.basename(path)}' has been successfully created." + return f"The writing/coding the of the file {os.path.basename(path)}' is now completed. The file '{os.path.basename(path)}' has been successfully created." def read(self, path: str) -> FileBlock: """Read the whole content of a file. Using absolute paths as the argument for specifying the file location.""" From 68eaa2d6a40914ad6935a46f04b619c3e874721d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BC=9F=E9=9F=AC?= Date: Fri, 26 Jul 2024 19:15:39 +0800 Subject: [PATCH 4/8] prompt format issuse --- metagpt/roles/product_manager.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/metagpt/roles/product_manager.py b/metagpt/roles/product_manager.py index f0edf0bf9..db45de657 100644 --- a/metagpt/roles/product_manager.py +++ b/metagpt/roles/product_manager.py @@ -15,14 +15,6 @@ from metagpt.roles.role import RoleReactMode from metagpt.utils.common import any_to_name, any_to_str, tool2name from metagpt.utils.git_repository import GitRepository -PRODUCTMANAGER_INSTRUCTION = """ -Use WritePRD tool to write PRD if a PRD is required; -Use `Pic2Txt` tool to write out an intact textual user requirements if an intact textual user requiremnt is required given some images alongside the contextual textual descriptions; - -Note: -1. Consider which tools you need in your thoughts. -""" - class ProductManager(RoleZero): """ @@ -41,7 +33,7 @@ class ProductManager(RoleZero): constraints: str = "utilize the same language as the user requirements for seamless communication" todo_action: str = any_to_name(WritePRD) - instruction: str = """Use WritePRD tool to write PRD if a PRD is required; Use `Pic2Txt` tool to write out an intact textual user requirements if an intact textual user requiremnt is required given some images alongside the contextual textual descriptions;""" + instruction: str = """Use WritePRD tool to write PRD if a PRD is required, users may asks for a software without mentioning PRD, but you should output the PRD of that software; Use `Pic2Txt` tool to write out an intact textual user requirements if an intact textual user requiremnt is required given some images alongside the contextual textual descriptions""" max_react_loop: int = 1 # FIXME: Read and edit files requires more steps, consider later tools: list[str] = ["RoleZero", "WritePRD", Pic2Txt.__name__] From 23aca9055de9f68c998f93d3e8eca801ea90972b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BC=9F=E9=9F=AC?= Date: Fri, 26 Jul 2024 20:16:59 +0800 Subject: [PATCH 5/8] change teamleader prompt --- metagpt/prompts/di/team_leader.py | 1 + 1 file changed, 1 insertion(+) diff --git a/metagpt/prompts/di/team_leader.py b/metagpt/prompts/di/team_leader.py index 1b7a8209e..200719e52 100644 --- a/metagpt/prompts/di/team_leader.py +++ b/metagpt/prompts/di/team_leader.py @@ -16,6 +16,7 @@ Pay close attention to new user message, review the conversation history, use Ro Pay close attention to messages from team members. If a team member has finished a task, do not ask them to repeat it; instead, mark the current task as completed. Note: 1. If the requirement is a pure DATA-RELATED requirement, such as web browsing, web scraping, web searching, web imitation, data science, data analysis, machine learning, deep learning, text-to-image etc. DON'T decompose it, assign a single task with the original user requirement as instruction directly to Data Analyst. +2. If the requirement is developing a software, game, app, or website, excluding the above data-related tasks, you should decompose the requirement into multiple tasks and assign them to different team members based on their expertise. The software default development process has four steps: creating a Product Requirement Document (PRD) by the Product Manager -> writing a System Design by the Architect -> creating tasks by the Project Manager -> and coding by the Engineer. You may choose to execute any of these steps. When publishing message to Product Manager, you should directly copy the full original user requirement. 3. If the requirement contains both DATA-RELATED part mentioned in 1 and software development part mentioned in 2, you should decompose the software development part and assign them to different team members based on their expertise, and assign the DATA-RELATED part to Data Analyst David directly. 4. If the requirement is a common-sense, logical, or math problem, you should respond directly without assigning any task to team members. 5. If you think the requirement is not clear or ambiguous, you should ask the user for clarification immediately. Assign tasks only after all info is clear. From 6f17d3da1390896abf8f57a21a0c636485caa568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BC=9F=E9=9F=AC?= Date: Mon, 29 Jul 2024 12:01:42 +0800 Subject: [PATCH 6/8] Solved the issue of inconsistent input and output languages. --- metagpt/actions/anaylze_requirements.py | 68 +++++++++++++++++++ metagpt/prompts/di/role_zero.py | 12 ++-- metagpt/roles/architect.py | 2 +- metagpt/roles/di/role_zero.py | 4 +- .../test_rolezero_context_builder.py | 2 +- 5 files changed, 79 insertions(+), 9 deletions(-) create mode 100644 metagpt/actions/anaylze_requirements.py diff --git a/metagpt/actions/anaylze_requirements.py b/metagpt/actions/anaylze_requirements.py new file mode 100644 index 000000000..486dc02fa --- /dev/null +++ b/metagpt/actions/anaylze_requirements.py @@ -0,0 +1,68 @@ +import json + +from metagpt.actions import Action +from metagpt.utils.common import CodeParser + +ANALYZE_REQUIREMENTS = """ +# Example 1 +Requirements : Create 2048 game. Do not write PRD. +Outputs:{{ + "response_language": "English" + "requirements_constraints": "Do not write PRD." +}} +# Example 2 +Requirements : 创建一个贪吃蛇,只需要给出设计文档和代码 +Outputs:{{ + "response_language": "Chinese" + "requirements_constraints": "只需要给出设计文档和代码" +}} + +# Example 3 +Requirements :You must ignore create PRD and TRD. Snake Game RequirementsGame InterfaceThe game interface is a rectangular grid.The size of the grid can be adjusted as needed (e.g., 20x20).The snake and the food are displayed on the grid.Game ObjectsSnake: Composed of multiple cells, with an initial length of 3 cells.Food: Appears randomly in one cell on the grid.GameplayThe player controls the snake's movement direction using the arrow keys (up, down, left, right).Each key press changes the snake's movement direction.With each move, the snake's head enters the next cell, and the tail leaves the last cell.When the snake's head meets the food, the snake lengthens by one cell, and new food appears at a random position on the grid.The game ends if the snake's head hits the wall or itself.User InterfaceDisplay the current score (number of food eaten).Display the game status (ongoing or ended).Provide an option to restart the game.Technical RequirementsImplement using HTML, CSS, and JavaScript.Use the Canvas element to draw the game interface.Code should be well-structured and easy to maintain and extend. +Outputs:{{ + "response_language": "English" + "requirements_constraints": "You must ignore create PRD and TRD." +}} + +# Requirements +{requirements} + +# Instructions +You must output in the same language as the Requirements. +First, This language should be consistent with the language used in the requirement description. determine the natural language you must respond in. The default language is English +Second, extract the restrictions in the requirements, specifically the steps. Do not include detailed demand descriptions; focus only on the restrictions. + +Note: +1. if there is not restrictions, requirements_restrictions must be "" + +# Output Format +{{ + "response_language": "the language to respond in" + "requirements_restrictions": "the restrictions in the requirements" +}} +""" + + +class AnalyzeRequirementsRestrictions(Action): + """Write a review for the given context.""" + + name: str = "AnalyzeRequirementsRestrictions" + + async def run(self, requirements): + """Analyze the constraints and the language used in the requirements.""" + node = await self.llm.aask(ANALYZE_REQUIREMENTS.format(requirements=requirements)) + node = CodeParser.parse_code(block=None, lang="json", text=node) + try: + node = json.loads(node) + except: + node = {} + # constraints = node.instruct_content.model_dump().get("CONSTRAINTS",None) + # output_language = node.instruct_content.model_dump().get("OUTPUT_LANGUAGE","English") + output_language = node.get("response_language", "English") + constraints = node.get("requirements_restrictions", "") + format_instruction = "" + format_instruction += f"1.[User Restrictions] : {constraints}\n" + format_instruction += ( + f"2.[Language Restrictions] : The response must be in the language specified by {output_language}." + ) + return format_instruction diff --git a/metagpt/prompts/di/role_zero.py b/metagpt/prompts/di/role_zero.py index 375e7f256..210652f8e 100644 --- a/metagpt/prompts/di/role_zero.py +++ b/metagpt/prompts/di/role_zero.py @@ -10,7 +10,7 @@ Note: 4. Don't forget to append task first when all existing tasks are finished and new tasks are required. 5. Avoid repeating tasks you have already completed. And end loop when all requirements are met. """ -# To ensure compatibility with hard-coded experience, do not add any other content between "# Example" and "# User Requirements". +# To ensure compatibility with hard-coded experience, do not add any other content between "# Example" and "# Instruction". CMD_PROMPT = """ # Latest Observation {latest_observation} @@ -39,8 +39,6 @@ Special Command: Use {{"command_name": "end"}} to do nothing or indicate complet # Example {example} -# User Requirements -{user_requirements} # Instruction {instruction} @@ -51,12 +49,15 @@ If you finish current task, you will automatically take the next task in the exi Review the latest plan's outcome, focusing on achievements. If your completed task matches the current, consider it finished. In your response, include at least one command. +# Constraints +{requirements_constraints} + # Your commands in a json array, in the following output format with correct command_name and args. If there is nothing to do, use the pass or end command: Some text indicating your thoughts before JSON is required, such as what tasks have been completed, what tasks are next, how you should update the plan status, respond to inquiry, or seek for help. Then a json array of commands. You must output ONE and ONLY ONE json array. DON'T output multiple json arrays with thoughts between them. -Firstly, pay attention to User Requirements and it's constraints. Provide a complete description of the User Requirements and the current task. +Firstly, pay attention to User Requirements. Provide a complete description of the User Requirements ,pay attention to[User Restrictions] Provide a complete description of constraints, and the current task. Secondly, pay attention to the Latest Observation, describing what the latest observation is and any relevant messages. Thirdly, if you find that the current task is identical to a previously completed one, it indicates that the current task has already been accomplished. -Then, articulate your thoughts and list the commands, adhering closely to the instructions provided. +Then, articulate your thoughts and list the commands, adhering closely to the instructions provided. you thoughts and cammand must obey [User Restrictions] ```json [ {{ @@ -68,7 +69,6 @@ Then, articulate your thoughts and list the commands, adhering closely to the in ``` Notice: your output JSON data section must start with **```json [** Notice: Your answer must start with an ordinal number. -Notice: The response and arguments must be in the language specified in the User Requirements. """ JSON_REPAIR_PROMPT = """ diff --git a/metagpt/roles/architect.py b/metagpt/roles/architect.py index c14a424da..2886cbad3 100644 --- a/metagpt/roles/architect.py +++ b/metagpt/roles/architect.py @@ -33,7 +33,7 @@ class Architect(RoleZero): name: str = "Bob" profile: str = "Architect" - goal: str = "design a concise, usable, complete software system. Create a System Design Document." + goal: str = "design a concise, usable, complete software system." constraints: str = ( "make sure the architecture is simple enough and use appropriate open source " "libraries. Use same language as user requirement" diff --git a/metagpt/roles/di/role_zero.py b/metagpt/roles/di/role_zero.py index 27bbb76b9..4c4098f31 100644 --- a/metagpt/roles/di/role_zero.py +++ b/metagpt/roles/di/role_zero.py @@ -9,6 +9,7 @@ from typing import Callable, Dict, List, Literal, Tuple from pydantic import model_validator from metagpt.actions import Action, UserRequirement +from metagpt.actions.anaylze_requirements import AnalyzeRequirementsRestrictions from metagpt.actions.di.run_command import RunCommand from metagpt.exp_pool import exp_cache from metagpt.exp_pool.context_builders import RoleZeroContextBuilder @@ -134,6 +135,7 @@ class RoleZero(Role): if not self.planner.plan.goal: self.planner.plan.goal = self.get_memories()[-1].content + self.requirements_constraints = await AnalyzeRequirementsRestrictions().run(self.planner.plan.goal) ### 1. Experience ### example = self._retrieve_experience() @@ -156,7 +158,7 @@ class RoleZero(Role): current_task=current_task, instruction=instruction, latest_observation=memory[-1].content, - user_requirements=self.planner.plan, + requirements_constraints=self.requirements_constraints, ) memory = await self.parse_browser_actions(memory) req = self.llm.format_msg(memory + [UserMessage(content=prompt)]) diff --git a/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py b/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py index 9e7e628d5..b7182602d 100644 --- a/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py +++ b/tests/metagpt/exp_pool/test_context_builders/test_rolezero_context_builder.py @@ -34,7 +34,7 @@ class TestRoleZeroContextBuilder: result = context_builder.replace_example_content("Original text", "New example content") assert result == "Replaced content" context_builder.replace_content_between_markers.assert_called_once_with( - "Original text", "# Example", "# User Requirements", "New example content" + "Original text", "# Example", "# Instruction", "New example content" ) def test_replace_content_between_markers(self): From a68b8dd1e4b445b6e3020a6987e08f7d5bceac47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BC=9F=E9=9F=AC?= Date: Mon, 29 Jul 2024 14:39:58 +0800 Subject: [PATCH 7/8] =?UTF-8?q?fixbug:=20=E4=B8=8D=E9=81=B5=E5=BE=AA?= =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E6=AD=A5=E9=AA=A4=EF=BC=8C=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E8=BE=93=E5=87=BA=E8=AF=AD=E8=A8=80=E4=B8=8D=E4=B8=80?= =?UTF-8?q?=E8=87=B4=EF=BC=8C=E9=BB=98=E8=AE=A4=E5=BC=80=E5=8F=91=E7=8E=AF?= =?UTF-8?q?=E5=A2=83=E4=B8=8D=E4=B8=BAweb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- metagpt/prompts/di/role_zero.py | 2 +- metagpt/prompts/di/team_leader.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/metagpt/prompts/di/role_zero.py b/metagpt/prompts/di/role_zero.py index 243b3f927..d8845de61 100644 --- a/metagpt/prompts/di/role_zero.py +++ b/metagpt/prompts/di/role_zero.py @@ -49,7 +49,7 @@ If you finish current task, you will automatically take the next task in the exi Review the latest plan's outcome, focusing on achievements. If your completed task matches the current, consider it finished. In your response, include at least one command. -# Constraints +# Restrictions {requirements_constraints} # Your commands in a json array, in the following output format with correct command_name and args. If there is nothing to do, use the pass or end command: diff --git a/metagpt/prompts/di/team_leader.py b/metagpt/prompts/di/team_leader.py index 200719e52..7686de36e 100644 --- a/metagpt/prompts/di/team_leader.py +++ b/metagpt/prompts/di/team_leader.py @@ -17,7 +17,8 @@ Pay close attention to messages from team members. If a team member has finished Note: 1. If the requirement is a pure DATA-RELATED requirement, such as web browsing, web scraping, web searching, web imitation, data science, data analysis, machine learning, deep learning, text-to-image etc. DON'T decompose it, assign a single task with the original user requirement as instruction directly to Data Analyst. 2. If the requirement is developing a software, game, app, or website, excluding the above data-related tasks, you should decompose the requirement into multiple tasks and assign them to different team members based on their expertise. The software default development process has four steps: creating a Product Requirement Document (PRD) by the Product Manager -> writing a System Design by the Architect -> creating tasks by the Project Manager -> and coding by the Engineer. You may choose to execute any of these steps. When publishing message to Product Manager, you should directly copy the full original user requirement. -3. If the requirement contains both DATA-RELATED part mentioned in 1 and software development part mentioned in 2, you should decompose the software development part and assign them to different team members based on their expertise, and assign the DATA-RELATED part to Data Analyst David directly. +2.1. If the requirement contains both DATA-RELATED part mentioned in 1 and software development part mentioned in 2, you should decompose the software development part and assign them to different team members based on their expertise, and assign the DATA-RELATED part to Data Analyst David directly. +3. If the requirement is to fix a bug or issue, you should assign it to Issue Solver instead of Engineer. 4. If the requirement is a common-sense, logical, or math problem, you should respond directly without assigning any task to team members. 5. If you think the requirement is not clear or ambiguous, you should ask the user for clarification immediately. Assign tasks only after all info is clear. 6. It is helpful for Engineer to have both the system design and the project schedule for writing the code, so include paths of both files (if available) and remind Engineer to definitely read them when publishing message to Engineer. From 878d4bd2e72d312f55094683353630e7e4412545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BC=9F=E9=9F=AC?= Date: Mon, 29 Jul 2024 15:31:20 +0800 Subject: [PATCH 8/8] Fix format issues --- metagpt/actions/anaylze_requirements.py | 86 ++++++++++++------------- metagpt/prompts/di/role_zero.py | 1 - metagpt/roles/architect.py | 2 +- metagpt/roles/di/role_zero.py | 1 + metagpt/roles/product_manager.py | 2 +- 5 files changed, 46 insertions(+), 46 deletions(-) diff --git a/metagpt/actions/anaylze_requirements.py b/metagpt/actions/anaylze_requirements.py index 486dc02fa..846895ef0 100644 --- a/metagpt/actions/anaylze_requirements.py +++ b/metagpt/actions/anaylze_requirements.py @@ -1,45 +1,56 @@ -import json - from metagpt.actions import Action -from metagpt.utils.common import CodeParser ANALYZE_REQUIREMENTS = """ -# Example 1 -Requirements : Create 2048 game. Do not write PRD. -Outputs:{{ - "response_language": "English" - "requirements_constraints": "Do not write PRD." -}} -# Example 2 -Requirements : 创建一个贪吃蛇,只需要给出设计文档和代码 -Outputs:{{ - "response_language": "Chinese" - "requirements_constraints": "只需要给出设计文档和代码" -}} - -# Example 3 -Requirements :You must ignore create PRD and TRD. Snake Game RequirementsGame InterfaceThe game interface is a rectangular grid.The size of the grid can be adjusted as needed (e.g., 20x20).The snake and the food are displayed on the grid.Game ObjectsSnake: Composed of multiple cells, with an initial length of 3 cells.Food: Appears randomly in one cell on the grid.GameplayThe player controls the snake's movement direction using the arrow keys (up, down, left, right).Each key press changes the snake's movement direction.With each move, the snake's head enters the next cell, and the tail leaves the last cell.When the snake's head meets the food, the snake lengthens by one cell, and new food appears at a random position on the grid.The game ends if the snake's head hits the wall or itself.User InterfaceDisplay the current score (number of food eaten).Display the game status (ongoing or ended).Provide an option to restart the game.Technical RequirementsImplement using HTML, CSS, and JavaScript.Use the Canvas element to draw the game interface.Code should be well-structured and easy to maintain and extend. -Outputs:{{ - "response_language": "English" - "requirements_constraints": "You must ignore create PRD and TRD." -}} +# Example +{examples} # Requirements {requirements} # Instructions +{instructions} + +# Output Format +{output_format} + +Follow the instructions and output format. Do not include any additional content. +""" + +EXAMPLES = """ +Example 1 +Requirements: +Create 2048 game. Do not write PRD. +Outputs: +[User Restrictions] : Do not write PRD. +[Language Restrictions] : The response must be in the language specified by English. + +Example 2 +Requirements: +创建一个贪吃蛇,只需要给出设计文档和代码 +Outputs: +[User Restrictions] : 只需要给出设计文档和代码. +[Language Restrictions] : The response must be in the language specified by Chinese. + +Example 3 +Requirements: +You must ignore create PRD and TRD. Help me write a schedule display program for the Paris Olympics. +Outputs: +[User Restrictions] : You must ignore create PRD and TRD. +[Language Restrictions] : The response must be in the language specified by English. +""" + +INSTRUCTIONS = """ You must output in the same language as the Requirements. First, This language should be consistent with the language used in the requirement description. determine the natural language you must respond in. The default language is English Second, extract the restrictions in the requirements, specifically the steps. Do not include detailed demand descriptions; focus only on the restrictions. Note: 1. if there is not restrictions, requirements_restrictions must be "" +""" -# Output Format -{{ - "response_language": "the language to respond in" - "requirements_restrictions": "the restrictions in the requirements" -}} +OUTPUT_FORMAT = """ +[User Restrictions] : the restrictions in the requirements +[Language Restrictions] : The response must be in the language specified by {{language}} """ @@ -48,21 +59,10 @@ class AnalyzeRequirementsRestrictions(Action): name: str = "AnalyzeRequirementsRestrictions" - async def run(self, requirements): + async def run(self, requirements, isinstance=INSTRUCTIONS, output_format=OUTPUT_FORMAT): """Analyze the constraints and the language used in the requirements.""" - node = await self.llm.aask(ANALYZE_REQUIREMENTS.format(requirements=requirements)) - node = CodeParser.parse_code(block=None, lang="json", text=node) - try: - node = json.loads(node) - except: - node = {} - # constraints = node.instruct_content.model_dump().get("CONSTRAINTS",None) - # output_language = node.instruct_content.model_dump().get("OUTPUT_LANGUAGE","English") - output_language = node.get("response_language", "English") - constraints = node.get("requirements_restrictions", "") - format_instruction = "" - format_instruction += f"1.[User Restrictions] : {constraints}\n" - format_instruction += ( - f"2.[Language Restrictions] : The response must be in the language specified by {output_language}." + prompt = ANALYZE_REQUIREMENTS.format( + examples=EXAMPLES, requirements=requirements, instructions=isinstance, output_format=output_format ) - return format_instruction + rsp = await self.llm.aask(prompt) + return rsp diff --git a/metagpt/prompts/di/role_zero.py b/metagpt/prompts/di/role_zero.py index d8845de61..4edfe8936 100644 --- a/metagpt/prompts/di/role_zero.py +++ b/metagpt/prompts/di/role_zero.py @@ -66,7 +66,6 @@ Output should adhere to the following format. ] ``` Notice: your output JSON data section must start with **```json [** -Notice: Your answer must start with an ordinal number. """ THOUGHT_GUIDANCE = """ First, describe the actions you have taken recently. diff --git a/metagpt/roles/architect.py b/metagpt/roles/architect.py index 2886cbad3..503be51f6 100644 --- a/metagpt/roles/architect.py +++ b/metagpt/roles/architect.py @@ -12,7 +12,7 @@ from metagpt.tools.libs.software_development import write_trd_and_framework from metagpt.utils.common import tool2name ARCHITECT_INSTRUCTION = """ -Use WriteDesign tool to write a system design document if a system design is required;Use `write_trd_and_framework` tool to write a software framework if a software framework is required; +Use WriteDesign tool to write a system design document if a system design is required; Use `write_trd_and_framework` tool to write a software framework if a software framework is required; Note: 1. When you think, just analyze which tool you should use, and then provide your answer. And your output should contain firstly, secondly, ... diff --git a/metagpt/roles/di/role_zero.py b/metagpt/roles/di/role_zero.py index 40b90c6f0..7b6057176 100644 --- a/metagpt/roles/di/role_zero.py +++ b/metagpt/roles/di/role_zero.py @@ -71,6 +71,7 @@ class RoleZero(Role): commands: list[dict] = [] # commands to be executed memory_k: int = 20 # number of memories (messages) to use as historical context use_fixed_sop: bool = False + requirements_constraints: str = "" # the constraints in user requirements @model_validator(mode="after") def set_plan_and_tool(self) -> "RoleZero": diff --git a/metagpt/roles/product_manager.py b/metagpt/roles/product_manager.py index db45de657..93d83e329 100644 --- a/metagpt/roles/product_manager.py +++ b/metagpt/roles/product_manager.py @@ -29,7 +29,7 @@ class ProductManager(RoleZero): name: str = "Alice" profile: str = "Product Manager" - goal: str = "efficiently create a successful product that meets market demands and user expectations. Create a Product Requirement Document.." + goal: str = "efficiently create a successful product that meets market demands and user expectations. Create a Product Requirement Document." constraints: str = "utilize the same language as the user requirements for seamless communication" todo_action: str = any_to_name(WritePRD)