基于LangGraph和Ollama实现可调用AI搜索引擎Tavily的Agentic RAG问答机器人

ops/2025/2/22 23:02:39/

这篇博客将和大家分享如何快速实现一个运行逻辑相较于传统链式RAG(用户询问 -> 检索相关信息作为上下文 -> LLM推理回复)更为智能、适应性更强的Agentic RAG Chatbot(实现思路参考 Langgraph Agentic RAG 实现官方文档教程)。该 Chatbot 基于Langgraph、Ollama以及提供搜索引擎服务的Tavily作为可调用的外部工具进行实现。

我们希望达成的目标是,该Chatbot可以:1. 根据用户询问判断是否需要调用外部工具(Tavily 搜索引擎);2. 若使用工具,需要基于调用工具后拿取到的信息,用LLM进一步判断用该信息作为回答用户询问的上下文是否足够;3. 如果获取的上下文信息不足,则进入到rewrite node对用户提问进行优化重写;4. 重写提问后,继续回到第一步判断,直到上下文信息足够,LLM进行推理回复用户提问,结束本轮对话。

Graph 图如下所示:
请添加图片描述

Graph 图中有四个关键节点,分别是 agent, retrieve, rewritegenerate,以及由 agentretrieve 这两个节点延展出的conditional edges。接下来对这些节点各自的功能和条件边做一下简单介绍:

Node

  1. agent:基于支持tool使用的LLM,根据用户询问判断是否需要调用外部工具;若不需要则直接推理回复。
  2. retrieve:外部工具,Tavily 搜索引擎,用于获取回复用户提问需要的外部信息。
  3. rewrite:基于LLM和提示词工程实现,将用户初始提问进行re-phrase。
  4. generate:基于LLM和提示词工程,将 retrieve 节点获取到的信息作为context,回复用户提问。

Conditional Edges

  1. from agent:判断是否需要调用工具
  2. from retrieve:判断目前获取到的信息是否足以很好回答用户询问,如不是则走到 rewrite 节点;否则走到 generate 节点。

代码实现

  1. 导入所需python库;
from langchain_ollama import ChatOllama
from typing import Annotated, Sequence
from typing_extensions import TypedDict
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages
from typing import Annotated, Literal, Sequence
from typing_extensions import TypedDict
from langchain import hub
from langchain_core.messages import BaseMessage, HumanMessage
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
# from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field
from langgraph.prebuilt import tools_condition
from langgraph.graph import END, StateGraph, START
from langgraph.prebuilt import ToolNode
import pprint
from langchain_community.tools.tavily_search import TavilySearchResults
  1. 定义用于表示graph状态的类;

关于创建State类的详细解释,有需要可移步至 基于LangGraph、Groq和Tavily打造可以调用外部搜索引擎工具的对话机器人 这篇博客进行了解。

class AgentState(TypedDict):# The add_messages function defines how an update should be processed# Default is to replace. add_messages says "append"messages: Annotated[Sequence[BaseMessage], add_messages]
  1. 创建名为 retrieve 的 tool node;
# 调用 Tavily 检索服务,max_results 参数值设置为2,即每次调用返回两个检索结果
tool = TavilySearchResults(max_results=2)
tools = [tool]
retrieve = ToolNode(tools)
  1. 用函数的方式创建 agent 节点(注释由 chatGPT-4o 生成);

在这个函数中,我们使用了 Ollama 提供LLM推理服务。需要特别注意的是关于模型的选择,需要能够支持 Tool 使用的,比如 llama3.1mistral-nemo 等等。具体哪些模型支持可以在 Ollama 官网 上进行查询和选择。

def agent(state):"""调用代理模型根据当前状态生成响应。根据问题,它将决定使用检索工具检索信息,或简单地结束。参数:state (messages): 当前状态返回:dict: 更新后的状态,其中附加了代理响应到消息中"""print("---CALL AGENT---")  # 打印调用代理的标识信息messages = state["messages"]  # 从状态中提取当前消息列表# 创建一个ChatOllama模型实例,指定使用"llama3.1:latest"版本,并设置温度参数为0.8model = ChatOllama(model="llama3.1:latest", temperature=0.8)# 将工具绑定到模型中,以便模型可以使用这些工具进行信息检索model = model.bind_tools(tools)# 调用模型以生成响应,传入当前的消息列表response = model.invoke(messages)# 返回一个字典,其中“messages”键对应一个列表,该列表包含新生成的响应# 这个列表将被添加到现有消息列表中return {"messages": [response]}
  1. 用函数的方式创建 rewrite 节点(注释由 chatGPT-4o 生成);

