Skip to content

添加工具

为了处理你的聊天机器人无法从记忆中回答的查询,请集成一个网络搜索工具。聊天机器人可以使用此工具查找相关信息并提供更好的回复。

Note

本教程基于构建一个基本的聊天机器人

先决条件

在开始本教程之前,请确保您具备以下内容:

1. 安装搜索引擎

安装使用 Tavily 搜索引擎 所需的依赖项:

pip install -U langchain-tavily

2. 配置你的环境

使用你的搜索引擎 API 密钥配置你的环境:

_set_env("TAVILY_API_KEY")
TAVILY_API_KEY:  ········

3. 定义工具

定义网络搜索工具:

API Reference: TavilySearch

from langchain_tavily import TavilySearch

tool = TavilySearch(max_results=2)
tools = [tool]
tool.invoke("What's a 'node' in LangGraph?")

结果是页面摘要,聊天机器人可以使用这些摘要来回答问题:

{'query': "What's a 'node' in LangGraph?",
'follow_up_questions': None,
'answer': None,
'images': [],
'results': [{'title': "Introduction to LangGraph: A Beginner's Guide - Medium",
'url': 'https://medium.com/@cplog/introduction-to-langgraph-a-beginners-guide-14f9be027141',
'content': 'Stateful Graph: LangGraph 围绕状态图的概念展开,其中图中的每个节点代表计算中的一个步骤,图维护一个随着计算过程传递和更新的状态。LangGraph 支持条件边,允许你根据图的当前状态动态确定要执行的下一个节点。我们定义了用于分类输入、处理问候语和处理搜索查询的节点。 def classify_input_node(state): LangGraph 是一个用于构建复杂、有状态应用的强大工具,它利用 LLM(大型语言模型)。通过理解其核心概念并通过简单的示例进行实践,初学者可以开始为其项目利用它的功能。请记住要注意状态管理、条件边以及确保图中没有死节点。',
'score': 0.7065353,
'raw_content': None},
{'title': 'LangGraph Tutorial: What Is LangGraph and How to Use It?',
'url': 'https://www.datacamp.com/tutorial/langgraph-tutorial',
'content': 'LangGraph 是 LangChain 生态系统中的一个库,它提供了一个框架,用于定义、协调和以结构化且高效的方式执行多个 LLM 代理(或链)。通过管理数据流和操作顺序,LangGraph 允许开发人员专注于应用程序的高层逻辑,而不是代理协调的细节。无论你需要一个能够处理各种用户请求的聊天机器人,还是一个执行复杂任务的多代理系统,LangGraph 都提供了构建所需功能的工具。LangGraph 通过提供一个结构化的框架来管理状态和协调代理交互,显著简化了复杂 LLM 应用程序的开发。',
'score': 0.5008063,
'raw_content': None}],
'response_time': 1.38}

4. 定义图

对于你在第一个教程中创建的 StateGraph,在 LLM 上添加 bind_tools。这可以让 LLM 知道如果它想使用搜索引擎时应该使用的正确 JSON 格式。

让我们首先选择我们的 LLM:


{}

pip install -U "langchain[openai]"
import os
from langchain.chat_models import init_chat_model

os.environ["OPENAI_API_KEY"] = "sk-..."

llm = init_chat_model("openai:gpt-4.1")

pip install -U "langchain[anthropic]"
import os
from langchain.chat_models import init_chat_model

os.environ["ANTHROPIC_API_KEY"] = "sk-..."

llm = init_chat_model("anthropic:claude-3-5-sonnet-latest")

pip install -U "langchain[openai]"
import os
from langchain.chat_models import init_chat_model

os.environ["AZURE_OPENAI_API_KEY"] = "..."
os.environ["AZURE_OPENAI_ENDPOINT"] = "..."
os.environ["OPENAI_API_VERSION"] = "2025-03-01-preview"

llm = init_chat_model(
    "azure_openai:gpt-4.1",
    azure_deployment=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"],
)

pip install -U "langchain[google-genai]"
import os
from langchain.chat_models import init_chat_model

os.environ["GOOGLE_API_KEY"] = "..."

llm = init_chat_model("google_genai:gemini-2.0-flash")

pip install -U "langchain[aws]"
from langchain.chat_models import init_chat_model

# 按照此处的步骤配置您的凭证:
# https://docs.aws.amazon.com/bedrock/latest/userguide/getting-started.html

llm = init_chat_model(
    "anthropic.claude-3-5-sonnet-20240620-v1:0",
    model_provider="bedrock_converse",
)

我们现在可以将其整合到 StateGraph 中:

from typing import Annotated

from typing_extensions import TypedDict

from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages

class State(TypedDict):
    messages: Annotated[list, add_messages]

graph_builder = StateGraph(State)

# 修改:告诉 LLM 它可以调用哪些工具
# highlight-next-line
llm_with_tools = llm.bind_tools(tools)

def chatbot(state: State):
    return {"messages": [llm_with_tools.invoke(state["messages"])]}

graph_builder.add_node("chatbot", chatbot)

5. 创建一个运行工具的函数

