马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
这个框架是课程讲解的,但资料比较少,觉得框架比较小众,所以这里只分析代码,计划把更多的精力放在metagpt的学习上,毕竟还是要学教为主流的框架,这对后续维护升级都有资助,当然感爱好作为研究,可以研究下这个小框架。
代码目的是要生成一个一个教程编写智能体,其主要功能是输入教程主题,然后自动生成完备的教程内容,首先定义WriteDirectoryAction类,用于生成教程的目次,然后再定义生成教程的类,最后是执行层的代码。
- 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
- }
复制代码- 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
复制代码- 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
- )
复制代码 执行层:
- 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
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |