diff --git a/metagpt/actions/search_enhanced_qa.py b/metagpt/actions/search_enhanced_qa.py index 1427f9b19..b1810f06a 100644 --- a/metagpt/actions/search_enhanced_qa.py +++ b/metagpt/actions/search_enhanced_qa.py @@ -209,7 +209,7 @@ class SearchEnhancedQA(Action): list[str]: Summaries of relevant web content. """ - relevant_urls = await self._collect_relevant_links(query) + relevant_urls = await self.collect_relevant_links(query) await self._reporter.async_report({"type": "search", "stage": "searching", "urls": relevant_urls}) if not relevant_urls: logger.warning(f"No relevant URLs found for query: {query}") @@ -226,7 +226,7 @@ class SearchEnhancedQA(Action): return citations - async def _collect_relevant_links(self, query: str) -> list[str]: + async def collect_relevant_links(self, query: str) -> list[str]: """Search and rank URLs relevant to the query. Args: diff --git a/metagpt/prompts/product_manager.py b/metagpt/prompts/product_manager.py new file mode 100644 index 000000000..0fc7c3557 --- /dev/null +++ b/metagpt/prompts/product_manager.py @@ -0,0 +1,175 @@ +from metagpt.prompts.di.role_zero import ROLE_INSTRUCTION + +EXTRA_INSTRUCTION = """ +You are a product manager AI assistant specializing in product requirement documentation and market research analysis. +Your work focuses on the analysis of problems and data. +You should always output a document. + +## Core Tools +1. Editor: For the creation and modification of `PRD/Research Report` documents. +2. SearchEnhancedQA: The specified tool for collecting information from the internet MUST BE USED for searching. +3. Browser: Access the search results provided by the SearchEnhancedQA tool using the "goto" method. + +## Mode 1: PRD Creation +Triggered by software/product requests or feature enhancements, ending with the output of a complete PRD. + +### Required Fields +1. Language & Project Info + - Language: Match user's language + - Programming Language: Default to native HTML if unspecified + - Project Name: Use snake_case format + - Restate the original requirements + +2. Product Definition(**IMPORTANT** ) + - Product Goals: 3 clear, orthogonal goals + - User Stories: 3-5 scenarios in "As a [role], I want [feature] so that [benefit]" format + - Competitive Analysis: 5-7 products with pros/cons + - Competitive Quadrant Chart(Required): Using Mermaid + +3. Technical Specifications + - Requirements Analysis: Comprehensive overview of technical needs + - Requirements Pool: List with P0/P1/P2 priorities + - UI Design Draft: Basic layout and functionality + - Open Questions: Unclear aspects needing clarification + +#### Mermaid Diagram Rules +1. Use mermaid quadrantChart syntax. Distribute scores evenly between 0 and 1 +2. Example: +```mermaid +quadrantChart + title "Reach and engagement of campaigns" + x-axis "Low Reach" --> "High Reach" + y-axis "Low Engagement" --> "High Engagement" + quadrant-1 "We should expand" + quadrant-2 "Need to promote" + quadrant-3 "Re-evaluate" + quadrant-4 "May be improved" + "Campaign A": [0.3, 0.6] + "Campaign B": [0.45, 0.23] + "Campaign C": [0.57, 0.69] + "Campaign D": [0.78, 0.34] + "Campaign E": [0.40, 0.34] + "Campaign F": [0.35, 0.78] + "Our Target Product": [0.5, 0.6] +``` + +### PRD Document Guidelines +- Use clear requirement language (Must/Should/May) +- Include measurable criteria +- Prioritize clearly (P0: Must-have, P1: Should-have, P2: Nice-to-have) +- Support with diagrams and charts +- Focus on user value and business goals + +## Mode 2: Market Research +Triggered by market analysis or competitor research requests, ending with the output of a complete report document. + +### **IMPORTANT** Information Collection Requirements + +Must follow this strict information gathering process: +1. Keyword Generation Rules: + - Infer 3 distinct keyword groups on user needs. + - Each group must be a space-separated phrase containing: + * Target industry/product name (REQUIRED) + * Specific aspect or metric + * Time frame or geographic scope when relevant + + Example format: + - Group 1: "electric vehicles market size forecast 2024" + - Group 2: "electric vehicles manufacturing costs analysis" + - Group 3: "electric vehicles consumer preferences survey" + +2. Search Process: + - For each keyword: + * Use SearchEnhancedQA TOOL (SearchEnhancedQA.collect_relevant_links) collect top 3 search results + * Remove duplicate URLs + +3. Information Analysis: + - Must read and analyze EACH unique source individually + - Synthesize information across all sources + - Cross-reference and verify key data points + - Identify critical insights and trends + +4. Quality Control: + - Verify data consistency across sources + - Fill information gaps with targeted additional research + - Ensure balanced perspective from multiple sources + + +### Report Structure +1. Summary: Key findings and recommendations +2. Industry Overview: Market size, trends, and structure +3. Market Analysis: Segments, growth drivers, and challenges +4. Competitor Landscape: Key players and positioning +5. Target Audience Analysis: User segments and needs +6. Pricing Analysis: Market rates and strategies +7. Key Findings: Major insights and opportunities +8. Strategic Recommendations: Action items +9. Appendices: Supporting data + + +### Final Report Requirements +1. Report must be entirely focused on insights and analysis: + - No mention of research methodology + - No source tracking or process documentation + - Present only validated findings and conclusions + +2. Professional Format: + - Clear section hierarchy + - Rich subsection content + - Evidence-based analysis + - Data visualization where appropriate + +3. Content Depth Requirements: + Executive Summary (500+ words): + - Key Market Metrics + - Critical Findings + - Strategic Recommendations + + Industry Overview (800+ words): + - Market Size and Growth + - Industry Value Chain + - Regulatory Environment + - Technology Trends + +4. Quality Standards: + - Every main section must have 3+ detailed subsections + - Each subsection requires 200-300 words minimum + - Include specific examples and data points + - Support all major claims with market evidence + +### Research Guidelines +- Base all analysis on collected data +- Include quantitative and qualitative insights +- Support claims with evidence +- Maintain professional formatting +- Use visuals to support key points + +## Document Standards +1. Format + - Clear heading hierarchy + - Consistent markdown formatting + - Numbered sections + - Professional graphics + - Output charts using Mermaid syntax + +2. Content + - Objective analysis + - Actionable insights + - Clear recommendations + - Supporting evidence + +3. Quality Checks + - Verify data accuracy + - Cross-reference sources + - Ensure completeness + - Review clarity + +Remember: +- Always start with thorough requirements analysis +- Use appropriate tools for each task +- Keep recommendations actionable +- Consider all stakeholder perspectives +- Maintain professional standards throughout +""" + +PRODUCT_MANAGER_INSTRUCTION = ROLE_INSTRUCTION + EXTRA_INSTRUCTION.strip() diff --git a/metagpt/roles/product_manager.py b/metagpt/roles/product_manager.py index f2a47affd..e91ad86e7 100644 --- a/metagpt/roles/product_manager.py +++ b/metagpt/roles/product_manager.py @@ -4,16 +4,14 @@ @Time : 2023/5/11 14:43 @Author : alexanderwu @File : product_manager.py -@Modified By: mashenquan, 2023/11/27. Add `PrepareDocuments` action according to Section 2.2.3.5.1 of RFC 135. +@Modified By: liushaojie, 2024/10/17. """ - -from metagpt.actions import UserRequirement, WritePRD -from metagpt.actions.prepare_documents import PrepareDocuments -from metagpt.actions.requirement_analysis.requirement.pic2txt import Pic2Txt +from metagpt.actions.search_enhanced_qa import SearchEnhancedQA +from metagpt.prompts.product_manager import PRODUCT_MANAGER_INSTRUCTION from metagpt.roles.di.role_zero import RoleZero -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 +from metagpt.tools.libs.browser import Browser +from metagpt.tools.libs.editor import Editor +from metagpt.utils.common import tool2name class ProductManager(RoleZero): @@ -29,38 +27,18 @@ 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 = "Create a Product Requirement Document or market research/competitive product research." 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""" - max_react_loop: int = 1 # FIXME: Read and edit files requires more steps, consider later - tools: list[str] = ["RoleZero", "WritePRD", Pic2Txt.__name__] + instruction: str = PRODUCT_MANAGER_INSTRUCTION + max_react_loop: int = 50 + tools: list[str] = ["RoleZero", Browser.__name__, Editor.__name__, SearchEnhancedQA.__name__] def __init__(self, **kwargs) -> None: super().__init__(**kwargs) - # NOTE: The following init setting will only be effective when self.use_fixed_sop is changed to True self.enable_memory = False - self.set_actions([PrepareDocuments(send_to=any_to_str(self)), WritePRD]) - if self.use_fixed_sop: - self._watch([UserRequirement, PrepareDocuments]) - self.rc.react_mode = RoleReactMode.BY_ORDER def _update_tool_execution(self): - wp = WritePRD() - self.tool_execution_map.update(tool2name(WritePRD, ["run"], wp.run)) - pic2txt = Pic2Txt() - self.tool_execution_map.update(tool2name(Pic2Txt, ["run"], pic2txt.run)) - - async def _think(self) -> bool: - """Decide what to do""" - if not self.use_fixed_sop: - return await super()._think() - - if GitRepository.is_git_dir(self.config.project_path) and not self.config.git_reinit: - self._set_state(1) - else: - self._set_state(0) - self.config.git_reinit = False - self.todo_action = any_to_name(WritePRD) - return bool(self.rc.todo) + se_qa = SearchEnhancedQA() + self.tool_execution_map.update( + tool2name(SearchEnhancedQA, ["collect_relevant_links"], se_qa.collect_relevant_links) + ) diff --git a/metagpt/schema.py b/metagpt/schema.py index 5224eaf14..24ca5b14f 100644 --- a/metagpt/schema.py +++ b/metagpt/schema.py @@ -685,7 +685,17 @@ class Plan(BaseModel): def append_task( self, task_id: str, dependent_task_ids: list[str], instruction: str, assignee: str, task_type: str = "" ): - """Append a new task with task_id (number) to the end of existing task sequences. If dependent_task_ids is not empty, the task will depend on the tasks with the ids in the list. Note that the assignee should be the 'name' of the role.""" + """ + Append a new task with task_id (number) to the end of existing task sequences. + If dependent_task_ids is not empty, the task will depend on the tasks with the ids in the list. + Note that the assignee should be the 'name' of the role. + Args: + task_id (str): The task id to be appended to the existing task sequence + dependent_task_ids (list[str]): The task ids that the new task depends on + instruction (str): The instruction of the new task + assignee (str): The assignee of the new task + task_type (str): The type of the new task, default is empty string + """ new_task = Task( task_id=task_id, dependent_task_ids=dependent_task_ids, diff --git a/tests/metagpt/roles/di/run_product_manager.py b/tests/metagpt/roles/di/run_product_manager.py index 3ab1e9bab..42aa7840a 100644 --- a/tests/metagpt/roles/di/run_product_manager.py +++ b/tests/metagpt/roles/di/run_product_manager.py @@ -1,13 +1,72 @@ import asyncio +import sys -from metagpt.roles.product_manager import ProductManager +from metagpt.logs import logger +from metagpt.roles import ProductManager WRITE_2048 = """Write a PRD for a cli 2048 game""" -REWRITE_2048 = """Rewrite the prd at /Users/gary/Files/temp/workspace/2048_game/docs/prd.json, add a web UI""" +# REWRITE_2048 = """Rewrite the prd at /Users/gary/Files/temp/workspace/2048_game/docs/prd.json, add a web UI""" CASUAL_CHAT = """What's your name?""" +CASE1_GREEDY_SNAKE = "设计一个贪吃蛇游戏,root path: '/Users/seeker/Projects/sdfz/mg/mgx_ops/workspace/temp'" +CASE2_SMART_HOME = "搜索并分析米家、华为智能家居和海尔智家在智能家居市场中的功能、用户需求和市场定位" +CASE3_BEST_SELLING_REFRIGERATOR = "调研当前市场上最畅销的智能冰箱的五个关键特性" + +OLD_PRD = """ +Language +en_us + +Programming Language +N/A + +Original Requirements +Write a PRD based on the current music streaming service. + +Project Name +music_streaming_service + +Product Goals +Enhance user experience with seamless music streaming +Improve accessibility and responsiveness across devices +Expand music library and personalized recommendations +User Stories +As a user, I want to easily search and find my favorite songs and artists. +As a user, I want to create and manage my own playlists. +As a user, I want to receive personalized music recommendations based on my listening history. +As a user, I want to stream music without interruptions or buffering. +As a user, I want to access the service on both desktop and mobile devices. +Competitive Analysis +Spotify: Extensive music library, strong personalized recommendations, and cross-platform availability. +Apple Music: High-quality audio, exclusive content, and seamless integration with Apple devices. +Amazon Music: Large music catalog, integration with Amazon Echo devices, and competitive pricing. +YouTube Music: Vast collection of music videos, user-generated content, and strong search capabilities. +Tidal: High-fidelity sound quality, exclusive releases, and artist-centric approach. +Competitive Quadrant Chart +quadrantChart title "Feature Richness vs. User Satisfaction" x-axis "Low Feature Richness" --> "High Feature Richness" y-axis "Low User Satisfaction" --> "High User Satisfaction" quadrant-1 "Market Leaders" quadrant-2 "Potential Growth" quadrant-3 "Needs Improvement" quadrant-4 "Niche Players" "Spotify": [0.9, 0.85] "Apple Music": [0.85, 0.8] "Amazon Music": [0.75, 0.7] "YouTube Music": [0.8, 0.75] "Tidal": [0.7, 0.65] "Our Target Product": [0.8, 0.8] + +Requirement Analysis +The current music streaming service needs to focus on enhancing user experience by providing seamless streaming, improving accessibility, and expanding the music library. Personalized recommendations and cross-platform availability are crucial for user retention. + +Requirement Pool +['P0', 'Implement a robust search functionality to find songs and artists easily.'] +['P0', 'Develop a feature for users to create and manage playlists.'] +['P1', 'Enhance the recommendation algorithm for personalized music suggestions.'] +['P1', 'Optimize the streaming service to minimize interruptions and buffering.'] +['P2', 'Ensure the service is fully responsive and accessible on both desktop and mobile devices.'] +UI Design draft +The UI should be clean and intuitive, with a prominent search bar, easy-to-navigate menus for playlists and recommendations, and a responsive design that adapts to different screen sizes. The player controls should be easily accessible, and the overall aesthetic should be modern and visually appealing. + +Anything UNCLEAR +Currently, all aspects of the project are clear. +""" +CASE4_MUSIC_STREAMING_MEDIA = f"""We have received feedback from users regarding the current music streaming service, stating that they need better personalized recommendations. Please readjust the content of PRD {OLD_PRD} based on these feedback.""" + +CASE5_SMART_BIG_SCREEN = """分析2024年上半年中国家庭智能大屏行业的发展情况并输出市场分析报告""" + +# CASE6 = "我想要生产一个电子烟产品,请帮我完成市场调研分析报告" + async def main(requirement): product_manager = ProductManager() @@ -15,4 +74,21 @@ async def main(requirement): if __name__ == "__main__": - asyncio.run(main(WRITE_2048)) + cases = [ + # CASE1_GREEDY_SNAKE, + # CASE2_SMART_HOME, + CASE3_BEST_SELLING_REFRIGERATOR, + # CASE4_MUSIC_STREAMING_MEDIA, + # CASE5_SMART_BIG_SCREEN, + # CASE6, + # WRITE_2048, + ] + logger.remove() + # logger.add(sys.stderr, level="DEBUG") + logger.add(sys.stderr, level="INFO") + for case in cases: + logger.info(f"user requirement:\n{case}") + try: + asyncio.run(main(case)) + except Exception as e: + print(e)