init
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Your complete code here.
|
||||
101
AlgoriAgent/examples/0_jupyter_example_template/main.ipynb
Normal file
101
AlgoriAgent/examples/0_jupyter_example_template/main.ipynb
Normal file
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# Your Example Title Here\n",
|
||||
"\n",
|
||||
"This example will show\n",
|
||||
"- How to ...\n",
|
||||
"- How to ...\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## Background (If needed)\n",
|
||||
"\n",
|
||||
"The background of your example here. \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## Tested Models\n",
|
||||
"\n",
|
||||
"These models are tested in this example. For other models, some modifications may be needed. \n",
|
||||
"- xxx\n",
|
||||
"- xxx \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## Prerequisites\n",
|
||||
"\n",
|
||||
"Fill the next cell to meet the following requirements \n",
|
||||
"- The requirements to execute this example\n",
|
||||
"- ...\n",
|
||||
"- [Optional] Optional requirements\n",
|
||||
"- ...\n"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "5f0c2fc19efe575e"
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# The prerequisites, e.g.\n",
|
||||
"bing_api_key = \"xxx\"\n",
|
||||
"\n",
|
||||
"your_model_configuration_name = \"xxx\"\n",
|
||||
"\n",
|
||||
"your_model_configuration = {\n",
|
||||
" \"model_type\": \"xxx\", \n",
|
||||
" \"config_name\": your_model_configuration_name,\n",
|
||||
" \n",
|
||||
" # ...\n",
|
||||
"}"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"is_executing": true
|
||||
},
|
||||
"id": "596cca552b163051"
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"outputs": [],
|
||||
"source": [],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "966b96e4893709a5"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "7cbb4630bf5e2c15"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 2
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython2",
|
||||
"version": "2.7.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
26
AlgoriAgent/examples/0_python_example_template/README.md
Normal file
26
AlgoriAgent/examples/0_python_example_template/README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Your Example Title Here
|
||||
|
||||
This example will show
|
||||
- How to ...
|
||||
- How to ...
|
||||
|
||||
|
||||
## Background (If needed)
|
||||
|
||||
The background of your example here.
|
||||
|
||||
|
||||
## Tested Models
|
||||
|
||||
These models are tested in this example. For other models, some modifications may be needed.
|
||||
- xxx
|
||||
- xxx
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Fill the next cell to meet the following requirements
|
||||
- The requirements to execute this example
|
||||
- ...
|
||||
- [Optional] Optional requirements
|
||||
- ...
|
||||
2
AlgoriAgent/examples/0_python_example_template/main.py
Normal file
2
AlgoriAgent/examples/0_python_example_template/main.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Your complete code here.
|
||||
21
AlgoriAgent/examples/conversation_basic/README.md
Normal file
21
AlgoriAgent/examples/conversation_basic/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Multi-Agent Conversation in AgentScope
|
||||
|
||||
This example will show how to program a multi-agent conversation in AgentScope.
|
||||
Complete code is in `conversation.py`, which set up a user agent and an
|
||||
assistant agent to have a conversation. When user input "exit", the
|
||||
conversation ends.
|
||||
You can modify the `sys_prompt` to change the role of assistant agent.
|
||||
```bash
|
||||
# Note: Set your api_key in conversation.py first
|
||||
python conversation.py
|
||||
```
|
||||
## Tested Models
|
||||
|
||||
These models are tested in this example. For other models, some modifications may be needed.
|
||||
- dashscope_chat (qwen-max)
|
||||
- ollama_chat (ollama_llama3_8b)
|
||||
- gemini_chat (models/gemini-pro)
|
||||
|
||||
## Prerequisites
|
||||
To set up model serving with open-source LLMs, follow the guidance in
|
||||
[scripts/REAMDE.md](../../scripts/README.md).
|
||||
49
AlgoriAgent/examples/conversation_basic/conversation.py
Normal file
49
AlgoriAgent/examples/conversation_basic/conversation.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""A simple example for conversation between user and assistant agent."""
|
||||
import agentscope
|
||||
from agentscope.agents import DialogAgent
|
||||
from agentscope.agents.user_agent import UserAgent
|
||||
from agentscope.pipelines.functional import sequentialpipeline
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""A basic conversation demo"""
|
||||
|
||||
agentscope.init(
|
||||
model_configs=[
|
||||
{
|
||||
"model_type": "openai_chat",
|
||||
"config_name": "gpt-3.5-turbo",
|
||||
"model_name": "gpt-3.5-turbo",
|
||||
"api_key": "xxx", # Load from env if not provided
|
||||
"organization": "xxx", # Load from env if not provided
|
||||
"generate_args": {
|
||||
"temperature": 0.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
"model_type": "post_api_chat",
|
||||
"config_name": "my_post_api",
|
||||
"api_url": "https://xxx",
|
||||
"headers": {},
|
||||
},
|
||||
],
|
||||
project="Multi-Agent Conversation",
|
||||
)
|
||||
|
||||
# Init two agents
|
||||
dialog_agent = DialogAgent(
|
||||
name="Assistant",
|
||||
sys_prompt="You're a helpful assistant.",
|
||||
model_config_name="gpt-3.5-turbo", # replace by your model config name
|
||||
)
|
||||
user_agent = UserAgent()
|
||||
|
||||
# start the conversation between user and assistant
|
||||
x = None
|
||||
while x is None or x.content != "exit":
|
||||
x = sequentialpipeline([dialog_agent, user_agent], x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,22 @@
|
||||
[
|
||||
{
|
||||
"config_name": "gpt-3.5-turbo",
|
||||
"model_type": "openai-chat",
|
||||
"model_name": "gpt-3.5-turbo",
|
||||
"api_key": "xxx",
|
||||
"organization": "xxx",
|
||||
"generate_args": {
|
||||
"temperature": 0.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "gpt-4",
|
||||
"model_type": "openai-chat",
|
||||
"model_name": "gpt-4",
|
||||
"api_key": "xxx",
|
||||
"organization": "xxx",
|
||||
"generate_args": {
|
||||
"temperature": 0.5
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,85 @@
|
||||
PRAGMA foreign_keys = ON;
|
||||
|
||||
|
||||
CREATE TABLE "stadium" (
|
||||
"Stadium_ID" int,
|
||||
"Location" text,
|
||||
"Name" text,
|
||||
"Capacity" int,
|
||||
"Highest" int,
|
||||
"Lowest" int,
|
||||
"Average" int,
|
||||
PRIMARY KEY ("Stadium_ID")
|
||||
);
|
||||
|
||||
|
||||
INSERT INTO "stadium" VALUES (1,"Raith Rovers","Stark's Park","10104","4812","1294","2106");
|
||||
INSERT INTO "stadium" VALUES (2,"Ayr United","Somerset Park","11998","2363","1057","1477");
|
||||
INSERT INTO "stadium" VALUES (3,"East Fife","Bayview Stadium","2000","1980","533","864");
|
||||
INSERT INTO "stadium" VALUES (4,"Queen's Park","Hampden Park","52500","1763","466","730");
|
||||
INSERT INTO "stadium" VALUES (5,"Stirling Albion","Forthbank Stadium","3808","1125","404","642");
|
||||
INSERT INTO "stadium" VALUES (6,"Arbroath","Gayfield Park","4125","921","411","638");
|
||||
INSERT INTO "stadium" VALUES (7,"Alloa Athletic","Recreation Park","3100","1057","331","637");
|
||||
INSERT INTO "stadium" VALUES (9,"Peterhead","Balmoor","4000","837","400","615");
|
||||
INSERT INTO "stadium" VALUES (10,"Brechin City","Glebe Park","3960","780","315","552");
|
||||
|
||||
CREATE TABLE "singer" (
|
||||
"Singer_ID" int,
|
||||
"Name" text,
|
||||
"Country" text,
|
||||
"Song_Name" text,
|
||||
"Song_release_year" text,
|
||||
"Age" int,
|
||||
"Is_male" bool,
|
||||
PRIMARY KEY ("Singer_ID")
|
||||
);
|
||||
|
||||
|
||||
|
||||
INSERT INTO "singer" VALUES (1,"Joe Sharp","Netherlands","You","1992",52,"F");
|
||||
INSERT INTO "singer" VALUES (2,"Timbaland","United States","Dangerous","2008",32,"T");
|
||||
INSERT INTO "singer" VALUES (3,"Justin Brown","France","Hey Oh","2013",29,"T");
|
||||
INSERT INTO "singer" VALUES (4,"Rose White","France","Sun","2003",41,"F");
|
||||
INSERT INTO "singer" VALUES (5,"John Nizinik","France","Gentleman","2014",43,"T");
|
||||
INSERT INTO "singer" VALUES (6,"Tribal King","France","Love","2016",25,"T");
|
||||
|
||||
|
||||
CREATE TABLE "concert" (
|
||||
"concert_ID" int,
|
||||
"concert_Name" text,
|
||||
"Theme" text,
|
||||
"Stadium_ID" text,
|
||||
"Year" text,
|
||||
PRIMARY KEY ("concert_ID"),
|
||||
FOREIGN KEY ("Stadium_ID") REFERENCES "stadium"("Stadium_ID")
|
||||
);
|
||||
|
||||
|
||||
|
||||
INSERT INTO "concert" VALUES (1,"Auditions","Free choice",1,2014);
|
||||
INSERT INTO "concert" VALUES (2,"Super bootcamp","Free choice 2",2,2014);
|
||||
INSERT INTO "concert" VALUES (3,"Home Visits","Bleeding Love",2,2015);
|
||||
INSERT INTO "concert" VALUES (4,"Week 1","Wide Awake",10,2014);
|
||||
INSERT INTO "concert" VALUES (5,"Week 1","Happy Tonight",9,2015);
|
||||
INSERT INTO "concert" VALUES (6,"Week 2","Party All Night",7,2015);
|
||||
|
||||
|
||||
CREATE TABLE "singer_in_concert" (
|
||||
"concert_ID" int,
|
||||
"Singer_ID" text,
|
||||
PRIMARY KEY ("concert_ID","Singer_ID"),
|
||||
FOREIGN KEY ("concert_ID") REFERENCES "concert"("concert_ID"),
|
||||
FOREIGN KEY ("Singer_ID") REFERENCES "singer"("Singer_ID")
|
||||
);
|
||||
|
||||
INSERT INTO "singer_in_concert" VALUES (1, 2);
|
||||
INSERT INTO "singer_in_concert" VALUES (1, 3);
|
||||
INSERT INTO "singer_in_concert" VALUES (1, 5);
|
||||
INSERT INTO "singer_in_concert" VALUES (2, 3);
|
||||
INSERT INTO "singer_in_concert" VALUES (2, 6);
|
||||
INSERT INTO "singer_in_concert" VALUES (3, 5);
|
||||
INSERT INTO "singer_in_concert" VALUES (4, 4);
|
||||
INSERT INTO "singer_in_concert" VALUES (5, 6);
|
||||
INSERT INTO "singer_in_concert" VALUES (5, 3);
|
||||
INSERT INTO "singer_in_concert" VALUES (6, 2);
|
||||
|
||||
File diff suppressed because one or more lines are too long
498
AlgoriAgent/examples/conversation_nl2sql/react_nl2sql.ipynb
Normal file
498
AlgoriAgent/examples/conversation_nl2sql/react_nl2sql.ipynb
Normal file
@@ -0,0 +1,498 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Convert Natural Language to SQL Query with ReAct Agent\n",
|
||||
"\n",
|
||||
"This notebook will show \n",
|
||||
"- how to use ReAct agent to convert natural language to SQL query\n",
|
||||
"- how to use a customized NL2SQL algorithm, DAIL-SQL, in AgentScope \n",
|
||||
"\n",
|
||||
"## Background\n",
|
||||
"\n",
|
||||
"NL2SQl is a challenging task in both database and natural language processing communities. It aims to convert natural language question into SQL query. In research community, there are many works exploring the potential of LLMs in NL2SQL, and it would be very interesting to explore this task with LLM-empowered agents. \n",
|
||||
"\n",
|
||||
"In this notebook, we try to equip the ReAct agent with a SOTA NL2SQL algorithm, DAIL-SQL, to see if the agent-level reasoning could bring any insights to this task. The implementation of DAIL-SQL refer to its [GitHub repository](https://github.com/BeachWang/DAIL-SQL) and [paper](https://arxiv.org/abs/2308.15363).\n",
|
||||
"\n",
|
||||
"## Prerequisites\n",
|
||||
"\n",
|
||||
"- Follow [READMD.md](https://github.com/modelscope/agentscope) to install AgentScope.\n",
|
||||
"- Install the third-party libraries used in [DAIL-SQL](https://github.com/BeachWang/DAIL-SQL/blob/main/requirements.txt).\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",
|
||||
"- Get familiar with service functions, ServiceToolkit module and build-in ReAct agent. The corresponding example can be found in [ReAct agent example](../conversation_with_react_agent/main.ipynb).\n",
|
||||
"\n",
|
||||
"## Note\n",
|
||||
"\n",
|
||||
"- The example is tested with the following models. For other models, you may need to adjust the prompt.\n",
|
||||
" - gpt-4 (The model that [DAIL-SQL](https://github.com/BeachWang/DAIL-SQL) is built on)\n",
|
||||
" - gpt-3.5-turbo "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 1: Initializing model config and SQL database\n",
|
||||
"First, we initalize the agentscope config and load the corresponding model."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import Callable\n",
|
||||
"import agentscope\n",
|
||||
"from agentscope.models import load_model_by_config_name\n",
|
||||
"agentscope.init(\n",
|
||||
" model_configs=\"./configs/model_configs.json\",\n",
|
||||
" project=\"Conversation with NL2SQL\",\n",
|
||||
")\n",
|
||||
"loaded_model = load_model_by_config_name('gpt-4')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Then, we init and provide the corresponding database path in sqlite file format.\n",
|
||||
"Here we generate the sqlite file using the provided sql commands [here](./database/concert_singer/schema.sql). \n",
|
||||
"You can also use the .sqlite format file directly."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sql_utils import create_sqlite_db_from_schema\n",
|
||||
"example_db_id = \"concert_singer\"\n",
|
||||
"db_schema_path = \"./database/concert_singer/schema.sql\"\n",
|
||||
"db_sqlite_path = \"./database/concert_singer/concert_singer.sqlite\"\n",
|
||||
"create_sqlite_db_from_schema(db_schema_path, db_sqlite_path)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We can show a general description of the database schema using the code below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"The database consists of four tables: \n",
|
||||
"\n",
|
||||
"1. Stadium: This table includes the following fields: Stadium_ID (which is the primary key), Location, Name, Capacity, Highest, Lowest, and Average.\n",
|
||||
"\n",
|
||||
"2. Singer: This table includes the following fields: Singer_ID (which is the primary key), Name, Country, Song_Name, Song_release_year, Age, and Is_male (a Boolean field that indicates the singer's gender).\n",
|
||||
"\n",
|
||||
"3. Concert: This table is linked to the Stadium table via the Stadium_ID field. The table includes the fields concert_ID (which is the primary key), concert_Name, Theme, Stadium_ID, and Year.\n",
|
||||
"\n",
|
||||
"4. Singer_in_Concert: This table acts as a junction table to establish a many-to-many relationship between the Singer and Concert tables. It includes the fields concert_ID and Singer_ID, which both make up the primary key for the table. These are also reference as foreign keys to their respective basetable: the Concert table via the concert_ID field, and the Singer table via the Singer_ID field.\n",
|
||||
"\n",
|
||||
"In summary, this database seems designed to track concerts, including details about singers, the concert's location (stadium), and which singer performed at which concert.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from loguru import logger\n",
|
||||
"from sql_utils import SQLPrompt\n",
|
||||
"describe_prompt = SQLPrompt().describe_schema(db_sqlite_path)\n",
|
||||
"sql_description = loaded_model([{\"role\": \"assistant\", \"content\": describe_prompt}]).text\n",
|
||||
"logger.chat(sql_description)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Setting up tool functions\n",
|
||||
"Then, we define the tools needed for React Agent to perform SQL query. Namely, our agent should be able to generate sql query given natural language and perform sql query to get the result.\n",
|
||||
"\n",
|
||||
"- We referenced a third-party Text-to-SQL [DAIL-SQL](https://github.com/BeachWang/DAIL-SQL) to generate Text-to-SQL prompt.\n",
|
||||
"- We use the query_sqlite service function in the agentscope.service module. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from agentscope.service import (\n",
|
||||
" ServiceResponse, \n",
|
||||
" ServiceExecStatus, \n",
|
||||
" ServiceToolkit, \n",
|
||||
" query_sqlite,\n",
|
||||
")\n",
|
||||
"from sql_utils import DailSQLPromptGenerator\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def generate_sql_query(question: str, db_path: str, model: Callable) -> ServiceResponse:\n",
|
||||
" \"\"\"\n",
|
||||
" Generate the sql query based on the natural language question from user.\n",
|
||||
" \n",
|
||||
" Args:\n",
|
||||
" question (`str`):\n",
|
||||
" The question asked by user in natural language.\n",
|
||||
" db_path (`str`):\n",
|
||||
" The path to the .sqlite file.\n",
|
||||
" model (`Callable`):\n",
|
||||
" The LLM model used to generate the SQL query.\n",
|
||||
" \"\"\"\n",
|
||||
" prompt_helper = DailSQLPromptGenerator(db_path)\n",
|
||||
" prepared_prompt = prompt_helper.generate_prompt({\"content\": question})\n",
|
||||
" \n",
|
||||
" def get_response_from_prompt(prompt: dict, model: Callable) -> str:\n",
|
||||
" \"\"\"\n",
|
||||
" Generate response from prompt using LLM\n",
|
||||
" \"\"\"\n",
|
||||
" messages = [{\"role\": \"assistant\", \"content\": prompt}]\n",
|
||||
" sql = model(messages).text\n",
|
||||
" sql = \" \".join(sql.replace(\"\\n\", \" \").split())\n",
|
||||
" sql = sql.strip().split(\"/*\")[0]\n",
|
||||
" if sql.startswith(\"SELECT\"):\n",
|
||||
" response = sql + \"\\n\"\n",
|
||||
" elif sql.startswith(\" \"):\n",
|
||||
" response = \"SELECT\" + sql + \"\\n\"\n",
|
||||
" else:\n",
|
||||
" response = \"SELECT \" + sql + \"\\n\"\n",
|
||||
" return response\n",
|
||||
"\n",
|
||||
" sql_response = get_response_from_prompt(\n",
|
||||
" prepared_prompt[\"prompt\"], model=model\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" return ServiceResponse(\n",
|
||||
" ServiceExecStatus.SUCCESS,\n",
|
||||
" sql_response\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Use Service Toolkit to set up tool functions for LLMs\n",
|
||||
"service_toolkit = ServiceToolkit()\n",
|
||||
"service_toolkit.add(generate_sql_query, db_path=db_sqlite_path, model=loaded_model)\n",
|
||||
"service_toolkit.add(query_sqlite, database=db_sqlite_path)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Create the ReAct agent to help perform SQL queries\n",
|
||||
"\n",
|
||||
"Now, we can init the ReAct Agent using the defined tools and interact with the agent."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from agentscope.agents import ReActAgent\n",
|
||||
"agent = ReActAgent(\n",
|
||||
" name=\"assistant\",\n",
|
||||
" model_config_name='gpt-4',\n",
|
||||
" service_toolkit=service_toolkit,\n",
|
||||
" sys_prompt=\"You are a helpful agent that preform SQL queries base on natual language instructions.\",\n",
|
||||
" verbose=True, # set verbose to True to show the reasoning process\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 4: Interact with the SQL ReAct Agent using natural lanugage\n",
|
||||
"\n",
|
||||
"Now let's see how the agent have response to our questions:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"user: How many singers do we have?\n",
|
||||
"##################### ITER 1, STEP 1: REASONING ######################\n",
|
||||
"assistant: {\n",
|
||||
" \"thought\": \"To answer the user's question, I need to find out how many unique singers are listed in the database. I will use the generate_sql_query function to create a SQL query to count distinct singers.\",\n",
|
||||
" \"speak\": \"Let me find this information for you.\",\n",
|
||||
" \"function\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"generate_sql_query\",\n",
|
||||
" \"arguments\": {\n",
|
||||
" \"question\": \"How many unique singers are we have in the database?\"\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"####################### ITER 1, STEP 2: ACTION #######################\n",
|
||||
">>> Executing function generate_sql_query ...\n",
|
||||
">>> END \n",
|
||||
"system: Execution Results:\n",
|
||||
"1. generate_sql_query:\n",
|
||||
" [EXECUTE STATUS]: SUCCESS\n",
|
||||
" [EXECUTE RESULT]: SELECT To find out how many unique singers are in the database, you would need to count the distinct singer IDs in the \"singer\" table. The appropriate SQL query for this would be: ```sql SELECT COUNT(DISTINCT Singer_ID) FROM singer; ```\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"##################### ITER 2, STEP 1: REASONING ######################\n",
|
||||
"assistant: {\n",
|
||||
" \"thought\": \"The generate_sql_query function has provided the necessary SQL query. Now I will use the query_sqlite function to execute this query and retrieve the count of unique singers.\",\n",
|
||||
" \"speak\": \"I'm now running the query to count the number of unique singers in the database.\",\n",
|
||||
" \"function\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"query_sqlite\",\n",
|
||||
" \"arguments\": {\n",
|
||||
" \"allow_change_data\": false,\n",
|
||||
" \"query\": \"SELECT COUNT(DISTINCT Singer_ID) FROM singer;\"\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"####################### ITER 2, STEP 2: ACTION #######################\n",
|
||||
">>> Executing function query_sqlite ...\n",
|
||||
">>> END \n",
|
||||
"system: Execution Results:\n",
|
||||
"1. query_sqlite:\n",
|
||||
" [EXECUTE STATUS]: SUCCESS\n",
|
||||
" [EXECUTE RESULT]: [(6,)]\n",
|
||||
"\n",
|
||||
"##################### ITER 3, STEP 1: REASONING ######################\n",
|
||||
"assistant: {\n",
|
||||
" \"thought\": \"I successfully executed the query to count the distinct singers in the database and received the result.\",\n",
|
||||
" \"speak\": \"We have 6 unique singers in the database.\",\n",
|
||||
" \"function\": []\n",
|
||||
"}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from agentscope.message import Msg\n",
|
||||
"\n",
|
||||
"mss = Msg(\n",
|
||||
" name=\"user\", \n",
|
||||
" content=\"How many singers do we have?\", \n",
|
||||
" role=\"user\"\n",
|
||||
")\n",
|
||||
"logger.chat(mss)\n",
|
||||
"\n",
|
||||
"sql_query_mss1 = agent(mss)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"user: Show all countries and the number of singers in each country.\n",
|
||||
"##################### ITER 1, STEP 1: REASONING ######################\n",
|
||||
"assistant: {\n",
|
||||
" \"thought\": \"To show all countries and the number of singers in each, I'll need to create and run an SQL query that counts singers by their country. This involves grouping the data by country and then counting the number of singers in each group.\",\n",
|
||||
" \"speak\": \"Let me find out how many singers there are in each country for you.\",\n",
|
||||
" \"function\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"generate_sql_query\",\n",
|
||||
" \"arguments\": {\n",
|
||||
" \"question\": \"Show all countries and the number of singers in each country.\"\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"####################### ITER 1, STEP 2: ACTION #######################\n",
|
||||
">>> Executing function generate_sql_query ...\n",
|
||||
">>> END \n",
|
||||
"system: Execution Results:\n",
|
||||
"1. generate_sql_query:\n",
|
||||
" [EXECUTE STATUS]: SUCCESS\n",
|
||||
" [EXECUTE RESULT]: SELECT To show all countries and the number of singers in each country based on the database schema provided, you can use the SQL query below. This query groups singers by their country and counts the number of singers in each country: ```sql SELECT Country, COUNT(*) AS NumberOfSingers FROM singer GROUP BY Country ``` This SQL query selects the `Country` column from the `singer` table and uses the `COUNT(*)` function to count the total number of singers for each country. The `GROUP BY` clause groups the results by the `Country`, so you get the count of singers for each distinct country listed in the `singer` table.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"##################### ITER 2, STEP 1: REASONING ######################\n",
|
||||
"assistant: {\n",
|
||||
" \"thought\": \"The generate_sql_query function has provided the correct SQL query for showing all countries and the number of singers in each. Now, I need to execute this query using the query_sqlite function to get the desired data.\",\n",
|
||||
" \"speak\": \"I'm now running the query to find out the number of singers in each country.\",\n",
|
||||
" \"function\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"query_sqlite\",\n",
|
||||
" \"arguments\": {\n",
|
||||
" \"allow_change_data\": false,\n",
|
||||
" \"query\": \"SELECT Country, COUNT(*) AS NumberOfSingers FROM singer GROUP BY Country\"\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"####################### ITER 2, STEP 2: ACTION #######################\n",
|
||||
">>> Executing function query_sqlite ...\n",
|
||||
">>> END \n",
|
||||
"system: Execution Results:\n",
|
||||
"1. query_sqlite:\n",
|
||||
" [EXECUTE STATUS]: SUCCESS\n",
|
||||
" [EXECUTE RESULT]: [('France', 4), ('Netherlands', 1), ('United States', 1)]\n",
|
||||
"\n",
|
||||
"##################### ITER 3, STEP 1: REASONING ######################\n",
|
||||
"assistant: {\n",
|
||||
" \"thought\": \"The query has been executed successfully and I got the result indicating the number of singers in each country. Now I will present this data to the user.\",\n",
|
||||
" \"speak\": \"We have 4 singers from France, 1 singer from Netherlands, and 1 singer from the United States.\",\n",
|
||||
" \"function\": []\n",
|
||||
"}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"mss = Msg(\n",
|
||||
" name=\"user\", \n",
|
||||
" content=\"Show all countries and the number of singers in each country.\", \n",
|
||||
" role=\"user\"\n",
|
||||
")\n",
|
||||
"logger.chat(mss)\n",
|
||||
"\n",
|
||||
"sql_query_mss2 = agent(mss)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"user: How many singers have held concert in multiple stadiums? Give me the name of these singers.\n",
|
||||
"##################### ITER 1, STEP 1: REASONING ######################\n",
|
||||
"assistant: {\n",
|
||||
" \"thought\": \"To find out how many singers have held concerts in multiple stadiums and get their names, I need to create a SQL query that joins relevant tables to count the number of distinct stadiums for each singer. Singers with counts greater than one have held concerts in multiple stadiums. I will start by generating the SQL query.\",\n",
|
||||
" \"speak\": \"Let me find out which singers have held concerts in multiple stadiums for you.\",\n",
|
||||
" \"function\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"generate_sql_query\",\n",
|
||||
" \"arguments\": {\n",
|
||||
" \"question\": \"How many singers have held concerts in multiple stadiums and what are their names?\"\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"####################### ITER 1, STEP 2: ACTION #######################\n",
|
||||
">>> Executing function generate_sql_query ...\n",
|
||||
">>> END \n",
|
||||
"system: Execution Results:\n",
|
||||
"1. generate_sql_query:\n",
|
||||
" [EXECUTE STATUS]: SUCCESS\n",
|
||||
" [EXECUTE RESULT]: SELECT s.Name, COUNT(DISTINCT c.Stadium_ID) FROM singer AS s JOIN singer_in_concert AS sic ON s.Singer_ID = sic.Singer_ID JOIN concert AS c ON sic.concert_ID = c.concert_ID GROUP BY s.Name HAVING COUNT(DISTINCT c.Stadium_ID) > 1\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"##################### ITER 2, STEP 1: REASONING ######################\n",
|
||||
"assistant: {\n",
|
||||
" \"thought\": \"The generate_sql_query function successfully generated the necessary SQL query to find singers who have held concerts in multiple stadiums along with their names. I will now use the query_sqlite function to execute this SQL query and retrieve the required information.\",\n",
|
||||
" \"speak\": \"I'm now running the query to find out which singers have performed in multiple stadiums.\",\n",
|
||||
" \"function\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"query_sqlite\",\n",
|
||||
" \"arguments\": {\n",
|
||||
" \"allow_change_data\": false,\n",
|
||||
" \"query\": \"SELECT s.Name, COUNT(DISTINCT c.Stadium_ID) FROM singer AS s JOIN singer_in_concert AS sic ON s.Singer_ID = sic.Singer_ID JOIN concert AS c ON sic.concert_ID = c.concert_ID GROUP BY s.Name HAVING COUNT(DISTINCT c.Stadium_ID) > 1\"\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"####################### ITER 2, STEP 2: ACTION #######################\n",
|
||||
">>> Executing function query_sqlite ...\n",
|
||||
">>> END \n",
|
||||
"system: Execution Results:\n",
|
||||
"1. query_sqlite:\n",
|
||||
" [EXECUTE STATUS]: SUCCESS\n",
|
||||
" [EXECUTE RESULT]: [('John Nizinik', 2), ('Justin Brown', 3), ('Timbaland', 2), ('Tribal King', 2)]\n",
|
||||
"\n",
|
||||
"##################### ITER 3, STEP 1: REASONING ######################\n",
|
||||
"assistant: {\n",
|
||||
" \"thought\": \"The SQL query has been executed successfully and the resulting dataset includes all singers who have held concerts in multiple stadiums.\",\n",
|
||||
" \"speak\": \"The singers who have held concerts in multiple stadiums are John Nizinik, Justin Brown, Timbaland, and Tribal King.\",\n",
|
||||
" \"function\": []\n",
|
||||
"}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"mss = Msg(\n",
|
||||
" name=\"user\", \n",
|
||||
" content=\"How many singers have held concert in multiple stadiums? Give me the name of these singers.\", \n",
|
||||
" role=\"user\"\n",
|
||||
")\n",
|
||||
"logger.chat(mss)\n",
|
||||
"sql_query_mss3 = agent(mss)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can use the following code to build a conversation with the ReAct agent:\n",
|
||||
"\n",
|
||||
"``` python\n",
|
||||
"from agentscope.agents import UserAgent\n",
|
||||
"\n",
|
||||
"user = UserAgent(name=\"User\")\n",
|
||||
"\n",
|
||||
"x = None\n",
|
||||
"while True:\n",
|
||||
" x = user(x)\n",
|
||||
" if x.content == \"exit\":\n",
|
||||
" break\n",
|
||||
" x = agent(x)\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The capabilities of the ReAct agent are indeed very powerful. By modifying prompts and expanding the corresponding usage tools, the ReAct agent can leverage the combination of LLM and tools to accomplish more complex tasks.\n",
|
||||
"\n",
|
||||
"We encourage users to delve deeper into exploring the Agent's functionalities and to try out the capabilities of the LLM agent on their own."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"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": 4
|
||||
}
|
||||
304
AlgoriAgent/examples/conversation_nl2sql/sql_utils.py
Normal file
304
AlgoriAgent/examples/conversation_nl2sql/sql_utils.py
Normal file
@@ -0,0 +1,304 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Utils and helpers for performing sql querys.
|
||||
Referenced from https://github.com/BeachWang/DAIL-SQL.
|
||||
"""
|
||||
import sqlite3
|
||||
import json
|
||||
from typing import Union
|
||||
from sqlite3 import Connection
|
||||
import os
|
||||
import numpy as np
|
||||
|
||||
|
||||
def query_sqlite(
|
||||
queries: Union[list[str], str],
|
||||
path_db: str = None,
|
||||
cur: str = None,
|
||||
) -> Union[list, str]:
|
||||
"""Execute queries and return results."""
|
||||
assert not (
|
||||
path_db is None and cur is None
|
||||
), "path_db and cur cannot be NoneType at the same time"
|
||||
con: Connection
|
||||
close_in_func = False
|
||||
if cur is None:
|
||||
con = sqlite3.connect(path_db)
|
||||
cur = con.cursor()
|
||||
close_in_func = True
|
||||
|
||||
if isinstance(queries, str):
|
||||
results = cur.execute(queries).fetchall()
|
||||
elif isinstance(queries, list):
|
||||
results = []
|
||||
for query in queries:
|
||||
res = cur.execute(query).fetchall()
|
||||
results.append(res)
|
||||
else:
|
||||
raise TypeError(f"queries cannot be {type(queries)}")
|
||||
|
||||
# close the connection if needed
|
||||
if close_in_func:
|
||||
con.close()
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def create_sqlite_db_from_schema(schema_path: str, db_path: str) -> None:
|
||||
"""Create a SQLite database file from a schema SQL file.
|
||||
|
||||
Args:
|
||||
schema_path: The file path to the schema SQL file.
|
||||
db_path: The file path for the SQLite database to be created.
|
||||
"""
|
||||
if os.path.exists(db_path):
|
||||
print(
|
||||
f"Database file '{db_path}' already exists. ",
|
||||
)
|
||||
return
|
||||
conn = sqlite3.connect(db_path)
|
||||
|
||||
with open(schema_path, "r", encoding="utf-8") as schema_file:
|
||||
schema_sql = schema_file.read()
|
||||
|
||||
cursor = conn.cursor()
|
||||
cursor.executescript(schema_sql)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def get_table_names(path_db: str = None, cur: str = None) -> list:
|
||||
"""Get names of all tables within the database,
|
||||
and reuse cur if it's not None"""
|
||||
table_names = query_sqlite(
|
||||
queries="SELECT name FROM sqlite_master WHERE type='table'",
|
||||
path_db=path_db,
|
||||
cur=cur,
|
||||
)
|
||||
table_names = [_[0] for _ in table_names]
|
||||
return table_names
|
||||
|
||||
|
||||
def get_sql_for_database(path_db: str = None, cur: str = None) -> list:
|
||||
"""
|
||||
Get sql table from database
|
||||
"""
|
||||
close_in_func = False
|
||||
if cur is None:
|
||||
con = sqlite3.connect(path_db)
|
||||
cur = con.cursor()
|
||||
close_in_func = True
|
||||
|
||||
table_names = get_table_names(path_db, cur)
|
||||
|
||||
queries = [
|
||||
f"SELECT sql FROM sqlite_master WHERE tbl_name='{name}'"
|
||||
for name in table_names
|
||||
]
|
||||
|
||||
sqls = query_sqlite(queries, path_db, cur)
|
||||
|
||||
if close_in_func:
|
||||
cur.close()
|
||||
|
||||
return [_[0][0] for _ in sqls]
|
||||
|
||||
|
||||
class SQLPrompt:
|
||||
"""SQL prompt helper"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.template_info = "/* Given the following database schema: */\n{}"
|
||||
self.template_question = "/* Answer the following: {} */"
|
||||
self.template_agent_prompt = (
|
||||
"You are a helpful agent that preform"
|
||||
"SQL querys base on natual language instructions."
|
||||
"Please describe the database schema provided"
|
||||
"in a simple and understandable manner. "
|
||||
)
|
||||
self.is_sql_prompt = (
|
||||
"Please read the user's question below and "
|
||||
"determine whether the question is an appropriate "
|
||||
"query for the given SQL schema. \n"
|
||||
"If the question is indeed a query pertaining to the SQL schema, "
|
||||
'respond with "YES". '
|
||||
"If the question is not a query related to the SQL schema, "
|
||||
"provide a brief explanation to the user explaining why their "
|
||||
"question does not correspond to a SQL query within the "
|
||||
"context of the schema. "
|
||||
"The user's question is: "
|
||||
)
|
||||
|
||||
def format_target(self, example: dict) -> str:
|
||||
"""Format sql prompt"""
|
||||
return self.format_question(example) + "\nSELECT "
|
||||
|
||||
def format_question(self, example: dict) -> str:
|
||||
"""Format question"""
|
||||
sqls = get_sql_for_database(example["path_db"])
|
||||
prompt_info = self.template_info.format("\n\n".join(sqls))
|
||||
prompt_question = self.template_question.format(example["question"])
|
||||
prompt_components = [prompt_info, prompt_question]
|
||||
prompt = "\n\n".join(prompt_components)
|
||||
return prompt
|
||||
|
||||
def describe_schema(self, db_path: str) -> str:
|
||||
"""Describe SQL schema"""
|
||||
sqls = get_sql_for_database(db_path)
|
||||
prompt_info = self.template_info.format("\n\n".join(sqls))
|
||||
prompt_components = [
|
||||
self.template_agent_prompt,
|
||||
"DB schema info: ",
|
||||
prompt_info,
|
||||
]
|
||||
prompt = "\n\n".join(prompt_components)
|
||||
return prompt
|
||||
|
||||
def is_sql_question(self, example: dict) -> str:
|
||||
"""whether the input is a sql question or not"""
|
||||
sqls = get_sql_for_database(example["path_db"])
|
||||
prompt_info = self.template_info.format("\n\n".join(sqls))
|
||||
prompt_components = [
|
||||
prompt_info,
|
||||
self.is_sql_prompt,
|
||||
example["question"],
|
||||
]
|
||||
prompt = "\n".join(prompt_components)
|
||||
return prompt
|
||||
|
||||
|
||||
class QuestionSqlExampleStyle:
|
||||
"""Provide QA pair as examples"""
|
||||
|
||||
def get_example_prefix(self) -> str:
|
||||
"""get example prefix"""
|
||||
return (
|
||||
"/* Some SQL examples are provided based on similar problems: */\n"
|
||||
)
|
||||
|
||||
def format_example(self, example: dict) -> str:
|
||||
"""format example"""
|
||||
template_qa = "/* Answer the following: {} */\n{}"
|
||||
return template_qa.format(example["question"], example["query"])
|
||||
|
||||
|
||||
class EuclideanDistanceExampleSelector:
|
||||
"""Select similar sample question"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.train_json_path = "./database/train.json"
|
||||
with open(self.train_json_path, "r", encoding="utf-8") as file:
|
||||
self.train_json = json.load(file)
|
||||
self.train_questions = [_["question"] for _ in self.train_json]
|
||||
|
||||
self.SELECT_MODEL = "sentence-transformers/all-mpnet-base-v2"
|
||||
|
||||
from sentence_transformers import SentenceTransformer
|
||||
|
||||
self.bert_model = SentenceTransformer(self.SELECT_MODEL, device="cpu")
|
||||
try:
|
||||
self.train_embeddings = np.load("./.cache/train_embeddings.npy")
|
||||
except FileNotFoundError:
|
||||
self.train_embeddings = self.bert_model.encode(
|
||||
self.train_questions,
|
||||
)
|
||||
np.save("./.cache/train_embeddings.npy", self.train_embeddings)
|
||||
|
||||
def get_examples(
|
||||
self,
|
||||
target: dict,
|
||||
num_example: int,
|
||||
) -> list:
|
||||
"""Get similar question examples for few shot"""
|
||||
target_embedding = self.bert_model.encode([target["question"]])
|
||||
|
||||
# find the most similar question in train dataset
|
||||
from sklearn.metrics.pairwise import euclidean_distances
|
||||
|
||||
distances = np.squeeze(
|
||||
euclidean_distances(target_embedding, self.train_embeddings),
|
||||
).tolist()
|
||||
pairs = list(zip(distances, range(len(distances))))
|
||||
train_json = self.train_json
|
||||
pairs_sorted = sorted(pairs, key=lambda x: x[0])
|
||||
top_pairs = []
|
||||
for d, index in pairs_sorted:
|
||||
top_pairs.append((index, d))
|
||||
if len(top_pairs) >= num_example:
|
||||
break
|
||||
|
||||
return [train_json[index] for (index, d) in top_pairs]
|
||||
|
||||
|
||||
class DailSQLPromptGenerator:
|
||||
"""Generate prompt given the dataset and question"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
db_path: str,
|
||||
) -> None:
|
||||
self.db_path = db_path
|
||||
self.sql_prompt = SQLPrompt()
|
||||
self.question_selector = EuclideanDistanceExampleSelector()
|
||||
self.question_style = QuestionSqlExampleStyle()
|
||||
self.SEP_EXAMPLE = "\n\n"
|
||||
self.scope_factor = 100
|
||||
self.NUM_EXAMPLE = 9
|
||||
self.cross_domain = False
|
||||
|
||||
def describe_schema(self) -> str:
|
||||
"""Describe the sql"""
|
||||
return self.sql_prompt.describe_schema(self.db_path)
|
||||
|
||||
def is_sql_question_prompt(self, question: str) -> str:
|
||||
"""
|
||||
prompt for LLM to judge whether the question is appropriate
|
||||
"""
|
||||
target = {
|
||||
"path_db": self.db_path,
|
||||
"question": question,
|
||||
}
|
||||
return self.sql_prompt.is_sql_question(target)
|
||||
|
||||
def generate_prompt(self, x: dict = None) -> dict:
|
||||
"""
|
||||
Generate prompt given input question
|
||||
"""
|
||||
question = x["content"]
|
||||
target = {
|
||||
"path_db": self.db_path,
|
||||
"question": question,
|
||||
}
|
||||
prompt_target = self.sql_prompt.format_target(target)
|
||||
if self.NUM_EXAMPLE != 0:
|
||||
examples = self.question_selector.get_examples(
|
||||
target,
|
||||
self.NUM_EXAMPLE * self.scope_factor,
|
||||
)
|
||||
prompt_example = []
|
||||
question = target["question"]
|
||||
example_prefix = self.question_style.get_example_prefix()
|
||||
for example in examples:
|
||||
example_format = self.question_style.format_example(example)
|
||||
|
||||
prompt_example.append(example_format)
|
||||
|
||||
if len(prompt_example) >= self.NUM_EXAMPLE:
|
||||
break
|
||||
n_valid_example = len(prompt_example)
|
||||
if len(prompt_example) > 0:
|
||||
prompt = example_prefix + self.SEP_EXAMPLE.join(
|
||||
prompt_example + [prompt_target],
|
||||
)
|
||||
else:
|
||||
prompt = self.SEP_EXAMPLE.join(
|
||||
prompt_example + [prompt_target],
|
||||
)
|
||||
else:
|
||||
n_valid_example = 0
|
||||
prompt = prompt_target
|
||||
return {
|
||||
"prompt": prompt,
|
||||
"n_examples": n_valid_example,
|
||||
}
|
||||
29
AlgoriAgent/examples/conversation_self_organizing/README.md
Normal file
29
AlgoriAgent/examples/conversation_self_organizing/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Self-Organizing Conversation Example
|
||||
|
||||
This example will show
|
||||
- How to set up a self-organizing conversation using the `DialogAgent` and `agent_builder`
|
||||
- How to extract the discussion scenario and participant agents from the `agent_builder`'s response
|
||||
- How to conduct a multi-round discussion among the participant agents
|
||||
|
||||
|
||||
## Background
|
||||
|
||||
In this example, we demonstrate how to create a self-organizing conversation where the `agent_builder` automatically sets up the agents participating in the discussion based on a given question. The `agent_builder` provides the discussion scenario and the characteristics of the participant agents. The participant agents then engage in a multi-round discussion to solve the given question.
|
||||
|
||||
|
||||
## Tested Models
|
||||
|
||||
These models are tested in this example. For other models, some modifications may be needed.
|
||||
- `dashscope_chat` with `qwen-turbo`
|
||||
- `ollama_chat` with `llama3_8b`
|
||||
- `gemini_chat` with `models/gemini-1.0-pro-latest`
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Fill the next cell to meet the following requirements
|
||||
- Set up the `model_configs` with the appropriate API keys and endpoints
|
||||
- Provide the path to the `agent_builder_instruct.txt` file in the `load_txt` function
|
||||
- Set the desired `max_round` for the discussion
|
||||
- Provide the `query` or question for the discussion
|
||||
- [Optional] Adjust the `generate_args` such as `temperature` for the `openai_chat` model
|
||||
@@ -0,0 +1,19 @@
|
||||
Act as a group discussion organizer. Please provide the suitable scenario for discussing this question, and list the roles of the people who need to participate in the discussion in order to answer this question, along with their system prompt to describe their characteristics.
|
||||
The response must in the format of:
|
||||
#scenario#: <discussion scenario>
|
||||
#participants#:
|
||||
* <participant1 type>: <characteristic description>
|
||||
* <participant2 type>: <characteristic description>
|
||||
|
||||
Here are some examples.
|
||||
Question: Joy can read 8 pages of a book in 20 minutes. How many hours will it take her to read 120 pages?
|
||||
Answer:
|
||||
#scenario#: grade school class discussion
|
||||
#participants#:
|
||||
* Instructor: Act as an instructor who is in a class group discussion to guide the student group discussion. Please encourage critical thinking. Encourage participants to think critically and challenge assumptions by asking thought-provoking questions or presenting different perspectives.
|
||||
* broad-minded-student: Act as a student who is broad-minded and is open to trying new or different ways to solve problems. You are in a group discussion with other student under the guidance of the instructor.
|
||||
* knowledgeable-student: Act as a knowledgeable student and discuss with others to retrieve more information about the topic. If you do not know the answer to a question, please do not share false information
|
||||
|
||||
Please give the discussion scenario and the corresponding participants for the following question:
|
||||
Question: {question}
|
||||
Answer:
|
||||
@@ -0,0 +1,73 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""A simple example for auto discussion: the agent builder automatically\
|
||||
set up the agents participating the discussion ."""
|
||||
from tools import load_txt, extract_scenario_and_participants
|
||||
import agentscope
|
||||
from agentscope.agents import DialogAgent
|
||||
from agentscope.pipelines.functional import sequentialpipeline
|
||||
from agentscope.message import Msg
|
||||
|
||||
model_configs = [
|
||||
{
|
||||
"model_type": "openai_chat",
|
||||
"config_name": "gpt-3.5-turbo",
|
||||
"model_name": "gpt-3.5-turbo",
|
||||
"api_key": "xxx", # Load from env if not provided
|
||||
"organization": "xxx", # Load from env if not provided
|
||||
"generate_args": {
|
||||
"temperature": 0.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
"model_type": "post_api_chat",
|
||||
"config_name": "my_post_api",
|
||||
"api_url": "https://xxx",
|
||||
"headers": {},
|
||||
"json_args": {},
|
||||
},
|
||||
]
|
||||
|
||||
agentscope.init(
|
||||
model_configs=model_configs,
|
||||
project="Self-Organizing Conversation",
|
||||
)
|
||||
|
||||
|
||||
# init the self-organizing conversation
|
||||
agent_builder = DialogAgent(
|
||||
name="agent_builder",
|
||||
sys_prompt="You're a helpful assistant.",
|
||||
model_config_name="my_post_api",
|
||||
)
|
||||
|
||||
|
||||
max_round = 2
|
||||
query = "Say the pupil of your eye has a diameter of 5 mm and you have a \
|
||||
telescope with an aperture of 50 cm. How much more light can the \
|
||||
telescope gather than your eye?"
|
||||
|
||||
# get the discussion scenario and participant agents
|
||||
x = load_txt(
|
||||
"examples/conversation_self_organizing/agent_builder_instruct.txt",
|
||||
).format(
|
||||
question=query,
|
||||
)
|
||||
|
||||
x = Msg("user", x, role="user")
|
||||
settings = agent_builder(x)
|
||||
scenario_participants = extract_scenario_and_participants(settings["content"])
|
||||
|
||||
# set the agents that participant the discussion
|
||||
agents = [
|
||||
DialogAgent(
|
||||
name=key,
|
||||
sys_prompt=val,
|
||||
model_config_name="my_post_api",
|
||||
)
|
||||
for key, val in scenario_participants["Participants"].items()
|
||||
]
|
||||
|
||||
# begin discussion
|
||||
msg = Msg("user", f"let's discuss to solve the question: {query}", role="user")
|
||||
for i in range(max_round):
|
||||
msg = sequentialpipeline(agents, msg)
|
||||
81
AlgoriAgent/examples/conversation_self_organizing/tools.py
Normal file
81
AlgoriAgent/examples/conversation_self_organizing/tools.py
Normal file
@@ -0,0 +1,81 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""some utils of angent_builder example"""
|
||||
import re
|
||||
|
||||
|
||||
def load_txt(instruction_file: str) -> str:
|
||||
"""
|
||||
load .txt file
|
||||
Arguments:
|
||||
instruction_file: str type, which is the .txt file pth
|
||||
|
||||
Returns:
|
||||
instruction: str type, which is the str in the instruction_file
|
||||
|
||||
"""
|
||||
with open(instruction_file, "r", encoding="utf-8") as f:
|
||||
instruction = f.read()
|
||||
return instruction
|
||||
|
||||
|
||||
# extract scenario和participants
|
||||
def extract_scenario_and_participants(content: str) -> dict:
|
||||
"""
|
||||
extract the scenario and participants from agent builder's response
|
||||
|
||||
Arguments:
|
||||
content: the agent builders response
|
||||
|
||||
Returns:
|
||||
result: dict
|
||||
|
||||
Examples:
|
||||
content: #scenario#: Astronomy club meeting
|
||||
#participants#:
|
||||
* Club Leader: Act as the club leader who is knowledgeable about\
|
||||
astronomy and optics. You are leading a discussion about the \
|
||||
capabilities of telescopes versus the human eye. Please provide \
|
||||
accurate information and guide the discussion.
|
||||
* Curious Member: Act as a curious club member who is interested \
|
||||
in astronomy but may not know all the technical details. You are \
|
||||
eager to learn and ask questions.
|
||||
* Experienced Astronomer: Act as an experienced astronomer who has \
|
||||
practical experience using telescopes for stargazing. You can \
|
||||
provide real-world examples and insights into the topic.
|
||||
|
||||
Return:
|
||||
{'Scenario': 'Astronomy club meeting',
|
||||
'Participants':
|
||||
{'Club_Leader': 'Act as the club leader who is knowledgeable \
|
||||
about astronomy and optics. You are leading a discussion about the \
|
||||
capabilities of telescopes versus the human eye. Please provide\
|
||||
accurate information and guide the discussion.',
|
||||
'Curious_Member': 'Act as a curious club member who is interested \
|
||||
in astronomy but may not know all the technical details. You are \
|
||||
eager to learn and ask questions.',
|
||||
'Experienced_Astronomer': 'Act as an experienced astronomer who has\
|
||||
practical experience using telescopes for stargazing. You can\
|
||||
provide real-world examples and insights into the topic.'}}
|
||||
|
||||
"""
|
||||
result = {}
|
||||
# define regular expression
|
||||
scenario_pattern = r"#scenario#:\s*(.*)"
|
||||
participants_pattern = r"\*\s*([^:\n]+):\s*([^\n]+)"
|
||||
|
||||
# search and extract scenario
|
||||
scenario_match = re.search(scenario_pattern, content)
|
||||
if scenario_match:
|
||||
result["Scenario"] = scenario_match.group(1).strip()
|
||||
|
||||
# search and extract participants
|
||||
participants_matches = re.finditer(participants_pattern, content)
|
||||
participants_dict = {}
|
||||
for match in participants_matches:
|
||||
participant_type, characteristic = match.groups()
|
||||
participants_dict[
|
||||
participant_type.strip().replace(" ", "_")
|
||||
] = characteristic.strip()
|
||||
result["Participants"] = participants_dict
|
||||
|
||||
return result
|
||||
48
AlgoriAgent/examples/conversation_with_RAG_agents/README.md
Normal file
48
AlgoriAgent/examples/conversation_with_RAG_agents/README.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# AgentScope Copilot: a Multi-Agent RAG Application
|
||||
|
||||
* **What is this example about?**
|
||||
With the provided implementation and configuration,
|
||||
you will obtain three different agents who can help you answer different questions about AgentScope.
|
||||
|
||||
* **What is this example for?** By this example, we want to show how the agent with retrieval augmented generation (RAG)
|
||||
capability can be used to build easily.
|
||||
|
||||
|
||||
## Prerequisites
|
||||
* **Cloning repo:** This example requires cloning the whole AgentScope repo to local.
|
||||
* **Packages:** This example is built on the LlamaIndex package. Thus, some packages need to be installed before running the example.
|
||||
```bash
|
||||
pip install llama-index==0.10.30 llama-index-readers-docstring-walker==0.1.3 tree-sitter==0.21.3 tree-sitter-languages==1.10.2
|
||||
```
|
||||
* **Model APIs:** This example uses Dashscope APIs. Thus, we also need an API key for DashScope.
|
||||
```bash
|
||||
export DASHSCOPE_API_KEY='YOUR_API_KEY'
|
||||
```
|
||||
|
||||
**Note:** This example has been tested with `dashscope_chat` and `dashscope_text_embedding` model wrapper, with `qwen-max` and `text-embedding-v2` models.
|
||||
However, you are welcome to replace the Dashscope language and embedding model wrappers or models with other models you like to test.
|
||||
|
||||
## Start AgentScope Copilot
|
||||
* **Terminal:** The most simple way to execute the AgentScope Copilot is running in terminal.
|
||||
```bash
|
||||
python ./rag_example.py
|
||||
```
|
||||
|
||||
|
||||
* **AS gradio:** If you want to have more organized, clean UI, you can also run with our `as_gradio`.
|
||||
```bash
|
||||
as_gradio ./rag_example.py
|
||||
```
|
||||
|
||||
### Agents in the example
|
||||
After you run the example, you may notice that this example consists of three RAG agents:
|
||||
* `Tutorial-Assistant`: responsible for answering questions based on AgentScope tutorials (markdown files).
|
||||
* `Code-Search-Assistant`: responsible for answering questions based on AgentScope code base (python files).
|
||||
* `API-Assistant`: responsible for answering questions based on AgentScope API documents (html files, generated by `sphinx`)
|
||||
* `Searching-Assistant`: responsible for general search in tutorial and code base (markdown files and code files)
|
||||
* `Agent-Guiding-Assistant`: responsible for referring the correct agent(s) among the above ones.
|
||||
|
||||
Besides the last `Agent-Guiding-Assistant`, all other agents can be configured to answering questions based on other GitHub repo by replacing the `knowledge`.
|
||||
|
||||
For more details about how to use the RAG module in AgentScope, please refer to the tutorial.
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
[
|
||||
{
|
||||
"class": "LlamaIndexAgent",
|
||||
"args": {
|
||||
"name": "Tutorial-Assistant",
|
||||
"description": "Tutorial-Assistant is an agent that can provide answer based on English tutorial material, mainly the markdown files. It can answer general questions about AgentScope.",
|
||||
"sys_prompt": "You're an assistant helping new users to use AgentScope. The language style is helpful and cheerful. You generate answers based on the provided context. The answer is expected to be no longer than 100 words. If the key words of the question can be found in the provided context, the answer should contain the section name which contains the answer. For example, 'You may refer to SECTION_NAME for more details.'",
|
||||
"model_config_name": "qwen_config",
|
||||
"knowledge_id_list": ["agentscope_tutorial_rag"],
|
||||
"similarity_top_k": 5,
|
||||
"log_retrieval": false,
|
||||
"recent_n_mem_for_retrieve": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "LlamaIndexAgent",
|
||||
"args": {
|
||||
"name": "Code-Search-Assistant",
|
||||
"description": "Code-Search-Assistant is an agent that can provide answer based on AgentScope code base. It can answer questions about specific modules in AgentScope.",
|
||||
"sys_prompt": "You're a coding assistant of AgentScope. The answer starts with appreciation for the question, then provide details regarding the functionality and features of the modules mentioned in the question. The language should be in a professional and simple style. The answer is limited to be less than 100 words.",
|
||||
"model_config_name": "qwen_config",
|
||||
"knowledge_id_list": ["agentscope_code_rag"],
|
||||
"similarity_top_k": 5,
|
||||
"log_retrieval": false,
|
||||
"recent_n_mem_for_retrieve": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "LlamaIndexAgent",
|
||||
"args": {
|
||||
"name": "API-Assistant",
|
||||
"description": "API-Assistant is an agent that can answer questions about APIs in AgentScope. It can answer general questions about AgentScope.",
|
||||
"sys_prompt": "You're an assistant providing answers to the questions related to APIs (functions and classes) in AgentScope. The language style is helpful and cheerful. You generate answers based on the provided context. The answer is expected to be no longer than 200 words. If the key words of the question can be found in the provided context, the answer should contain the module of the API. For example, 'You may refer to MODULE_NAME for more details.'",
|
||||
"model_config_name": "qwen_config",
|
||||
"knowledge_id_list": ["agentscope_api_rag"],
|
||||
"similarity_top_k": 2,
|
||||
"log_retrieval": true,
|
||||
"recent_n_mem_for_retrieve": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "LlamaIndexAgent",
|
||||
"args": {
|
||||
"name": "Searching-Assistant",
|
||||
"description": "Search-Assistant is an agent that can provide answer based on AgentScope code and tutorial. It can answer questions about everything in AgentScope codes and tutorials.",
|
||||
"sys_prompt": "You're a helpful assistant of AgentScope. The answer starts with appreciation for the question, then provide output the location of the code or section that the most relevant to the question. The answer is limited to be less than 50 words.",
|
||||
"model_config_name": "qwen_config",
|
||||
"knowledge_id_list": ["agentscope_code_rag","agentscope_tutorial_rag"],
|
||||
"similarity_top_k": 5,
|
||||
"log_retrieval": false,
|
||||
"recent_n_mem_for_retrieve": 1,
|
||||
"persist_dir": "./rag_storage/searching_assist"
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "DialogAgent",
|
||||
"args": {
|
||||
"name": "Agent-Guiding-Assistant",
|
||||
"sys_prompt": "You're an assistant guiding the user to specific agent for help. The answer is in a cheerful styled language. The output starts with appreciation for the question. Next, rephrase the question in a simple declarative Sentence for example, 'I think you are asking...'. Last, if the question is about detailed code or example in AgentScope Framework, output '@ Code-Search-Assistant you might be suitable for answering the question'; if the question is about API or function calls (Example: 'Is there function related...' or 'how can I initialize ...' ) in AgentScope, output '@ API-Assistant, I think you are more suitable for the question, please tell us more about it'; if question is about where to find some context (Example:'where can I find...'), output '@ Searching-Assistant, we need your help', otherwise, output '@ Tutorial-Assistant, I think you are more suitable for the question, can you tell us more about it?'. The answer is expected to be only one sentence",
|
||||
"model_config_name": "qwen_config",
|
||||
"use_memory": false
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,114 @@
|
||||
[
|
||||
{
|
||||
"knowledge_id": "agentscope_code_rag",
|
||||
"emb_model_config_name": "qwen_emb_config",
|
||||
"chunk_size": 2048,
|
||||
"chunk_overlap": 40,
|
||||
"data_processing": [
|
||||
{
|
||||
"load_data": {
|
||||
"loader": {
|
||||
"create_object": true,
|
||||
"module": "llama_index.core",
|
||||
"class": "SimpleDirectoryReader",
|
||||
"init_args": {
|
||||
"input_dir": "../../src/agentscope",
|
||||
"recursive": true,
|
||||
"required_exts": [
|
||||
".py"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"store_and_index": {
|
||||
"transformations": [
|
||||
{
|
||||
"create_object": true,
|
||||
"module": "llama_index.core.node_parser",
|
||||
"class": "CodeSplitter",
|
||||
"init_args": {
|
||||
"language": "python",
|
||||
"chunk_lines": 100
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"knowledge_id": "agentscope_api_rag",
|
||||
"emb_model_config_name": "qwen_emb_config",
|
||||
"chunk_size": 1024,
|
||||
"chunk_overlap": 40,
|
||||
"data_processing": [
|
||||
{
|
||||
"load_data": {
|
||||
"loader": {
|
||||
"create_object": true,
|
||||
"module": "llama_index.core",
|
||||
"class": "SimpleDirectoryReader",
|
||||
"init_args": {
|
||||
"input_dir": "../../docs/docstring_html/",
|
||||
"required_exts": [
|
||||
".html"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"knowledge_id": "agentscope_global_rag",
|
||||
"emb_model_config_name": "qwen_emb_config",
|
||||
"chunk_size": 2048,
|
||||
"chunk_overlap": 40,
|
||||
"data_processing": [
|
||||
{
|
||||
"load_data": {
|
||||
"loader": {
|
||||
"create_object": true,
|
||||
"module": "llama_index.core",
|
||||
"class": "SimpleDirectoryReader",
|
||||
"init_args": {
|
||||
"input_dir": "../../docs/sphinx_doc/en/source/tutorial",
|
||||
"required_exts": [
|
||||
".md"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"load_data": {
|
||||
"loader": {
|
||||
"create_object": true,
|
||||
"module": "llama_index.core",
|
||||
"class": "SimpleDirectoryReader",
|
||||
"init_args": {
|
||||
"input_dir": "../../src/agentscope",
|
||||
"recursive": true,
|
||||
"required_exts": [
|
||||
".py"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"store_and_index": {
|
||||
"transformations": [
|
||||
{
|
||||
"create_object": true,
|
||||
"module": "llama_index.core.node_parser",
|
||||
"class": "CodeSplitter",
|
||||
"init_args": {
|
||||
"language": "python",
|
||||
"chunk_lines": 100
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,14 @@
|
||||
[
|
||||
{
|
||||
"model_type": "dashscope_text_embedding",
|
||||
"config_name": "qwen_emb_config",
|
||||
"model_name": "text-embedding-v2",
|
||||
"api_key": ""
|
||||
},
|
||||
{
|
||||
"model_type": "dashscope_chat",
|
||||
"config_name": "qwen_config",
|
||||
"model_name": "qwen-max",
|
||||
"api_key": ""
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,37 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Group chat utils."""
|
||||
import re
|
||||
from typing import Sequence
|
||||
|
||||
|
||||
def select_next_one(agents: Sequence, rnd: int) -> Sequence:
|
||||
"""
|
||||
Select next agent.
|
||||
"""
|
||||
return agents[rnd % len(agents)]
|
||||
|
||||
|
||||
def filter_agents(string: str, agents: Sequence) -> Sequence:
|
||||
"""
|
||||
This function filters the input string for occurrences of the given names
|
||||
prefixed with '@' and returns a list of the found names.
|
||||
"""
|
||||
if len(agents) == 0:
|
||||
return []
|
||||
|
||||
# Create a pattern that matches @ followed by any of the candidate names
|
||||
pattern = (
|
||||
r"@(" + "|".join(re.escape(agent.name) for agent in agents) + r")\b"
|
||||
)
|
||||
|
||||
# Find all occurrences of the pattern in the string
|
||||
matches = re.findall(pattern, string)
|
||||
|
||||
# Create a dictionary mapping agent names to agent objects for quick lookup
|
||||
agent_dict = {agent.name: agent for agent in agents}
|
||||
|
||||
# Return the list of matched agent objects preserving the order
|
||||
ordered_agents = [
|
||||
agent_dict[name] for name in matches if name in agent_dict
|
||||
]
|
||||
return ordered_agents
|
||||
148
AlgoriAgent/examples/conversation_with_RAG_agents/rag_example.py
Normal file
148
AlgoriAgent/examples/conversation_with_RAG_agents/rag_example.py
Normal file
@@ -0,0 +1,148 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
An example for conversation between user and agents with RAG capability.
|
||||
One agent is a tutorial assistant, the other is a code explainer.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
|
||||
from groupchat_utils import filter_agents
|
||||
|
||||
import agentscope
|
||||
from agentscope.agents import UserAgent
|
||||
from agentscope.rag import KnowledgeBank
|
||||
|
||||
|
||||
AGENT_CHOICE_PROMPT = """
|
||||
There are following available agents. You need to choose the most appropriate
|
||||
agent(s) to answer the user's question.
|
||||
|
||||
agent descriptions:{}
|
||||
|
||||
First, rephrase the user's question, which must contain the key information.
|
||||
The you need to think step by step. If you believe some of the agents are
|
||||
good candidates to answer the question (e.g., AGENT_1 and AGENT_2), then
|
||||
you need to follow the following format to generate your output:
|
||||
|
||||
'
|
||||
Because $YOUR_REASONING.
|
||||
I believe @AGENT_1 and @AGENT_2 are the most appropriate agents to answer
|
||||
your question.
|
||||
'
|
||||
"""
|
||||
|
||||
|
||||
def prepare_docstring_html() -> None:
|
||||
"""prepare docstring in html for API assistant"""
|
||||
if not os.path.exists("../../docs/docstring_html/"):
|
||||
os.system(
|
||||
"sphinx-apidoc -f -o ../../docs/sphinx_doc/en/source "
|
||||
"../../src/agentscope -t template",
|
||||
)
|
||||
os.system(
|
||||
"sphinx-build -b html ../../docs/sphinx_doc/en/source "
|
||||
"../../docs/docstring_html/ -W --keep-going",
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""A RAG multi-agent demo"""
|
||||
# prepare html for api agent
|
||||
prepare_docstring_html()
|
||||
|
||||
# prepare models
|
||||
with open("configs/model_config.json", "r", encoding="utf-8") as f:
|
||||
model_configs = json.load(f)
|
||||
|
||||
# load config of the agents
|
||||
with open("configs/agent_config.json", "r", encoding="utf-8") as f:
|
||||
agent_configs = json.load(f)
|
||||
|
||||
agent_list = agentscope.init(
|
||||
model_configs=model_configs,
|
||||
agent_configs=agent_configs,
|
||||
project="Conversation with RAG agents",
|
||||
)
|
||||
rag_agent_list = agent_list[:4]
|
||||
guide_agent = agent_list[4]
|
||||
|
||||
# the knowledge bank can be configured by loading config file
|
||||
knowledge_bank = KnowledgeBank(configs="configs/knowledge_config.json")
|
||||
|
||||
# alternatively, we can easily input the configs to add data to RAG
|
||||
knowledge_bank.add_data_as_knowledge(
|
||||
knowledge_id="agentscope_tutorial_rag",
|
||||
emb_model_name="qwen_emb_config",
|
||||
data_dirs_and_types={
|
||||
"../../docs/sphinx_doc/en/source/tutorial": [".md"],
|
||||
},
|
||||
)
|
||||
|
||||
# let knowledgebank to equip rag agent with a (set of) knowledge
|
||||
# corresponding to its knowledge_id_list
|
||||
for agent in rag_agent_list:
|
||||
knowledge_bank.equip(agent, agent.knowledge_id_list)
|
||||
|
||||
# an alternative way is to provide knowledge list to agents
|
||||
# when initializing them one by one, e.g.
|
||||
#
|
||||
# ```
|
||||
# knowledge = knowledge_bank.get_knowledge(knowledge_id)
|
||||
# agent = LlamaIndexAgent(
|
||||
# name="rag_worker",
|
||||
# sys_prompt="{your_prompt}",
|
||||
# model_config_name="{your_model}",
|
||||
# knowledge_list=[knowledge], # provide knowledge object directly
|
||||
# similarity_top_k=3,
|
||||
# log_retrieval=False,
|
||||
# recent_n_mem_for_retrieve=1,
|
||||
# )
|
||||
# ```
|
||||
|
||||
rag_agent_names = [agent.name for agent in rag_agent_list]
|
||||
# update guide agent system prompt with the descriptions of rag agents
|
||||
rag_agent_descriptions = [
|
||||
"agent name: "
|
||||
+ agent.name
|
||||
+ "\n agent description:"
|
||||
+ agent.description
|
||||
+ "\n"
|
||||
for agent in rag_agent_list
|
||||
]
|
||||
|
||||
guide_agent.sys_prompt = (
|
||||
guide_agent.sys_prompt
|
||||
+ AGENT_CHOICE_PROMPT.format(
|
||||
"".join(rag_agent_descriptions),
|
||||
)
|
||||
)
|
||||
|
||||
user_agent = UserAgent()
|
||||
while True:
|
||||
# The workflow is the following:
|
||||
# 1. user input a message,
|
||||
# 2. if it mentions (@) one of the agents, the agent will be called
|
||||
# 3. otherwise, the guide agent will decide which agent to call
|
||||
# 4. the called agent will respond to the user
|
||||
# 5. repeat
|
||||
x = user_agent()
|
||||
x.role = "user" # to enforce dashscope requirement on roles
|
||||
if len(x["content"]) == 0 or str(x["content"]).startswith("exit"):
|
||||
break
|
||||
speak_list = filter_agents(x.get("content", ""), rag_agent_list)
|
||||
if len(speak_list) == 0:
|
||||
guide_response = guide_agent(x)
|
||||
# Only one agent can be called in the current version,
|
||||
# we may support multi-agent conversation later
|
||||
speak_list = filter_agents(
|
||||
guide_response.get("content", ""),
|
||||
rag_agent_list,
|
||||
)
|
||||
agent_name_list = [agent.name for agent in speak_list]
|
||||
for agent_name, agent in zip(agent_name_list, speak_list):
|
||||
if agent_name in rag_agent_names:
|
||||
agent(x)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.6 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
54
AlgoriAgent/examples/conversation_with_gpt-4o/README.md
Normal file
54
AlgoriAgent/examples/conversation_with_gpt-4o/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Conversation with gpt-4o (OpenAI Vision Model)
|
||||
|
||||
This example will show
|
||||
- How to use gpt-4o and other OpenAI vision models in AgentScope
|
||||
|
||||
In this example,
|
||||
- you can have a conversation with OpenAI vision models.
|
||||
- you can show gpt-4o with your drawings or web ui designs and look for its suggestions.
|
||||
- you can share your pictures with gpt-4o and ask for its comments,
|
||||
|
||||
Just input your image url (both local and web URLs are supported) and talk with gpt-4o.
|
||||
|
||||
|
||||
## Background
|
||||
|
||||
In May 13, 2024, OpenAI released their new model, gpt-4o, which is a large multimodal model that can process both text and multimodal data.
|
||||
|
||||
|
||||
## Tested Models
|
||||
|
||||
The following models are tested in this example. For other models, some modifications may be needed.
|
||||
- gpt-4o
|
||||
- gpt-4-turbo
|
||||
- gpt-4-vision
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You need to satisfy the following requirements to run this example.
|
||||
- Install the latest version of AgentScope by
|
||||
```bash
|
||||
git clone https://github.com/modelscope/agentscope.git
|
||||
cd agentscope
|
||||
pip install -e .
|
||||
```
|
||||
- Prepare an OpenAI API key
|
||||
|
||||
## Running the Example
|
||||
|
||||
First fill your OpenAI API key in `conversation_with_gpt-4o.py`, then execute the following command to run the conversation with gpt-4o.
|
||||
|
||||
```bash
|
||||
python conversation_with_gpt-4o.py
|
||||
```
|
||||
|
||||
## A Running Example
|
||||
|
||||
- Conversation history with gpt-4o.
|
||||
|
||||
<img src="https://img.alicdn.com/imgextra/i4/O1CN01oQHcmy1mHXALklkMe_!!6000000004929-2-tps-5112-1276.png" alt="conversation history"/>
|
||||
|
||||
- My picture
|
||||
|
||||
<img src="https://img.alicdn.com/imgextra/i3/O1CN01UpQaLN27hjidUipMv_!!6000000007829-0-tps-720-1280.jpg" alt="my picture" width="200" />
|
||||
@@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""An example for conversation with OpenAI vision models, especially for
|
||||
GPT-4o."""
|
||||
import agentscope
|
||||
from agentscope.agents import UserAgent, DialogAgent
|
||||
|
||||
# Fill in your OpenAI API key
|
||||
YOUR_OPENAI_API_KEY = "xxx"
|
||||
|
||||
model_config = {
|
||||
"config_name": "gpt-4o_config",
|
||||
"model_type": "openai_chat",
|
||||
"model_name": "gpt-4o",
|
||||
"api_key": YOUR_OPENAI_API_KEY,
|
||||
"generate_args": {
|
||||
"temperature": 0.7,
|
||||
},
|
||||
}
|
||||
|
||||
agentscope.init(
|
||||
model_configs=model_config,
|
||||
project="Conversation with GPT-4o",
|
||||
)
|
||||
|
||||
# Require user to input URL, and press enter to skip the URL input
|
||||
user = UserAgent("user", require_url=True)
|
||||
|
||||
agent = DialogAgent(
|
||||
"Friday",
|
||||
sys_prompt="You're a helpful assistant named Friday.",
|
||||
model_config_name="gpt-4o_config",
|
||||
)
|
||||
|
||||
x = None
|
||||
while True:
|
||||
x = agent(x)
|
||||
x = user(x)
|
||||
if x.content == "exit": # type "exit" to break the loop
|
||||
break
|
||||
27
AlgoriAgent/examples/conversation_with_langchain/README.md
Normal file
27
AlgoriAgent/examples/conversation_with_langchain/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Create an Agent with LangChain
|
||||
|
||||
AgentScope is a highly flexible multi-agent platform. It allows developers
|
||||
to create agents with third-party libraries.
|
||||
|
||||
In this example, we will show how to create an assistant agent with
|
||||
LangChain in AgentScope, and interact with user in a conversation.
|
||||
|
||||
**Note** we use OpenAI API for LangChain in this example. Developers can
|
||||
modify it according to their own needs.
|
||||
|
||||
## Install LangChain
|
||||
|
||||
Before running the example, please install LangChain by the following command:
|
||||
```bash
|
||||
pip install langchain==0.1.11 langchain-openai==0.0.8
|
||||
```
|
||||
|
||||
## Create Agent with LangChain
|
||||
|
||||
In this example, the memory management, prompt engineering, and model
|
||||
invocation are all handled by LangChain.
|
||||
Specifically, we create an agent class named `LangChainAgent`.
|
||||
In its `reply` function, developers only need parse the input message and
|
||||
wrap the output message into `agentscope.message.Msg` class.
|
||||
After that, developers can build the conversation in AgentScope, and the
|
||||
`LangChainAgent` is the same as other agents in AgentScope.
|
||||
@@ -0,0 +1,87 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""A simple example of using langchain to create an assistant agent in
|
||||
AgentScope."""
|
||||
import os
|
||||
from typing import Optional, Union, Sequence
|
||||
|
||||
from langchain_openai import OpenAI
|
||||
from langchain.memory import ConversationBufferMemory
|
||||
from langchain.prompts import PromptTemplate
|
||||
from langchain.chains import LLMChain
|
||||
|
||||
import agentscope
|
||||
from agentscope.agents import AgentBase
|
||||
from agentscope.agents import UserAgent
|
||||
from agentscope.message import Msg
|
||||
|
||||
|
||||
class LangChainAgent(AgentBase):
|
||||
"""An agent that implemented by langchain."""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
"""Initialize the agent."""
|
||||
|
||||
# Disable AgentScope memory and use langchain memory instead
|
||||
super().__init__(name, use_memory=False)
|
||||
|
||||
# [START] BY LANGCHAIN
|
||||
# Create a memory in langchain
|
||||
memory = ConversationBufferMemory(memory_key="chat_history")
|
||||
|
||||
# Prepare prompt
|
||||
template = """
|
||||
You are a helpful assistant, and your goal is to help the user.
|
||||
|
||||
{chat_history}
|
||||
Human: {human_input}
|
||||
Assistant:"""
|
||||
|
||||
prompt = PromptTemplate(
|
||||
input_variables=["chat_history", "human_input"],
|
||||
template=template,
|
||||
)
|
||||
|
||||
llm = OpenAI(openai_api_key=os.environ["OPENAI_API_KEY"])
|
||||
|
||||
# Prepare a chain and manage the memory by LLMChain in langchain
|
||||
self.llm_chain = LLMChain(
|
||||
llm=llm,
|
||||
prompt=prompt,
|
||||
verbose=False,
|
||||
memory=memory,
|
||||
)
|
||||
# [END] BY LANGCHAIN
|
||||
|
||||
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
|
||||
# [START] BY LANGCHAIN
|
||||
|
||||
# Generate response
|
||||
response_str = self.llm_chain.predict(human_input=x.content)
|
||||
|
||||
# [END] BY LANGCHAIN
|
||||
|
||||
# Wrap the response in a message object in AgentScope
|
||||
return Msg(name=self.name, content=response_str, role="assistant")
|
||||
|
||||
|
||||
# Build a conversation between user and assistant agent
|
||||
|
||||
# init AgentScope
|
||||
agentscope.init(
|
||||
project="Conversation with LangChain",
|
||||
)
|
||||
|
||||
# Create an instance of the langchain agent
|
||||
agent = LangChainAgent(name="Assistant")
|
||||
|
||||
# Create a user agent from AgentScope
|
||||
user = UserAgent("User")
|
||||
|
||||
msg = None
|
||||
while True:
|
||||
# User input
|
||||
msg = user(msg)
|
||||
if msg.content == "exit":
|
||||
break
|
||||
# Agent speaks
|
||||
msg = agent(msg)
|
||||
36
AlgoriAgent/examples/conversation_with_mentions/README.md
Normal file
36
AlgoriAgent/examples/conversation_with_mentions/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
###
|
||||
# Multi-Agent Group Conversation in AgentScope
|
||||
|
||||
This example demonstrates a multi-agent group conversation facilitated by AgentScope. The script sets up a virtual chat room where a user agent interacts with several NPC (non-player character) agents. Participants can utilize a special "@" mention functionality to address specific agents directly.
|
||||
|
||||
## Background
|
||||
|
||||
The conversation takes place in a simulated chat room environment with predefined roles for each participant. Topics are open-ended and evolve based on the user's input and agents' responses.
|
||||
|
||||
## Tested Models
|
||||
|
||||
These models are tested in this example. For other models, some modifications may be needed.
|
||||
- gemini_chat (models/gemini-pro, models/gemini-1.0-pro)
|
||||
- dashscope_chat (qwen-max, qwen-turbo)
|
||||
- ollama_chat (ollama_llama3_8b)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Fill the next cell to meet the following requirements:
|
||||
- Set your `api_key` in the `configs/model_configs.json` file
|
||||
- Optional: Launch agentscope gradio with `as_gradio main.py`
|
||||
|
||||
## How to Use
|
||||
|
||||
1. Run the script using the command: `python main.py`
|
||||
2. Address specific agents by typing "@" followed by the agent's name.
|
||||
3. Type "exit" to leave the chat.
|
||||
|
||||
## Customization Options
|
||||
|
||||
You can adjust the behavior and parameters of the NPC agents and conversation model by editing the `agent_configs.json` and `model_configs.json` files, respectively.
|
||||
|
||||
### Changing User Input Time Limit
|
||||
|
||||
Adjust the `USER_TIME_TO_SPEAK` variable in the `main.py` script to change the time limit for user input.
|
||||
###
|
||||
@@ -0,0 +1,29 @@
|
||||
[
|
||||
{
|
||||
"class": "DialogAgent",
|
||||
"args": {
|
||||
"name": "Lingfeng",
|
||||
"sys_prompt":"You are Lingfeng, a noble in the imperial court, known for your wisdom and strategic acumen. You often engage in complex political intrigues and have recently suspected the Queen’s adviser of treachery. Your speaking style is reminiscent of classical literature.",
|
||||
"model_config_name": "gpt-4",
|
||||
"use_memory": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "DialogAgent",
|
||||
"args": {
|
||||
"name": "Boyu",
|
||||
"sys_prompt":"You are Boyu, a friend of Lingfeng and an enthusiast of court dramas. Your speech is modern but with a flair for the dramatic, matching your love for emotive storytelling. You've been closely following Lingfeng’s political maneuvers in the imperial court through secret correspondence.",
|
||||
"model_config_name": "gpt-4",
|
||||
"use_memory": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "DialogAgent",
|
||||
"args": {
|
||||
"name": "Haotian",
|
||||
"sys_prompt":"You are Haotian, Lingfeng’s cousin who prefers the open fields to the confines of court life. As a celebrated athlete, your influence has protected Lingfeng in times of political strife. You promote physical training as a way to prepare for life's battles, often using sports metaphors in conversation.",
|
||||
"model_config_name": "gpt-4",
|
||||
"use_memory": true
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
[
|
||||
{
|
||||
"model_type": "openai_chat",
|
||||
"config_name": "gpt-4",
|
||||
"model_name": "gpt-4",
|
||||
"api_key": "xxx",
|
||||
"organization": "xxx",
|
||||
"generate_args": {
|
||||
"temperature": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"model_type": "post_api_chat",
|
||||
"config_name": "my_post_api",
|
||||
"api_url": "https://xxx",
|
||||
"headers": {},
|
||||
"json_args": {}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,37 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Group chat utils."""
|
||||
import re
|
||||
from typing import Sequence
|
||||
|
||||
|
||||
def select_next_one(agents: Sequence, rnd: int) -> Sequence:
|
||||
"""
|
||||
Select next agent.
|
||||
"""
|
||||
return agents[rnd % len(agents)]
|
||||
|
||||
|
||||
def filter_agents(string: str, agents: Sequence) -> Sequence:
|
||||
"""
|
||||
This function filters the input string for occurrences of the given names
|
||||
prefixed with '@' and returns a list of the found names.
|
||||
"""
|
||||
if len(agents) == 0:
|
||||
return []
|
||||
|
||||
# Create a pattern that matches @ followed by any of the candidate names
|
||||
pattern = (
|
||||
r"@(" + "|".join(re.escape(agent.name) for agent in agents) + r")\b"
|
||||
)
|
||||
|
||||
# Find all occurrences of the pattern in the string
|
||||
matches = re.findall(pattern, string)
|
||||
|
||||
# Create a dictionary mapping agent names to agent objects for quick lookup
|
||||
agent_dict = {agent.name: agent for agent in agents}
|
||||
|
||||
# Return the list of matched agent objects preserving the order
|
||||
ordered_agents = [
|
||||
agent_dict[name] for name in matches if name in agent_dict
|
||||
]
|
||||
return ordered_agents
|
||||
79
AlgoriAgent/examples/conversation_with_mentions/main.py
Normal file
79
AlgoriAgent/examples/conversation_with_mentions/main.py
Normal file
@@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" A group chat where user can talk any time implemented by agentscope. """
|
||||
from loguru import logger
|
||||
from groupchat_utils import (
|
||||
select_next_one,
|
||||
filter_agents,
|
||||
)
|
||||
|
||||
import agentscope
|
||||
from agentscope.agents import UserAgent
|
||||
from agentscope.message import Msg
|
||||
from agentscope.msghub import msghub
|
||||
|
||||
USER_TIME_TO_SPEAK = 10
|
||||
DEFAULT_TOPIC = """
|
||||
This is a chat room and you can speak freely and briefly.
|
||||
"""
|
||||
|
||||
SYS_PROMPT = """
|
||||
You can designate a member to reply to your message, you can use the @ symbol.
|
||||
This means including the @ symbol in your message, followed by
|
||||
that person's name, and leaving a space after the name.
|
||||
|
||||
All participants are: {agent_names}
|
||||
"""
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""group chat"""
|
||||
npc_agents = agentscope.init(
|
||||
model_configs="./configs/model_configs.json",
|
||||
agent_configs="./configs/agent_configs.json",
|
||||
project="Conversation with Mentions",
|
||||
)
|
||||
|
||||
user = UserAgent()
|
||||
|
||||
agents = list(npc_agents) + [user]
|
||||
|
||||
hint = Msg(
|
||||
name="Host",
|
||||
content=DEFAULT_TOPIC
|
||||
+ SYS_PROMPT.format(
|
||||
agent_names=[agent.name for agent in agents],
|
||||
),
|
||||
role="assistant",
|
||||
)
|
||||
|
||||
rnd = 0
|
||||
speak_list = []
|
||||
with msghub(agents, announcement=hint):
|
||||
while True:
|
||||
try:
|
||||
x = user(timeout=USER_TIME_TO_SPEAK)
|
||||
if x.content == "exit":
|
||||
break
|
||||
except TimeoutError:
|
||||
x = {"content": ""}
|
||||
logger.info(
|
||||
f"User has not typed text for "
|
||||
f"{USER_TIME_TO_SPEAK} seconds, skip.",
|
||||
)
|
||||
|
||||
speak_list += filter_agents(x.get("content", ""), npc_agents)
|
||||
|
||||
if len(speak_list) > 0:
|
||||
next_agent = speak_list.pop(0)
|
||||
x = next_agent()
|
||||
else:
|
||||
next_agent = select_next_one(npc_agents, rnd)
|
||||
x = next_agent()
|
||||
|
||||
speak_list += filter_agents(x.content, npc_agents)
|
||||
|
||||
rnd += 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,90 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""An example of a conversation with a ReAct agent."""
|
||||
import sys
|
||||
import io
|
||||
|
||||
from agentscope.agents import UserAgent
|
||||
from agentscope.agents.react_agent import ReActAgent
|
||||
from agentscope.service import (
|
||||
bing_search, # or google_search,
|
||||
read_text_file,
|
||||
write_text_file,
|
||||
ServiceToolkit,
|
||||
ServiceResponse,
|
||||
ServiceExecStatus,
|
||||
)
|
||||
import agentscope
|
||||
|
||||
# Prepare the Bing API key and model configuration
|
||||
BING_API_KEY = "{YOUR_BING_API_KEY}"
|
||||
|
||||
YOUR_MODEL_CONFIGURATION_NAME = "{YOUR_MODEL_CONFIGURATION_NAME}"
|
||||
YOUR_MODEL_CONFIGURATION = {
|
||||
"model_type": "xxx",
|
||||
"config_name": YOUR_MODEL_CONFIGURATION_NAME,
|
||||
# ...
|
||||
}
|
||||
|
||||
|
||||
# Prepare a new tool function
|
||||
def execute_python_code(code: str) -> ServiceResponse: # pylint: disable=C0301
|
||||
"""
|
||||
Execute Python code and capture the output. Note you must `print` the output to get the result.
|
||||
Args:
|
||||
code (`str`):
|
||||
The Python code to be executed.
|
||||
""" # noqa
|
||||
|
||||
# Create a StringIO object to capture the output
|
||||
old_stdout = sys.stdout
|
||||
new_stdout = io.StringIO()
|
||||
sys.stdout = new_stdout
|
||||
|
||||
try:
|
||||
# Using `exec` to execute code
|
||||
exec(code)
|
||||
except Exception as e:
|
||||
# If an exception occurs, capture the exception information
|
||||
output = str(e)
|
||||
status = ServiceExecStatus.ERROR
|
||||
else:
|
||||
# If the execution is successful, capture the output
|
||||
output = new_stdout.getvalue()
|
||||
status = ServiceExecStatus.SUCCESS
|
||||
finally:
|
||||
# Recover the standard output
|
||||
sys.stdout = old_stdout
|
||||
|
||||
# Wrap the output and status into a ServiceResponse object
|
||||
return ServiceResponse(status, output)
|
||||
|
||||
|
||||
# Prepare the tools for the agent
|
||||
service_toolkit = ServiceToolkit()
|
||||
|
||||
service_toolkit.add(bing_search, api_key=BING_API_KEY, num_results=3)
|
||||
service_toolkit.add(execute_python_code)
|
||||
service_toolkit.add(read_text_file)
|
||||
service_toolkit.add(write_text_file)
|
||||
|
||||
agentscope.init(
|
||||
model_configs=YOUR_MODEL_CONFIGURATION,
|
||||
project="Conversation with ReActAgent",
|
||||
)
|
||||
|
||||
# Create agents
|
||||
agent = ReActAgent(
|
||||
name="assistant",
|
||||
model_config_name=YOUR_MODEL_CONFIGURATION_NAME,
|
||||
verbose=True,
|
||||
service_toolkit=service_toolkit,
|
||||
)
|
||||
user = UserAgent(name="User")
|
||||
|
||||
# Build
|
||||
x = None
|
||||
while True:
|
||||
x = user(x)
|
||||
if x.content == "exit":
|
||||
break
|
||||
x = agent(x)
|
||||
576
AlgoriAgent/examples/conversation_with_react_agent/main.ipynb
Normal file
576
AlgoriAgent/examples/conversation_with_react_agent/main.ipynb
Normal file
@@ -0,0 +1,576 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# Conversation with a ReAct Agent\n",
|
||||
"\n",
|
||||
"In this example, we will show you\n",
|
||||
"- How to create a new service function for the tool agent to use\n",
|
||||
"- How to use the ServiceToolkit module pre-process the tool functions for LLMs\n",
|
||||
"- How to use the built-in ReAct agent to solve a problem\n",
|
||||
"\n",
|
||||
"## Prerequisites\n",
|
||||
"\n",
|
||||
"- Follow [READMD.md](https://github.com/modelscope/agentscope) to install AgentScope. \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",
|
||||
"- [Optional] A bing (or google) search API key is suggested to experience the web search function. Here we take bing search as an example. \n",
|
||||
"\n",
|
||||
"## Note\n",
|
||||
"\n",
|
||||
"- The example is tested with the following models. For other models, you may need to adjust the prompt.\n",
|
||||
" - gpt-4\n",
|
||||
" - gpt-3.5-turbo\n",
|
||||
" - qwen-max"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "6b868755498c634a"
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"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",
|
||||
"}\n",
|
||||
"\n",
|
||||
"BING_API_KEY = \"{BING_API_KEY}\""
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-04-16T01:51:29.449020Z",
|
||||
"start_time": "2024-04-16T01:51:29.435200Z"
|
||||
}
|
||||
},
|
||||
"id": "8355a19d4eb5af55"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Step 1: Customize a Service Function\n",
|
||||
"\n",
|
||||
"Taking `execute_python_code` as an example, we will show how to create a new service function that can be processed by `ServiceToolkit` module.\n",
|
||||
"\n",
|
||||
"In AgentScope, a service function should have the following structure:\n",
|
||||
"\n",
|
||||
"- A well formatted docstring (Google style is recommended), which contains\n",
|
||||
" - A brief description of function in docstring.\n",
|
||||
" - A brief description of the input arguments.\n",
|
||||
" - Wrap the output and execution status into a `ServiceResponse` object.\n",
|
||||
"\n",
|
||||
"The following is a simple example of a service function that executes Python code and captures the output. (Also, you can use the `execute_python_code` function in the `agentscope.service` module directly, which provide more features.)\""
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "8ef2e3639e08cc0a"
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from agentscope.service import ServiceResponse, ServiceExecStatus\n",
|
||||
"import sys, io\n",
|
||||
"\n",
|
||||
"def execute_python_code(code: str) -> ServiceResponse:\n",
|
||||
" \"\"\"\n",
|
||||
" Execute Python code and capture the output. Note you must `print` the output to get the result.\n",
|
||||
" Args:\n",
|
||||
" code (`str`):\n",
|
||||
" The Python code to be executed.\n",
|
||||
" \"\"\" # noqa\n",
|
||||
"\n",
|
||||
" # Create a StringIO object to capture the output\n",
|
||||
" old_stdout = sys.stdout\n",
|
||||
" new_stdout = io.StringIO()\n",
|
||||
" sys.stdout = new_stdout\n",
|
||||
"\n",
|
||||
" try:\n",
|
||||
" # Using `exec` to execute code\n",
|
||||
" exec(code)\n",
|
||||
" except Exception as e:\n",
|
||||
" # If an exception occurs, capture the exception information\n",
|
||||
" output = str(e)\n",
|
||||
" status = ServiceExecStatus.ERROR\n",
|
||||
" else:\n",
|
||||
" # If the execution is successful, capture the output\n",
|
||||
" output = new_stdout.getvalue()\n",
|
||||
" status = ServiceExecStatus.SUCCESS\n",
|
||||
" finally:\n",
|
||||
" # Recover the standard output\n",
|
||||
" sys.stdout = old_stdout\n",
|
||||
"\n",
|
||||
" # Wrap the output and status into a ServiceResponse object\n",
|
||||
" return ServiceResponse(status, output)"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-04-16T01:51:38.238708Z",
|
||||
"start_time": "2024-04-16T01:51:36.965973Z"
|
||||
}
|
||||
},
|
||||
"id": "9d34e13ea408f21d"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"After defining the service function, we try to use `ServiceToolkit` to pre-process the tool functions for LLMs. Here, we take `execute_python_code` function as example and observe the JSON schema generated by `service_toolkit`."
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "a97eab8ecc98ed89"
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{\n",
|
||||
" \"execute_python_code\": {\n",
|
||||
" \"type\": \"function\",\n",
|
||||
" \"function\": {\n",
|
||||
" \"name\": \"execute_python_code\",\n",
|
||||
" \"description\": \"Execute Python code and capture the output. Note you must `print` the output to get the result.\",\n",
|
||||
" \"parameters\": {\n",
|
||||
" \"type\": \"object\",\n",
|
||||
" \"properties\": {\n",
|
||||
" \"code\": {\n",
|
||||
" \"type\": \"string\",\n",
|
||||
" \"description\": \"The Python code to be executed.\"\n",
|
||||
" }\n",
|
||||
" },\n",
|
||||
" \"required\": [\n",
|
||||
" \"code\"\n",
|
||||
" ]\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
"}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from agentscope.service import ServiceToolkit\n",
|
||||
"\n",
|
||||
"service_toolkit = ServiceToolkit()\n",
|
||||
"service_toolkit.add(execute_python_code)\n",
|
||||
"\n",
|
||||
"import json\n",
|
||||
"print(json.dumps(service_toolkit.json_schemas, indent=4))"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-04-16T01:51:43.581845Z",
|
||||
"start_time": "2024-04-16T01:51:43.578326Z"
|
||||
}
|
||||
},
|
||||
"id": "1ef000177bccd2a5"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Step 2: Prepare all tool functions for the agent\n",
|
||||
"Similar as above, we can create different service functions, or use the built-in functions in `agentscope.service` module as follows. More service functions can be found under the `agentscope.service` module."
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "ebd210b104459fb5"
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from agentscope.service import (\n",
|
||||
" bing_search, # or google_search,\n",
|
||||
" read_text_file,\n",
|
||||
" write_text_file, \n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Deal with arguments that need to be input by developers\n",
|
||||
"service_toolkit.add(bing_search, api_key=BING_API_KEY, num_results=3)\n",
|
||||
"service_toolkit.add(read_text_file)\n",
|
||||
"service_toolkit.add(write_text_file)"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-04-16T01:52:00.399308Z",
|
||||
"start_time": "2024-04-16T01:52:00.393475Z"
|
||||
}
|
||||
},
|
||||
"id": "9c7f4d40bfab5003"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Step 3: Create a React Agent"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "794e63922cd0c954"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"A ReAct Agent is built in AgentScope to show how to construct complex reasoning processes. It solves a problem by a loop of \"thought\", \"action\" and \"observation\" steps. \n",
|
||||
"\n",
|
||||
"- thought: analyze and decide next action (the tools to use)\n",
|
||||
"- action: execute the action (the tool function)\n",
|
||||
"- observation: observe the execution results\n",
|
||||
"\n",
|
||||
"In AgentScope, we implement the above steps in a `ReActAgent` class. Let's first taking a look at its system prompt. "
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "3f2e4ad0458966cd"
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"2024-04-16 09:52:31.694 | INFO | agentscope.models:read_model_configs:181 - Load configs for model wrapper: qwen, gpt-4, ollama\n",
|
||||
"2024-04-16 09:52:31.711 | INFO | agentscope.utils.monitor:_create_monitor_table:341 - Init [monitor_metrics] as the monitor table\n",
|
||||
"2024-04-16 09:52:31.712 | INFO | agentscope.utils.monitor:_create_monitor_table:342 - Init [monitor_metrics_quota_exceeded] as the monitor trigger\n",
|
||||
"2024-04-16 09:52:31.712 | INFO | agentscope.utils.monitor:__init__:311 - SqliteMonitor initialization completed at [./runs/run_20240416-095137_jgmih8/agentscope.db]\n",
|
||||
"2024-04-16 09:52:31.716 | INFO | agentscope.models.model:__init__:200 - Initialize model by configuration [qwen]\n",
|
||||
"2024-04-16 09:52:31.718 | INFO | agentscope.utils.monitor:register:362 - Register metric [qwen-max.call_counter] to SqliteMonitor with unit [times] and quota [None]\n",
|
||||
"2024-04-16 09:52:31.719 | INFO | agentscope.utils.monitor:register:362 - Register metric [qwen-max.prompt_tokens] to SqliteMonitor with unit [token] and quota [None]\n",
|
||||
"2024-04-16 09:52:31.721 | INFO | agentscope.utils.monitor:register:362 - Register metric [qwen-max.completion_tokens] to SqliteMonitor with unit [token] and quota [None]\n",
|
||||
"2024-04-16 09:52:31.722 | INFO | agentscope.utils.monitor:register:362 - Register metric [qwen-max.total_tokens] to SqliteMonitor with unit [token] and quota [None]\n",
|
||||
"################################################################################\n",
|
||||
"You're a helpful assistant. Your name is assistant.\n",
|
||||
"\n",
|
||||
"## Tool Functions:\n",
|
||||
"The following tool functions are available in the format of\n",
|
||||
"```\n",
|
||||
"{index}. {function name}: {function description}\n",
|
||||
"{argument1 name} ({argument type}): {argument description}\n",
|
||||
"{argument2 name} ({argument type}): {argument description}\n",
|
||||
"...\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"1. execute_python_code: Execute Python code and capture the output. Note you must `print` the output to get the result.\n",
|
||||
"\tcode (string): The Python code to be executed.\n",
|
||||
"2. bing_search: Search question in Bing Search API and return the searching results\n",
|
||||
"\tquestion (string): The search query string.\n",
|
||||
"3. read_text_file: Read the content of the text file.\n",
|
||||
"\tfile_path (string): The path to the text file to be read.\n",
|
||||
"4. write_text_file: Write content to a text file.\n",
|
||||
"\tfile_path (string): The path to the file where content will be written.\n",
|
||||
"\toverwrite (boolean): Whether to overwrite the file if it already exists.\n",
|
||||
"\tcontent (string): Content to write into the file.\n",
|
||||
"\n",
|
||||
"## What You Should Do:\n",
|
||||
"1. First, analyze the current situation, and determine your goal.\n",
|
||||
"2. Then, check if your goal is already achieved. If so, try to generate a response. Otherwise, think about how to achieve it with the help of provided tool functions.\n",
|
||||
"3. Respond in the required format.\n",
|
||||
"\n",
|
||||
"## Note:\n",
|
||||
"1. Fully understand the tool functions and their arguments before using them.\n",
|
||||
"2. You should decide if you need to use the tool functions, if not then return an empty list in \"function\" field.\n",
|
||||
"3. Make sure the types and values of the arguments you provided to the tool functions are correct.\n",
|
||||
"4. Don't take things for granted. For example, where you are, what's the time now, etc. You can try to use the tool functions to get information.\n",
|
||||
"5. If the function execution fails, you should analyze the error and try to solve it.\n",
|
||||
"\n",
|
||||
"################################################################################\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from agentscope.agents import ReActAgent\n",
|
||||
"import agentscope\n",
|
||||
"\n",
|
||||
"agentscope.init(\n",
|
||||
" model_configs=YOUR_MODEL_CONFIGURATION,\n",
|
||||
" project=\"Conversation with ReActAgent\",\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"agent = ReActAgent(\n",
|
||||
" name=\"assistant\",\n",
|
||||
" model_config_name=YOUR_MODEL_CONFIGURATION_NAME,\n",
|
||||
" service_toolkit=service_toolkit, \n",
|
||||
" verbose=True, # set verbose to True to show the reasoning process\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(\"#\"*80)\n",
|
||||
"print(agent.sys_prompt)\n",
|
||||
"print(\"#\"*80)"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-04-16T01:52:31.741951Z",
|
||||
"start_time": "2024-04-16T01:52:31.675Z"
|
||||
}
|
||||
},
|
||||
"id": "ad793ef9e2bb7945"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"As shown above, the system prompt is consisted of \n",
|
||||
"\n",
|
||||
"- the description of the agent\n",
|
||||
"- the description of tool functions\n",
|
||||
"- some notices for the large language models\n",
|
||||
"\n",
|
||||
"Besides, when ReAct Agent generates \"thought\", we use the following prompt to guide the generation. It's wrapped into a message with `role` field as `\"system\"` to distinguish from the user's input.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"# print(agent.parser.format_instruction)\n",
|
||||
"\"\"\"\n",
|
||||
"You should respond a json object in a json fenced code block as follows:\n",
|
||||
"```json\n",
|
||||
"{\n",
|
||||
"\t\"thought\": \"what you thought\", \n",
|
||||
"\t\"speak\": \"what you speak\", \n",
|
||||
"\t\"function\": [\n",
|
||||
"\t\t{\n",
|
||||
"\t\t\t\"name\": \"{function name}\", \n",
|
||||
"\t\t\t\"arguments\": {\n",
|
||||
"\t\t\t\t\"{argument1 name}\": xxx, \n",
|
||||
"\t\t\t\t\"{argument2 name}\": xxx\n",
|
||||
"\t\t\t}\n",
|
||||
"\t\t}\n",
|
||||
"\t]\n",
|
||||
"}```\n",
|
||||
"\"\"\"\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"When the `function` field in the response dictionary is empty, the agent will end the \"reasoning-acting\" loop and return the final response to the user. \n",
|
||||
"\n",
|
||||
"More implementation details please refer to the [source code](../../src/agentscope/agents/react_agent.py)."
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "ca977a86cdd1b482"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Step 4: Try to Solve a Problem with the ReAct Agent\n",
|
||||
"\n",
|
||||
"Now, let's try to ask the example question in the ReAct Paper: `\"Aside from the Apple Remote, what other device can control the program Apple Remote was originally designed to interact with?\"` as follows"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "b6e2e7a1c5fac168"
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from agentscope.message import Msg\n",
|
||||
"\n",
|
||||
"msg_question = Msg(\n",
|
||||
" name=\"user\", \n",
|
||||
" content=\"Aside from the Apple Remote, what other device can control the program Apple Remote was originally designed to interact with?\", \n",
|
||||
" role=\"user\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"res = agent(msg_question)"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-04-16T02:02:06.982344Z",
|
||||
"start_time": "2024-04-16T02:00:21.137787Z"
|
||||
}
|
||||
},
|
||||
"id": "be6ffe0c91474589"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"The above example is very interesting! Because the ReAct algorithm is famous and its example question occurs in many different websites, the results in the first searching are all about ReAct algorithm, rather than the answer to the question. \n",
|
||||
"\n",
|
||||
"Knowing this, in the reasoning step of the second iteration, the ReAct agent decides to rewrite the query and re-search in the website. It finally finds the answer in the third iteration. \n",
|
||||
"\n",
|
||||
"The behavior of the ReAct agent is unexpected and interesting. It shows that the ReAct agent can learn from the previous results and adjust its behavior in the next iteration. \n",
|
||||
"\n",
|
||||
"You can use the following code to build a conversation with the ReAct agent, and we also provide [completed code](./code/conversation_with_react_agent.py). \n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"from agentscope.agents import UserAgent\n",
|
||||
"\n",
|
||||
"user = UserAgent(name=\"User\")\n",
|
||||
"\n",
|
||||
"x = None\n",
|
||||
"while True:\n",
|
||||
" x = user(x)\n",
|
||||
" if x.content == \"exit\":\n",
|
||||
" break\n",
|
||||
" x = agent(x)\n",
|
||||
"```"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "602ccd32a8514db7"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"In the end, we print the memory of the agent to show the reasoning process."
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"id": "a1b8d2b3993d36a"
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[\n",
|
||||
" {\n",
|
||||
" \"id\": \"d71ec3345ca3452697d33da946d3725f\",\n",
|
||||
" \"timestamp\": \"2024-03-26 19:19:57\",\n",
|
||||
" \"name\": \"system\",\n",
|
||||
" \"content\": \"You are a helpful assistant.\\n\\nThe following tool functions are available in the format of\\n```\\n{index}. {function name}: {function description}\\n {argument name} ({argument type}): {argument description}\\n ...\\n```\\n\\nTool Functions:\\n1. bing_search: Search question in Bing Search API and return the searching results\\n\\tquestion (string): The search query string.\\n2. execute_python_code: Execute Python code and capture the output. Note you must `print` the output to get the result.\\n\\tcode (string): The Python code to be executed.\\n3. read_text_file: Read the content of the text file.\\n\\tfile_path (string): The path to the text file to be read.\\n4. write_text_file: Write content to a text file.\\n\\toverwrite (boolean): Whether to overwrite the file if it already exists.\\n\\tfile_path (string): The path to the file where content will be written.\\n\\tcontent (string): Content to write into the file.\\n\\nNotice:\\n1. Fully understand the tool function and its arguments before using it.\\n2. Only use the tool function when it's necessary.\\n3. Check if the arguments you provided to the tool function is correct in type and value.\\n4. You can't take some problems for granted. For example, where you are, what's the time now, etc. But you can try to use the tool function to solve the problem.\\n5. If the function execution fails, you should analyze the error and try to solve it.\\n\\n\",\n",
|
||||
" \"url\": null,\n",
|
||||
" \"role\": \"system\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"2a43c07ef95644aa9eb25b28731cd65c\",\n",
|
||||
" \"timestamp\": \"2024-03-26 19:19:57\",\n",
|
||||
" \"name\": \"user\",\n",
|
||||
" \"content\": \"Aside from the Apple Remote, what other device can control the program Apple Remote was originally designed to interact with?\",\n",
|
||||
" \"url\": null,\n",
|
||||
" \"role\": \"user\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"4a25ccc466f34653ac6e6acb86fc24d6\",\n",
|
||||
" \"timestamp\": \"2024-03-26 19:20:02\",\n",
|
||||
" \"name\": \"assistant\",\n",
|
||||
" \"content\": {\n",
|
||||
" \"thought\": \"I need to search for information about what other devices can control the program that the Apple Remote was originally designed to interact with.\",\n",
|
||||
" \"speak\": \"Let me find that information for you.\",\n",
|
||||
" \"function\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"bing_search\",\n",
|
||||
" \"arguments\": {\n",
|
||||
" \"question\": \"What devices can control the program Apple Remote was designed for?\"\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" ]\n",
|
||||
" },\n",
|
||||
" \"url\": null,\n",
|
||||
" \"role\": \"assistant\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"253d8cc15548499e97259d5fedde92f7\",\n",
|
||||
" \"timestamp\": \"2024-03-26 19:20:03\",\n",
|
||||
" \"name\": \"system\",\n",
|
||||
" \"content\": \"Execution Results:\\n1. bing_search:\\n [EXECUTE STATUS]: SUCCESS\\n [EXECUTE RESULT]: [{'title': '《ReAct: SYNERGIZING REASONING AND ACTING IN ...', 'link': 'https://www.cnblogs.com/LittleHann/p/17541295.html', 'snippet': 'Aside from the Apple Remote, what other devices can control the program Apple Remote was originally designed to interact with? 我们可以看到该模型生成了任务解决轨迹(思考、行动)。'}, {'title': 'REACT:在大模型中协同推理与行动,使其能够解决推理和 ...', 'link': 'https://baijiahao.baidu.com/s?id=1775590643651365661', 'snippet': 'Q:Aside from the Apple Remote, what other device can control the program Apple Remote was originally designed to intect with? 除了苹果遥控器之外,还有哪些设备可以控制最初设计用于连接的苹果遥控器所配合的程序?'}, {'title': 'ReAct Prompting | Prompt Engineering Guide', 'link': 'https://www.promptingguide.ai/techniques/react', 'snippet': 'Aside from the Apple Remote, what other devices can control the program Apple Remote was originally designed to interact with? Note that in-context examples are also added to the prompt but we exclude that here for simplicity.'}]\\n\",\n",
|
||||
" \"url\": null,\n",
|
||||
" \"role\": \"system\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"2346ccec579b48848a669d9f16b53c49\",\n",
|
||||
" \"timestamp\": \"2024-03-26 19:20:10\",\n",
|
||||
" \"name\": \"assistant\",\n",
|
||||
" \"content\": {\n",
|
||||
" \"thought\": \"The search results did not provide a clear answer to the question. I need to refine the search query to get more specific results.\",\n",
|
||||
" \"speak\": \"I'm sorry, I couldn't find a clear answer. Let me try a different search.\",\n",
|
||||
" \"function\": [\n",
|
||||
" {\n",
|
||||
" \"name\": \"bing_search\",\n",
|
||||
" \"arguments\": {\n",
|
||||
" \"question\": \"What devices can control Apple TV other than Apple Remote?\"\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" ]\n",
|
||||
" },\n",
|
||||
" \"url\": null,\n",
|
||||
" \"role\": \"assistant\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"67d707e4c0d44751aae5c5bbbe978f16\",\n",
|
||||
" \"timestamp\": \"2024-03-26 19:20:11\",\n",
|
||||
" \"name\": \"system\",\n",
|
||||
" \"content\": \"Execution Results:\\n1. bing_search:\\n [EXECUTE STATUS]: SUCCESS\\n [EXECUTE RESULT]: [{'title': 'Use other remotes to control Apple TV - Apple Support', 'link': 'https://support.apple.com/guide/tv/use-other-remotes-atvb0410f604/tvos', 'snippet': 'Table of Contents. Use other remotes to control Apple TV. You can use a supported TV or receiver remote, a network-based remote for home-control systems, or an infrared remote (commonly known as a universal remote) to control Apple TV.'}, {'title': '4 Siri Remote Alternatives You Can Use to Control Your Apple TV - MUO', 'link': 'https://www.makeuseof.com/alternative-apple-tv-remotes/', 'snippet': \\\"Fortunately, if you find yourself looking for alternatives to control your Apple TV, there are several good options for you. You can use other Apple devices to operate the Apple TV, or even affordable Bluetooth accessories. We'll highlight the best alternatives to the Apple TV remote. 1. Use Your iPhone or iPad to Control the Apple TV\\\"}, {'title': 'Apple TV Siri Remote: How to control TVs and receivers - 9to5Mac', 'link': 'https://9to5mac.com/2021/05/27/apple-tv-siri-remote-control-tv-receiver/', 'snippet': 'The old Siri Remote and Apple TV Remote also feature this functionality, but without a dedicated power button, it’s less convenient and intuitive to use. Another benefit of HDMI-CEC is that...'}]\\n\",\n",
|
||||
" \"url\": null,\n",
|
||||
" \"role\": \"system\"\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"id\": \"7c36f98d1c204a03941375bef1eb44ee\",\n",
|
||||
" \"timestamp\": \"2024-03-26 19:20:19\",\n",
|
||||
" \"name\": \"assistant\",\n",
|
||||
" \"content\": {\n",
|
||||
" \"thought\": \"The search results provided a clear answer to the question. Other than the Apple Remote, you can use a supported TV or receiver remote, a network-based remote for home-control systems, an infrared remote (commonly known as a universal remote), or other Apple devices like an iPhone or iPad to control the Apple TV.\",\n",
|
||||
" \"speak\": \"Other than the Apple Remote, you can use a supported TV or receiver remote, a network-based remote for home-control systems, an infrared remote (commonly known as a universal remote), or other Apple devices like an iPhone or iPad to control the Apple TV.\"\n",
|
||||
" },\n",
|
||||
" \"url\": null,\n",
|
||||
" \"role\": \"assistant\"\n",
|
||||
" }\n",
|
||||
"]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(json.dumps(agent.memory.get_memory(), indent=4, ensure_ascii=False))"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2024-03-26T12:08:33.469827Z",
|
||||
"start_time": "2024-03-26T12:08:33.456020Z"
|
||||
}
|
||||
},
|
||||
"id": "5e099490946662f1"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 2
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython2",
|
||||
"version": "2.7.6"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
291
AlgoriAgent/examples/conversation_with_swe-agent/main.ipynb
Normal file
291
AlgoriAgent/examples/conversation_with_swe-agent/main.ipynb
Normal file
@@ -0,0 +1,291 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Conversation with Software Engineering Agent\n",
|
||||
"\n",
|
||||
"SWE-agent(SoftWare Engineering Agent) is an agent designed for solving real world software engineering problems, such as fixing github issues.\n",
|
||||
"More details can be found in the project's [homepage](https://swe-agent.com/) and related [github repo](https://swe-agent.com/).\n",
|
||||
"\n",
|
||||
"In the example here, we partially implement the SWE-agent, and provide a simple example of how to use the implemented SWE-agent to fix a bug in a python file.\n",
|
||||
"You should note that currently how to enable agents with stronger programming capabilities remains an open challenge, and the performance of the paritially implemented SWE-agent is not guaranteed.\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",
|
||||
"- Understand the ServiceToolkit module and how to use it to pre-process the tool functions for LLMs. You can refer to the [ReAct agent example](../conversation_with_react_agent/main.ipynb) and you should also refer to the [tutorial](https://modelscope.github.io/agentscope/en/tutorial/204-service.html) for service functions.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## Note\n",
|
||||
"\n",
|
||||
"- The example is tested with the following models. For other models, you may need to adjust the prompt.\n",
|
||||
" - gpt-4\n",
|
||||
" - dashscope_chat (qwen-max)\n",
|
||||
" - gemini_chat (gemini-pro)\n",
|
||||
" - ollama_chat (llama3_8b)\n",
|
||||
"- How to enable agents with stronger programming capabilities remains an open challenge, and the current implementations are not perfect. Please feel free to explore it yourself."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"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: Initialize the AgentScope environment and SWE-agent\n",
|
||||
"\n",
|
||||
"Here we init the agentscope environment and load the SWE-agent.\n",
|
||||
"\n",
|
||||
"The code of SWE-agent is in `swe_agent.py`, and the related prompts are in `swe_agent_prompts.py`.\n",
|
||||
"\n",
|
||||
"If you are interested in the details, please refer to the code and the origianl SWE-agent repo [here](https://github.com/princeton-nlp/SWE-agent)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from swe_agent import SWEAgent\n",
|
||||
"\n",
|
||||
"import agentscope\n",
|
||||
"\n",
|
||||
"agentscope.init(\n",
|
||||
" model_configs=YOUR_MODEL_CONFIGURATION,\n",
|
||||
" project=\"Conversation with SWE-agent\",\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"agent = SWEAgent(\n",
|
||||
" name=\"assistant\",\n",
|
||||
" model_config_name=YOUR_MODEL_CONFIGURATION_NAME,\n",
|
||||
")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 2: Create the code to be processed by the SWE-agent\n",
|
||||
"\n",
|
||||
"Here we use the `write_file` function to write the following code into `gcd.py`.\n",
|
||||
"The code here is a wrong implementation of the [Greatest Common Divisor (GCD) algorithm](https://en.wikipedia.org/wiki/Euclidean_algorithm).\n",
|
||||
"We will ask the SWE-agent to correct it in our next step."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'status': <ServiceExecStatus.SUCCESS: 1>,\n",
|
||||
" 'content': 'WRITE OPERATION:\\nYou have written to \"gcd.py\" on these lines: 0:-1.\\ndef gcd(a, b):\\n if a == 0:\\n return b\\n while a != 0:\\n a, b = b, a\\n return b\\n\\ndef lcm(a, b):\\n return (a * b) // gcd(a, b)\\n\\n# testing on GCD and LCM functions\\nprint(\"GCD of 12 and 18 is:\", gcd(12, 18))\\nprint(\"LCM of 12 and 18 is:\", lcm(12, 18))\\n\\n'}"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from swe_agent_service_func import write_file\n",
|
||||
"\n",
|
||||
"# here the gcd code is written in a wrong way\n",
|
||||
"wrong_gcd_text = \"\"\"\n",
|
||||
"def gcd(a, b):\n",
|
||||
" if a == 0:\n",
|
||||
" return b\n",
|
||||
" while a != 0:\n",
|
||||
" a, b = b, a\n",
|
||||
" return b\n",
|
||||
"\n",
|
||||
"def lcm(a, b):\n",
|
||||
" return (a * b) // gcd(a, b)\n",
|
||||
"\n",
|
||||
"# testing on GCD and LCM functions\n",
|
||||
"print(\"GCD of 12 and 18 is:\", gcd(12, 18))\n",
|
||||
"print(\"LCM of 12 and 18 is:\", lcm(12, 18))\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"write_file(\"gcd.py\", wrong_gcd_text)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Step 3: Ask the SWE-agent to correct the code\n",
|
||||
"\n",
|
||||
"Here we simple ask the SWE-agent to correct the code in `gcd.py`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"user: The file in gcd.py is not returning the correct answer, can you fix the file for me?\n",
|
||||
"assistant: {\n",
|
||||
" \"thought\": \"First thing I'll do is read the content of gcd.py file to understand the existing logic.\",\n",
|
||||
" \"action\": {\n",
|
||||
" \"name\": \"read_file\",\n",
|
||||
" \"arguments\": {\n",
|
||||
" \"file_path\": \"gcd.py\"\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"assistant: \n",
|
||||
"====Observation====\n",
|
||||
"\n",
|
||||
"def gcd(a, b):\n",
|
||||
" if a == 0:\n",
|
||||
" return b\n",
|
||||
" while a != 0:\n",
|
||||
" a, b = b, a\n",
|
||||
" return b\n",
|
||||
"\n",
|
||||
"def lcm(a, b):\n",
|
||||
" return (a * b) // gcd(a, b)\n",
|
||||
"\n",
|
||||
"# testing on GCD and LCM functions\n",
|
||||
"print(\"GCD of 12 and 18 is:\", gcd(12, 18))\n",
|
||||
"print(\"LCM of 12 and 18 is:\", lcm(12, 18))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"assistant: {\n",
|
||||
" \"thought\": \"I can see the error in the gcd calculation. The gcd calculation in the file is incorrect. The correct way to find the gcd of two numbers using the Euclidean algorithm is to continually reduce a and b by finding the remainder of a % b until b is 0, at which point a will be the gcd of the original a and b values. In the given code, instead of finding the remainder, it is incorrectly swapping the values of a and b. I'll correct this error by modifying the gcd function using the write_file command, reflecting the correct Euclidean algorithm.\",\n",
|
||||
" \"action\": {\n",
|
||||
" \"name\": \"write_file\",\n",
|
||||
" \"arguments\": {\n",
|
||||
" \"start_line\": 0,\n",
|
||||
" \"end_line\": 15,\n",
|
||||
" \"content\": \"def gcd(a, b):\\n while b != 0:\\n a, b = b, a % b\\n return a\\n\\n\\ndef lcm(a, b):\\n return (a * b) // gcd(a, b)\\n\\n\\n# testing on GCD and LCM functions\\nprint(\\\"GCD of 12 and 18 is:\\\", gcd(12, 18))\\nprint(\\\"LCM of 12 and 18 is:\\\", lcm(12, 18))\\n\",\n",
|
||||
" \"file_path\": \"gcd.py\"\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"assistant: \n",
|
||||
"====Observation====\n",
|
||||
"WRITE OPERATION:\n",
|
||||
"You have written to \"gcd.py\" on these lines: 0:15.def gcd(a, b):\n",
|
||||
" while b != 0:\n",
|
||||
" a, b = b, a % b\n",
|
||||
" return a\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def lcm(a, b):\n",
|
||||
" return (a * b) // gcd(a, b)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# testing on GCD and LCM functions\n",
|
||||
"print(\"GCD of 12 and 18 is:\", gcd(12, 18))\n",
|
||||
"print(\"LCM of 12 and 18 is:\", lcm(12, 18))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"assistant: {\n",
|
||||
" \"thought\": \"I should run the python file to see if the changes I made have fixed the gcd function.\",\n",
|
||||
" \"action\": {\n",
|
||||
" \"name\": \"execute_shell_command\",\n",
|
||||
" \"arguments\": {\n",
|
||||
" \"command\": \"python3 gcd.py\"\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"assistant: \n",
|
||||
"====Observation====\n",
|
||||
"GCD of 12 and 18 is: 6\n",
|
||||
"LCM of 12 and 18 is: 36\n",
|
||||
"assistant: {\n",
|
||||
" \"thought\": \"The gcd.py file has been fixed and tested successfully. Therefore, no further actions are needed.\",\n",
|
||||
" \"action\": {\n",
|
||||
" \"name\": \"exit\",\n",
|
||||
" \"arguments\": {}\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"assistant: \n",
|
||||
"====Observation====\n",
|
||||
"Current task finished, exitting.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from loguru import logger\n",
|
||||
"from agentscope.message import Msg\n",
|
||||
"\n",
|
||||
"mss = Msg(\n",
|
||||
" name=\"user\", \n",
|
||||
" content=\"The file in gcd.py is not returning the correct answer, can you fix the file for me?\", \n",
|
||||
" role=\"user\"\n",
|
||||
")\n",
|
||||
"logger.chat(mss)\n",
|
||||
"answer_mss = agent(mss)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Conlusion\n",
|
||||
"\n",
|
||||
"After a few iterations, the SWE-agent assistant finish the job successfully, and the code is now working fine."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Above we shown a example of how to use the SWE-agent to fix code errors.\n",
|
||||
"Although the design of the SWE-agent is primarily aimed at addressing GitHub issues, with modifications, it can also be utilized for more general programming tasks.\n",
|
||||
"\n",
|
||||
"Currently, how to enable agent with general programming ablities remains a challenging open question, with the efficacy of agent programming potentially influenced by factors such as prompt construction, model capabilities, and the complexity of the task at hand. Here we just provide an interesting toy example. \n",
|
||||
"\n",
|
||||
"We encourage users to experiment by altering the prompts within this example or by assigning different tasks to the agent, among other methods of exploration. Please feel free to experiment and explore on your own. The AgentScope team will continue to provide updates, enhancing the capabilities of the Programming Agents in the future!"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "datajuicer",
|
||||
"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
|
||||
}
|
||||
274
AlgoriAgent/examples/conversation_with_swe-agent/swe_agent.py
Normal file
274
AlgoriAgent/examples/conversation_with_swe-agent/swe_agent.py
Normal file
@@ -0,0 +1,274 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""An agent class that partially implements the SWE-agent.
|
||||
SWE-agent is an agent designed for solving github issues.
|
||||
More details can be found in https://swe-agent.com/.
|
||||
|
||||
Here we partially implement and modified the SWE-agent,
|
||||
try to make it work with wider range of tasks then just fixing github issues.
|
||||
"""
|
||||
|
||||
from agentscope.agents import AgentBase
|
||||
from agentscope.message import Msg
|
||||
from agentscope.exception import ResponseParsingError
|
||||
from agentscope.parsers import MarkdownJsonDictParser
|
||||
from typing import List, Callable, Optional, Union, Sequence
|
||||
import json
|
||||
from agentscope.service import (
|
||||
ServiceFactory,
|
||||
execute_shell_command,
|
||||
)
|
||||
|
||||
from swe_agent_service_func import (
|
||||
exec_py_linting,
|
||||
write_file,
|
||||
read_file,
|
||||
)
|
||||
|
||||
from swe_agent_prompts import (
|
||||
get_system_prompt,
|
||||
get_context_prompt,
|
||||
get_step_prompt,
|
||||
)
|
||||
|
||||
|
||||
def prepare_func_prompt(function: Callable) -> str:
|
||||
func, desc = ServiceFactory.get(function)
|
||||
func_name = desc["function"]["name"]
|
||||
func_desc = desc["function"]["description"]
|
||||
args_desc = desc["function"]["parameters"]["properties"]
|
||||
|
||||
args_list = [f"{func_name}: {func_desc}"]
|
||||
for args_name, args_info in args_desc.items():
|
||||
if "type" in args_info:
|
||||
args_line = (
|
||||
f'\t{args_name} ({args_info["type"]}): '
|
||||
f'{args_info.get("description", "")}'
|
||||
)
|
||||
else:
|
||||
args_line = f'\t{args_name}: {args_info.get("description", "")}'
|
||||
args_list.append(args_line)
|
||||
|
||||
func_prompt = "\n".join(args_list)
|
||||
return func_prompt
|
||||
|
||||
|
||||
COMMANDS_DISCRIPTION_DICT = {
|
||||
"exit": "exit: Executed when the current task is complete, takes no arguments", # noqa
|
||||
"scroll_up": "scroll_up: Scrolls up the current open file, will scroll up and show you the 100 lines above your current lines, takes no arguments", # noqa
|
||||
"scroll_down": "scroll_down: Scrolls down the current open file, will scroll down and show you the 100 lines below your current lines'takes no arguments", # noqa
|
||||
"goto": "goto: This will take you directly to the line <line_num> and show you the 100 lines below it. \n line_num (int): The line number to go to.", # noqa
|
||||
}
|
||||
|
||||
COMMANDS_DISCRIPTION_DICT["write_file"] = prepare_func_prompt(write_file)
|
||||
COMMANDS_DISCRIPTION_DICT["read_file"] = prepare_func_prompt(read_file)
|
||||
COMMANDS_DISCRIPTION_DICT["execute_shell_command"] = prepare_func_prompt(
|
||||
execute_shell_command,
|
||||
)
|
||||
COMMANDS_DISCRIPTION_DICT["exec_py_linting"] = prepare_func_prompt(
|
||||
exec_py_linting,
|
||||
)
|
||||
|
||||
|
||||
ERROR_INFO_PROMPT = """Your response is not a JSON object, and cannot be parsed by `json.loads` in parse function:
|
||||
## Your Response:
|
||||
[YOUR RESPONSE BEGIN]
|
||||
{response}
|
||||
[YOUR RESPONSE END]
|
||||
|
||||
## Error Information:
|
||||
{error_info}
|
||||
|
||||
Analyze the reason, and re-correct your response in the correct format.""" # pylint: disable=all # noqa
|
||||
|
||||
|
||||
def count_file_lines(file_path: str) -> int:
|
||||
with open(file_path, "r") as file:
|
||||
lines = file.readlines()
|
||||
return len(lines)
|
||||
|
||||
|
||||
class SWEAgent(AgentBase):
|
||||
"""
|
||||
The SWE-agent
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
model_config_name: str,
|
||||
) -> None:
|
||||
""" """
|
||||
super().__init__(
|
||||
name=name,
|
||||
model_config_name=model_config_name,
|
||||
)
|
||||
|
||||
self.memory_window = 6
|
||||
self.max_retries = 2
|
||||
self.running_memory: List[str] = []
|
||||
self.cur_file: str = ""
|
||||
self.cur_line: int = 0
|
||||
self.cur_file_content: str = ""
|
||||
|
||||
self.main_goal = ""
|
||||
self.commands_prompt = ""
|
||||
self.parser = MarkdownJsonDictParser()
|
||||
self.get_commands_prompt()
|
||||
|
||||
def get_current_file_content(self) -> None:
|
||||
"""
|
||||
Get the current file content.
|
||||
"""
|
||||
if self.cur_file == "":
|
||||
return
|
||||
start_line = self.cur_line - 50
|
||||
if start_line < 0:
|
||||
start_line = 0
|
||||
end_line = self.cur_line + 50
|
||||
if end_line > count_file_lines(self.cur_file):
|
||||
end_line = -1
|
||||
read_res = read_file(self.cur_file, start_line, end_line)
|
||||
self.cur_file_content = read_res.content
|
||||
|
||||
def step(self) -> Msg:
|
||||
"""
|
||||
Step the SWE-agent.
|
||||
"""
|
||||
message_list = []
|
||||
|
||||
# construct system prompt
|
||||
system_prompt = get_system_prompt(self.commands_prompt)
|
||||
message_list.append(Msg("user", system_prompt, role="system"))
|
||||
|
||||
# construct context prompt, i.e. previous actions
|
||||
context_prompt = get_context_prompt(
|
||||
self.running_memory,
|
||||
self.memory_window,
|
||||
)
|
||||
message_list.append(Msg("user", context_prompt, role="user"))
|
||||
|
||||
# construct step prompt for this instance
|
||||
self.get_current_file_content()
|
||||
step_prompt = get_step_prompt(
|
||||
self.main_goal,
|
||||
self.cur_file,
|
||||
self.cur_line,
|
||||
self.cur_file_content,
|
||||
)
|
||||
message_list.append(Msg("user", step_prompt, role="user"))
|
||||
|
||||
# get response from agent
|
||||
try:
|
||||
in_prompt = self.model.format(message_list)
|
||||
res = self.model(
|
||||
in_prompt,
|
||||
parse_func=self.parser.parse,
|
||||
max_retries=1,
|
||||
)
|
||||
|
||||
except ResponseParsingError as e:
|
||||
response_msg = Msg(self.name, e.raw_response, "assistant")
|
||||
self.speak(response_msg)
|
||||
|
||||
# Re-correct by model itself
|
||||
error_msg = Msg(
|
||||
name="system",
|
||||
content={
|
||||
"action": {"name": "error"},
|
||||
"error_msg": ERROR_INFO_PROMPT.format(
|
||||
parse_func=self.parser.parse,
|
||||
error_info=e.message,
|
||||
response=e.raw_response,
|
||||
),
|
||||
},
|
||||
role="system",
|
||||
)
|
||||
self.speak(error_msg)
|
||||
# continue
|
||||
self.running_memory.append(error_msg)
|
||||
return error_msg
|
||||
|
||||
msg_res = Msg(self.name, res.parsed, role="assistant")
|
||||
|
||||
self.speak(
|
||||
Msg(self.name, json.dumps(res.parsed, indent=4), role="assistant"),
|
||||
)
|
||||
|
||||
# parse and execute action
|
||||
action = res.parsed.get("action")
|
||||
|
||||
obs = self.prase_command(res.parsed["action"])
|
||||
self.speak(
|
||||
Msg(self.name, "\n====Observation====\n" + obs, role="assistant"),
|
||||
)
|
||||
|
||||
# add msg to context windows
|
||||
self.running_memory.append(str(action) + str(obs))
|
||||
return msg_res
|
||||
|
||||
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
|
||||
action_name = None
|
||||
self.main_goal = x.content
|
||||
while not action_name == "exit":
|
||||
msg = self.step()
|
||||
action_name = msg.content["action"]["name"]
|
||||
return msg
|
||||
|
||||
def prase_command(self, command_call: dict) -> str:
|
||||
command_name = command_call["name"]
|
||||
command_args = command_call["arguments"]
|
||||
if command_name == "exit":
|
||||
return "Current task finished, exitting."
|
||||
if command_name in ["goto", "scroll_up", "scroll_down"]:
|
||||
if command_name == "goto":
|
||||
line = command_call["arguments"]["line_num"]
|
||||
command_str = f"Going to {self.cur_file} line \
|
||||
{command_args['line_mum']}."
|
||||
command_failed_str = f"Failed to go to {self.cur_file} \
|
||||
line {command_args['line_num']}"
|
||||
if command_name == "scroll_up":
|
||||
line = self.cur_line - 100
|
||||
if line < 0:
|
||||
line = 0
|
||||
command_str = (
|
||||
f"Scrolling up from file {self.cur_file} to line {line}."
|
||||
)
|
||||
command_failed_str = (
|
||||
f"Failed to scroll up {self.cur_file} to line {line}"
|
||||
)
|
||||
if command_name == "scroll_down":
|
||||
line = self.cur_line + 100
|
||||
if line > count_file_lines(self.cur_file):
|
||||
line = count_file_lines(self.cur_file)
|
||||
command_str = (
|
||||
f"Scrolling down from file {self.cur_file} to line {line}."
|
||||
)
|
||||
command_failed_str = (
|
||||
f"Failed to scrool down {self.cur_file} to line {line}"
|
||||
)
|
||||
read_status = read_file(self.cur_file, line, line + 100)
|
||||
if read_status.status == "success":
|
||||
self.cur_line = line
|
||||
obs = read_status.content
|
||||
return f"{command_str}. Observe file content: {obs}"
|
||||
else:
|
||||
return command_failed_str
|
||||
if command_name == "execute_shell_command":
|
||||
return execute_shell_command(**command_args).content
|
||||
if command_name == "write_file":
|
||||
self.cur_file = command_args["file_path"]
|
||||
self.cur_line = command_args.get("start_line", 0)
|
||||
write_status = write_file(**command_args)
|
||||
return write_status.content
|
||||
if command_name == "read_file":
|
||||
self.cur_file = command_args["file_path"]
|
||||
self.cur_line = command_args.get("start_line", 0)
|
||||
read_status = read_file(**command_args)
|
||||
return read_status.content
|
||||
if command_name == "exec_py_linting":
|
||||
return exec_py_linting(**command_args).content
|
||||
return "No such command"
|
||||
|
||||
def get_commands_prompt(self) -> None:
|
||||
for name, desc in COMMANDS_DISCRIPTION_DICT.items():
|
||||
self.commands_prompt += f"{name}: {desc}\n"
|
||||
@@ -0,0 +1,123 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=C0301
|
||||
"""The SWE-agent relay heavily on it's prompts.
|
||||
This file contains the neccessary prompts for the SWE-agent.
|
||||
Some prompts are taken and modified from the original SWE-agent repo
|
||||
or the SWE-agent implementation from Open-Devin.
|
||||
"""
|
||||
|
||||
WINDOW = 100
|
||||
|
||||
|
||||
def get_system_prompt(command_prompt: str) -> str:
|
||||
"""
|
||||
Get the system prompt for SWE-agent.
|
||||
"""
|
||||
return f"""
|
||||
SETTING:
|
||||
You are an autonomous coding agent, here to perform codding tasks given the instruction.
|
||||
You have been designed with a wide range of programming tasks, from code editing and debugging to testing and deployment.
|
||||
You have access to a variety of tools and commands that you can use to help you solve problems efficiently.
|
||||
|
||||
You're working directly in the command line with a special interface.
|
||||
|
||||
The special interface consists of a file editor that shows you {WINDOW} lines of a file at a time.
|
||||
In addition to typical bash commands, you can also use the following commands to help you navigate and edit files.
|
||||
|
||||
COMMANDS:
|
||||
{command_prompt}
|
||||
|
||||
Please note that THE WRITE COMMAND REQUIRES PROPER INDENTATION.
|
||||
If you'd like to add the line ' print(x)' you must fully write that out, with all those spaces before the code!
|
||||
Indentation is important and code that is not indented correctly will fail and require fixing before it can be run.
|
||||
|
||||
If you'd like to issue two commands at once, PLEASE DO NOT DO THAT! Please instead first submit just the first command, and then after receiving a response you'll be able to issue the second command.
|
||||
You're free to use any other bash commands you want (e.g. find, grep, cat, ls) in addition to the special commands listed above.
|
||||
|
||||
However, the environment does NOT support interactive session commands (e.g. vim, python), so please do not invoke them.
|
||||
|
||||
{RESPONSE_FORMAT_PROMPT}
|
||||
|
||||
""" # noqa
|
||||
|
||||
|
||||
RESPONSE_FORMAT_PROMPT = """
|
||||
## Response Format:
|
||||
You should respond with a JSON object in the following format.
|
||||
```json
|
||||
{
|
||||
"thought": "what you thought",
|
||||
"action": {"name": "{command name}", "arguments": {"{argument1 name}": xxx, "{argument2 name}": xxx}}
|
||||
}
|
||||
```
|
||||
|
||||
For Example:
|
||||
```json
|
||||
{
|
||||
"thought": "First I'll start by using ls to see what files are in the current directory. Then maybe we can look at some relevant files to see what they look like.",
|
||||
"action": {"name": "execute_shell_command", "arguments": {"command": "ls -a"}}
|
||||
}
|
||||
```
|
||||
OUTPUT the JSON format and ONLY OUTPUT the JSON format.
|
||||
Your Response should always be a valid JSON string that can be parsed.
|
||||
""" # noqa
|
||||
|
||||
|
||||
def get_step_prompt(
|
||||
task: str,
|
||||
file: str,
|
||||
line: int,
|
||||
current_file_content: str,
|
||||
) -> str:
|
||||
"""
|
||||
Get the step prompt for SWE-agent.
|
||||
"""
|
||||
return f"""
|
||||
We're currently perform the following coding task. Here's the original task description from the user.
|
||||
{task}
|
||||
|
||||
CURRENT
|
||||
Open File: {file} on line {line}
|
||||
|
||||
Current File Content:
|
||||
{current_file_content}
|
||||
|
||||
You can use these commands with the current file:
|
||||
Navigation: `scroll_up`, `scroll_down`, and `goto <line>`
|
||||
|
||||
|
||||
INSTRUCTIONS:
|
||||
|
||||
1. If you run a command and it doesn't work, try running a different command. A command that did not work once will not work the second time unless you modify it!
|
||||
|
||||
2. If you open a file and need to get to an area around a specific line that is not in the first 100 lines, say line 583, don't just use the scroll_down command multiple times. Instead, use the goto 583 command. It's much quicker.
|
||||
|
||||
3. Always make sure to look at the currently open file and the current working directory (which appears right after the currently open file). The currently open file might be in a different directory! Note that some commands, such as 'write_file' and 'read_file', open files, so they might change the current open file.
|
||||
|
||||
4. When editing files, it is easy to accidentally specify a wrong line number or to write code with incorrect indentation. Always check the code after you issue an edit to make sure that it reflects what you wanted to accomplish. If it didn't, issue another command to fix it.
|
||||
|
||||
5. After modifying python files, you can run `exec_py_linting` to check for errors. If there are errors, fix them and repeat the previous step.
|
||||
|
||||
NOTE THAT THIS ENVIRONMENT DOES NOT SUPPORT INTERACTIVE SESSION COMMANDS, such as "vim" or "python", or "python3". So DONOT execute them by running `execute_shell_command` with `python` command or `python3` command if the code need additional inputs.
|
||||
If you want to check whether a python file is valid, you can use `exec_py_linting` to check for errors.
|
||||
|
||||
You should always notice your response format and respond with a JSON object in the following format.
|
||||
{RESPONSE_FORMAT_PROMPT}
|
||||
""" # noqa
|
||||
|
||||
|
||||
def get_context_prompt(memory: list, window: int) -> str:
|
||||
"""
|
||||
Get the context prompt for the given memory and window.
|
||||
"""
|
||||
res = f"These are your past {window} actions:\n"
|
||||
window_size = window if len(memory) > window else len(memory)
|
||||
cur_mems = memory[-window_size:]
|
||||
res += "===== Previous Actions =====\n"
|
||||
for idx, mem in enumerate(cur_mems):
|
||||
res += f"\nMemory {idx}:\n{mem}\n"
|
||||
res += "======= End Actions =======\n"
|
||||
res += "Use these memories to provide additional context to \
|
||||
the problem you are solving.\nRemember that you have already \
|
||||
completed these steps so you do not need to perform them again."
|
||||
return res
|
||||
@@ -0,0 +1,147 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=C0301
|
||||
"""
|
||||
Tools for swe-agent, such as checking files with linting and formatting,
|
||||
writing and reading files by lines, etc.
|
||||
"""
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
from agentscope.service.service_response import ServiceResponse
|
||||
from agentscope.service.service_status import ServiceExecStatus
|
||||
|
||||
|
||||
def exec_py_linting(file_path: str) -> ServiceResponse:
|
||||
"""
|
||||
Executes flake8 linting on the given .py file with specified checks and
|
||||
returns the linting result.
|
||||
|
||||
Args:
|
||||
file_path (`str`): The path to the Python file to lint.
|
||||
|
||||
Returns:
|
||||
ServiceResponse: Contains either the output from the flake8 command as
|
||||
a string if successful, or an error message including the error type.
|
||||
"""
|
||||
command = f"flake8 --isolated --select=F821,F822,F831,\
|
||||
E111,E112,E113,E999,E902 {file_path}"
|
||||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
command,
|
||||
shell=True,
|
||||
check=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
)
|
||||
return ServiceResponse(
|
||||
status=ServiceExecStatus.SUCCESS,
|
||||
content=result.stdout.strip()
|
||||
if result.stdout
|
||||
else "No lint errors found.",
|
||||
)
|
||||
except subprocess.CalledProcessError as e:
|
||||
error_message = (
|
||||
e.stderr.strip()
|
||||
if e.stderr
|
||||
else "An error occurred while linting the file."
|
||||
)
|
||||
return ServiceResponse(
|
||||
status=ServiceExecStatus.ERROR,
|
||||
content=error_message,
|
||||
)
|
||||
except Exception as e:
|
||||
return ServiceResponse(
|
||||
status=ServiceExecStatus.ERROR,
|
||||
content=str(e),
|
||||
)
|
||||
|
||||
|
||||
def write_file(
|
||||
file_path: str,
|
||||
content: str,
|
||||
start_line: int = 0,
|
||||
end_line: int = -1,
|
||||
) -> ServiceResponse:
|
||||
"""
|
||||
Write content to a file by replacing the current lines between <start_line> and <end_line> with <content>. Default start_line = 0 and end_line = -1. Calling this with no <start_line> <end_line> args will replace the whole file, so besure to use this with caution when writing to a file that already exists.
|
||||
|
||||
Args:
|
||||
file_path (`str`): The path to the file to write to.
|
||||
content (`str`): The content to write to the file.
|
||||
start_line (`Optional[int]`, defaults to `0`): The start line of the file to be replace with <content>.
|
||||
end_line (`Optional[int]`, defaults to `-1`): The end line of the file to be replace with <content>. end_line = -1 means the end of the file, otherwise it should be a positive integer indicating the line number.
|
||||
""" # noqa
|
||||
try:
|
||||
mode = "w" if not os.path.exists(file_path) else "r+"
|
||||
insert = content.split("\n")
|
||||
with open(file_path, mode, encoding="utf-8") as file:
|
||||
if mode != "w":
|
||||
all_lines = file.readlines()
|
||||
new_file = [""] if start_line == 0 else all_lines[:start_line]
|
||||
new_file += [i + "\n" for i in insert]
|
||||
last_line = end_line + 1
|
||||
new_file += [""] if end_line == -1 else all_lines[last_line:]
|
||||
else:
|
||||
new_file = insert
|
||||
|
||||
file.seek(0)
|
||||
file.writelines(new_file)
|
||||
file.truncate()
|
||||
obs = f'WRITE OPERATION:\nYou have written to "{file_path}" \
|
||||
on these lines: {start_line}:{end_line}.'
|
||||
return ServiceResponse(
|
||||
status=ServiceExecStatus.SUCCESS,
|
||||
content=obs + "".join(new_file),
|
||||
)
|
||||
except Exception as e:
|
||||
error_message = f"{e.__class__.__name__}: {e}"
|
||||
return ServiceResponse(
|
||||
status=ServiceExecStatus.ERROR,
|
||||
content=error_message,
|
||||
)
|
||||
|
||||
|
||||
def read_file(
|
||||
file_path: str,
|
||||
start_line: int = 0,
|
||||
end_line: int = -1,
|
||||
) -> ServiceResponse:
|
||||
"""
|
||||
Shows a given file's contents starting from <start_line> up to <end_line>. Default: start_line = 0, end_line = -1. By default the whole file will be read.
|
||||
|
||||
Args:
|
||||
file_path (`str`): The path to the file to read.
|
||||
start_line (`Optional[int]`, defaults to `0`): The start line of the file to be read.
|
||||
end_line (`Optional[int]`, defaults to `-1`): The end line of the file to be read.
|
||||
""" # noqa
|
||||
start_line = max(start_line, 0)
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as file:
|
||||
if end_line == -1:
|
||||
if start_line == 0:
|
||||
code_view = file.read()
|
||||
else:
|
||||
all_lines = file.readlines()
|
||||
code_slice = all_lines[start_line:]
|
||||
code_view = "".join(code_slice)
|
||||
else:
|
||||
all_lines = file.readlines()
|
||||
num_lines = len(all_lines)
|
||||
begin = max(0, min(start_line, num_lines - 2))
|
||||
end_line = (
|
||||
-1 if end_line > num_lines else max(begin + 1, end_line)
|
||||
)
|
||||
code_slice = all_lines[begin:end_line]
|
||||
code_view = "".join(code_slice)
|
||||
return ServiceResponse(
|
||||
status=ServiceExecStatus.SUCCESS,
|
||||
content=f"{code_view}",
|
||||
)
|
||||
except Exception as e:
|
||||
error_message = f"{e.__class__.__name__}: {e}"
|
||||
return ServiceResponse(
|
||||
status=ServiceExecStatus.ERROR,
|
||||
content=error_message,
|
||||
)
|
||||
41
AlgoriAgent/examples/distributed_conversation/README.md
Normal file
41
AlgoriAgent/examples/distributed_conversation/README.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Distributed Conversation
|
||||
|
||||
This example will show
|
||||
- How to set up and run a distributed conversation.
|
||||
- How to configure and use different language models in the system.
|
||||
|
||||
## Background
|
||||
|
||||
This example demonstrates a distributed dialog system leveraging various language models. The system is designed to handle conversational AI tasks in a distributed manner, allowing for scalable and efficient dialog management.
|
||||
|
||||
## Tested Models
|
||||
|
||||
These models are tested in this example. For other models, some modifications may be needed.
|
||||
- Ollama Chat (llama3_8b)
|
||||
- Dashscope Chat (qwen-Max)
|
||||
- Gemini Chat (gemini-pro)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before running the example, please install the distributed version of Agentscope, fill in your model configuration correctly in `configs/model_configs.json`, and modify the `model_config_name` field in `distributed_dialog.py` accordingly.
|
||||
|
||||
## Running the Example
|
||||
Use the following command to start the assistant agent:
|
||||
|
||||
```
|
||||
cd examples/distributed_basic
|
||||
python distributed_dialog.py --role assistant --assistant-host localhost --assistant-port 12010
|
||||
# Please make sure the port is available.
|
||||
# If the assistant agent and the user agent are started on different machines,
|
||||
# please fill in the ip address of the assistant agent in the host field
|
||||
```
|
||||
|
||||
Then, run the user agent:
|
||||
|
||||
```
|
||||
python distributed_dialog.py --role user --assistant-host localhost --assistant-port 12010
|
||||
# If the assistant agent is started on another machine,
|
||||
# please fill in the ip address of the assistant agent in the host field
|
||||
```
|
||||
|
||||
Now, you can chat with the assistant agent using the command line.
|
||||
@@ -0,0 +1,21 @@
|
||||
[
|
||||
{
|
||||
"config_name": "gpt-4",
|
||||
"model_type": "openai_chat",
|
||||
"model_name": "gpt-4",
|
||||
"api_key": "xxx",
|
||||
"organization": "xxx",
|
||||
"generate_args": {
|
||||
"temperature": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "qwen",
|
||||
"model_type": "dashscope_chat",
|
||||
"model_name": "qwen-max",
|
||||
"api_key": "xxx",
|
||||
"generate_args": {
|
||||
"temperature": 0.5
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,83 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" An example of distributed dialog """
|
||||
|
||||
import argparse
|
||||
from loguru import logger
|
||||
|
||||
import agentscope
|
||||
from agentscope.agents.user_agent import UserAgent
|
||||
from agentscope.agents.dialog_agent import DialogAgent
|
||||
from agentscope.server import RpcAgentServerLauncher
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
"""Parse arguments"""
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--role",
|
||||
choices=["assistant", "user"],
|
||||
default="user",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--assistant-port",
|
||||
type=int,
|
||||
default=12010,
|
||||
)
|
||||
parser.add_argument(
|
||||
"--assistant-host",
|
||||
type=str,
|
||||
default="localhost",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def setup_assistant_server(assistant_host: str, assistant_port: int) -> None:
|
||||
"""Set up assistant rpc server"""
|
||||
agentscope.init(
|
||||
model_configs="configs/model_configs.json",
|
||||
project="Distributed Conversation",
|
||||
)
|
||||
assistant_server_launcher = RpcAgentServerLauncher(
|
||||
host=assistant_host,
|
||||
port=assistant_port,
|
||||
)
|
||||
assistant_server_launcher.launch()
|
||||
assistant_server_launcher.wait_until_terminate()
|
||||
|
||||
|
||||
def run_main_process(assistant_host: str, assistant_port: int) -> None:
|
||||
"""Run dialog main process"""
|
||||
agentscope.init(
|
||||
model_configs="configs/model_configs.json",
|
||||
project="Distributed Conversation",
|
||||
)
|
||||
assistant_agent = DialogAgent(
|
||||
name="Assistant",
|
||||
sys_prompt="You are a helpful assistant.",
|
||||
model_config_name="qwen",
|
||||
use_memory=True,
|
||||
).to_dist(
|
||||
host=assistant_host,
|
||||
port=assistant_port,
|
||||
)
|
||||
user_agent = UserAgent(
|
||||
name="User",
|
||||
require_url=False,
|
||||
)
|
||||
logger.info(
|
||||
"Setup successfully, have fun chatting! (enter 'exit' to close the "
|
||||
"agent)",
|
||||
)
|
||||
msg = user_agent()
|
||||
while not msg.content.endswith("exit"):
|
||||
msg = assistant_agent(msg)
|
||||
logger.chat(msg)
|
||||
msg = user_agent(msg)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_args()
|
||||
if args.role == "assistant":
|
||||
setup_assistant_server(args.assistant_host, args.assistant_port)
|
||||
elif args.role == "user":
|
||||
run_main_process(args.assistant_host, args.assistant_port)
|
||||
80
AlgoriAgent/examples/distributed_debate/README.md
Normal file
80
AlgoriAgent/examples/distributed_debate/README.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Distributed Debate Competition
|
||||
|
||||
This example demonstrates:
|
||||
- How to simulate a debate competition with three participant agents
|
||||
- How to allow human participation in the debate
|
||||
|
||||
## Background
|
||||
|
||||
This example simulates a debate competition with three participant agents:
|
||||
1. The affirmative side (**Pro**)
|
||||
2. The negative side (**Con**)
|
||||
3. The adjudicator (**Judge**)
|
||||
|
||||
The debate topic is whether AGI can be achieved using the GPT model framework. Pro argues in favor, while Con contests it. Judge listens to both sides' arguments and provides an analytical judgment on which side presented a more compelling case.
|
||||
|
||||
Each agent is an independent process and can run on different machines. Human participants can join as Pro or Con.
|
||||
|
||||
## Tested Models
|
||||
|
||||
These models are tested in this example. For other models, some modifications may be needed.
|
||||
- Ollama Chat (qwen2:1.5b)
|
||||
- Dashscope Chat (qwen-Max)
|
||||
- Gemini Chat (gemini-pro)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before running the example:
|
||||
- Install the distributed version of AgentScope by running
|
||||
```bash
|
||||
# On windows
|
||||
pip install -e .[distribute]
|
||||
# On mac / linux
|
||||
pip install -e .\[distribute\]
|
||||
```
|
||||
- Fill in your model configuration correctly in `configs/model_configs.json`
|
||||
- Modify the `model_config_name` field in `configs/debate_agent_configs.json` accordingly
|
||||
- Ensure the specified ports are available and IP addresses are accessible
|
||||
|
||||
## Setup and Execution
|
||||
|
||||
### Step 1: Setup Pro and Con agent servers
|
||||
|
||||
For an LLM-based Pro:
|
||||
```shell
|
||||
cd examples/distributed_debate
|
||||
python distributed_debate.py --role pro --pro-host localhost --pro-port 12011
|
||||
```
|
||||
|
||||
(Alternatively) for human participation as Pro:
|
||||
```shell
|
||||
python distributed_debate.py --role pro --pro-host localhost --pro-port 12011 --is-human
|
||||
```
|
||||
|
||||
For an LLM-based Con:
|
||||
```shell
|
||||
python distributed_debate.py --role con --con-host localhost --con-port 12012
|
||||
```
|
||||
|
||||
(Alternatively) for human participation as Con:
|
||||
```shell
|
||||
python distributed_debate.py --role con --con-host localhost --con-port 12012 --is-human
|
||||
```
|
||||
|
||||
### Step 2: Run the main process
|
||||
|
||||
```shell
|
||||
python distributed_debate.py --role main --pro-host localhost --pro-port 12011 --con-host localhost --con-port 12012
|
||||
```
|
||||
|
||||
### Step 3: Watch or join the debate in your terminal
|
||||
|
||||
If you join as Con, you'll see something like:
|
||||
|
||||
```text
|
||||
System: Welcome to the debate on whether Artificial General Intelligence (AGI) can be achieved
|
||||
...
|
||||
Pro: Thank you. I argue that AGI can be achieved using the GPT model framework.
|
||||
...
|
||||
User Input:
|
||||
```
|
||||
@@ -0,0 +1,29 @@
|
||||
[
|
||||
{
|
||||
"class": "DialogAgent",
|
||||
"args": {
|
||||
"name": "Pro",
|
||||
"sys_prompt": "Assume the role of a debater who is arguing in favor of the proposition that AGI (Artificial General Intelligence) can be achieved using the GPT model framework. Construct a coherent and persuasive argument, including scientific, technological, and theoretical evidence, to support the statement that GPT models are a viable path to AGI. Highlight the advancements in language understanding, adaptability, and scalability of GPT models as key factors in progressing towards AGI.",
|
||||
"model_config_name": "gpt-3.5-turbo",
|
||||
"use_memory": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "DialogAgent",
|
||||
"args": {
|
||||
"name": "Con",
|
||||
"sys_prompt": "Assume the role of a debater who is arguing against the proposition that AGI can be achieved using the GPT model framework. Construct a coherent and persuasive argument, including scientific, technological, and theoretical evidence, to support the statement that GPT models, while impressive, are insufficient for reaching AGI. Discuss the limitations of GPT models such as lack of understanding, consciousness, ethical reasoning, and general problem-solving abilities that are essential for true AGI.",
|
||||
"model_config_name": "gpt-3.5-turbo",
|
||||
"use_memory": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "DialogAgent",
|
||||
"args": {
|
||||
"name": "Judge",
|
||||
"sys_prompt": "Assume the role of an impartial judge in a debate where the affirmative side argues that AGI can be achieved using the GPT model framework, and the negative side contests this. Listen to both sides' arguments and provide an analytical judgment on which side presented a more compelling and reasonable case. Consider the strength of the evidence, the persuasiveness of the reasoning, and the overall coherence of the arguments presented by each side.",
|
||||
"model_config_name": "gpt-3.5-turbo",
|
||||
"use_memory": true
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
[
|
||||
{
|
||||
"config_name": "gpt-4",
|
||||
"model_type": "openai_chat",
|
||||
"model_name": "gpt-4",
|
||||
"api_key": "xxx",
|
||||
"organization": "xxx",
|
||||
"generate_args": {
|
||||
"temperature": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "qwen",
|
||||
"model_type": "dashscope_chat",
|
||||
"model_name": "qwen-max",
|
||||
"api_key": "xxx",
|
||||
"generate_args": {
|
||||
"temperature": 0.5
|
||||
}
|
||||
}
|
||||
]
|
||||
129
AlgoriAgent/examples/distributed_debate/distributed_debate.py
Normal file
129
AlgoriAgent/examples/distributed_debate/distributed_debate.py
Normal file
@@ -0,0 +1,129 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" An example of distributed debate """
|
||||
|
||||
import argparse
|
||||
|
||||
from user_proxy_agent import UserProxyAgent
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import agentscope
|
||||
from agentscope.agents import DialogAgent
|
||||
from agentscope.msghub import msghub
|
||||
from agentscope.server import RpcAgentServerLauncher
|
||||
from agentscope.message import Msg
|
||||
|
||||
|
||||
FIRST_ROUND = """
|
||||
Welcome to the debate on whether Artificial General Intelligence (AGI) can be achieved using the GPT model framework. This debate will consist of three rounds. In each round, the affirmative side will present their argument first, followed by the negative side. After both sides have presented, the adjudicator will summarize the key points and analyze the strengths of the arguments.
|
||||
|
||||
The rules are as follows:
|
||||
|
||||
Each side must present clear, concise arguments backed by evidence and logical reasoning.
|
||||
No side may interrupt the other while they are presenting their case.
|
||||
After both sides have presented, the adjudicator will have time to deliberate and will then provide a summary, highlighting the most persuasive points from both sides.
|
||||
The adjudicator's summary will not declare a winner for the individual rounds but will focus on the quality and persuasiveness of the arguments.
|
||||
At the conclusion of the three rounds, the adjudicator will declare the overall winner based on which side won two out of the three rounds, considering the consistency and strength of the arguments throughout the debate.
|
||||
Let us begin the first round. The affirmative side: please present your argument for why AGI can be achieved using the GPT model framework.
|
||||
""" # noqa
|
||||
|
||||
SECOND_ROUND = """
|
||||
Let us begin the second round. It's your turn, the affirmative side.
|
||||
"""
|
||||
|
||||
THIRD_ROUND = """
|
||||
Next is the final round.
|
||||
"""
|
||||
|
||||
END = """
|
||||
Judge, please declare the overall winner now.
|
||||
"""
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
"""Parse arguments"""
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--role",
|
||||
choices=["pro", "con", "main"],
|
||||
default="main",
|
||||
)
|
||||
parser.add_argument("--is-human", action="store_true")
|
||||
parser.add_argument("--pro-host", type=str, default="localhost")
|
||||
parser.add_argument(
|
||||
"--pro-port",
|
||||
type=int,
|
||||
default=12011,
|
||||
)
|
||||
parser.add_argument("--con-host", type=str, default="localhost")
|
||||
parser.add_argument(
|
||||
"--con-port",
|
||||
type=int,
|
||||
default=12012,
|
||||
)
|
||||
parser.add_argument("--judge-host", type=str, default="localhost")
|
||||
parser.add_argument(
|
||||
"--judge-port",
|
||||
type=int,
|
||||
default=12013,
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def setup_server(parsed_args: argparse.Namespace) -> None:
|
||||
"""Setup rpc server for participant agent"""
|
||||
agentscope.init(
|
||||
model_configs="configs/model_configs.json",
|
||||
project="Distributed Conversation",
|
||||
)
|
||||
host = getattr(parsed_args, f"{parsed_args.role}_host")
|
||||
port = getattr(parsed_args, f"{parsed_args.role}_port")
|
||||
server_launcher = RpcAgentServerLauncher(
|
||||
host=host,
|
||||
port=port,
|
||||
custom_agents=[UserProxyAgent, DialogAgent],
|
||||
)
|
||||
server_launcher.launch(in_subprocess=False)
|
||||
server_launcher.wait_until_terminate()
|
||||
|
||||
|
||||
def run_main_process(parsed_args: argparse.Namespace) -> None:
|
||||
"""Setup the main debate competition process"""
|
||||
pro_agent, con_agent, judge_agent = agentscope.init(
|
||||
model_configs="configs/model_configs.json",
|
||||
agent_configs="configs/debate_agent_configs.json",
|
||||
project="Distributed Conversation",
|
||||
)
|
||||
pro_agent = pro_agent.to_dist(
|
||||
host=parsed_args.pro_host,
|
||||
port=parsed_args.pro_port,
|
||||
)
|
||||
con_agent = con_agent.to_dist(
|
||||
host=parsed_args.con_host,
|
||||
port=parsed_args.con_port,
|
||||
)
|
||||
participants = [pro_agent, con_agent, judge_agent]
|
||||
announcements = [
|
||||
Msg(name="system", content=FIRST_ROUND, role="system"),
|
||||
Msg(name="system", content=SECOND_ROUND, role="system"),
|
||||
Msg(name="system", content=THIRD_ROUND, role="system"),
|
||||
]
|
||||
end = Msg(name="system", content=END, role="system")
|
||||
with msghub(participants=participants) as hub:
|
||||
for i in range(3):
|
||||
hub.broadcast(announcements[i])
|
||||
pro_resp = pro_agent()
|
||||
logger.chat(pro_resp)
|
||||
con_resp = con_agent()
|
||||
logger.chat(con_resp)
|
||||
judge_agent()
|
||||
hub.broadcast(end)
|
||||
judge_agent()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_args()
|
||||
if args.role == "main":
|
||||
run_main_process(args)
|
||||
else:
|
||||
setup_server(args)
|
||||
31
AlgoriAgent/examples/distributed_debate/user_proxy_agent.py
Normal file
31
AlgoriAgent/examples/distributed_debate/user_proxy_agent.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""User Proxy Agent class for distributed usage"""
|
||||
from typing import Sequence, Union
|
||||
from typing import Optional
|
||||
|
||||
from agentscope.agents import UserAgent
|
||||
from agentscope.message import Msg
|
||||
|
||||
|
||||
class UserProxyAgent(UserAgent):
|
||||
"""User proxy agent class"""
|
||||
|
||||
def reply( # type: ignore[override]
|
||||
self,
|
||||
x: Optional[Union[Msg, Sequence[Msg]]] = None,
|
||||
required_keys: Optional[Union[list[str], str]] = None,
|
||||
) -> Msg:
|
||||
"""
|
||||
Reply with `self.speak(x)`
|
||||
"""
|
||||
if x is not None:
|
||||
self.speak(x)
|
||||
return super().reply(x, required_keys)
|
||||
|
||||
def observe(self, x: Union[dict, Sequence[dict]]) -> None:
|
||||
"""
|
||||
Observe with `self.speak(x)`
|
||||
"""
|
||||
if x is not None:
|
||||
self.speak(x) # type: ignore[arg-type]
|
||||
self.memory.add(x)
|
||||
@@ -0,0 +1,83 @@
|
||||
# Multi-Agent Copilot Search
|
||||
|
||||
## Introduction
|
||||
|
||||
This example application converts the user's questions into keywords to call the search engine, and then retrieves a series of web pages to find answers. It involves three types of Agents, namely the UserAgent for the user, the SearcherAgent responsible for searching, and the AnswererAgent responsible for retrieves web pages.
|
||||
|
||||
There are many web page links returned by the search engine. To improve performance, multiple instances of AnswererAgent need to run together. However, with the traditional single-process mode, even if there are multiple AnswererAgent instances, they can only obtain web page and answer questions one by one on a single CPU.
|
||||
|
||||
But, with AgentScope's distributed mode, you can automatically make these AnswererAgent instances run at the same time to improve performance.
|
||||
|
||||
From this example, you can learn:
|
||||
|
||||
- how to run multiple agents in different processes,
|
||||
- how to make multiple agents run in parallel automatically,
|
||||
- how to convert a single-process version AgentScope application into a multi-processes version.
|
||||
|
||||
## How to Run
|
||||
|
||||
### Step 0: Install AgentScope distributed version
|
||||
|
||||
This example requires the distributed version of AgentScope.
|
||||
|
||||
```bash
|
||||
# On windows
|
||||
pip install -e .[distribute]
|
||||
# On mac / linux
|
||||
pip install -e .\[distribute\]
|
||||
```
|
||||
|
||||
### Step 1: Prepare your model and search engine API configuration
|
||||
|
||||
For the model configuration, please fill your model configurations in `configs/model_configs.json`.
|
||||
Here we give an example.
|
||||
|
||||
> Dashscope models, e.g. qwen-max, and openai models, e.g. gpt-3.5-turbo and gpt-4 are tested for this example.
|
||||
> Other models may require certain modification to the code.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"config_name": "my_model",
|
||||
"model_type": "dashscope_chat",
|
||||
"model_name": "qwen-max",
|
||||
"api_key": "your_api_key",
|
||||
"generate_args": {
|
||||
"temperature": 0.5
|
||||
},
|
||||
"messages_key": "input"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
For search engines, this example now supports two types of search engines, google and bing. The configuration items for each of them are as follows:
|
||||
|
||||
- google
|
||||
- `api-key`
|
||||
- `cse-id`
|
||||
- bing
|
||||
- `api-key`
|
||||
|
||||
### Step 2: Run the example
|
||||
|
||||
Use the `main.py` script to run the example. The following are the parameters required to run the script:
|
||||
|
||||
- `--num-workers`: The number of AnswererAgent instances.
|
||||
- `--use-dist`: Enable distributed mode.
|
||||
- `--search-engine`: The search engine used, currently supports `google` or `bing`.
|
||||
- `--api-key`: API key for google or bing.
|
||||
- `--cse-id`: CSE id for google (If you use bing, ignore this parameter).
|
||||
|
||||
For example, if you want to start the example application in distributed mode with 10 AnswererAgents and use the bing search engine, you can use the following command
|
||||
|
||||
```shell
|
||||
python main.py --num-workers 10 --search-engine bing --api-key xxxxx --use-dist
|
||||
```
|
||||
|
||||
And if you want to run the above case in a traditional single-process mode, you can use the following command.
|
||||
|
||||
```shell
|
||||
python main.py --num-workers 10 --search-engine bing --api-key xxxxx
|
||||
```
|
||||
|
||||
You can ask the same question in both modes to compare the difference in runtime. For examples, answer a question with 10 workers only takes 13.2s in distributed mode, while it takes 51.3s in single-process mode.
|
||||
@@ -0,0 +1,61 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Answerer Agent."""
|
||||
from typing import Optional, Union, Sequence
|
||||
|
||||
from agentscope.message import Msg
|
||||
from agentscope.agents import AgentBase
|
||||
from agentscope.service import load_web
|
||||
|
||||
|
||||
class AnswererAgent(AgentBase):
|
||||
"""An agent with web digest tool."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
model_config_name: str = None,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
name=name,
|
||||
sys_prompt="You are an AI assistant. You need to find answers to "
|
||||
"user questions based on specified web content.",
|
||||
model_config_name=model_config_name,
|
||||
use_memory=False,
|
||||
)
|
||||
|
||||
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
|
||||
response = load_web(
|
||||
url=x.url,
|
||||
keep_raw=False,
|
||||
html_selected_tags=["p", "div", "h1", "li"],
|
||||
timeout=5,
|
||||
).content
|
||||
if (
|
||||
"html_to_text" not in response
|
||||
or len(response["html_to_text"]) == 0
|
||||
):
|
||||
return Msg(
|
||||
self.name,
|
||||
content=f"Unable to load web page [{x.url}].",
|
||||
url=x.url,
|
||||
)
|
||||
# prepare prompt
|
||||
prompt = self.model.format(
|
||||
Msg(name="system", role="system", content=self.sys_prompt),
|
||||
Msg(
|
||||
name="user",
|
||||
role="user",
|
||||
content=f"Please answer my question based on the content of"
|
||||
" the following web page:\n\n"
|
||||
f"{response['html_to_text']}"
|
||||
f"\n\nBased on the above web page,"
|
||||
f" please answer my question\n{x.query}",
|
||||
),
|
||||
)
|
||||
# call llm and generate response
|
||||
response = self.model(prompt).text
|
||||
msg = Msg(self.name, content=response, url=x.url)
|
||||
|
||||
self.speak(msg)
|
||||
|
||||
return msg
|
||||
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"model_type": "tongyi_chat",
|
||||
"config_name": "my_model",
|
||||
"model_name": "qwen-max",
|
||||
"api_key": "your_api_key",
|
||||
"generate_args": {
|
||||
"temperature": 0.5
|
||||
},
|
||||
"messages_key": "input"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,78 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""An example use multiple agents to search the Internet for answers"""
|
||||
import time
|
||||
import argparse
|
||||
from loguru import logger
|
||||
from searcher_agent import SearcherAgent
|
||||
from answerer_agent import AnswererAgent
|
||||
|
||||
import agentscope
|
||||
from agentscope.agents.user_agent import UserAgent
|
||||
from agentscope.message import Msg
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
"""Parse arguments"""
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--num-workers", type=int, default=5)
|
||||
parser.add_argument("--use-dist", action="store_true")
|
||||
parser.add_argument(
|
||||
"--search-engine",
|
||||
type=str,
|
||||
choices=["google", "bing"],
|
||||
default="google",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--api-key",
|
||||
type=str,
|
||||
)
|
||||
parser.add_argument("--cse-id", type=str, default=None)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_args()
|
||||
agentscope.init(
|
||||
model_configs="configs/model_configs.json",
|
||||
project="Parallel Optimization",
|
||||
)
|
||||
|
||||
WORKER_NUM = 3
|
||||
searcher = SearcherAgent(
|
||||
name="Searcher",
|
||||
model_config_name="my_model",
|
||||
result_num=args.num_workers,
|
||||
search_engine_type=args.search_engine,
|
||||
api_key=args.api_key,
|
||||
cse_id=args.cse_id,
|
||||
)
|
||||
answerers = []
|
||||
for i in range(args.num_workers):
|
||||
answerer = AnswererAgent(
|
||||
name=f"Answerer-{i}",
|
||||
model_config_name="my_model",
|
||||
)
|
||||
if args.use_dist:
|
||||
answerer = answerer.to_dist(lazy_launch=False)
|
||||
answerers.append(answerer)
|
||||
|
||||
user_agent = UserAgent()
|
||||
|
||||
msg = user_agent()
|
||||
while not msg.content == "exit":
|
||||
start_time = time.time()
|
||||
msg = searcher(msg)
|
||||
results = []
|
||||
for page, worker in zip(msg.content, answerers):
|
||||
results.append(worker(Msg(**page)))
|
||||
for result in results:
|
||||
logger.chat(result)
|
||||
end_time = time.time()
|
||||
logger.chat(
|
||||
Msg(
|
||||
name="system",
|
||||
role="system",
|
||||
content=f"Completed in [{end_time - start_time:.2f}]s",
|
||||
),
|
||||
)
|
||||
msg = user_agent()
|
||||
@@ -0,0 +1,97 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Searcher agent."""
|
||||
|
||||
from functools import partial
|
||||
from typing import Optional, Union, Sequence
|
||||
|
||||
from agentscope.message import Msg
|
||||
from agentscope.agents import AgentBase
|
||||
from agentscope.service import google_search, bing_search
|
||||
|
||||
|
||||
class SearcherAgent(AgentBase):
|
||||
"""An agent with search tool."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
model_config_name: str = None,
|
||||
result_num: int = 10,
|
||||
search_engine_type: str = "google",
|
||||
api_key: str = None,
|
||||
cse_id: str = None,
|
||||
) -> None:
|
||||
"""Init a SearcherAgent.
|
||||
|
||||
Args:
|
||||
name (`str`): the name of this agent.
|
||||
model_config_name (`str`, optional): The name of model
|
||||
configuration for this agent. Defaults to None.
|
||||
result_num (`int`, optional): The number of return results.
|
||||
Defaults to 10.
|
||||
search_engine_type (`str`, optional): the search engine to use.
|
||||
Defaults to "google".
|
||||
api_key (`str`, optional): api key for the search engine. Defaults
|
||||
to None.
|
||||
cse_id (`str`, optional): cse_id for the search engine. Defaults to
|
||||
None.
|
||||
"""
|
||||
super().__init__(
|
||||
name=name,
|
||||
sys_prompt="You are an AI assistant who optimizes search"
|
||||
" keywords. You need to transform users' questions into a series "
|
||||
"of efficient search keywords.",
|
||||
model_config_name=model_config_name,
|
||||
use_memory=False,
|
||||
)
|
||||
self.result_num = result_num
|
||||
if search_engine_type == "google":
|
||||
assert (api_key is not None) and (
|
||||
cse_id is not None
|
||||
), "google search requires 'api_key' and 'cse_id'"
|
||||
self.search = partial(
|
||||
google_search,
|
||||
api_key=api_key,
|
||||
cse_id=cse_id,
|
||||
)
|
||||
elif search_engine_type == "bing":
|
||||
assert api_key is not None, "bing search requires 'api_key'"
|
||||
self.search = partial(bing_search, api_key=api_key)
|
||||
|
||||
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
|
||||
prompt = self.model.format(
|
||||
Msg(name="system", role="system", content=self.sys_prompt),
|
||||
x,
|
||||
Msg(
|
||||
name="user",
|
||||
role="user",
|
||||
content="Please convert the question into keywords. The return"
|
||||
" format is:\nKeyword1 Keyword2...",
|
||||
),
|
||||
)
|
||||
query = self.model(prompt).text
|
||||
results = self.search(
|
||||
question=query,
|
||||
num_results=self.result_num,
|
||||
).content
|
||||
msg = Msg(
|
||||
self.name,
|
||||
content=[
|
||||
Msg(
|
||||
name=self.name,
|
||||
content=result,
|
||||
url=result["link"],
|
||||
query=x.content,
|
||||
)
|
||||
for result in results
|
||||
],
|
||||
)
|
||||
self.speak(
|
||||
Msg(
|
||||
name=self.name,
|
||||
role="assistant",
|
||||
content="Search results:\n"
|
||||
f"{[result['link'] for result in results]}",
|
||||
),
|
||||
)
|
||||
return msg
|
||||
103
AlgoriAgent/examples/distributed_simulation/README.md
Normal file
103
AlgoriAgent/examples/distributed_simulation/README.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Distributed Large Scale Simulation
|
||||
|
||||
> **WARNING:**
|
||||
> **This example will consume a huge amount of tokens.**
|
||||
> **Using paid model API with this example can introduce a high cost.**
|
||||
> **Users with powerful GPUs (A800 or better) can use local inference services (such as vLLM) to run this example,**
|
||||
> **while CPU inference services such as ollama is not recommended.**
|
||||
|
||||
This example is a large scale simulation to demonstrate the scalability of AgentScope's distributed mode. From this example, you can learn:
|
||||
|
||||
- How to run a large number of agent servers in a GPU cluster.
|
||||
- How to connect to those agent servers and run a huge number of agents in them.
|
||||
|
||||
> Based on this example, we deploy 64,000 agents evenly on 4 machines, and each machine has 64 CPU cores and 8 A100 GPUs. The running time is about 30s (excluding initialization time).
|
||||
|
||||
## Background
|
||||
|
||||
This example simulates the following scenario:
|
||||
|
||||
A large number of people participate in a game in which the moderator asks each participant to provide a number between 0 and N. The moderator will calculate the average of all numbers and announce it. The person closest to the average will win.
|
||||
|
||||
## Tested Models
|
||||
|
||||
Only vLLM local inference service is tested for this example.
|
||||
|
||||
This example will consume a huge amount of tokens. Please do not use model API that requires payment.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- The distribute version of AgentScope is installed
|
||||
- Use MacOS or Linux (Windows requires some modifiations to the scripts)
|
||||
- [Optional] Have multiple machines with powerful GPUs (A800 or better) and install [vLLM](https://github.com/vllm-project/vllm)
|
||||
|
||||
## How to Run
|
||||
|
||||
### Step 1: start local inference service
|
||||
|
||||
> If you only have one machine and don't have a powerful GPU (A800 or better), you can ignore this step.
|
||||
|
||||
You can use `start_vllm.sh` to start vllm inference services on each of your machines.
|
||||
Before running the script, please set `gpu_num`, `model_path` and `base_port` properly.
|
||||
|
||||
- `gpu_num`: number of GPUs for this machine.
|
||||
- `model_path`: the model checkpoint path.
|
||||
- `base_port`: The starting point of the port number used by the local inference services.
|
||||
|
||||
For example, if `base_port` is `8010` and `gpu_num` is `4`, 4 inference services will be started, and the port numbers are `8010`, `8011`, `8012` and `8013` respectively.
|
||||
|
||||
vLLM inference services start slowly, so you need to wait for these servers to actually start before proceeding to the next step.
|
||||
|
||||
> The above configuration requires that the model checkpoint can be loaded by a single GPU.
|
||||
> If you need to use a model that must be loaded by multiple GPUs, you need to modify the script.
|
||||
|
||||
### Step 2: start agent server
|
||||
|
||||
> If you only have one machine and don't have a powerful GPU, you can just use the default setting of the scripts.
|
||||
|
||||
You can use `start_all_server.sh` to start multiple agent servers on each of your machine.
|
||||
Before running the script, please set `base_port`, `host_name` and `moderator_num` properly.
|
||||
|
||||
- `base_port`: The starting point of the port number used by the agent servers.
|
||||
- `host_name`: The hostname of this machine, and must be accessible to other machines in the cluster (The default value `localhost` is only used for single machine scenario).
|
||||
- `moderator_num`: Number of moderators. When the number of participants is large, this value needs to be expanded to avoid bottlenecks.
|
||||
|
||||
After setting the above values correctly, you can use the script to start multiple agent server on your machine. The following command will start 10 agent servers on your machine with port numbers starting from `base_port` to `base_port + 9`, and will also start `moderator_num` agent servers for moderators with port numbers starting from `base_port + 10` to `base_port + moderator_num + 9`.
|
||||
|
||||
```shell
|
||||
#./start_all_server.sh <number_of_server_per_host>
|
||||
./start_all_server.sh 10
|
||||
```
|
||||
|
||||
If you have multiple machines, please make sure the `base_port` and `moderator_num` parameters are exactly the same on all machines, and start the same number of agent servers.
|
||||
|
||||
### Step 3: run simulation
|
||||
|
||||
You can use `run_simulation.sh` to start the simulation.
|
||||
Before running the script, please set the following setting correctly:
|
||||
|
||||
- `base_port`: the base port for agent servers, must be the same as used in Step 2.
|
||||
- `hosts`: hostnames of all machines. If you only have one machine, use the default value `localhost`.
|
||||
- `moderator_per_host`: Consistent with `moderator_num` in Step 2.
|
||||
- `agent_type`: `random` or `llm`. Please use `random` if you don't have local inference service.
|
||||
- `max_value`: The upper bound of numbers generated in the game.
|
||||
|
||||
The command below will run a simulation with 1000 participant agents and evenly distributed those agents to the 10 agent servers started in Step 2.
|
||||
|
||||
```shell
|
||||
#./run_simulation.sh <number_of_server_per_host> <total_number_of_participant>
|
||||
./run_simulation.sh 10 1000
|
||||
```
|
||||
|
||||
The following is sample output from a single-machine (16 CPU cores) simulation scenario:
|
||||
|
||||
```log
|
||||
2024-04-16 10:31:53.786 | INFO | agentscope.models:read_model_configs:178 - Load configs for model wrapper: model_1, model_2, model_3, model_4, model_5, model_6, model_7, model_8
|
||||
2024-04-16 10:31:53.822 | INFO | agentscope.utils.monitor:_create_monitor_table:343 - Init [monitor_metrics] as the monitor table
|
||||
2024-04-16 10:31:53.822 | INFO | agentscope.utils.monitor:_create_monitor_table:344 - Init [monitor_metrics_quota_exceeded] as the monitor trigger
|
||||
2024-04-16 10:31:53.822 | INFO | agentscope.utils.monitor:__init__:313 - SqliteMonitor initialization completed at [./runs/run_20240416-103153_h0xuo5/agentscope.db]
|
||||
2024-04-16 10:31:53.829 | INFO | __main__:run_main_process_new:106 - init 1000 random participant agents...
|
||||
2024-04-16 10:31:53.829 | INFO | __main__:run_main_process_new:139 - init 4 moderator agents...
|
||||
2024-04-16 10:31:54.211 | INFO | __main__:run_main_process_new:163 - [init takes 0.38274645805358887 s]
|
||||
Moderator: The average value is 49.561 [takes 4.197571277618408 s]
|
||||
```
|
||||
@@ -0,0 +1,98 @@
|
||||
[
|
||||
{
|
||||
"model_type": "openai_chat",
|
||||
"config_name": "model_1",
|
||||
"model_name": "path-to-your-model-dir",
|
||||
"api_key": "EMPTY",
|
||||
"client_args": {
|
||||
"base_url": "http://127.0.0.1:8010/v1/"
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model_type": "openai_chat",
|
||||
"config_name": "model_2",
|
||||
"model_name": "path-to-your-model-dir",
|
||||
"api_key": "EMPTY",
|
||||
"client_args": {
|
||||
"base_url": "http://127.0.0.1:8011/v1/"
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model_type": "openai_chat",
|
||||
"config_name": "model_3",
|
||||
"model_name": "path-to-your-model-dir",
|
||||
"api_key": "EMPTY",
|
||||
"client_args": {
|
||||
"base_url": "http://127.0.0.1:8012/v1/"
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model_type": "openai_chat",
|
||||
"config_name": "model_4",
|
||||
"model_name": "path-to-your-model-dir",
|
||||
"api_key": "EMPTY",
|
||||
"client_args": {
|
||||
"base_url": "http://127.0.0.1:8013/v1/"
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model_type": "openai_chat",
|
||||
"config_name": "model_5",
|
||||
"model_name": "path-to-your-model-dir",
|
||||
"api_key": "EMPTY",
|
||||
"client_args": {
|
||||
"base_url": "http://127.0.0.1:8014/v1/"
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model_type": "openai_chat",
|
||||
"config_name": "model_6",
|
||||
"model_name": "path-to-your-model-dir",
|
||||
"api_key": "EMPTY",
|
||||
"client_args": {
|
||||
"base_url": "http://127.0.0.1:8015/v1/"
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model_type": "openai_chat",
|
||||
"config_name": "model_7",
|
||||
"model_name": "path-to-your-model-dir",
|
||||
"api_key": "EMPTY",
|
||||
"client_args": {
|
||||
"base_url": "http://127.0.0.1:8016/v1/"
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"model_type": "openai_chat",
|
||||
"config_name": "model_8",
|
||||
"model_name": "path-to-your-model-dir",
|
||||
"api_key": "EMPTY",
|
||||
"client_args": {
|
||||
"base_url": "http://127.0.0.1:8017/v1/"
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 1.0
|
||||
}
|
||||
}
|
||||
]
|
||||
216
AlgoriAgent/examples/distributed_simulation/main.py
Normal file
216
AlgoriAgent/examples/distributed_simulation/main.py
Normal file
@@ -0,0 +1,216 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" A large-scale social simulation experiment """
|
||||
|
||||
import argparse
|
||||
import time
|
||||
from concurrent import futures
|
||||
from concurrent.futures import as_completed
|
||||
from loguru import logger
|
||||
|
||||
from participant import Moderator, RandomParticipant, LLMParticipant
|
||||
|
||||
import agentscope
|
||||
from agentscope.agents import AgentBase
|
||||
from agentscope.server import RpcAgentServerLauncher
|
||||
from agentscope.message import Msg
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
"""Parse arguments"""
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--role",
|
||||
choices=["participant", "main"],
|
||||
default="main",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--agent-type",
|
||||
choices=["random", "llm"],
|
||||
default="random",
|
||||
)
|
||||
parser.add_argument("--max-value", type=int, default=100)
|
||||
parser.add_argument("--sleep-time", type=float, default=1.0)
|
||||
parser.add_argument(
|
||||
"--hosts",
|
||||
type=str,
|
||||
nargs="+",
|
||||
default=["localhost"],
|
||||
)
|
||||
parser.add_argument("--participant-num", type=int, default=100)
|
||||
parser.add_argument("--base-port", type=int, default=12010)
|
||||
parser.add_argument(
|
||||
"--server-per-host",
|
||||
type=int,
|
||||
)
|
||||
parser.add_argument("--model-per-host", type=int, default=1)
|
||||
parser.add_argument("--moderator-per-host", type=int, default=1)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def setup_participant_agent_server(host: str, port: int) -> None:
|
||||
"""Set up agent server"""
|
||||
agentscope.init(
|
||||
project="simulation",
|
||||
name="server",
|
||||
runtime_id=str(port),
|
||||
save_code=False,
|
||||
save_api_invoke=False,
|
||||
model_configs="configs/model_configs.json",
|
||||
use_monitor=False,
|
||||
)
|
||||
assistant_server_launcher = RpcAgentServerLauncher(
|
||||
host=host,
|
||||
port=port,
|
||||
max_pool_size=16384,
|
||||
custom_agents=[Moderator, RandomParticipant, LLMParticipant],
|
||||
)
|
||||
assistant_server_launcher.launch(in_subprocess=False)
|
||||
assistant_server_launcher.wait_until_terminate()
|
||||
|
||||
|
||||
def init_moderator(
|
||||
name: str,
|
||||
configs: list[dict],
|
||||
host: str,
|
||||
port: int,
|
||||
agent_type: str,
|
||||
max_value: int,
|
||||
sleep_time: float,
|
||||
) -> AgentBase:
|
||||
"""Init moderator"""
|
||||
return Moderator( # pylint: disable=E1123
|
||||
name=name,
|
||||
part_configs=configs,
|
||||
agent_type=agent_type,
|
||||
max_value=max_value,
|
||||
sleep_time=sleep_time,
|
||||
to_dist={
|
||||
"host": host,
|
||||
"port": port,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def run_main_process(
|
||||
hosts: list[str],
|
||||
base_port: int,
|
||||
server_per_host: int,
|
||||
model_per_host: int,
|
||||
participant_num: int,
|
||||
moderator_per_host: int = 10,
|
||||
agent_type: str = "random",
|
||||
max_value: int = 100,
|
||||
sleep_time: float = 1.0,
|
||||
) -> None:
|
||||
"""Run main process"""
|
||||
agentscope.init(
|
||||
project="simulation",
|
||||
name="main",
|
||||
save_code=False,
|
||||
save_api_invoke=False,
|
||||
model_configs="configs/model_configs.json",
|
||||
use_monitor=False,
|
||||
)
|
||||
host_num = len(hosts)
|
||||
total_agent_server_num = server_per_host * host_num
|
||||
participant_per_agent_server = participant_num // total_agent_server_num
|
||||
ist = time.time()
|
||||
configs = []
|
||||
logger.info(f"init {participant_num} {agent_type} participant agents...")
|
||||
# build init configs of participants
|
||||
for i in range(participant_num):
|
||||
idx = i // participant_per_agent_server
|
||||
host_id = idx // server_per_host
|
||||
port_id = idx % server_per_host
|
||||
model_id = i % model_per_host
|
||||
host = hosts[host_id]
|
||||
port = base_port + port_id
|
||||
config_name = f"model_{model_id + 1}"
|
||||
if agent_type == "random":
|
||||
configs.append(
|
||||
{
|
||||
"name": f"P{i}",
|
||||
"host": host,
|
||||
"port": port,
|
||||
},
|
||||
)
|
||||
else:
|
||||
configs.append(
|
||||
{
|
||||
"name": f"P{i}",
|
||||
"model_config_name": config_name,
|
||||
"host": host,
|
||||
"port": port,
|
||||
},
|
||||
)
|
||||
|
||||
mods = []
|
||||
moderator_num = moderator_per_host * host_num
|
||||
participant_per_moderator = participant_num // moderator_num
|
||||
tasks = []
|
||||
|
||||
logger.info(f"init {moderator_num} moderator agents...")
|
||||
# init moderators
|
||||
with futures.ThreadPoolExecutor(max_workers=None) as executor:
|
||||
for i in range(moderator_num):
|
||||
tasks.append(
|
||||
executor.submit(
|
||||
init_moderator,
|
||||
name=f"mod_{i}",
|
||||
configs=configs[
|
||||
i
|
||||
* participant_per_moderator : (i + 1) # noqa
|
||||
* participant_per_moderator
|
||||
],
|
||||
host=hosts[i // moderator_per_host],
|
||||
port=base_port + server_per_host + i % moderator_per_host,
|
||||
agent_type=agent_type,
|
||||
max_value=max_value,
|
||||
sleep_time=sleep_time,
|
||||
),
|
||||
)
|
||||
for task in as_completed(tasks):
|
||||
mods.append(task.result())
|
||||
|
||||
iet = time.time()
|
||||
logger.info(f"[init takes {iet - ist} s]")
|
||||
|
||||
# run te
|
||||
st = time.time()
|
||||
results = []
|
||||
for p in mods:
|
||||
results.append(p())
|
||||
summ = 0
|
||||
cnt = 0
|
||||
for r in results:
|
||||
try:
|
||||
summ += int(r["content"]["sum"])
|
||||
cnt += int(r["content"]["cnt"])
|
||||
except Exception:
|
||||
logger.error(r["content"])
|
||||
et = time.time()
|
||||
logger.chat(
|
||||
Msg(
|
||||
name="Moderator",
|
||||
role="assistant",
|
||||
content=f"The average value is {summ/cnt} [takes {et-st} s]",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_args()
|
||||
if args.role == "participant":
|
||||
setup_participant_agent_server(args.hosts[0], args.base_port)
|
||||
elif args.role == "main":
|
||||
run_main_process(
|
||||
hosts=args.hosts,
|
||||
base_port=args.base_port,
|
||||
participant_num=args.participant_num,
|
||||
server_per_host=args.server_per_host,
|
||||
model_per_host=args.model_per_host,
|
||||
moderator_per_host=args.moderator_per_host,
|
||||
agent_type=args.agent_type,
|
||||
sleep_time=args.sleep_time,
|
||||
max_value=args.max_value,
|
||||
)
|
||||
158
AlgoriAgent/examples/distributed_simulation/participant.py
Normal file
158
AlgoriAgent/examples/distributed_simulation/participant.py
Normal file
@@ -0,0 +1,158 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""A general dialog agent."""
|
||||
import random
|
||||
import time
|
||||
import re
|
||||
from typing import Optional, Union, Sequence
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from agentscope.message import Msg
|
||||
from agentscope.agents import AgentBase
|
||||
|
||||
|
||||
class RandomParticipant(AgentBase):
|
||||
"""A fake participant who generates number randomly."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
max_value: int = 100,
|
||||
sleep_time: float = 1.0,
|
||||
) -> None:
|
||||
"""Initialize the participant."""
|
||||
super().__init__(
|
||||
name=name,
|
||||
)
|
||||
self.max_value = max_value
|
||||
self.sleep_time = sleep_time
|
||||
|
||||
def generate_random_response(self) -> str:
|
||||
"""generate a random int"""
|
||||
time.sleep(self.sleep_time)
|
||||
return str(random.randint(0, self.max_value))
|
||||
|
||||
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
|
||||
"""Generate a random value"""
|
||||
# generate a response in content
|
||||
response = self.generate_random_response()
|
||||
msg = Msg(self.name, content=response)
|
||||
return msg
|
||||
|
||||
|
||||
class LLMParticipant(AgentBase):
|
||||
"""A participant agent who generates number using LLM."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
model_config_name: str,
|
||||
max_value: int = 100,
|
||||
) -> None:
|
||||
"""Initialize the participant."""
|
||||
super().__init__(
|
||||
name=name,
|
||||
model_config_name=model_config_name,
|
||||
use_memory=True,
|
||||
)
|
||||
self.max_value = max_value
|
||||
self.prompt = Msg(
|
||||
name="system",
|
||||
role="system",
|
||||
content="You are participating in a game where everyone "
|
||||
f"provides a number between 0 and {max_value}. The person "
|
||||
"closest to the average will win.",
|
||||
)
|
||||
|
||||
def parse_value(self, txt: str) -> str:
|
||||
"""Parse the number from the response."""
|
||||
numbers = re.findall(r"\d+", txt)
|
||||
if len(numbers) == 0:
|
||||
logger.warning(
|
||||
f"Fail to parse value from [{txt}], use "
|
||||
f"{self.max_value // 2} instead.",
|
||||
)
|
||||
return str(self.max_value // 2)
|
||||
else:
|
||||
return numbers[-1]
|
||||
|
||||
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
|
||||
"""Generate a value by LLM"""
|
||||
if self.memory:
|
||||
self.memory.add(x)
|
||||
|
||||
# prepare prompt
|
||||
prompt = self.model.format(self.prompt, self.memory.get_memory())
|
||||
|
||||
# call llm and generate response
|
||||
response = self.model(prompt).text
|
||||
|
||||
response = self.parse_value(response)
|
||||
|
||||
msg = Msg(self.name, response, role="assistant")
|
||||
|
||||
# Record the message in memory
|
||||
if self.memory:
|
||||
self.memory.add(msg)
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
class Moderator(AgentBase):
|
||||
"""A Moderator to collect values from participants."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
part_configs: list[dict],
|
||||
agent_type: str = "random",
|
||||
max_value: int = 100,
|
||||
sleep_time: float = 1.0,
|
||||
) -> None:
|
||||
super().__init__(name)
|
||||
self.max_value = max_value
|
||||
if agent_type == "llm":
|
||||
self.participants = [
|
||||
LLMParticipant(
|
||||
name=config["name"],
|
||||
model_config_name=config["model_config_name"],
|
||||
max_value=max_value,
|
||||
).to_dist(
|
||||
host=config["host"],
|
||||
port=config["port"],
|
||||
)
|
||||
for config in part_configs
|
||||
]
|
||||
else:
|
||||
self.participants = [
|
||||
RandomParticipant(
|
||||
name=config["name"],
|
||||
max_value=max_value,
|
||||
sleep_time=sleep_time,
|
||||
).to_dist(
|
||||
host=config["host"],
|
||||
port=config["port"],
|
||||
)
|
||||
for config in part_configs
|
||||
]
|
||||
|
||||
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
|
||||
results = []
|
||||
msg = Msg(
|
||||
name="moderator",
|
||||
role="user",
|
||||
content=f"Now give a number between 0 and {self.max_value}.",
|
||||
)
|
||||
for p in self.participants:
|
||||
results.append(p(msg))
|
||||
summ = 0
|
||||
for r in results:
|
||||
try:
|
||||
summ += int(r["content"])
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return Msg(
|
||||
name=self.name,
|
||||
role="assistant",
|
||||
content={"sum": summ, "cnt": len(self.participants)},
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
# default values
|
||||
base_port=12330
|
||||
hosts="localhost" # or "server1 server2 server3 ..."
|
||||
moderator_per_host=4
|
||||
model_per_host=8
|
||||
agent_type="random" # or "llm"
|
||||
max_value=100
|
||||
|
||||
# check server-per-host
|
||||
if ! [[ "$1" =~ ^[0-9]+$ ]]; then
|
||||
echo "Usage: $0 <server-per-host> <participant-num>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# check participant-num
|
||||
if ! [[ "$2" =~ ^[0-9]+$ ]]; then
|
||||
echo "Usage: $0 <server-per-host> <participant-num>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p log
|
||||
|
||||
python main.py --role main --hosts ${hosts} --base-port ${base_port} --participant-num $2 --server-per-host $1 --model-per-host ${model_per_host} --moderator-per-host ${moderator_per_host} --agent-type ${agent_type} --max-value ${max_value}
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
# default values
|
||||
base_port=12330
|
||||
host_name="localhost"
|
||||
moderator_num=4
|
||||
|
||||
# get number of server
|
||||
if ! [[ "$1" =~ ^[0-9]+$ ]]; then
|
||||
echo "Usage: $0 <number-of-server-for-participant>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
participant_server_num=$1
|
||||
|
||||
# create files for pid
|
||||
> .pid
|
||||
# create log dir
|
||||
mkdir -p log
|
||||
|
||||
# start all agent servers
|
||||
for ((i=0; i<(participant_server_num + moderator_num); i++)); do
|
||||
port=$((base_port + i))
|
||||
python main.py --role participant --hosts ${host_name} --base-port ${port} > log/${port}.log 2>&1 &
|
||||
echo $! >> .pid
|
||||
echo "Started agent server on ${host_name}:${port} with PID $!"
|
||||
done
|
||||
|
||||
echo "All servers started"
|
||||
19
AlgoriAgent/examples/distributed_simulation/start_vllm.sh
Normal file
19
AlgoriAgent/examples/distributed_simulation/start_vllm.sh
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
# default values
|
||||
gpu_num=8
|
||||
model_path="path-to-your-model-dir"
|
||||
base_port=8010
|
||||
|
||||
> .vllm_pid
|
||||
mkdir -p log
|
||||
|
||||
for ((i=0; i<8; i++)); do
|
||||
port=$((base_port + i))
|
||||
export CUDA_VISIBLE_DEVICES=$i
|
||||
python -m vllm.entrypoints.openai.api_server --model "${model_path}" --port ${port} --enforce-eager > log/vllm-${port}.log 2>&1 &
|
||||
echo $! >> .vllm_pid
|
||||
echo "Started vllm server on port ${port} with PID $!"
|
||||
done
|
||||
|
||||
echo "All vllm server started"
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ ! -f .pid ]; then
|
||||
echo "PID file not found. Are the servers running?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while read pid; do
|
||||
kill -9 $pid
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Killed server with PID $pid"
|
||||
else
|
||||
echo "Failed to kill server with PID $pid"
|
||||
fi
|
||||
done < .pid
|
||||
|
||||
rm .pid
|
||||
|
||||
echo "All servers stopped."
|
||||
19
AlgoriAgent/examples/distributed_simulation/stop_vllm.sh
Normal file
19
AlgoriAgent/examples/distributed_simulation/stop_vllm.sh
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ ! -f .vllm_pid ]; then
|
||||
echo "PID file not found. Are the servers running?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while read pid; do
|
||||
kill -9 $pid
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Killed vllm server with PID $pid"
|
||||
else
|
||||
echo "Failed to kill vllm server with PID $pid"
|
||||
fi
|
||||
done < .vllm_pid
|
||||
|
||||
rm .vllm_pid
|
||||
|
||||
echo "All vllm servers stopped."
|
||||
173
AlgoriAgent/examples/game_gomoku/code/board_agent.py
Normal file
173
AlgoriAgent/examples/game_gomoku/code/board_agent.py
Normal file
@@ -0,0 +1,173 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""A board agent class that can host a Gomoku game, and a function to
|
||||
convert the board to an image."""
|
||||
from typing import Optional, Union, Sequence
|
||||
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt, patches
|
||||
|
||||
from agentscope.message import Msg
|
||||
from agentscope.agents import AgentBase
|
||||
|
||||
|
||||
CURRENT_BOARD_PROMPT_TEMPLATE = """The current board is as follows:
|
||||
{board}
|
||||
{player}, it's your turn."""
|
||||
|
||||
NAME_BLACK = "Alice"
|
||||
NAME_WHITE = "Bob"
|
||||
|
||||
# The mapping from name to piece
|
||||
NAME_TO_PIECE = {
|
||||
NAME_BLACK: "o",
|
||||
NAME_WHITE: "x",
|
||||
}
|
||||
|
||||
EMPTY_PIECE = "0"
|
||||
|
||||
|
||||
def board2img(board: np.ndarray, save_path: str) -> str:
|
||||
"""Convert the board to an image and save it to the specified path."""
|
||||
|
||||
size = board.shape[0]
|
||||
fig, ax = plt.subplots(figsize=(10, 10))
|
||||
ax.set_xlim(0, size - 1)
|
||||
ax.set_ylim(0, size - 1)
|
||||
|
||||
for i in range(size):
|
||||
ax.axhline(i, color="black", linewidth=1)
|
||||
ax.axvline(i, color="black", linewidth=1)
|
||||
|
||||
for y in range(size):
|
||||
for x in range(size):
|
||||
if board[y, x] == NAME_TO_PIECE[NAME_BLACK]: # black player
|
||||
circle = patches.Circle(
|
||||
(x, y),
|
||||
0.45,
|
||||
edgecolor="black",
|
||||
facecolor="black",
|
||||
zorder=10,
|
||||
)
|
||||
ax.add_patch(circle)
|
||||
elif board[y, x] == NAME_TO_PIECE[NAME_WHITE]: # white player
|
||||
circle = patches.Circle(
|
||||
(x, y),
|
||||
0.45,
|
||||
edgecolor="black",
|
||||
facecolor="white",
|
||||
zorder=10,
|
||||
)
|
||||
ax.add_patch(circle)
|
||||
# Hide the axes and invert the y-axis
|
||||
ax.set_xticks(range(size))
|
||||
ax.set_yticks(range(size))
|
||||
ax.set_xticklabels(range(size))
|
||||
ax.set_yticklabels(range(size))
|
||||
ax.invert_yaxis()
|
||||
plt.savefig(save_path, bbox_inches="tight", pad_inches=0.1)
|
||||
plt.close(fig) # Close the figure to free memory
|
||||
return save_path
|
||||
|
||||
|
||||
class BoardAgent(AgentBase):
|
||||
"""A board agent that can host a Gomoku game."""
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
super().__init__(name=name, use_memory=False)
|
||||
|
||||
# Init the board
|
||||
self.size = 15
|
||||
self.board = np.full((self.size, self.size), EMPTY_PIECE)
|
||||
|
||||
# Record the status of the game
|
||||
self.game_end = False
|
||||
|
||||
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
|
||||
if x is None:
|
||||
# Beginning of the game
|
||||
content = (
|
||||
"Welcome to the Gomoku game! Black player goes first. "
|
||||
"Please make your move."
|
||||
)
|
||||
else:
|
||||
row, col = x.content
|
||||
|
||||
self.assert_valid_move(row, col)
|
||||
|
||||
# change the board
|
||||
self.board[row, col] = NAME_TO_PIECE[x.name]
|
||||
|
||||
# check if the game ends
|
||||
if self.check_draw():
|
||||
content = "The game ends in a draw!"
|
||||
self.game_end = True
|
||||
else:
|
||||
next_player_name = (
|
||||
NAME_BLACK if x.name == NAME_WHITE else NAME_WHITE
|
||||
)
|
||||
content = CURRENT_BOARD_PROMPT_TEMPLATE.format(
|
||||
board=self.board2text(),
|
||||
player=next_player_name,
|
||||
)
|
||||
|
||||
if self.check_win(row, col, NAME_TO_PIECE[x.name]):
|
||||
content = f"The game ends, {x.name} wins!"
|
||||
self.game_end = True
|
||||
|
||||
msg_host = Msg(self.name, content, role="assistant")
|
||||
self.speak(msg_host)
|
||||
|
||||
# Note: we disable the image display here to avoid too many images
|
||||
# img = plt.imread(board2img(self.board, 'current_board.png'))
|
||||
# plt.imshow(img)
|
||||
# plt.axis('off')
|
||||
# plt.show()
|
||||
|
||||
return msg_host
|
||||
|
||||
def assert_valid_move(self, x: int, y: int) -> None:
|
||||
"""Check if the move is valid."""
|
||||
if not (0 <= x < self.size and 0 <= y < self.size):
|
||||
raise RuntimeError(f"Invalid move: {[x, y]} out of board range.")
|
||||
|
||||
if not self.board[x, y] == EMPTY_PIECE:
|
||||
raise RuntimeError(
|
||||
f"Invalid move: {[x, y]} is already "
|
||||
f"occupied by {self.board[x, y]}.",
|
||||
)
|
||||
|
||||
def check_win(self, x: int, y: int, piece: str) -> bool:
|
||||
"""Check if the player wins the game."""
|
||||
xline = self._check_line(self.board[x, :], piece)
|
||||
yline = self._check_line(self.board[:, y], piece)
|
||||
diag1 = self._check_line(np.diag(self.board, y - x), piece)
|
||||
diag2 = self._check_line(
|
||||
np.diag(np.fliplr(self.board), self.size - 1 - x - y),
|
||||
piece,
|
||||
)
|
||||
return xline or yline or diag1 or diag2
|
||||
|
||||
def check_draw(self) -> bool:
|
||||
"""Check if the game ends in a draw."""
|
||||
return np.all(self.board != EMPTY_PIECE)
|
||||
|
||||
def board2text(self) -> str:
|
||||
"""Convert the board to a text representation."""
|
||||
return "\n".join(
|
||||
[
|
||||
str(_)[1:-1].replace("'", "").replace(" ", "")
|
||||
for _ in self.board
|
||||
],
|
||||
)
|
||||
|
||||
def _check_line(self, line: np.ndarray, piece: str) -> bool:
|
||||
"""Check if the player wins in a line."""
|
||||
count = 0
|
||||
for i in line:
|
||||
if i == piece:
|
||||
count += 1
|
||||
if count == 5:
|
||||
return True
|
||||
else:
|
||||
count = 0
|
||||
return False
|
||||
77
AlgoriAgent/examples/game_gomoku/code/game_gomoku.py
Normal file
77
AlgoriAgent/examples/game_gomoku/code/game_gomoku.py
Normal file
@@ -0,0 +1,77 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The main script to start a Gomoku game between two agents and a board
|
||||
agent."""
|
||||
|
||||
from board_agent import NAME_TO_PIECE, NAME_BLACK, NAME_WHITE, BoardAgent
|
||||
from gomoku_agent import GomokuAgent
|
||||
|
||||
from agentscope import msghub
|
||||
|
||||
import agentscope
|
||||
|
||||
|
||||
MAX_STEPS = 10
|
||||
|
||||
SYS_PROMPT_TEMPLATE = """
|
||||
You're a skillful Gomoku player. You should play against your opponent according to the following rules:
|
||||
|
||||
Game Rules:
|
||||
1. This Gomoku board is a 15*15 grid. Moves are made by specifying row and column indexes, with [0, 0] marking the top-left corner and [14, 14] indicating the bottom-right corner.
|
||||
2. The goal is to be the first player to form an unbroken line of your pieces horizontally, vertically, or diagonally.
|
||||
3. If the board is completely filled with pieces and no player has formed a row of five, the game is declared a draw.
|
||||
|
||||
Note:
|
||||
1. Your pieces are represented by '{}', your opponent's by '{}'. 0 represents an empty spot on the board.
|
||||
2. You should think carefully about your strategy and moves, considering both your and your opponent's subsequent moves.
|
||||
3. Make sure you don't place your piece on a spot that has already been occupied.
|
||||
4. Only an unbroken line of five same pieces will win the game. For example, "xxxoxx" won't be considered a win.
|
||||
5. Note the unbroken line can be formed in any direction: horizontal, vertical, or diagonal.
|
||||
""" # noqa
|
||||
|
||||
# Prepare the model configuration
|
||||
YOUR_MODEL_CONFIGURATION_NAME = "{YOUR_MODEL_CONFIGURATION_NAME}"
|
||||
YOUR_MODEL_CONFIGURATION = {
|
||||
"config_name": YOUR_MODEL_CONFIGURATION_NAME,
|
||||
# ...
|
||||
}
|
||||
|
||||
# Initialize the agents
|
||||
agentscope.init(model_configs=YOUR_MODEL_CONFIGURATION)
|
||||
|
||||
piece_black = NAME_TO_PIECE[NAME_BLACK]
|
||||
piece_white = NAME_TO_PIECE[NAME_WHITE]
|
||||
|
||||
black = GomokuAgent(
|
||||
NAME_BLACK,
|
||||
model_config_name=YOUR_MODEL_CONFIGURATION_NAME,
|
||||
sys_prompt=SYS_PROMPT_TEMPLATE.format(piece_black, piece_white),
|
||||
)
|
||||
|
||||
white = GomokuAgent(
|
||||
NAME_WHITE,
|
||||
model_config_name=YOUR_MODEL_CONFIGURATION_NAME,
|
||||
sys_prompt=SYS_PROMPT_TEMPLATE.format(piece_white, piece_black),
|
||||
)
|
||||
|
||||
board = BoardAgent(name="Host")
|
||||
|
||||
# Start the game!
|
||||
msg = None
|
||||
i = 0
|
||||
# Use a msg hub to share conversation between two players, e.g. white player
|
||||
# can hear what black player says to the board
|
||||
with msghub(participants=[black, white, board]):
|
||||
while not board.game_end and i < MAX_STEPS:
|
||||
for player in [black, white]:
|
||||
# receive the move from the player, judge if the game ends and
|
||||
# remind the player to make a move
|
||||
msg = board(msg)
|
||||
|
||||
# end the game if draw or win
|
||||
if board.game_end:
|
||||
break
|
||||
|
||||
# make a move
|
||||
msg = player(msg)
|
||||
|
||||
i += 1
|
||||
82
AlgoriAgent/examples/game_gomoku/code/gomoku_agent.py
Normal file
82
AlgoriAgent/examples/game_gomoku/code/gomoku_agent.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""A Gomoku agent that can play the game with another agent."""
|
||||
|
||||
from typing import Optional, Union, Sequence
|
||||
|
||||
import json
|
||||
|
||||
from agentscope.message import Msg
|
||||
from agentscope.agents import AgentBase
|
||||
from agentscope.models import ModelResponse
|
||||
|
||||
HINT_PROMPT = """
|
||||
You should respond in the following format, which can be loaded by json.loads in Python:
|
||||
{{
|
||||
"thought": "analyze the present situation, and what move you should make",
|
||||
"move": [row index, column index]
|
||||
}}
|
||||
""" # noqa
|
||||
|
||||
|
||||
def parse_func(response: ModelResponse) -> ModelResponse:
|
||||
"""Parse the response from the model into a dict with "move" and "thought"
|
||||
keys."""
|
||||
res_dict = json.loads(response.text)
|
||||
if "move" in res_dict and "thought" in res_dict:
|
||||
return ModelResponse(raw=res_dict)
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Invalid response format in parse_func "
|
||||
f"with response: {response.text}",
|
||||
)
|
||||
|
||||
|
||||
class GomokuAgent(AgentBase):
|
||||
"""A Gomoku agent that can play the game with another agent."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
sys_prompt: str,
|
||||
model_config_name: str,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
name=name,
|
||||
sys_prompt=sys_prompt,
|
||||
model_config_name=model_config_name,
|
||||
)
|
||||
|
||||
self.memory.add(Msg("system", sys_prompt, role="system"))
|
||||
|
||||
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None) -> Msg:
|
||||
if self.memory:
|
||||
self.memory.add(x)
|
||||
|
||||
msg_hint = Msg("system", HINT_PROMPT, role="system")
|
||||
|
||||
prompt = self.model.format(
|
||||
self.memory.get_memory(),
|
||||
msg_hint,
|
||||
)
|
||||
|
||||
response = self.model(
|
||||
prompt,
|
||||
parse_func=parse_func,
|
||||
max_retries=3,
|
||||
).raw
|
||||
|
||||
# For better presentation, we print the response proceeded by
|
||||
# json.dumps, this msg won't be recorded in memory
|
||||
self.speak(
|
||||
Msg(
|
||||
self.name,
|
||||
json.dumps(response, indent=4, ensure_ascii=False),
|
||||
role="assistant",
|
||||
),
|
||||
)
|
||||
|
||||
if self.memory:
|
||||
self.memory.add(Msg(self.name, response, role="assistant"))
|
||||
|
||||
# Hide thought from the response
|
||||
return Msg(self.name, response["move"], role="assistant")
|
||||
881
AlgoriAgent/examples/game_gomoku/main.ipynb
Normal file
881
AlgoriAgent/examples/game_gomoku/main.ipynb
Normal file
File diff suppressed because one or more lines are too long
81
AlgoriAgent/examples/game_werewolf/README.md
Normal file
81
AlgoriAgent/examples/game_werewolf/README.md
Normal file
@@ -0,0 +1,81 @@
|
||||
|
||||
# Werewolf Game in AgentScope
|
||||
|
||||
This example demonstrates how to use AgentScope to play the Werewolf game, where six agents play against each other as werewolves and villagers.
|
||||
You will learn the following features in AgentScope:
|
||||
|
||||
- How to make an agent respond with **different specified fields** in **different situations** in AgentScope (Like a finite state machine!)
|
||||
- How to use **msghub** and **pipeline** in AgentScope to construct a game with **COMPLEX SOP**
|
||||
|
||||
## Background
|
||||
|
||||
The werewolf game involves a complex SOP with multiple roles and different phases. In these phases, players with different roles should take different actions, e.g. discussion, voting, checking roles (seer), using potions (witch), and so on.
|
||||
|
||||
Therefore, for an agent in werewolf game, it should be able to switch its status according to the game phase and its role, and respond accordingly.
|
||||
Of course, we can hard code the SOP (or finite state machine) within the agent, but we expect the agent to be more **flexible**, **intelligent**, and **adaptive**, which means **the agent shouldn't be designed for a specific game only**. It should be able to adapt to different tasks and SOPs!
|
||||
|
||||
To achieve this goal, in AgentScope, we use a built-in [DictDialogAgent](https://github.com/modelscope/agentscope/blob/main/src/agentscope/agents/dict_dialog_agent.py) class, together with a [parser](https://modelscope.github.io/agentscope/en/tutorial/203-parser.html) module to construct the werewolf game.
|
||||
|
||||
Moreover, the [pipeline and msghub](https://modelscope.github.io/agentscope/en/tutorial/202-pipeline.html) in AgentScope enable us to easily construct a complex SOP with multiple agents. We hope the implementation is concise, clear and readable!
|
||||
|
||||
More details please refer to our tutorial:
|
||||
- [Parser](https://modelscope.github.io/agentscope/en/tutorial/203-parser.html)
|
||||
- [Pipeline and msghub](https://modelscope.github.io/agentscope/en/tutorial/202-pipeline.html)
|
||||
|
||||
|
||||
|
||||
|
||||
https://github.com/DavdGao/AgentScope/assets/102287034/86951418-e1cc-486b-a3dc-b237a0108994
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## Tested Models
|
||||
|
||||
This example has been tested with the following models:
|
||||
- dashscope_chat (qwen-turbo)
|
||||
- ollama_chat (llama3_8b)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
To run this example, you need to:
|
||||
- Set your API key in `./configs/model_configs.json`
|
||||
|
||||
[Optional] To play the game in person, see [werewolf.py](werewolf.py) for the complete code.
|
||||
|
||||
|
||||
## Code Snippets
|
||||
|
||||
### About Pipeline and MsgHub
|
||||
|
||||
The following code is the implementation of daytime discussion in Werewolf. With msghub and pipeline, it's very easy to program a discussion among agents.
|
||||
|
||||
```python
|
||||
# ...
|
||||
with msghub(survivors, announcement=hints) as hub:
|
||||
# discuss
|
||||
set_parsers(survivors, Prompts.survivors_discuss_parser)
|
||||
x = sequentialpipeline(survivors)
|
||||
# ...
|
||||
```
|
||||
|
||||
### About Parser
|
||||
|
||||
The parser is used to specify the required fields in the agent's response and how to handle them. Here's an example of a parser configuration:
|
||||
|
||||
```python
|
||||
to_wolves_vote = "Which player do you vote to kill?"
|
||||
|
||||
wolves_vote_parser = MarkdownJsonDictParser(
|
||||
content_hint={
|
||||
"thought": "what you thought",
|
||||
"vote": "player_name",
|
||||
},
|
||||
required_keys=["thought", "vote"],
|
||||
keys_to_memory="vote",
|
||||
keys_to_content="vote",
|
||||
)
|
||||
```
|
||||
|
||||
In this example, the `MarkdownJsonDictParser` is used to parse the agent's response. The `content_hint` parameter specifies the expected fields and their descriptions. The `required_keys` parameter indicates the mandatory fields in the response. The `keys_to_memory` and `keys_to_content` parameters determine which fields should be stored in memory and included in the content of the returned message, respectively.
|
||||
@@ -0,0 +1,56 @@
|
||||
[
|
||||
{
|
||||
"class": "DictDialogAgent",
|
||||
"args": {
|
||||
"name": "Player1",
|
||||
"sys_prompt": "Act as a player in a werewolf game. You are Player1 and\nthere are totally 6 players, named Player1, Player2, Player3, Player4, Player5 and Player6.\n\nPLAYER ROLES:\nIn werewolf game, players are divided into two werewolves, two villagers, one seer and one witch. Note only werewolves know who are their teammates.\nWerewolves: They know their teammates' identities and attempt to eliminate a villager each night while trying to remain undetected.\nVillagers: They do not know who the werewolves are and must work together during the day to deduce who the werewolves might be and vote to eliminate them.\nSeer: A villager with the ability to learn the true identity of one player each night. This role is crucial for the villagers to gain information.\nWitch: A character who has a one-time ability to save a player from being eliminated at night (sometimes this is a potion of life) and a one-time ability to eliminate a player at night (a potion of death).\n\nGAME RULE:\nThe game is consisted of two phases: night phase and day phase. The two phases are repeated until werewolf or villager win the game.\n1. Night Phase: During the night, the werewolves discuss and vote for a player to eliminate. Special roles also perform their actions at this time (e.g., the Seer chooses a player to learn their role, the witch chooses a decide if save the player).\n2. Day Phase: During the day, all surviving players discuss who they suspect might be a werewolf. No one reveals their role unless it serves a strategic purpose. After the discussion, a vote is taken, and the player with the most votes is \"lynched\" or eliminated from the game.\n\nVICTORY CONDITION:\nFor werewolves, they win the game if the number of werewolves is equal to or greater than the number of remaining villagers.\nFor villagers, they win if they identify and eliminate all of the werewolves in the group.\n\nCONSTRAINTS:\n1. Your response should be in the first person.\n2. This is a conversational game. You should response only based on the conversation history and your strategy.\n\nYou are playing werewolf in this game.\n",
|
||||
"model_config_name": "gpt-4",
|
||||
"use_memory": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "DictDialogAgent",
|
||||
"args": {
|
||||
"name": "Player2",
|
||||
"sys_prompt": "Act as a player in a werewolf game. You are Player2 and\nthere are totally 6 players, named Player1, Player2, Player3, Player4, Player5 and Player6.\n\nPLAYER ROLES:\nIn werewolf game, players are divided into two werewolves, two villagers, one seer and one witch. Note only werewolves know who are their teammates.\nWerewolves: They know their teammates' identities and attempt to eliminate a villager each night while trying to remain undetected.\nVillagers: They do not know who the werewolves are and must work together during the day to deduce who the werewolves might be and vote to eliminate them.\nSeer: A villager with the ability to learn the true identity of one player each night. This role is crucial for the villagers to gain information.\nWitch: A character who has a one-time ability to save a player from being eliminated at night (sometimes this is a potion of life) and a one-time ability to eliminate a player at night (a potion of death).\n\nGAME RULE:\nThe game is consisted of two phases: night phase and day phase. The two phases are repeated until werewolf or villager win the game.\n1. Night Phase: During the night, the werewolves discuss and vote for a player to eliminate. Special roles also perform their actions at this time (e.g., the Seer chooses a player to learn their role, the witch chooses a decide if save the player).\n2. Day Phase: During the day, all surviving players discuss who they suspect might be a werewolf. No one reveals their role unless it serves a strategic purpose. After the discussion, a vote is taken, and the player with the most votes is \"lynched\" or eliminated from the game.\n\nVICTORY CONDITION:\nFor werewolves, they win the game if the number of werewolves is equal to or greater than the number of remaining villagers.\nFor villagers, they win if they identify and eliminate all of the werewolves in the group.\n\nCONSTRAINTS:\n1. Your response should be in the first person.\n2. This is a conversational game. You should response only based on the conversation history and your strategy.\n\nYou are playing werewolf in this game.\n",
|
||||
"model_config_name": "gpt-4",
|
||||
"use_memory": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "DictDialogAgent",
|
||||
"args": {
|
||||
"name": "Player3",
|
||||
"sys_prompt": "Act as a player in a werewolf game. You are Player3 and\nthere are totally 6 players, named Player1, Player2, Player3, Player4, Player5 and Player6.\n\nPLAYER ROLES:\nIn werewolf game, players are divided into two werewolves, two villagers, one seer and one witch. Note only werewolves know who are their teammates.\nWerewolves: They know their teammates' identities and attempt to eliminate a villager each night while trying to remain undetected.\nVillagers: They do not know who the werewolves are and must work together during the day to deduce who the werewolves might be and vote to eliminate them.\nSeer: A villager with the ability to learn the true identity of one player each night. This role is crucial for the villagers to gain information.\nWitch: A character who has a one-time ability to save a player from being eliminated at night (sometimes this is a potion of life) and a one-time ability to eliminate a player at night (a potion of death).\n\nGAME RULE:\nThe game is consisted of two phases: night phase and day phase. The two phases are repeated until werewolf or villager win the game.\n1. Night Phase: During the night, the werewolves discuss and vote for a player to eliminate. Special roles also perform their actions at this time (e.g., the Seer chooses a player to learn their role, the witch chooses a decide if save the player).\n2. Day Phase: During the day, all surviving players discuss who they suspect might be a werewolf. No one reveals their role unless it serves a strategic purpose. After the discussion, a vote is taken, and the player with the most votes is \"lynched\" or eliminated from the game.\n\nVICTORY CONDITION:\nFor werewolves, they win the game if the number of werewolves is equal to or greater than the number of remaining villagers.\nFor villagers, they win if they identify and eliminate all of the werewolves in the group.\n\nCONSTRAINTS:\n1. Your response should be in the first person.\n2. This is a conversational game. You should response only based on the conversation history and your strategy.\n\nYou are playing villager in this game.\n",
|
||||
"model_config_name": "gpt-4",
|
||||
"use_memory": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "DictDialogAgent",
|
||||
"args": {
|
||||
"name": "Player4",
|
||||
"sys_prompt": "Act as a player in a werewolf game. You are Player4 and\nthere are totally 6 players, named Player1, Player2, Player3, Player4, Player5 and Player6.\n\nPLAYER ROLES:\nIn werewolf game, players are divided into two werewolves, two villagers, one seer and one witch. Note only werewolves know who are their teammates.\nWerewolves: They know their teammates' identities and attempt to eliminate a villager each night while trying to remain undetected.\nVillagers: They do not know who the werewolves are and must work together during the day to deduce who the werewolves might be and vote to eliminate them.\nSeer: A villager with the ability to learn the true identity of one player each night. This role is crucial for the villagers to gain information.\nWitch: A character who has a one-time ability to save a player from being eliminated at night (sometimes this is a potion of life) and a one-time ability to eliminate a player at night (a potion of death).\n\nGAME RULE:\nThe game is consisted of two phases: night phase and day phase. The two phases are repeated until werewolf or villager win the game.\n1. Night Phase: During the night, the werewolves discuss and vote for a player to eliminate. Special roles also perform their actions at this time (e.g., the Seer chooses a player to learn their role, the witch chooses a decide if save the player).\n2. Day Phase: During the day, all surviving players discuss who they suspect might be a werewolf. No one reveals their role unless it serves a strategic purpose. After the discussion, a vote is taken, and the player with the most votes is \"lynched\" or eliminated from the game.\n\nVICTORY CONDITION:\nFor werewolves, they win the game if the number of werewolves is equal to or greater than the number of remaining villagers.\nFor villagers, they win if they identify and eliminate all of the werewolves in the group.\n\nCONSTRAINTS:\n1. Your response should be in the first person.\n2. This is a conversational game. You should response only based on the conversation history and your strategy.\n\nYou are playing villager in this game.\n",
|
||||
"model_config_name": "gpt-4",
|
||||
"use_memory": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "DictDialogAgent",
|
||||
"args": {
|
||||
"name": "Player5",
|
||||
"sys_prompt": "Act as a player in a werewolf game. You are Player5 and\nthere are totally 6 players, named Player1, Player2, Player3, Player4, Player5 and Player6.\n\nPLAYER ROLES:\nIn werewolf game, players are divided into two werewolves, two villagers, one seer and one witch. Note only werewolves know who are their teammates.\nWerewolves: They know their teammates' identities and attempt to eliminate a villager each night while trying to remain undetected.\nVillagers: They do not know who the werewolves are and must work together during the day to deduce who the werewolves might be and vote to eliminate them.\nSeer: A villager with the ability to learn the true identity of one player each night. This role is crucial for the villagers to gain information.\nWitch: A character who has a one-time ability to save a player from being eliminated at night (sometimes this is a potion of life) and a one-time ability to eliminate a player at night (a potion of death).\n\nGAME RULE:\nThe game is consisted of two phases: night phase and day phase. The two phases are repeated until werewolf or villager win the game.\n1. Night Phase: During the night, the werewolves discuss and vote for a player to eliminate. Special roles also perform their actions at this time (e.g., the Seer chooses a player to learn their role, the witch chooses a decide if save the player).\n2. Day Phase: During the day, all surviving players discuss who they suspect might be a werewolf. No one reveals their role unless it serves a strategic purpose. After the discussion, a vote is taken, and the player with the most votes is \"lynched\" or eliminated from the game.\n\nVICTORY CONDITION:\nFor werewolves, they win the game if the number of werewolves is equal to or greater than the number of remaining villagers.\nFor villagers, they win if they identify and eliminate all of the werewolves in the group.\n\nCONSTRAINTS:\n1. Your response should be in the first person.\n2. This is a conversational game. You should response only based on the conversation history and your strategy.\n\nYou are playing seer in this game.\n",
|
||||
"model_config_name": "gpt-4",
|
||||
"use_memory": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"class": "DictDialogAgent",
|
||||
"args": {
|
||||
"name": "Player6",
|
||||
"sys_prompt": "Act as a player in a werewolf game. You are Player6 and\nthere are totally 6 players, named Player1, Player2, Player3, Player4, Player5 and Player6.\n\nPLAYER ROLES:\nIn werewolf game, players are divided into two werewolves, two villagers, one seer and one witch. Note only werewolves know who are their teammates.\nWerewolves: They know their teammates' identities and attempt to eliminate a villager each night while trying to remain undetected.\nVillagers: They do not know who the werewolves are and must work together during the day to deduce who the werewolves might be and vote to eliminate them.\nSeer: A villager with the ability to learn the true identity of one player each night. This role is crucial for the villagers to gain information.\nWitch: A character who has a one-time ability to save a player from being eliminated at night (sometimes this is a potion of life) and a one-time ability to eliminate a player at night (a potion of death).\n\nGAME RULE:\nThe game is consisted of two phases: night phase and day phase. The two phases are repeated until werewolf or villager win the game.\n1. Night Phase: During the night, the werewolves discuss and vote for a player to eliminate. Special roles also perform their actions at this time (e.g., the Seer chooses a player to learn their role, the witch chooses a decide if save the player).\n2. Day Phase: During the day, all surviving players discuss who they suspect might be a werewolf. No one reveals their role unless it serves a strategic purpose. After the discussion, a vote is taken, and the player with the most votes is \"lynched\" or eliminated from the game.\n\nVICTORY CONDITION:\nFor werewolves, they win the game if the number of werewolves is equal to or greater than the number of remaining villagers.\nFor villagers, they win if they identify and eliminate all of the werewolves in the group.\n\nCONSTRAINTS:\n1. Your response should be in the first person.\n2. This is a conversational game. You should response only based on the conversation history and your strategy.\n\nYou are playing witch in this game.\n",
|
||||
"model_config_name": "gpt-4",
|
||||
"use_memory": true
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
[
|
||||
{
|
||||
"model_type": "openai_chat",
|
||||
"config_name": "gpt-4",
|
||||
"model_name": "gpt-4",
|
||||
"api_key": "xxx",
|
||||
"organization": "xxx",
|
||||
"generate_args": {
|
||||
"temperature": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"model_type": "post_api_chat",
|
||||
"config_name": "my_post_api",
|
||||
"api_url": "https://xxx",
|
||||
"headers": {},
|
||||
"json_args": {}
|
||||
}
|
||||
]
|
||||
152
AlgoriAgent/examples/game_werewolf/prompt.py
Normal file
152
AlgoriAgent/examples/game_werewolf/prompt.py
Normal file
@@ -0,0 +1,152 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Used to record prompts, will be replaced by configuration"""
|
||||
from agentscope.parsers.json_object_parser import MarkdownJsonDictParser
|
||||
|
||||
|
||||
class Prompts:
|
||||
"""Prompts for werewolf game"""
|
||||
|
||||
to_wolves = (
|
||||
"{}, if you are the only werewolf, eliminate a player. Otherwise, "
|
||||
"discuss with your teammates and reach an agreement."
|
||||
)
|
||||
|
||||
wolves_discuss_parser = MarkdownJsonDictParser(
|
||||
content_hint={
|
||||
"thought": "what you thought",
|
||||
"speak": "what you speak",
|
||||
"finish_discussion": "whether the discussion reached an "
|
||||
"agreement or not (true/false)",
|
||||
},
|
||||
required_keys=["thought", "speak", "finish_discussion"],
|
||||
keys_to_memory="speak",
|
||||
keys_to_content="speak",
|
||||
keys_to_metadata=["finish_discussion"],
|
||||
)
|
||||
|
||||
to_wolves_vote = "Which player do you vote to kill?"
|
||||
|
||||
wolves_vote_parser = MarkdownJsonDictParser(
|
||||
content_hint={
|
||||
"thought": "what you thought",
|
||||
"vote": "player_name",
|
||||
},
|
||||
required_keys=["thought", "vote"],
|
||||
keys_to_memory="vote",
|
||||
keys_to_content="vote",
|
||||
)
|
||||
|
||||
to_wolves_res = "The player with the most votes is {}."
|
||||
|
||||
to_witch_resurrect = (
|
||||
"{witch_name}, you're the witch. Tonight {dead_name} is eliminated. "
|
||||
"Would you like to resurrect {dead_name}?"
|
||||
)
|
||||
|
||||
to_witch_resurrect_no = "The witch has chosen not to resurrect the player."
|
||||
to_witch_resurrect_yes = "The witch has chosen to resurrect the player."
|
||||
|
||||
witch_resurrect_parser = MarkdownJsonDictParser(
|
||||
content_hint={
|
||||
"thought": "what you thought",
|
||||
"speak": "whether to resurrect the player and the reason",
|
||||
"resurrect": "whether to resurrect the player or not (true/false)",
|
||||
},
|
||||
required_keys=["thought", "speak", "resurrect"],
|
||||
keys_to_memory="speak",
|
||||
keys_to_content="speak",
|
||||
keys_to_metadata=["resurrect"],
|
||||
)
|
||||
|
||||
to_witch_poison = (
|
||||
"Would you like to eliminate one player? If yes, "
|
||||
"specify the player_name."
|
||||
)
|
||||
|
||||
witch_poison_parser = MarkdownJsonDictParser(
|
||||
content_hint={
|
||||
"thought": "what you thought",
|
||||
"speak": "what you speak",
|
||||
"eliminate": "whether to eliminate a player or not (true/false)",
|
||||
},
|
||||
required_keys=["thought", "speak", "eliminate"],
|
||||
keys_to_memory="speak",
|
||||
keys_to_content="speak",
|
||||
keys_to_metadata=["eliminate"],
|
||||
)
|
||||
|
||||
to_seer = (
|
||||
"{}, you're the seer. Which player in {} would you like to check "
|
||||
"tonight?"
|
||||
)
|
||||
|
||||
seer_parser = MarkdownJsonDictParser(
|
||||
content_hint={
|
||||
"thought": "what you thought",
|
||||
"speak": "player_name",
|
||||
},
|
||||
required_keys=["thought", "speak"],
|
||||
keys_to_memory="speak",
|
||||
keys_to_content="speak",
|
||||
)
|
||||
|
||||
to_seer_result = "Okay, the role of {} is a {}."
|
||||
|
||||
to_all_danger = (
|
||||
"The day is coming, all the players open your eyes. Last night, "
|
||||
"the following player(s) has been eliminated: {}."
|
||||
)
|
||||
|
||||
to_all_peace = (
|
||||
"The day is coming, all the players open your eyes. Last night is "
|
||||
"peaceful, no player is eliminated."
|
||||
)
|
||||
|
||||
to_all_discuss = (
|
||||
"Now the alive players are {}. Given the game rules and your role, "
|
||||
"based on the situation and the information you gain, to vote a "
|
||||
"player eliminated among alive players and to win the game, what do "
|
||||
"you want to say to others? You can decide whether to reveal your "
|
||||
"role."
|
||||
)
|
||||
|
||||
survivors_discuss_parser = MarkdownJsonDictParser(
|
||||
content_hint={
|
||||
"thought": "what you thought",
|
||||
"speak": "what you speak",
|
||||
},
|
||||
required_keys=["thought", "speak"],
|
||||
keys_to_memory="speak",
|
||||
keys_to_content="speak",
|
||||
)
|
||||
|
||||
survivors_vote_parser = MarkdownJsonDictParser(
|
||||
content_hint={
|
||||
"thought": "what you thought",
|
||||
"vote": "player_name",
|
||||
},
|
||||
required_keys=["thought", "vote"],
|
||||
keys_to_memory="vote",
|
||||
keys_to_content="vote",
|
||||
)
|
||||
|
||||
to_all_vote = (
|
||||
"Given the game rules and your role, based on the situation and the"
|
||||
" information you gain, to win the game, it's time to vote one player"
|
||||
" eliminated among the alive players. Which player do you vote to "
|
||||
"kill?"
|
||||
)
|
||||
|
||||
to_all_res = "{} has been voted out."
|
||||
|
||||
to_all_wolf_win = (
|
||||
"The werewolves have prevailed and taken over the village. Better "
|
||||
"luck next time!"
|
||||
)
|
||||
|
||||
to_all_village_win = (
|
||||
"The game is over. The werewolves have been defeated, and the village "
|
||||
"is safe once again!"
|
||||
)
|
||||
|
||||
to_all_continue = "The game goes on."
|
||||
149
AlgoriAgent/examples/game_werewolf/werewolf.py
Normal file
149
AlgoriAgent/examples/game_werewolf/werewolf.py
Normal file
@@ -0,0 +1,149 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""A werewolf game implemented by agentscope."""
|
||||
from functools import partial
|
||||
|
||||
from prompt import Prompts
|
||||
from werewolf_utils import (
|
||||
check_winning,
|
||||
update_alive_players,
|
||||
majority_vote,
|
||||
extract_name_and_id,
|
||||
n2s,
|
||||
set_parsers,
|
||||
)
|
||||
from agentscope.message import Msg
|
||||
from agentscope.msghub import msghub
|
||||
from agentscope.pipelines.functional import sequentialpipeline
|
||||
import agentscope
|
||||
|
||||
|
||||
# pylint: disable=too-many-statements
|
||||
def main() -> None:
|
||||
"""werewolf game"""
|
||||
# default settings
|
||||
HostMsg = partial(Msg, name="Moderator", role="assistant", echo=True)
|
||||
healing, poison = True, True
|
||||
MAX_WEREWOLF_DISCUSSION_ROUND = 3
|
||||
MAX_GAME_ROUND = 6
|
||||
# read model and agent configs, and initialize agents automatically
|
||||
survivors = agentscope.init(
|
||||
model_configs="./configs/model_configs.json",
|
||||
agent_configs="./configs/agent_configs.json",
|
||||
project="Werewolf",
|
||||
)
|
||||
|
||||
roles = ["werewolf", "werewolf", "villager", "villager", "seer", "witch"]
|
||||
wolves, witch, seer = survivors[:2], survivors[-1], survivors[-2]
|
||||
|
||||
# start the game
|
||||
for _ in range(1, MAX_GAME_ROUND + 1):
|
||||
# night phase, werewolves discuss
|
||||
hint = HostMsg(content=Prompts.to_wolves.format(n2s(wolves)))
|
||||
with msghub(wolves, announcement=hint) as hub:
|
||||
set_parsers(wolves, Prompts.wolves_discuss_parser)
|
||||
for _ in range(MAX_WEREWOLF_DISCUSSION_ROUND):
|
||||
x = sequentialpipeline(wolves)
|
||||
if x.metadata.get("finish_discussion", False):
|
||||
break
|
||||
|
||||
# werewolves vote
|
||||
set_parsers(wolves, Prompts.wolves_vote_parser)
|
||||
hint = HostMsg(content=Prompts.to_wolves_vote)
|
||||
votes = [
|
||||
extract_name_and_id(wolf(hint).content)[0] for wolf in wolves
|
||||
]
|
||||
# broadcast the result to werewolves
|
||||
dead_player = [majority_vote(votes)]
|
||||
hub.broadcast(
|
||||
HostMsg(content=Prompts.to_wolves_res.format(dead_player[0])),
|
||||
)
|
||||
|
||||
# witch
|
||||
healing_used_tonight = False
|
||||
if witch in survivors:
|
||||
if healing:
|
||||
hint = HostMsg(
|
||||
content=Prompts.to_witch_resurrect.format_map(
|
||||
{
|
||||
"witch_name": witch.name,
|
||||
"dead_name": dead_player[0],
|
||||
},
|
||||
),
|
||||
)
|
||||
set_parsers(witch, Prompts.witch_resurrect_parser)
|
||||
if witch(hint).metadata.get("resurrect", False):
|
||||
healing_used_tonight = True
|
||||
dead_player.pop()
|
||||
healing = False
|
||||
HostMsg(content=Prompts.to_witch_resurrect_yes)
|
||||
else:
|
||||
HostMsg(content=Prompts.to_witch_resurrect_no)
|
||||
|
||||
if poison and not healing_used_tonight:
|
||||
set_parsers(witch, Prompts.witch_poison_parser)
|
||||
x = witch(HostMsg(content=Prompts.to_witch_poison))
|
||||
if x.metadata.get("eliminate", False):
|
||||
dead_player.append(extract_name_and_id(x.content)[0])
|
||||
poison = False
|
||||
|
||||
# seer
|
||||
if seer in survivors:
|
||||
hint = HostMsg(
|
||||
content=Prompts.to_seer.format(seer.name, n2s(survivors)),
|
||||
)
|
||||
set_parsers(seer, Prompts.seer_parser)
|
||||
x = seer(hint)
|
||||
|
||||
player, idx = extract_name_and_id(x.content)
|
||||
role = "werewolf" if roles[idx] == "werewolf" else "villager"
|
||||
hint = HostMsg(content=Prompts.to_seer_result.format(player, role))
|
||||
seer.observe(hint)
|
||||
|
||||
survivors, wolves = update_alive_players(
|
||||
survivors,
|
||||
wolves,
|
||||
dead_player,
|
||||
)
|
||||
if check_winning(survivors, wolves, "Moderator"):
|
||||
break
|
||||
|
||||
# daytime discussion
|
||||
content = (
|
||||
Prompts.to_all_danger.format(n2s(dead_player))
|
||||
if dead_player
|
||||
else Prompts.to_all_peace
|
||||
)
|
||||
hints = [
|
||||
HostMsg(content=content),
|
||||
HostMsg(content=Prompts.to_all_discuss.format(n2s(survivors))),
|
||||
]
|
||||
with msghub(survivors, announcement=hints) as hub:
|
||||
# discuss
|
||||
set_parsers(survivors, Prompts.survivors_discuss_parser)
|
||||
x = sequentialpipeline(survivors)
|
||||
|
||||
# vote
|
||||
set_parsers(survivors, Prompts.survivors_vote_parser)
|
||||
hint = HostMsg(content=Prompts.to_all_vote.format(n2s(survivors)))
|
||||
votes = [
|
||||
extract_name_and_id(_(hint).content)[0] for _ in survivors
|
||||
]
|
||||
vote_res = majority_vote(votes)
|
||||
# broadcast the result to all players
|
||||
result = HostMsg(content=Prompts.to_all_res.format(vote_res))
|
||||
hub.broadcast(result)
|
||||
|
||||
survivors, wolves = update_alive_players(
|
||||
survivors,
|
||||
wolves,
|
||||
vote_res,
|
||||
)
|
||||
|
||||
if check_winning(survivors, wolves, "Moderator"):
|
||||
break
|
||||
|
||||
hub.broadcast(HostMsg(content=Prompts.to_all_continue))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
86
AlgoriAgent/examples/game_werewolf/werewolf_utils.py
Normal file
86
AlgoriAgent/examples/game_werewolf/werewolf_utils.py
Normal file
@@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""utils."""
|
||||
import re
|
||||
from typing import Union, Any, Sequence
|
||||
|
||||
import numpy as np
|
||||
from loguru import logger
|
||||
|
||||
from prompt import Prompts
|
||||
from agentscope.agents import AgentBase
|
||||
from agentscope.message import Msg
|
||||
|
||||
|
||||
def check_winning(alive_agents: list, wolf_agents: list, host: str) -> bool:
|
||||
"""check which group wins"""
|
||||
if len(wolf_agents) * 2 >= len(alive_agents):
|
||||
msg = Msg(host, Prompts.to_all_wolf_win, role="assistant")
|
||||
logger.chat(msg)
|
||||
return True
|
||||
if alive_agents and not wolf_agents:
|
||||
msg = Msg(host, Prompts.to_all_village_win, role="assistant")
|
||||
logger.chat(msg)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def update_alive_players(
|
||||
survivors: Sequence[AgentBase],
|
||||
wolves: Sequence[AgentBase],
|
||||
dead_names: Union[str, list[str]],
|
||||
) -> tuple[list, list]:
|
||||
"""update the list of alive agents"""
|
||||
if not isinstance(dead_names, list):
|
||||
dead_names = [dead_names]
|
||||
return [_ for _ in survivors if _.name not in dead_names], [
|
||||
_ for _ in wolves if _.name not in dead_names
|
||||
]
|
||||
|
||||
|
||||
def majority_vote(votes: list) -> Any:
|
||||
"""majority_vote function"""
|
||||
votes_valid = [item for item in votes if item != "Abstain"]
|
||||
# Count the votes excluding abstentions.
|
||||
unit, counts = np.unique(votes_valid, return_counts=True)
|
||||
return unit[np.argmax(counts)]
|
||||
|
||||
|
||||
def extract_name_and_id(name: str) -> tuple[str, int]:
|
||||
"""extract player name and id from a string"""
|
||||
try:
|
||||
name = re.search(r"\b[Pp]layer\d+\b", name).group(0)
|
||||
idx = int(re.search(r"[Pp]layer(\d+)", name).group(1)) - 1
|
||||
except AttributeError:
|
||||
# In case Player remains silent or speaks to abstain.
|
||||
logger.warning(f"vote: invalid name {name}, set to Abstain")
|
||||
name = "Abstain"
|
||||
idx = -1
|
||||
return name, idx
|
||||
|
||||
|
||||
def n2s(agents: Sequence[Union[AgentBase, str]]) -> str:
|
||||
"""combine agent names into a string, and use "and" to connect the last
|
||||
two names."""
|
||||
|
||||
def _get_name(agent_: Union[AgentBase, str]) -> str:
|
||||
return agent_.name if isinstance(agent_, AgentBase) else agent_
|
||||
|
||||
if len(agents) == 1:
|
||||
return _get_name(agents[0])
|
||||
|
||||
return (
|
||||
", ".join([_get_name(_) for _ in agents[:-1]])
|
||||
+ " and "
|
||||
+ _get_name(agents[-1])
|
||||
)
|
||||
|
||||
|
||||
def set_parsers(
|
||||
agents: Union[AgentBase, list[AgentBase]],
|
||||
parser_name: str,
|
||||
) -> None:
|
||||
"""Add parser to agents"""
|
||||
if not isinstance(agents, list):
|
||||
agents = [agents]
|
||||
for agent in agents:
|
||||
agent.set_parser(parser_name)
|
||||
@@ -0,0 +1,37 @@
|
||||
[{
|
||||
"config_name": "dashscope_chat-qwen-max",
|
||||
"model_type": "dashscope_chat",
|
||||
"model_name": "qwen-max",
|
||||
"api_key": "{your_api_key}",
|
||||
"generate_args": {
|
||||
"temperature": 0.7
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "dashscope_chat-qwen-max-1201",
|
||||
"model_type": "dashscope_chat",
|
||||
"model_name": "qwen-max-1201",
|
||||
"api_key": "{your_api_key}",
|
||||
"generate_args": {
|
||||
"temperature": 0.7
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "dashscope_chat-qwen-turbo",
|
||||
"model_type": "dashscope_chat",
|
||||
"model_name": "qwen-turbo",
|
||||
"api_key": "{your_api_key}",
|
||||
"generate_args": {
|
||||
"temperature": 0.7
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "dashscope_chat-qwen-plus",
|
||||
"model_type": "dashscope_chat",
|
||||
"model_name": "qwen-plus",
|
||||
"api_key": "{your_api_key}",
|
||||
"generate_args": {
|
||||
"temperature": 0.7
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,34 @@
|
||||
[{
|
||||
"config_name": "dashscope_image_synthesis-wanx-v1-1024x1024",
|
||||
"model_type": "dashscope_image_synthesis",
|
||||
"model_name": "wanx-v1",
|
||||
"api_key": "{your_api_key}",
|
||||
"generate_args": {
|
||||
"n": 1,
|
||||
"negative_prompt": "{unwanted_prompt}",
|
||||
"size": "1024*1024"
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "dashscope_image_synthesis-wanx-v1-720x1280",
|
||||
"model_type": "dashscope_image_synthesis",
|
||||
"model_name": "wanx-v1",
|
||||
"api_key": "{your_api_key}",
|
||||
"generate_args": {
|
||||
"n": 1,
|
||||
"negative_prompt": "{unwanted_prompt}",
|
||||
"size": "720*1280"
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "dashscope_image_synthesis-wanx-v1-1280x720",
|
||||
"model_type": "dashscope_image_synthesis",
|
||||
"model_name": "wanx-v1",
|
||||
"api_key": "{your_api_key}",
|
||||
"generate_args": {
|
||||
"n": 1,
|
||||
"negative_prompt": "{unwanted_prompt}",
|
||||
"size": "1280*720"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,40 @@
|
||||
[{
|
||||
"config_name": "dashscope_multimodal-qwen-vl-plus",
|
||||
"model_type": "dashscope_multimodal",
|
||||
"model_name": "qwen-vl-plus",
|
||||
"api_key": "{your_api_key}",
|
||||
"generate_args": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "dashscope_multimodal-qwen-vl-max",
|
||||
"model_type": "dashscope_multimodal",
|
||||
"model_name": "qwen-vl-max",
|
||||
"api_key": "{your_api_key}",
|
||||
"generate_args": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "dashscope_multimodal-qwen-audio-turbo",
|
||||
"model_type": "dashscope_multimodal",
|
||||
"model_name": "qwen-audio-turbo",
|
||||
"api_key": "{your_api_key}",
|
||||
"generate_args": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "dashscope_multimodal-qwen-vl-chat-v1",
|
||||
"model_type": "dashscope_multimodal",
|
||||
"model_name": "qwen-vl-chat-v1",
|
||||
"api_key": "{your_api_key}",
|
||||
"generate_args": {
|
||||
}
|
||||
},{
|
||||
"config_name": "dashscope_multimodal-qwen-audio-chat-v1",
|
||||
"model_type": "dashscope_multimodal",
|
||||
"model_name": "qwen-vl-chat-v1",
|
||||
"api_key": "{your_api_key}",
|
||||
"generate_args": {
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,13 @@
|
||||
[{
|
||||
"config_name": "dashscope_text_embedding-text-embedding-v1",
|
||||
"model_type": "dashscope_text_embedding",
|
||||
"model_name": "text-embedding-v1",
|
||||
"api_key": "{your_api_key}"
|
||||
},
|
||||
{
|
||||
"config_name": "dashscope_text_embedding-text-embedding-v2",
|
||||
"model_type": "dashscope_text_embedding",
|
||||
"model_name": "text-embedding-v2",
|
||||
"api_key": "{your_api_key}"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[{
|
||||
"config_name": "gemini_chat-gemini-pro",
|
||||
"model_type": "gemini_chat",
|
||||
"model_name": "gemini-pro",
|
||||
"api_key": "{your_api_key}"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[{
|
||||
"config_name": "gemini_chat-embedding-001",
|
||||
"model_type": "gemini_embedding",
|
||||
"model_name": "models/embedding-001",
|
||||
"api_key": "{your_api_key}"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,11 @@
|
||||
[{
|
||||
"config_name": "lite_llm_openai_chat_gpt-3.5-turbo",
|
||||
"model_type": "litellm_chat",
|
||||
"model_name": "gpt-3.5-turbo"
|
||||
},
|
||||
{
|
||||
"config_name": "lite_llm_claude3",
|
||||
"model_type": "litellm_chat",
|
||||
"model_name": "claude-3-opus-20240229"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,37 @@
|
||||
[{
|
||||
"config_name": "ollama_chat-llama2",
|
||||
"model_type": "ollama_chat",
|
||||
"model_name": "llama2",
|
||||
"options": {
|
||||
"temperature": 0.7
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
},
|
||||
{
|
||||
"config_name": "ollama_chat-mistral",
|
||||
"model_type": "ollama_chat",
|
||||
"model_name": "mistral",
|
||||
"options": {
|
||||
"temperature": 0.7
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
},
|
||||
{
|
||||
"config_name": "ollama_chat-qwen:0.5b",
|
||||
"model_type": "ollama_chat",
|
||||
"model_name": "qwen:0.5b",
|
||||
"options": {
|
||||
"temperature": 0.7
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
},
|
||||
{
|
||||
"config_name": "ollama_chat-codellama",
|
||||
"model_type": "ollama_chat",
|
||||
"model_name": "codellama",
|
||||
"options": {
|
||||
"temperature": 0.7
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,28 @@
|
||||
[{
|
||||
"config_name": "ollama_embedding-llama2",
|
||||
"model_type": "ollama_embedding",
|
||||
"model_name": "llama2",
|
||||
"options": {
|
||||
"temperature": 0.7
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
},
|
||||
{
|
||||
"config_name": "ollama_embedding-mistral",
|
||||
"model_type": "ollama_embedding",
|
||||
"model_name": "mistral",
|
||||
"options": {
|
||||
"temperature": 0.7
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
},
|
||||
{
|
||||
"config_name": "ollama_embedding-qwen:0.5b",
|
||||
"model_type": "ollama_embedding",
|
||||
"model_name": "qwen:0.5b",
|
||||
"options": {
|
||||
"temperature": 0.7
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,28 @@
|
||||
[{
|
||||
"config_name": "ollama_generate-llama2",
|
||||
"model_type": "ollama_generate",
|
||||
"model_name": "llama2",
|
||||
"options": {
|
||||
"temperature": 0.7
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
},
|
||||
{
|
||||
"config_name": "ollama_generate-mistral",
|
||||
"model_type": "ollama_generate",
|
||||
"model_name": "mistral",
|
||||
"options": {
|
||||
"temperature": 0.7
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
},
|
||||
{
|
||||
"config_name": "ollama_generate-qwen:0.5b",
|
||||
"model_type": "ollama_generate",
|
||||
"model_name": "qwen:0.5b",
|
||||
"options": {
|
||||
"temperature": 0.7
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,38 @@
|
||||
[
|
||||
{
|
||||
"config_name": "openai_chat_gpt-4",
|
||||
"model_type": "openai_chat",
|
||||
"model_name": "gpt-4",
|
||||
"api_key": "{your_api_key}",
|
||||
"client_args": {
|
||||
"max_retries": 3
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 0.7
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "openai_chat_gpt-3.5-turbo",
|
||||
"model_type": "openai_chat",
|
||||
"model_name": "gpt-3.5-turbo",
|
||||
"api_key": "{your_api_key}",
|
||||
"client_args": {
|
||||
"max_retries": 3
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 0.7
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "openai_chat_gpt-4o",
|
||||
"model_type": "openai_chat",
|
||||
"model_name": "gpt-4o",
|
||||
"api_key": "{your_api_key}",
|
||||
"client_args": {
|
||||
"max_retries": 3
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 0.7
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,27 @@
|
||||
[{
|
||||
"config_name": "openai_dall_e-dall-e-2",
|
||||
"model_type": "openai_dall_e",
|
||||
"model_name": "dall-e-2",
|
||||
"api_key": "{your_api_key}",
|
||||
"client_args": {
|
||||
"max_retries": 3
|
||||
},
|
||||
"generate_args": {
|
||||
"n": 1,
|
||||
"size": "512x512"
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "openai_dall_e-dall-e-3",
|
||||
"model_type": "openai_dall_e",
|
||||
"model_name": "dall-e-3",
|
||||
"api_key": "{your_api_key}",
|
||||
"client_args": {
|
||||
"max_retries": 3
|
||||
},
|
||||
"generate_args": {
|
||||
"n": 1,
|
||||
"size": "512x512"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,13 @@
|
||||
[{
|
||||
"config_name": "openai_embedding-text-embedding-ada-002",
|
||||
"model_type": "openai_embedding",
|
||||
"model_name": "text-embedding-ada-002",
|
||||
"api_key": "{your_api_key}",
|
||||
"client_args": {
|
||||
"max_retries": 3
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 0.7
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,81 @@
|
||||
[{
|
||||
"config_name": "post_api_chat-flask_llama2-7b-chat-hf",
|
||||
"model_type": "post_api_chat",
|
||||
"api_url": "http://127.0.0.1:8000/llm/",
|
||||
"json_args": {
|
||||
"max_length": 4096,
|
||||
"temperature": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "post_api_chat-flask_llama2-7b-chat-ms",
|
||||
"model_type": "post_api_chat",
|
||||
"api_url": "http://127.0.0.1:8000/llm/",
|
||||
"json_args": {
|
||||
"max_length": 4096,
|
||||
"temperature": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "post_api-fastchat_llama2-7b-chat-hf",
|
||||
"model_type": "openai_chat",
|
||||
"api_key": "EMPTY",
|
||||
"client_args": {
|
||||
"base_url": "http://127.0.0.1:8000/v1/"
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "post_api-vllm_llama2-7b-chat-hf",
|
||||
"model_type": "openai_chat",
|
||||
"api_key": "EMPTY",
|
||||
"client_args": {
|
||||
"base_url": "http://127.0.0.1:8000/v1/"
|
||||
},
|
||||
"generate_args": {
|
||||
"temperature": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "post_api_chat-model-inference-api-gpt2",
|
||||
"model_type": "post_api_chat",
|
||||
"headers": {
|
||||
"Authorization": "Bearer {YOUR_API_TOKEN}"
|
||||
},
|
||||
"api_url": "https://api-inference.huggingface.co/models/gpt2"
|
||||
},
|
||||
{
|
||||
"config_name": "post_api_img_syn_config",
|
||||
"model_type": "post_api_dall_e",
|
||||
"api_url": "http://xxx.xxx.xxx.xxx:xxxx/xxx",
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer {YOUR_API_TOKEN}"
|
||||
},
|
||||
"messages_key": "prompt",
|
||||
"json_args": {
|
||||
"model": "{YOUR_MODEL}",
|
||||
"n":1,
|
||||
"quality":"standard",
|
||||
"response_format":"url",
|
||||
"size":"512x512",
|
||||
"style":"natural"
|
||||
}
|
||||
},
|
||||
{
|
||||
"config_name": "post_api_embedding_config",
|
||||
"model_type": "post_api_embedding",
|
||||
"api_url": "http://xxx.xxx.xxx.xxx:xxxx/xxx",
|
||||
"headers": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer {YOUR_API_TOKEN}"
|
||||
},
|
||||
"messages_key": "input",
|
||||
"json_args": {
|
||||
"model": "{YOUR_MODEL}",
|
||||
"encoding_format": "float"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[{
|
||||
"config_name": "zhipuai_chat-glm",
|
||||
"model_type": "zhipuai_chat",
|
||||
"model_name": "glm-4",
|
||||
"api_key": "{your_api_key}"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,7 @@
|
||||
[{
|
||||
"config_name": "zhipu-embedding",
|
||||
"model_type": "zhipuai_embedding",
|
||||
"model_name": "embedding-2",
|
||||
"api_key": "{your_api_key}"
|
||||
}
|
||||
]
|
||||
136
AlgoriAgent/examples/model_llama3/README.md
Normal file
136
AlgoriAgent/examples/model_llama3/README.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# Llama3 in AgentScope
|
||||
|
||||
AgentScope supports Llama3 now! You can
|
||||
|
||||
- 🚀 Set up Llama3 model service in AgentScope! Both CPU and GPU inference are supported!
|
||||
- 🔧 Test Llama3 in AgentScope built-in examples!
|
||||
- 🖋 Use Llama3 to build your own multi-agent applications!
|
||||
|
||||
Follow the guidance below to use Llama3 in AgentScope!
|
||||
|
||||
## Contents
|
||||
|
||||
- [CPU Inference](#cpu-inference)
|
||||
- [Setup Llama3 Service](#setup-llama3-service)
|
||||
- [Use Llama3 in AgentScope](#use-llama3-in-agentscope)
|
||||
- [GPU Inference](#gpu-inference)
|
||||
- [Setup Llama3 Service](#setup-llama3-service-1)
|
||||
- [Use Llama3 in AgentScope](#use-llama3-in-agentscope-1)
|
||||
|
||||
## CPU Inference
|
||||
|
||||
### Setup Llama3 Service
|
||||
|
||||
AgentScope supports Llama3 CPU inference with the help of ollama. Note the llama3 models in ollama are quantized into 4 bits.
|
||||
|
||||
1. Download ollama from [here](https://ollama.com/).
|
||||
|
||||
2. Start ollama software, or execute the following command in terminal
|
||||
|
||||
```bash
|
||||
ollama serve
|
||||
```
|
||||
|
||||
3. Pull llama3 model by the following command
|
||||
|
||||
```bash
|
||||
# llama3 8b model
|
||||
ollama pull llama3
|
||||
|
||||
# llama3 70b model
|
||||
ollama pull llama3:70b
|
||||
```
|
||||
|
||||
### Use Llama3 in AgentScope
|
||||
|
||||
Use llama3 model with the following model configuration in AgentScope
|
||||
|
||||
```python
|
||||
llama3_8b_ollama_model_configuration = {
|
||||
"config_name": "ollama_llama3_8b",
|
||||
"model_type": "ollama_chat",
|
||||
"model_name": "llama3",
|
||||
"options": {
|
||||
"temperature": 0.5,
|
||||
"seed": 123
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
}
|
||||
|
||||
llama3_70b_ollama_model_configuration = {
|
||||
"config_name": "ollama_llama3_70b",
|
||||
"model_type": "ollama_chat",
|
||||
"model_name": "llama3:70b",
|
||||
"options": {
|
||||
"temperature": 0.5,
|
||||
"seed": 123
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
}
|
||||
```
|
||||
|
||||
After that, you can experience llama3 with our built-in examples! For example, start a conversation with llama3-8b model by the following code:
|
||||
|
||||
```python
|
||||
import agentscope
|
||||
from agentscope.agents import UserAgent, DialogAgent
|
||||
|
||||
agentscope.init(model_configs=llama3_8b_ollama_model_configuration)
|
||||
|
||||
user = UserAgent("user")
|
||||
agent = DialogAgent("assistant", sys_prompt="You're a helpful assistant.", model_config_name="ollama_llama3_8b")
|
||||
|
||||
x = None
|
||||
while True:
|
||||
x = agent(x)
|
||||
x = user(x)
|
||||
if x.content == "exit":
|
||||
break
|
||||
```
|
||||
|
||||
## GPU Inference
|
||||
|
||||
### Setup Llama3 Service
|
||||
|
||||
If you have a GPU, you can set up llama3 model service with the help of Flask and Transformers quickly.
|
||||
|
||||
Note you need to apply for permission to download the llama3 model from [Hugging Face model hub](https://huggingface.co/unsloth/llama-3-8b-Instruct).
|
||||
|
||||
1. Install Flask and Transformers
|
||||
|
||||
```bash
|
||||
pip install flask transformers torch
|
||||
```
|
||||
|
||||
2. Apply for model permission, and log in your huggingface account in terminal
|
||||
|
||||
```bash
|
||||
huggingface-cli login
|
||||
```
|
||||
|
||||
3. Then run flask server by the following command in scripts directory:
|
||||
|
||||
```bash
|
||||
# 8B model
|
||||
python flask_transformers/setup_hf_service.py --model_name_or_path meta-llama/Meta-Llama-3-8B-Instruct --port 8000
|
||||
|
||||
# 70B model
|
||||
python flask_transformers/setup_hf_service.py --model_name_or_path meta-llama/Meta-Llama-3-70B-Instruct --port 8000
|
||||
```
|
||||
|
||||
### Use Llama3 in AgentScope
|
||||
|
||||
In AgentScope, use the following model configurations
|
||||
|
||||
```python
|
||||
llama3_flask_model_configuration = {
|
||||
"model_type": "post_api_chat",
|
||||
"config_name": "llama-3",
|
||||
"api_url": "http://127.0.0.1:8000/llm/",
|
||||
"json_args": {
|
||||
"max_length": 4096,
|
||||
"temperature": 0.5,
|
||||
"eos_token_id": [128001, 128009] # currently the model configuration in huggingface misses eos_token_id
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"model_type": "post_api_chat",
|
||||
"config_name": "llama-3",
|
||||
"api_url": "http://127.0.0.1:8000/llm/",
|
||||
"json_args": {
|
||||
"max_length": 4096,
|
||||
"temperature": 0.5
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
[
|
||||
{
|
||||
"config_name": "ollama_llama3_8b",
|
||||
"model_type": "ollama_chat",
|
||||
"model_name": "llama3",
|
||||
"options": {
|
||||
"temperature": 0.5,
|
||||
"seed": 123
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
},
|
||||
{
|
||||
"config_name": "ollama_llama3_70b",
|
||||
"model_type": "ollama_chat",
|
||||
"model_name": "llama3:70b",
|
||||
"options": {
|
||||
"temperature": 0.5,
|
||||
"seed": 123
|
||||
},
|
||||
"keep_alive": "5m"
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user