这个框架是课程讲解的,但资料比较少,觉得框架比较小众,所以这里只分析代码,打算把更多的精力放在metagpt的学习上,毕竟还是要学教为主流的框架,这对后续维护升级都有帮助,当然感兴趣作为研究,可以研究下这个小框架。
代码目的是要生成一个一个教程编写智能体,其主要功能是输入教程主题,然后自动生成完整的教程内容,首先定义WriteDirectoryAction类,用于生成教程的目录,然后再定义生成教程的类,最后是执行层的代码。
python
Python复制
class WriteDirectoryAction(BaseAction):
"""
生成教程目录结构的动作类。
该类用于根据给定的主题和语言,生成教程的目录结构。目录结构以字典格式输出,包含主目录和子目录,每个目录标题都有实际意义。
Attributes:
action_name (str): 动作名称,固定为"WriteDirectory"。
action_desc (str): 动作描述,固定为"Generate tutorial directory structure"。
params_doc (dict): 参数文档,包含主题(topic)和语言(language)两个参数的类型和说明。
Methods:
__call__(**kwargs): 根据给定的主题和语言生成教程目录结构。
Example:
>>> action = WriteDirectoryAction()
>>> result = action(topic="Python编程", language="Chinese")
>>> print(result)
{'topic': 'Python编程', 'language': 'Chinese', 'directory_data': {'title': 'Python编程', 'directory': [{'基础概念': ['变量', '数据类型']}, {'进阶应用': ['函数', '模块']}]}}
Note:
该类依赖于LLM模型来生成目录结构,如果LLM模型返回的数据不符合预期格式,将返回默认的目录数据。
"""
def __init__(self) -> None:
"""
初始化WriteDirectoryAction类。
初始化时设置动作名称、描述和参数文档。
"""
action_name = "WriteDirectory"
action_desc = "Generate tutorial directory structure"
params_doc = {
"topic": "(Type: string): The tutorial topic name",
"language": "(Type: string): Output language (default: 'Chinese')"
}
super().__init__(action_name, action_desc, params_doc)
def __call__(self, **kwargs):
"""
根据给定的主题和语言生成教程目录结构。
Args:
**kwargs: 关键字参数,包含主题(topic)和语言(language)两个参数。
topic (str): 教程主题名称,默认为空字符串。
language (str): 输出语言,默认为"Chinese"。
Returns:
dict: 包含主题、语言和目录数据的字典。
Raises:
json.JSONDecodeError: 如果LLM模型返回的数据不符合JSON格式。
"""
topic = kwargs.get("topic", "")
language = kwargs.get("language", "Chinese")
directory_prompt = f"""
请为主题"{topic}"生成教程目录结构,要求:
1. 输出语言必须是{language}
2. 严格按照以下字典格式输出: {
{"title": "xxx", "directory": [{
{"章节1": ["小节1", "小节2"]}}, {
{"章节2": ["小节3", "小节4"]}}]}}
3. 目录层次要合理,包含主目录和子目录
4. 每个目录标题要有实际意义
5. 不要有多余的空格或换行
"""
# 调用 LLM 生成目录
directory_data = llm.llm_chain.invoke({"prompt": directory_prompt})
try:
directory_data = json.loads(directory_data)
except:
directory_data = {"title": topic, "directory": []}
return {
"topic": topic,
"language": language,
"directory_data": directory_data
}
python
class WriteContentAction(BaseAction):
"""
生成教程详细内容的动作类。
该类用于根据给定的教程标题、章节、小节标题、目录结构和语言,生成教程的详细内容。内容以Markdown格式输出,包含代码示例(如有),长度适中。
Attributes:
action_name (str): 动作名称,固定为"WriteContent"。
action_desc (str): 动作描述,固定为"Generate detailed tutorial content based on directory structure"。
params_doc (dict): 参数文档,包含标题(title)、章节(chapter)、目录数据(directory_data)和语言(language)四个参数的类型和说明。
Methods:
__call__(**kwargs): 根据给定的参数生成教程详细内容。
Example:
>>> action = WriteContentAction()
>>> directory_data = {'title': 'Python编程', 'directory': [{'基础概念': ['变量', '数据类型']}, {'进阶应用': ['函数', '模块']}]}
>>> content = action(title="变量", chapter="基础概念", language="Chinese", directory_data=directory_data)
>>> print(content)
# 变量
在Python中,变量是用来存储数据的容器...
Note:
该类依赖于LLM模型来生成内容,如果LLM模型返回的数据不符合预期,可能需要手动调整。
"""
def __init__(self) -> None:
"""
初始化WriteContentAction类。
初始化时设置动作名称、描述和参数文档。
"""
action_name = "WriteContent"
action_desc = "Generate detailed tutorial content based on directory structure"
params_doc = {
"title": "(Type: string): The section title",
"chapter": "(Type: string): The chapter title",
"directory_data": "(Type: dict): The complete directory structure",
"language": "(Type: string): Output language (default: 'Chinese')"
}
super().__init__(action_name, action_desc, params_doc)
def __call__(self, **kwargs):
"""
根据给定的参数生成教程详细内容。
Args:
**kwargs: 关键字参数,包含标题(title)、章节(chapter)、语言(language)和目录数据(directory_data)四个参数。
title (str): 小节标题,默认为空字符串。
chapter (str): 章节标题,默认为空字符串。
language (str): 输出语言,默认为"Chinese"。
directory_data (dict): 完整的目录结构,默认为空字典。
Returns:
str: 生成的教程详细内容。
Raises:
Exception: 如果LLM模型调用失败。
"""
title = kwargs.get("title", "")
chapter = kwargs.get("chapter", "")
language = kwargs.get("language", "Chinese")
directory_data = kwargs.get("directory_data", {})
content_prompt = f"""
请为教程章节生成详细内容:
教程标题: {directory_data.get('title', '')}
章节: {chapter}
小节: {title}
要求:
1. 内容要详细且准确
2. 如果需要代码示例,请按标准规范提供
3. 使用 Markdown 格式
4. 输出语言必须是{language}
5. 内容长度适中,通常在500-1000字之间
"""
# 调用 LLM 生成内容
content = llm.llm_chain.invoke({"prompt": content_prompt})
return content
python
class TutorialAssistant(BaseAgent):
"""
教程生成助手类,管理目录和内容创建。
该类用于生成完整教程,包括目录结构和详细内容。它依赖于WriteDirectoryAction和WriteContentAction两个动作类来分别生成目录结构和详细内容。
Attributes:
name (str): 助手名称,固定为"TutorialAssistant"。
role (str): 助手角色描述,说明其专业领域和能力。
llm (BaseLLM): 语言模型实例,用于生成目录结构和详细内容。
language (str): 输出语言,默认为"Chinese"。
directory_action (WriteDirectoryAction): 生成目录结构的动作实例。
content_action (WriteContentAction): 生成详细内容的动作实例。
Methods:
_generate_tutorial(directory_data): 根据目录结构生成完整教程内容。
__call__(task): 处理教程生成任务,生成目录结构和详细内容,并保存结果。
_add_tutorial_example(): 添加教程生成助手的示例用例。
Example:
>>> assistant = TutorialAssistant(llm)
>>> task = TaskPackage(instruction="Create a Python tutorial for beginners")
>>> result = assistant(task)
>>> print(result.answer)
# Python基础教程
## 目录
1. 第一章:Python介绍
1.1 什么是Python
1.2 环境搭建
...
Note:
该类假设语言模型能够正常工作,如果语言模型返回的数据不符合预期,可能需要手动调整。
"""
def __init__(
self,
llm: BaseLLM,
language: str = "Chinese"
):
"""
初始化TutorialAssistant类。
初始化时设置助手名称、角色描述、语言模型实例、输出语言、目录动作实例和内容动作实例。
Args:
llm (BaseLLM): 语言模型实例。
language (str, optional): 输出语言,默认为"Chinese"。
"""
name = "TutorialAssistant"
role = """You are a professional tutorial writer. You can create well-structured,
comprehensive tutorials on various topics. You excel at organizing content logically
and explaining complex concepts clearly."""
super().__init__(
name=name,
role=role,
llm=llm,
)
self.language = language
self.directory_action = WriteDirectoryAction()
self.content_action = WriteContentAction()
# Add example for the tutorial assistant
self._add_tutorial_example()
def _generate_tutorial(self, directory_data: Dict) -> str:
"""
根据目录结构生成完整教程内容。
Args:
directory_data (Dict): 目录结构数据,包含教程标题和章节信息。
Returns:
str: 生成的完整教程内容。
Raises:
Exception: 如果目录结构数据不符合预期格式。
"""
full_content = []
title = directory_data["title"]
full_content.append(f"# {title}\n")
# Generate table of contents
full_content.append("## 目录\n")
for idx, chapter in enumerate(directory_data["directory"], 1):
for chapter_title, sections in chapter.items():
full_content.append(f"{idx}. {chapter_title}")
for section_idx, section in enumerate(sections, 1):
full_content.append(f" {idx}.{section_idx}. {section}")
full_content.append("\n---\n")
# Generate content for each section
for chapter in directory_data["directory"]:
for chapter_title, sections in chapter.items():
for section in sections:
content = self.content_action(
title=section,
chapter=chapter_title,
directory_data=directory_data,
language=self.language
)
full_content.append(content)
full_content.append("\n---\n")
return "\n".join(full_content)
def __call__(self, task: TaskPackage):
"""
处理教程生成任务,生成目录结构和详细内容,并保存结果。
Args:
task (TaskPackage): 教程生成任务,包含指令信息。
Returns:
TaskPackage: 处理后的任务,包含生成的教程内容和完成状态。
Raises:
Exception: 如果任务指令不符合预期格式。
"""
# Extract topic from task
topic = task.instruction.split("Create a ")[-1].split(" tutorial")[0]
if not topic:
topic = task.instruction
# Generate directory structure
directory_result = self.directory_action(
topic=topic,
language=self.language
)
print(directory_result)
# Generate complete tutorial
tutorial_content = self._generate_tutorial(directory_result["directory_data"])
# Save the result
task.answer = tutorial_content
task.completion = "completed"
return task
def _add_tutorial_example(self):
"""
添加教程生成助手的示例用例。
示例用例用于演示教程生成助手的工作流程和输出格式。
"""
exp_task = "Create a Python tutorial for beginners"
exp_task_pack = TaskPackage(instruction=exp_task)
topic = "Python基础教程"
act_1 = AgentAct(
name=ThinkAct.action_name,
params={INNER_ACT_KEY: """First, I'll create a directory structure for the Python tutorial,
then generate detailed content for each section."""}
)
obs_1 = "OK. I'll start with the directory structure."
act_2 = AgentAct(
name=self.directory_action.action_name,
params={
"topic": topic,
"language": self.language
}
)
obs_2 = """{"title": "Python基础教程", "directory": [
{"第一章:Python介绍": ["1.1 什么是Python", "1.2 环境搭建"]},
{"第二章:基础语法": ["2.1 变量和数据类型", "2.2 控制流"]}
]}"""
act_3 = AgentAct(
name=self.content_action.action_name,
params={
"title": "什么是Python",
"chapter": "第一章:Python介绍",
"directory_data": json.loads(obs_2),
"language": self.language
}
)
obs_3 = """# 第一章:Python介绍\n## 什么是Python\n\nPython是一种高级编程语言..."""
act_4 = AgentAct(
name=FinishAct.action_name,
params={INNER_ACT_KEY: "Tutorial structure and content generated successfully."}
)
obs_4 = "Tutorial generation task completed successfully."
exp_act_obs = [(act_1, obs_1), (act_2, obs_2), (act_3, obs_3), (act_4, obs_4)]
self.prompt_gen.add_example(
task=exp_task_pack,
action_chain=exp_act_obs
)
执行层:
python
if __name__ == "__main__":
#这行代码创建了一个TutorialAssistant实例,传入了一个语言模型llm。这个实例将用于生成教程
assistant = TutorialAssistant(llm=llm)
# 交互式生成教程
FLAG_CONTINUE = True
#使用一个while循环来持续接收用户输入,直到用户选择不再生成新的教程。
while FLAG_CONTINUE:
#通过input函数接收用户想要生成的教程主题。
input_text = input("What tutorial would you like to create?\n")
#将用户输入的主题封装成一个TaskPackage对象,这个对象将传递给TutorialAssistant实例。
task = TaskPackage(instruction=input_text)
#调用TutorialAssistant实例的__call__方法来处理任务,生成教程内容
result = assistant(task)
#将生成的教程内容打印到控制台。
print("\nGenerated Tutorial:\n")
print(result.answer)
# 创建输出目录,使用当前时间创建一个唯一的输出目录,确保每次生成的教程文件不会互相覆盖。
output_dir = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
os.makedirs(output_dir, exist_ok=True)
# 处理文件名,确保有效
safe_input_text = "".join([c if c.isalnum() or c in (' ', '_') else '_' for c in input_text])
output_file = os.path.join(output_dir, f"{safe_input_text}.md")
# 保存文件
with open(output_file, 'w', encoding='utf-8') as f:
f.write(result.answer)
# 询问用户是否继续
#通过input函数询问用户是否想要继续生成新的教程,如果用户输入n,则退出循环。
if input("\nDo you want to create another tutorial? (y/n): ").lower() != "y":
FLAG_CONTINUE = False