MetaGPT源码 (ContextMixin 类)

news2024/12/13 9:03:43

目录

    • 理解 ContextMixin
      • 什么是 ContextMixin?
      • 主要组件
      • 实现细节
    • 测试 ContextMixin
      • 示例:ModelX
        • 1. 配置优先级
        • 2. 多继承
        • 3. 多继承重写
        • 4. 配置优先级

在本文中,我们将探索 ContextMixin 类,它在多重继承场景中的集成及其在 Python 配置和上下文管理中的应用。此外,我们将通过测试验证其功能,以了解它如何简化模型配置的处理。让我们深入了解代码片段的详细解释。


理解 ContextMixin

什么是 ContextMixin?

ContextMixin 是一个用于高效管理上下文和配置的 Python 类。继承该类的模型或对象能够:

  1. 通过灵活的优先级规则处理上下文(private_context)和配置(private_config)。
  2. 管理与 LLM(private_llm)实例的交互。
  3. 支持动态设置属性的覆盖机制。

主要组件

  • 私有上下文和配置

    • private_contextprivate_config 被设计为内部属性,为每个实例提供灵活的作用域。
    • 这些属性默认值为 None,但可以显式覆盖。
  • LLM 管理

    • 通过 private_llm 集成 LLM,支持从配置动态初始化。

实现细节

以下是核心 ContextMixin 类:

from typing import Optional

from pydantic import BaseModel, ConfigDict, Field, model_validator

from metagpt.config2 import Config
from metagpt.context import Context
from metagpt.provider.base_llm import BaseLLM


class ContextMixin(BaseModel):
    """Mixin class for context and config"""

    model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow")

    # Pydantic has bug on _private_attr when using inheritance, so we use private_* instead
    # - https://github.com/pydantic/pydantic/issues/7142
    # - https://github.com/pydantic/pydantic/issues/7083
    # - https://github.com/pydantic/pydantic/issues/7091

    # Env/Role/Action will use this context as private context, or use self.context as public context
    private_context: Optional[Context] = Field(default=None, exclude=True)
    # Env/Role/Action will use this config as private config, or use self.context.config as public config
    private_config: Optional[Config] = Field(default=None, exclude=True)

    # Env/Role/Action will use this llm as private llm, or use self.context._llm instance
    private_llm: Optional[BaseLLM] = Field(default=None, exclude=True)

    @model_validator(mode="after")
    def validate_context_mixin_extra(self):
        self._process_context_mixin_extra()
        return self

    def _process_context_mixin_extra(self):
        """Process the extra field"""
        kwargs = self.model_extra or {}
        self.set_context(kwargs.pop("context", None))
        self.set_config(kwargs.pop("config", None))
        self.set_llm(kwargs.pop("llm", None))

    def set(self, k, v, override=False):
        """Set attribute"""
        if override or not self.__dict__.get(k):
            self.__dict__[k] = v

    def set_context(self, context: Context, override=True):
        """Set context"""
        self.set("private_context", context, override)

    def set_config(self, config: Config, override=False):
        """Set config"""
        self.set("private_config", config, override)
        if config is not None:
            _ = self.llm  # init llm

    def set_llm(self, llm: BaseLLM, override=False):
        """Set llm"""
        self.set("private_llm", llm, override)

    @property
    def config(self) -> Config:
        """Role config: role config > context config"""
        if self.private_config:
            return self.private_config
        return self.context.config

    @config.setter
    def config(self, config: Config) -> None:
        """Set config"""
        self.set_config(config)

    @property
    def context(self) -> Context:
        """Role context: role context > context"""
        if self.private_context:
            return self.private_context
        return Context()

    @context.setter
    def context(self, context: Context) -> None:
        """Set context"""
        self.set_context(context)

    @property
    def llm(self) -> BaseLLM:
        """Role llm: if not existed, init from role.config"""
        # print(f"class:{self.__class__.__name__}({self.name}), llm: {self._llm}, llm_config: {self._llm_config}")
        if not self.private_llm:
            self.private_llm = self.context.llm_with_cost_manager_from_llm_config(self.config.llm)
        return self.private_llm

    @llm.setter
    def llm(self, llm: BaseLLM) -> None:
        """Set llm"""
        self.private_llm = llm

