📘 **TELUS Agriculture & Consumer Goods** 如何通过 **Haystack Agents** 转变促销交易

教程:构建工具调用代理


概述

在本教程中,您将学习如何创建一个能够使用工具来回答问题和执行任务的代理。我们将探讨两种方法:

  1. Agent 与简单的网络搜索工具结合使用
  2. Agent 与包含多个组件的更复杂的流水线结合使用

Agent 组件允许您创建能够使用工具来收集信息、执行操作和与外部系统交互的人工智能助手。它使用大型语言模型 (LLM) 来理解用户查询并决定使用哪些工具来回答这些查询。

准备环境

首先,让我们安装 Haystack 和我们稍后将需要的另外两个依赖项

%%bash

pip install haystack-ai docstring-parser trafilatura

输入 API 密钥

输入您的 OpenAI 和 SerperDev API 密钥

from getpass import getpass
import os

if "OPENAI_API_KEY" not in os.environ:
    os.environ["OPENAI_API_KEY"] = getpass("Enter OpenAI API key:")
if "SERPERDEV_API_KEY" not in os.environ:
    os.environ["SERPERDEV_API_KEY"] = getpass("Enter SerperDev API key: ")

将组件用作工具来使用代理

我们从一个简单的例子开始,将 Agent 用作独立的组件,并附带网络搜索工具。该工具可以触发网络搜索并获取包含最相关搜索结果的搜索引擎结果页面 (SERP)。

from haystack.components.agents import Agent
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.components.websearch import SerperDevWebSearch
from haystack.dataclasses import ChatMessage
from haystack.tools.component_tool import ComponentTool

# Create a web search tool using SerperDevWebSearch
web_tool = ComponentTool(component=SerperDevWebSearch(), name="web_tool")

# Create the agent with the web search tool
agent = Agent(chat_generator=OpenAIChatGenerator(model="gpt-4o-mini"), tools=[web_tool])

# Run the agent with a query
result = agent.run(messages=[ChatMessage.from_user("Find information about Haystack AI framework")])

# Print the final response
print(result["messages"][-1].text)

Agent 具有一些可选参数,可让您自定义其行为

  • system_prompt 用于定义一个系统提示,其中包含对 Agent 的 LLM 的指令
  • exit_conditions 将导致代理返回。它是一个字符串列表,其中的项可以是 "text",表示 Agent 一旦 LLM 只回复文本响应就会退出;或者特定的工具名称,使 Agent 在调用了具有该名称的工具后立即返回。
  • state_schema 用于在一次代理调用运行时共享的状态。它定义了工具可以在执行过程中读取或写入的额外信息(例如文档或上下文)。您可以使用此架构来传递工具可以生成和消耗的参数。
  • streaming_callback 用于将来自 LLM 的 token 直接流式传输到输出。
  • raise_on_tool_invocation_failure 用于决定代理在工具调用失败时是否应引发异常。如果设置为 False,则异常将转换为聊天消息并传递给 LLM。然后,它可以通过下一次工具调用进行改进。
  • max_agent_steps 用于限制 Agent 调用工具的次数,并防止无限循环。

exit_conditions 设置为默认值 [“text”] 时,您可以启用流式传输,以便在响应的 token 生成时就能看到它们。

from haystack.components.generators.utils import print_streaming_chunk

agent = Agent(
    chat_generator=OpenAIChatGenerator(model="gpt-4o-mini"), tools=[web_tool], streaming_callback=print_streaming_chunk
)

result = agent.run(messages=[ChatMessage.from_user("Find information about Haystack AI framework")])

您可以轻松地替换 Agent 中使用的 ChatGenerator。目前,以下所有 ChatGenerator 都支持工具,因此可以与 Agent 一起使用:

例如,如果您安装了 HF_API_TOKENhuggingface_hub[inference]>=0.27.0,您只需要将 OpenAIChatGenerator 替换为 HuggingFaceAPIChatGenerator 并运行 from haystack.components.generators.chat import HuggingFaceAPIChatGenerator

将流水线用作工具来使用代理

现在,对于更复杂的示例,让我们构建一个研究助手,它可以搜索网络、从链接中获取内容并生成全面的答案。与我们之前的 Agent 不同,我们现在希望跟踪搜索引擎结果页面上的链接,访问其内容并通过 OutputAdapter 解析其内容。我们将从 Haystack Pipeline 开始,Agent 可以将其用作工具。

from haystack.components.builders.answer_builder import AnswerBuilder
from haystack.components.converters.html import HTMLToDocument
from haystack.components.converters.output_adapter import OutputAdapter
from haystack.components.fetchers.link_content import LinkContentFetcher
from haystack.components.websearch.serper_dev import SerperDevWebSearch
from haystack.dataclasses import ChatMessage
from haystack.core.pipeline import Pipeline