rewrite 节点的功能实现中,也用到了LLM推理,这里的模型不需要具备 tool 的支持能力,所以可以使用和 agent 节点中不一样的模型。(示例代码中还是使用了 llama3.1

def rewrite(state):"""转换查询以生成一个更好的问题。参数:state (messages): 当前状态返回:dict: 更新后的状态,其中包含重新措辞的问题"""print("---TRANSFORM QUERY---")  # 打印转换查询的标识信息messages = state["messages"]  # 从状态中提取当前消息列表question = messages[0].content  # 获取消息列表中的第一个问题的内容# 构建一个新的消息列表,包含用户输入提示msg = [HumanMessage(content=f""" \n 查看输入并尝试推理其潜在的语义意图/含义。 \n 这是最初的问题:\n ------- \n{question} \n ------- \n制定一个改进后的问题: """,)]# 创建一个ChatOllama模型实例,指定使用"llama3.1:latest"版本,并设置温度参数为0.8model = ChatOllama(model="llama3.1:latest", temperature=0.8)# 调用模型以生成响应,传入构建的消息列表response = model.invoke(msg)# 返回一个字典,其中“messages”键对应一个列表,该列表包含模型生成的改进问题return {"messages": [response]}
  1. 用函数的方式创建 generate 节点(注释由 chatGPT-4o 生成);

和上一步创建的 rewrite 节点同理,这里面使用的LLM也不需要具备 tool 的支持能力,可以根据需要选择其他模型。

def generate(state):"""生成答案。参数:state (messages): 当前状态返回:dict: 更新后的状态,其中包含生成的答案"""print("---GENERATE---")  # 打印生成过程的标识信息messages = state["messages"]  # 从状态中提取当前消息列表question = messages[0].content  # 获取消息列表中的第一个问题的内容last_message = messages[-1]  # 获取消息列表中的最后一条消息docs = last_message.content  # 从最后一条消息中提取内容作为文档# 提示prompt = hub.pull("rlm/rag-prompt")  # 从hub中拉取名为“rlm/rag-prompt”的提示# 大语言模型 (LLM)llm = ChatOllama(model="llama3.1:latest", temperature=0.8)  # 创建一个ChatOllama模型实例# 后处理函数def format_docs(docs):# 将文档中的页面内容用两个换行符分隔并连接成字符串return "\n\n".join(doc.page_content for doc in docs)# 链式调用rag_chain = prompt | llm | StrOutputParser()  # 创建一个链式结构,将提示、LLM和输出解析器连接# 运行response = rag_chain.invoke({"context": docs, "question": question})  # 调用链式结构并传入上下文和问题# 返回一个字典,其中“messages”键对应一个列表,该列表包含生成的响应return {"messages": [response]}
  1. 创建出发自 agent 节点的 condition edges;

代码实现见后续graph的搭建。因为 agent 节点的条件边是判断是否需要使用tool,可以直接使用 langgraph 中提前实现的 tools_condition,在第1步中已经导入。

from langgraph.prebuilt import tools_condition
  1. 创建出发自 retrieve 节点的conditional edges(注释由 chatGPT-4o 生成);

retrieve 节点的条件边用来决定 which is the next node to go,具体是通过 grade_documents() 这个函数来实现的。该函数通过提示词工程以及将LLM输出结构化等技术,将其作为一个基于用户提问,判断上下文信息是否与提问相关的二元评分器;然后基于评分结果,决定下一个node的选择,是 generate 还是 rewrite

def grade_documents(state) -> Literal["generate", "rewrite"]:"""判断检索到的文档是否与问题相关。参数:state (messages): 当前状态返回:str: 决定文档是否相关的结果"""print("---CHECK RELEVANCE---")  # 打印检查相关性的标识信息# 数据模型class grade(BaseModel):"""用于相关性检查的二元评分。"""binary_score: str = Field(description="相关性评分 'yes' 或 'no'")# 大语言模型 (LLM)model = ChatOllama(model="llama3.1:latest", temperature=0.8)  # 创建一个ChatOllama模型实例# 使用工具和验证的LLMllm_with_tool = model.with_structured_output(grade)  # 将模型与结构化输出结合# 提示模板prompt = PromptTemplate(template="""你是一名评估员,负责评估检索到的文档与用户问题的相关性。 \n 这是检索到的文档: \n\n {context} \n\n这是用户的问题: {question} \n如果文档包含与用户问题相关的关键词或语义含义,请将其评定为相关。 \n给出一个二元评分 'yes' 或 'no',以指示文档是否与问题相关。""",input_variables=["context", "question"],)# 链式调用chain = prompt | llm_with_tool  # 创建一个链式结构,将提示和带工具的模型连接messages = state["messages"]  # 从状态中提取当前消息列表last_message = messages[-1]  # 获取消息列表中的最后一条消息question = messages[0].content  # 获取消息列表中的第一个问题的内容docs = last_message.content  # 从最后一条消息中提取文档内容scored_result = chain.invoke({"question": question, "context": docs})  # 调用链式结构并传入问题和上下文score = scored_result.binary_score  # 获取评分结果if score == "yes":print("---DECISION: DOCS RELEVANT---")  # 打印文档相关的决策信息return "generate"  # 返回“generate”表示文档相关else:print("---DECISION: DOCS NOT RELEVANT---")  # 打印文档不相关的决策信息print(score)  # 打印评分return "rewrite"  # 返回“rewrite”表示文档不相关
  1. 创建 Graph(注释由 chatGPT-4o 生成);
# 定义一个新的状态图
workflow = StateGraph(AgentState)# 定义我们将在其中循环的节点
workflow.add_node("agent", agent)  # 代理节点
retrieve = ToolNode(tools)  # 检索节点,使用工具
workflow.add_node("retrieve", retrieve)  # 添加检索节点
workflow.add_node("rewrite", rewrite)  # 重新措辞问题的节点
workflow.add_node("generate", generate
)  # 在确认文档相关后生成响应的节点# 调用代理节点以决定是否进行检索
workflow.add_edge(START, "agent")  # 从起始节点到代理节点的边# 决定是否进行检索
workflow.add_conditional_edges("agent",# 评估代理决策tools_condition,{# 将条件输出转换为我们图中的节点"tools": "retrieve",  # 如果条件满足,转到检索节点END: END,  # 否则,结束},
)# 在调用`retrieve`节点后采取的边
workflow.add_conditional_edges("retrieve",# 评估文档相关性grade_documents,
)workflow.add_edge("generate", END)  # 生成节点到结束的边
workflow.add_edge("rewrite", "agent")  # 重新措辞节点返回代理节点# 编译
graph = workflow.compile()  # 编译状态图以生成可执行的工作流
  1. 提问,检验问答效果;

用英文询问当前北京的天气如何。

user_query = "how is the current weather in Beijing city?"inputs = {"messages": [("user", user_query),]
}
for output in graph.stream(inputs):for key, value in output.items():pprint.pprint(f"Output from node '{key}':")pprint.pprint("---")pprint.pprint(value, indent=2, width=80, depth=None)pprint.pprint("\n---\n")

状态图中被执行后的节点产生的 messages 内容打印如下:

(可以看出graph的运行路径是:input -> agent节点 -> retrieve节点 -> generate节点 -> END;暂时没有涉及到 rewrite。)

---CALL AGENT---
"Output from node 'agent':"
'---'
{ 'messages': [ AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'llama3.1:latest', 'created_at': '2025-02-18T07:29:16.232338Z', 'done': True, 'done_reason': 'stop', 'total_duration': 5865025625, 'load_duration': 1112864375, 'prompt_eval_count': 197, 'prompt_eval_duration': 3894000000, 'eval_count': 24, 'eval_duration': 855000000, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-9e83acda-bfc5-4991-a9d2-265e187c801d-0', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': 'Beijing current weather'}, 'id': 'a1717377-a6ac-4c72-84f2-cbbda0685b23', 'type': 'tool_call'}], usage_metadata={'input_tokens': 197, 'output_tokens': 24, 'total_tokens': 221})]}
'\n---\n'
---CHECK RELEVANCE---
---DECISION: DOCS RELEVANT---
"Output from node 'retrieve':"
'---'
{ 'messages': [ ToolMessage(content='[{"url": "https://www.weatherapi.com/", "content": "{\'location\': {\'name\': \'Beijing\', \'region\': \'Beijing\', \'country\': \'China\', \'lat\': 39.9289, \'lon\': 116.3883, \'tz_id\': \'Asia/Shanghai\', \'localtime_epoch\': 1739863764, \'localtime\': \'2025-02-18 15:29\'}, \'current\': {\'last_updated_epoch\': 1739862900, \'last_updated\': \'2025-02-18 15:15\', \'temp_c\': 6.3, \'temp_f\': 43.3, \'is_day\': 1, \'condition\': {\'text\': \'Sunny\', \'icon\': \'//cdn.weatherapi.com/weather/64x64/day/113.png\', \'code\': 1000}, \'wind_mph\': 7.8, \'wind_kph\': 12.6, \'wind_degree\': 330, \'wind_dir\': \'NNW\', \'pressure_mb\': 1029.0, \'pressure_in\': 30.39, \'precip_mm\': 0.0, \'precip_in\': 0.0, \'humidity\': 11, \'cloud\': 0, \'feelslike_c\': 3.7, \'feelslike_f\': 38.7, \'windchill_c\': 3.4, \'windchill_f\': 38.1, \'heatindex_c\': 6.0, \'heatindex_f\': 42.8, \'dewpoint_c\': -23.3, \'dewpoint_f\': -9.9, \'vis_km\': 10.0, \'vis_miles\': 6.0, \'uv\': 1.1, \'gust_mph\': 9.2, \'gust_kph\': 14.8}}"}, {"url": "https://www.meteoprog.com/weather/Beijing/month/february/", "content": "Beijing weather in February 2025 ⋆ Beijing temperature in February ≡ Weather forecast in China | METEOPROG Weather in China Weather Widgets Русский (UA) Русский WEATHER 7-day Forecast Weather on a map Weather Widget Русский (UA) Русский 2 Weeks Beijing weather in February 2025 February in Beijing Max. temperature +23°C Min. temperature -24.1°C +1° +7° -3° +4° +17° +17° -3° -4° +4° +3° +18° -1° -14° +17° Weather Weather in China Monthly weather forecast in Beijing Weather in February 2 Weeks Weather Widgets Editorial policy Hyperlink to Meteoprog.com is required when using materials from the site. The editorial staff of the project may not share the opinion of the authors and is not responsible for copyrighted materials. Русский (UA) Русский"}]', name='tavily_search_results_json', id='14b19aee-92ad-4b80-b146-b4d3ed05ca67', tool_call_id='a1717377-a6ac-4c72-84f2-cbbda0685b23', artifact={'query': 'Beijing current weather', 'follow_up_questions': None, 'answer': None, 'images': [], 'results': [{'title': 'Weather in Beijing', 'url': 'https://www.weatherapi.com/', 'content': "{'location': {'name': 'Beijing', 'region': 'Beijing', 'country': 'China', 'lat': 39.9289, 'lon': 116.3883, 'tz_id': 'Asia/Shanghai', 'localtime_epoch': 1739863764, 'localtime': '2025-02-18 15:29'}, 'current': {'last_updated_epoch': 1739862900, 'last_updated': '2025-02-18 15:15', 'temp_c': 6.3, 'temp_f': 43.3, 'is_day': 1, 'condition': {'text': 'Sunny', 'icon': '//cdn.weatherapi.com/weather/64x64/day/113.png', 'code': 1000}, 'wind_mph': 7.8, 'wind_kph': 12.6, 'wind_degree': 330, 'wind_dir': 'NNW', 'pressure_mb': 1029.0, 'pressure_in': 30.39, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 11, 'cloud': 0, 'feelslike_c': 3.7, 'feelslike_f': 38.7, 'windchill_c': 3.4, 'windchill_f': 38.1, 'heatindex_c': 6.0, 'heatindex_f': 42.8, 'dewpoint_c': -23.3, 'dewpoint_f': -9.9, 'vis_km': 10.0, 'vis_miles': 6.0, 'uv': 1.1, 'gust_mph': 9.2, 'gust_kph': 14.8}}", 'score': 0.9327485, 'raw_content': None}, {'url': 'https://www.meteoprog.com/weather/Beijing/month/february/', 'title': 'Beijing weather in February 2025 - Meteoprog.com', 'content': 'Beijing weather in February 2025 ⋆ Beijing temperature in February ≡ Weather forecast in China | METEOPROG Weather in China Weather Widgets Русский (UA) Русский WEATHER 7-day Forecast Weather on a map Weather Widget Русский (UA) Русский 2 Weeks Beijing weather in February 2025 February in Beijing Max. temperature +23°C Min. temperature -24.1°C +1° +7° -3° +4° +17° +17° -3° -4° +4° +3° +18° -1° -14° +17° Weather Weather in China Monthly weather forecast in Beijing Weather in February 2 Weeks Weather Widgets Editorial policy Hyperlink to Meteoprog.com is required when using materials from the site. The editorial staff of the project may not share the opinion of the authors and is not responsible for copyrighted materials. Русский (UA) Русский', 'score': 0.8934678, 'raw_content': None}], 'response_time': 1.76})]}
'\n---\n'
---GENERATE---
"Output from node 'generate':"
'---'
{ 'messages': [ 'The current weather in Beijing city is sunny with a ''temperature of 6.3°C, according to the provided weather data ''from WeatherAPI. The wind is blowing at 12.6 km/h from the ''NNW direction. The humidity is 11%.']}
'\n---\n'

