wow-agent---Day3 Zigent 智能代理开发框架

这个框架是课程讲解的,但资料比较少,觉得框架比较小众,所以这里只分析代码,打算把更多的精力放在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
相关推荐
IT_陈寒1 小时前
React 18实战:7个被低估的Hooks技巧让你的开发效率提升50%
前端·人工智能·后端
数据智能老司机2 小时前
精通 Python 设计模式——分布式系统模式
python·设计模式·架构
逛逛GitHub2 小时前
飞书多维表“独立”了!功能强大的超出想象。
人工智能·github·产品
机器之心2 小时前
刚刚,DeepSeek-R1论文登上Nature封面,通讯作者梁文锋
人工智能·openai
数据智能老司机3 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机3 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机3 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i3 小时前
drf初步梳理
python·django
每日AI新事件3 小时前
python的异步函数
python
这里有鱼汤4 小时前
miniQMT下载历史行情数据太慢怎么办?一招提速10倍!
前端·python