LLM 自动选择多工具底层完整原理
LLM 自动选择多工具底层完整原理
一、核心前提:工具元数据全部传给 LLM
执行llm.bind_tools([calculator, search, weather])时,LangChain 会自动做两件事:
- 读取每个工具:
@tool函数的文档字符串、参数名、参数类型、参数描述 - 把所有工具转换成标准 JSON Schema 工具列表,塞进发给 LLM 的系统提示附加字段
发给大模型的工具列表简化示例:
json
[ { "name": "calculator_tool", "description": "计算数学四则表达式,支持abs、round求和等数值运算", "parameters": { "type": "object", "properties": { "expression": {"type": "string", "description": "纯数学表达式,如 10+20*5"} }, "required": ["expression"] } }, { "name": "get_weather", "description": "查询指定城市实时天气", "parameters": {"city": {"type": "string", "description": "城市名称"}} }, { "name": "web_search", "description": "联网搜索最新实时资讯、百科、事件,静态知识不知道时调用" } ]LLM 会同时看到所有工具名称、功能描述、入参要求,依靠自身语义理解做匹配判断。
二、LLM 选择工具的 4 层判断逻辑(从上到下执行)
1. 语义意图匹配(第一层核心判断)
模型对比用户提问和每个工具description的用途描述,做相似度匹配:
- 用户问
123乘以45等于多少→ 和 calculator 描述「数学计算」高度匹配,优先选计算器 - 用户问
北京今天多少度→ 和 weather「查询城市天气」匹配,选天气工具 - 用户问
2026最新GDP数据→ 静态知识库过时,匹配 search「联网查实时信息」
2. 关键词特征辅助筛选
工具描述里的专属关键词会强化模型判断:
- calculator:
calculate、sum、math、expression、加减乘除 - weather:
weather、temperature、气温、下雨、城市 - search:
最新、实时、新闻、查询、百科、现在
3. 参数校验:能否提取对应入参(过滤不匹配工具)
模型不仅看用途,还会判断能不能从用户问题里提取出工具需要的参数:
- 提问:
上海天气weather 需要city参数,能提取上海→ 可用 calculator 需要expression,提取不出数学式子 → 排除 - 提问:
50除以2calculator 可提取表达式"50 / 2"weather 需要城市,问题无城市 → 直接放弃天气工具
4. 优先级与多工具同时调用
- 单一意图:只选 1 个工具
深圳明天天气→ 仅调用 get_weather - 复合意图:同时调用多个工具(模型可输出多条 tool_call) 示例提问:
深圳今天气温多少,再算一下250*8LLM 会生成两个 tool_call:- 调用 get_weather (city="深圳")
- 调用 calculator_tool (expression="250 * 8")
- 不需要任何工具问题纯常识、主观问答、无需计算 / 联网:
猫喜欢吃什么,模型直接输出文本,tool_calls = []
三、完整执行链路(LangGraph ReAct 循环)
- 用户输入问题
agent节点调用绑定全部工具的llm_with_tools- LLM 读取全部工具 Schema,语义匹配,生成 AIMessage:
- 包含
tool_calls数组:工具名 + 提取好的参数
- 包含
- 路由函数
should_continue判断:- 存在 tool_calls → 进入
ToolNode
- 存在 tool_calls → 进入
- ToolNode 自动分发执行对应工具:
- 根据
tool_call["name"]匹配函数列表里的工具,传入参数执行 - 多个 tool_call 会循环依次执行,全部生成 ToolMessage
- 根据
- 工具结果放回 messages 列表,回到 agent 节点
- LLM 结合工具返回数据,整理自然语言最终回答,无新 tool_call 则结束
四、人为控制 LLM 工具选择的优化技巧
1. 写清晰、差异化的工具 docstring(最重要)
避免描述模糊,每个工具写明适用场景、不适用场景,减少模型选错:
python
运行
# 优秀示例 @tool def calculator_tool(expression: str) -> str: """仅用于数学数值计算。不查天气、不查新闻。 处理加减乘除、绝对值、求和等数字运算。 参数:纯数字运算表达式,例如 "100 - 20 * 3" """2. 工具命名语义化
工具名带上业务标识,模型更容易识别:calculator_tool/weather_query/general_web_search不建议命名func1tool_a无意义名称。
3. 区分工具适用边界,减少混淆
比如搜索和计算器功能完全隔离,描述不要重叠; 如果两个工具用途相近(比如本地知识库检索 + 联网搜索),在描述里明确区分:
- local_rag:查内部文档、历史资料
- web_search:查互联网实时新鲜信息
4. system prompt 补充工具选择规则
给 LLM 额外约束,强制选择逻辑:
python
运行
system_prompt = """ 你拥有3个工具,使用规则: 1. 所有数字计算、求和、四则运算必须使用 calculator_tool,禁止自己口算; 2. 查询任意城市温度、降雨使用 get_weather; 3. 超过2025年的实时数据、网络新闻使用 web_search; 4. 普通常识问题,不需要调用任何工具,直接回答。 """ llm_with_tools = llm.bind_tools(tools).with_messages([SystemMessage(content=system_prompt)])五、常见选错工具的原因
- 工具文档描述太简短、模糊,模型分不清用途
- 多个工具功能高度重叠,无明确边界说明
- temperature > 0,随机性导致模型乱选工具
- 用户提问语义模糊,同时包含多个领域关键词
- 缺少系统提示词约束工具使用规则
六、多工具完整可运行示例
python
运行
from langchain.tools import tool from langgraph.prebuilt import ToolNode, MessagesState from langgraph.graph import StateGraph, START, END from langchain_openai import ChatOpenAI # 工具1:计算器 @tool def calculator_tool(expression: str) -> str: """仅处理数学四则运算、数值计算,不处理天气/网络查询""" allowed = {"abs":abs, "round":round} try: res = eval(expression, {"__builtins__":{}}, allowed) return str(res) except Exception as e: return str(e) # 工具2:天气 @tool def get_weather(city: str) -> str: """查询指定城市实时天气,仅接收城市名称""" return f"{city} 今日 27℃ 多云" # 工具3:联网搜索 @tool def web_search(query: str) -> str: """查询互联网实时资讯、最新数据,模型静态知识不足时使用""" return f"搜索结果:{query} 的相关实时信息" # 注册全部工具 tools = [calculator_tool, get_weather, web_search] tool_node = ToolNode(tools) llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) llm_with_tools = llm.bind_tools(tools) def agent(state: MessagesState): return {"messages": [llm_with_tools.invoke(state["messages"])]} def route(state): last_msg = state["messages"][-1] if last_msg.tool_calls: return "tools" return END builder = StateGraph(MessagesState) builder.add_node("agent", agent) builder.add_node("tools", tool_node) builder.add_edge(START, "agent") builder.add_conditional_edges("agent", route) builder.add_edge("tools", "agent") graph = builder.compile() # 测试复合提问,自动调用两个工具 res = graph.invoke({"messages": [("human", "武汉今天天气怎么样,再计算 36 * 15")]}) print(res["messages"][-1].content)运行后模型会自动识别同时需要天气 + 计算器,并行生成两条工具调用指令。
