【AI的未来 - AI Agent系列】【MetaGPT】5. 更复杂的Agent实战 - 实现技术文档助手

简介: 【AI的未来 - AI Agent系列】【MetaGPT】5. 更复杂的Agent实战 - 实现技术文档助手

0. 本文实现内容

今天我们来实现一个有实际意义的Agent - 实现一个技术文档助手,用户只需要输入技术文档的标题,例如“Git教程”,Agent自动将Git教程写成文档,分目录,分块,条理清晰,并有代码示例。

先看下要实现的效果(全程用户只需要输入“Git 教程”):

  • MarkDown格式
  • 分目录,一级标题、二级标题
  • 有代码示例

1. 实现思路

因为token限制的原因,我们先通过 LLM 大模型生成教程的目录,再对目录按照二级标题进行分块,对于每块目录按照标题生成详细内容,最后再将标题和内容进行拼接,解决 LLM 大模型长文本的限制问题。

整体流程如下(下图来自《MetaGPT智能体开发入门》):

分析上述流程图,我们需要实现:

  • 生成文档大纲的Action:WriteDirectory
  • 子任务的Action:WriteContent
  • 在得到文档大纲之后,要对大纲进行拆分(本例按目录进行拆分),然后根据拆分内容动态添加子任务Action,让子任务去根据目录写技术文档的内容
  • 将子任务Action生成的内容最后做拼接,形成最终的MarkDown文档

2. 完整代码及细节注释

直接放出完整代码,代码中添加了一些细节注释来帮助你理解,用的MetaGPT 0.5.2版本。建议你一定要实操一遍,因为不实操,你永远不知道自己会遇到多少坑…

代码并不复杂

  • WriteDirectory的实现:基本就是我们把自己的需求放入我们准备好的提示词模板里,询问大模型得到结果,然后我们对得到的内容做一个解析。(数据格式化)
  • WriteContent的实现:直接根据传入的子标题内容调用大模型生成回答
# 加载 .env 到环境变量
from dotenv import load_dotenv, find_dotenv
_ = load_dotenv(find_dotenv())
from datetime import datetime
from typing import Dict
import asyncio
from metagpt.actions.write_tutorial import WriteDirectory, WriteContent
from metagpt.const import TUTORIAL_PATH
from metagpt.logs import logger
from metagpt.roles import Role
from metagpt.schema import Message
from metagpt.utils.file import File
import fire
import time
from typing import Dict
from metagpt.actions import Action
from metagpt.prompts.tutorial_assistant import DIRECTORY_PROMPT, CONTENT_PROMPT
from metagpt.utils.common import OutputParser
## 1. 生成文档大纲目录
class WriteDirectory(Action):
    """Action class for writing tutorial directories.
    Args:
        name: The name of the action.
        language: The language to output, default is "Chinese".
    """
    def __init__(self, name: str = "", language: str = "Chinese", *args, **kwargs):
        super().__init__(name, *args, **kwargs)
        self.language = language
    async def run(self, topic: str, *args, **kwargs) -> Dict:
        COMMON_PROMPT = """
        You are now a seasoned technical professional in the field of the internet. 
        We need you to write a technical tutorial with the topic "{topic}".
        """
        DIRECTORY_PROMPT = COMMON_PROMPT + """
        Please provide the specific table of contents for this tutorial, strictly following the following requirements:
        1. The output must be strictly in the specified language, {language}.
        2. Answer strictly in the dictionary format like {{"title": "xxx", "directory": [{{"dir 1": ["sub dir 1", "sub dir 2"]}}, {{"dir 2": ["sub dir 3", "sub dir 4"]}}]}}.
        3. The directory should be as specific and sufficient as possible, with a primary and secondary directory.The secondary directory is in the array.
        4. Do not have extra spaces or line breaks.
        5. Each directory title has practical significance.
        """
        prompt = DIRECTORY_PROMPT.format(topic=topic, language=self.language)
        resp = await self._aask(prompt=prompt)
        return OutputParser.extract_struct(resp, dict) ## 1.1 对结果进行校验,必须符合Dict结构,否则报错
## 2. 子任务Action,这里是根据拆分的目录标题写技术文档内容
class WriteContent(Action):
    """Action class for writing tutorial content.
    Args:
        name: The name of the action.
        directory: The content to write.
        language: The language to output, default is "Chinese".
    """
    def __init__(self, name: str = "", directory: str = "", language: str = "Chinese", *args, **kwargs):
        super().__init__(name, *args, **kwargs)
        self.language = language
        self.directory = directory
    async def run(self, topic: str, *args, **kwargs) -> str:
        COMMON_PROMPT = """
        You are now a seasoned technical professional in the field of the internet. 
        We need you to write a technical tutorial with the topic "{topic}".
        """
        CONTENT_PROMPT = COMMON_PROMPT + """
        Now I will give you the module directory titles for the topic. 
        Please output the detailed principle content of this title in detail. 
        If there are code examples, please provide them according to standard code specifications. 
        Without a code example, it is not necessary.
        The module directory titles for the topic is as follows:
        {directory}
        Strictly limit output according to the following requirements:
        1. Follow the Markdown syntax format for layout.
        2. If there are code examples, they must follow standard syntax specifications, have document annotations, and be displayed in code blocks.
        3. The output must be strictly in the specified language, {language}.
        4. Do not have redundant output, including concluding remarks.
        5. Strict requirement not to output the topic "{topic}".
        """
        prompt = CONTENT_PROMPT.format(
            topic=topic, language=self.language, directory=self.directory)
        return await self._aask(prompt=prompt)
