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
相关推荐
Tester_孙大壮1 分钟前
第13章:Python TDD完善货币加法运算(二)
开发语言·python
洛阳纸贵6 分钟前
基于SpringCloud的广告系统设计与实现(一)
java·开发语言
壮Sir不壮7 分钟前
go chan底层分析
开发语言·后端·golang
egekm_sefg9 分钟前
搭建Golang gRPC环境:protoc、protoc-gen-go 和 protoc-gen-go-grpc 工具安装教程
开发语言·后端·golang
正在走向自律11 分钟前
当AI Agent遇上CRM:客户关系管理的智能化变革(29/30)
人工智能·crm系统·ai agent·ai智能体
一只小bit23 分钟前
C/C++内存管理(超详解)
开发语言·c++
蹦蹦跳跳真可爱58932 分钟前
Python----Python高级(面向对象:对象,类,属性,方法)
开发语言·python
JoYER_cc33 分钟前
C 陷阱与缺陷 —— Chapter one 词法陷阱
c语言·开发语言
滴滴哒哒答答1 小时前
《自动驾驶与机器人中的SLAM技术》ch8:基于预积分和图优化的紧耦合 LIO 系统
人工智能·机器人·自动驾驶
从零开始学习人工智能1 小时前
傅里叶变换在语音识别中的关键作用
人工智能·语音识别