现在,创建一个函数,用于在工具被调用时运行这些工具。通过将工具添加到一个新的节点BasicToolNode中来实现这一点,该节点检查状态中的最新消息,并在消息包含tool_calls时调用工具。它依赖于LLM的tool_calling支持功能,该功能在Anthropic、OpenAI、Google Gemini以及一些其他LLM提供商中都可用。

API Reference: ToolMessage

import json

from langchain_core.messages import ToolMessage


class BasicToolNode:
    """一个节点,用于运行最后一条AIMessage中请求的工具。"""

    def __init__(self, tools: list) -> None:
        self.tools_by_name = {tool.name: tool for tool in tools}

    def __call__(self, inputs: dict):
        if messages := inputs.get("messages", []):
            message = messages[-1]
        else:
            raise ValueError("在输入中未找到消息")
        outputs = []
        for tool_call in message.tool_calls:
            tool_result = self.tools_by_name[tool_call["name"]].invoke(
                tool_call["args"]
            )
            outputs.append(
                ToolMessage(
                    content=json.dumps(tool_result),
                    name=tool_call["name"],
                    tool_call_id=tool_call["id"],
                )
            )
        return {"messages": outputs}


tool_node = BasicToolNode(tools=[tool])
graph_builder.add_node("tools", tool_node)

Note

如果你将来不想自己构建这个节点,可以使用LangGraph预构建的 ToolNode

6. 定义 conditional_edges

在添加了工具节点后,现在可以定义 conditional_edges

Edges 控制流程从一个节点流向下一个节点。Conditional edges 从单个节点开始,通常包含 "if" 语句,根据当前图的状态路由到不同的节点。这些函数接收当前图的 state,并返回一个字符串或字符串列表,表示下一步要调用的节点。

接下来,定义一个名为 route_tools 的路由器函数,该函数检查聊天机器人的输出中是否有 tool_calls。通过调用 add_conditional_edges 将此函数提供给图,告诉图每当 chatbot 节点完成时,检查此函数以确定下一步去向。

如果存在工具调用,则条件将路由到 tools;如果没有,则路由到 END。由于条件可以返回 END,因此这次不需要显式设置 finish_point

def route_tools(
    state: State,
):
    """
    在 conditional_edge 中使用,如果最后一条消息有工具调用,则路由到 ToolNode。
    否则,路由到终点。
    """
    if isinstance(state, list):
        ai_message = state[-1]
    elif messages := state.get("messages", []):
        ai_message = messages[-1]
    else:
        raise ValueError(f"在 tool_edge 输入状态中未找到消息:{state}")
    if hasattr(ai_message, "tool_calls") and len(ai_message.tool_calls) > 0:
        return "tools"
    return END


# `tools_condition` 函数如果聊天机器人要求使用工具,则返回 "tools";
# 如果可以直接响应,则返回 "END"。
# 这种条件路由定义了代理的主要循环。
graph_builder.add_conditional_edges(
    "chatbot",
    route_tools,
    # 下面的字典允许你告诉图将条件的输出解释为特定的节点
    # 默认是恒等函数,但如果你想使用除 "tools" 以外的其他命名节点,
    # 可以更新字典的值为其他名称
    # 例如:"tools": "my_tools"
    {"tools": "tools", END: END},
)
# 每当调用工具时,我们返回到 chatbot 以决定下一步
graph_builder.add_edge("tools", "chatbot")
graph_builder.add_edge(START, "chatbot")
graph = graph_builder.compile()

Note

你可以用预构建的 tools_condition 来替代,使代码更简洁。

7. 可视化图(可选)

你可以使用 get_graph 方法和其中一个“绘制”方法,如 draw_asciidraw_png 来可视化图。每个 draw 方法都需要额外的依赖项。

from IPython.display import Image, display

try:
    display(Image(graph.get_graph().draw_mermaid_png()))
except Exception:
    # 这需要一些额外的依赖项,并且是可选的
    pass

chatbot-with-tools-diagram

8. 向机器人提问

现在你可以向聊天机器人提出超出其训练数据范围的问题:

def stream_graph_updates(user_input: str):
    for event in graph.stream({"messages": [{"role": "user", "content": user_input}]}):
        for value in event.values():
            print("Assistant:", value["messages"][-1].content)

while True:
    try:
        user_input = input("User: ")
        if user_input.lower() in ["quit", "exit", "q"]:
            print("Goodbye!")
            break

        stream_graph_updates(user_input)
    except:
        # 如果 input() 不可用时的后备方案
        user_input = "What do you know about LangGraph?"
        print("User: " + user_input)
        stream_graph_updates(user_input)
        break