ContextMixin 通过 Pydantic 进行模型验证和数据管理,在处理任意字段时提供了灵活性。


测试 ContextMixin

示例:ModelX

为了演示 ContextMixin 的工作原理,我们创建了一个简单的模型 ModelX,继承自 ContextMixin, 验证 ModelX 能正确继承默认属性,同时保留 ContextMixin 的功能。

ContextMixin 可以无缝集成到多重继承的层次结构中,
ModelY 结合了 ContextMixinWTFMixin,继承了两者的字段和功能。

class ModelX(ContextMixin, BaseModel):
    a: str = "a"
    b: str = "b"

class WTFMixin(BaseModel):
    c: str = "c"
    d: str = "d"

class ModelY(WTFMixin, ModelX):
    pass

def test_config_mixin_1():
    new_model = ModelX()
    assert new_model.a == "a"
    assert new_model.b == "b"
test_config_mixin_1()
1. 配置优先级
from metagpt.configs.llm_config import LLMConfig

mock_llm_config = LLMConfig(
    llm_type="mock",
    api_key="mock_api_key",
    base_url="mock_base_url",
    app_id="mock_app_id",
    api_secret="mock_api_secret",
    domain="mock_domain",
)
mock_llm_config_proxy = LLMConfig(
    llm_type="mock",
    api_key="mock_api_key",
    base_url="mock_base_url",
    proxy="http://localhost:8080",
)

def test_config_mixin_2():
    i = Config(llm=mock_llm_config)
    j = Config(llm=mock_llm_config_proxy)
    obj = ModelX(config=i)
    assert obj.config == i
    assert obj.config.llm == mock_llm_config

    obj.set_config(j)
    # obj already has a config, so it will not be set
    assert obj.config == i
test_config_mixin_2()
2. 多继承
def test_config_mixin_3_multi_inheritance_not_override_config():
    """Test config mixin with multiple inheritance"""
    i = Config(llm=mock_llm_config)
    j = Config(llm=mock_llm_config_proxy)
    obj = ModelY(config=i)
    assert obj.config == i
    assert obj.config.llm == mock_llm_config

    obj.set_config(j)
    # obj already has a config, so it will not be set
    assert obj.config == i
    assert obj.config.llm == mock_llm_config

    assert obj.a == "a"
    assert obj.b == "b"
    assert obj.c == "c"
    assert obj.d == "d"

    print(obj.__dict__.keys())
    print(obj.__dict__)
    
    assert "private_config" in obj.__dict__.keys()

test_config_mixin_3_multi_inheritance_not_override_config()
dict_keys(['private_context', 'private_config', 'private_llm', 'a', 'b', 'c', 'd'])
{'private_context': None, 'private_config': Config(extra_fields=None, project_path='', project_name='', inc=False, reqa_file='', max_auto_summarize_code=0, git_reinit=False, llm=LLMConfig(extra_fields=None, api_key='mock_api_key', api_type=<LLMType.OPENAI: 'openai'>, base_url='mock_base_url', api_version=None, model=None, pricing_plan=None, access_key=None, secret_key=None, session_token=None, endpoint=None, app_id='mock_app_id', api_secret='mock_api_secret', domain='mock_domain', max_token=4096, temperature=0.0, top_p=1.0, top_k=0, repetition_penalty=1.0, stop=None, presence_penalty=0.0, frequency_penalty=0.0, best_of=None, n=None, stream=True, seed=None, logprobs=None, top_logprobs=None, timeout=600, context_length=None, region_name=None, proxy=None, calc_usage=True, use_system_prompt=True), embedding=EmbeddingConfig(extra_fields=None, api_type=None, api_key=None, base_url=None, api_version=None, model=None, embed_batch_size=None, dimensions=None), omniparse=OmniParseConfig(extra_fields=None, api_key='', base_url=''), proxy='', search=SearchConfig(extra_fields=None, api_type=<SearchEngineType.DUCK_DUCK_GO: 'ddg'>, api_key='', cse_id='', search_func=None, params={'engine': 'google', 'google_domain': 'google.com', 'gl': 'us', 'hl': 'en'}), browser=BrowserConfig(extra_fields=None, engine=<WebBrowserEngineType.PLAYWRIGHT: 'playwright'>, browser_type='chromium'), mermaid=MermaidConfig(extra_fields=None, engine='nodejs', path='mmdc', puppeteer_config='', pyppeteer_path='/usr/bin/google-chrome-stable'), s3=None, redis=None, repair_llm_output=False, prompt_schema='json', workspace=WorkspaceConfig(extra_fields=None, path=WindowsPath('d:/llm/metagpt/workspace'), use_uid=False, uid=''), enable_longterm_memory=False, code_review_k_times=2, agentops_api_key='', metagpt_tti_url='', language='English', redis_key='placeholder', iflytek_app_id='', iflytek_api_secret='', iflytek_api_key='', azure_tts_subscription_key='', azure_tts_region=''), 'private_llm': <metagpt.provider.openai_api.OpenAILLM object at 0x00000128F0753910>, 'a': 'a', 'b': 'b', 'c': 'c', 'd': 'd'}
3. 多继承重写
mock_llm_config_zhipu = LLMConfig(
    llm_type="zhipu",
    api_key="mock_api_key.zhipu",
    base_url="mock_base_url",
    model="mock_zhipu_model",
    proxy="http://localhost:8080",
)

