Solved the issue of inconsistent input and output languages.

This commit is contained in:
黄伟韬 2024-07-29 12:01:42 +08:00
parent 23aca9055d
commit 6f17d3da13
5 changed files with 79 additions and 9 deletions

View file

@ -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

View file

@ -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 = """

View file

@ -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"

View file

@ -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)])

View file

@ -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):