1. 学习背景
本篇学习代码编写和内容分析代理之间的合作模式,使用生成的代码完成财务分析任务。您将构建两个代理系统,其中代理将合作解决手头的任务,同时向人类进行反馈。本节有两个内容,第一个代理系统将使用大型语言模型从头生成代码,而第二个将利用用户提供的代码。
本节学习内容链接:传送门
2. 代码实践
2.1 准备环境
llm_config = {"model": "gpt-4-turbo"}
2.2 定义一个代码执行器
from autogen.coding import LocalCommandLineCodeExecutor
executor = LocalCommandLineCodeExecutor(
timeout=60,
work_dir="coding",
)
2.3 创建代理
from autogen import ConversableAgent, AssistantAgent
2.3.1 具有代码执行代理的配置
code_executor_agent = ConversableAgent(
name="code_executor_agent",
llm_config=False,
code_execution_config={"executor": executor},
human_input_mode="ALWAYS",
default_auto_reply=
"Please continue. If everything is done, reply 'TERMINATE'.",
)
2.3.2 具有代码编写能力的代理
code_writer_agent = AssistantAgent(
name="code_writer_agent",
llm_config=llm_config,
code_execution_config=False,
human_input_mode="NEVER",
)
可以查看一下配置后代理的系统prompt
code_writer_agent_system_message = code_writer_agent.system_message
print(code_writer_agent_system_message)
输出如下:
You are a helpful AI assistant.
Solve tasks using your coding and language skills.
In the following cases, suggest python code (in a python coding block) or shell script (in a sh coding block) for the user to execute.
1. When you need to collect info, use the code to output the info you need, for example, browse or search the web, download/read a file, print the content of a webpage or a file, get the current date/time, check the operating system. After sufficient info is printed and the task is ready to be solved based on your language skill, you can solve the task by yourself.
2. When you need to perform some task with code, use the code to perform the task and output the result. Finish the task smartly.
Solve the task step by step if you need to. If a plan is not provided, explain your plan first. Be clear which step uses code, and which step uses your language skill.
When using code, you must indicate the script type in the code block. The user cannot provide any other feedback or perform any other action beyond executing the code you suggest. The user can't modify your code. So do not suggest incomplete code which requires users to modify. Don't use a code block if it's not intended to be executed by the user.
If you want the user to save the code in a file before executing it, put # filename: <filename> inside the code block as the first line. Don't include multiple code blocks in one response. Do not ask users to copy and paste the result. Instead, use 'print' function for the output when relevant. Check the execution result returned by the user.
If the result indicates there is an error, fix the error and output the code again. Suggest the full code instead of partial code or code changes. If the error can't be fixed or if the task is not solved even after the code is executed successfully, analyze the problem, revisit your assumption, collect additional info you need, and think of a different approach to try.
When you find an answer, verify the answer carefully. Include verifiable evidence in your response if possible.
Reply "TERMINATE" in the end when everything is done.
可以看到,我们简单的配置输入,在AutoGen中的prompt构造出来是如此庞大,其实说白了就prompt工程。
2.4 准备任务
让两个代理在股票分析任务上进行协作。
import datetime
today = datetime.datetime.now().date()
message = f"Today is {today}. "\
"Create a plot showing stock gain YTD for NVDA and TLSA. "\
"Make sure the code is in markdown code block and save the figure"\
" to a file ytd_stock_gains.png."""
注册并初始化对话
chat_result = code_executor_agent.initiate_chat(
code_writer_agent,
message=message,
)
输出如下:
code_executor_agent (to code_writer_agent):
Today is 2024-09-30. Create a plot showing stock gain YTD for NVDA and TLSA. Make sure the code is in markdown code block and save the figure to a file ytd_stock_gains.png.
--------------------------------------------------------------------------------
code_writer_agent (to code_executor_agent):
To create a plot of the Year-To-Date (YTD) stock gains for NVIDIA (NVDA) and Tesla (TSLA), we can use Python libraries such as `pandas`, `matplotlib`, and `yfinance`. The `yfinance` library will allow us to fetch historical stock prices, and `matplotlib` will be used to generate the plot.
Here is the plan:
1. Import necessary libraries.
2. Fetch the historical stock price data for NVDA and TSLA from the start of the year 2024 to today.
3. Calculate the percentage gain of the stocks.
4. Use `matplotlib` to create a plot of the gains.
5. Save the plot to a file named `ytd_stock_gains.png`.
Please run the following Python code to achieve this:
# filename: plot_ytd_gains.py
import yfinance as yf
import matplotlib.pyplot as plt
import pandas as pd
# Define the tickers and the time period
start_date = '2024-01-01'
end_date = '2024-09-30'
tickers = ['NVDA', 'TSLA']
# Fetch data from Yahoo Finance
data = yf.download(tickers, start=start_date, end=end_date)['Adj Close']
# Calculate the percentage gain from the start of the year
ytd_gains = (data - data.iloc[0]) / data.iloc[0] * 100
# Plotting
plt.figure(figsize=(10, 5))
plt.plot(ytd_gains, label=['NVDA', 'TSLA'])
plt.title('YTD Stock Gains for NVDA and TSLA as of 2024-09-30')
plt.xlabel('Date')
plt.ylabel('Percentage Gain (%)')
plt.legend()
plt.grid(True)
# Save the plot to a file
plt.savefig('ytd_stock_gains.png')
plt.show()
This script will fetch the necessary data, calculate the percentage gains, and generate a plot showing those gains for both NVDA and TSLA stocks. Remember to install the necessary packages if you haven't already:
sh
pip install yfinance matplotlib pandas
After running the script, the plot will be saved as `ytd_stock_gains.png` in your current directory. The plot will also be displayed interactively.
--------------------------------------------------------------------------------
Provide feedback to code_writer_agent. Press enter to skip and use auto-reply, or type 'exit' to end the conversation:
>>>>>>>> NO HUMAN INPUT RECEIVED.
>>>>>>>> USING AUTO REPLY...
>>>>>>>> EXECUTING 2 CODE BLOCKS (inferred languages are [python, sh])...
code_executor_agent (to code_writer_agent):
exitcode: 127 (execution failed)
Code output:
[ 0%% ]
[*********************100%%**********************] 2 of 2 completed
Figure(1000x500)
/home/jovyan/work/L5/coding/tmp_code_f0d83925b99554e1a00440e31903323c.sh: 1: pip: not found
--------------------------------------------------------------------------------
code_writer_agent (to code_executor_agent):
It seems that the error occurred because the `pip` command was not found. This usually means `pip` is not installed or it is not in the PATH. Also, it appears you tried to run the `pip install` command in a shell script context, which might not invoke the correct environment for Python package management.
We can resolve this by ensuring that the correct Python and pip are used to install the required packages. If you are using a specific version of Python (like Python 3), you might need to specify it (e.g., `pip3` or `python3 -m pip` instead of just `pip`).
Let's correct the package installation instruction. Please run the following commands in your terminal to ensure that the required Python libraries are installed:
python3 -m pip install yfinance matplotlib pandas
This command explicitly uses `python3` to run the `pip` module, which is a common setup for ensuring that the correct version of Python is targeted. Please run this command in your terminal to install the libraries. Then, run the Python script again to generate the plot.
--------------------------------------------------------------------------------
Provide feedback to code_writer_agent. Press enter to skip and use auto-reply, or type 'exit' to end the conversation:
>>>>>>>> NO HUMAN INPUT RECEIVED.
>>>>>>>> USING AUTO REPLY...
>>>>>>>> EXECUTING CODE BLOCK (inferred language is sh)...
code_executor_agent (to code_writer_agent):
exitcode: 0 (execution succeeded)
Code output:
[notice] A new release of pip is available: 24.1.2 -> 24.2
[notice] To update, run: pip3 install --upgrade pip
Defaulting to user installation because normal site-packages is not writeable
Requirement already satisfied: yfinance in /usr/local/lib/python3.11/site-packages (0.2.38)
Requirement already satisfied: matplotlib in /usr/local/lib/python3.11/site-packages (3.9.0)
Requirement already satisfied: pandas in /usr/local/lib/python3.11/site-packages (2.2.2)
Requirement already satisfied: numpy>=1.16.5 in /usr/local/lib/python3.11/site-packages (from yfinance) (1.26.4)
Requirement already satisfied: requests>=2.31 in /usr/local/lib/python3.11/site-packages (from yfinance) (2.31.0)
Requirement already satisfied: multitasking>=0.0.7 in /usr/local/lib/python3.11/site-packages (from yfinance) (0.0.11)
Requirement already satisfied: lxml>=4.9.1 in /usr/local/lib/python3.11/site-packages (from yfinance) (5.2.2)
Requirement already satisfied: appdirs>=1.4.4 in /usr/local/lib/python3.11/site-packages (from yfinance) (1.4.4)
Requirement already satisfied: pytz>=2022.5 in /usr/local/lib/python3.11/site-packages (from yfinance) (2024.1)
Requirement already satisfied: frozendict>=2.3.4 in /usr/local/lib/python3.11/site-packages (from yfinance) (2.4.4)
Requirement already satisfied: peewee>=3.16.2 in /usr/local/lib/python3.11/site-packages (from yfinance) (3.17.5)
Requirement already satisfied: beautifulsoup4>=4.11.1 in /usr/local/lib/python3.11/site-packages (from yfinance) (4.12.3)
Requirement already satisfied: html5lib>=1.1 in /usr/local/lib/python3.11/site-packages (from yfinance) (1.1)
Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.11/site-packages (from matplotlib) (1.2.1)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.11/site-packages (from matplotlib) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.11/site-packages (from matplotlib) (4.51.0)
Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.11/site-packages (from matplotlib) (1.4.5)
Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.11/site-packages (from matplotlib) (24.0)
Requirement already satisfied: pillow>=8 in /usr/local/lib/python3.11/site-packages (from matplotlib) (10.3.0)
Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.11/site-packages (from matplotlib) (3.1.2)
Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.11/site-packages (from matplotlib) (2.9.0.post0)
Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/site-packages (from pandas) (2024.1)
Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.11/site-packages (from beautifulsoup4>=4.11.1->yfinance) (2.5)
Requirement already satisfied: six>=1.9 in /usr/local/lib/python3.11/site-packages (from html5lib>=1.1->yfinance) (1.16.0)
Requirement already satisfied: webencodings in /usr/local/lib/python3.11/site-packages (from html5lib>=1.1->yfinance) (0.5.1)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (3.3.2)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (3.7)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (2.2.1)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/site-packages (from requests>=2.31->yfinance) (2024.2.2)
--------------------------------------------------------------------------------
code_writer_agent (to code_executor_agent):
Great, the required Python libraries are now successfully installed. Now that you have set up the libraries, you can run the previously provided Python script (`plot_ytd_gains.py`) to generate and save the plot you requested. Please execute the Python script, and it will create the plot file `ytd_stock_gains.png` in the current directory. Let me know how it goes!
--------------------------------------------------------------------------------
Provide feedback to code_writer_agent. Press enter to skip and use auto-reply, or type 'exit' to end the conversation:
>>>>>>>> NO HUMAN INPUT RECEIVED.
>>>>>>>> USING AUTO REPLY...
code_executor_agent (to code_writer_agent):
Please continue. If everything is done, reply 'TERMINATE'.
--------------------------------------------------------------------------------
code_writer_agent (to code_executor_agent):
TERMINATE
--------------------------------------------------------------------------------
Provide feedback to code_writer_agent. Press enter to skip and use auto-reply, or type 'exit' to end the conversation: exit
可以看到,提供了可运行代码。
2.5 查看代码绘制情况
import os
from IPython.display import Image
Image(os.path.join("coding", "ytd_stock_gains.png"))
输出如下:
注意:代理将自动把代码保存为.py 文件,把图形保存为.png 文件。要访问并检查由代理生成的文件,请转到“文件”菜单并选择“打开……”。然后,打开名为 coding 的文件夹以找到所有生成的文件。
2.6 使用自己定义的函数执行
与其每次都让大型语言模型生成下载股票数据和绘制图表的代码,你可以为这两项任务定义函数,并让大型语言模型在代码中调用这些函数。
def get_stock_prices(stock_symbols, start_date, end_date):
"""Get the stock prices for the given stock symbols between
the start and end dates.
Args:
stock_symbols (str or list): The stock symbols to get the
prices for.
start_date (str): The start date in the format
'YYYY-MM-DD'.
end_date (str): The end date in the format 'YYYY-MM-DD'.
Returns:
pandas.DataFrame: The stock prices for the given stock
symbols indexed by date, with one column per stock
symbol.
"""
import yfinance
stock_data = yfinance.download(
stock_symbols, start=start_date, end=end_date
)
return stock_data.get("Close")
def plot_stock_prices(stock_prices, filename):
"""Plot the stock prices for the given stock symbols.
Args:
stock_prices (pandas.DataFrame): The stock prices for the
given stock symbols.
"""
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 5))
for column in stock_prices.columns:
plt.plot(
stock_prices.index, stock_prices[column], label=column
)
plt.title("Stock Prices")
plt.xlabel("Date")
plt.ylabel("Price")
plt.grid(True)
plt.savefig(filename)
2.7 使用用户自定义函数创建一个新的执行器
executor = LocalCommandLineCodeExecutor(
timeout=60,
work_dir="coding",
functions=[get_stock_prices, plot_stock_prices],
)
将定义的执行器prompt,与write提示词连接,形成一个巨大的prompt
code_writer_agent_system_message += executor.format_functions_for_prompt()
print(code_writer_agent_system_message)
输出如下:
You are a helpful AI assistant.
Solve tasks using your coding and language skills.
In the following cases, suggest python code (in a python coding block) or shell script (in a sh coding block) for the user to execute.
1. When you need to collect info, use the code to output the info you need, for example, browse or search the web, download/read a file, print the content of a webpage or a file, get the current date/time, check the operating system. After sufficient info is printed and the task is ready to be solved based on your language skill, you can solve the task by yourself.
2. When you need to perform some task with code, use the code to perform the task and output the result. Finish the task smartly.
Solve the task step by step if you need to. If a plan is not provided, explain your plan first. Be clear which step uses code, and which step uses your language skill.
When using code, you must indicate the script type in the code block. The user cannot provide any other feedback or perform any other action beyond executing the code you suggest. The user can't modify your code. So do not suggest incomplete code which requires users to modify. Don't use a code block if it's not intended to be executed by the user.
If you want the user to save the code in a file before executing it, put # filename: <filename> inside the code block as the first line. Don't include multiple code blocks in one response. Do not ask users to copy and paste the result. Instead, use 'print' function for the output when relevant. Check the execution result returned by the user.
If the result indicates there is an error, fix the error and output the code again. Suggest the full code instead of partial code or code changes. If the error can't be fixed or if the task is not solved even after the code is executed successfully, analyze the problem, revisit your assumption, collect additional info you need, and think of a different approach to try.
When you find an answer, verify the answer carefully. Include verifiable evidence in your response if possible.
Reply "TERMINATE" in the end when everything is done.
You have access to the following user defined functions. They can be accessed from the module called `functions` by their function names.
For example, if there was a function called `foo` you could import it by writing `from functions import foo`
def get_stock_prices(stock_symbols, start_date, end_date):
"""Get the stock prices for the given stock symbols between
the start and end dates.
Args:
stock_symbols (str or list): The stock symbols to get the
prices for.
start_date (str): The start date in the format
'YYYY-MM-DD'.
end_date (str): The end date in the format 'YYYY-MM-DD'.
Returns:
pandas.DataFrame: The stock prices for the given stock
symbols indexed by date, with one column per stock
symbol.
"""
...
def plot_stock_prices(stock_prices, filename):
"""Plot the stock prices for the given stock symbols.
Args:
stock_prices (pandas.DataFrame): The stock prices for the
given stock symbols.
"""
...
最后,以OpenAI可以理解的形式构造了一个很大的prompt
2.8 让我们用新的系统消息更新代理
code_writer_agent = ConversableAgent(
name="code_writer_agent",
system_message=code_writer_agent_system_message,
llm_config=llm_config,
code_execution_config=False,
human_input_mode="NEVER",
)
code_executor_agent = ConversableAgent(
name="code_executor_agent",
llm_config=False,
code_execution_config={"executor": executor},
human_input_mode="ALWAYS",
default_auto_reply=
"Please continue. If everything is done, reply 'TERMINATE'.",
)
2.9 执行相同的任务
chat_result = code_executor_agent.initiate_chat(
code_writer_agent,
message=f"Today is {today}."
"Download the stock prices YTD for NVDA and TSLA and create"
"a plot. Make sure the code is in markdown code block and "
"save the figure to a file stock_prices_YTD_plot.png.",
)
输出如下:
code_executor_agent (to code_writer_agent):
Today is 2024-09-30.Download the stock prices YTD for NVDA and TSLA and createa plot. Make sure the code is in markdown code block and save the figure to a file stock_prices_YTD_plot.png.
--------------------------------------------------------------------------------
code_writer_agent (to code_executor_agent):
To accomplish this, the steps we will follow are below:
1. Calculate the start of the year, which would be `2024-01-01`.
2. Use the `get_stock_prices` function to retrieve the stock prices for NVDA and TSLA from `2024-01-01` to `2024-09-30`.
3. Plot the stock prices using the `plot_stock_prices` function and save the plot to a file named `stock_prices_YTD_plot.png`.
Here's the Python code to execute these steps:
# filename: stock_prices_plot.py
from functions import get_stock_prices, plot_stock_prices
import pandas as pd
# Define the stock symbols and the date range
stock_symbols = ["NVDA", "TSLA"]
start_date = "2024-01-01"
end_date = "2024-09-30"
# Fetch the stock prices
stock_prices = get_stock_prices(stock_symbols, start_date, end_date)
# Plot the stock prices and save to a file
plot_stock_prices(stock_prices, filename="stock_prices_YTD_plot.png")
print("Stock prices plot saved as 'stock_prices_YTD_plot.png'")
Please save the above script as `stock_prices_plot.py` and run it using your Python environment. This will fetch the data, create a plot, and save the figure to the specified file.
--------------------------------------------------------------------------------
Provide feedback to code_writer_agent. Press enter to skip and use auto-reply, or type 'exit' to end the conversation:
>>>>>>>> NO HUMAN INPUT RECEIVED.
>>>>>>>> USING AUTO REPLY...
>>>>>>>> EXECUTING CODE BLOCK (inferred language is python)...
code_executor_agent (to code_writer_agent):
exitcode: 0 (execution succeeded)
Code output:
[ 0%% ]
[*********************100%%**********************] 2 of 2 completed
Stock prices plot saved as 'stock_prices_YTD_plot.png'
--------------------------------------------------------------------------------
code_writer_agent (to code_executor_agent):
The task was successfully completed. The stock prices for NVDA and TSLA for the year-to-date have been downloaded, plotted, and the plot was saved as 'stock_prices_YTD_plot.png'.
If you need further assistance or another task, feel free to ask. Otherwise, that concludes the current request.
TERMINATE
--------------------------------------------------------------------------------
Provide feedback to code_writer_agent. Press enter to skip and use auto-reply, or type 'exit' to end the conversation:
>>>>>>>> NO HUMAN INPUT RECEIVED.
>>>>>>>> USING AUTO REPLY...
code_executor_agent (to code_writer_agent):
Please continue. If everything is done, reply 'TERMINATE'.
--------------------------------------------------------------------------------
code_writer_agent (to code_executor_agent):
TERMINATE
--------------------------------------------------------------------------------
Provide feedback to code_writer_agent. Press enter to skip and use auto-reply, or type 'exit' to end the conversation:
>>>>>>>> NO HUMAN INPUT RECEIVED.
绘制结果
Image(os.path.join("coding", "stock_prices_YTD_plot.png"))
输出一下:
3. 总结
本文用两种方式,一种是LLM全自动自行实现写代码和绘制图,另一种是自定义代码,让LLM代理调用执行。两种方式均可实现最后的目标,这种设计模式是一个不错的思路,扩展性非常方便,可根据需求自行调整。