Assistant: [{'text': "为了为您提供准确且最新的LangGraph信息,我需要搜索最新详情。让我为您查找。", 'type': 'text'}, {'id': 'toolu_01Q588CszHaSvvP2MxRq9zRD', 'input': {'query': 'LangGraph AI tool information'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]
Assistant: [{"url": "https://www.langchain.com/langgraph", "content": "LangGraph为构建和扩展AI工作负载奠定了基础——从对话代理、复杂任务自动化到定制的LLM支持体验,这些都能‘开箱即用’。使用LLM构建复杂生产就绪功能的下一阶段是智能代理,通过LangGraph和LangSmith,LangChain提供了开箱即用的解决方案 ..."}, {"url": "https://github.com/langchain-ai/langgraph", "content": "概述。LangGraph是一个用于构建具有状态、多参与者应用的LLM库,用于创建代理和多代理工作流。与其它LLM框架相比,它提供了这些核心优势:循环、可控性和持久性。LangGraph允许你定义涉及循环的流程,这对于大多数智能代理架构至关重要 ..."}]
Assistant: 根据搜索结果,我可以为您提供有关LangGraph的信息:

1. 目的:
   LangGraph是一个专为使用大型语言模型(LLMs)构建有状态、多参与者应用程序而设计的库。它特别适用于创建代理和多代理工作流。

2. 开发者:
   LangGraph由LangChain开发,这是一家以AI和LLM领域工具及框架闻名的公司。

3. 关键特性:
   - 循环:LangGraph允许定义包含循环的流程,这对大多数智能代理架构至关重要。
   - 可控性:它提供对应用程序流程的增强控制。
   - 持久性:该库提供了在基于LLM的应用程序中维持状态和持久性的方法。

4. 应用场景:
   LangGraph可用于多种应用,包括:
   - 对话代理
   - 复杂任务自动化
   - 定制的LLM支持体验

5. 集成:
   LangGraph与LangChain的另一个工具LangSmith结合使用,为使用LLM构建复杂、生产就绪的功能提供开箱即用的解决方案。

6. 重要性:
...
   LangGraph相较于其他LLM框架,具有独特的优势,尤其是在处理循环、提供可控性和维持持久性方面。

LangGraph在基于LLM的应用程序开发不断演变的领域中显得尤为重要,为开发者提供了创建更复杂、有状态和交互式AI系统的新方法。
Goodbye!
输出被截断。请作为可滚动元素查看或在文本编辑器中打开。调整单元格输出设置...

9. 使用预构建组件

为便于使用,请将代码中以下部分替换为 LangGraph 的预构建组件。这些组件内置了诸如并行执行 API 等功能。


{}

pip install -U "langchain[openai]"
import os
from langchain.chat_models import init_chat_model

os.environ["OPENAI_API_KEY"] = "sk-..."

llm = init_chat_model("openai:gpt-4.1")

pip install -U "langchain[anthropic]"
import os
from langchain.chat_models import init_chat_model

os.environ["ANTHROPIC_API_KEY"] = "sk-..."

llm = init_chat_model("anthropic:claude-3-5-sonnet-latest")

pip install -U "langchain[openai]"
import os
from langchain.chat_models import init_chat_model

os.environ["AZURE_OPENAI_API_KEY"] = "..."
os.environ["AZURE_OPENAI_ENDPOINT"] = "..."
os.environ["OPENAI_API_VERSION"] = "2025-03-01-preview"

llm = init_chat_model(
    "azure_openai:gpt-4.1",
    azure_deployment=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"],
)

pip install -U "langchain[google-genai]"
import os
from langchain.chat_models import init_chat_model

os.environ["GOOGLE_API_KEY"] = "..."

llm = init_chat_model("google_genai:gemini-2.0-flash")

pip install -U "langchain[aws]"
from langchain.chat_models import init_chat_model

# 按照此处的步骤配置您的凭证:
# https://docs.aws.amazon.com/bedrock/latest/userguide/getting-started.html

llm = init_chat_model(
    "anthropic.claude-3-5-sonnet-20240620-v1:0",
    model_provider="bedrock_converse",
)

from typing import Annotated

from langchain_tavily import TavilySearch
from langchain_core.messages import BaseMessage
from typing_extensions import TypedDict

from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode, tools_condition

class State(TypedDict):
    messages: Annotated[list, add_messages]

graph_builder = StateGraph(State)

tool = TavilySearch(max_results=2)
tools = [tool]
llm_with_tools = llm.bind_tools(tools)

def chatbot(state: State):
    return {"messages": [llm_with_tools.invoke(state["messages"])]}

graph_builder.add_node("chatbot", chatbot)

tool_node = ToolNode(tools=[tool])
graph_builder.add_node("tools", tool_node)

graph_builder.add_conditional_edges(
    "chatbot",
    tools_condition,
)
# 每当调用工具时,我们返回到 chatbot 以决定下一步
graph_builder.add_edge("tools", "chatbot")
graph_builder.add_edge(START, "chatbot")
graph = graph_builder.compile()

恭喜! 你已经创建了一个可以在 LangGraph 中使用的会话代理,它可以根据需要使用搜索引擎检索最新信息。现在它可以处理更广泛范围的用户查询。要查看你的代理刚刚采取的所有步骤,请查看这个 LangSmith trace

下一步

聊天机器人无法自行记住过去的交互,这限制了它进行连贯的多轮对话的能力。在接下来的部分中,你将添加**记忆**来解决这个问题。