Reference:Datawhale wow agent day10
本節課我們將通過 Zigent 框架實現一個教程編寫智能體,其主要功能是輸入教程主題,然後自動生成完整的教程內容。 設計思路:
先通過 LLM 大模型生成教程的目錄,再對目錄按照二級標題進行分塊,對於每塊目錄按照標題生成詳細內容,最後再將標題和內容進行拼接。分塊的設計解決了 LLM 大模型長文本的限制問題。
定義生成教程的目錄 Action 類#
定義 WriteDirectoryAction 類,繼承自 BaseAction。該類的主要功能是生成一個教程的目錄結構。具體來說,它通過調用大語言模型(LLM)來根據給定的主題和語言生成一個符合特定格式的目錄。
class WriteDirectoryAction(BaseAction):
"""生成教程目錄結構的動作"""
def __init__(self) -> None:
action_name = "WriteDirectory"
action_desc = "生成教程目錄結構"
params_doc = {
"topic": "(類型: 字串): 教程主題名稱",
"language": "(類型: 字串): 輸出語言 (默認: '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):
"""生成教程內容的動作"""
def __init__(self) -> None:
action_name = "WriteContent"
action_desc = "根據目錄結構生成詳細的教程內容"
params_doc = {
"title": "(類型: 字串): 章節標題",
"chapter": "(類型: 字串): 章節標題",
"directory_data": "(類型: 字典): 完整的目錄結構",
"language": "(類型: 字串): 輸出語言 (默認: '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 方法處理生成教程的任務。它從任務中提取主題,生成目錄結構,然後生成完整的教程內容,並將結果保存到本地。
class TutorialAssistant(BaseAgent):
"""教程生成助手,管理目錄和內容創建"""
def __init__(
self,
llm: LLM,
language: str = "Chinese"
):
name = "TutorialAssistant"
role = """您是一位專業的教程編寫者。您可以創建結構良好、
全面的各種主題教程。您擅長邏輯性地組織內容
並清晰地解釋複雜概念。"""
super().__init__(
name=name,
role=role,
llm=llm,
)
self.language = language
self.directory_action = WriteDirectoryAction()
self.content_action = WriteContentAction()
# 為教程助手添加示例
self._add_tutorial_example()
def _generate_tutorial(self, directory_data: Dict) -> str:
"""根據目錄結構生成完整的教程內容"""
full_content = []
title = directory_data["title"]
full_content.append(f"# {title}\n")
# 生成目錄
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")
# 為每個章節生成內容
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):
"""處理教程生成任務"""
# 從任務中提取主題
topic = task.instruction.split("Create a ")[-1].split(" tutorial")[0]
if not topic:
topic = task.instruction
# 生成目錄結構
directory_result = self.directory_action(
topic=topic,
language=self.language
)
print(directory_result)
# 生成完整教程
tutorial_content = self._generate_tutorial(directory_result["directory_data"])
# 保存結果
task.answer = tutorial_content
task.completion = "completed"
return task
def _add_tutorial_example(self):
"""為教程助手添加插圖示例"""
exp_task = "為初學者創建一個 Python 教程"
exp_task_pack = TaskPackage(instruction=exp_task)
topic = "Python基礎教程"
act_1 = AgentAct(
name=ThinkAct.action_name,
params={INNER_ACT_KEY: """首先,我將為 Python 教程創建一個目錄結構,
然後為每個章節生成詳細內容。"""}
)
obs_1 = "好的。我將從目錄結構開始。"
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: "教程結構和內容生成成功。"}
)
obs_4 = "教程生成任務成功完成。"
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("您想創建什麼教程?\n")
task = TaskPackage(instruction=input_text)
result = assistant(task)
print("\n生成的教程:\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("\n您想創建另一個教程嗎?(y/n): ").lower() != "y":
FLAG_CONTINUE = False
測試結果#
生成基礎拓撲學教程:
太長了就不完全放上來了。