def test_config_mixin_4_multi_inheritance_override_config():
    """Test config mixin with multiple inheritance"""
    i = Config(llm=mock_llm_config)
    j = Config(llm=mock_llm_config_zhipu)
    obj = ModelY(config=i)
    assert obj.config == i
    assert obj.config.llm == mock_llm_config

    obj.set_config(j, override=True)
    # override obj.config
    assert obj.config == j
    assert obj.config.llm == mock_llm_config_zhipu

    assert obj.a == "a"
    assert obj.b == "b"
    assert obj.c == "c"
    assert obj.d == "d"

    print(obj.__dict__.keys())
    assert "private_config" in obj.__dict__.keys()
    assert obj.config.llm.model == "mock_zhipu_model"
test_config_mixin_4_multi_inheritance_override_config()
dict_keys(['private_context', 'private_config', 'private_llm', 'a', 'b', 'c', 'd'])
4. 配置优先级
from pathlib import Path
import pytest
from metagpt.actions import Action
from metagpt.config2 import Config
from metagpt.const import CONFIG_ROOT
from metagpt.environment import Environment
from metagpt.roles import Role
from metagpt.team import Team

@pytest.mark.asyncio
async def test_config_priority():
    """If action's config is set, then its llm will be set, otherwise, it will use the role's llm"""
    home_dir = Path.home() / CONFIG_ROOT
    gpt4t = Config.from_home("gpt-4-turbo.yaml")
    if not home_dir.exists():
        assert gpt4t is None
    gpt35 = Config.default()
    gpt35.llm.model = "gpt35"
    gpt4 = Config.default()
    gpt4.llm.model = "gpt-4-0613"

    a1 = Action(name="Say", instruction="Say your opinion with emotion and don't repeat it", config=gpt4t)
    a2 = Action(name="Say", instruction="Say your opinion with emotion and don't repeat it")
    a3 = Action(name="Vote", instruction="Vote for the candidate, and say why you vote for him/her")

    # it will not work for a1 because the config is already set
    A = Role(name="A", profile="Democratic candidate", goal="Win the election", actions=[a1], watch=[a2], config=gpt4)
    # it will work for a2 because the config is not set
    B = Role(name="B", profile="Republican candidate", goal="Win the election", actions=[a2], watch=[a1], config=gpt4)
    # ditto
    C = Role(name="C", profile="Voter", goal="Vote for the candidate", actions=[a3], watch=[a1, a2], config=gpt35)

    env = Environment(desc="US election live broadcast")
    Team(investment=10.0, env=env, roles=[A, B, C])

    assert a1.llm.model == "gpt-4-turbo" if Path(home_dir / "gpt-4-turbo.yaml").exists() else "gpt-4-0613"
    assert a2.llm.model == "gpt-4-0613"
    assert a3.llm.model == "gpt35"

await test_config_priority()

如果有任何问题,欢迎在评论区提问。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2258695.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鲲鹏麒麟安装Kafka-v1.1.1

