1. 动作优化

1. SummarizeCode动作:用于基于代码进行总结,思考bug、逻辑、todo
  2. CodeReview动作优化:目前强制要求回答问题,有更高的成功率了
2. 数据结构
  1. Document的标准化:Env->Repo->Document,其中Document/Asset/Code都只用Document
    1. 原用于检索的Document改为IndexableDocument
  2. Repo结构引入:用于Document装载与元数据装载
  3. RepoParser引入:写了一个简单的AST parser(后续可能要换tree-sitter),给出了整库symbol
3. 配置优化
  1. 默认更换为gpt-4-1106-preview,以获得最好的效果与成本
  2. 提供~/.metagpt作为配置最高优先级目录,从中读取config.yaml
  3. workspace可以灵活指定了,在config中配置
4. metagpt作为默认命令行,而非python startup.py
  1. 使用新的METAGPT_ROOT生成方式,而非寻找git,以便cli安装
  2. 命令行由fire换为了typer,它会带来相对更好的体验
  3. project_name可以灵活指定了,在metagpt命令行输入中配置
5. 其他
  1. BossRequirement -> UserRequirement
  2. 大量错误文本的修正,增加了可读性
  3. 中量提示词优化,稍微提升了一些准确率
  4. 暂时屏蔽了LongtermMemory相关逻辑,这个逻辑底层调用了langchain的FAISS,会带来~5秒加载耗时
  5. 修复了安装包中的部分描述错误
This commit is contained in:
geekan 2023-11-20 11:24:46 +08:00
parent 6f345002c4
commit 331d74059f
50 changed files with 699 additions and 387 deletions

View file