## 3. 技术文档角色,用来执行Action
class TutorialAssistant(Role):
    def __init__(
        self,
        name: str = "Stitch",
        profile: str = "Tutorial Assistant",
        goal: str = "Generate tutorial documents",
        constraints: str = "Strictly follow Markdown's syntax, with neat and standardized layout",
        language: str = "Chinese",
    ):
        super().__init__(name, profile, goal, constraints)
        self._init_actions([WriteDirectory(language=language)]) ## 3.1 初始化时,先只添加WriteDirectory Action,生成目录。WriteContent Action后面根据目录动态添加,这里你也不知道要添加多少个,添加的内容是什么。
        self.topic = ""
        self.main_title = "" ## 3.2 记录文章题目
        self.total_content = "" ## 3.3 生成的所有内容,拼接到这里
        self.language = language
    async def _think(self) -> None:
        """Determine the next action to be taken by the role."""
        if self._rc.todo is None:
            self._set_state(0) ## 3.4 转到第一个Action执行
            return
        if self._rc.state + 1 < len(self._states):
            self._set_state(self._rc.state + 1) ## 3.5 将要执行下一个Action
        else:
            self._rc.todo = None
  ## 3.6 根据生成的目录,拆分出一级标题和二级标题,动态添加到WriteContent Action中,输入的titles必须是Dict类型,这就要求WriteDirectory的输出必须能按Dict类型解析,否则报错,程序无法继续执行。
    async def _handle_directory(self, titles: Dict) -> Message:
        self.main_title = titles.get("title")
        directory = f"{self.main_title}\n"
        self.total_content += f"# {self.main_title}"
        actions = list()
        for first_dir in titles.get("directory"):
            actions.append(WriteContent(
                language=self.language, directory=first_dir)) ## 3.7 动态添加 WriteContent Action,将一级目录内容传入
            key = list(first_dir.keys())[0]
            directory += f"- {key}\n"
            for second_dir in first_dir[key]:
                directory += f"  - {second_dir}\n"
        self._init_actions(actions) ## 3.8 执行了这一句,此时动作列表全是WriteContent了
        self._rc.todo = None
        return Message(content=directory)
    async def _act(self) -> Message:
        """Perform an action as determined by the role.
        Returns:
            A message containing the result of the action.
        """
        time.sleep(20) ## 3.9 这是为了避免OpenAI接口调用频率限制,不是办法的办法
        todo = self._rc.todo
        if type(todo) is WriteDirectory: 
            msg = self._rc.memory.get(k=1)[0] ## 3.10 获取记忆,这里是获取用户输入,因为任何动作都还没执行,所以只有用户输入
            self.topic = msg.content
            resp = await todo.run(topic=self.topic) ## 3.11 根据用户输入生成目录
            logger.info(resp)
            return await self._handle_directory(resp)
        resp = await todo.run(topic=self.topic) ## 3.12 走到这里的都是WriteContent Action。 这里的self.topic还是用户输入,因为并没有其它地方更新该值。这里传入的目的是让WriteContent写的内容以这个为范围限制
        logger.info(resp)
        if self.total_content != "":
            self.total_content += "\n\n\n"
        self.total_content += resp ## 3.13 拼接数据
        return Message(content=resp, role=self.profile)
    async def _react(self) -> Message:
        """Execute the assistant's think and actions.
        Returns:
            A message containing the final result of the assistant's actions.
        """
        while True:
            await self._think()
            if self._rc.todo is None:
                break
            msg = await self._act()
    ## 3.14 全部Action执行完毕,写文件
        root_path = TUTORIAL_PATH / datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
        await File.write(root_path, f"{self.main_title}.md", self.total_content.encode('utf-8'))
        return msg
async def main():
    msg = "Git 教程"
    role = TutorialAssistant()
    logger.info(msg)
    result = await role.run(msg)
    logger.info(result)
