如何在LangChain中利用模板插入链执行结果以实现后续推理
如何在LangChain中利用模板插入链执行结果以实现后续推理
嘿,我明白你现在的困惑——你已经让LLM知道该调用哪些工具了,但不知道怎么把工具返回的结果塞回对话里,让Bob(你的AI)能用这些信息继续唠下去对吧?其实你当前的链只完成了一半:它让LLM生成了工具调用的指令,但没有自动执行工具,也没把结果反馈给模型做后续推理。下面我给你两种解决方案,一种是用LangChain的Agent框架(推荐,省心省力),另一种是手动处理工具调用循环,适合你想自定义流程的场景。
一、推荐方案:用Tool Calling Agent自动处理流程
LangChain的AgentExecutor会帮你自动完成「LLM决定调用工具→执行工具→把结果喂回LLM→生成最终回答」的全流程,还能自动维护对话历史,完美解决你的需求。
修改后的完整代码
from langchain_openai import ChatOpenAI from dotenv import load_dotenv import os from langchain_core.prompts import ChatPromptTemplate from langchain_core.tools import tool from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain_core.chat_history import BaseChatMessageHistory, InMemoryChatMessageHistory from langchain_core.runnables.history import RunnableWithMessageHistory load_dotenv() api_key = os.getenv("OPENAI_API_KEY") if api_key is not None: os.environ["OPENAI_API_KEY"] = api_key else: raise ValueError("OPENAI_API_KEY environment variable is not set.") llm = ChatOpenAI( model="gpt-4o", temperature=0, ) # 调整prompt模板,保留你原来的初始对话,加入agent_scratchpad占位符 template = ChatPromptTemplate.from_messages([ ("system", "You are a helpful AI bot. Your name is Bob. Respond as if you are a cat when answering."), ("human", "Hello, how are you doing?"), ("ai", "I'm doing well, thanks!"), ("human", "{user_input}"), ("placeholder", "{agent_scratchpad}") # 关键:自动填充工具调用及结果的上下文 ]) @tool def weather(city: str) -> str: """Gives the weather in a given city""" return f"The weather in {city} is sunny" @tool def sum_numbers(numbers: str) -> str: """Sums two numbers (input should be two numbers separated by space, e.g., '3 1')""" return str(sum(map(int, numbers.split()))) # 创建工具调用Agent和执行器 agent = create_tool_calling_agent(llm, [weather, sum_numbers], template) agent_executor = AgentExecutor(agent=agent, tools=[weather, sum_numbers], verbose=True) # 配置对话历史存储(用内存模拟,生产环境可换成数据库) store = {} def get_session_history(session_id: str) -> BaseChatMessageHistory: if session_id not in store: store[session_id] = InMemoryChatMessageHistory() return store[session_id] # 包装成带对话历史的链 agent_with_history = RunnableWithMessageHistory( agent_executor, get_session_history, input_messages_key="user_input", history_messages_key="chat_history", ) # 第一次调用:获取天气和求和结果 first_res = agent_with_history.invoke( {"user_input": "What is the weather in Tokyo? also what is 3 + 1? Give me the answer as if you are a cat"}, config={"configurable": {"session_id": "bob_cat_session"}} ) print(first_res["output"]) # 后续对话:基于之前的结果继续推理 second_res = agent_with_history.invoke( {"user_input": "Can you add that sum to 5 and tell me the new total? Also remind me the Tokyo weather again~"}, config={"configurable": {"session_id": "bob_cat_session"}} ) print(second_res["output"])
关键细节说明
{agent_scratchpad}:这个占位符会自动填充工具调用的请求和返回结果,让LLM能基于这些信息继续思考。AgentExecutor:它会自动判断是否需要调用工具,执行工具后把结果反馈给LLM,直到LLM能生成最终回答为止。- 对话历史:通过
RunnableWithMessageHistory维护会话上下文,同一个session_id的调用会共享之前的所有对话和工具结果。
二、手动处理工具调用循环(适合高度自定义)
如果你不想用Agent框架,想完全控制每一步流程,可以手动解析LLM的工具调用请求,执行工具后把结果加入对话历史再重新调用LLM。
示例代码
from langchain_openai import ChatOpenAI from dotenv import load_dotenv import os from langchain_core.prompts import ChatPromptTemplate from langchain_core.tools import tool from langchain_core.messages import AIMessage, ToolMessage load_dotenv() api_key = os.getenv("OPENAI_API_KEY") if api_key is not None: os.environ["OPENAI_API_KEY"] = api_key else: raise ValueError("OPENAI_API_KEY environment variable is not set.") llm = ChatOpenAI( model="gpt-4o", temperature=0, ) # 初始化对话历史 chat_history = [ ("system", "You are a helpful AI bot. Your name is Bob. Respond as if you are a cat when answering."), ("human", "Hello, how are you doing?"), ("ai", "I'm doing well, thanks!") ] @tool def weather(city: str) -> str: """Gives the weather in a given city""" return f"The weather in {city} is sunny" @tool def sum_numbers(numbers: str) -> str: """Sums two numbers (input should be two numbers separated by space, e.g., '3 1')""" return str(sum(map(int, numbers.split()))) # 第一步:用户提问,加入对话历史 user_input = "What is the weather in Tokyo? also what is 3 + 1? Give me the answer as if you are a cat" chat_history.append(("human", user_input)) # 让LLM生成工具调用请求 template = ChatPromptTemplate.from_messages(chat_history) chain = template | llm.bind_tools([weather, sum_numbers]) llm_response = chain.invoke({}) # 解析并执行工具调用 if llm_response.tool_calls: tool_results = [] for tool_call in llm_response.tool_calls: tool_name = tool_call["name"] tool_args = tool_call["args"] # 执行对应工具 if tool_name == "weather": result = weather.invoke(tool_args) elif tool_name == "sum_numbers": # 适配工具输入格式,把3+1转换成"3 1" result = sum_numbers.invoke("3 1") else: result = f"Tool {tool_name} not found" # 包装成ToolMessage,让LLM识别为工具返回结果 tool_results.append(ToolMessage(content=result, tool_call_id=tool_call["id"])) # 更新对话历史:加入AI的工具调用指令和工具结果 chat_history.append(AIMessage(content="", tool_calls=llm_response.tool_calls)) chat_history.extend(tool_results) # 第二步:基于更新后的对话历史生成最终回答 final_template = ChatPromptTemplate.from_messages(chat_history) final_chain = final_template | llm final_response = final_chain.invoke({}) print(final_response.content) # 把最终回答加入历史,用于后续对话 chat_history.append(AIMessage(content=final_response.content))
关键细节说明
- 手动解析
llm_response.tool_calls字段,获取要调用的工具和参数。 - 用
ToolMessage包装工具结果,确保LLM能正确识别这是工具返回的信息。 - 每次对话后更新
chat_history,为下一轮推理提供上下文。
备注:内容来源于stack exchange,提问作者Norhther
相关产品推荐
相关产品推荐