@ -100,7 +100,7 @@ For testing, we can use the PyTest framework. This is a mature full-featured Pyt
file_list = ["main.py", "room.py", "player.py", "game.py", "object.py", "puzzle.py", "test_game.py"]
```
## Data structures and interface definitions:
## Data structures and interfaces:
```mermaid
classDiagram
class Room{
@ -209,7 +209,7 @@ Shared knowledge for this project includes understanding the basic principles of
"""
```
## Anything UNCLEAR: Provide as Plain text. Make clear here. For example, don't forget a main entry. don't forget to init 3rd party libs.
## Anything UNCLEAR: Provide as Plain text. Try to clarify it. For example, don't forget a main entry. don't forget to init 3rd party libs.
```python
"""
The original requirements did not specify whether the game should have a save/load feature, multiplayer support, or any specific graphical user interface. More information on these aspects could help in further refining the product design and requirements.

View file

@ -7,7 +7,7 @@
"""
import pytest
from metagpt.actions import BossRequirement
from metagpt.actions import UserRequirement
from metagpt.logs import logger
from metagpt.roles.product_manager import ProductManager
from metagpt.schema import Message
@ -17,7 +17,7 @@ from metagpt.schema import Message
async def test_write_prd():
product_manager = ProductManager()
requirements = "开发一个基于大语言模型与私有知识库的搜索引擎,希望可以基于大语言模型进行搜索总结"
prd = await product_manager.handle(Message(content=requirements, cause_by=BossRequirement))
prd = await product_manager.handle(Message(content=requirements, cause_by=UserRequirement))
logger.info(requirements)
logger.info(prd)

View file

@ -7,22 +7,22 @@
"""
import pytest
from metagpt.const import DATA_PATH
from metagpt.document_store.document import Document
from metagpt.const import METAGPT_ROOT
from metagpt.document import IndexableDocument
CASES = [
("st/faq.xlsx", "Question", "Answer", 1),
("cases/faq.csv", "Question", "Answer", 1),
("requirements.txt", None, None, 0),
# ("cases/faq.csv", "Question", "Answer", 1),
# ("cases/faq.json", "Question", "Answer", 1),
("docx/faq.docx", None, None, 1),
("cases/faq.pdf", None, None, 0), # 这是因为pdf默认没有分割段落
("cases/faq.txt", None, None, 0), # 这是因为txt按照256分割段落
# ("docx/faq.docx", None, None, 1),
# ("cases/faq.pdf", None, None, 0), # 这是因为pdf默认没有分割段落
# ("cases/faq.txt", None, None, 0), # 这是因为txt按照256分割段落
]
@pytest.mark.parametrize("relative_path, content_col, meta_col, threshold", CASES)
def test_document(relative_path, content_col, meta_col, threshold):
doc = Document(DATA_PATH / relative_path, content_col, meta_col)
doc = IndexableDocument.from_path(METAGPT_ROOT / relative_path, content_col, meta_col)
rsp = doc.get_docs_and_metadatas()
assert len(rsp[0]) > threshold
assert len(rsp[1]) > threshold

View file

@ -4,7 +4,7 @@
from metagpt.config import CONFIG
from metagpt.schema import Message
from metagpt.actions import BossRequirement
from metagpt.actions import UserRequirement
from metagpt.roles.role import RoleContext
from metagpt.memory import LongTermMemory
@ -15,24 +15,24 @@ def test_ltm_search():
assert len(openai_api_key) > 20
role_id = 'UTUserLtm(Product Manager)'
rc = RoleContext(watch=[BossRequirement])
rc = RoleContext(watch=[UserRequirement])
ltm = LongTermMemory()
ltm.recover_memory(role_id, rc)
idea = 'Write a cli snake game'
message = Message(role='BOSS', content=idea, cause_by=BossRequirement)
message = Message(role='User', content=idea, cause_by=UserRequirement)
news = ltm.find_news([message])
assert len(news) == 1
ltm.add(message)
sim_idea = 'Write a game of cli snake'
sim_message = Message(role='BOSS', content=sim_idea, cause_by=BossRequirement)
sim_message = Message(role='User', content=sim_idea, cause_by=UserRequirement)
news = ltm.find_news([sim_message])
assert len(news) == 0
ltm.add(sim_message)
new_idea = 'Write a 2048 web game'
new_message = Message(role='BOSS', content=new_idea, cause_by=BossRequirement)
new_message = Message(role='User', content=new_idea, cause_by=UserRequirement)
news = ltm.find_news([new_message])
assert len(news) == 1
ltm.add(new_message)
@ -48,7 +48,7 @@ def test_ltm_search():
assert len(news) == 0
new_idea = 'Write a Battle City'
new_message = Message(role='BOSS', content=new_idea, cause_by=BossRequirement)
new_message = Message(role='User', content=new_idea, cause_by=UserRequirement)
news = ltm_new.find_news([new_message])
assert len(news) == 1

View file

@ -6,7 +6,7 @@ from typing import List
from metagpt.memory.memory_storage import MemoryStorage
from metagpt.schema import Message
from metagpt.actions import BossRequirement
from metagpt.actions import UserRequirement
from metagpt.actions import WritePRD
from metagpt.actions.action_output import ActionOutput
@ -14,7 +14,7 @@ from metagpt.actions.action_output import ActionOutput
def test_idea_message():
idea = 'Write a cli snake game'
role_id = 'UTUser1(Product Manager)'
message = Message(role='BOSS', content=idea, cause_by=BossRequirement)
message = Message(role='User', content=idea, cause_by=UserRequirement)
memory_storage: MemoryStorage = MemoryStorage()
messages = memory_storage.recover_memory(role_id)
@ -24,12 +24,12 @@ def test_idea_message():
assert memory_storage.is_initialized is True
sim_idea = 'Write a game of cli snake'
sim_message = Message(role='BOSS', content=sim_idea, cause_by=BossRequirement)
sim_message = Message(role='User', content=sim_idea, cause_by=UserRequirement)
new_messages = memory_storage.search(sim_message)
assert len(new_messages) == 0 # similar, return []
new_idea = 'Write a 2048 web game'
new_message = Message(role='BOSS', content=new_idea, cause_by=BossRequirement)
new_message = Message(role='User', content=new_idea, cause_by=UserRequirement)
new_messages = memory_storage.search(new_message)
assert new_messages[0].content == message.content
@ -49,7 +49,7 @@ def test_actionout_message():
ic_obj = ActionOutput.create_model_class('prd', out_mapping)
role_id = 'UTUser2(Architect)'
content = 'The boss has requested the creation of a command-line interface (CLI) snake game'
content = 'The user has requested the creation of a command-line interface (CLI) snake game'
message = Message(content=content,
instruct_content=ic_obj(**out_data),
role='user',

View file

@ -9,7 +9,7 @@ import pytest
from semantic_kernel.core_skills import FileIOSkill, MathSkill, TextSkill, TimeSkill
from semantic_kernel.planning.action_planner.action_planner import ActionPlanner
from metagpt.actions import BossRequirement
from metagpt.actions import UserRequirement
from metagpt.roles.sk_agent import SkAgent
from metagpt.schema import Message
@ -23,7 +23,7 @@ async def test_action_planner():
role.import_skill(TimeSkill(), "time")
role.import_skill(TextSkill(), "text")
task = "What is the sum of 110 and 990?"
role.recv(Message(content=task, cause_by=BossRequirement))
role.recv(Message(content=task, cause_by=UserRequirement))
await role._think() # it will choose mathskill.Add
assert "1100" == (await role._act()).content

View file

@ -8,7 +8,7 @@
import pytest
from semantic_kernel.core_skills import TextSkill
from metagpt.actions import BossRequirement
from metagpt.actions import UserRequirement
from metagpt.const import SKILL_DIRECTORY
from metagpt.roles.sk_agent import SkAgent
from metagpt.schema import Message
@ -26,7 +26,7 @@ async def test_basic_planner():
role.import_semantic_skill_from_directory(SKILL_DIRECTORY, "WriterSkill")
role.import_skill(TextSkill(), "TextSkill")
# using BasicPlanner
role.recv(Message(content=task, cause_by=BossRequirement))
role.recv(Message(content=task, cause_by=UserRequirement))
await role._think()
# assuming sk_agent will think he needs WriterSkill.Brainstorm and WriterSkill.Translate
assert "WriterSkill.Brainstorm" in role.plan.generated_plan.result

View file

@ -5,10 +5,10 @@
@Author : alexanderwu
@File : mock.py
"""
from metagpt.actions import BossRequirement, WriteDesign, WritePRD, WriteTasks
from metagpt.actions import UserRequirement, WriteDesign, WritePRD, WriteTasks
from metagpt.schema import Message
BOSS_REQUIREMENT = """开发一个基于大语言模型与私有知识库的搜索引擎,希望可以基于大语言模型进行搜索总结"""
USER_REQUIREMENT = """开发一个基于大语言模型与私有知识库的搜索引擎,希望可以基于大语言模型进行搜索总结"""
DETAIL_REQUIREMENT = """需求开发一个基于LLM大语言模型与私有知识库的搜索引擎希望有几点能力
1. 用户可以在私有知识库进行搜索再根据大语言模型进行总结输出的结果包括了总结
@ -94,7 +94,7 @@ SYSTEM_DESIGN = '''## Python package name
]
```
## Data structures and interface definitions
## Data structures and interfaces
```mermaid
classDiagram
class Main {
@ -252,7 +252,7 @@ a = 'a'
class MockMessages:
req = Message(role="Boss", content=BOSS_REQUIREMENT, cause_by=BossRequirement)
req = Message(role="User", content=USER_REQUIREMENT, cause_by=UserRequirement)
prd = Message(role="Product Manager", content=PRD, cause_by=WritePRD)
system_design = Message(role="Architect", content=SYSTEM_DESIGN, cause_by=WriteDesign)
tasks = Message(role="Project Manager", content=TASKS, cause_by=WriteTasks)

View file

@ -8,7 +8,8 @@ from functools import wraps
from importlib import import_module
from metagpt.actions import Action, ActionOutput, WritePRD
from metagpt.const import WORKSPACE_ROOT
# from metagpt.const import WORKSPACE_ROOT
from metagpt.config import CONFIG
from metagpt.logs import logger
from metagpt.roles import Role
from metagpt.schema import Message
@ -29,7 +30,7 @@ Attention: Use '##' to split sections, not '#', and '## <SECTION_NAME>' SHOULD W
## Selected Elements:Provide as Plain text, up to 5 specified elements, clear and simple
## HTML Layout:Provide as Plain text, use standard HTML code
## CSS Styles (styles.css):Provide as Plain text,use standard css code
## Anything UNCLEAR:Provide as Plain text. Make clear here.
## Anything UNCLEAR:Provide as Plain text. Try to clarify it.
"""
@ -214,7 +215,7 @@ class UIDesign(Action):
logger.info("Finish icon design using StableDiffusion API")
async def _save(self, css_content, html_content):
save_dir = WORKSPACE_ROOT / "resources" / "codes"
save_dir = CONFIG.workspace_path / "resources" / "codes"
if not os.path.exists(save_dir):
os.makedirs(save_dir, exist_ok=True)
# Save CSS and HTML content to files

View file

@ -8,7 +8,7 @@
import pytest
from metagpt.actions import BossRequirement
from metagpt.actions import UserRequirement
from metagpt.environment import Environment
from metagpt.logs import logger
from metagpt.manager import Manager
@ -49,7 +49,7 @@ async def test_publish_and_process_message(env: Environment):
env.add_roles([product_manager, architect])
env.set_manager(Manager())
env.publish_message(Message(role="BOSS", content="需要一个基于LLM做总结的搜索引擎", cause_by=BossRequirement))
env.publish_message(Message(role="User", content="需要一个基于LLM做总结的搜索引擎", cause_by=UserRequirement))
await env.run(k=2)
logger.info(f"{env.history=}")

View file

@ -4,7 +4,9 @@
#
import os
from metagpt.tools.sd_engine import SDEngine, WORKSPACE_ROOT
from metagpt.config import CONFIG
from metagpt.tools.sd_engine import SDEngine
def test_sd_engine_init():
@ -21,5 +23,5 @@ def test_sd_engine_generate_prompt():
async def test_sd_engine_run_t2i():
sd_engine = SDEngine()
await sd_engine.run_t2i(prompts=["test"])
img_path = WORKSPACE_ROOT / "resources" / "SD_Output" / "output_0.png"
img_path = CONFIG.workspace_path / "resources" / "SD_Output" / "output_0.png"
assert os.path.exists(img_path) == True

View file

@ -10,7 +10,7 @@ import os
import pytest
from metagpt.const import get_project_root
from metagpt.const import get_metagpt_root
class TestGetProjectRoot:
@ -20,11 +20,11 @@ class TestGetProjectRoot:
os.chdir(abs_root)
def test_get_project_root(self):
project_root = get_project_root()
project_root = get_metagpt_root()
assert project_root.name == 'metagpt'
def test_get_root_exception(self):
with pytest.raises(Exception) as exc_info:
self.change_etc_dir()
get_project_root()
get_metagpt_root()
assert str(exc_info.value) == "Project root not found."

View file

@ -218,7 +218,7 @@ We need clarification on how the high score should be stored. Should it persist
}
t_text1 = '''## Original Requirements:
The boss wants to create a web-based version of the game "Fly Bird".
The user wants to create a web-based version of the game "Fly Bird".
## Product Goals:

View file

@ -6,12 +6,12 @@
@File : test_read_docx.py
"""
from metagpt.const import PROJECT_ROOT
from metagpt.const import METAGPT_ROOT
from metagpt.utils.read_document import read_docx
class TestReadDocx:
def test_read_docx(self):
docx_sample = PROJECT_ROOT / "tests/data/docx_for_test.docx"
docx_sample = METAGPT_ROOT / "tests/data/docx_for_test.docx"
docx = read_docx(docx_sample)
assert len(docx) == 6