Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add notebook executor as service function and add codeact agent. #231

Merged
merged 58 commits into from
Aug 2, 2024
Merged
Show file tree
Hide file tree
Changes from 52 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
a4bc218
fix minor example bug
Feb 22, 2024
b9f381d
fix single typo
Feb 22, 2024
e88ffad
fix single typo in 105-logging.md
Feb 22, 2024
775913a
Merge remote-tracking branch 'upstream/main'
garyzhang99 Mar 26, 2024
5b082c4
Merge remote-tracking branch 'upstream/main'
garyzhang99 Apr 1, 2024
a396b9b
Merge remote-tracking branch 'upstream/main'
garyzhang99 Apr 7, 2024
ca5d3dc
Merge remote-tracking branch 'upstream/main'
garyzhang99 Apr 12, 2024
67a07c9
Merge remote-tracking branch 'upstream/main'
garyzhang99 Apr 18, 2024
e835e5c
Merge remote-tracking branch 'upstream/main'
garyzhang99 Apr 22, 2024
5fcd43d
Merge remote-tracking branch 'upstream/main'
garyzhang99 Apr 23, 2024
728743b
Merge remote-tracking branch 'upstream/main'
garyzhang99 Apr 24, 2024
ba21e67
Merge remote-tracking branch 'upstream/main'
garyzhang99 Apr 26, 2024
0b936d5
Merge remote-tracking branch 'upstream/main'
garyzhang99 May 8, 2024
b8f54de
Merge remote-tracking branch 'upstream/main'
garyzhang99 May 9, 2024
45a0382
Merge remote-tracking branch 'upstream/main'
garyzhang99 May 10, 2024
61de86f
Merge remote-tracking branch 'upstream/main'
garyzhang99 May 15, 2024
b16a2c7
init notebook service function and codeact agent
garyzhang99 May 17, 2024
0e8d6fa
add notebook dependency in setup.py
garyzhang99 May 17, 2024
3ae6e13
Merge remote-tracking branch 'upstream/main'
garyzhang99 May 17, 2024
a734b17
update example in README
garyzhang99 May 17, 2024
9b8f24a
Merge branch 'main' into dev/service_function
garyzhang99 May 17, 2024
e2bd9ea
Merge remote-tracking branch 'upstream/main'
garyzhang99 May 17, 2024
3cb202c
Merge remote-tracking branch 'upstream/main'
garyzhang99 May 21, 2024
850ca1c
Merge remote-tracking branch 'upstream/main'
garyzhang99 May 22, 2024
4793b86
add nested asyncio
garyzhang99 May 22, 2024
4147541
remove empty blocks
garyzhang99 May 27, 2024
132147d
resolve threads
garyzhang99 May 27, 2024
6658dd5
Merge remote-tracking branch 'upstream/main'
garyzhang99 May 27, 2024
633115c
add example
garyzhang99 May 28, 2024
4ee5516
add more detail in comments
garyzhang99 May 28, 2024
e546ee5
Merge branch 'main' into dev/service_function
garyzhang99 May 28, 2024
4ea7597
Merge remote-tracking branch 'upstream/main'
garyzhang99 May 31, 2024
ef67443
resolve threads
garyzhang99 Jun 4, 2024
b469348
Merge remote-tracking branch 'upstream/main'
garyzhang99 Jun 4, 2024
bc1d5f7
Merge remote-tracking branch 'upstream/main'
garyzhang99 Jun 6, 2024
1bbcf5f
Merge remote-tracking branch 'upstream/main'
garyzhang99 Jun 14, 2024
dc7afcc
Merge remote-tracking branch 'upstream/main'
garyzhang99 Jun 19, 2024
672dc28
Merge remote-tracking branch 'upstream/main'
garyzhang99 Jul 2, 2024
42f54f0
Merge remote-tracking branch 'upstream/main'
garyzhang99 Jul 8, 2024
85416dc
fix dir name typo
garyzhang99 Jul 12, 2024
c1adb7c
Merge remote-tracking branch 'upstream/main'
garyzhang99 Jul 17, 2024
f10ec06
Merge remote-tracking branch 'upstream/main'
garyzhang99 Jul 18, 2024
a3e915d
Merge remote-tracking branch 'upstream/main'
garyzhang99 Jul 23, 2024
522d49a
Merge remote-tracking branch 'upstream/main'
garyzhang99 Jul 25, 2024
dc75410
merge main
garyzhang99 Jul 25, 2024
dcd8da1
using RegexTaggedContentParser
garyzhang99 Jul 25, 2024
d2644ac
fix typo repo
garyzhang99 Jul 25, 2024
56cd47c
Merge remote-tracking branch 'upstream/main'
garyzhang99 Jul 29, 2024
b39e74d
Merge branch 'main' into dev/service_function
garyzhang99 Jul 29, 2024
7c06d2c
fix threads
garyzhang99 Jul 30, 2024
534f30a
add file_manager
garyzhang99 Jul 30, 2024
c6718e9
fix typing and threads
garyzhang99 Jul 30, 2024
d6d83b5
fix threads
garyzhang99 Jul 30, 2024
93f8afb
add test for ipython and update tutorial
garyzhang99 Aug 1, 2024
86c316a
update doc language
garyzhang99 Aug 1, 2024
eaed4b8
add notebook dependency
garyzhang99 Aug 1, 2024
8df0f73
fix precommit
garyzhang99 Aug 2, 2024
460a60d
update test with no print
garyzhang99 Aug 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ the following libraries.
- <img src="https://img.alicdn.com/imgextra/i3/O1CN01SFL0Gu26nrQBFKXFR_!!6000000007707-2-tps-500-500.png" alt="new" width="30" height="30"/>[Conversation with Customized Tools](https://github.com/modelscope/agentscope/blob/main/examples/conversation_with_customized_services/)
- <img src="https://img.alicdn.com/imgextra/i3/O1CN01SFL0Gu26nrQBFKXFR_!!6000000007707-2-tps-500-500.png" alt="new" width="30" height="30"/>[Mixture of Agents Algorithm](https://github.com/modelscope/agentscope/blob/main/examples/conversation_mixture_of_agents/)
- <img src="https://img.alicdn.com/imgextra/i3/O1CN01SFL0Gu26nrQBFKXFR_!!6000000007707-2-tps-500-500.png" alt="new" width="30" height="30"/>[Conversation in Stream Mode](https://github.com/modelscope/agentscope/blob/main/examples/conversation_in_stream_mode/)
- <img src="https://img.alicdn.com/imgextra/i3/O1CN01SFL0Gu26nrQBFKXFR_!!6000000007707-2-tps-500-500.png" alt="new" width="30" height="30"/>[Conversation with CodeAct Agent](https://github.com/modelscope/agentscope/blob/main/examples/conversation_with_codeact_agent/)


- Game
- [Gomoku](https://github.com/modelscope/agentscope/blob/main/examples/game_gomoku)
Expand Down
4 changes: 4 additions & 0 deletions README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,14 @@ AgentScope支持使用以下库快速部署本地模型服务。
- [通过对话查询SQL信息](./examples/conversation_nl2sql/)
- [与RAG智能体对话](./examples/conversation_with_RAG_agents)
- <img src="https://img.alicdn.com/imgextra/i3/O1CN01SFL0Gu26nrQBFKXFR_!!6000000007707-2-tps-500-500.png" alt="new" width="30" height="30"/>[与gpt-4o模型对话](./examples/conversation_with_gpt-4o)
- <img src="https://img.alicdn.com/imgextra/i3/O1CN01SFL0Gu26nrQBFKXFR_!!6000000007707-2-tps-500-500.png" alt="new" width="30" height="30"/>[与自定义服务对话](./examples/conversation_with_customized_services/)

- <img src="https://img.alicdn.com/imgextra/i3/O1CN01SFL0Gu26nrQBFKXFR_!!6000000007707-2-tps-500-500.png" alt="new" width="30" height="30"/>[与SoftWare Engineering智能体对话](./examples/conversation_with_swe-agent/)
- <img src="https://img.alicdn.com/imgextra/i3/O1CN01SFL0Gu26nrQBFKXFR_!!6000000007707-2-tps-500-500.png" alt="new" width="30" height="30"/>[自定义工具函数](./examples/conversation_with_customized_services/)
- <img src="https://img.alicdn.com/imgextra/i3/O1CN01SFL0Gu26nrQBFKXFR_!!6000000007707-2-tps-500-500.png" alt="new" width="30" height="30"/>[Mixture of Agents算法](https://github.com/modelscope/agentscope/blob/main/examples/conversation_mixture_of_agents/)
- <img src="https://img.alicdn.com/imgextra/i3/O1CN01SFL0Gu26nrQBFKXFR_!!6000000007707-2-tps-500-500.png" alt="new" width="30" height="30"/>[流式对话](https://github.com/modelscope/agentscope/blob/main/examples/conversation_in_stream_mode/)
- <img src="https://img.alicdn.com/imgextra/i3/O1CN01SFL0Gu26nrQBFKXFR_!!6000000007707-2-tps-500-500.png" alt="new" width="30" height="30"/>[与CodeAct智能体对话](https://github.com/modelscope/agentscope/blob/main/examples/conversation_with_codeact_agent/)


- 游戏
- [五子棋](./examples/game_gomoku)
Expand Down
166 changes: 166 additions & 0 deletions examples/conversation_with_codeact_agent/codeact_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# -*- coding: utf-8 -*-
# pylint: disable=C0301
"""An agent class that implements the CodeAct agent.
This agent can execute code interactively as actions.
More details can be found at the paper of codeact agent
https://arxiv.org/abs/2402.01030
and the original repo of codeact https://github.com/xingyaoww/code-act
"""
from agentscope.agents import AgentBase
from agentscope.message import Msg
from agentscope.service import (
ServiceResponse,
ServiceExecStatus,
NoteBookExecutor,
)
from agentscope.parsers import RegexTaggedContentParser

SYSTEM_MESSAGE = """system
garyzhang99 marked this conversation as resolved.
Show resolved Hide resolved
You are a helpful assistant that gives helpful, detailed, and polite answers to the user's questions.
You should interact with the interactive Python (Jupyter Notebook) environment and receive the corresponding output when needed. The code written by assistant should be enclosed using <execute> tag, for example: <execute> print('Hello World!') </execute>.
You should attempt fewer things at a time instead of putting too much code in one <execute> block. You can install packages through PIP by <execute> !pip install [package needed] </execute> and should always import packages and define variables before starting to use them.
You should stop <execute> and provide an answer when they have already obtained the answer from the execution result. Whenever possible, execute the code for the user using <execute> instead of providing it.
Your response should be concise, but do express their thoughts. Always write the code in <execute> block to execute them.
You should not ask for the user's input unless necessary. Solve the task on your own and leave no unanswered questions behind.
You should do every thing by your self.
""" # noqa

EXAMPLE_MESSAGE = """
Additionally, you are provided with the following code available:
{example_code}
The above code is already available in your interactive Python (Jupyter Notebook) environment, allowing you to directly use these variables and functions without needing to redeclare them.
""" # noqa


class CodeActAgent(AgentBase):
"""
The implementation of CodeAct-agent.
The agent can execute code interactively as actions.
More details can be found at the paper of codeact agent
https://arxiv.org/abs/2402.01030
and the original repo of codeact https://github.com/xingyaoww/code-act
"""

def __init__(
self,
name: str,
model_config_name: str,
example_code: str = "",
) -> None:
"""
Initialize the CodeActAgent.
Args:
name(`str`):
The name of the agent.
model_config_name(`str`):
The name of the model configuration.
example_code(Optional`str`):
The example code to be executed bewfore the interaction.
You can import reference libs, define variables
and functions to be called. For example:

```python
from agentscope.service import bing_search
import os

api_key = "{YOUR_BING_API_KEY}"

def search(question: str):
return bing_search(question, api_key=api_key, num_results=3).content
```

""" # noqa
super().__init__(
name=name,
model_config_name=model_config_name,
)
self.n_max_executions = 5
self.example_code = example_code
self.code_executor = NoteBookExecutor()

sys_msg = Msg(name="system", role="system", content=SYSTEM_MESSAGE)
example_msg = Msg(
name="user",
role="user",
content=EXAMPLE_MESSAGE.format(example_code=self.example_code),
)

self.memory.add(sys_msg)

if self.example_code != "":
code_execution_result = self.code_executor.run_code_on_notebook(
self.example_code,
)
code_exec_msg = self.handle_code_result(
code_execution_result,
"Example Code excuted: ",
)
self.memory.add(example_msg)
self.memory.add(code_exec_msg)
self.speak(code_exec_msg)

self.parser = RegexTaggedContentParser(try_parse_json=False)

def handle_code_result(
self,
code_execution_result: ServiceResponse,
content_pre_sring: str = "",
) -> Msg:
"""return the message from code result"""
code_exec_content = content_pre_sring
if code_execution_result.status == ServiceExecStatus.SUCCESS:
code_exec_content += "Excution Successful:\n"
else:
code_exec_content += "Excution Failed:\n"
code_exec_content += "Execution Output:\n" + str(
code_execution_result.content,
)
return Msg(name="user", role="user", content=code_exec_content)
garyzhang99 marked this conversation as resolved.
Show resolved Hide resolved

def reply(self, x: Msg = None) -> Msg:
"""The reply function that implements the codeact agent."""

self.memory.add(x)

excution_count = 0
while (
self.memory.get_memory(1)[-1].role == "user"
garyzhang99 marked this conversation as resolved.
Show resolved Hide resolved
and excution_count < self.n_max_executions
):
prompt = self.model.format(self.memory.get_memory())
model_res = self.model(prompt)
msg_res = Msg(
name=self.name,
content=model_res.text,
role="assistant",
)
self.memory.add(msg_res)
self.speak(msg_res)
res = self.parser.parse(model_res)
code = res.parsed.get("execute")
if code is not None:
code = code.strip()
code_execution_result = (
self.code_executor.run_code_on_notebook(code)
)
excution_count += 1
code_exec_msg = self.handle_code_result(code_execution_result)
self.memory.add(code_exec_msg)
self.speak(code_exec_msg)

if excution_count == self.n_max_executions:
assert self.memory.get_memory(1)[-1].role == "user"
code_max_exec_msg = Msg(
name="assitant",
role="assistant",
content=(
"I have reached the maximum number "
f"of executions ({self.n_max_executions=}). "
"Can you assist me or ask me another question?"
),
)
self.memory.add(code_max_exec_msg)
self.speak(code_max_exec_msg)
return code_max_exec_msg

return msg_res
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Conversation with CodeAct Agent\n",
"\n",
"CodeAct agent is an agent that not only chats but also writes and executes Python code for you.\n",
"More details can be found in the project's related [github repo](https://github.com/xingyaoww/code-act). In the example here, we implement the CodeAct agent, and provide a simple example of how to use the CodeAct agent.\n",
"\n",
"## Prerequisites\n",
"\n",
"- Follow [READMD.md](https://github.com/modelscope/agentscope) to install AgentScope. We require the lastest version, so you should build from source by running `pip install -e .` instead of intalling from pypi. \n",
"- Prepare a model configuration. AgentScope supports both local deployed model services (CPU or GPU) and third-party services. More details and example model configurations please refer to our [tutorial](https://modelscope.github.io/agentscope/en/tutorial/203-model.html).\n",
"\n",
"## Note\n",
"- The example is tested with the following models. For other models, you may need to adjust the prompt.\n",
" - qwen-max"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"YOUR_MODEL_CONFIGURATION_NAME = \"{YOUR_MODEL_CONFIGURATION_NAME}\"\n",
"\n",
"YOUR_MODEL_CONFIGURATION = {\n",
" \"model_type\": \"xxx\", \n",
" \"config_name\": YOUR_MODEL_CONFIGURATION_NAME\n",
" \n",
" # ...\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Step 1: Initalize the CodeAct-agent\n",
"\n",
"Here we load the CodeAct agent."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from codeact_agent import CodeActAgent\n",
"\n",
"import agentscope\n",
"\n",
"agentscope.init(model_configs=YOUR_MODEL_CONFIGURATION)\n",
"\n",
"import nest_asyncio\n",
garyzhang99 marked this conversation as resolved.
Show resolved Hide resolved
"nest_asyncio.apply()\n",
"agent = CodeActAgent(\n",
" name=\"assistant\",\n",
" model_config_name=YOUR_MODEL_CONFIGURATION_NAME,\n",
")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"###Step 2: Ask the CodeAct-agent to execute tasks\n",
"\n",
"Here, we ask the CodeAct-agent to implement a statistical simulation and modeling procedure."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2024-05-16 19:48:01.620 | INFO | agentscope.models.model:__init__:201 - Initialize model by configuration [dashscope_chat-qwen-max]\n",
"2024-05-16 19:48:01.624 | INFO | agentscope.utils.monitor:register:417 - Register metric [qwen-max.call_counter] to SqliteMonitor with unit [times] and quota [None]\n",
"2024-05-16 19:48:01.627 | INFO | agentscope.utils.monitor:register:417 - Register metric [qwen-max.prompt_tokens] to SqliteMonitor with unit [token] and quota [None]\n",
"2024-05-16 19:48:01.630 | INFO | agentscope.utils.monitor:register:417 - Register metric [qwen-max.completion_tokens] to SqliteMonitor with unit [token] and quota [None]\n",
"2024-05-16 19:48:01.632 | INFO | agentscope.utils.monitor:register:417 - Register metric [qwen-max.total_tokens] to SqliteMonitor with unit [token] and quota [None]\n",
"user: Given y = 0.9x + 6.1, randomly sample data points as pairs of (x, y). Then fit a linear regression on the sampled data and plot the points, fitted line, and ground-truth line.\n",
"assistant: To accomplish this task, I will follow these steps:\n",
"\n",
"1. Generate random `x` values within a reasonable range.\n",
"2. Use the equation `y = 0.9x + 6.1` to compute the corresponding `y` values for each `x`.\n",
"3. Add some noise to the `y` values to simulate real-world data variability.\n",
"4. Split the data into training and testing sets (though for simplicity and since you didn't specify, we'll just use all the data for fitting).\n",
"5. Fit a linear regression model on the generated data.\n",
"6. Plot the original data points, the fitted line from the regression, and the ground-truth line.\n",
"\n",
"Let's start by generating the data points and fitting the regression model.\n",
"\n",
"[execute]\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from sklearn.linear_model import LinearRegression\n",
"\n",
"# Set a seed for reproducibility\n",
"np.random.seed(42)\n",
"\n",
"# Generate random x values between 0 and 100\n",
"x_values = np.random.rand(100) * 100\n",
"\n",
"# Compute the corresponding y values without noise\n",
"y_values_ground_truth = 0.9 * x_values + 6.1\n",
"\n",
"# Add some noise to y values\n",
"noise = np.random.normal(0, 10, size=x_values.shape)\n",
"y_values_noisy = y_values_ground_truth + noise\n",
"\n",
"# Combine into a single dataset\n",
"data = np.column_stack((x_values, y_values_noisy))\n",
"\n",
"# Fit a linear regression model\n",
"model = LinearRegression()\n",
"model.fit(data[:, 0].reshape(-1, 1), data[:, 1])\n",
"\n",
"# Prepare to plot\n",
"plt.figure(figsize=(10, 6))\n",
"[/execute]\n",
"user: Execution Output:\n",
"['<Figure size 1000x600 with 0 Axes>', 'Unsupported display type']\n",
"assistant: It seems there was an issue with displaying the plot directly here. No worries, I will still generate the plot and save it to a file instead, which you can view separately. Let me adjust the code to save the plot as an image file.\n",
"\n",
"[execute]\n",
"# Plotting the data points, fitted line, and ground-truth line\n",
"plt.scatter(data[:, 0], data[:, 1], label='Sampled Data', color='blue')\n",
"plt.plot(data[:, 0], model.predict(data[:, 0].reshape(-1, 1)), label='Fitted Line', color='red', linestyle='--')\n",
"plt.plot(data[:, 0], y_values_ground_truth, label='Ground-Truth Line', color='green')\n",
"\n",
"plt.title('Linear Regression on Sampled Data')\n",
"plt.xlabel('X')\n",
"plt.ylabel('Y')\n",
"plt.legend()\n",
"plt.grid(True)\n",
"\n",
"# Save the plot to a file\n",
"plt.savefig('linear_regression_plot.png')\n",
"plt.close()\n",
"[/execute]\n",
"\n",
"The plot has been saved as 'linear_regression_plot.png'. You can view this file to see the sampled data points, the fitted line from the linear regression, and the ground-truth line based on the equation `y = 0.9x + 6.1`. If you need further analysis or have any other requests, feel free to ask!\n",
"user: Execution Output:\n",
"[]\n",
"assistant: It appears the output confirmation was suppressed in this environment, but typically, when running the code locally or in a supported environment, you would see a message indicating the plot was successfully saved to 'linear_regression_plot.png'.\n",
"\n",
"Since we cannot directly view the saved file here, trust that the file has been created with the following components:\n",
"\n",
"- **Sampled Data Points**: Represented as blue dots, scattered according to the generated `x` values and the noisy `y` values.\n",
"- **Fitted Line**: Shown as a red dashed line, representing the linear regression model's prediction based on the sampled data.\n",
"- **Ground-Truth Line**: Displayed as a green line, illustrating the true relationship defined by `y = 0.9x + 6.1`.\n",
"\n",
"If you need further assistance or another operation, such as analyzing the quality of the fit or re-running the process with different parameters, please let me know!\n"
]
}
],
"source": [
"from loguru import logger\n",
"from agentscope.message import Msg\n",
"\n",
"mss = Msg(\n",
" name=\"user\", \n",
" content=\"Given y = 0.9x + 6.1, randomly sample data points as pairs of (x, y). Then fit a linear regression on the sampled data and plot the points, fitted line, and ground-truth line.\", \n",
" role=\"user\"\n",
")\n",
"logger.chat(mss)\n",
"answer_mss1 = agent(mss)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "datajuicer",
garyzhang99 marked this conversation as resolved.
Show resolved Hide resolved
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.18"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Loading