提交版本

This commit is contained in:
CakeCN
2025-01-02 09:29:49 +08:00
parent eb67bcfb70
commit a1904afbc8
137 changed files with 1906 additions and 885 deletions

View File

@@ -19,11 +19,17 @@ from agentscope.service import (
ServiceExecStatus,
)
import json
from AlgoriAgent.projects.algoriAgent.agent.score_agent import ScoreAgent
from AlgoriAgent.projects.algoriAgent.agent.total_score_agent import TotalScoreAgent
import re
# 这个INSTRUCTION_PROMPT 交给免费Agent进行使用不包含评测与得分标准但是会在没有自己注释的大段代码或复制粘贴代码是通知学生进入一次理解性测试。
INSTRUCTION_PROMPT = """## Your Role:
You are a powerful AI agent to teach student computer algorithm, you are to company a student to learn algorithm or solve problems.
INSTRUCTION_PROMPT_EN = """## Your Role:
You need to help the student learn algorithms, verify the learning process, ensure that the student understands the current chapter's content, and then guide the student to the next chapter.
## What You Should Do:
0. You MUST follow the teaching instructions made by human teacher with several chapters, ONLY focus on one chapter at a time.
@@ -42,24 +48,78 @@ You are a powerful AI agent to teach student computer algorithm, you are to comp
1. The tool functions you can use.
2. The context, including the student's code, and teaching instructions.
""" # noqa
INSTRUCTION_PROMPT_CN = """## 你的角色:
你需要帮助学生学习算法,检验学习过程,确保学生理解当前章节的内容后,带领学生进入下一章
## 你需要做的:
0. 你必须根据老师提供的教学大纲,按照章节顺序,依次学习。
1. 学生可能会提出一些问题,你无需回答问题,而是根据上下文(比如学生自己的代码)来分析,并给出一步的解决方案。
2. 教学大纲中会指明每个章节的学习目标,你按照目标学习。
3. 系统会occasionally gather学生信息你需要分析学生学习记录调用必要的函数。
## 注意事项:
1. 确保使用工具函数时,提供的参数类型和值是正确的。
2. 不要太相信自己,例如,当前位置,当前时间等,你可以尝试使用工具函数获取信息。
3. 如果函数执行失败,你需要分析错误并尝试解决。
4. 确保学生提出的问题或想法是否与当前章节相关,如果不相关,你应答并提醒学生关注当前章节。
## 资源:
1. 你可以使用的工具函数。
2. 上下文,包括学生的代码,和教学大纲。
"""
LANGUAGE_HINT_EN = "Use English to reply"
LANGUAGE_HINT_CN = "使用中文回复"
CHAPTER_FINISH = 0
CHAPTER_FOCUS = 1
CHAPTER_LATTER = 2
CHAPTER_FAILED = 3
class Chapter():
def __init__(self, No = 1, focus = 2,title="", chapter = "", chapter_prompt = "", score_prompt = "", append_tools : Callable[..., Any] = None) -> None:
def __init__(self, course_id, lesson_id, No = 1, focus = 2,title="", chapter = "", chapter_prompt = "",
score_prompt = "", append_tools : list[Callable[..., Any], dict] = None) -> None:
'''
No : 序号
focus : 0: Finished, 1: Focus, 2: Latter, 3: Failed
title : 子章节标题
chapter : 教案子章节内容
chapter_prompt : 教案的提示
score_prompt : 评测标准
append_tools : 追加工具函数
'''
self.No = No
self.focus = focus
self.chapter = chapter
self.chapter_prompt = chapter_prompt
self.score_prompt = score_prompt
self.append_tools = append_tools
self.memory = None
self.title =title
self.course_id = course_id
self.lesson_id = lesson_id
def GetChapter(self):
if self.focus == CHAPTER_FINISH: f = "(Finished Chapter)"
elif self.focus == CHAPTER_FOCUS: f = "(Your Now Chapter)"
elif self.focus == CHAPTER_LATTER: f = "(Ignore for Latter Chapter)"
elif self.focus == CHAPTER_FAILED: f = "(Failed Chapter)"
return f"{f} Chapter {self.No}: {self.chapter}"
# des = f"{f} Chapter {self.No}: {self.chapter if self.focus else 'Hidden for further study.'}"
des = f"{f} Chapter {self.No}: "
if self.focus == CHAPTER_FINISH or self.focus == CHAPTER_FAILED: des += 'Hidden due to finished.'
if self.focus == CHAPTER_LATTER: des += 'Hidden for further study.'
if self.focus == CHAPTER_FOCUS:
des+=self.chapter
des+='\n'
des+='Here are some concrete instructions:\n'
des+=self.chapter_prompt+'\n'
return des
def Finished(self, successful: bool = True):
if successful: self.focus = 0
@@ -93,18 +153,21 @@ def next_chapter(name: str):
name (`str`): The name of the agent to go to next chapter.
Returns:
None
message (`str`): The result of the operation.
"""
res=""
try:
ChapterChainAgent.Instance[name].next_chapter()
except:
print(ChapterChainAgent.Instance)
print(name in ChapterChainAgent.Instance)
res = ChapterChainAgent.Instance[name].next_chapter()
except Exception as e:
status = ServiceExecStatus.ERROR
return ServiceResponse(status, "Failed to go to next chapter. name '"+name+"' not found in ChapterChainAgent.Instance")
return ServiceResponse(status, str(e))
status = ServiceExecStatus.SUCCESS
return ServiceResponse(status, None)
return ServiceResponse(status, res)
from AlgoriAgent.projects.algoriAgent.tools.file_tools import file_tools
class ChapterChainAgent(AgentBase):
"""An agent class to preform chapter chain algorithm.
@@ -122,6 +185,7 @@ class ChapterChainAgent(AgentBase):
verbose: bool = True,
chapter_chain: Sequence[Chapter] = None,
stop_when_one_CHAPTER_failed: bool = True,
root_path: str = ".",
**kwargs: Any,
) -> None:
"""
@@ -150,9 +214,10 @@ class ChapterChainAgent(AgentBase):
sys_prompt=sys_prompt,
model_config_name=model_config_name,
)
self.model_config_name = model_config_name
# TODO: To compatible with the old version, which will be deprecated
# soon
self.name=name
if "tools" in kwargs:
logger.warning(
"The argument `tools` will be deprecated soon. "
@@ -186,6 +251,8 @@ class ChapterChainAgent(AgentBase):
service_toolkit.add(record,name=name)
service_toolkit.add(next_chapter,name=name)
for tool in file_tools:
service_toolkit.add(tool, root_path=root_path)
self.service_toolkit = service_toolkit
self.service_toolkit.agent = self
@@ -200,7 +267,7 @@ class ChapterChainAgent(AgentBase):
# The brief intro of the role and target
sys_prompt.format(name=self.name),
# The detailed instruction prompt for the agent
INSTRUCTION_PROMPT,
INSTRUCTION_PROMPT_CN,
],
)
@@ -221,7 +288,7 @@ class ChapterChainAgent(AgentBase):
# Only print the speak field when verbose is False
keys_to_content=True if self.verbose else "speak",
)
self.language_hint = LANGUAGE_HINT_CN
self.chapter_chain = chapter_chain
@@ -232,13 +299,16 @@ class ChapterChainAgent(AgentBase):
ChapterChainAgent.Instance[name] = self
self.agent_manager = None
self.root_path = root_path
def chapter_chain_to_memory(self):
mem = "##The Chapter Chain##\n"
for chapter in self.chapter_chain:
if (chapter.focus == CHAPTER_FOCUS or chapter.focus == CHAPTER_FINISH):
mem+=chapter.GetChapter()+"\n"
mem+="\n"
mem+= "Remember your now chapter is "+ self.chapter_chain[self.chapter_chain_now].GetChapter()+"\n"
# mem+= "Remember your now chapter is "+ self.chapter_chain[self.chapter_chain_now].GetChapter()+"\n"
return Msg("system", mem, role="system")
def _has_unfinished_chapter(self):
@@ -247,20 +317,45 @@ class ChapterChainAgent(AgentBase):
return True
return False
def next_chapter(self, successful: bool = True):
if self.chapter_chain[self.chapter_chain_now].append_tools is not None:
for callable_tools in self.chapter_chain[self.chapter_chain_now].append_tools:
if self.chapter_chain[self.chapter_chain_now].append_tools is not None or len(self.chapter_chain[self.chapter_chain_now].append_tools)==0:
for callable_tools, args in self.chapter_chain[self.chapter_chain_now].append_tools:
self.service_toolkit.Remove(callable_tools)
self.chapter_chain[self.chapter_chain_now].Finished(successful)
try:
score_agent = ScoreAgent(name=self.name, model_config_name=self.model_config_name, memory=self.chapter_memory,
chapter_score_prompt=self.chapter_chain[self.chapter_chain_now].score_prompt,
service_toolkit=self.service_toolkit, sys_prompt="", max_iters=self.max_iters, verbose=self.verbose)
res = score_agent.reply()
total_score_agent = TotalScoreAgent(name=self.name, model_config_name=self.model_config_name, input=res['content']['speak'],
service_toolkit=self.service_toolkit, sys_prompt="", max_iters=self.max_iters, verbose=self.verbose)
score = total_score_agent.reply()
except Exception as e:
print("=*="*50)
print(e)
self.agent_manager.message_pass(self, "chapter_score", json.dumps({'chapter_id':self.chapter_chain_now+1, 'data':res}))
self.agent_manager.save_chapter_memory(self,self.chapter_chain[self.chapter_chain_now].course_id, self.chapter_chain[self.chapter_chain_now].lesson_id,
self.chapter_chain[self.chapter_chain_now].title, self.chapter_memory.export(to_mem = True),
score, is_rebuttal=False)
self.chapter_memory = TemporaryMemory()
self.agent_manager.message_pass(self, "next_chapter","")
self.agent_manager.system_message("进入下一节")
for i in range(len(self.chapter_chain)):
if self.chapter_chain[i].focus == 2:
if self.chapter_chain[i].focus == CHAPTER_LATTER:
self.chapter_chain[i].Focus()
if self.chapter_chain[i].append_tools is not None:
for callable_tools in self.chapter_chain[i].append_tools:
self.service_toolkit.add(callable_tools)
if self.chapter_chain[i].append_tools is not None and len(self.chapter_chain[i].append_tools) > 0:
for callable_tools, args in self.chapter_chain[i].append_tools:
print("add tools:", callable_tools)
print("args:", args)
args['root_path'] = self.root_path
self.service_toolkit.add(callable_tools, **args)
self.chapter_chain_now = i
return
return "成功进入下一章"
# 找不到章节
return "学生完成了本课所有章节,已经没有下一章了!"
def add_chapters_after(self, CHAPTER_No, chapters: Sequence[Chapter]):
for i in range(len(self.chapter_chain)):
@@ -273,8 +368,7 @@ class ChapterChainAgent(AgentBase):
self.chapter_chain[j].No += len(chapters)
break
def reply(self, x: Optional[Union[Msg, Sequence[Msg]]] = None, user_backboard:str = "") -> Msg:
if self.chapter_memory.size() == 0:
if self.chapter_memory.size() <= 1:
self.chapter_chain[self.chapter_chain_now].memory = self.chapter_memory
for msg in self.memory.get_memory():
self.chapter_memory.add(msg)
@@ -283,7 +377,7 @@ class ChapterChainAgent(AgentBase):
self.chapter_memory.add(x)
for _ in range(1):
for _ in range(self.max_iters):
# Step 1: Thought
if self.verbose:
self.speak(f" ITER {_+1}, STEP 1: REASONING ".center(70, "#"))
@@ -304,31 +398,29 @@ class ChapterChainAgent(AgentBase):
)
hint_msg = Msg(
"system",
self.parser.format_instruction+"\n ####",
self.parser.format_instruction+"\n ####" + "!!"+ self.language_hint +"!!",
role="system",
echo=self.verbose,
)
prompt = self.model.format(self.chapter_memory.get_memory(),
backboard_hint_msg,
# The instruction prompt for tools
tools_hint_msg,
hint_msg)
print("*********************************************************************")
print(prompt)
if self.verbose:
self.speak(f"Prompt".center(70, "#"))
self.speak(str(self.chapter_memory.get_memory()[-1].content))
# print(prompt)
self.speak(str(prompt))
try:
if self.verbose:
self.speak(f"API Trigger".center(70, "#"))
res = self.model(
prompt,
parse_func=self.parser.parse,
max_retries=1,
max_retries=2,
######################
)
if self.verbose:
self.speak(f"Result Parsed".center(70, "#"))
self.speak(str(res.parsed))
@@ -354,6 +446,7 @@ class ChapterChainAgent(AgentBase):
self.speak(msg_returned)
return msg_returned
if self.verbose:
self.speak(f"Function".center(70, "#"))
self.speak(str(res.parsed["function"]))
@@ -382,27 +475,59 @@ class ChapterChainAgent(AgentBase):
self.chapter_memory.add([response_msg, error_msg])
# Skip acting step to re-correct the response
continue
# 2. Acting
def function_call(self, parsed_function) -> Msg:
if self.verbose:
self.speak(f" ITER {_+1}, STEP 2: ACTING ".center(70, "#"))
self.speak(f"ACTING ".center(70, "#"))
print(str(parsed_function))
# Parse, check and execute the tool functions in service toolkit
try:
execute_results = self.service_toolkit.parse_and_call_func(
res.parsed["function"],
parsed_function# res.parsed["function"],
)
# 在这里补充任务结束行动
if self.finish_now_chapter:
if self.finish_now_chapter: self.finish()
# Note: Observing the execution results and generate response
# are finished in the next reasoning step. We just put the
# execution results into memory, and wait for the next loop
# to generate response.
# Record execution results into memory as system message
msg_res = Msg("system", execute_results, "system")
self.speak(msg_res)
self.chapter_memory.add(msg_res)
pattern = r"\[RESULT\]: (.*)"
match = re.search(pattern, msg_res['content'])
result_content='正则匹配失败'
if match:
result_content = match.group(1)
res = self.reply(Msg(name='system', content="命令执行结果如上,请总结并引导学生进行下一步操作", role="system"))
self.agent_manager.system_message(parsed_function['name'] + "执行" + ("成功" if "[STATUS]: SUCCESS" in str(msg_res['content']) else "失败") + ",结果为:" + result_content)
self.agent_manager.message_pass(self, "message", res.content['speak'])
except FunctionCallError as e:
# Catch the function calling error that can be handled by
# the model
error_msg = Msg("system", str(e), "system")
self.speak(error_msg)
self.chapter_memory.add(error_msg)
except Exception as e:
# Catch the function calling error that can not be handled
error_msg = Msg("system", str(e), "system")
self.speak(error_msg)
self.chapter_memory.add(error_msg)
def finish(self):
self.finish_now_chapter = False
hint_msg = Msg(
"system",
"You have finished your own chapter."
"You have finished your now chapter."
"Now generate a reply by summarizing the current "
"situation. Remember this summary will be recorded in global memory. Make sure keep important information.",
role="system",
@@ -417,35 +542,10 @@ class ChapterChainAgent(AgentBase):
self.speak(res_msg)
self.next_chapter(successful=True)
self.success_own_chapter = True
break
# Note: Observing the execution results and generate response
# are finished in the next reasoning step. We just put the
# execution results into memory, and wait for the next loop
# to generate response.
# Record execution results into memory as system message
msg_res = Msg("system", execute_results, "system")
self.speak(msg_res)
self.chapter_memory.add(msg_res)
except FunctionCallError as e:
# Catch the function calling error that can be handled by
# the model
error_msg = Msg("system", str(e), "system")
self.speak(error_msg)
self.chapter_memory.add(error_msg)
continue
except Exception as e:
# Catch the function calling error that can not be handled
error_msg = Msg("system", str(e), "system")
self.speak(error_msg)
self.chapter_memory.add(error_msg)
continue
def change_language(self, language):
if(language == "zh"):self.language_hint = LANGUAGE_HINT_CN
if(language == "en"):self.language_hint = LANGUAGE_HINT_EN
def GetProcess(self):
process = []

View 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")

View 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")

View File

@@ -2,7 +2,7 @@ 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
@@ -32,7 +32,6 @@ OPENAI_CFG_DICT = {
"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": {
@@ -55,13 +54,25 @@ def tool_name_to_tool(tool_name_list):
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):
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 = {}
def new_agent(self, markdown:str, markdown_prompt:str, score_prompt:str, id = None):
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文件内容
@@ -107,23 +118,27 @@ class AgentManager:
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(require_tools)
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())
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(require_tools)
chapter_dict[h3_name]["require_tools"] = tool_name_to_tool_with_args(require_tools, require_tools_args)
h3_name = ""
@@ -146,7 +161,7 @@ class AgentManager:
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"]))
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()
@@ -156,22 +171,42 @@ class AgentManager:
# for tool_function in unity_function_list:
# service_toolkit.add(tool_function)
agent = ChapterChainAgent(
name="assistant",
name=id,
model_config_name="openai_cfg",
verbose=True,
service_toolkit=service_toolkit,
max_iters=5,
chapter_chain=chapter_chain
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
@@ -206,17 +241,76 @@ class AgentManager:
return id, self.agents[id]
def invoke(self,id, query, user_backboard):
def invoke(self,id, query, user_backboard, reset=False):
msg = Msg("user", query, role="user")
return self.agents[id](msg, user_backboard = user_backboard)
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__':
# 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()

View 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]

View File

@@ -5,41 +5,53 @@ from agentscope.service import (
ServiceExecStatus,
)
import os
def judge(filepath:str, name: str):
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/'+name
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 = os.path.dirname(filepath)
save_dir = root_path
Report = ""
passed_num=0
failed_num=0
erroroutput = ""
exceptoutput=""
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")
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 = "Passed {file}"
re = f"Passed {file}"
passed_num += 1
else:
re = "Failed {file}"
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))
@@ -47,7 +59,7 @@ def judge(filepath:str, name: str):
status = ServiceExecStatus.SUCCESS
return ServiceResponse(status, (Report, score))
return ServiceResponse(status, (score, f"评测得分为 {score}, 在 {passed_num + failed_num} 个测试用例中通过了 {passed_num}个。最后一个错误样例期望输出:'{exceptoutput}',但你的输出:'{erroroutput}"))
def compare_file(path1:str, path2:str):
@@ -56,7 +68,9 @@ def compare_file(path1:str, path2:str):
"""
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

Some files were not shown because too many files have changed in this diff Show More