#
让多个智能体在多智能体层级中协作 🤖🤝🤖

作者：Aymeric Roucher

> 本教程属于进阶内容，建议先了解另一本指南中的概念！

在本笔记本中，我们将构建一个多智能体网页浏览器：一个多个智能体协作，通过互联网解决问题的智能体系统！

它将是一个简单的层级结构，使用 `ManagedAgent` 对象来封装受管理的网页搜索智能体：

                  +----------------+
                  | 管理员智能体    |
                  +----------------+
                           |
            _______________|______________
           |                              |
      代码解释器       +--------------------------------+
           工具         |         受管理的智能体        |
                         |      +------------------+      |
                         |      | 网页搜索智能体   |      |
                         |      +------------------+      |
                         |         |            |         |
                         |  网页搜索工具       |         |
                         |             访问网页工具   |
                         +--------------------------------+

让我们开始搭建这个系统。

⚡️ 我们的智能体将由 meta-llama/Meta-Llama-3.1-70B-Instruct 提供支持，使用 `HfApiEngine` 类，它利用了 HF 的推理 API：推理 API 可以快速、轻松地运行任何操作系统模型。

运行以下命令来安装所需的依赖项：

    !pip install markdownify duckduckgo-search "transformers[agents]" --upgrade -q

我们将选择使用由 Qwen/Qwen2.5-72B-Instruct 提供支持的模型，因为它非常强大，并且在 HF API 中可以免费使用。

    model = "Qwen/Qwen2.5-72B-Instruct"

###
🔍 创建一个网页搜索工具

对于网页浏览，我们可以直接使用我们现有的 `DuckDuckGoSearchTool` 工具来提供一个类似于 Google 搜索的功能。

但是，我们还需要能够查看 `DuckDuckGoSearchTool` 找到的网页内容。
为此，我们可以导入库中内建的 `VisitWebpageTool`，但我们将重新构建这个工具，以便了解它是如何实现的。

因此，让我们从零开始，使用 `markdownify` 创建我们的 `VisitWebpageTool` 工具。

    import re
    import requests
    from markdownify import markdownify as md
    from requests.exceptions import RequestException
    from transformers.agents import tool

    @tool
    def visit_webpage(url: str) -> str:
        """Visits a webpage at the given URL and returns its content as a markdown string.

        Args:
            url: The URL of the webpage to visit.

        Returns:
            The content of the webpage converted to Markdown, or an error message if the request fails.
        """
        try:
            # Send a GET request to the URL
            response = requests.get(url)
            response.raise_for_status()  # Raise an exception for bad status codes

            # Convert the HTML content to Markdown
            markdown_content = md(response.text).strip()

            # Remove multiple line breaks
            markdown_content = re.sub(r"\n{3,}", "\n\n", markdown_content)

            return markdown_content

        except RequestException as e:
            return f"Error fetching the webpage: {str(e)}"
        except Exception as e:
            return f"An unexpected error occurred: {str(e)}"

好了，现在让我们初始化并测试我们的工具！

    >>> print(visit_webpage("https://en.wikipedia.org/wiki/Hugging_Face")[:500])

    Hugging Face \- Wikipedia

    [Jump to content](#bodyContent)

    Main menu

    Main menu
    move to sidebar
    hide

     Navigation

    * [Main page](/wiki/Main_Page "Visit the main page [z]")
    * [Contents](/wiki/Wikipedia:Contents "Guides to browsing Wikipedia")
    * [Current events](/wiki/Portal:Current_events "Articles related to current events")
    * [Random article](/wiki/Special:Random "Visit a randomly selected article [x]")
    * [About Wikipedia](/wiki/Wikipedia:About "Learn about Wikipedia and how it works")
    * [Co

##
构建我们的多智能体系统 🤖🤝🤖

现在我们已经拥有了所有的工具 `search` 和 `visit_webpage`，可以使用它们来创建网页智能体。

该选择什么配置呢？

- 网页浏览是一个单线程任务，不需要并行调用工具，因此使用 JSON 调用工具非常合适。因此，我们选择 `ReactJsonAgent`。
- 此外，由于有时网页搜索需要浏览多个页面才能找到正确答案，我们更倾向于将 `max_iterations` 增加到 10。

    from transformers.agents import (
        ReactCodeAgent,
        ReactJsonAgent,
        HfApiEngine,
        ManagedAgent,
    )
    from transformers.agents.search import DuckDuckGoSearchTool

    llm_engine = HfApiEngine(model)

    web_agent = ReactJsonAgent(
        tools=[DuckDuckGoSearchTool(), visit_webpage],
        llm_engine=llm_engine,
        max_iterations=10,
    )

然后，我们将这个智能体封装到一个 `ManagedAgent` 中，这样它就可以通过管理员智能体进行调用了。

    managed_web_agent = ManagedAgent(
        agent=web_agent,
        name="search",
        description="Runs web searches for you. Give it your query as an argument.",
    )

最后，我们创建一个管理员智能体，并在初始化时将我们的受管理智能体通过 `managed_agents` 参数传递给它。

由于这个智能体负责规划和思考，因此高级推理将非常有帮助，所以选择 `ReactCodeAgent` 是最合适的。

另外，我们想提一个涉及当前年份的问题：因此，我们需要添加 `additional_authorized_imports=["time", "datetime"]`。

    manager_agent = ReactCodeAgent(
        tools=[],
        llm_engine=llm_engine,
        managed_agents=[managed_web_agent],
        additional_authorized_imports=["time", "datetime"],
    )

就这样！现在让我们运行我们的系统！我们选择一个需要进行一些计算的问题

    manager_agent.run("How many years ago was Stripe founded?")

我们的智能体成功地高效协作，解决了任务！ ✅

💡 你可以轻松地扩展到更多智能体：一个负责代码执行，一个负责网页搜索，一个负责文件加载……

🤔💭 甚至可以考虑构建更复杂的树状层级结构，一个 CEO 智能体负责管理多个中层经理，每个经理下有多个报告。

我们甚至可以添加更多的中间管理层，每层都有多个日常会议，进行大量敏捷工作和 Scrum 主管，每个新增的组件都会增加足够的摩擦力，确保任务永远无法完成……嗯，等等，不，我们还是坚持我们的简单结构吧。

Update on GitHub