search_pipeline = Pipeline()

search_pipeline.add_component("search", SerperDevWebSearch(top_k=10))
search_pipeline.add_component("fetcher", LinkContentFetcher(timeout=3, raise_on_failure=False, retry_attempts=2))
search_pipeline.add_component("converter", HTMLToDocument())
search_pipeline.add_component(
    "output_adapter",
    OutputAdapter(
        template="""
{%- for doc in docs -%}
  {%- if doc.content -%}
  <search-result url="{{ doc.meta.url }}">
  {{ doc.content|truncate(25000) }}
  </search-result>
  {%- endif -%}
{%- endfor -%}
""",
        output_type=str,
    ),
)

search_pipeline.connect("search.links", "fetcher.urls")
search_pipeline.connect("fetcher.streams", "converter.sources")
search_pipeline.connect("converter.documents", "output_adapter.docs")

从流水线创建工具

接下来,将 search_pipeline 包装在 SuperComponent 中,并使用 ComponentTool 将其转换为工具。ComponentTool 会根据组件的输入插槽自动创建 LLM 兼容的工具模式。

要控制 ComponentTool 应接收和返回的数据,您可以选择定义 input_mappingoutput_mapping。例如,这可以确保只有 search_pipeline"query" 输入在 LLM 兼容的工具模式中被提及,并且只有 "search_result"SuperComponent 返回。

最后,您可以使用生成的 search_tool 初始化 Agent。

💡 在 ToolMCPTool 文档页面中了解创建工具的替代方法。

from haystack.core.super_component import SuperComponent
from haystack.tools import ComponentTool
from haystack.components.agents import Agent
from haystack.components.generators.chat import OpenAIChatGenerator

search_component = SuperComponent(
    pipeline=search_pipeline,
    input_mapping={"query": ["search.query"]},
    output_mapping={"output_adapter.output": "search_result"},
)

search_tool = ComponentTool(
    name="search",
    description="Use this tool to search for information on the internet.",
    component=search_component,
    outputs_to_string={"source": "search_result"},
)

agent = Agent(
    chat_generator=OpenAIChatGenerator(model="gpt-4o-mini"),
    tools=[search_tool],
    system_prompt="""
    You are a deep research assistant.
    You create comprehensive research reports to answer the user's questions.
    You use the 'search'-tool to answer any questions.
    You perform multiple searches until you have the information you need to answer the question.
    Make sure you research different aspects of the question.
    Use markdown to format your response.
    When you use information from the websearch results, cite your sources using markdown links.
    It is important that you cite accurately.
    """,
    exit_conditions=["text"],
    max_agent_steps=20,
)

我们的 Agent 已准备就绪!在运行 Agent 之前调用 agent.warm_up() 是一个好习惯,它确保模型已加载(如果需要)。

query = "What are the latest updates on the Artemis moon mission?"
messages = [ChatMessage.from_user(query)]

agent.warm_up()
agent_output = agent.run(messages=messages)

print(agent_output["messages"][-1].text)

要以 markdown 格式渲染 Agent 的响应,请运行代码片段

from IPython.display import Markdown, display

display(Markdown(agent_output["messages"][-1].text))

让我们来分解一下教程中的最后一个示例。Agent 是协调 LLM 和工具之间交互的主要组件。我们使用 ComponentTool 作为包装器,允许 Haystack 组件被 Agent 用作工具。SuperComponent 包装整个流水线,以便它们可以被用作组件,从而也可以被用作工具。

我们创建了一个复杂的搜索流水线,该流水线:

  1. 使用 SerperDevWebSearch 搜索网络
  2. 从找到的链接中获取内容
  3. 将 HTML 内容转换为 Documents
  4. 为 Agent 格式化结果

然后,Agent 使用此流水线作为工具来收集信息并生成全面的答案。

顺便问一下,您知道 Agent 本身就是一个 Haystack 组件吗?这意味着您可以像使用任何其他组件一样在流水线中使用和组合 Agent!

下一步

🎉 恭喜!您已学会如何使用 Haystack 创建一个工具调用代理。您现在可以:

  • 使用基本工具创建简单的代理
  • 构建包含多个组件的复杂流水线
  • 使用 Agent 组件创建复杂的人工智能助手
  • 在您的应用程序中结合网络搜索、内容获取和文档处理

如果您喜欢本教程,您可能还会喜欢重用以下示例中的流水线,并将它们变成强大 Agent 的工具:

要随时了解最新的 Haystack 开发动态,您可以 订阅我们的 newsletter加入 Haystack discord 社区

感谢阅读!