核心要点
能讲清定义工具的三种方式:@tool 装饰器(最简,函数即工具)、StructuredTool.from_function(多参数/异步更灵活)、继承 BaseTool(需要复杂状态或自定义校验时)
能说出工具三要素:名称、清晰的描述(给模型看,决定要不要调)、参数 schema(用类型注解或 Pydantic 定义,模型据此填参)
能讲清绑定与调用闭环:model.bind_tools([...]) 把工具 schema 喂给支持 function calling 的模型,模型返回 tool_calls(要调哪个工具、什么参数)→ 本地执行 → 把结果作为 ToolMessage 回传 → 模型据此续答
能点出准确率关键:工具描述和参数 schema 的质量直接决定模型选对工具、填对参数的概率,描述要写清「什么时候用、参数含义、返回什么」
标准回答
整体思路
让模型「会用工具」分两步:先把工具定义成模型能理解的 schema,再用 bind_tools 绑定,由模型决定何时调用、调用谁、传什么参数,框架负责执行并把结果回传。
第一步:定义工具
- @tool 装饰器:最常用。给普通函数加
@tool,函数名作工具名,docstring 作描述,类型注解推断参数 schema。 - StructuredTool.from_function:需要多参数、异步实现或更精细控制时用,可分别传同步/异步函数和显式 args_schema。
- 继承 BaseTool:实现 _run/_arun,适合需要持有状态、做复杂参数校验或自定义错误处理的工具。
三种方式都要写清三要素:名称、描述(给模型判断是否调用)、参数 schema(推荐用 Pydantic 模型,给每个字段加 description)。
第二步:绑定模型
llm_with_tools = model.bind_tools([tool_a, tool_b])
bind_tools 会把工具的 JSON schema 注入到对模型的请求里,模型本身需支持 function calling / tool use(如 GPT、Claude、通义等主流模型)。
第三步:执行调用闭环
- 调
llm_with_tools.invoke(messages),若模型决定用工具,返回的 AIMessage 带 tool_calls(含工具名和结构化参数)。 - 遍历 tool_calls,按名字找到对应工具并用参数执行,得到结果。
- 把结果包成 ToolMessage(带对应 tool_call_id)追加到消息列表,再次 invoke 模型。
- 模型读取工具结果,生成最终自然语言回答;若需要可多轮循环(多次调用工具)。
工程要点
- 用 Agent 或 LangGraph 时,这套「调用-执行-回传」循环由框架自动驱动,无需手写。
- 描述与 schema 质量是命中率核心;并发场景注意一次返回多个 tool_calls;工具内部要做异常处理,把错误也作为可读结果回传给模型,便于其纠正重试。
常见误区
⚠️ 常见踩坑
以为 bind_tools 后模型会自动执行工具——它只产出 tool_calls,真正执行和回传结果要你(或 Agent/LangGraph 框架)来做;工具描述写得含糊或参数没加 description,模型就选错工具、填错参数;忽略 tool_call_id,回传 ToolMessage 时对不上号会出错;模型不支持 function calling 还硬绑会失效,应改用提示词 + OutputParser 方案;把未校验的模型入参直接执行高危操作(删库、转账)而不加白名单与人工确认,存在安全风险。
追问
追问 1:Function Calling 和 ReAct 提示式工具调用有什么区别?该怎么选?
追问 2:怎么提高模型选对工具、填对参数的准确率?
写好描述:工具描述讲清「什么场景用、不该在什么场景用、返回什么」,让模型有明确的选择依据;相似工具要在描述里区分边界。
精确 schema:用 Pydantic 给每个参数加类型、description、枚举和默认值,约束模型填参空间;必填与可选要分清。
控制数量:单次绑定的工具别太多,过载会降低命中率,可按场景分组或先做一层路由。
容错回传:工具执行失败时把错误信息作为结果回传,模型能据此调整参数重试。
评测:用真实 query 集回归测试工具选择与参数正确率,针对错例迭代描述和 schema。
追问 3:模型一次返回多个 tool_calls 要并行执行吗?怎么处理多轮工具调用?
并行:模型可能在一条 AIMessage 里返回多个相互独立的 tool_calls,这些可以并发执行以降延迟,但要保证每个结果用对应的 tool_call_id 包成 ToolMessage 回传,顺序无所谓、id 对得上即可。
有依赖时:若后一个调用依赖前一个结果,模型通常会分多轮逐步发起,不会一次全给,按轮次串行执行即可。
多轮循环:把「invoke→执行 tool_calls→回传 ToolMessage→再 invoke」做成循环,直到模型不再产出 tool_calls 给出最终答复;用 LangGraph/Agent 时该循环由框架管理,并应设最大轮数和超时,防止工具调用无限循环。
🔗 相似问题
同一考点的不同问法,面试官可能换着问,一起刷更稳
没找到想看的面试题?把你想看的告诉我们 →
延伸学习
按主题分类的相关资源,便于系统复习