【LLM-agent】(task6)构建教程编写智能体

news2025/2/3 13:54:06

note

  • 构建教程编写智能体

文章目录

  • note
  • 一、功能需求
  • 二、相关代码
    • (1)定义生成教程的目录 Action 类
    • (2)定义生成教程内容的 Action 类
    • (3)定义教程编写智能体
    • (4)交互式操作调用教程编写智能体
  • 三、Python小细节
  • Reference

一、功能需求

功能:输入教程主题,然后自动生成完整的教程内容
思路:先通过 LLM 大模型生成教程的目录,再对目录按照二级标题进行分块,对于每块目录按照标题生成详细内容,最后再将标题和内容进行拼接。分块的设计解决了 LLM 大模型长文本的限制问题。

二、相关代码

(1)定义生成教程的目录 Action 类

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

(2)定义生成教程内容的 Action 类

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

(3)定义教程编写智能体

定义 TutorialAssistant 类,继承自 BaseAgent,用于生成教程内容。其主要功能包括:

  • 初始化目录和内容生成的动作(WriteDirectoryActionWriteContentAction
  • _generate_tutorial 方法根据目录数据生成完整的教程内容包括目录和每个章节的详细内容
  • _add_tutorial_example 方法为助手添加一个示例任务并展示如何生成一个 Python 教程的目录和内容。最终调用 __call__ 方法处理生成教程的任务。它从任务中提取主题,生成目录结构,然后生成完整的教程内容,并将结果保存到本地。

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

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

import os
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()
# 初始化变量
base_url = None
chat_model = None
api_key = None

# 使用with语句打开文件,确保文件使用完毕后自动关闭
env_path = ".env.txt"
with open(env_path, 'r') as file:
    # 逐行读取文件
    for line in file:
        # 移除字符串头尾的空白字符(包括'\n')
        line = line.strip()
        # 检查并解析变量
        if "base_url" in line:
            base_url = line.split('=', 1)[1].strip().strip('"')
        elif "chat_model" in line:
            chat_model = line.split('=', 1)[1].strip().strip('"')
        elif "ZHIPU_API_KEY" in line:
            api_key = line.split('=', 1)[1].strip().strip('"')
        elif "BOCHA_API_KEY" in line:
            BOCHA_API_KEY = line.split('=', 1)[1].strip().strip('"')

# 打印变量以验证
print(f"base_url: {base_url}")
print(f"chat_model: {chat_model}")
print(f"ZHIPU_API_KEY: {api_key}")


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


llm = LLM(api_key=api_key, base_url=base_url, model_name=chat_model)
response = llm.run("你是谁?")
print(response)

# 一、定义生成教程的目录 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.llm_chain.invoke({"prompt": directory_prompt})
        directory_data = llm.run(prompt=directory_prompt)  # 注意这里传入的是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.llm_chain.invoke({"prompt": content_prompt})
        content = llm.run(prompt=content_prompt) 
        return content
    

# 三、定义教程编写智能体
class TutorialAssistant(BaseAgent):
    """Tutorial generation assistant that manages directory and content creation"""
    def __init__(
        self,
        llm: LLM, # BaseLLM,
        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

输出教程的主题后就会生成markdown格式的教程文档,我输的music,由于是先生成教程的大标题和各种子标题,再逐个将标题对应的内容生成,这样保证了长文本的生成,从结果来看确实有一大坨字数:
在这里插入图片描述

三、Python小细节

在Python中,__call__ 方法允许一个类的实例表现得像函数一样,这意味着你可以直接调用一个实例,就像它是函数一样。当你定义了 __call__ 方法后,这个类的实例就可以被当作一个可调用的对象。
下面是一个简单的例子来说明 __call__ 方法是如何工作的:

class CallableClass:
    def __init__(self, value):
        self.value = value
    def __call__(self, addend):
        return self.value + addend
# 创建一个CallableClass的实例
callable_instance = CallableClass(10)
# 直接调用实例,就像它是函数一样
result = callable_instance(5)  # 这将调用 __call__ 方法
print(result)  # 输出 15

在这个例子中,CallableClass 有一个 __call__ 方法,它接受一个参数 addend,并返回实例属性 valueaddend 的和。

以下是 __call__ 方法的一些用途:

  1. 创建函数工厂:你可以创建一个类,其实例是定制化的函数。
  2. 封装函数调用:你可以使用类来封装函数调用,提供额外的逻辑或状态管理。
  3. 装饰器:在编写装饰器时,有时会使用 __call__ 方法来定义装饰器如何调用原始函数。
  4. 回调函数:在需要传递回调函数的场景中,你可以使用具有 __call__ 方法的对象,这样可以在回调中保持状态。

Reference

[1] https://github.com/datawhalechina/wow-agent
[2] https://www.datawhale.cn/learn/summary/86
[3] https://open.bochaai.com/
[4] 官方文档:https://docs.cloud.llamaindex.ai/
[5] 出题智能体、metagpt:https://www.cnblogs.com/HYLOVEYOURSELF/p/18691941
[6] 教程编写智能体:https://www.cnblogs.com/HYLOVEYOURSELF/p/18680532

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2291293.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】2.12 连续数组:为什么contiguous这么重要?

2.12 连续数组:为什么contiguous这么重要? 目录 #mermaid-svg-wxhozKbHdFIldAkj {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-wxhozKbHdFIldAkj .error-icon{fill:#552222;}#mermaid-svg-…

O3 模型正式上线,能否与 DeepSeek 一较高下?

OpenAI 最近推出了 GPT O3 模型,并对 ChatGPT Plus 用户的 O3-mini 版本进行了升级,提升了每日消息限额,从 50 条增加至 150 条。这一调整大大提升了用户体验,让更多用户有机会深入体验 O3 模型的能力。那么,O3 模型的…

计算机网络 应用层 笔记1(C/S模型,P2P模型,FTP协议)

应用层概述: 功能: 常见协议 应用层与其他层的关系 网络应用模型 C/S模型: 优点 缺点 P2P模型: 优点 缺点 DNS系统: 基本功能 系统架构 域名空间: DNS 服务器 根服务器: 顶级域…

MATLAB的数据类型和各类数据类型转化示例

一、MATLAB的数据类型 在MATLAB中 ,数据类型是非常重要的概念,因为它们决定了如何存储和操作数据。MATLAB支持数值型、字符型、字符串型、逻辑型、结构体、单元数组、数组和矩阵等多种数据类型。MATLAB 是一种动态类型语言,这意味着变量的数…

[SAP ABAP] SE11 / SE16N 修改标准表(慎用)

1.SE16N修改标准表 使用事务码ME16N进入到查询页面,填入要修改的标准表MARA,在事务码输入框中填入/H,回车之后点击按钮,进入Debug调试界面 把GD-SAPEDIT 与 GD-EDIT 的值更改为X然后点击按钮(快捷键按F8)进行下一步操作 可以在此…

Arduino大师练成手册 -- 控制 AS608 指纹识别模块

要在 Arduino 上控制 AS608 指纹识别模块,你可以按照以下步骤进行: 硬件连接 连接指纹模块:将 AS608 指纹模块与 Arduino 连接。通常,AS608 使用 UART 接口进行通信。你需要将 AS608 的 TX、RX、VCC 和 GND 引脚分别连接到 Ardu…

maven mysql jdk nvm node npm 环境安装

安装JDK 1.8 11 环境 maven环境安装 打开网站 下载 下载zip格式 解压 自己创建一个maven库 以后在idea 使用maven时候重新设置一下 这三个地方分别设置 这时候maven才算设置好 nvm 管理 npm nodejs nvm下载 安装 Releases coreybutler/nvm-windows GitHub 一键安装且若有…

Java实现LFU缓存策略实战

LFU算法原理在Java中示例实现集成Caffeine的W-TinyLFU策略缓存实战总结LFU与LRU稍有不同,LFU是根据数据被访问的频率来决定去留。尽管它考虑了数据的近期使用,但它不会区分数据的首次访问和后续访问,淘汰那些访问次数最少的数据。 这种缓存策略主要用来处理以下场景: 数据…

安卓(android)饭堂广播【Android移动开发基础案例教程(第2版)黑马程序员】

一、实验目的(如果代码有错漏,可查看源码) 1.熟悉广播机制的实现流程。 2.掌握广播接收者的创建方式。 3.掌握广播的类型以及自定义官博的创建。 二、实验条件 熟悉广播机制、广播接收者的概念、广播接收者的创建方式、自定广播实现方式以及有…

基于改进的强跟踪技术的扩展Consider Kalman滤波算法在无人机导航系统中的应用研究

在无人机组合导航系统中,精确的状态估计对于任务的成功执行至关重要。然而,系统面临的非线性特性和不确定性,如传感器的量测偏差和动态环境变化,常常导致传统Kalman滤波算法失效。因此,提出一种鲁棒且有效的滤波算法&a…

1.初识beamer

系列文章目录 初识beamer 文章目录 系列文章目录前言一、什么是beamer1.1 定义和背景1.2 使用场景1.3 Beamer优势 二、overleaf 入门beamer三、开始使用beamer3.1 新建一个beamer文件3.2 创建beamer页/帧3.3 目录页3.4 配置beamer整体风格 结束语 前言 工欲善其事&#xff0c…

DeepSeek R1本地化部署 Ollama + Chatbox 打造最强 AI 工具

🌈 个人主页:Zfox_ 🔥 系列专栏:Linux 目录 一:🔥 Ollama 🦋 下载 Ollama🦋 选择模型🦋 运行模型🦋 使用 && 测试 二:🔥 Chat…

《基于Scapy的综合性网络扫描与通信工具集解析》

在网络管理和安全评估中,网络扫描和通信是两个至关重要的环节。Python 的 Scapy 库因其强大的网络数据包处理能力,成为开发和实现这些功能的理想工具。本文将介绍一个基于 Scapy 编写的 Python 脚本,该脚本集成了 ARP 扫描、端口扫描以及 TCP…

基于Python的药物相互作用预测模型AI构建与优化(上.文字部分)

一、引言 1.1 研究背景与意义 在临床用药过程中,药物相互作用(Drug - Drug Interaction, DDI)是一个不可忽视的重要问题。当患者同时服用两种或两种以上药物时,药物之间可能会发生相互作用,从而改变药物的疗效、增加不良反应的发生风险,甚至危及患者的生命安全。例如,…

Linux环境下的Java项目部署技巧:环境安装

安装 JDK: 第上传 jdk 压缩安装包到服务器 将压缩安装包解压缩: tar -xvf jdk-8uXXX-linux-x64.tar.gz 配置环境变量: 编辑 /etc/profile 文件,在文件末尾添加以下内容: export JAVA_HOME/path/to/jdk //JAVA_HOME…

【系统迁移】将系统迁移到新硬盘中(G15 5520)

文章目录 前言问题描述解决步骤(红色为 debug 步骤)参考文献 前言 参数: 电脑 dell g15 5520硬盘:1T 自带硬盘 海力士 2230 -> 2T 西数蓝盘 2280 问题描述 电脑硬盘过小(且只有一个接口),将…

小智 AI 聊天机器人

小智 AI 聊天机器人 (XiaoZhi AI Chatbot) 👉参考源项目复现 👉 ESP32SenseVoiceQwen72B打造你的AI聊天伴侣!【bilibili】 👉 手工打造你的 AI 女友,新手入门教程【bilibili】 项目目的 本…

MySql运维篇---008:日志:错误日志、二进制日志、查询日志、慢查询日志,主从复制:概述 虚拟机更改ip注意事项

#先登录mysql mysql -uroot -p1234#通过此系统变量,查看当前mysql的版本中默认的日志格式是哪个 show variables like %binlog\_format%;1.2.3 查看 由于日志是以二进制方式存储的,不能直接读取,需要通过二进制日志查询工具 mysqlbinlog 来查…

理解DeepSeek源代码之如何安装triton包

DeepSeek选择了开源路线,在github上可以下载到所有的源代码还有参数(数据集应该没有开源),大语言模型的源代码规模其实非常小,DeepSeek V3的模型函数不过804行,阅读源代码有助于更好理解大语言模型。 1. D…

C++ Primer 标准库类型string

欢迎阅读我的 【CPrimer】专栏 专栏简介:本专栏主要面向C初学者,解释C的一些基本概念和基础语言特性,涉及C标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级…