提交版本
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
180
AlgoriAgent/projects/algoriAgent/agent/score_agent.py
Normal file
180
AlgoriAgent/projects/algoriAgent/agent/score_agent.py
Normal file
@@ -0,0 +1,180 @@
|
||||
|
||||
from typing import Any, Callable, Optional, Union, Sequence
|
||||
|
||||
from loguru import logger
|
||||
from agent.flex_service_toolkit import FlexServiceToolkit
|
||||
from agentscope.exception import ResponseParsingError, FunctionCallError
|
||||
from agentscope.agents import AgentBase
|
||||
from agentscope.memory.temporary_memory import TemporaryMemory
|
||||
from agentscope.message import Msg
|
||||
from agentscope.parsers import MarkdownJsonDictParser
|
||||
from agentscope.service.service_toolkit import ServiceFunction
|
||||
from agentscope.service import (
|
||||
ServiceToolkit,
|
||||
ServiceResponse,
|
||||
ServiceExecStatus,
|
||||
)
|
||||
import json
|
||||
|
||||
|
||||
INSTRUCTION_SCORE_PROMPT_CN = """
|
||||
你是一名经验丰富的算法课程评分专家,你的任务是:基于学生对一个章节的学习日志、对话流,按照指定的评分标准进行评分。
|
||||
但是不同于普通老师,为了提高得分的区分度,你需要作为一名非常挑剔的专家,根据评分标准仔细挑剔学生的学习日志,并给出评分报告。
|
||||
|
||||
重要的挑剔点:
|
||||
1. 存在错误的概念理解
|
||||
2. 存在矛盾的概念理解
|
||||
3. 存在不清晰、不连贯的概念表达
|
||||
4. 其他你认为可以挑剔的地方
|
||||
|
||||
下面是学生的整个学习日志和对话流:
|
||||
"""
|
||||
|
||||
CHAPTER_HINT_CN ="""
|
||||
上面就是学生的整个学习日志和对话流,请进行下面的各条章节评分标准进行挑剔与评分。
|
||||
"""
|
||||
|
||||
RESPONSE_HINT_CN = """
|
||||
你的返回必须包含:
|
||||
对于每条章节评分标准,报告学生的得分以及挑剔的结果。
|
||||
例如:
|
||||
```
|
||||
{'评分标准1': {'得分': 8, '挑剔报告': '答案正确,但对于xxx概念表述有误'}
|
||||
}
|
||||
```
|
||||
"""
|
||||
|
||||
INSTRUCTION_SCORE_PROMPT_EN = """
|
||||
You are a experienced algorithm course scoring expert, your task is to: Based on the students' learning logs and dialogues, score them according to the specified scoring standard.
|
||||
But unlike a normal teacher, to improve the distinction of the score, you need to be a very critical expert, carefully pick out the students' learning logs according to the scoring standard and give a score report.
|
||||
|
||||
The important points to pick out:
|
||||
1. There are errors in the concept understanding
|
||||
2. There are contradictions in the concept understanding
|
||||
3. There are unclear, incoherent concept expressions
|
||||
4. Other places you think can be picked out
|
||||
Below is the students' entire learning log and dialogue:
|
||||
"""
|
||||
|
||||
CHAPTER_HINT_EN = """
|
||||
Above is the students' entire learning log and dialogue, please pick out according to the following chapter scoring standard and score them.
|
||||
"""
|
||||
|
||||
RESPONSE_HINT_EN="""
|
||||
Your response must contain:
|
||||
For each chapter scoring standard, report the students' score and pick out the results.
|
||||
For example:
|
||||
```
|
||||
{'Score standard 1': {'Score': 8, 'Pick out report': 'The answer is correct, but for the xxx concept expression is wrong'}
|
||||
}
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
class ScoreAgent(AgentBase):
|
||||
"""
|
||||
ScoreAgent is a agent that can score students' learning logs.
|
||||
"""
|
||||
def __init__(self, name: str, model_config_name: str, memory: TemporaryMemory,
|
||||
chapter_score_prompt: str,
|
||||
service_toolkit: ServiceToolkit,
|
||||
sys_prompt: str = "You're a helpful assistant.",
|
||||
max_iters: int = 5,
|
||||
verbose: bool = True,
|
||||
**kwargs):
|
||||
self.service_toolkit = service_toolkit
|
||||
super().__init__(
|
||||
name=name,
|
||||
sys_prompt=sys_prompt,
|
||||
model_config_name=model_config_name,
|
||||
)
|
||||
self.max_iters = max_iters
|
||||
self.verbose = verbose
|
||||
if not sys_prompt.endswith("\n"):
|
||||
sys_prompt = sys_prompt + "\n"
|
||||
|
||||
self.sys_prompt = "\n".join(
|
||||
[
|
||||
# The brief intro of the role and target
|
||||
sys_prompt.format(name=self.name),
|
||||
# The detailed instruction prompt for the agent
|
||||
INSTRUCTION_SCORE_PROMPT_CN,
|
||||
],
|
||||
)
|
||||
self.memory = TemporaryMemory()
|
||||
self.memory.add(Msg("system", self.sys_prompt, role="system"))
|
||||
|
||||
self.memory.add(memory.get_memory())
|
||||
|
||||
self.memory.add(Msg("system", CHAPTER_HINT_CN, role="system"))
|
||||
|
||||
self.memory.add(Msg("system", chapter_score_prompt, role="system"))
|
||||
|
||||
self.memory.add(Msg("system", RESPONSE_HINT_CN, role="system"))
|
||||
|
||||
self.parser = MarkdownJsonDictParser(
|
||||
content_hint={
|
||||
"thought": "what you thought",
|
||||
"speak": "actual response in correct format mentioned above",
|
||||
},
|
||||
required_keys=["thought", "speak"],
|
||||
# Only print the speak field when verbose is False
|
||||
keys_to_content=True if self.verbose else "speak",
|
||||
)
|
||||
|
||||
def reply(self, x = None, user_backboard = ""):
|
||||
for _ in range(self.max_iters):
|
||||
if self.verbose:
|
||||
self.speak(f" ITER {_+1} ".center(70, "#"))
|
||||
try:
|
||||
|
||||
hint_msg = Msg(
|
||||
"system",
|
||||
self.parser.format_instruction+"\n",
|
||||
role="system",
|
||||
echo=self.verbose,
|
||||
)
|
||||
prompt = self.model.format(self.memory.get_memory(),hint_msg
|
||||
)
|
||||
if self.verbose:
|
||||
self.speak(f"API Trigger".center(70, "#"))
|
||||
self.speak(str(prompt))
|
||||
res = self.model(
|
||||
prompt,
|
||||
parse_func=self.parser.parse,
|
||||
max_retries=2,
|
||||
######################
|
||||
)
|
||||
|
||||
if self.verbose:
|
||||
self.speak(f"Result Parsed".center(70, "#"))
|
||||
self.speak(str(res.parsed))
|
||||
print(res.parsed)
|
||||
self.memory.add(
|
||||
Msg(
|
||||
self.name,
|
||||
self.parser.to_memory(res.parsed),
|
||||
"assistant",
|
||||
),
|
||||
)
|
||||
msg_returned = Msg(
|
||||
self.name,
|
||||
self.parser.to_content(res.parsed),
|
||||
"assistant",
|
||||
)
|
||||
return msg_returned
|
||||
except ResponseParsingError as e:
|
||||
# Print out raw response from models for developers to debug
|
||||
response_msg = Msg(self.name, e.raw_response, "assistant")
|
||||
self.speak(response_msg)
|
||||
# Re-correct by model itself
|
||||
error_msg = Msg("system", str(e), "system")
|
||||
self.speak(error_msg)
|
||||
self.memory.add([response_msg, error_msg])
|
||||
except Exception as e:
|
||||
self.speak(f"Error: {e}".center(70, "#"))
|
||||
self.speak(f"Retrying".center(70, "#"))
|
||||
continue
|
||||
|
||||
return Msg(self.name, "Error: Max iterations reached", "assistant")
|
||||
|
||||
152
AlgoriAgent/projects/algoriAgent/agent/total_score_agent.py
Normal file
152
AlgoriAgent/projects/algoriAgent/agent/total_score_agent.py
Normal file
@@ -0,0 +1,152 @@
|
||||
|
||||
from typing import Any, Callable, Optional, Union, Sequence
|
||||
|
||||
from loguru import logger
|
||||
from agent.flex_service_toolkit import FlexServiceToolkit
|
||||
from agentscope.exception import ResponseParsingError, FunctionCallError
|
||||
from agentscope.agents import AgentBase
|
||||
from agentscope.memory.temporary_memory import TemporaryMemory
|
||||
from agentscope.message import Msg
|
||||
from agentscope.parsers import MarkdownJsonDictParser
|
||||
from agentscope.service.service_toolkit import ServiceFunction
|
||||
from agentscope.service import (
|
||||
ServiceToolkit,
|
||||
ServiceResponse,
|
||||
ServiceExecStatus,
|
||||
)
|
||||
import json
|
||||
|
||||
|
||||
INSTRUCTION_TOTAL_SCORE_PROMPT_CN = """
|
||||
你是一名精通文件处理的专家,你的本次任务非常简单,给你一段由其他老师给出的评分评价,你需要从中提取每一条标准下的得分,并计算总分,返回总分即可。
|
||||
"""
|
||||
|
||||
|
||||
RESPONSE_TOTAL_SCORE_HINT_CN = """
|
||||
你的返回必须包含且仅包含一个整数,表示得分。
|
||||
例如:
|
||||
输入:
|
||||
```
|
||||
{'评分标准1': {'得分': 8, '挑剔报告': '答案正确,但对于xxx概念表述有误'},
|
||||
'评分标准2': {'得分': 3, '挑剔报告': '答案错误,对于xxx概念理解完全错误,导致回答有误'}
|
||||
}
|
||||
```
|
||||
输出:
|
||||
11
|
||||
下面是真正的输入:
|
||||
"""
|
||||
|
||||
INSTRUCTION_TOTAL_SCORE_PROMPT_EN = """
|
||||
You are an expert in file processing. Your task is very simple. You will be given a segment of evaluation comments provided by another teacher. You need to extract the scores for each criterion and calculate the total score, returning only the total score.
|
||||
"""
|
||||
|
||||
|
||||
RESPONSE_TOTAL_SCORE_HINT_EN="""
|
||||
Your return must contain and only contain an integer representing the score. For example:
|
||||
Input:
|
||||
```
|
||||
{'Criterion 1': {'Score': 8, 'Critical Report': 'The answer is correct, but there is a mistake in the explanation of the xxx concept'},
|
||||
'Criterion 2': {'Score': 3, 'Critical Report': 'The answer is incorrect, with a complete misunderstanding of the xxx concept, leading to an incorrect response'}
|
||||
}
|
||||
```
|
||||
Output:
|
||||
```
|
||||
{'output': 11}
|
||||
```
|
||||
Below is the actual input:
|
||||
"""
|
||||
|
||||
|
||||
class TotalScoreAgent(AgentBase):
|
||||
"""
|
||||
TotalScoreAgent is a agent that can gather students' all score.
|
||||
"""
|
||||
def __init__(self, name: str, model_config_name: str, input: str,
|
||||
service_toolkit: ServiceToolkit,
|
||||
sys_prompt: str = "You're a helpful assistant.",
|
||||
max_iters: int = 5,
|
||||
verbose: bool = True,
|
||||
**kwargs):
|
||||
self.service_toolkit = service_toolkit
|
||||
super().__init__(
|
||||
name=name,
|
||||
sys_prompt=sys_prompt,
|
||||
model_config_name=model_config_name,
|
||||
)
|
||||
self.max_iters = max_iters
|
||||
self.verbose = verbose
|
||||
if not sys_prompt.endswith("\n"):
|
||||
sys_prompt = sys_prompt + "\n"
|
||||
|
||||
self.sys_prompt = "\n".join(
|
||||
[
|
||||
# The brief intro of the role and target
|
||||
sys_prompt.format(name=self.name),
|
||||
# The detailed instruction prompt for the agent
|
||||
INSTRUCTION_TOTAL_SCORE_PROMPT_CN,
|
||||
RESPONSE_TOTAL_SCORE_HINT_CN
|
||||
],
|
||||
)
|
||||
self.memory = TemporaryMemory()
|
||||
self.memory.add(Msg("system", self.sys_prompt, role="system"))
|
||||
|
||||
self.memory.add(Msg("User", input, role="system"))
|
||||
self.parser = MarkdownJsonDictParser(
|
||||
content_hint={
|
||||
"output": "total score",
|
||||
},
|
||||
required_keys=["output"],
|
||||
# Only print the speak field when verbose is False
|
||||
keys_to_content=True if self.verbose else "speak",
|
||||
)
|
||||
|
||||
def reply(self, x = None, user_backboard = ""):
|
||||
for _ in range(self.max_iters):
|
||||
if self.verbose:
|
||||
self.speak(f" ITER {_+1} ".center(70, "#"))
|
||||
try:
|
||||
|
||||
hint_msg = Msg(
|
||||
"system",
|
||||
self.parser.format_instruction+"\n",
|
||||
role="system",
|
||||
echo=self.verbose,
|
||||
)
|
||||
prompt = self.model.format(self.memory.get_memory(),hint_msg
|
||||
)
|
||||
if self.verbose:
|
||||
self.speak(f"API Trigger".center(70, "#"))
|
||||
self.speak(str(prompt))
|
||||
res = self.model(
|
||||
prompt,
|
||||
parse_func=self.parser.parse,
|
||||
max_retries=2,
|
||||
######################
|
||||
)
|
||||
|
||||
print('====-======-=====')
|
||||
|
||||
return res.parsed['output']
|
||||
|
||||
|
||||
if self.verbose:
|
||||
self.speak(f"Result Parsed".center(70, "#"))
|
||||
self.speak(str(res))
|
||||
print(res)
|
||||
|
||||
return res
|
||||
except ResponseParsingError as e:
|
||||
# Print out raw response from models for developers to debug
|
||||
response_msg = Msg(self.name, e.raw_response, "assistant")
|
||||
self.speak(response_msg)
|
||||
# Re-correct by model itself
|
||||
error_msg = Msg("system", str(e), "system")
|
||||
self.speak(error_msg)
|
||||
self.memory.add([response_msg, error_msg])
|
||||
except Exception as e:
|
||||
self.speak(f"Error: {e}".center(70, "#"))
|
||||
self.speak(f"Retrying".center(70, "#"))
|
||||
continue
|
||||
|
||||
return Msg(self.name, "Error: Max iterations reached", "assistant")
|
||||
|
||||
@@ -1,235 +1,329 @@
|
||||
import sys
|
||||
import os
|
||||
current_directory = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.append(current_directory)
|
||||
|
||||
import agentscope
|
||||
from agentscope.message import Msg
|
||||
import os
|
||||
import asyncio
|
||||
import threading
|
||||
import json
|
||||
|
||||
from agent.flex_service_toolkit import *
|
||||
from AlgoriAgent.projects.algoriAgent.agent.algori_agent import *
|
||||
|
||||
from agentscope.service import (
|
||||
ServiceToolkit,
|
||||
ServiceResponse,
|
||||
ServiceExecStatus,
|
||||
)
|
||||
import configparser
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read('config.ini')
|
||||
openai_api_key = config['Global']['api_key']
|
||||
|
||||
|
||||
|
||||
OPENAI_CFG_DICT = {
|
||||
"config_name": "openai_cfg", # 此配置的名称,必须保证唯一
|
||||
"model_type": "openai_chat", # 模型类型
|
||||
"model_name": "gpt-4o-mini", # 模型名称
|
||||
#"model_name": "gpt-4", # 模型名称
|
||||
#"model_name": "llama3",
|
||||
|
||||
"api_key": openai_api_key, # OpenAI API key. 如果没有设置,将使用环境变量中的 OPENAI_API_KEY
|
||||
|
||||
"client_args": {
|
||||
"base_url": config['Global']['base_chat_url']
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
import uuid
|
||||
from AlgoriAgent.projects.algoriAgent.tools.judge_tools import judge
|
||||
EMPTY_CHAPTER_CHAIN = [ Chapter(1, CHAPTER_FOCUS, "本章是未打开某个具体章节时的默认章节。", "处于本章节时不会有任何章节跳转。请作为一名经验丰富的算法教师,回答用户的问题。") ]
|
||||
|
||||
def tool_name_to_tool(tool_name_list):
|
||||
tools = []
|
||||
for tool_name in tool_name_list:
|
||||
if tool_name == "":
|
||||
continue
|
||||
if tool_name == "judge":
|
||||
tools.append(judge)
|
||||
|
||||
return tools
|
||||
|
||||
class AgentManager:
|
||||
def __init__(self):
|
||||
|
||||
agentscope.init(model_configs=[OPENAI_CFG_DICT])#, studio_url="http://0.0.0.0:5000")
|
||||
self.agents = {}
|
||||
|
||||
def new_agent(self, markdown:str, markdown_prompt:str, score_prompt:str, id = None):
|
||||
'''
|
||||
markdown: 教案的markdown文件内容
|
||||
markdown_prompt: 教案的prompt的markdown文件内容
|
||||
score_prompt: 评分的prompt的markdown文件内容
|
||||
根据3个教案的prompt,生成一个agent,返回agent的id与agent
|
||||
'''
|
||||
markdown_list = markdown.split("\n")
|
||||
markdown_prompt_list = markdown_prompt.split("\n")
|
||||
score_prompt_list = score_prompt.split("\n")
|
||||
# 获取 H1 标题
|
||||
title = ""
|
||||
for line in markdown_list:
|
||||
if line.startswith("# "):
|
||||
title = line[2:]
|
||||
break
|
||||
|
||||
# 对于 H3 标题 构造每一个 Chapter
|
||||
# 首先找到所有的 H3 标题
|
||||
chapter_dict = {}
|
||||
chapter_sequence = []
|
||||
for line in markdown_list:
|
||||
if line.startswith("### "):
|
||||
chapter_name = line[4:]
|
||||
chapter_dict[chapter_name] = {}
|
||||
chapter_sequence.append(chapter_name)
|
||||
# 将 H3 标题 和 其对应的内容 构造成一个 Chapter
|
||||
|
||||
h3_name = ""
|
||||
content = ""
|
||||
for i in range(len(markdown_list)):
|
||||
if markdown_list[i].startswith("### "):
|
||||
if(h3_name != ""):
|
||||
chapter_dict[h3_name]["markdown"] = content
|
||||
h3_name = markdown_list[i][4:]
|
||||
content = ""
|
||||
continue
|
||||
if h3_name != "":
|
||||
content += markdown_list[i]+"\n"
|
||||
if(h3_name != ""):
|
||||
chapter_dict[h3_name]["markdown"] = content
|
||||
|
||||
|
||||
h3_name = ""
|
||||
content = ""
|
||||
require_tools = []
|
||||
for i in range(len(markdown_prompt_list)):
|
||||
if markdown_prompt_list[i].startswith("### "):
|
||||
if(h3_name != ""):
|
||||
chapter_dict[h3_name]["markdown_prompt"] = content
|
||||
chapter_dict[h3_name]["require_tools"] = tool_name_to_tool(require_tools)
|
||||
h3_name = markdown_prompt_list[i][4:]
|
||||
content = ""
|
||||
continue
|
||||
|
||||
if h3_name != "":
|
||||
if markdown_prompt_list[i].startswith("_require_tools"):
|
||||
require_tools.append(markdown_prompt_list[i].split("=")[1].strip())
|
||||
continue
|
||||
content += markdown_prompt_list[i]+"\n"
|
||||
if(h3_name != ""):
|
||||
chapter_dict[h3_name]["markdown_prompt"] = content
|
||||
chapter_dict[h3_name]["require_tools"] = tool_name_to_tool(require_tools)
|
||||
|
||||
|
||||
h3_name = ""
|
||||
content = ""
|
||||
for i in range(len(score_prompt_list)):
|
||||
if score_prompt_list[i].startswith("### "):
|
||||
if(h3_name != ""):
|
||||
chapter_dict[h3_name]["score_prompt"] = content
|
||||
h3_name = score_prompt_list[i][4:]
|
||||
content = ""
|
||||
continue
|
||||
|
||||
if h3_name != "":
|
||||
content += score_prompt_list[i]+"\n"
|
||||
if(h3_name != ""):
|
||||
chapter_dict[h3_name]["score_prompt"] = content
|
||||
|
||||
|
||||
chapter_chain = []
|
||||
No = 1
|
||||
print (chapter_dict)
|
||||
for chapter_name in chapter_sequence:
|
||||
chapter_chain.append(Chapter(No, CHAPTER_LATTER, title, chapter_dict[chapter_name]["markdown"], chapter_dict[chapter_name]["markdown_prompt"], chapter_dict[chapter_name]["score_prompt"],chapter_dict[chapter_name]["require_tools"]))
|
||||
No+=1
|
||||
chapter_chain[0].Focus()
|
||||
|
||||
|
||||
# Prepare the tools for the agent
|
||||
service_toolkit = FlexServiceToolkit()
|
||||
# for tool_function in unity_function_list:
|
||||
# service_toolkit.add(tool_function)
|
||||
agent = ChapterChainAgent(
|
||||
name="assistant",
|
||||
model_config_name="openai_cfg",
|
||||
verbose=True,
|
||||
service_toolkit=service_toolkit,
|
||||
max_iters=5,
|
||||
chapter_chain=chapter_chain
|
||||
)
|
||||
self.agents[id] = agent
|
||||
return id, agent
|
||||
|
||||
|
||||
|
||||
def new_agent_with_chain(self, chapter_chain = None, id = None):
|
||||
'''
|
||||
|
||||
'''
|
||||
if chapter_chain is None:
|
||||
chapter_chain = EMPTY_CHAPTER_CHAIN
|
||||
|
||||
# Prepare the tools for the agent
|
||||
service_toolkit = FlexServiceToolkit()
|
||||
# for tool_function in unity_function_list:
|
||||
# service_toolkit.add(tool_function)
|
||||
agent = ChapterChainAgent(
|
||||
name="assistant",
|
||||
model_config_name="openai_cfg",
|
||||
verbose=True,
|
||||
service_toolkit=service_toolkit,
|
||||
max_iters=5,
|
||||
chapter_chain=EMPTY_CHAPTER_CHAIN
|
||||
)
|
||||
if id is None: id = uuid.uuid4()
|
||||
self.agents[id] = agent
|
||||
return id, agent
|
||||
|
||||
|
||||
def get_agent(self, id=None):
|
||||
'''
|
||||
如果在get agent之前没有new agent,并用id进行访问,就返回一个章节链为空的agent
|
||||
'''
|
||||
if id:
|
||||
if id in self.agents:
|
||||
return self.agents[id]
|
||||
self.agents[id] = self.new_agent(id)[1]
|
||||
else:
|
||||
id = str(uuid.uuid4())
|
||||
self.agents[id] = self.new_agent()[1]
|
||||
return id, self.agents[id]
|
||||
|
||||
|
||||
def invoke(self,id, query, user_backboard):
|
||||
msg = Msg("user", query, role="user")
|
||||
return self.agents[id](msg, user_backboard = user_backboard)
|
||||
|
||||
|
||||
import time
|
||||
if __name__ == '__main__':
|
||||
# tool_demo = ToolDemo("Lava")
|
||||
# response = tool_demo.invoke("I want such a Gurouce, when use it, it will be thrown and fly towards the mouse position for a short time, and stop. And will damage Enemy who step on it. I call it Lava Gurouce.")
|
||||
# print(response)
|
||||
# Start the WebSocket server in a separate thread
|
||||
manager = AgentManager()
|
||||
id, agent = manager.new_agent()
|
||||
|
||||
# Main thread logic
|
||||
try:
|
||||
# Your code that might be interrupted
|
||||
while True:
|
||||
input_data = input("用户:")
|
||||
print(manager.invoke(id, input_data))
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("Process interrupted by user.")
|
||||
# You can add any cleanup code here if needed
|
||||
finally:
|
||||
print("Exiting program.")
|
||||
# Code to run before the program exits
|
||||
import sys
|
||||
import os
|
||||
current_directory = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.append(current_directory)
|
||||
from flask_socketio import SocketIO, join_room, emit, Namespace
|
||||
import agentscope
|
||||
from agentscope.message import Msg
|
||||
import os
|
||||
import asyncio
|
||||
import threading
|
||||
import json
|
||||
|
||||
from agent.flex_service_toolkit import *
|
||||
from AlgoriAgent.projects.algoriAgent.agent.algori_agent import *
|
||||
|
||||
from agentscope.service import (
|
||||
ServiceToolkit,
|
||||
ServiceResponse,
|
||||
ServiceExecStatus,
|
||||
)
|
||||
import configparser
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
config.read('config.ini')
|
||||
openai_api_key = config['Global']['api_key']
|
||||
|
||||
|
||||
|
||||
OPENAI_CFG_DICT = {
|
||||
"config_name": "openai_cfg", # 此配置的名称,必须保证唯一
|
||||
"model_type": "openai_chat", # 模型类型
|
||||
"model_name": "gpt-4o-mini", # 模型名称
|
||||
#"model_name": "gpt-4", # 模型名称
|
||||
#"model_name": "llama3",
|
||||
"api_key": openai_api_key, # OpenAI API key. 如果没有设置,将使用环境变量中的 OPENAI_API_KEY
|
||||
|
||||
"client_args": {
|
||||
"base_url": config['Global']['base_chat_url']
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
import uuid
|
||||
from AlgoriAgent.projects.algoriAgent.tools.judge_tools import judge
|
||||
EMPTY_CHAPTER_CHAIN = [ Chapter(1, CHAPTER_FOCUS, "本章是未打开某个具体章节时的默认章节。", "处于本章节时不会有任何章节跳转。请作为一名经验丰富的算法教师,回答用户的问题。") ]
|
||||
|
||||
def tool_name_to_tool(tool_name_list):
|
||||
tools = []
|
||||
for tool_name in tool_name_list:
|
||||
if tool_name == "":
|
||||
continue
|
||||
if tool_name == "judge":
|
||||
tools.append(judge)
|
||||
|
||||
return tools
|
||||
|
||||
def tool_name_to_tool_with_args(tool_name_list, tool_args_list) -> list[tuple[Callable, dict]]:
|
||||
tools = []
|
||||
for tool_name, tool_args in zip(tool_name_list, tool_args_list):
|
||||
if tool_name == "":
|
||||
continue
|
||||
if tool_name == "judge":
|
||||
tools.append((judge, {"course_id": tool_args[0], "lesson_id": tool_args[1], "name": tool_args[2]}))
|
||||
|
||||
return tools
|
||||
class AgentManager:
|
||||
def __init__(self,max_iter = 5, app=None, socketio=None):
|
||||
|
||||
agentscope.init(model_configs=[OPENAI_CFG_DICT])#, studio_url="http://0.0.0.0:5000")
|
||||
self.agents = {}
|
||||
self.max_iter = max_iter
|
||||
self.agent_to_id = {}
|
||||
self.app = app
|
||||
self.socketio = socketio
|
||||
def new_agent(self, course_id, lesson_id, markdown:str, markdown_prompt:str, score_prompt:str, id = "Defult Assistant", root_path="."):
|
||||
'''
|
||||
markdown: 教案的markdown文件内容
|
||||
markdown_prompt: 教案的prompt的markdown文件内容
|
||||
score_prompt: 评分的prompt的markdown文件内容
|
||||
根据3个教案的prompt,生成一个agent,返回agent的id与agent
|
||||
'''
|
||||
markdown_list = markdown.split("\n")
|
||||
markdown_prompt_list = markdown_prompt.split("\n")
|
||||
score_prompt_list = score_prompt.split("\n")
|
||||
# 获取 H1 标题
|
||||
title = ""
|
||||
for line in markdown_list:
|
||||
if line.startswith("# "):
|
||||
title = line[2:]
|
||||
break
|
||||
|
||||
# 对于 H3 标题 构造每一个 Chapter
|
||||
# 首先找到所有的 H3 标题
|
||||
chapter_dict = {}
|
||||
chapter_sequence = []
|
||||
for line in markdown_list:
|
||||
if line.startswith("### "):
|
||||
chapter_name = line[4:]
|
||||
chapter_dict[chapter_name] = {}
|
||||
chapter_sequence.append(chapter_name)
|
||||
# 将 H3 标题 和 其对应的内容 构造成一个 Chapter
|
||||
|
||||
h3_name = ""
|
||||
content = ""
|
||||
for i in range(len(markdown_list)):
|
||||
if markdown_list[i].startswith("### "):
|
||||
if(h3_name != ""):
|
||||
chapter_dict[h3_name]["markdown"] = content
|
||||
h3_name = markdown_list[i][4:]
|
||||
content = ""
|
||||
continue
|
||||
if h3_name != "":
|
||||
content += markdown_list[i]+"\n"
|
||||
if(h3_name != ""):
|
||||
chapter_dict[h3_name]["markdown"] = content
|
||||
|
||||
|
||||
h3_name = ""
|
||||
content = ""
|
||||
require_tools = []
|
||||
require_tools_args = []
|
||||
for i in range(len(markdown_prompt_list)):
|
||||
if markdown_prompt_list[i].startswith("### "):
|
||||
if(h3_name != ""):
|
||||
chapter_dict[h3_name]["markdown_prompt"] = content
|
||||
chapter_dict[h3_name]["require_tools"] = tool_name_to_tool_with_args(require_tools, require_tools_args)
|
||||
h3_name = markdown_prompt_list[i][4:]
|
||||
content = ""
|
||||
require_tools=[]
|
||||
require_tools_args = []
|
||||
continue
|
||||
|
||||
if h3_name != "":
|
||||
if markdown_prompt_list[i].startswith("_require_tools"):
|
||||
require_tools.append(markdown_prompt_list[i].split("=")[1].strip().split(",")[0])
|
||||
require_tools_args.append((markdown_prompt_list[i].split("=")[1].strip().split(",")[1:]))
|
||||
continue
|
||||
content += markdown_prompt_list[i]+"\n"
|
||||
if(h3_name != ""):
|
||||
chapter_dict[h3_name]["markdown_prompt"] = content
|
||||
chapter_dict[h3_name]["require_tools"] = tool_name_to_tool_with_args(require_tools, require_tools_args)
|
||||
|
||||
|
||||
h3_name = ""
|
||||
content = ""
|
||||
for i in range(len(score_prompt_list)):
|
||||
if score_prompt_list[i].startswith("### "):
|
||||
if(h3_name != ""):
|
||||
chapter_dict[h3_name]["score_prompt"] = content
|
||||
h3_name = score_prompt_list[i][4:]
|
||||
content = ""
|
||||
continue
|
||||
|
||||
if h3_name != "":
|
||||
content += score_prompt_list[i]+"\n"
|
||||
if(h3_name != ""):
|
||||
chapter_dict[h3_name]["score_prompt"] = content
|
||||
|
||||
|
||||
chapter_chain = []
|
||||
No = 1
|
||||
print (chapter_dict)
|
||||
for chapter_name in chapter_sequence:
|
||||
chapter_chain.append(Chapter(course_id, lesson_id, No, CHAPTER_LATTER, chapter_name, chapter_dict[chapter_name]["markdown"], chapter_dict[chapter_name]["markdown_prompt"], chapter_dict[chapter_name]["score_prompt"],chapter_dict[chapter_name]["require_tools"]))
|
||||
No+=1
|
||||
chapter_chain[0].Focus()
|
||||
|
||||
|
||||
# Prepare the tools for the agent
|
||||
service_toolkit = FlexServiceToolkit()
|
||||
# for tool_function in unity_function_list:
|
||||
# service_toolkit.add(tool_function)
|
||||
agent = ChapterChainAgent(
|
||||
name=id,
|
||||
model_config_name="openai_cfg",
|
||||
verbose=True,
|
||||
service_toolkit=service_toolkit,
|
||||
max_iters=5,
|
||||
chapter_chain=chapter_chain,
|
||||
root_path = root_path,
|
||||
)
|
||||
self.agents[id] = agent
|
||||
self.agent_to_id[agent] = id
|
||||
agent.agent_manager = self
|
||||
return id, agent
|
||||
|
||||
def message_pass(self, agent, messagetype, message):
|
||||
id = self.agent_to_id[agent]
|
||||
print("message_pass", id, messagetype, message)
|
||||
with self.app.app_context():
|
||||
try:
|
||||
self.socketio.emit(messagetype, message, room=id, namespace='/agent')
|
||||
except Exception as e:
|
||||
print("message_pass",e)
|
||||
|
||||
def system_message(self, message):
|
||||
with self.app.app_context():
|
||||
try:
|
||||
self.socketio.emit('system_message', message, room=id, namespace='/agent')
|
||||
except Exception as e:
|
||||
print("ERROR: system_message",e)
|
||||
|
||||
|
||||
def save_chapter_memory(self, agent,course_id, lesson_id, subchapter_title, mem_list, score, is_rebuttal):
|
||||
id = self.agent_to_id[agent]
|
||||
self.app.my_function.save_chapter_memory(id, course_id, lesson_id, subchapter_title, mem_list, score, is_rebuttal)
|
||||
|
||||
|
||||
def new_agent_with_chain(self, chapter_chain = None, id = None):
|
||||
if chapter_chain is None:
|
||||
chapter_chain = EMPTY_CHAPTER_CHAIN
|
||||
|
||||
# Prepare the tools for the agent
|
||||
service_toolkit = FlexServiceToolkit()
|
||||
# for tool_function in unity_function_list:
|
||||
# service_toolkit.add(tool_function)
|
||||
agent = ChapterChainAgent(
|
||||
name="assistant",
|
||||
model_config_name="openai_cfg",
|
||||
verbose=True,
|
||||
service_toolkit=service_toolkit,
|
||||
max_iters=5,
|
||||
chapter_chain=EMPTY_CHAPTER_CHAIN
|
||||
)
|
||||
if id is None: id = uuid.uuid4()
|
||||
self.agents[id] = agent
|
||||
return id, agent
|
||||
|
||||
|
||||
def get_agent(self, id=None):
|
||||
'''
|
||||
如果在get agent之前没有new agent,并用id进行访问,就返回一个章节链为空的agent
|
||||
'''
|
||||
if id:
|
||||
if id in self.agents:
|
||||
return self.agents[id]
|
||||
self.agents[id] = self.new_agent(id)[1]
|
||||
else:
|
||||
id = str(uuid.uuid4())
|
||||
self.agents[id] = self.new_agent()[1]
|
||||
return id, self.agents[id]
|
||||
|
||||
|
||||
def invoke(self,id, query, user_backboard, reset=False):
|
||||
msg = Msg("user", query, role="user")
|
||||
agent = self.agents[id]
|
||||
res = agent(msg, user_backboard=user_backboard)
|
||||
return res
|
||||
# 暂时取消生成器的写法
|
||||
# 假设 agent 是一个生成器
|
||||
# if reset or not hasattr(agent, '_generator'):
|
||||
# agent._generator = agent(msg, user_backboard=user_backboard)
|
||||
|
||||
# try:
|
||||
# response = next(agent._generator)
|
||||
# yield response
|
||||
# except StopIteration:
|
||||
# return
|
||||
|
||||
def function_call(self, id, arg_function):
|
||||
agent = self.agents[id]
|
||||
return agent.function_call(arg_function)
|
||||
|
||||
def change_language(self, id, language):
|
||||
agent = self.agents[id]
|
||||
agent.change_language(language)
|
||||
|
||||
def sample_judge(self, id, bb):
|
||||
agent = self.agents[id]
|
||||
|
||||
with self.app.app_context():
|
||||
try:
|
||||
print(bb.get_active_file_reletive_path())
|
||||
assert bb is not None and bb.active_file_path != "" , "no path specified"
|
||||
if bb.get_active_file_reletive_path().endswith(".py"):
|
||||
self.socketio.emit('terminal', {'data': f"python {bb.get_active_file_reletive_path()}"}, room=id, namespace='/vscode')
|
||||
self.socketio.emit('system_message', "代码试运行尚在建设,推荐直接通过命令行执行!", room=id, namespace='/agent')
|
||||
else:
|
||||
self.socketio.emit('system_message', "代码试运行尚仅支持python文件", room=id, namespace='/agent')
|
||||
except Exception as e:
|
||||
print(e)
|
||||
if (str(e) == "no path specified"):
|
||||
self.socketio.emit("system_message", "未加载IDE文件同步,请尝试重新打开IDE文件或刷新页面,并确保插件已连接", room=id, namespace='/agent')
|
||||
|
||||
def judge(self, id, bb):
|
||||
agent = self.agents[id]
|
||||
with self.app.app_context():
|
||||
try:
|
||||
if (agent.chapter_chain[agent.chapter_chain_now].append_tools is not None and len(agent.chapter_chain[agent.chapter_chain_now].append_tools)):
|
||||
for tool, tool_kwargs in agent.chapter_chain[agent.chapter_chain_now].append_tools:
|
||||
if tool.__name__ == "judge":
|
||||
print(bb.get_active_file_reletive_path())
|
||||
assert bb is not None and bb.active_file_path != "" , "no path specified"
|
||||
if bb.get_active_file_reletive_path().endswith(".py"):
|
||||
# self.socketio.emit('terminal', {'data': f"python {bb.get_active_file_reletive_path()}"}, room=id, namespace='/vscode')
|
||||
self.socketio.emit('system_message', "代码评测中,请稍后", room=id, namespace='/agent')
|
||||
agent.function_call({'name':'judge','arguments':{'filepath': bb.get_active_file_reletive_path()}})
|
||||
else:
|
||||
self.socketio.emit('system_message', "代码评测尚仅支持python文件", room=id, namespace='/agent')
|
||||
|
||||
else:
|
||||
with self.app.app_context():
|
||||
self.socketio.emit("system_message", "本章学习无需评测", room=id, namespace='/agent')
|
||||
else:
|
||||
with self.app.app_context():
|
||||
self.socketio.emit("system_message", "本章学习无需评测", room=id, namespace='/agent')
|
||||
except Exception as e:
|
||||
if (str(e) == "no path specified"):
|
||||
self.socketio.emit("system_message", "未加载IDE文件同步,请尝试重新打开IDE文件或刷新页面,并确保插件已连接", room=id, namespace='/agent')
|
||||
|
||||
|
||||
import time
|
||||
if __name__ == '__main__':
|
||||
manager = AgentManager()
|
||||
id, agent = manager.new_agent()
|
||||
|
||||
# Main thread logic
|
||||
try:
|
||||
# Your code that might be interrupted
|
||||
while True:
|
||||
input_data = input("用户:")
|
||||
print(manager.invoke(id, input_data))
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("Process interrupted by user.")
|
||||
# You can add any cleanup code here if needed
|
||||
finally:
|
||||
print("Exiting program.")
|
||||
# Code to run before the program exits
|
||||
|
||||
Binary file not shown.
Binary file not shown.
54
AlgoriAgent/projects/algoriAgent/tools/file_tools.py
Normal file
54
AlgoriAgent/projects/algoriAgent/tools/file_tools.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from agentscope.service.service_toolkit import ServiceFunction
|
||||
from agentscope.service import (
|
||||
ServiceToolkit,
|
||||
ServiceResponse,
|
||||
ServiceExecStatus,
|
||||
)
|
||||
import os
|
||||
def read_file(filepath:str, root_path:str):
|
||||
"""Read the file and return the content. Remember use 'judge' function if you want to judge file, instead of this function.
|
||||
|
||||
Args:
|
||||
filepath (`str`): The path to the file.
|
||||
root_path (`str`): The root path of now student's workspace.
|
||||
|
||||
Returns:
|
||||
content (`str`): The content of the file.
|
||||
"""
|
||||
# 从books/code_tests/name/中获取所有.in文件
|
||||
|
||||
filepath = os.path.join('..', root_path, filepath)
|
||||
try:
|
||||
with open(filepath, 'r') as f:
|
||||
content = f.read()
|
||||
except Exception as e:
|
||||
status = ServiceExecStatus.ERROR
|
||||
content = str(e)
|
||||
return ServiceResponse(status, (content))
|
||||
|
||||
status = ServiceExecStatus.SUCCESS
|
||||
return ServiceResponse(status, ('```\n'+content+'```\n'))
|
||||
|
||||
|
||||
def write_file(filepath:str, content:str, root_path:str):
|
||||
"""Write content to the file.
|
||||
|
||||
Args:
|
||||
filepath (`str`): The path to the file.
|
||||
content (`str`): The content to be written to the file.
|
||||
root_path (`str`): The root path of now student's workspace.
|
||||
|
||||
Returns:
|
||||
None.
|
||||
"""
|
||||
filepath = os.path.join('..', root_path, filepath)
|
||||
try:
|
||||
with open(filepath, 'w') as f:
|
||||
f.write(content)
|
||||
except Exception as e:
|
||||
status = ServiceExecStatus.ERROR
|
||||
return ServiceResponse(status, None)
|
||||
status = ServiceExecStatus.SUCCESS
|
||||
return ServiceResponse(status, None)
|
||||
|
||||
file_tools = [read_file, write_file]
|
||||
@@ -1,64 +1,78 @@
|
||||
from agentscope.service.service_toolkit import ServiceFunction
|
||||
from agentscope.service import (
|
||||
ServiceToolkit,
|
||||
ServiceResponse,
|
||||
ServiceExecStatus,
|
||||
)
|
||||
import os
|
||||
def judge(filepath:str, name: str):
|
||||
"""Call this method to judge the student's solution after they have completed the problem.
|
||||
|
||||
Args:
|
||||
filepath (`str`): The path to the file containing the student's solution.
|
||||
name (`str`): The name of the problem.
|
||||
|
||||
Returns:
|
||||
Report `tuple(int,str)`: The report of the student's solution.
|
||||
"""
|
||||
# 从books/code_tests/name/中获取所有.in文件
|
||||
|
||||
directory = 'books/code_tests/'+name
|
||||
# 如果目录不存在,报错
|
||||
if not os.path.exists(directory):
|
||||
status = ServiceExecStatus.FAILED
|
||||
return ServiceResponse(status, f"The name {name} is not found.")
|
||||
files = os.listdir(directory)
|
||||
in_files = [file for file in files if file.endswith('.in')]
|
||||
save_dir = os.path.dirname(filepath)
|
||||
Report = ""
|
||||
passed_num=0
|
||||
failed_num=0
|
||||
for file in in_files:
|
||||
os.remove(os.path.join(save_dir, f"_{name}.out"))
|
||||
cmd = "cat " + os.path.join(directory, file) + " | " + "python " + filepath +" > " + os.path.join(save_dir, f"_{name}.out")
|
||||
os.system(cmd)
|
||||
# 比较结果
|
||||
re = ""
|
||||
if compare_file(os.path.join(save_dir, f"_{name}.out"), os.path.join(directory, file.replace(".in", ".out"))):
|
||||
re = "Passed {file}"
|
||||
passed_num += 1
|
||||
else:
|
||||
re = "Failed {file}"
|
||||
failed_num += 1
|
||||
Report = Report + re + "\n"
|
||||
os.remove(os.path.join(save_dir, f"_{name}.out"))
|
||||
score = int (100 * passed_num / (passed_num + failed_num))
|
||||
|
||||
|
||||
|
||||
status = ServiceExecStatus.SUCCESS
|
||||
return ServiceResponse(status, (Report, score))
|
||||
|
||||
|
||||
def compare_file(path1:str, path2:str):
|
||||
"""
|
||||
Compare two files and return true if they are the same.
|
||||
"""
|
||||
with open(path1, 'r') as f1, open(path2, 'r') as f2:
|
||||
# 逐行比较
|
||||
for line1, line2 in zip(f1, f2):
|
||||
if line1.strip() != line2.strip():
|
||||
return False
|
||||
return True
|
||||
|
||||
from agentscope.service.service_toolkit import ServiceFunction
|
||||
from agentscope.service import (
|
||||
ServiceToolkit,
|
||||
ServiceResponse,
|
||||
ServiceExecStatus,
|
||||
)
|
||||
import os
|
||||
def judge(filepath:str, name: str, course_id: str, lesson_id: str, root_path:str):
|
||||
"""Call this method to judge the student's solution after they have completed the problem.
|
||||
|
||||
Args:
|
||||
filepath (`str`): The path to the file containing the student's solution.
|
||||
name (`str`): The name of the problem.
|
||||
course_id (`str`): The id of the course.
|
||||
lesson_id (`str`): The id of the lesson.
|
||||
root_path (`str`): The root path of the user's workspace project.
|
||||
|
||||
Returns:
|
||||
Report `tuple(int,str)`: The report of the student's solution.
|
||||
"""
|
||||
# 从books/code_tests/name/中获取所有.in文件
|
||||
|
||||
directory = 'books/code_tests/'+course_id+'/'+name
|
||||
# 如果目录不存在,报错
|
||||
if not os.path.exists(directory):
|
||||
status = ServiceExecStatus.FAILED
|
||||
return ServiceResponse(status, f"The name {name} is not found.")
|
||||
files = os.listdir(directory)
|
||||
in_files = [file for file in files if file.endswith('.in')]
|
||||
save_dir = root_path
|
||||
Report = ""
|
||||
passed_num=0
|
||||
failed_num=0
|
||||
erroroutput = ""
|
||||
exceptoutput=""
|
||||
for file in in_files:
|
||||
file_path = os.path.join(save_dir, f"_{name}.out")
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
with open(file_path, 'w') as ff:
|
||||
ff.write("")
|
||||
|
||||
cmd = "cat " + os.path.join(directory, file) + " | " + "python " + os.path.join(root_path, filepath) +" > " + os.path.join(save_dir, f"_{name}.out")
|
||||
os.system(cmd)
|
||||
# 比较结果
|
||||
re = ""
|
||||
if compare_file(os.path.join(save_dir, f"_{name}.out"), os.path.join(directory, file.replace(".in", ".out"))):
|
||||
re = f"Passed {file}"
|
||||
passed_num += 1
|
||||
else:
|
||||
re = f"Failed {file}"
|
||||
failed_num += 1
|
||||
with open(os.path.join(directory, file.replace(".in", ".out")),'r') as f: exceptoutput = f.read()
|
||||
with open(os.path.join(save_dir, f"_{name}.out"),'r') as f: erroroutput = f.read()
|
||||
Report = Report + re + "\n"
|
||||
os.remove(os.path.join(save_dir, f"_{name}.out"))
|
||||
score = int (100 * passed_num / (passed_num + failed_num))
|
||||
|
||||
|
||||
|
||||
status = ServiceExecStatus.SUCCESS
|
||||
return ServiceResponse(status, (score, f"评测得分为 {score}, 在 {passed_num + failed_num} 个测试用例中通过了 {passed_num}个。最后一个错误样例期望输出:'{exceptoutput}',但你的输出:'{erroroutput}"))
|
||||
|
||||
|
||||
def compare_file(path1:str, path2:str):
|
||||
"""
|
||||
Compare two files and return true if they are the same.
|
||||
"""
|
||||
with open(path1, 'r') as f1, open(path2, 'r') as f2:
|
||||
# 逐行比较
|
||||
print('-------------------COMPARE-------------------------')
|
||||
for line1, line2 in zip(f1, f2):
|
||||
print(line1.strip(), "||",line2.strip())
|
||||
if line1.strip() != line2.strip():
|
||||
return False
|
||||
return True
|
||||
|
||||
judge_tools = [judge]
|
||||
Reference in New Issue
Block a user