[智能体-229]:LangChain 工具调用原理 + 两类代码示例(传统 Agent / LCEL 原生 bind_tools,推荐 LCEL)
结合前面硬件类比:
工具调用 = LLM (CPU) 发起网卡网络请求,向外获取外部数据 / 算力;
RAG 是本地硬盘读数据,Tool 是跨网拉取外部资源。
一、工具调用核心原理
- 工具定义:封装外部能力(查天气、计算器、SQL、HTTP 接口),具备名字、功能描述、入参格式;
- 工具绑定 LLM:把工具列表注入大模型,LLM 识别用户问题缺信息时,输出结构化工具调用 JSON;工具注入大模型之后,大模型就可以在理解自然语言语义之后知道如何调用外部工具。
- 解析 + 执行工具:框架截取模型输出的工具名 + 参数,调用对应函数拿到结果;
- 工具结果回灌上下文:把返回数据拼入 Prompt,再次送入 LLM 生成最终答案。
二、环境依赖
bash
运行
pip install langchain langchain-openaipython
运行
from langchain_openai import ChatOpenAI from langchain_core.tools import tool from langchain_core.messages import HumanMessage, ToolMessage方式 1:LCEL 原生工具调用(新项目首选,RISC 思想,无黑盒)
1. 自定义工具(计算器示例)
python
运行
# 装饰器快速定义工具 @tool def calculator(a: float, b: float, op: str) -> float: """ 数学计算器,支持加减乘除 :param a: 第一个数字 :param b: 第二个数字 :param op: 运算符,可选 + - * / """ if op == "+": return a + b elif op == "-": return a - b elif op == "*": return a * b elif op == "/": return a / b else: raise ValueError("运算符非法") tools = [calculator]2. LLM 绑定工具
python
运行
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0) # bind_tools:把工具元数据注入模型,原生输出function_call llm_with_tools = llm.bind_tools(tools)3. 完整一轮工具调用链路
python
运行
query = "123加456等于多少?" msg = [HumanMessage(content=query)] # 第一步:模型生成工具调用指令,由大模型生成调用指令指示。 ai_msg = llm_with_tools.invoke(msg) msg.append(ai_msg) # 第二步:由Agent负责遍历工具调用、调用执行函数,并把执行的结果添加的消息列表中 for tool_call in ai_msg.tool_calls: name = tool_call["name"] args = tool_call["args"] # 根据名字匹配工具 tool_func = globals()[name] res = tool_func(**args) # 工具执行结果封装成ToolMessage塞回消息列表 msg.append(ToolMessage(content=str(res), tool_call_id=tool_call["id"])) # 第三步:携带工具结果再次调用LLM生成最终答案 final_ans = llm_with_tools.invoke(msg) print(final_ans.content)输出:
plaintext
123加上456的结果是579。方式 2:传统 OpenAI Agent(旧版预定义 Chain/CISC 黑盒,老项目维护用)
python
运行
from langchain.agents import AgentExecutor, create_openai_tools_agent prompt = ChatPromptTemplate.from_messages([ ("system", "你是擅长使用工具的助手"), ("user", "{input}") ]) # 构造Agent链 agent = create_openai_tools_agent(llm, tools, prompt) agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) res = agent_executor.invoke({"input": "78乘以9等于多少"}) print(res["output"])三、拓展:多工具混合(计算器 + 查字符串长度)
python
运行
@tool def str_len(s: str) -> int: """获取字符串长度 :param s: 输入字符串 """ return len(s) tools = [calculator, str_len] # 重新绑定工具 llm_with_tools = llm.bind_tools(tools)提问:"abcdef有几个字符,100除以20是多少",模型会自动拆分两次工具调用。
四、关键知识点(贴合之前架构类比)
- LCEL bind_tools:原子化,工具绑定、调用、结果拼接全流程白盒可控(ARM 精简指令);
- 传统 AgentExecutor:整套思考 + 调用逻辑内部封装黑盒(x86 CISC 复合指令);
- Tool ≈ 网卡外设:不在 LLM 上下文 / 内存 / RAG 硬盘中,需要跨外部系统实时获取数据;
- LangGraph 场景:复杂多轮循环工具调用(思考→调用→结果→再思考),用 LangGraph 替代手动循环。
五、生产常用扩展
- 第三方工具:LangChain 内置
WikipediaQueryRun、DuckDuckGoSearchRun搜索引擎工具; - 工具异常:
with_fallbacks做工具调用失败降级; - 流式工具调用:
astream分段捕获模型输出的工具参数。
