[智能体-230]:Tools 绑定 LLM 而非 Chain:原理 + 类比 + 完整代码详解
一、核心结论承接前面 CPU 类比Tools 挂载在 LLM (CPU) 上不绑定 Chain (指令流水线)LLM CPU 运算核心bind_tools(tools)等价于CPU 挂载外设驱动网卡 / 外设模型自身永久携带工具 Schema具备自主生成tool_call调用指令的能力Chain 指令执行流水线Chain只负责消息流转、输入输出拼接不存储、不持有工具定义同一份带工具的 LLM 可以随意接入 N 条不同 Chain本质边界工具认知权属于模型调度执行权属于链路 Chain。一句话模型知道自己能用什么工具Chain 只负责拿到模型的工具调用指令、去落地执行。二、底层原理bind_tools 到底做了什么llm.bind_tools([tool1,tool2])不会修改 Chain只会生成包装后的新 LLM 实例提取每个 Tool 的name/description/入参JSON Schema封装成大模型 API 规范的 Function 定义每次调用 LLM 时自动随请求参数传入模型服务端LLM 在推理时自主判断需要外部数据→返回AIMessage.tool_calls结构化调用指令不需要→直接返回自然文本Chain 只读取tool_calls字段根据名字去全局工具池匹配并运行函数Chain 本身不存工具列表。关键更换 Prompt / 更换 Chain只要用同一个 bind 过 tools 的 llm模型始终认识全部工具。三、代码实证同一个带工具 LLM复用多条不同 Chain环境依赖bash运行pip install langchain langchain-openaipython运行from langchain_openai import ChatOpenAI from langchain_core.tools import tool from langchain_core.messages import HumanMessage, ToolMessage from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import RunnablePassthrough1. 定义全局工具、绑定到 LLM只绑一次python运行# 全局工具只绑定在LLM和Chain无关 tool def calc_add(a:float,b:float)-float: 加法计算两个数字求和 return ab tool def get_len(s:str)-int: 获取字符串长度 return len(s) tools [calc_add,get_len] # ✅ 工具仅绑定LLM仅此一处绑定 llm_raw ChatOpenAI(modelgpt-3.5-turbo,temperature0) llm_with_tool llm_raw.bind_tools(tools) # 挂载外设后的CPU2. 构建两条完全不同的 Chain共用同一个带工具的 LLMpython运行# Chain1通用问答链Prompt1 prompt1 ChatPromptTemplate.from_messages([(system,简洁回答问题),(user,{query})]) chain_1 prompt1 | llm_with_tool # Chain2专业数据分析链Prompt2和Chain1业务逻辑完全不同 prompt2 ChatPromptTemplate.from_messages([(system,以专业报表格式输出结果),(user,{query})]) chain_2 prompt2 | llm_with_tool重点两条 Chain 没有传入任何 tools 参数但全部继承 LLM 自带的工具能力。3.通用工具执行函数Chain 无工具统一外部智能体调度执行python运行# 全局工具注册表Chain运行时根据模型返回的tool_name查表 tool_map {t.name:t for t in tools} def run_tool_loop(chain_input,chain_runnable): msgs [HumanMessage(contentchain_input[query])] ai_msg chain_runnable.invoke(msgs) # 模型返回工具调用指令Chain本身没有工具去全局map查找 if ai_msg.tool_calls: msgs.append(ai_msg) for call in ai_msg.tool_calls: func tool_map[call[name]] res func.invoke(call[args]) msgs.append(ToolMessage(contentstr(res),tool_call_idcall[id])) final chain_runnable.invoke(msgs) return final.content return ai_msg.content4. 分别调用两条 Chain自动复用 LLM 携带的工具python运行# 调用链1加法需求 res1 run_tool_loop({query:12.537.5等于多少},chain_1) print(链1结果,res1) # 输出链1结果12.5与37.5相加结果为50。 # 调用链2字符串长度需求换Prompt依然能正常调用工具 res2 run_tool_loop({query:字符串langchain有几个字符},chain_2) print(链2结果,res2) # 输出 # 【数据结果报表】 # 目标字符串langchain # 字符总数9现象证明没有给chain_1/chain_2传入任何 tools两条链全部自动拥有工具调用能力修改任意一条 Chain 的 Prompt、链路结构模型工具认知不变因为工具绑定在 LLM 上。四、反例老版 Agent 是把 tools 绑 Chain不推荐CISC 黑盒老版create_openai_tools_agent是工具随 Chain 绑定每条 Agent Chain 单独持有一份 tools换链就要重新传 tools违背 LCEL 原子化设计python运行from langchain.agents import create_openai_tools_agent,AgentExecutor prompt_old ChatPromptTemplate.from_messages([(system,助手),(user,{input})]) # ❌ 工具绑定在Agent/Chain层面换链必须重新传tools agent_chain create_openai_tools_agent(llm_raw,tools,prompt_old) executor AgentExecutor(agentagent_chain,toolstools)缺点多条 Agent Chain 要重复传入 tools冗余LLM 本身不带工具换 Prompt 就要重新构造 Agent新版 LCEL 设计思想工具归模型CPU流程归链路指令链。五、落地设计优势工程价值工具一次绑定全链路复用同一个 LLM 实例供给问答链、数据分析链、客服链全部共用一套工具灵活切换链路不改动工具配置修改 Chain 的 Prompt、增加前置数据处理 Runnable不用重新绑定工具分层解耦LLM 层管理工具定义、参数 Schema、决策要不要调用工具Chain 层管理输入预处理、消息拼接、结果后处理、工具落地执行动态替换模型替换不同厂商兼容 FunctionCall 的 LLMChain 代码完全不用改仅更换 llm 实例即可。六、延伸类比复盘呼应四层架构表格硬件层AI 层说明CPU(LLM)核心计算单元bind_tools 挂载硬件外设驱动外设 (网卡 / 硬盘)Tools (工具 / RAG)外设硬件属性绑定 CPU不是绑定总线指令CPU 指令流水线 (Chain)LCEL 链路只做数据搬运、指令流转不持有硬件