因项目需要在鲲鹏麒麟服务器上安装Kafka v1.1.1&#xff0c;因此这里将安装配置过程记录下来。 环境说明 # 查看系统相关详细信息 [roottest kafka_2.12-1.1.1]# uname -a Linux test.novalocal 4.19.148 #1 SMP Mon Oct 5 22:04:46 EDT 2020 aarch64 aarch64 aarch64 GNU/Li…

EFAK kafka可视化管理工具部署使用

简介&#xff1a;EFAK是开源的可视化和管理软件。它允许您查询、可视化、提醒和探索您的指标&#xff0c;无论它们存储在何处。简单来说&#xff0c;它为您提供了将 Kafka 集群数据转换为漂亮的图形和可视化效果的工具。 环境&#xff1a;①操作系统&#xff1a;CentOS7.6&…

YOLOv11改进,YOLOv11添加引入U-Netv2分割网络中SDI信息融合模块+GSConv卷积,助力小目标

# 理论介绍 完成本篇需要参考以下两篇文章,并已添加到YOLOv11代码中 YOLOv11改进,YOLOv11添加GSConv卷积+Slim-neck,助力小目标检测,二次创新C3k2结构YOLOv11改进,YOLOv11添加U-Netv2分割网络中SDI信息融合模块,助力小目标检测下文都是手把手教程,跟着操作即可添加成功…

Linux dd命令读写flash之误区

1. 问题 通常在Linux系统上需使用dd命令读写flash设备&#xff0c;个人最近调试了一款spi-nor flash芯片&#xff0c;分区分配了8MB大小的分区&#xff0c;是用dd命令验证读写flash时&#xff0c;出现校验失败。 使用如下命令读写8KB数据就会出现校验数据失败 time dd if/dev…

六、nginx负载均衡

负载均衡&#xff1a;将四层或者七层的请求分配到多台后端的服务器上。 从而分担整个业务的负载。提高系统的稳定性&#xff0c;也可以提高高可用&#xff08;备灾&#xff0c;其中一台后端服务器如果发生故障不影响整体业务&#xff09;. 负载均衡的算法 round robin 轮询 r…

Python使用Selenium库获取 网页节点元素、名称、内容的方法

我们要用到一些网页源码信息&#xff0c;例如获取一些节点的class内容&#xff0c; 除了使用Beautifulsoup来解析&#xff0c;还可以直接用Selenium库打印节点&#xff08;元素&#xff09;名称&#xff0c;用来获取元素的文本内容或者标签名。 例如获取下面的class的内容&am…

scala的泛型2

package test55 //隐式转换 //1.隐式函数 //2.隐式类 //3.隐式对象 //4.函数的隐式参数//泛型&#xff1a;类型参数化。 //Pair 约定一对数据 class Pair[T](var x:T, var y:T) //泛型的应用场景&#xff1a; //1.泛型函数 //2.泛型类 //3.泛型特质 object test2 {def main(arg…

服务器数据恢复—热备盘上线过程中硬盘离线导致raid5阵列崩溃的数据恢复案例

服务器数据恢复环境&#xff1a; 两组分别由4块SAS接口硬盘组建的raid5阵列&#xff0c;两组raid5阵列划分LUN并由LVM管理&#xff0c;格式化为EXT3文件系统。 服务器故障&#xff1a; RAID5阵列中一块硬盘未知原因离线&#xff0c;热备盘自动激活上线替换离线硬盘。在热备盘上…

基于Qwen2-VL模型针对LaTeX OCR任务进行微调训练 - 数据处理

基于Qwen2-VL模型针对LaTeX OCR任务进行微调训练 - 数据处理 flyfish 基于Qwen2-VL模型针对LaTeX_OCR任务进行微调训练_-_LoRA配置如何写 基于Qwen2-VL模型针对LaTeX_OCR任务进行微调训练_-_单图推理 基于Qwen2-VL模型针对LaTeX_OCR任务进行微调训练_-_原模型_单图推理 基于Q…

华为开源自研AI框架昇思MindSpore应用案例:基于MindSpore框架的SGD优化器案例实现

