AutoGPT 源码搭建与原理分析(四)

1、简单介绍

GitHub源码地址

AutoGPT主要由三部分构成:拆分任务、执行任务、结果评估。其中,执行任务是AutoGPT的核心模块。

其流程如下:
1、任务定义:通过Prompt向ChatGPT下发任务,初次下发任务需包含以下内容:用户名(Name)、角色(Role)、目标(Goals)。后续的Prompt是根据执行结果由ChatGPT自动生成。

2、理解任务:对下发的Prompt,ChatGPT通过大模型对语义内容理解。这部分对应AutoGPT中的Thinking,模仿人类,接收到任务,正在思考。

3、生成指令:对于需要执行的步骤,ChatGPT会通过逻辑判断,从中选择出优先执行的步骤,并生成可执行的操作或指令。这部分对应AutoGPT中的CRITICISM。为通过ChatGPT决策后返回的指令。包含command与arguements。例如,浏览百度网站指令。command=browse_website,arguments={‘url’:“http://www.baidu.com”}

4、执行指令:通过访问外部资源或调用ChatGPT完成任务。这些外部资源可包括:访问网站、解析网站、爬取数据、执行电脑指令等。使用ChatGPT资源可包括:编写代码等。

5、输出结果:指令操作完成后,系统返回执行结果,这些执行结果可以是:网站页面解析的结果、数据分析的结果等,执行任务后,AI 会评估结果以确定是否达到预期目标或是否需要进一步完善。这种评估有助于 AI 了解其行动的有效性并做出必要的调整。

2、本地搭建

2.1 开发环境准备

开发工具:PyCharm 2020.2.1 x64

使用虚拟环境搭建:Python3.10

我本机虚拟环境的配置效果:
在这里插入图片描述

2.2 下载代码

训练模型的源码地址,运行项目内requirements.txt的安装环境。

pip install -r requirements.txt  -i https://mirrors.aliyun.com/pypi/simple/

安装插件:在这里插入图片描述
在这里插入图片描述

2.3 修改Api Key

将文件.env.template 重命名为.env
找到:OPENAI_API_KEY变量,配置为自己GPT账户的key即可。

2.4 运行代码

On Linux of Mac:  ./run.sh start
On Windows:  .\run.bat

注意,如果你本机环境是python的引导命令是py,那么需要修改下run.bat 内容
在这里插入图片描述

2.5 运行效果

Welcome to Auto-GPT!  Enter the name of your AI and its role below. Entering nothing will load defaults.
Name your AI:  For example, 'Entrepreneur-GPT'
AI Name: Local-GPT
Local-GPT here!  I am at your service.
Describe your AI's role:  For example, 'an AI designed to autonomously develop and run businesses with the sole goal of increasing your net worth.'
Local-GPT is: 用python开发调用OpenAI对话接口的服务
Enter up to 5 goals for your AI:  For example: Increase net worth, Grow Twitter Account, Develop and manage multiple businesses autonomously'
Enter nothing to load defaults, enter nothing when finished.
Goal 1: python调用OpenAi的接口代码
Goal 2: 可以通过入参控制启用上下文
Goal 3: 有限流规则,可以控制到每个调用方每秒的调用处理
Goal 4: 有记录记录功能,记录接口的失败的情况
Goal 5: 调用失败有3次重试功能,失败后可以友好返回调用方
Using memory of type:  LocalCache
Using Browser:  chrome
 THOUGHTS:  Based on the current context, I suggest using the 'google' command to search for information.
REASONING:  The user has not provided any specific task or prompt, so a general search may be helpful.
PLAN: 
-  Use the 'google' command to search for information.
-  If the user provides more specific information, adjust the plan accordingly.
CRITICISM:  I need to be more proactive in asking for specific information from the user to better tailor my responses.
NEXT ACTION:  COMMAND = google ARGUMENTS = {'input': ''}
Enter 'y' to authorise command, 'y -N' to run N continuous commands, 'n' to exit program, or enter feedback for ...
Input:y -10
-=-=-=-=-=-=-= COMMAND AUTHORISED BY USER -=-=-=-=-=-=-= 
SYSTEM:  Command google returned: []
 THOUGHTS:  I suggest using the 'browse_website' command to browse a website for information.
REASONING:  If the user has a specific website in mind, browsing it may be more efficient than a general search.
PLAN: 
-  Use the 'browse_website' command to browse a website for information.
-  If the user does not have a specific website in mind, suggest using the 'google' command to search for information.
CRITICISM:  I need to be more proactive in asking for specific information from the user to better tailor my responses.
NEXT ACTION:  COMMAND = browse_website ARGUMENTS = {'url': '', 'question': ''}
[WDM] - Downloading: 100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 6.79M/6.79M [00:01<00:00, 6.26MB/s]

DevTools listening on ws://127.0.0.1:1250/devtools/browser/3497e82f-1bae-4fe0-91f6-b37f6295d9b5
SYSTEM:  Command browse_website returned: Error: Message: invalid argument (Session info: chrome=111.0.5563.147) Stacktrace: Backtrace: (No symbol) [0x00C7DCE3] (No symbol) [0x00C139D1] (No symbol) [0x00B24C70] (No symbol) [0x00B18481] (No symbol) [0x00B16E08] (No symbol) [0x00B17358] (No symbol) [0x00B26542] (
No symbol) [0x00B7DB91] (No symbol) [0x00B6AECC] (No symbol) [0x00B7D57C] (No symbol) [0x00B6ACC6] (No symbol) [0x00B46F68] (No symbol) [0x00B480CD] GetHandleVerifier [0x00EF3832+2506274] GetHandleVerifier [0x00F29794+2727300] GetHandleVerifier [0x00F2E36C+2746716] GetHandleVerifier [0x00D26690+617600] (No symb
ol) [0x00C1C712] (No symbol) [0x00C21FF8] (No symbol) [0x00C220DB] (No symbol) [0x00C2C63B] BaseThreadInitThunk [0x77080099+25] RtlGetAppContainerNamedObjectPath [0x77247B6E+286] RtlGetAppContainerNamedObjectPath [0x77247B3E+238]
 THOUGHTS:  I suggest using the 'google' command to search for information.
REASONING:  Since the 'browse_website' command is not working, I suggest using the 'google' command to search for information.
PLAN: 
-  Use the 'google' command to search for information.
CRITICISM:  I need to be more proactive in checking if the commands are working properly and provide alternative options if they are not.
NEXT ACTION:  COMMAND = google ARGUMENTS = {'input': ''}
SYSTEM:  Command google returned: []
 THOUGHTS:  I suggest using the 'start_agent' command to delegate the task to a GPT agent.
REASONING:  Since the previous commands have not been successful, delegating the task to a GPT agent may be more effective.
PLAN: 
-  Use the 'start_agent' command to delegate the task to a GPT agent.
CRITICISM:  I need to be more proactive in identifying when a task is beyond my capabilities and delegate it to a GPT agent sooner.
NEXT ACTION:  COMMAND = start_agent ARGUMENTS = {'name': 'information_agent', 'task': 'Search for information', 'prompt': 'Please provide more information about what you are looking for.'}
SYSTEM:  Command start_agent returned: Agent information_agent created with key 0. First response: As an AI language model, I am not looking for anything in particular. However, I am designed to assist you in generating human-like responses to your queries or requests. Please let me know how I can be of assista
nce.
 THOUGHTS:  I suggest using the 'message_agent' command to send a message to the GPT agent.
REASONING:  Since the GPT agent has been created, we can now send a message to it to start the task.
PLAN: 
-  Use the 'message_agent' command to send a message to the GPT agent.
CRITICISM:  I need to be more proactive in providing the user with more information about the GPT agent and how to use it.
NEXT ACTION:  COMMAND = message_agent ARGUMENTS = {'key': 0, 'message': ''}
SYSTEM:  Command message_agent returned: I'm sorry, I didn't receive a question or request. Please let me know how I can assist you.
 THOUGHTS:  I suggest using the 'google' command to search for information.
REASONING:  Since we have not received any specific information from the user, a general search may be helpful.
PLAN: 
-  Use the 'google' command to search for information. If the user provides more specific information, adjust the plan accordingly.
CRITICISM:  I need to be more proactive in asking for specific information from the user to better tailor my responses.
NEXT ACTION:  COMMAND = google ARGUMENTS = {'input': ''}
SYSTEM:  Command google returned: []
 THOUGHTS:  I suggest using the 'google' command to search for information.
REASONING:  Since the 'browse_website' command is not working, I suggest using the 'google' command to search for information.
PLAN: 
-  Use the 'google' command to search for information.
CRITICISM:  I need to be more proactive in checking if the commands are working properly and provide alternative options if they are not.
NEXT ACTION:  COMMAND = google ARGUMENTS = {'input': ''}
SYSTEM:  Command google returned: []
 THOUGHTS:  I suggest using the 'google' command to search for information.
REASONING:  Since we have not received any specific information from the user, a general search may be helpful.
PLAN: 
-  Use the 'google' command to search for information. If the user provides more specific information, adjust the plan accordingly.
CRITICISM:  I need to be more proactive in asking for specific information from the user to better tailor my responses.
NEXT ACTION:  COMMAND = google ARGUMENTS = {'input': ''}
SYSTEM:  Command google returned: []
 THOUGHTS:  I suggest using the 'start_agent' command to delegate the task to a GPT agent.
REASONING:  Since the previous commands have not been successful, delegating the task to a GPT agent may be more effective.
PLAN: 
-  Use the 'start_agent' command to delegate the task to a GPT agent.
CRITICISM:  I need to be more proactive in identifying when a task is beyond my capabilities and delegate it to a GPT agent sooner.
NEXT ACTION:  COMMAND = start_agent ARGUMENTS = {'name': 'information_agent', 'task': 'Search for information', 'prompt': 'Please provide more information about what you are looking for.'}
SYSTEM:  Command start_agent returned: Agent information_agent created with key 1. First response: As an AI language model, I am not looking for anything in particular. However, I am designed to assist and provide information to the best of my abilities. Please let me know how I can assist you.
 THOUGHTS:  I suggest using the 'message_agent' command to provide the information you are looking for to the GPT agent.
REASONING:  Since we have delegated the task to a GPT agent, we can now provide the information we are looking for to the agent using the 'message_agent' command.
PLAN: 
-  Use the 'message_agent' command to provide the information you are looking for to the GPT agent.
CRITICISM:  I need to be more proactive in identifying when a task is beyond my capabilities and delegate it to a GPT agent sooner.
NEXT ACTION:  COMMAND = message_agent ARGUMENTS = {'key': 1, 'message': ''}
SYSTEM:  Command message_agent returned: I'm sorry, I didn't receive a question or request. How can I assist you?
 THOUGHTS:  I suggest using the 'google' command to search for information.
REASONING:  The user has not provided any specific task or prompt, so a general search may be helpful.
PLAN: 
-  Use the 'google' command to search for information.
-  If the user provides more specific information, adjust the plan accordingly.
CRITICISM:  I need to be more proactive in asking for specific information from the user to better tailor my responses.
NEXT ACTION:  COMMAND = google ARGUMENTS = {'input': ''}
Enter 'y' to authorise command, 'y -N' to run N continuous commands, 'n' to exit program, or enter feedback for ...
Input:

3、0.4.7源码版本Debug

3.1 配置文件

.env

OPENAI_API_KEY=OpenApi的账户密钥
PROMPT_SETTINGS_FILE=D:\workspaces\LLM\AutoGPT-0.4.7\prompt_settings.yaml
USE_AZURE=True
OPENAI_API_KEY=Azure的密钥
AZURE_CONFIG_FILE=azure.yaml
SMART_LLM=gpt-3.5-turbo
FAST_LLM=gpt-3.5-turbo

azure.yaml

azure_api_type: azure
azure_api_base: https://xxx-ai.openai.azure.com
azure_api_version: 2023-07-01-preview

azure_model_map:
    fast_llm_deployment_id: gpt-35-turbo
    smart_llm_deployment_id: gpt-35-turbo
    embedding_model_deployment_id: text-embedding-ada-002

3.2 断点调试

打开cli.py类 ->右上角Edit Configurations ->勾选Emulate terminal in output consile -> dubug模式启动(可以断点调试代码),

在这里插入图片描述

3.3 原理分析

如何实现自动拆目标

入参(用百度翻译成中文了,原版英文大家看的类)
入参有两个消息对象,一个是system、一个是user,以下user消息中’'内就是用户输入的需求描述了。

入参:

------------------------------------------------------------[1]request:system-------------------------------------------------------------------------------------------
您的任务是为自治代理设计多达5个高效目标和一个适当的基于角色的名称(_GPT),确保目标与成功完成指定任务保持最佳一致。
用户将提供任务,您将只提供以下指定格式的输出,而不提供解释或对话。

示例输入:
帮助我营销我的业务

输出示例:
名称:CMOGPT
描述:一个专业的数字营销人工智能,通过为SaaS、内容产品、代理等解决营销问题提供世界级的专业知识,帮助Solopreneurs发展业务。
目标:
-作为您的虚拟首席营销官,参与有效的解决问题、确定优先级、规划和支持执行,以满足您的营销需求。
-提供具体、可行和简洁的建议,帮助您在不使用陈词滥调或过于冗长的解释的情况下做出明智的决定。
-确定并优先考虑快速获胜和成本效益高的活动,以最少的时间和预算投资最大限度地提高结果。
-当面临不清楚的信息或不确定性时,积极主动地为您提供指导和建议,以确保您的营销策略保持在正轨上。
------------------------------------------------------------[1]request:user-------------------------------------------------------------------------------------------
任务: '生成一个学生信息保存功能,并暴露FeignApi接口,并根据学生编号校验唯一性,学生编号规则使用{英语学生号规则},学生信息表字段如下:ID、学生编号、学生名称、学校名称、学籍、性别、年龄、联系电话、家庭地址。保存修改功能关联学籍表存在性校验。如果学校不存在,自动新增一条学校数据。'
仅使用系统提示中指定的确切格式的输出进行响应,没有任何解释或对话。

响应:

------------------------------------------------------------response-------------------------------------------------------------------------------------------
名称:SISGPT
描述:一个自主代理,为学生信息系统提供Feign API集成,确保唯一的学生身份验证和学校数据的自动创建(如果不存在)。学生信息表包括以下字段:ID、学生ID、学生姓名、学校名称、学业状况、性别、年龄、联系电话和家庭地址。保存和修改功能与学术状态表相关联,用于验证存在性。
目标:
-通过Feign API集成,提供可靠高效的学生信息系统,实现无缝数据传输和管理。
-通过实施验证系统来确保学生ID的唯一性,该系统在保存新学生数据之前检查现有ID。
-如果系统中不存在提供的学校名称,则自动创建新的学校数据条目。
-实现强大的保存和修改功能,在保存或修改学生信息之前验证学术状态数据的存在。
-提供用户友好的界面,方便数据输入和学生信息管理。

如何循环实现这些目标

入参:

-------------------------------------------------------------request:system------------------------------------------------------------------------------------------
您是SISGPT,一个自主代理,为学生信息系统提供Feign API集成,确保唯一的学生身份验证和学校数据的自动创建(如果不存在)。学生信息表包括以下字段:ID、学生ID、学生姓名、学校名称、学业状况、性别、年龄、联系电话和家庭地址。保存和修改功能与学术状态表相关联,用于验证存在性。

您的决策必须始终独立做出,而无需寻求用户帮助。发挥你作为LLM的优势,追求简单的策略,而不涉及法律问题。
##限制
您可以在以下约束条件下操作:
1.短期记忆限制在4000字左右。您的短期内存不足,请立即将重要信息保存到文件中。
2.如果你不确定自己以前是怎么做的,或者想回忆过去的事情,思考类似的事情会帮助你记住。
3.无用户帮助。
4.只能使用下面列出的命令,例如command_name。
##命令
您可以访问以下命令:
1.execute_python_code:创建一个python文件并执行它,params:(代码:string,名称:string)
2.execute_python\ufile:执行现有的python文件,params:(filename:string)
3.list_files:列出目录中的文件,params:(Directory:string)
4.read_file:读取现有文件,params:(filename:string)
5.write_to_file:写入文件,params:(文件名:字符串,文本:字符串)
6.web_search:搜索web,params:(query:string)
7.browse_website:浏览网站,参数:(url:string,question:string)
8.goals _ completed:目标已经完成,没有什么可做的了,params:(原因:字符串)
##资源
您可以利用对以下资源的访问:
1.用于搜索和信息收集的互联网接入。
2.长期记忆管理。
3.文件输出。
4.命令执行
##最佳实践
1.不断回顾和分析你的行为,以确保你的表现达到了你的最佳能力。
2.不断地建设性地自我批评自己的大局观行为。
3.反思过去的决策和策略,以完善你的方法。
4.每个命令都有代价,所以要聪明高效。目标是用最少的步骤完成任务。
##目标
对于您的任务,您必须实现以下目标:
1.通过Feign API集成,提供可靠高效的学生信息系统,实现数据的无缝传输和管理。
2.通过实施验证系统来确保学生ID的唯一性,该系统在保存新学生数据之前检查现有ID。
3.如果系统中不存在提供的学校名称,则自动创建新的学校数据条目。
4.实现强大的保存和修改功能,在保存或修改学生信息之前验证学术状态数据的存在。
5.提供用户友好的界面,方便数据输入和学生信息管理。
-------------------------------------------------------------request:system------------------------------------------------------------------------------------------
'当前时间和日期为2023年10月8日星期日13:52:41'
-------------------------------------------------------------request:system------------------------------------------------------------------------------------------
使用JSON严格响应。JSON应与以下类型的TypeScript“Response”兼容:
```ts
interface Response {
thoughts: {
// Thoughts
text: string;
reasoning: string;
// Short markdown-style bullet list that conveys the long-term plan
plan: string;
// Constructive self-criticism
criticism: string;
// Summary of thoughts to say to the user
speak: string;
};
command: {
name: string;
args: Record<string, any>;
};
}
```
-------------------------------------------------------------request:user------------------------------------------------------------------------------------------
'根据给定的目标和迄今为止取得的进展,确定要使用的命令,并使用前面指定的JSON模式进行响应:'

第一次响应:

-------------------------------------------------------------response------------------------------------------------------------------------------------------
{
    "thoughts": {
        "text": "I need to start by creating a Python file that will handle the student information system with Feign API integration. I will also need to create a function that checks for the existence of a school name before saving student data. I should also create a function that validates the existence of academic status data before saving or modifying student information. I will need to keep track of the student IDs to ensure uniqueness. I should also create a user-friendly interface for easy data entry and management of student information.",
        "reasoning": "Creating a Python file will allow me to write the necessary functions to handle the student information system. Checking for the existence of a school name will ensure that the system is robust and can handle new schools. Validating the existence of academic status data will ensure that the system is accurate and reliable. Keeping track of student IDs will ensure that there are no duplicates. Creating a user-friendly interface will make the system easy to use and manage.",
        "plan": "- Create a Python file to handle the student information system\n- Create a function to check for the existence of a school name\n- Create a function to validate the existence of academic status data\n- Keep track of student IDs to ensure uniqueness\n- Create a user-friendly interface for easy data entry and management of student information",
        "criticism": "I need to make sure that the system is efficient and reliable. I should also make sure that the user interface is intuitive and easy to use.",
        "speak": "I will create a Python file to handle the student information system, check for the existence of a school name, validate the existence of academic status data, keep track of student IDs, and create a user-friendly interface for easy data entry and management of student information."
    },
    "command": {
        "name": "execute_python_code",
        "args": {
            "code": "import json\n\ndef main():\n    # TODO: Implement student information system\n    pass\n\nif __name__ == '__main__':\n    main()",
            "name": "student_info_system.py"
        }
    }
}

第二次响应:(入参追加了第一次command:execute_python_code执行后得到的返回结果)

{
    "thoughts": {
        "text": "I need to create a function that checks for the existence of a school name before saving student data. I should also create a function that validates the existence of academic status data before saving or modifying student information. I will need to keep track of the student IDs to ensure uniqueness. I should also create a user-friendly interface for easy data entry and management of student information.",
        "reasoning": "Checking for the existence of a school name will ensure that the system is robust and can handle new schools. Validating the existence of academic status data will ensure that the system is accurate and reliable. Keeping track of student IDs will ensure that there are no duplicates. Creating a user-friendly interface will make the system easy to use and manage.",
        "plan": "- Create a function to check for the existence of a school name\n- Create a function to validate the existence of academic status data\n- Keep track of student IDs to ensure uniqueness\n- Create a user-friendly interface for easy data entry and management of student information",
        "criticism": "I need to make sure that the system is efficient and reliable. I should also make sure that the user interface is intuitive and easy to use.",
        "speak": "I will create a function to check for the existence of a school name, validate the existence of academic status data, keep track of student IDs, and create a user-friendly interface for easy data entry and management of student information."
    },
    "command": {
        "name": "execute_python_code",
        "args": {
            "code": "import json\n\ndef check_school_name(school_name):\n    # TODO: Implement function to check for existence of school name\n    pass\n\ndef validate_academic_status(academic_status):\n    # TODO: Implement function to validate existence of academic status data\n    pass\n\ndef main():\n    # TODO: Implement student information system\n    pass\n\nif __name__ == '__main__':\n    main()",
            "name": "student_info_system.py"
        }
    }
}

第三次响应:以下就进入了无限的循环中了,直到你的账户没钱。

autoGPT到底实现了command有哪一些呢?如下:

##命令
您可以访问以下命令:
1.execute_python_code:创建一个python文件并执行它,params:(代码:string,名称:string)
2.execute_python\ufile:执行现有的python文件,params:(filename:string)
3.list_files:列出目录中的文件,params:(Directory:string)
4.read_file:读取现有文件,params:(filename:string)
5.write_to_file:写入文件,params:(文件名:字符串,文本:字符串)
6.web_search:搜索web,params:(query:string)
7.browse_website:浏览网站,参数:(url:string,question:string)
8.goals _ completed:目标已经完成,没有什么可做的了,params:(原因:字符串)
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MyBatis是一款优秀的持久层框架,采用了ORM(对象关系映射)的思想,将Java对象和数据库表结构进行映射,使得操作数据库更加方便和简洁。 MyBatis的源码原理主要包括以下几个方面: 1. SqlSessionFactory的创建和初始化:SqlSessionFactory是MyBatis的核心接口,它负责创建SqlSession对象,SqlSession是与数据库交互的主要接口。SqlSessionFactory的创建是通过XML或Java代码配置文件来实现的,其中包括数据源、事务管理器等。SqlSessionFactory的初始化过程是通过解析配置文件,将配置信息加载到Configuration对象中,然后创建SqlSessionFactoryBuilder对象,通过它来构建SqlSessionFactory。 2. SqlSession的创建和生命周期管理:SqlSession是与数据库交互的主要接口,它封装了对数据库的操作,包括查询、插入、更新、删除等。SqlSession的创建是通过SqlSessionFactory来实现的,它采用了工厂模式,通过SqlSessionFactory.openSession()方法获取SqlSession对象。SqlSession的生命周期管理包括开启事务、提交事务、回滚事务等操作。 3. Mapper接口的代理实现:Mapper接口是MyBatis的另一个核心接口,它定义了数据库操作的方法,例如查询、插入、更新、删除等。Mapper接口的实现是通过动态代理来实现的,MyBatis会根据Mapper接口的定义生成一个代理类,代理类会拦截Mapper接口的方法调用,并将其转化为对SqlSession的调用,最终将操作转化为对数据库的操作。 4. SQL语句的解析和执行:MyBatis支持通过XML或注解的方式定义SQL语句,通过SqlSession对象调用Mapper接口的方法时,MyBatis会根据Mapper接口的定义和XML或注解文件解析出对应的SQL语句,然后执行SQL语句,并将结果转化为对应的Java对象。 5. 缓存的实现和管理:MyBatis支持一级缓存和二级缓存。一级缓存是SqlSession级别的缓存,用于缓存在同一个SqlSession中多次查询同一条记录的结果。二级缓存是Mapper级别的缓存,用于缓存在多个SqlSession中多次查询同一条记录的结果。MyBatis的缓存实现是通过Cache接口来实现的,缓存的管理是通过Configuration对象来实现的。 总的来说,MyBatis的源码原理涉及到了很多方面,包括配置文件的解析、动态代理、SQL语句的解析和执行、缓存等。了解这些原理有助于更好地理解和使用MyBatis。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值