asyncio.run(main())
相关文章
|
2天前
|
机器学习/深度学习 人工智能 算法
FinRobot:开源的金融专业 AI Agent,提供市场预测、报告分析和交易策略等金融解决方案
FinRobot 是一个开源的 AI Agent 平台,专注于金融领域的应用,通过大型语言模型(LLMs)构建复杂的金融分析和决策工具,提供市场预测、文档分析和交易策略等多种功能。
42 13
FinRobot:开源的金融专业 AI Agent,提供市场预测、报告分析和交易策略等金融解决方案
|
4天前
|
人工智能 开发框架 算法
Qwen-Agent:阿里通义开源 AI Agent 应用开发框架,支持构建多智能体,具备自动记忆上下文等能力
Qwen-Agent 是阿里通义开源的一个基于 Qwen 模型的 Agent 应用开发框架,支持指令遵循、工具使用、规划和记忆能力,适用于构建复杂的智能代理应用。
59 10
Qwen-Agent:阿里通义开源 AI Agent 应用开发框架,支持构建多智能体,具备自动记忆上下文等能力
|
22天前
|
机器学习/深度学习 人工智能 自然语言处理
Gemini 2.0:谷歌推出的原生多模态输入输出 + Agent 为核心的 AI 模型
谷歌最新推出的Gemini 2.0是一款原生多模态输入输出的AI模型,以Agent技术为核心,支持多种数据类型的输入与输出,具备强大的性能和多语言音频输出能力。本文将详细介绍Gemini 2.0的主要功能、技术原理及其在多个领域的应用场景。
130 20
Gemini 2.0:谷歌推出的原生多模态输入输出 + Agent 为核心的 AI 模型
|
8天前
|
存储 人工智能 人机交互
PC Agent:开源 AI 电脑智能体,自动收集人机交互数据,模拟认知过程实现办公自动化
PC Agent 是上海交通大学与 GAIR 实验室联合推出的智能 AI 系统,能够模拟人类认知过程,自动化执行复杂的数字任务,如组织研究材料、起草报告等,展现了卓越的数据效率和实际应用潜力。
78 1
PC Agent:开源 AI 电脑智能体,自动收集人机交互数据,模拟认知过程实现办公自动化
|
19天前
|
机器学习/深度学习 人工智能 算法
Meta Motivo:Meta 推出能够控制数字智能体动作的 AI 模型,提升元宇宙互动体验的真实性
Meta Motivo 是 Meta 公司推出的 AI 模型,旨在控制数字智能体的全身动作,提升元宇宙体验的真实性。该模型通过无监督强化学习算法,能够实现零样本学习、行为模仿与生成、多任务泛化等功能,适用于机器人控制、虚拟助手、游戏角色动画等多个应用场景。
50 4
Meta Motivo:Meta 推出能够控制数字智能体动作的 AI 模型,提升元宇宙互动体验的真实性
|
4天前
|
人工智能 自然语言处理 前端开发
三大行业案例:AI大模型+Agent实践全景
本文将从AI Agent和大模型的发展背景切入,结合51Talk、哈啰出行以及B站三个各具特色的行业案例,带你一窥事件驱动架构、RAG技术、人机协作流程,以及一整套行之有效的实操方法。具体包含内容有:51Talk如何让智能客服“主动进攻”,带来约课率、出席率双提升;哈啰出行如何由Copilot模式升级为Agent模式,并应用到客服、营销策略生成等多个业务场景;B站又是如何借力大模型与RAG方法,引爆了平台的高效内容检索和强互动用户体验。
70 5
|
1天前
|
存储 人工智能 开发框架
Eliza:TypeScript 版开源 AI Agent 开发框架,快速搭建智能、个性的 Agents 系统
Eliza 是一个开源的多代理模拟框架,支持多平台连接、多模型集成,能够快速构建智能、高效的AI系统。
24 8
Eliza:TypeScript 版开源 AI Agent 开发框架,快速搭建智能、个性的 Agents 系统
|
22天前
|
人工智能 API 语音技术
TEN Agent:开源的实时多模态 AI 代理框架,支持语音、文本和图像的实时通信交互
TEN Agent 是一个开源的实时多模态 AI 代理框架,集成了 OpenAI Realtime API 和 RTC 技术,支持语音、文本和图像的多模态交互,具备实时通信、模块化设计和多语言支持等功能,适用于智能客服、实时语音助手等多种场景。
123 15
TEN Agent:开源的实时多模态 AI 代理框架,支持语音、文本和图像的实时通信交互
|
23天前
|
人工智能 自然语言处理 前端开发
Director:构建视频智能体的 AI 框架,用自然语言执行搜索、编辑、合成和生成等复杂视频任务
Director 是一个构建视频智能体的 AI 框架,用户可以通过自然语言命令执行复杂的视频任务,如搜索、编辑、合成和生成视频内容。该框架基于 VideoDB 的“视频即数据”基础设施,集成了多个预构建的视频代理和 AI API,支持高度定制化,适用于开发者和创作者。
81 9
Director:构建视频智能体的 AI 框架,用自然语言执行搜索、编辑、合成和生成等复杂视频任务
|
1月前
|
人工智能 自然语言处理 JavaScript
Agent-E:基于 AutoGen 代理框架构建的 AI 浏览器自动化系统
Agent-E 是一个基于 AutoGen 代理框架构建的智能自动化系统,专注于浏览器内的自动化操作。它能够执行多种复杂任务,如填写表单、搜索和排序电商产品、定位网页内容等,从而提高在线效率,减少重复劳动。本文将详细介绍 Agent-E 的功能、技术原理以及如何运行该系统。
84 5
Agent-E:基于 AutoGen 代理框架构建的 AI 浏览器自动化系统