Reference:Datawhale wow agent day10
In this lesson, we will implement a tutorial writing agent using the Zigent framework, whose main function is to input the tutorial topic and then automatically generate complete tutorial content. Design idea:
First, generate the tutorial directory using the LLM large model, then chunk the directory according to the second-level headings, generate detailed content for each chunk based on the headings, and finally concatenate the headings and content. The chunking design solves the problem of long text limitations of the LLM large model.
Define the Action class for generating the tutorial directory#
Define the WriteDirectoryAction class, inheriting from BaseAction. The main function of this class is to generate a tutorial directory structure. Specifically, it generates a directory that conforms to a specific format by calling a large language model (LLM) based on the given topic and language.
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"""
Please generate a tutorial directory structure for the topic "{topic}", with the following requirements:
1. The output language must be {language}
2. Strictly output in the following dictionary format: {{"title": "xxx", "directory": [{{"Chapter 1": ["Section 1", "Section 2"]}}, {{"Chapter 2": ["Section 3", "Section 4"]}}]}}
3. The directory hierarchy should be reasonable, including main directories and subdirectories
4. Each directory title should have actual significance
5. Do not have extra spaces or line breaks
"""
# Call LLM to generate directory
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
}
Define the Action class for generating tutorial content#
The WriteContentAction class is used to generate tutorial content. Its call method receives the title, chapter, language, and directory data, constructs a content prompt, and finally calls the LLM to generate the corresponding content.
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"""
Please generate detailed content for the tutorial chapter:
Tutorial Title: {directory_data.get('title', '')}
Chapter: {chapter}
Section: {title}
Requirements:
1. The content must be detailed and accurate
2. If code examples are needed, please provide them according to standard specifications
3. Use Markdown format
4. The output language must be {language}
5. The content length should be moderate, typically between 500-1000 words
"""
# Call LLM to generate content
content = llm.run(content_prompt)
return content
Define the tutorial writing agent#
Define the TutorialAssistant class, inheriting from BaseAgent, to generate tutorial content. Its main functions include: initializing the actions for directory and content generation (WriteDirectoryAction and WriteContentAction), the _generate_tutorial method generates complete tutorial content including the directory and detailed content for each chapter based on the directory data, and the _add_tutorial_example method adds an example task for the assistant and demonstrates how to generate a directory and content for a Python tutorial. Finally, it calls the call method to process the tutorial generation task. It extracts the topic from the task, generates the directory structure, then generates the complete tutorial content, and saves the result locally.
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("## Table of Contents\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 Basic Tutorial"
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 Basic Tutorial", "directory": [
{"Chapter 1: Introduction to Python": ["1.1 What is Python", "1.2 Setting up the environment"]},
{"Chapter 2: Basic Syntax": ["2.1 Variables and Data Types", "2.2 Control Flow"]}
]}"""
act_3 = AgentAct(
name=self.content_action.action_name,
params={
"title": "What is Python",
"chapter": "Chapter 1: Introduction to Python",
"directory_data": json.loads(obs_2),
"language": self.language
}
)
obs_3 = """# Chapter 1: Introduction to Python\n## What is Python\n\nPython is a high-level programming language..."""
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
)
Interactive operation calling the tutorial writing agent#
In the main program, create an instance of TutorialAssistant and call its call method to achieve interactive tutorial generation functionality. Users can input the tutorial topic they want to create, then call the TutorialAssistant to generate the corresponding tutorial content and save the results to a local file.
if __name__ == "__main__":
assistant = TutorialAssistant(llm=llm)
# Interactive tutorial generation
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)
# Create output directory
output_dir = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
os.makedirs(output_dir, exist_ok=True)
# Save file
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
Test results#
Generate a basic topology tutorial:
It's too long to display completely.