972 lines
46 KiB
Markdown
972 lines
46 KiB
Markdown
请给我详细介绍一下AutoGen架构,我想充分了解后,运行一个测试用例。
|
||
|
||
|
||
|
||
好的,我们来详细地拆解和介绍 AutoGen 框架,并一步步带你运行一个经典的测试用例。
|
||
|
||
### AutoGen 架构详解
|
||
|
||
AutoGen 是由微软开发的一个开源框架,旨在简化和赋能基于大型语言模型(LLM)的多代理(Multi-Agent)应用程序的开发。它的核心思想是:**通过让多个具有不同角色和能力的“代理(Agent)”相互对话和协作,来完成复杂的任务。**
|
||
|
||
想象一下一个项目团队:有项目经理(负责规划)、程序员(负责写代码)、测试员(负责验证代码)、产品经理(负责提需求)。AutoGen 就是让你用代码来定义这些角色(Agent),并让他们自动开会、讨论、执行,最终完成你交待的任务。
|
||
|
||
---
|
||
|
||
#### 1. 核心概念与组件
|
||
|
||
AutoGen 的架构主要由以下几个核心组件构成:
|
||
|
||
##### a. 代理(Agents)
|
||
|
||
Agent 是 AutoGen 的基本执行单元。每个 Agent 都有一个角色,并能执行某些操作,如与人交互、编写代码、执行代码、调用 LLM 等。最核心和最常用的两种 Agent 是:
|
||
|
||
* **`AssistantAgent` (助理代理)**
|
||
* **角色**: 这是一个纯粹的 LLM 驱动的代理。你可以把它想象成“大脑”或“规划者”。
|
||
* **能力**:
|
||
* 根据对话历史和收到的消息,调用 LLM 生成回复。
|
||
* 可以提出计划、编写代码片段、撰写文章、回答问题等。
|
||
* **特点**: 它**不会**自己执行代码。它只会生成代码并建议让别人(通常是 `UserProxyAgent`)去执行。
|
||
|
||
* **`UserProxyAgent` (用户代理代理)**
|
||
* **角色**: 它是人类用户的“替身”或“执行者”。你可以把它想象成“双手”或“执行终端”。
|
||
* **能力**:
|
||
1. **征求人类输入**: 可以在关键节点暂停,询问人类用户的意见或下一步指示。
|
||
2. **执行代码**: 这是它最强大的能力。当 `AssistantAgent` 提供一段代码后,`UserProxyAgent` 可以在本地环境中执行这段代码(Python、Shell 等)。
|
||
3. **提供反馈**: 执行代码后,它会将执行结果(成功、失败、输出信息、错误日志)作为消息再发回给 `AssistantAgent`,形成一个闭环。
|
||
* **特点**: 它充当了 LLM 世界和真实世界(代码执行环境、文件系统)之间的桥梁。
|
||
|
||
##### b. 对话与通信模式
|
||
|
||
AutoGen 的核心驱动力是 Agent 之间的自动化对话。
|
||
|
||
* **发起对话**: 通常由一个 Agent(如 `UserProxyAgent`)通过调用 `.initiate_chat()` 方法来发起与另一个 Agent 的对话,并给出初始任务。
|
||
* **轮流发言**: 一旦对话开始,两个(或多个)Agent 会根据预设的规则轮流发言。例如,`UserProxyAgent` 提出问题 -> `AssistantAgent` 回答并提供代码 -> `UserProxyAgent` 执行代码并返回结果 -> `AssistantAgent` 根据结果修正代码或进行下一步... 如此循环。
|
||
* **消息传递**: Agent 之间通过传递结构化的消息(通常是包含 `content` 和 `role` 的字典)来进行通信。
|
||
* **终止条件**: 对话会在满足特定条件时结束,例如:
|
||
* 任务完成(`AssistantAgent` 输出了 `TERMINATE` 信号)。
|
||
* 达到了最大对话轮次。
|
||
* `UserProxyAgent` 在需要人类输入时,人类输入了 `exit`。
|
||
|
||
##### c. LLM 配置 (`llm_config`)
|
||
|
||
所有依赖 LLM 的 Agent(如 `AssistantAgent`)都需要一个 `llm_config` 来告诉它们如何与 LLM 服务(如 OpenAI, Azure OpenAI)进行通信。这通常包括:
|
||
|
||
* **`config_list`**: 一个包含一个或多个 LLM 服务配置的列表。每个配置指定了模型名称(如 `gpt-4`)、API 密钥等。这使得 AutoGen 可以轻松地在多个模型或备用服务之间切换。
|
||
* **`temperature`**: 控制 LLM 输出的随机性。
|
||
* **`timeout`**: 请求超时时间。
|
||
* **`cache_seed`**: 用于缓存和复现结果。
|
||
|
||
---
|
||
|
||
#### 2. AutoGen 的工作流(以双代理为例)
|
||
|
||
下面是一个经典的工作流程图,展示了 `AssistantAgent` 和 `UserProxyAgent` 是如何协作的:
|
||
|
||
```
|
||
+------------------+ +-------------------+
|
||
| UserProxyAgent | | AssistantAgent |
|
||
| (执行者/用户替身) | | (规划者/思考者) |
|
||
+------------------+ +-------------------+
|
||
| |
|
||
| 1. 发起任务: |
|
||
| "请画出NVDA和TSLA的股价图" |
|
||
'----------------------------->'
|
||
|
|
||
| 2. 思考并调用LLM
|
||
| 生成Python代码
|
||
| (需要 yfinance, matplotlib)
|
||
|
|
||
.----------------------------< '
|
||
| 3. 收到代码建议: |
|
||
| "```python |
|
||
| import yfinance as yf |
|
||
| ... |
|
||
| plt.savefig('stock.png') |
|
||
| ```" |
|
||
| |
|
||
+------------------+ |
|
||
| 本地代码执行环境 | |
|
||
+------------------+ |
|
||
^ |
|
||
| 4. 执行代码 |
|
||
| (安装库, 运行脚本) |
|
||
| |
|
||
| 5. 返回执行结果: |
|
||
| "代码已成功执行, |
|
||
| 图片已保存为 stock.png" |
|
||
'----------------------------->'
|
||
|
|
||
| 6. 收到成功反馈
|
||
| 判断任务已完成
|
||
| 回复 "TERMINATE"
|
||
|
|
||
.----------------------------< '
|
||
| 7. 收到 "TERMINATE" |
|
||
| 对话结束 |
|
||
| |
|
||
```
|
||
|
||
---
|
||
|
||
### 测试用例:绘制股价图并保存
|
||
|
||
现在,让我们通过一个实际的例子来体验 AutoGen 的威力。
|
||
|
||
**任务**: 让 AutoGen 自动编写并执行 Python 代码,获取英伟达(NVDA)和特斯拉(TSLA)过去一年的股价,绘制在一张图上,并将图片保存为文件。
|
||
|
||
#### 第1步: 环境准备
|
||
|
||
1. **安装 AutoGen 和依赖库**:
|
||
这个任务需要访问网络获取股价(`yfinance`)和绘图(`matplotlib`)。我们可以让 AutoGen 自己安装,但为了确保环境干净,建议手动安装。
|
||
|
||
```bash
|
||
pip install "pyautogen>=0.2.0" yfinance matplotlib
|
||
```
|
||
|
||
2. **获取 LLM API 密钥**:
|
||
你需要一个大语言模型的 API 访问权限。最常用的是 OpenAI。
|
||
* 前往 [OpenAI platform](https://platform.openai.com/account/api-keys) 获取你的 API Key。
|
||
|
||
3. **配置 API 密钥**:
|
||
**强烈推荐**使用环境变量或配置文件,而不是将密钥硬编码在代码里。AutoGen 推荐的方式是创建一个 `OAI_CONFIG_LIST` 文件。
|
||
|
||
* 在你的项目根目录下,创建一个名为 `OAI_CONFIG_LIST` 的 JSON 文件。
|
||
* 在文件中填入以下内容,并将 `"your_openai_api_key"` 替换为你的真实密钥。
|
||
|
||
```json
|
||
[
|
||
{
|
||
"model": "gpt-4",
|
||
"api_key": "your_openai_api_key"
|
||
}
|
||
]
|
||
```
|
||
*你也可以使用 `gpt-3.5-turbo`,速度更快成本更低,但对于复杂任务 `gpt-4` 效果更好。*
|
||
|
||
#### 第2步: 编写 Python 脚本
|
||
|
||
创建一个名为 `run_autogen_stock_plot.py` 的 Python 文件,并粘贴以下代码:
|
||
|
||
```python
|
||
import autogen
|
||
|
||
# 1. 加载 LLM 配置
|
||
# AutoGen 会自动寻找 OAI_CONFIG_LIST 文件或同名环境变量
|
||
config_list = autogen.config_list_from_json(
|
||
"OAI_CONFIG_LIST",
|
||
filter_dict={
|
||
"model": ["gpt-4"] # 你可以指定想用的模型,例如 "gpt-4" 或 "gpt-3.5-turbo"
|
||
}
|
||
)
|
||
|
||
# 2. 创建 LLM 配置字典
|
||
llm_config = {
|
||
"config_list": config_list,
|
||
"temperature": 0, # 温度设为0,让输出更具确定性
|
||
"cache_seed": 42, # 使用缓存种子,对于相同问题可以复用结果,节省token
|
||
}
|
||
|
||
# 3. 创建 AssistantAgent (助理代理/规划者)
|
||
assistant = autogen.AssistantAgent(
|
||
name="assistant",
|
||
llm_config=llm_config,
|
||
system_message="你是一个乐于助人的AI助手,擅长编写Python代码来解决问题。当你认为任务完成时,请只回复'TERMINATE'。"
|
||
)
|
||
|
||
# 4. 创建 UserProxyAgent (用户代理代理/执行者)
|
||
user_proxy = autogen.UserProxyAgent(
|
||
name="user_proxy",
|
||
human_input_mode="NEVER", # NEVER: 完全不需人类干预。TERMINATE: 在任务结束或需要帮助时暂停。ALWAYS: 每一步都需人类确认。
|
||
max_consecutive_auto_reply=10, # 限制连续自动回复的次数,防止无限循环
|
||
is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("TERMINATE"),
|
||
code_execution_config={
|
||
"work_dir": "coding", # 代码将在这个文件夹中执行
|
||
"use_docker": False, # 设为False,直接在本地环境执行。如果你安装了Docker,建议设为True,更安全。
|
||
},
|
||
)
|
||
|
||
# 5. 发起对话
|
||
task_prompt = "获取英伟达(NVDA)和特斯拉(TSLA)从2023年1月1日至今的每日收盘价,并用一张图表绘制出来,将图表保存为 'stock_price_chart.png'。"
|
||
|
||
user_proxy.initiate_chat(
|
||
assistant,
|
||
message=task_prompt
|
||
)
|
||
```
|
||
|
||
#### 第3步: 运行脚本
|
||
|
||
1. 确保你的目录结构如下:
|
||
```
|
||
.
|
||
├── OAI_CONFIG_LIST
|
||
└── run_autogen_stock_plot.py
|
||
```
|
||
|
||
2. 在终端中运行脚本:
|
||
```bash
|
||
python run_autogen_stock_plot.py
|
||
```
|
||
|
||
#### 第4步: 观察输出并检查结果
|
||
|
||
当你运行脚本后,你会在终端看到 `assistant` 和 `user_proxy` 之间非常详细的对话过程。你会看到类似下面的流程:
|
||
|
||
1. **`user_proxy`** 向 **`assistant`** 发送了初始任务。
|
||
2. **`assistant`** 回复说:“好的,我需要使用 `yfinance` 库来获取股价,用 `matplotlib` 来绘图。这是代码:” 然后提供了一段 Python 代码。
|
||
3. **`user_proxy`** 收到代码,回复:“正在执行代码...”,然后它会尝试运行。
|
||
4. **第一次执行可能会失败!** 因为 `yfinance` 或 `matplotlib` 可能没安装。`user_proxy` 会把 `ModuleNotFoundError` 的错误信息返回给 `assistant`。
|
||
5. **`assistant`** 看到错误后,会智能地回复:“哦,看起来是缺少了必要的库。请先执行这个 Shell 命令来安装它们:” 然后提供 `pip install yfinance matplotlib` 的命令。
|
||
6. **`user_proxy`** 收到 Shell 命令,执行它,然后返回成功信息。
|
||
7. **`assistant`** 再次提供最初的 Python 绘图代码。
|
||
8. **`user_proxy`** 再次执行代码,这次成功了。它会返回执行成功的信息,比如 "代码已执行,没有输出"。
|
||
9. **`assistant`** 看到代码成功执行,认为任务已经完成,于是回复 `TERMINATE`。
|
||
10. **`user_proxy`** 收到 `TERMINATE`,对话结束。
|
||
|
||
**最终结果**:
|
||
在你的项目目录下,会多出一个名为 `coding` 的文件夹。在这个文件夹里,你会找到一张名为 `stock_price_chart.png` 的图片,上面绘制了两只股票的股价走势图。
|
||
|
||
这个例子完美地展示了 AutoGen 的核心价值:**通过代理间的对话、代码生成、执行和反馈循环,自动化地解决需要多个步骤和工具协作才能完成的复杂任务。**
|
||
|
||
现在你已经对 AutoGen 的架构有了深入的了解,并成功运行了一个测试用例。接下来,你可以尝试修改任务(比如分析其他数据、操作文件等)或者探索更复杂的 `GroupChat` 模式来构建更强大的应用。
|
||
|
||
|
||
如何在autogen中使用deepseek?
|
||
|
||
|
||
|
||
当然可以!在 AutoGen 中使用 DeepSeek 模型非常简单,因为它也提供了与 OpenAI API 兼容的接口。这意味着你基本上只需要更改配置,而不需要修改代理(Agent)的代码。
|
||
|
||
下面是详细的步骤和解释,我们依然以上一个“绘制股价图”的例子为基础进行修改。
|
||
|
||
### 核心原理:利用 OpenAI 兼容的 API
|
||
|
||
许多 LLM 提供商(包括 DeepSeek, Groq, Together.ai 等)为了方便开发者迁移,都提供了一个遵循 OpenAI API 规范的端点(Endpoint)。
|
||
|
||
AutoGen 的 `AssistantAgent` 在设计上就是通过一个可配置的 `llm_config` 来与 LLM 通信的。这个配置中除了 `api_key` 和 `model`,还有一个关键参数:`base_url` (或 `api_base`)。
|
||
|
||
我们只需要将这个 `base_url` 指向 DeepSeek 的 API 服务器地址,AutoGen 就会把原本要发给 OpenAI 的请求,转而发给 DeepSeek。
|
||
|
||
---
|
||
|
||
### 步骤一:获取 DeepSeek API 密钥
|
||
|
||
1. 访问 [DeepSeek 开放平台](https://platform.deepseek.com/)。
|
||
2. 注册并登录你的账户。
|
||
3. 在“API 密钥” (API Keys) 页面创建一个新的密钥并复制它。请妥善保管。
|
||
|
||
### 步骤二:准备新的配置文件
|
||
|
||
为了保持清晰,我们不修改原来的 `OAI_CONFIG_LIST` 文件,而是创建一个新的配置文件专门用于 DeepSeek。
|
||
|
||
1. 在你的项目根目录下,创建一个名为 `OAI_CONFIG_LIST_DEEPSEEK.json` 的新文件。
|
||
2. 在文件中填入以下内容,并将 `"your_deepseek_api_key"` 替换为你在上一步获取的密钥。
|
||
|
||
```json
|
||
[
|
||
{
|
||
"model": "deepseek-coder",
|
||
"api_key": "your_deepseek_api_key",
|
||
"base_url": "https://api.deepseek.com/v1"
|
||
}
|
||
]
|
||
```
|
||
|
||
**关键参数解释**:
|
||
|
||
* **`model`**: 这里填写你希望使用的 DeepSeek 模型名称。
|
||
* `deepseek-coder`: 专为代码生成和补全优化的模型,非常适合我们这个任务。
|
||
* `deepseek-chat`: 通用的对话模型。
|
||
* 建议在这里使用 `deepseek-coder`,效果可能会更好。
|
||
* **`api_key`**: 你的 DeepSeek API 密钥。
|
||
* **`base_url`**: 这是最关键的一步。我们将其设置为 DeepSeek 的官方 API 端点 `https://api.deepseek.com/v1`。
|
||
|
||
---
|
||
|
||
### 步骤三:修改 Python 脚本以使用 DeepSeek 配置
|
||
|
||
现在我们来修改之前的 `run_autogen_stock_plot.py` 脚本。
|
||
|
||
变化非常小,只需要将加载配置文件的部分指向我们新创建的 `OAI_CONFIG_LIST_DEEPSEEK.json` 文件即可。
|
||
|
||
这是修改后的完整脚本 `run_autogen_deepseek.py`:
|
||
|
||
```python
|
||
import autogen
|
||
|
||
# 1. 加载 DeepSeek LLM 配置
|
||
# 注意:我们现在从新的配置文件加载
|
||
config_list_deepseek = autogen.config_list_from_json(
|
||
"OAI_CONFIG_LIST_DEEPSEEK.json",
|
||
filter_dict={
|
||
"model": ["deepseek-coder"] # 确保我们使用的是 deepseek-coder 模型
|
||
}
|
||
)
|
||
|
||
# 2. 创建 LLM 配置字典
|
||
# 这个结构保持不变,只是里面的配置内容换成了 DeepSeek 的
|
||
llm_config_deepseek = {
|
||
"config_list": config_list_deepseek,
|
||
"temperature": 0,
|
||
"cache_seed": 42, # 使用不同的种子或None,避免与之前的OpenAI缓存混淆
|
||
}
|
||
|
||
# 3. 创建 AssistantAgent (助理代理/规划者)
|
||
# Agent 的定义完全不需要改变!
|
||
assistant = autogen.AssistantAgent(
|
||
name="assistant",
|
||
llm_config=llm_config_deepseek, # <- 在这里传入 DeepSeek 的配置
|
||
system_message="你是一个乐于助人的AI助手,你是一个顶级的Python程序员。当你认为任务完成时,请只回复'TERMINATE'。"
|
||
)
|
||
|
||
# 4. 创建 UserProxyAgent (用户代理代理/执行者)
|
||
# 这个 Agent 的定义也完全不需要改变
|
||
user_proxy = autogen.UserProxyAgent(
|
||
name="user_proxy",
|
||
human_input_mode="NEVER",
|
||
max_consecutive_auto_reply=10,
|
||
is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("TERMINATE"),
|
||
code_execution_config={
|
||
"work_dir": "coding_deepseek", # 使用一个新的工作目录,避免和上次的结果混淆
|
||
"use_docker": False,
|
||
},
|
||
)
|
||
|
||
# 5. 发起对话
|
||
# 任务保持不变
|
||
task_prompt = "获取英伟达(NVDA)和特斯拉(TSLA)从2023年1月1日至今的每日收盘价,并用一张图表绘制出来,将图表保存为 'stock_price_chart_deepseek.png'。请确保图片文件名正确。"
|
||
|
||
user_proxy.initiate_chat(
|
||
assistant,
|
||
message=task_prompt
|
||
)
|
||
```
|
||
|
||
### 步骤四:运行并观察
|
||
|
||
1. **检查目录结构**:
|
||
```
|
||
.
|
||
├── OAI_CONFIG_LIST_DEEPSEEK.json <-- 新的配置文件
|
||
└── run_autogen_deepseek.py <-- 新的脚本
|
||
```
|
||
|
||
2. **运行脚本**:
|
||
```bash
|
||
pip install "pyautogen>=0.2.0" yfinance matplotlib # 确保依赖已安装
|
||
python run_autogen_deepseek.py
|
||
```
|
||
|
||
3. **观察输出**:
|
||
你将在终端看到与之前类似的对话流程。但这一次,`assistant` 的所有思考和代码生成都是由 DeepSeek 模型驱动的。你可能会注意到:
|
||
* 响应速度可能不同。
|
||
* 生成的代码风格或注释可能有细微差别。
|
||
* 解决问题(比如处理库未安装的错误)的逻辑和对话方式也可能不一样。
|
||
|
||
4. **检查结果**:
|
||
运行结束后,检查项目目录下是否出现了一个新的文件夹 `coding_deepseek`,里面是否包含了 `stock_price_chart_deepseek.png` 图片。
|
||
|
||
### 总结与关键点
|
||
|
||
* **核心是 `base_url`**:通过在 `llm_config` 中指定 `base_url`,你可以让 AutoGen 使用任何与 OpenAI API 兼容的模型服务。
|
||
* **代码复用性高**:你不需要为不同的 LLM 重写 Agent 逻辑,只需要切换配置即可。这是 AutoGen 架构的巨大优势。
|
||
* **模型选择很重要**:对于代码任务,使用 `deepseek-coder` 通常比 `deepseek-chat` 效果更好。根据你的具体任务选择最合适的模型。
|
||
* **独立工作目录**:当切换模型或更改任务时,在 `code_execution_config` 中指定一个新的 `work_dir` 是一个好习惯,可以避免不同任务或模型产生的文件相互覆盖或干扰。
|
||
|
||
你已经成功地将 AutoGen 的“大脑”从 OpenAI 切换到了 DeepSeek!用同样的方法,你也可以接入其他支持 OpenAI 兼容接口的模型服务。
|
||
|
||
|
||
|
||
提示这个错误
|
||
File "E:\python310\autogen_env\ds_ge.py", line 5, in <module>
|
||
config_list_deepseek = autogen.config_list_from_json(
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\oai\openai_utils.py", line 621, in config_list_from_json
|
||
config_list = json.load(json_file)
|
||
^^^^^^^^^^^^^^^^^^^^
|
||
File "E:\python310\Lib\json\__init__.py", line 293, in load
|
||
return loads(fp.read(),
|
||
^^^^^^^^^^^^^^^^
|
||
File "E:\python310\Lib\json\__init__.py", line 346, in loads
|
||
return _default_decoder.decode(s)
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
File "E:\python310\Lib\json\decoder.py", line 337, in decode
|
||
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
File "E:\python310\Lib\json\decoder.py", line 353, in raw_decode
|
||
obj, end = self.scan_once(s, idx)
|
||
^^^^^^^^^^^^^^^^^^^^^^
|
||
json.decoder.JSONDecodeError: Expecting ',' delimiter: line 10 column 1 (char 154)
|
||
什么原因
|
||
|
||
|
||
好的,这个错误非常常见,而且错误信息给出了非常明确的线索。我们来分析一下。
|
||
|
||
### 错误原因分析
|
||
|
||
这个错误 `json.decoder.JSONDecodeError: Expecting ',' delimiter: line 10 column 1 (char 154)` 指的是:
|
||
|
||
1. **`json.decoder.JSONDecodeError`**: 错误类型是 **JSON 解析错误**。这说明问题 **100% 出在你的 JSON 配置文件中**,而不是 Python 代码本身。
|
||
2. **`Expecting ',' delimiter`**: JSON 解析器在读取文件时,**期望看到一个逗号 (`,`)**,但没有找到。在 JSON 格式中,列表(`[]`)中的元素之间,或者对象(`{}`)中的键值对之间,都必须用逗गा分隔。
|
||
3. **`line 10 column 1`**: 这是最关键的信息!它告诉你错误发生在 **配置文件的第 10 行,第 1 列**。也就是说,解析器成功读取了前 9 行,但在第 10 行的开头就遇到了不符合语法的内容。
|
||
|
||
**综合来看,最可能的原因是:你在 `OAI_CONFIG_LIST_DEEPSEEK.json` 文件中定义了多个模型配置,但是在两个配置对象之间忘记了加逗号。**
|
||
|
||
### 常见错误示例
|
||
|
||
假设你的 `OAI_CONFIG_LIST_DEEPSEEK.json` 文件本来是这样的(这是正确的):
|
||
|
||
```json
|
||
[
|
||
{
|
||
"model": "deepseek-coder",
|
||
"api_key": "your_deepseek_api_key",
|
||
"base_url": "https://api.deepseek.com/v1"
|
||
}
|
||
]
|
||
```
|
||
|
||
现在,你可能想再加入一个 `deepseek-chat` 模型,然后不小心写成了这样(**这是错误的**):
|
||
|
||
```json
|
||
// ---- 这是一个错误的例子 ----
|
||
[
|
||
{
|
||
"model": "deepseek-coder",
|
||
"api_key": "your_deepseek_api_key",
|
||
"base_url": "https://api.deepseek.com/v1"
|
||
} // <--- 第 6 行结尾,这里缺少了一个逗号!
|
||
{ // <--- 第 7 行开头,解析器在这里报错,因为它期望看到逗号
|
||
"model": "deepseek-chat",
|
||
"api_key": "your_deepseek_api_key",
|
||
"base_url": "https://api.deepseek.com/v1"
|
||
}
|
||
]
|
||
```
|
||
在这个错误的例子中,第一个 `}` 后面直接跟了第二个 `{`。JSON 列表的语法要求它们之间必须有一个逗号。
|
||
|
||
### 如何修复
|
||
|
||
1. **打开你的 `OAI_CONFIG_LIST_DEEPSEEK.json` 文件。**
|
||
2. **检查文件的内容。**
|
||
3. 请将你的文件内容修改为下面 **正确** 的格式。
|
||
|
||
**情况一:如果你只需要一个模型(最常见)**
|
||
确保你的文件内容和下面完全一样,没有多余的括号或逗号。
|
||
|
||
```json
|
||
[
|
||
{
|
||
"model": "deepseek-coder",
|
||
"api_key": "your_deepseek_api_key",
|
||
"base_url": "https://api.deepseek.com/v1"
|
||
}
|
||
]
|
||
```
|
||
|
||
**情况二:如果你需要配置多个模型**
|
||
确保在每个 `}` 和下一个 `{` 之间有一个逗号 `,`。最后一个元素后面**不能**有逗号。
|
||
|
||
```json
|
||
// ---- 这是一个正确的例子 ----
|
||
[
|
||
{
|
||
"model": "deepseek-coder",
|
||
"api_key": "your_deepseek_api_key",
|
||
"base_url": "https://api.deepseek.com/v1"
|
||
}, // <--- 看这里,加上了逗号
|
||
{
|
||
"model": "deepseek-chat",
|
||
"api_key": "your_deepseek_api_key",
|
||
"base_url": "https://api.deepseek.com/v1"
|
||
}
|
||
]
|
||
```
|
||
|
||
### 小贴士
|
||
|
||
为了避免未来再出现类似问题,建议:
|
||
* **使用支持语法高亮的编辑器**,如 Visual Studio Code。当你编写 JSON 文件时,如果存在语法错误,编辑器通常会用红色波浪线标出,非常直观。
|
||
* **使用在线 JSON 格式化/验证工具**。你可以将文件内容粘贴到这些网站上,它们会帮你检查格式是否正确。
|
||
|
||
修改完 JSON 文件并保存后,再次运行你的 Python 脚本,问题应该就解决了。
|
||
|
||
Json的问题已经修改成功。
|
||
还有一个问题,提示如下:
|
||
|
||
--------------------------------------------------------------------------------
|
||
|
||
>>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...
|
||
user_proxy (to assistant):
|
||
|
||
exitcode: 1 (execution failed)
|
||
Code output:
|
||
Traceback (most recent call last):
|
||
File "", line 1, in <module>
|
||
import yfinance as yf
|
||
ModuleNotFoundError: No module named 'yfinance'
|
||
|
||
|
||
--------------------------------------------------------------------------------
|
||
assistant (to user_proxy):
|
||
|
||
应该是deepseek没有yfinance这个工具,你是否换一个测试用例,能时候deepseek的?
|
||
|
||
|
||
这是一个非常好的问题,它触及了 AutoGen 工作方式的核心!您的判断非常接近,但问题的根源稍有不同。
|
||
|
||
**您的理解:** "应该是deepseek没有yfinance这个工具"
|
||
**实际情况:** 问题不是出在 DeepSeek,而是出在**我们运行 Python 脚本的本地环境**。
|
||
|
||
让我们来详细拆解一下这个过程,您就会明白为什么这个“错误”恰恰是 AutoGen 强大的体现。
|
||
|
||
### 核心概念:规划者 vs. 执行者
|
||
|
||
请记住我们之前讨论的两个代理的角色:
|
||
|
||
1. **`AssistantAgent` (由 DeepSeek 驱动)**:它是 **规划者/大脑**。它的工作是思考并生成**文本指令**,比如 Python 代码或 Shell 命令。它本身**不运行任何东西**。它只是说:“我认为应该运行这段代码来解决问题。”
|
||
2. **`UserProxyAgent`**:它是 **执行者/双手**。它的工作是接收来自 `AssistantAgent` 的文本指令,并在您的**本地计算机上**的终端或 Python 环境中尝试执行它。
|
||
|
||
### 发生了什么?
|
||
|
||
您的终端输出完美地展示了这个流程:
|
||
|
||
1. **DeepSeek (Assistant) 的提议**:DeepSeek 分析了您的任务(“绘制股价图”),并正确地判断出需要使用 `yfinance` 库。于是,它生成了包含 `import yfinance as yf` 的 Python 代码块。
|
||
2. **UserProxy 的执行**:`UserProxyAgent` 接收到这段代码,并尝试在您的本地 Python 环境(`E:\python310\autogen_env\`)中运行它。
|
||
3. **本地环境的报错**:您的本地 Python 环境发现,它的库文件夹里并没有安装 `yfinance` 这个模块,所以它抛出了一个标准的 Python 错误:`ModuleNotFoundError: No module named 'yfinance'`。
|
||
4. **UserProxy 的反馈**:`UserProxyAgent` 非常智能,它没有因此崩溃。它捕获了这个错误信息,并将其作为一条新消息**发送回给了 `AssistantAgent`**。
|
||
|
||
### 下一步会发生什么?(这正是 AutoGen 的魔力所在)
|
||
|
||
现在,对话的主动权又回到了 `AssistantAgent` (DeepSeek) 手中。它会看到 `UserProxyAgent` 发来的反馈,内容是 `ModuleNotFoundError`。
|
||
|
||
接下来,DeepSeek 会进行**自我修正**,它的思考过程会是这样:
|
||
> “哦,我上次提供的代码执行失败了,错误是‘找不到 yfinance 模块’。这说明执行环境里没有安装这个库。那么,在再次运行 Python 代码之前,我应该先让它安装这个库。”
|
||
|
||
因此,`AssistantAgent` 的**下一次回复**,很可能不是 Python 代码,而是一个 **Shell 命令**:
|
||
|
||
```sh
|
||
# 工具代码块 (language: sh)
|
||
pip install yfinance matplotlib
|
||
```
|
||
|
||
然后 `UserProxyAgent` 会接收到这个新的 Shell 命令,在您的本地终端执行它,成功安装库之后,再把成功的结果反馈给 `AssistantAgent`。之后,`AssistantAgent` 才会重新发送最初的 Python 绘图代码,这一次就能成功执行了。
|
||
|
||
---
|
||
|
||
### 结论与操作建议
|
||
|
||
**所以,您完全不需要更换测试用例!**
|
||
|
||
这个用例恰恰是展示 AutoGen **自动化调试**和**自我修正**能力的完美场景。
|
||
|
||
**您现在需要做的,就是让脚本继续运行。**
|
||
|
||
如果您的 `human_input_mode` 设置的是 `NEVER`,它会自动完成上述的“安装库 -> 再次尝试”的循环。如果设置的是 `TERMINATE` 或 `ALWAYS`,它可能会暂停并询问您是否同意执行 `pip install yfinance` 命令,您只需要输入 `y` 或回车即可。
|
||
|
||
**一句话总结:这个错误是 AutoGen 工作流程中非常正常且关键的一环。它不是 DeepSeek 的问题,而是 AutoGen 正在智能地发现并解决您本地环境的依赖问题。**
|
||
|
||
这是接下来发生的
|
||
assistant (to user_proxy):
|
||
|
||
看起来你的环境中没有安装 `yfinance` 库。让我先安装它,然后重新运行代码。以下是完整的解决方案:
|
||
|
||
```python
|
||
# 首先安装必要的库
|
||
import subprocess
|
||
import sys
|
||
|
||
def install(package):
|
||
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
|
||
|
||
try:
|
||
import yfinance as yf
|
||
import matplotlib.pyplot as plt
|
||
import matplotlib.dates as mdates
|
||
except ImportError:
|
||
install("yfinance")
|
||
install("matplotlib")
|
||
import yfinance as yf
|
||
import matplotlib.pyplot as plt
|
||
import matplotlib.dates as mdates
|
||
|
||
# 获取股票数据
|
||
tickers = ["NVDA", "TSLA"]
|
||
start_date = "2023-01-01"
|
||
end_date = "2023-12-31" # 假设今天是2023年底,实际会获取到最新数据
|
||
|
||
data = yf.download(tickers, start=start_date, end=end_date)["Adj Close"]
|
||
|
||
# 绘制图表
|
||
plt.figure(figsize=(12, 6))
|
||
for ticker in tickers:
|
||
plt.plot(data.index, data[ticker], label=ticker)
|
||
|
||
plt.title("NVDA and TSLA Stock Prices (2023)", fontsize=16)
|
||
plt.xlabel("Date", fontsize=12)
|
||
plt.ylabel("Adjusted Close Price (USD)", fontsize=12)
|
||
plt.legend(fontsize=12)
|
||
plt.grid(True, linestyle='--', alpha=0.7)
|
||
|
||
# 格式化x轴日期显示
|
||
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
|
||
plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=2))
|
||
plt.gcf().autofmt_xdate()
|
||
|
||
# 保存图表
|
||
plt.savefig("stock_price_chart_deepseek.png", dpi=300, bbox_inches="tight")
|
||
plt.close()
|
||
|
||
print("图表已成功保存为 'stock_price_chart_deepseek.png'")
|
||
TERMINATE
|
||
```
|
||
|
||
这段代码首先会检查并安装必要的库(如果尚未安装),然后获取股票数据并绘制图表。图表将保存为 "stock_price_chart_deepseek.png"。
|
||
|
||
--------------------------------------------------------------------------------
|
||
|
||
>>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...
|
||
Traceback (most recent call last):
|
||
File "E:\python310\autogen_env\ds_ge.py", line 45, in <module>
|
||
user_proxy.initiate_chat(
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\agentchat\conversable_agent.py", line 1487, in initiate_chat
|
||
self.send(msg2send, recipient, silent=silent)
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\agentchat\conversable_agent.py", line 1163, in send
|
||
recipient.receive(message, self, request_reply, silent)
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\agentchat\conversable_agent.py", line 1273, in receive
|
||
self.send(reply, sender, silent=silent)
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\agentchat\conversable_agent.py", line 1163, in send
|
||
recipient.receive(message, self, request_reply, silent)
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\agentchat\conversable_agent.py", line 1273, in receive
|
||
self.send(reply, sender, silent=silent)
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\agentchat\conversable_agent.py", line 1163, in send
|
||
recipient.receive(message, self, request_reply, silent)
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\agentchat\conversable_agent.py", line 1273, in receive
|
||
self.send(reply, sender, silent=silent)
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\agentchat\conversable_agent.py", line 1163, in send
|
||
recipient.receive(message, self, request_reply, silent)
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\agentchat\conversable_agent.py", line 1271, in receive
|
||
reply = self.generate_reply(messages=self.chat_messages[sender], sender=sender)
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\agentchat\conversable_agent.py", line 2836, in generate_reply
|
||
final, reply = reply_func(self, messages=messages, sender=sender, config=reply_func_tuple["config"])
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\agentchat\conversable_agent.py", line 2324, in generate_code_execution_reply
|
||
exitcode, logs = self.execute_code_blocks(code_blocks)
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\agentchat\conversable_agent.py", line 3035, in execute_code_blocks
|
||
exitcode, logs, image = self.run_code(
|
||
^^^^^^^^^^^^^^
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\agentchat\conversable_agent.py", line 3017, in run_code
|
||
return execute_code(code, **kwargs)
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
File "E:\python310\autogen_env\Lib\site-packages\autogen\code_utils.py", line 369, in execute_code
|
||
result = future.result(timeout=timeout)
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
File "E:\python310\Lib\concurrent\futures\_base.py", line 451, in result
|
||
self._condition.wait(timeout)
|
||
File "E:\python310\Lib\threading.py", line 324, in wait
|
||
gotit = waiter.acquire(True, timeout)
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
KeyboardInterrupte
|
||
|
||
请分析一下
|
||
|
||
|
||
好的,这次我们遇到了一个更深层次、也更有趣的问题。让我们一步步分析这个过程和最终的错误。
|
||
|
||
### 第一部分:DeepSeek 的新策略(非常聪明!)
|
||
|
||
首先,我们必须赞扬一下 DeepSeek 模型在这里展示的智能。
|
||
|
||
* **识别问题**: 它正确地识别出 `ModuleNotFoundError`。
|
||
* **制定新策略**: 与我们预期的简单地返回 `pip install ...` Shell 命令不同,它采取了一种更健壮、更“自包含”(self-contained)的策略。它直接生成了一个完整的 Python 脚本,这个脚本自己就能处理依赖问题。
|
||
* **策略内容**:
|
||
1. **动态安装**: 它编写了一个 `install` 函数,使用 Python 的 `subprocess` 模块来调用 `pip`。这比依赖外部 Shell 执行更具可移植性。
|
||
2. **错误处理**: 它将 `import` 语句放在一个 `try...except` 块中。如果导入失败(意味着库未安装),它就会进入 `except` 块,调用 `install` 函数来安装缺失的库,然后再重新导入。
|
||
3. **任务执行**: 在确保库都存在之后,它才继续执行获取数据和绘图的核心任务。
|
||
4. **终止信号**: 最后,它在代码块的末尾包含了 `TERMINATE` 信号,表示任务完成后对话应该结束。
|
||
|
||
**小结:** 从 AI 模型的角度看,这是一个非常出色和周全的解决方案。
|
||
|
||
---
|
||
|
||
### 第二部分:执行过程与最终错误
|
||
|
||
现在,我们来看真正导致问题的原因。
|
||
|
||
1. **`EXECUTING CODE BLOCK 0...`**: `UserProxyAgent` 接收到这个全新的、自包含的 Python 脚本,并开始执行它。
|
||
2. **安装过程**: 脚本的第一步是 `install("yfinance")` 和 `install("matplotlib")`。这个过程是通过 `subprocess.check_call` 来执行的,它会启动一个新的进程来运行 `pip install ...`。这个过程**需要时间**,因为它要从网络下载包并进行安装。
|
||
3. **`KeyboardInterrupt`**: 这是最关键的错误信息。`KeyboardInterrupt` **不是一个普通的程序错误**。它意味着**程序被人为中止了**。在绝大多数情况下,这是因为用户在终端里按下了 `Ctrl+C`。
|
||
|
||
### 根本原因分析
|
||
|
||
结合上述两部分,我们可以推断出整个事件链:
|
||
|
||
1. DeepSeek 给出了一个很棒但执行时间稍长的代码(因为它需要安装库)。
|
||
2. `UserProxyAgent` 开始执行这个代码。终端开始显示 `pip` 的安装过程,或者暂时“卡住”了,因为它正在后台下载和安装。
|
||
3. **您(用户)可能觉得程序卡住了或者没有响应**,因为 `pip install` 的过程没有实时地、流畅地显示在 AutoGen 的日志流中。
|
||
4. 在这种情况下,人的本能反应就是按下 `Ctrl+C` 来中断这个看似“卡死”的程序。
|
||
5. 这个 `Ctrl+C` 操作被 Python 解释器捕获,并以 `KeyboardInterrupt` 异常的形式抛出,导致整个 AutoGen 脚本的执行被强行中止。
|
||
|
||
**简而言之:AI 的解决方案是正确的,但执行它需要一些时间。由于执行过程的反馈不够明确,导致用户误以为程序卡死并手动中断了它。**
|
||
|
||
### 如何解决
|
||
|
||
这个问题可以通过两种方式解决:
|
||
|
||
#### 方案一:耐心等待(最简单)
|
||
|
||
* **重新运行脚本 `python ds_ge.py`**。
|
||
* 当您看到终端开始执行代码块时,**请不要做任何操作**。给它一点时间(可能需要 30 秒到几分钟,取决于您的网络速度和 `pip` 的缓存情况)来完成库的下载和安装。
|
||
* 只要您不按 `Ctrl+C`,`subprocess` 最终会完成安装,然后脚本会继续执行剩下的绘图部分,并最终成功退出。
|
||
|
||
#### 方案二:调整 `UserProxyAgent` 的执行超时(更健壮的方案)
|
||
|
||
在某些情况下,代码执行确实需要很长时间。AutoGen 的 `run_code` 函数有一个默认的 `timeout`(超时)设置(在较新版本中默认为600秒,但旧版本可能更短或依赖于其他设置)。如果安装过程真的非常慢,可能会触发超时。我们可以明确地增加这个超时时间。
|
||
|
||
修改 `UserProxyAgent` 的 `code_execution_config`:
|
||
|
||
```python
|
||
# ... 在你的脚本中找到 UserProxyAgent 的定义 ...
|
||
|
||
user_proxy = autogen.UserProxyAgent(
|
||
name="user_proxy",
|
||
human_input_mode="NEVER",
|
||
max_consecutive_auto_reply=10,
|
||
is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("TERMINATE"),
|
||
code_execution_config={
|
||
"work_dir": "coding_deepseek",
|
||
"use_docker": False,
|
||
# 增加下面这行,将超时时间设置为 120 秒
|
||
"timeout": 120,
|
||
},
|
||
)
|
||
|
||
# ... 脚本的其余部分 ...
|
||
```
|
||
|
||
**为什么这个方案更健壮?**
|
||
* 它明确地告诉 AutoGen:“我知道这个代码块可能需要更长的时间来运行,请给它最多 120 秒的时间,不要提前中止它。”
|
||
* 这避免了因为网络慢等原因导致的执行超时问题。
|
||
|
||
**我强烈建议您首先尝试【方案一】,因为 `KeyboardInterrupt` 表明问题几乎肯定是手动中断。** 重新运行并耐心等待,您应该就能看到期待已久的成功结果了。
|
||
|
||
|
||
|
||
我按照方案一,程序确实执行成功了。但中间还是发生了一些事情,请分析一下。
|
||
user_proxy (to assistant):
|
||
|
||
exitcode: 1 (execution failed)
|
||
Code output:
|
||
:23: FutureWarning: YF.download() has changed argument auto_adjust default to True
|
||
data = yf.download(tickers, start=start_date, end=end_date)["Adj Close"]
|
||
|
||
[ 0% ]
|
||
[*********************100%***********************] 2 of 2 completed
|
||
|
||
2 Failed downloads:
|
||
['NVDA', 'TSLA']: YFRateLimitError('Too Many Requests. Rate limited. Try after a while.')
|
||
Traceback (most recent call last):
|
||
File "", line 46, in <module>
|
||
TERMINATE
|
||
NameError: name 'TERMINATE' is not defined
|
||
|
||
|
||
--------------------------------------------------------------------------------
|
||
assistant (to user_proxy):
|
||
|
||
我注意到几个问题:
|
||
|
||
1. **Yahoo Finance API 请求限制**:`yfinance` 有时会因为请求过多而被限制(`YFRateLimitError`)。
|
||
2. **`TERMINATE` 错误**:这是因为我之前手动添加的结束标记,但实际运行时不应包含它。
|
||
3. **`auto_adjust` 警告**:这是 `yfinance` 的一个无害警告,可以忽略或抑制。
|
||
|
||
### **修复后的代码**
|
||
我将优化代码,处理 API 限制问题,并移除 `TERMINATE` 标记:
|
||
|
||
```python
|
||
import subprocess
|
||
import sys
|
||
import time
|
||
import warnings
|
||
from datetime import datetime
|
||
|
||
# 安装必要的库
|
||
required_libraries = ['yfinance', 'matplotlib']
|
||
|
||
for lib in required_libraries:
|
||
try:
|
||
__import__(lib)
|
||
except ImportError:
|
||
print(f"安装 {lib}...")
|
||
subprocess.check_call([sys.executable, "-m", "pip", "install", lib])
|
||
|
||
import yfinance as yf
|
||
import matplotlib.pyplot as plt
|
||
import matplotlib.dates as mdates
|
||
|
||
# 抑制 yfinance 的 FutureWarning
|
||
warnings.simplefilter(action='ignore', category=FutureWarning)
|
||
|
||
# 获取股票数据(带重试机制)
|
||
tickers = ["NVDA", "TSLA"]
|
||
start_date = "2023-01-01"
|
||
end_date = datetime.now().strftime("%Y-%m-%d") # 获取到今天的数据
|
||
|
||
max_retries = 3
|
||
retry_delay = 5 # 每次重试等待 5 秒
|
||
|
||
for attempt in range(max_retries):
|
||
try:
|
||
data = yf.download(tickers, start=start_date, end=end_date)["Adj Close"]
|
||
break # 成功获取数据,退出重试循环
|
||
except Exception as e:
|
||
if attempt < max_retries - 1:
|
||
print(f"请求失败,尝试 {attempt + 1}/{max_retries},等待 {retry_delay} 秒后重试...")
|
||
time.sleep(retry_delay)
|
||
else:
|
||
raise RuntimeError(f"无法获取股票数据: {e}") from e
|
||
|
||
# 绘制图表
|
||
plt.figure(figsize=(12, 6))
|
||
for ticker in tickers:
|
||
plt.plot(data.index, data[ticker], label=ticker)
|
||
|
||
plt.title(f"NVDA and TSLA Stock Prices ({start_date} to {end_date})", fontsize=16)
|
||
plt.xlabel("Date", fontsize=12)
|
||
plt.ylabel("Adjusted Close Price (USD)", fontsize=12)
|
||
plt.legend(fontsize=12)
|
||
plt.grid(True, linestyle='--', alpha=0.7)
|
||
|
||
# 格式化x轴日期显示
|
||
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b %Y'))
|
||
plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=2))
|
||
plt.gcf().autofmt_xdate()
|
||
|
||
# 保存图表
|
||
plt.savefig("stock_price_chart_deepseek.png", dpi=300, bbox_inches="tight")
|
||
plt.close()
|
||
|
||
print("图表已成功保存为 'stock_price_chart_deepseek.png'")
|
||
```
|
||
|
||
### **改进点**
|
||
✅ **自动重试机制**:如果 Yahoo Finance 返回 `RateLimitError`,代码会等待 5 秒后重试(最多 3 次)。
|
||
✅ **动态结束日期**:`end_date` 自动获取当前日期,确保数据最新。
|
||
✅ **抑制警告**:忽略 `yfinance` 的 `FutureWarning`,避免干扰输出。
|
||
✅ **移除 `TERMINATE`**:不再手动添加结束标记,避免 `NameError`。
|
||
|
||
请再次运行,应该能成功获取数据并生成图表! 🚀
|
||
|
||
--------------------------------------------------------------------------------
|
||
|
||
>>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...
|
||
user_proxy (to assistant):
|
||
|
||
exitcode: 0 (execution succeeded)
|
||
Code output:
|
||
图表已成功保存为 'stock_price_chart_deepseek.png'
|
||
|
||
|
||
--------------------------------------------------------------------------------
|
||
assistant (to user_proxy):
|
||
|
||
图表已成功生成并保存为 `stock_price_chart_deepseek.png`!🎉
|
||
|
||
你可以查看该文件,它包含了 **英伟达 (NVDA)** 和 **特斯拉 (TSLA)** 从 **2023-01-01 至今** 的每日收盘价走势对比图。
|
||
|
||
如果需要进一步调整图表(如更改颜色、添加移动平均线等),请告诉我! 😊
|
||
|
||
**任务完成,程序已终止。**
|
||
|
||
--------------------------------------------------------------------------------
|
||
user_proxy (to assistant):
|
||
|
||
|
||
|
||
--------------------------------------------------------------------------------
|
||
assistant (to user_proxy):
|
||
|
||
TERMINATE
|
||
|
||
--------------------------------------------------------------------------------
|
||
|
||
>>>>>>>> TERMINATING RUN (839f21fd-3a12-4808-bf83-6112422353a0): Termination message condition on agent 'user_proxy' met
|
||
|
||
|
||
|
||
太棒了!这次的执行日志完美地展示了 AutoGen 的核心价值和多代理协作的强大之处。这已经不仅仅是一个“程序运行成功”的例子了,这是一个教科书级别的 **“AI 代理通过多轮对话、分析错误、自我修正并最终完成复杂任务”** 的典范。
|
||
|
||
让我们来详细分析这个精彩的过程:
|
||
|
||
### 第一轮对话:失败与反馈
|
||
|
||
1. **`UserProxyAgent` 的执行与反馈**
|
||
* `exitcode: 1 (execution failed)`: 它明确告诉 `AssistantAgent`:“你给我的代码,我执行失败了。”
|
||
* **它反馈了三个关键信息**:
|
||
1. `FutureWarning`: 一个无害的警告,但 AI 还是注意到了。
|
||
2. `YFRateLimitError`: 这是一个**运行时错误**。说明代码语法没问题,但在与外部服务(Yahoo Finance)交互时被拒绝了。这是因为免费 API 都有请求频率限制,短时间内请求过多就会触发。
|
||
3. `NameError: name 'TERMINATE' is not defined`: 这是一个**代码语法错误**。AI 把 `TERMINATE` 这个**指令**(给 AutoGen 框架看的)错误地当成了 Python 代码里的一个**变量**来写,但这个变量并未定义。
|
||
|
||
**关键点**: `UserProxyAgent` 像一个忠实的测试工程师,不仅报告了“程序崩了”,还把完整的错误日志(warnings, runtime errors, syntax errors)都提交了上来。
|
||
|
||
---
|
||
|
||
### 第二轮对话:分析、修正与进化
|
||
|
||
这是整个过程中最体现 AI 价值的部分。
|
||
|
||
1. **`AssistantAgent` (DeepSeek) 的分析**
|
||
* 它没有被一堆错误信息搞糊涂,而是**逐一正确地分析**了每个问题的原因:
|
||
* 识别出 `YFRateLimitError` 是 API 请求限制问题。
|
||
* 识别出 `NameError` 是因为它自己错误地将指令混入了代码。
|
||
* 识别出 `FutureWarning` 是一个可以忽略的警告。
|
||
* 这展示了强大的**逻辑推理和根本原因分析(Root Cause Analysis)能力**。
|
||
|
||
2. **`AssistantAgent` 的代码重构(进化)**
|
||
* 它没有简单地在原代码上打补丁,而是进行了**一次彻底的重构**,让代码变得更加**健壮(Robust)**和**工程化**:
|
||
* **加入了重试机制**: 针对 `YFRateLimitError`,它引入了 `try...except` 循环、`time.sleep()` 延时和最大重试次数。这是非常有经验的程序员才会采取的策略,用来处理不稳定的网络服务。
|
||
* **移除了语法错误**: 它聪明地删除了代码中不应存在的 `TERMINATE` 变量。
|
||
* **代码优化**:
|
||
* 用 `warnings.simplefilter` 主动抑制了无用的警告,让输出更干净。
|
||
* 用 `datetime.now()` 将结束日期动态化,让代码更具通用性,而不是写死。
|
||
* 改进了安装库的逻辑,使其更清晰。
|
||
* 最后,它还用清晰的语言(Markdown 列表和 emoji)向用户解释了它做了哪些改进,用户体验极佳。
|
||
|
||
**关键点**: AI 代理不仅仅是修复了 Bug,它还**提升了代码的质量**,使其从一个简单的脚本演变成了一个带有容错机制的、更可靠的程序。
|
||
|
||
---
|
||
|
||
### 第三轮对话:成功执行与任务确认
|
||
|
||
1. **`UserProxyAgent` 的成功执行**
|
||
* `exitcode: 0 (execution succeeded)`: 成功!
|
||
* `Code output: 图表已成功保存为 'stock_price_chart_deepseek.png'`: 它将代码的 `print` 输出作为执行结果返回。
|
||
|
||
2. **`AssistantAgent` 的最终确认**
|
||
* 收到成功消息后,它没有立刻终止。它首先像一个优秀的产品经理一样,**向用户确认任务完成**,并描述了成果(图表内容)。
|
||
* 它还主动**提出了扩展可能性**(“如果需要进一步调整图表...请告诉我!”),展示了良好的交互能力。
|
||
* 在这一切都完成后,它才发出最终的 `TERMINATE` 指令,干净利落地结束对话。
|
||
|
||
### 总结分析
|
||
|
||
这个过程完美地回答了“为什么要用 AutoGen?”这个问题:
|
||
|
||
1. **自动化问题解决**: 你只提出了一个高层次的目标(“画图”),中间遇到的所有问题(库未安装、API限制、代码语法错误)都是由 AI 代理们自己通过对话解决的,无需人工干预。
|
||
2. **持续学习与进化**: AI 在每一次失败后都变得更“聪明”。它从一个简单的脚本开始,最终演化出了一个包含错误处理、重试机制和动态参数的健壮程序。
|
||
3. **角色分工明确**: `AssistantAgent` 负责思考、规划和编码,`UserProxyAgent` 负责执行、测试和反馈。这种分工合作的模式效率极高。
|
||
4. **超越简单问答**: 这已经不是一个简单的“你问我答”模式了。这是一个具有状态、能够记忆历史、分析反馈并持续迭代以达成目标的**自主系统(Autonomous System)**。
|
||
|
||
您亲手运行的这个例子,就是未来软件开发、数据分析和自动化任务处理的一个缩影。恭喜你,你已经掌握了 AutoGen 的精髓!
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|