如果使用了 langsmith 则可以看到更为直观的状态图运行路径和每个被运行节点的输入输出内容。

请添加图片描述

完整代码

from langchain_ollama import ChatOllama
from typing import Annotated, Sequence
from typing_extensions import TypedDict
from langchain_core.messages import BaseMessage
from langgraph.graph.message import add_messages
from typing import Annotated, Literal, Sequence
from typing_extensions import TypedDict
from langchain import hub
from langchain_core.messages import BaseMessage, HumanMessage
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from pydantic import BaseModel, Field
from langgraph.prebuilt import tools_condition
from langgraph.graph import END, StateGraph, START
from langgraph.prebuilt import ToolNode
import pprint
from langchain_community.tools.tavily_search import TavilySearchResults# 工具定义,使用Tavily搜索结果,最多返回两个结果
tool = TavilySearchResults(max_results=2)
tools = [tool]# 定义AgentState类,管理消息的状态
class AgentState(TypedDict):messages: Annotated[Sequence[BaseMessage], add_messages]  # 添加消息的策略是追加# 定义函数判断文档是否与问题相关
def grade_documents(state) -> Literal["generate", "rewrite"]:"""判断检索到的文档是否与问题相关。参数:state (messages): 当前状态返回:str: 决定文档是否相关的结果"""print("---CHECK RELEVANCE---")# 数据模型class grade(BaseModel):"""用于相关性检查的二元评分。"""binary_score: str = Field(description="相关性评分 'yes' 或 'no'")# 创建一个ChatOllama模型实例model = ChatOllama(model="llama3.1:latest", temperature=0.8)llm_with_tool = model.with_structured_output(grade)  # 使用工具和验证的LLM# 提示模板prompt = PromptTemplate(template="""你是一名评估员,负责评估检索到的文档与用户问题的相关性。 \n 这是检索到的文档: \n\n {context} \n\n这是用户的问题: {question} \n如果文档包含与用户问题相关的关键词或语义含义,请将其评定为相关。 \n给出一个二元评分 'yes' 或 'no',以指示文档是否与问题相关。""",input_variables=["context", "question"],)# 创建链式结构,将提示和带工具的模型连接chain = prompt | llm_with_toolmessages = state["messages"]  # 从状态中提取当前消息列表last_message = messages[-1]  # 获取消息列表中的最后一条消息question = messages[0].content  # 获取消息列表中的第一个问题的内容docs = last_message.content  # 从最后一条消息中提取文档内容scored_result = chain.invoke({"question": question, "context": docs})  # 调用链式结构并传入问题和上下文score = scored_result.binary_score  # 获取评分结果if score == "yes":print("---DECISION: DOCS RELEVANT---")  # 打印文档相关的决策信息return "generate"  # 返回“generate”表示文档相关else:print("---DECISION: DOCS NOT RELEVANT---")  # 打印文档不相关的决策信息print(score)  # 打印评分return "rewrite"  # 返回“rewrite”表示文档不相关# 定义函数用于调用代理模型生成响应
def agent(state):"""调用代理模型根据当前状态生成响应。根据问题,它将决定使用检索工具检索信息,或简单地结束。参数:state (messages): 当前状态返回:dict: 更新后的状态,其中附加了代理响应到消息中"""print("---CALL AGENT---")messages = state["messages"]  # 从状态中提取当前消息列表model = ChatOllama(model="llama3.1:latest", temperature=0.8)  # 创建一个ChatOllama模型实例model = model.bind_tools(tools)  # 将工具绑定到模型中response = model.invoke(messages)  # 调用模型以生成响应return {"messages": [response]}  # 返回一个字典,其中“messages”键对应一个列表,该列表包含新生成的响应# 定义函数用于转换查询生成更好的问题
def rewrite(state):"""转换查询以生成一个更好的问题。参数:state (messages): 当前状态返回:dict: 更新后的状态,其中包含重新措辞的问题"""print("---TRANSFORM QUERY---")messages = state["messages"]  # 从状态中提取当前消息列表question = messages[0].content  # 获取消息列表中的第一个问题的内容# 构建一个新的消息列表,包含用户输入提示msg = [HumanMessage(content=f""" \n 查看输入并尝试推理其潜在的语义意图/含义。 \n 这是最初的问题:\n ------- \n{question} \n ------- \n制定一个改进后的问题: """,)]model = ChatOllama(model="llama3.1:latest", temperature=0.8)  # 创建一个ChatOllama模型实例response = model.invoke(msg)  # 调用模型以生成响应return {"messages": [response]}  # 返回一个字典,其中“messages”键对应一个列表,该列表包含模型生成的改进问题# 定义函数用于生成答案
def generate(state):"""生成答案。参数:state (messages): 当前状态返回:dict: 更新后的状态,其中包含生成的答案"""print("---GENERATE---")messages = state["messages"]  # 从状态中提取当前消息列表question = messages[0].content  # 获取消息列表中的第一个问题的内容last_message = messages[-1]  # 获取消息列表中的最后一条消息docs = last_message.content  # 从最后一条消息中提取内容作为文档# 提示prompt = hub.pull("rlm/rag-prompt")  # 从hub中拉取名为“rlm/rag-prompt”的提示llm = ChatOllama(model="llama3.1:latest", temperature=0.8)  # 创建一个ChatOllama模型实例# 后处理函数def format_docs(docs):# 将文档中的页面内容用两个换行符分隔并连接成字符串return "\n\n".join(doc.page_content for doc in docs)# 链式调用rag_chain = prompt | llm | StrOutputParser()  # 创建一个链式结构,将提示、LLM和输出解析器连接# 运行response = rag_chain.invoke({"context": docs, "question": question})  # 调用链式结构并传入上下文和问题return {"messages": [response]}  # 返回一个字典,其中“messages”键对应一个列表,该列表包含生成的响应print("*" * 20 + "Prompt[rlm/rag-prompt]" + "*" * 20)
prompt = hub.pull("rlm/rag-prompt").pretty_print()  # 打印提示模板# 定义一个新的状态图
workflow = StateGraph(AgentState)# 定义我们将在其中循环的节点
workflow.add_node("agent", agent)  # 代理节点
retrieve = ToolNode(tools)  # 检索节点,使用工具
workflow.add_node("retrieve", retrieve)  # 添加检索节点
workflow.add_node("rewrite", rewrite)  # 重新措辞问题的节点
workflow.add_node("generate", generate)  # 在确认文档相关后生成响应的节点# 调用代理节点以决定是否进行检索
workflow.add_edge(START, "agent")  # 从起始节点到代理节点的边# 决定是否进行检索
workflow.add_conditional_edges("agent",# 评估代理决策tools_condition,{# 将条件输出转换为我们图中的节点"tools": "retrieve",  # 如果条件满足,转到检索节点END: END,  # 否则,结束},
)# 在调用`action`节点后采取的边
workflow.add_conditional_edges("retrieve",# 评估文档相关性grade_documents,
)
workflow.add_edge("generate", END)  # 生成节点到结束的边
workflow.add_edge("rewrite", "agent")  # 重新措辞节点返回代理节点# 编译状态图以生成可执行的工作流
graph = workflow.compile()user_query = "how is the current weather in Beijing city?"
# user_query = "What does Lilian Weng say about the types of agent memory?"inputs = {"messages": [("user", user_query),]
}
# 处理用户输入并输出结果
for output in graph.stream(inputs):for key, value in output.items():pprint.pprint(f"Output from node '{key}':")pprint.pprint("---")pprint.pprint(value, indent=2, width=80, depth=None)pprint.pprint("\n---\n")

