引言
在上一篇教程中,我们使用 LangGraph 构建了一个简单的 Chatbot。虽然这个 Chatbot 能够处理基本的对话,但在面对一些需要实时信息或超出其知识范围的问题时,它的表现可能会显得力不从心。例如,当用户询问“今天的天气如何?”或“最新的新闻是什么?”时,Chatbot 无法“凭记忆”回答这些问题。
为了解决这个问题,我们可以为 Chatbot 集成一个网络搜索工具 。通过这个工具,Chatbot 可以实时查找相关信息,并提供更准确、更及时的响应。在本教程中,我们将使用 tavily-python
和 langchain_community
库来实现这一功能。
什么是网络搜索工具?
网络搜索工具是一种能够通过 API 访问互联网资源并检索相关信息的工具。通过集成网络搜索工具,Chatbot 可以在对话过程中动态获取外部数据,从而增强其回答能力。例如,当用户询问某个特定话题的最新信息时,Chatbot 可以通过网络搜索工具查找相关内容,并将其整合到对话中。
在本教程中,我们将使用 tavily-python
库来实现网络搜索功能。tavily-python
是一个简单易用的 Python 库,能够快速检索网络上的相关信息。
安装依赖
在开始之前,我们需要安装一些额外的依赖库。你可以通过以下命令安装这些库:
1 pip install -U tavily-python langchain_community
tavily-python : 用于实现网络搜索功能。
langchain_community : 提供与 LangChain 相关的工具和集成。
安装完成后,我们就可以开始集成网络搜索工具了。
定义工具
在 LangGraph 中,工具(Tool)是一种可以扩展 Chatbot 功能的组件。我们可以通过定义工具来实现网络搜索功能。首先,我们需要创建一个工具类,并在其中实现搜索逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 from langchain_community.tools.tavily_search import TavilySearchResultsimport osimport getpassif not os.environ.get("TAVILY_API_KEY" ): os.environ["TAVILY_API_KEY" ] = getpass.getpass("Enter API key for Tavily: " ) tool = TavilySearchResults(max_results=2 ) tools = [tool] tool.invoke("What's a 'node' in LangGraph?" )
在这个例子中,我们定义了一个 TavilySearchResults
工具,它接收一个查询字符串并返回搜索结果。max_results=2
表示每次搜索最多返回 2 个结果。
集成工具到 Chatbot
接下来,我们需要将这个工具集成到 Chatbot 中。我们可以通过修改 Chatbot 的逻辑,使其在遇到无法回答的问题时调用搜索工具。
1 2 3 4 5 6 7 8 9 10 from langchain_openai import ChatOpenAIif not os.environ.get("OPENAI_API_KEY" ): os.environ["OPENAI_API_KEY" ] = getpass.getpass("Enter API key for OpenAI: " ) llm = ChatOpenAI(model="gpt-4o-mini" ,base_url="https://api.chatanywhere.tech/v1" ) llm_with_tools = llm.bind_tools(tools)
在这个例子中,我们使用 bind_tools
方法将工具绑定到语言模型(LLM)。这样,LLM 在生成响应时,可以根据需要调用工具来获取外部信息。
构建增强版对话图
现在,我们可以使用增强版的 Chatbot 函数来构建一个新的对话图。
1 2 3 4 5 6 7 8 9 10 11 from langgraph.graph import StateGraph, START, ENDfrom langgraph.graph.message import add_messagesclass State (TypedDict ): messages: Annotated[list , add_messages] def chatbot (state: State ): return {"messages" : [llm_with_tools.invoke(state["messages" ])]} graph_builder = StateGraph(State) graph_builder.add_node("chatbot" , chatbot)
在这个例子中,我们创建了一个新的对话图,并使用 chatbot
函数作为节点。对话图的结构与之前的版本类似,但 Chatbot 的功能得到了增强。
添加工具节点
为了让 Chatbot 能够调用工具,我们需要添加一个工具节点。这个节点负责执行工具调用,并将结果返回给 Chatbot。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import jsonfrom langchain_core.messages import ToolMessageclass BasicToolNode : 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("No message found in input" ) 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)
在这个例子中,我们定义了一个 BasicToolNode
类,它负责执行工具调用并返回结果。然后,我们将这个工具节点添加到对话图中。
定义路由器函数
为了让 Chatbot 在需要时调用工具,我们需要定义一个路由器函数。这个函数会根据 Chatbot 的输出决定下一步是调用工具还是结束对话。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 def route_tools (state: State ): if isinstance (state, list ): ai_message = state[-1 ] elif messages := state.get("messages" , []): ai_message = messages[-1 ] else : raise ValueError(f"No messages found in input state to tool_edge: {state} " ) if hasattr (ai_message, "tool_calls" ) and len (ai_message.tool_calls) > 0 : return "tools" return END graph_builder.add_conditional_edges( "chatbot" , route_tools, {"tools" : "tools" , END: END}, ) graph_builder.add_edge("tools" , "chatbot" ) graph_builder.add_edge(START, "chatbot" ) graph = graph_builder.compile ()
在这个例子中,route_tools
函数会检查 Chatbot 的输出是否包含工具调用。如果有工具调用,则路由到工具节点;否则,结束对话。
根据上面建边情况,可以得到如下的路由图:
运行增强版 Chatbot
最后,我们可以运行增强版 Chatbot 并观察其行为。通过 graph.stream
方法,我们可以将用户输入传递给 Chatbot,并逐步生成对话。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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 : user_input = "What do you know about LangGraph?" print ("User: " + user_input) stream_graph_updates(user_input) break
在这个例子中,我们创建了一个简单的交互式循环,用户可以输入消息,增强版 Chatbot 会生成响应。如果用户输入 "quit"
、"exit"
或 "q"
,程序将退出。
结论
通过本教程,我们学习了如何为 Chatbot 集成网络搜索工具,从而增强其回答能力。我们定义了搜索工具、修改了 Chatbot 的逻辑,并最终运行了增强版 Chatbot。这个增强版 Chatbot 能够处理更多类型的问题,并提供更准确、更及时的响应。
希望这篇教程对你理解如何增强 Chatbot 的功能有所帮助!如果你有任何问题或建议,欢迎在评论区留言。
作者 : Mudrobot
日期 : 2025.01.24
标签 : LangGraph, Chatbot, 网络搜索, NLP, 自然语言处理