CH10 - SunXiaoXiang/learn_wowagent GitHub Wiki

引入相关依赖

引入 Zigent 框架中实现智能体所需的各种功能和工具,以便后续的代码可以使用这些类和函数来构建智能体的行为和逻辑。引入 datetime 以便生成命名教程目录。

from typing import List, Dict
from zigent.llm.agent_llms import LLM
from zigent.actions import BaseAction, ThinkAct, FinishAct
from zigent.agents import BaseAgent
from zigent.commons import TaskPackage, AgentAct
from zigent.actions.InnerActions import INNER_ACT_KEY
from datetime import datetime
import json

定义生成教程的目录 Action 类

定义 WriteDirectoryAction 类,继承自 BaseAction。该类的主要功能是生成一个教程的目录结构。具体来说,它通过调用大语言模型(LLM)来根据给定的主题和语言生成一个符合特定格式的目录。

class WriteDirectoryAction(BaseAction):
    """Generate tutorial directory structure action"""
    def __init__(self) -> None:
        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):
        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.run(directory_prompt)
        try:
            directory_data = json.loads(directory_data)
        except:
            directory_data = {"title": topic, "directory": []}
            
        return {
            "topic": topic,
            "language": language,
            "directory_data": directory_data
        }
  

定义生成教程内容的 Action 类

WriteContentAction 类用于生成教程内容。它的 __call__ 方法接收标题、章节、语言和目录数据,并构建一个内容提示,最后调用 LLM 生成相应的内容。

class WriteContentAction(BaseAction):
    """Generate tutorial content action"""
    def __init__(self) -> None:
        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):
        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.run(content_prompt)
        return content

定义教程编写智能体

定义 TutorialAssistant 类,继承自 BaseAgent,用于生成教程内容。其主要功能包括:初始化目录和内容生成的动作(WriteDirectoryAction 和 WriteContentAction)、_generate_tutorial 方法根据目录数据生成完整的教程内容包括目录和每个章节的详细内容、_add_tutorial_example 方法为助手添加一个示例任务并展示如何生成一个 Python 教程的目录和内容。最终调用 __call__ 方法处理生成教程的任务。它从任务中提取主题,生成目录结构,然后生成完整的教程内容,并将结果保存到b本地。

class TutorialAssistant(BaseAgent):
    """Tutorial generation assistant that manages directory and content creation"""
    def __init__(
        self,
        llm: LLM,
        language: str = "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:
        """Generate complete tutorial content based on directory structure"""
        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):
        """Process the tutorial generation task"""
        # 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):
        """Add an illustration example for the tutorial assistant"""
        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
        )

交互式操作调用教程编写智能体

在主程序中,创建 TutorialAssistant 实例并调用其 __call__ 方法,实现交互式生成教程的功能。用户可以输入要创建的教程主题,然后调用 TutorialAssistant 生成相应的教程内容,并将结果保存到本地文件。

if __name__ == "__main__":
    assistant = TutorialAssistant(llm=llm)

     # 交互式生成教程
    FLAG_CONTINUE = True
    while FLAG_CONTINUE:
        input_text = input("What tutorial would you like to create?\n")
        task = TaskPackage(instruction=input_text)
        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)
        
        # 保存文件
        output_file = os.path.join(output_dir, f"{input_text}.md")
        with open(output_file, 'w', encoding='utf-8') as f:
            f.write(result.answer)
        if input("\nDo you want to create another tutorial? (y/n): ").lower() != "y":
            FLAG_CONTINUE = False

预期结果会在当前目录生成一个时间戳目录,目录下包含生成的教程文件。如 2024-12-30_12-58-36/Agent教程.md:

Agent教程

目录

  1. 章节1 1.1. Agent基础概念与介绍 1.2. Agent编程环境搭建
  2. 章节2 2.1. Agent编程语言基础 2.2. 数据结构与算法
  3. 章节3 3.1. Agent通信机制 3.2. 消息传递与同步
  4. 章节4 4.1. Agent行为与策略 4.2. 决策与规划
  5. 章节5 5.1. 多智能体系统 5.2. 协同与竞争
  6. 章节6 6.1. Agent应用案例 6.2. 实际项目实践
  7. 章节7 7.1. Agent性能优化 7.2. 调试与测试
  8. 章节8 8.1. Agent未来发展趋势 8.2. 研究前沿与展望

代码

from typing import List, Dict

from zigent.llm.agent_llms import LLM

from zigent.actions import BaseAction, ThinkAct, FinishAct

from zigent.agents import BaseAgent

from zigent.commons import TaskPackage, AgentAct

from zigent.actions.InnerActions import INNER_ACT_KEY

from datetime import datetime

import json

import os

  

# 配置 LLM

api_key = os.getenv('ZISHU_API_KEY')

base_url = "https://open.bigmodel.cn/api/paas/v4/"

chat_model = "glm-4-flash"

llm = LLM(api_key=api_key, base_url=base_url, model_name=chat_model)

  

# 定义生成教程目录的 Action 类

class WriteDirectoryAction(BaseAction):

"""Generate tutorial directory structure action"""

def __init__(self) -> None:

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):

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.run(directory_prompt)

try:

directory_data = json.loads(directory_data)

except:

directory_data = {"title": topic, "directory": []}

return {

"topic": topic,

"language": language,

"directory_data": directory_data

}

  

# 定义生成教程内容的 Action 类

class WriteContentAction(BaseAction):

"""Generate tutorial content action"""

def __init__(self) -> None:

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):

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.run(content_prompt)

return content

  

# 定义教程编写智能体

class TutorialAssistant(BaseAgent):

"""Tutorial generation assistant that manages directory and content creation"""

def __init__(

self,

llm: LLM,

language: str = "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:

"""Generate complete tutorial content based on directory structure"""

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):

"""Process the tutorial generation task"""

# 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):

"""Add an illustration example for the tutorial assistant"""

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__":

assistant = TutorialAssistant(llm=llm)

  

# 交互式生成教程

FLAG_CONTINUE = True

while FLAG_CONTINUE:

input_text = input("What tutorial would you like to create?\n")

task = TaskPackage(instruction=input_text)

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)

# 保存文件

output_file = os.path.join(output_dir, f"{input_text}.md")

with open(output_file, 'w', encoding='utf-8') as f:

f.write(result.answer)

if input("\nDo you want to create another tutorial? (y/n): ").lower() != "y":

FLAG_CONTINUE = False

输出