相关阅读

[1] LangSmith 简单使用说明

[2] LangGraph 通过in-memory持久化实现多轮对话能力Chatbot

[3] 使用LangChain自定义tools的三种方式


http://www.ppmy.cn/ops/160620.html

相关文章

com.alibaba.fastjson.JSONException: parseDecimal error, field

json.toJavaObject报这个错。 com.alibaba.fastjson.JSONException: parseDecimal error, field 一开始觉得报文的json里的key是少于java实体的,所以以为是key少取不到,所以报错,但是名称是一看转换报错的问题。 最后debug确实也是这样的问…

OSPF协议五种网络类型中DR和BDR选举说明

OSPF协议五种网络类型中DR和BDR选举说明 OSPF链路类型有3种:点到点,广播型,NBMA(非广播-多路访问网络(Non-Broadcast Multiple Access,NBMA))。 在3种链路类型上扩展出5种网络类型:点到点&…

网络运维学习笔记 017HCIA-Datacom综合实验01

文章目录 综合实验1实验需求总部特性 分支8分支9 配置一、 基本配置(IP二层VLAN链路聚合)ACC_SWSW-S1SW-S2SW-Ser1SW-CoreSW8SW9DHCPISPGW 二、 单臂路由GW 三、 vlanifSW8SW9 四、 OSPFSW8SW9GW 五、 DHCPDHCPGW 六、 NAT缺省路由GW 七、 HTTPGW 综合实…

