From 7cae8572036690ca6c5bb1d472d75f5078178655 Mon Sep 17 00:00:00 2001 From: geekan Date: Fri, 5 Jan 2024 10:56:48 +0800 Subject: [PATCH] use context instead of FileRepo... done main process. --- metagpt/actions/talk_action.py | 26 ++++++++++++++--------- metagpt/actions/write_teaching_plan.py | 2 +- metagpt/config.py | 4 ++-- metagpt/config2.py | 25 ++++++++++++++++------ metagpt/configs/llm_config.py | 2 +- metagpt/memory/brain_memory.py | 12 +++++------ metagpt/provider/azure_openai_api.py | 2 +- metagpt/utils/make_sk_kernel.py | 8 +++---- tests/metagpt/actions/test_talk_action.py | 7 +++--- 9 files changed, 53 insertions(+), 35 deletions(-) diff --git a/metagpt/actions/talk_action.py b/metagpt/actions/talk_action.py index dc127109c..052adfb2f 100644 --- a/metagpt/actions/talk_action.py +++ b/metagpt/actions/talk_action.py @@ -9,25 +9,31 @@ from typing import Optional from metagpt.actions import Action -from metagpt.config import CONFIG -from metagpt.const import DEFAULT_LANGUAGE +from metagpt.config2 import config from metagpt.logs import logger from metagpt.schema import Message -# TOTEST class TalkAction(Action): context: str history_summary: str = "" knowledge: str = "" rsp: Optional[Message] = None + @property + def agent_description(self): + return self.g_context.kwargs["agent_description"] + + @property + def language(self): + return self.g_context.kwargs["language"] or config.language + @property def prompt(self): prompt = "" - if CONFIG.agent_description: + if self.agent_description: prompt = ( - f"You are {CONFIG.agent_description}. Your responses should align with the role-play agreement, " + f"You are {self.agent_description}. Your responses should align with the role-play agreement, " f"maintaining the character's persona and habits. When faced with unrelated questions, playfully " f"decline to answer without revealing your AI nature to preserve the character's image.\n\n" ) @@ -36,7 +42,7 @@ class TalkAction(Action): prompt += ( "If the information is insufficient, you can search in the historical conversation or knowledge above.\n" ) - language = CONFIG.language or DEFAULT_LANGUAGE + language = self.language prompt += ( f"Answer the following questions strictly in {language}, and the answers must follow the Markdown format.\n " f"{self.context}" @@ -47,10 +53,10 @@ class TalkAction(Action): @property def prompt_gpt4(self): kvs = { - "{role}": CONFIG.agent_description or "", + "{role}": self.agent_description or "", "{history}": self.history_summary or "", "{knowledge}": self.knowledge or "", - "{language}": CONFIG.language or DEFAULT_LANGUAGE, + "{language}": self.language, "{ask}": self.context, } prompt = TalkActionPrompt.FORMATION_LOOSE @@ -68,9 +74,9 @@ class TalkAction(Action): @property def aask_args(self): - language = CONFIG.language or DEFAULT_LANGUAGE + language = self.language system_msgs = [ - f"You are {CONFIG.agent_description}.", + f"You are {self.agent_description}.", "Your responses should align with the role-play agreement, " "maintaining the character's persona and habits. When faced with unrelated questions, playfully " "decline to answer without revealing your AI nature to preserve the character's image.", diff --git a/metagpt/actions/write_teaching_plan.py b/metagpt/actions/write_teaching_plan.py index ea9be4819..76923a663 100644 --- a/metagpt/actions/write_teaching_plan.py +++ b/metagpt/actions/write_teaching_plan.py @@ -75,7 +75,7 @@ class WriteTeachingPlanPart(Action): if "{" not in value: return value - # FIXME: 从Context中获取参数 + # FIXME: 从Context中获取参数,而非从options merged_opts = CONFIG.options or {} try: return value.format(**merged_opts) diff --git a/metagpt/config.py b/metagpt/config.py index 176b54cfc..524c95256 100644 --- a/metagpt/config.py +++ b/metagpt/config.py @@ -80,7 +80,7 @@ class Config(metaclass=Singleton): LLMType.OPEN_LLM: self._is_valid_llm_key(self.OPEN_LLM_API_BASE), LLMType.GEMINI: self._is_valid_llm_key(self.GEMINI_API_KEY), LLMType.METAGPT: bool(self._is_valid_llm_key(self.OPENAI_API_KEY) and self.OPENAI_API_TYPE == "metagpt"), - LLMType.AZURE_OPENAI: bool( + LLMType.AZURE: bool( self._is_valid_llm_key(self.OPENAI_API_KEY) and self.OPENAI_API_TYPE == "azure" and self.DEPLOYMENT_NAME @@ -108,7 +108,7 @@ class Config(metaclass=Singleton): provider = provider or self.get_default_llm_provider_enum() model_mappings = { LLMType.OPENAI: self.OPENAI_API_MODEL, - LLMType.AZURE_OPENAI: self.DEPLOYMENT_NAME, + LLMType.AZURE: self.DEPLOYMENT_NAME, } return model_mappings.get(provider, "") diff --git a/metagpt/config2.py b/metagpt/config2.py index ca46cc7a5..f7cd697a5 100644 --- a/metagpt/config2.py +++ b/metagpt/config2.py @@ -64,6 +64,7 @@ class Config(CLIParams, YamlModel): llm_for_researcher_summary: str = "gpt3" llm_for_researcher_report: str = "gpt3" METAGPT_TEXT_TO_IMAGE_MODEL_URL: str = "" + language: str = "English" @classmethod def default(cls): @@ -103,14 +104,24 @@ class Config(CLIParams, YamlModel): raise ValueError(f"LLM {name} not found in config") return self.llm[name] - def get_openai_llm(self, name: Optional[str] = None) -> LLMConfig: + def get_llm_configs_by_type(self, llm_type: LLMType) -> List[LLMConfig]: + """Get LLM instance by type""" + return [v for k, v in self.llm.items() if v.api_type == llm_type] + + def get_llm_config_by_type(self, llm_type: LLMType) -> Optional[LLMConfig]: + """Get LLM instance by type""" + llm = self.get_llm_configs_by_type(llm_type) + if llm: + return llm[0] + return None + + def get_openai_llm(self) -> Optional[LLMConfig]: """Get OpenAI LLMConfig by name. If no OpenAI, raise Exception""" - if name is None: - # Use the first OpenAI LLM as default - name = [k for k, v in self.llm.items() if v.api_type == LLMType.OPENAI][0] - if name not in self.llm: - raise ValueError(f"OpenAI LLM {name} not found in config") - return self.llm[name] + return self.get_llm_config_by_type(LLMType.OPENAI) + + def get_azure_llm(self) -> Optional[LLMConfig]: + """Get Azure LLMConfig by name. If no Azure, raise Exception""" + return self.get_llm_config_by_type(LLMType.AZURE) def merge_dict(dicts: Iterable[Dict]) -> Dict: diff --git a/metagpt/configs/llm_config.py b/metagpt/configs/llm_config.py index 0961478a4..c1a8bc4d3 100644 --- a/metagpt/configs/llm_config.py +++ b/metagpt/configs/llm_config.py @@ -22,7 +22,7 @@ class LLMType(Enum): OPEN_LLM = "open_llm" GEMINI = "gemini" METAGPT = "metagpt" - AZURE_OPENAI = "azure" + AZURE = "azure" OLLAMA = "ollama" diff --git a/metagpt/memory/brain_memory.py b/metagpt/memory/brain_memory.py index ff29eaddb..cf5cf902a 100644 --- a/metagpt/memory/brain_memory.py +++ b/metagpt/memory/brain_memory.py @@ -14,8 +14,8 @@ from typing import Dict, List, Optional from pydantic import BaseModel, Field -from metagpt.config import CONFIG -from metagpt.const import DEFAULT_LANGUAGE, DEFAULT_MAX_TOKENS, DEFAULT_TOKEN_SIZE +from metagpt.config2 import config +from metagpt.const import DEFAULT_MAX_TOKENS, DEFAULT_TOKEN_SIZE from metagpt.logs import logger from metagpt.provider import MetaGPTLLM from metagpt.provider.base_llm import BaseLLM @@ -83,7 +83,7 @@ class BrainMemory(BaseModel): def to_redis_key(prefix: str, user_id: str, chat_id: str): return f"{prefix}:{user_id}:{chat_id}" - async def set_history_summary(self, history_summary, redis_key, redis_conf): + async def set_history_summary(self, history_summary, redis_key): if self.historical_summary == history_summary: if self.is_dirty: await self.dumps(redis_key=redis_key) @@ -140,7 +140,7 @@ class BrainMemory(BaseModel): return text summary = await self._summarize(text=text, max_words=max_words, keep_language=keep_language, limit=limit) if summary: - await self.set_history_summary(history_summary=summary, redis_key=CONFIG.REDIS_KEY, redis_conf=CONFIG.REDIS) + await self.set_history_summary(history_summary=summary, redis_key=config.redis.key) return summary raise ValueError(f"text too long:{text_length}") @@ -164,7 +164,7 @@ class BrainMemory(BaseModel): msgs.reverse() self.history = msgs self.is_dirty = True - await self.dumps(redis_key=CONFIG.REDIS_KEY) + await self.dumps(redis_key=config.redis.key) self.is_dirty = False return BrainMemory.to_metagpt_history_format(self.history) @@ -181,7 +181,7 @@ class BrainMemory(BaseModel): summary = await self.summarize(llm=llm, max_words=500) - language = CONFIG.language or DEFAULT_LANGUAGE + language = config.language command = f"Translate the above summary into a {language} title of less than {max_words} words." summaries = [summary, command] msg = "\n".join(summaries) diff --git a/metagpt/provider/azure_openai_api.py b/metagpt/provider/azure_openai_api.py index 987eafc4c..bd965f2cf 100644 --- a/metagpt/provider/azure_openai_api.py +++ b/metagpt/provider/azure_openai_api.py @@ -18,7 +18,7 @@ from metagpt.provider.llm_provider_registry import register_provider from metagpt.provider.openai_api import OpenAILLM -@register_provider(LLMType.AZURE_OPENAI) +@register_provider(LLMType.AZURE) class AzureOpenAILLM(OpenAILLM): """ Check https://platform.openai.com/examples for examples diff --git a/metagpt/utils/make_sk_kernel.py b/metagpt/utils/make_sk_kernel.py index e0272ea13..319ba3e34 100644 --- a/metagpt/utils/make_sk_kernel.py +++ b/metagpt/utils/make_sk_kernel.py @@ -13,20 +13,20 @@ from semantic_kernel.connectors.ai.open_ai.services.open_ai_chat_completion impo OpenAIChatCompletion, ) -from metagpt.config import CONFIG +from metagpt.config2 import config def make_sk_kernel(): kernel = sk.Kernel() - if CONFIG.OPENAI_API_TYPE == "azure": + if llm := config.get_openai_llm(): kernel.add_chat_service( "chat_completion", - AzureChatCompletion(CONFIG.DEPLOYMENT_NAME, CONFIG.OPENAI_BASE_URL, CONFIG.OPENAI_API_KEY), + AzureChatCompletion(llm.model, llm.base_url, llm.api_key), ) else: kernel.add_chat_service( "chat_completion", - OpenAIChatCompletion(CONFIG.OPENAI_API_MODEL, CONFIG.OPENAI_API_KEY), + OpenAIChatCompletion(llm.model, llm.api_key), ) return kernel diff --git a/tests/metagpt/actions/test_talk_action.py b/tests/metagpt/actions/test_talk_action.py index 0a1e240b0..c46814a9b 100644 --- a/tests/metagpt/actions/test_talk_action.py +++ b/tests/metagpt/actions/test_talk_action.py @@ -9,7 +9,7 @@ import pytest from metagpt.actions.talk_action import TalkAction -from metagpt.config import CONFIG +from metagpt.context import Context from metagpt.schema import Message @@ -36,8 +36,9 @@ from metagpt.schema import Message @pytest.mark.usefixtures("llm_mock") async def test_prompt(agent_description, language, context, knowledge, history_summary): # Prerequisites - CONFIG.agent_description = agent_description - CONFIG.language = language + g_context = Context() + g_context.kwargs["agent_description"] = agent_description + g_context.kwargs["language"] = language action = TalkAction(context=context, knowledge=knowledge, history_summary=history_summary) assert "{" not in action.prompt