SGD优化器基本原理讲解 随机梯度下降&#xff08;SGD&#xff09;是一种迭代方法&#xff0c;其背后基本思想最早可以追溯到1950年代的Robbins-Monro算法&#xff0c;用于优化可微分目标函数。 它可以被视为梯度下降优化的随机近似&#xff0c;因为它用实际梯度&#xff08;从…

【C++】闰年判断问题完整解析与代码优化

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述&#x1f4af;我的解法分析 &#x1f4af;老师解法分析代码 1&#xff08;未优化版本&#xff09;分析 代码 2&#xff08;优化版本&#xff09;分析 &#x1f4af…

云和恩墨 zCloud 与华为云 GaussDB 完成兼容性互认证

近日&#xff0c;云和恩墨&#xff08;北京&#xff09;信息技术有限公司&#xff08;以下简称&#xff1a;云和恩墨&#xff09;的多元数据库智能管理平台 zCloud 与华为云计算技术有限公司&#xff08;以下简称&#xff1a;华为云&#xff09;的 GaussDB 数据库完成了兼容性互…

HtmlRAG开源,RAG系统联网搜索能力起飞~

网络是RAG系统中使用的主要外部知识来源&#xff0c;许多商业系统&#xff0c;如ChatGPT和Perplexity&#xff0c;都使用网络搜索引擎作为他们的主要检索系统。传统的RAG系统将网页的HTML内容转换为纯文本后输入LLM&#xff0c;这会导致结构和语义信息的丢失。 HTML转换为纯文…

Android显示系统(10)- SurfaceFlinger内部结构

一、前言&#xff1a; 之前讲述了native层如何使用SurfaceFlinger&#xff0c;我们只是看到了简单的API调用&#xff0c;从本文开始&#xff0c;我们逐步进行SurfaceFlinger内部结构的分析。话不多说&#xff0c;莱茨狗~ 二、类图&#xff1a; 2.1、总体架构&#xff1a; 先…

PPT技巧:将幻灯片里的图片背景设置为透明

在PPT中添加了图片&#xff0c;想要将图片中的背景设置为透明或者想要抠图&#xff0c;有什么方法吗&#xff1f;今天分享两个方法。 方法一&#xff1a; 添加图片&#xff0c;选中图片之后&#xff0c;点击【图片格式】功能&#xff0c;点击最左边的【删除背景】 PPT会自动帮…

以太网链路详情

文章目录 1、交换机1、常见的概念1、冲突域2、广播域3、以太网卡1、以太网卡帧 4、mac地址1、mac地址表示2、mac地址分类3、mac地址转换为二进制 2、交换机的工作原理1、mac地址表2、交换机三种数据帧处理行为3、为什么会泛洪4、转发5、丢弃 3、mac表怎么获得4、同网段数据通信…

CNCF云原生生态版图

CNCF云原生生态版图 概述什么是云原生生态版图如何使用生态版图 项目和产品&#xff08;Projects and products&#xff09;会员&#xff08;Members&#xff09;认证合作伙伴与提供商&#xff08;Certified partners and providers&#xff09;无服务&#xff08;Serverless&a…

每日计划-1212

1. 完成 SQL1 查询所有列 2. 八股部分 1) C 中多态性在实际项目中的应用场景有哪些&#xff1f; &#xff08;1&#xff09;图形绘制系统 场景描述&#xff1a;在一个图形绘制软件中&#xff0c;可能有多种图形&#xff0c;如圆形、矩形、三角形等。每种图形都需要有自己的…

Autosar CP RTE:一个例子简要介绍工作原理

以下是一个示例&#xff0c;展示如何通过AUTOSAR的RTE机制利用配置&#xff08;ARXML文件&#xff09;来实现软件组件集成&#xff0c;包含对应的C源代码以及模拟自动生成的RTE框架代码的示例。请注意&#xff0c;实际的AUTOSAR项目会复杂得多&#xff0c;这里只是一个简化且示…

动手学深度学习---预备知识

深度学习是关于优化的学习。对一个带有参数的模型&#xff0c;找到其中能拟合数据最好的模型。 一、数据操作 张量&#xff1a;表示一个由数值组成的数组&#xff0c;这个数组可能有多个维度。具有一个轴的张量对应数学上的向量&#xff0c;具有两个轴的张量对应数学上的矩阵&…