Huggingface简介和基础使用指南(抱脸)(NLP公司、Transformers库、Huggingface Hub)

文章目录 Huggingface 是什么?基础使用步骤(命令行版)1️⃣ 环境准备2️⃣ 账户认证3️⃣ 仓库管理4️⃣ 文件操作5️⃣ 调用模型 新手须知 Huggingface 是什么? Huggingface 是专注于自然语言处理(NLP)的…

Excell 代码处理

文章目录 Excell 代码处理cvc格式xlsl格式小结 Excell 代码处理 有时候要对excell进行分析,或者数据的导入导出,这个时候如果可以用代码读写分析操作那么会方便很多 cvc格式 CSV(Comma-Separated Values,逗号分隔值)是…

小狐狸ai3.1.2版本源码无授权版本内 含搭建教程+各种上线教程

内容目录 一、详细介绍小狐狸3.1.2版本源码,新增deepseek接口 文件夹说明: 1、后端:文件夹是后台文件 5、.sql文件是数据库文件后台安装步骤: 1、在宝塔新建个站点,php版本使用7.4,将“后端”文件夹里的文件…

设计模式教程:命令模式(Command Pattern)

1. 什么是命令模式? 命令模式(Command Pattern)是一种行为型设计模式。它将请求封装成一个对象,从而使你能够用不同的请求、队列和日志请求以及支持可撤销操作。 简单来说,命令模式通过把请求封装成对象的方式解耦了…

vue2.x 中父组件通过props向子组件传递数据详细解读

1. 父组件向子组件传递数据的步骤 在子组件中定义 props: 子组件通过 props 选项声明它期望接收的数据。props 可以是数组形式(简单声明)或对象形式(支持类型检查和默认值)。 在父组件中使用子组件时绑定 props&#x…