面试官:“你的 Agent 能调用哪些工具?”

‍♂️ 他说:“能查数据库、查知识库、发企微通知、创建工单,还能调用内部接口。”

‍ 面试官接着问:“那工具调用失败了怎么办?”

‍♂️ 他说:“失败的话,大模型应该会重新规划。”

‍ 面试官追问:“应该?你测过吗?数据库超时怎么办?接口返回 500 怎么办?参数格式错了怎么办?用户没权限怎么办?Agent 连续调用同一个工具 5 次怎么办?”

‍♂️ 他答不上来了。

‍ 面试官最后说了一句:

“很多人做 Agent,只证明了模型会调工具。但生产环境要证明的是:工具失败了,系统不会崩。”

这个问题其实特别典型。

很多同学做 Agent Demo 的时候,演示效果很好:

用户一句话下任务,模型自动拆解步骤,自动调用工具,自动查数据,最后生成答案。

但一上线就各种翻车:

  • 工具参数填错;

  • 接口偶发超时;

  • Agent 一直重复调用同一个工具;

  • 用户没权限还继续查;

  • 工具失败后模型开始胡编;

  • 创建工单重复创建了好几次。

所以,Agent 真正难的地方,不是“能不能调用工具”,而是工具调用失败时,系统能不能稳住

今天就把 Agent 工具调用的稳定性设计讲清楚。


简要回答

Agent 工具调用不能完全交给大模型自由发挥,必须有一层Tool Executor 工具执行器做统一控制。

一个生产级 Agent 的工具调用链路,至少要包含:

参数校验、权限校验、超时控制、错误分类、有限重试、降级兜底、调用次数限制、日志追踪。

一句话总结就是:

模型负责规划,系统负责约束,工具负责执行,日志负责追踪,兜底负责稳定性。

面试里如果被问“工具调用失败怎么办”,不要只说“加重试”。

你要说清楚:

  1. 调用前先做参数校验和权限校验;

  2. 调用时设置超时,避免 Agent 卡死;

  3. 失败后根据错误类型判断是否重试;

  4. 网络超时、服务不可用可以重试;

  5. 参数错误、权限不足、业务对象不存在不能重试;

  6. 多次失败后走降级,比如返回缓存、转人工、创建工单;

  7. 对整个工具调用过程记录 trace 日志,方便线上排查。

这才是工程化 Agent 的回答。


详细解析

先搞清楚:Agent 为什么会在工具调用上翻车?

很多人以为 Agent 调工具很简单。

不就是给模型几个 function,然后让模型自己决定调用哪个吗?

比如:

tools = [
 "query_order",
 "create_ticket",
 "send_wechat_message"
]

用户问:“帮我查一下订单 20260509001 怎么还没发货。”

模型调用query_order,传入订单号,然后返回结果。

Demo 阶段确实没问题。

但真实环境里,用户不会一直这么规范。

用户可能问:

我上周买的那个耳机怎么还没发?

这里没有订单号。

用户也可能问:

帮我催一下,真的服了。

这里既没有订单号,也没有明确操作。

更麻烦的是,工具本身也不稳定:

  • 订单接口超时;

  • 数据库返回空;

  • 用户没有权限;

  • API 返回 500;

  • 参数字段不匹配;

  • 下游系统限流;

  • 工具返回的数据不完整。

所以 Agent 调工具的核心不是“能不能调”,而是:

调用失败、参数不全、权限不足、服务异常时,系统怎么处理。

这就是 Demo 和生产系统的区别。


第一层:参数校验,不能相信模型生成的参数

模型生成的工具参数不一定可靠。

比如工具需要:

{
"order_id":"20260509001"
}

但模型可能生成:

{
"id":"20260509001"
}

也可能生成:

{
"order_id":""
}

甚至生成:

{
"order_id":"用户上周买的耳机"
}

如果你直接把这个参数丢给订单系统,轻则报错,重则查错数据。

所以工具调用前必须做参数校验。

frompydanticimportBaseModel, Field, ValidationError

classQueryOrderInput(BaseModel):
  order_id: str = Field(..., min_length=6, max_length=30)

defvalidate_args(tool_name, args):
 iftool_name =="query_order":
   returnQueryOrderInput(**args)
 raiseValueError("unknown tool")

如果参数缺失,不要硬调工具,而是让模型追问用户:

请提供订单号,我才能帮你查询发货状态。

这一步非常关键。

生产环境里,模型可以生成参数,但系统不能无条件相信参数。


第二层:权限校验,绝对不能只靠 Prompt

Agent 一旦能调工具,就有了执行能力。

它可能查订单、查工资、查客户资料、创建工单,甚至触发退款。

这个时候权限校验必须由后端系统做,不能靠 Prompt。

比如用户问:

帮我查一下张三这个月工资。

模型可能判断要调用query_salary工具。

但用户有没有权限查张三工资?

这个不能让模型决定,必须走权限系统。

defcheck_permission(user_id, tool_name, args):
 iftool_name =="query_salary":
   returnpermission_service.can_view_salary(
      user_id=user_id,
      employee_id=args["employee_id"]
    )
 returnTrue

面试里如果你说:

我们在 Prompt 里告诉模型不能查敏感信息。

这基本不够。

Prompt 是软约束,权限系统才是硬约束。

真正的安全边界一定要放在系统层。


第三层:超时控制,防止 Agent 一直转圈

生产环境里,工具超时太常见了。

数据库慢、内部接口慢、第三方 API 抖动,都可能导致 Agent 一直等。

如果没有超时控制,用户看到的就是页面一直转圈。

所以每个工具都要设置 timeout。

importasyncio

asyncdefcall_tool_with_timeout(tool_func, args, timeout=3):
 try:
   returnawaitasyncio.wait_for(tool_func(args), timeout)
 exceptasyncio.TimeoutError:
   return{
     "success":False,
     "error_code":"TOOL_TIMEOUT",
     "message":"工具调用超时"
    }

不同工具超时时间可以不一样:

  • Redis 查询:100ms-300ms;

  • 数据库简单查询:1s-2s;

  • 内部 HTTP API:2s-5s;

  • 第三方 API:3s-10s;

  • 长任务:不要同步等,改成异步任务。

比如生成报告、批量导出、跑数据分析,这种任务就不应该让用户在聊天窗口干等。

正确做法是:

创建任务 → 返回任务 ID → 后台执行 → 完成后通知用户。


第四层:错误分类,不是所有失败都应该重试

很多人一说工具失败,就说“加重试”。

但面试官马上会追问:

哪些错误能重试?哪些错误不能重试?

如果你答不上来,说明没真正做过。

工具错误一般分三类。

第一类:可重试错误。

比如:

  • 网络超时;

  • 服务 502 / 503;

  • 接口临时不可用;

  • 连接池短暂耗尽;

  • 第三方 API 限流。

这类错误可以有限重试。

第二类:不可重试错误。

比如:

  • 参数缺失;

  • 参数格式错误;

  • 用户无权限;

  • 订单不存在;

  • 用户不存在;

  • 业务规则不允许。

这类错误重试也没用,应该直接提示用户或者追问补充信息。

第三类:需要人工介入的错误。

比如:

  • 数据互相矛盾;

  • 高风险操作失败;

  • 金额异常;

  • 投诉升级;

  • 订单状态异常。

这类问题不要让 Agent 硬编,要转人工或者创建人工工单。

RETRYABLE = {"TIMEOUT","NETWORK_ERROR","SERVICE_UNAVAILABLE"}
NON_RETRYABLE = {"INVALID_ARGS","PERMISSION_DENIED","NOT_FOUND"}

defcan_retry(error_code):
 returnerror_codeinRETRYABLE

这就是稳定性的关键:

不是失败了都重试,而是先判断失败类型,再决定下一步。


第五层:重试要有限制,不能无限调工具

可重试错误可以重试,但一定要有边界。

不能这样写:

whileTrue:
  result = call_tool()

这会把下游服务打爆,也会让 Agent 卡死。

正确做法是:

  • 最大重试次数;

  • 指数退避;

  • 随机抖动;

  • 超过次数后降级。

importasyncio
importrandom

asyncdefretry_call(tool_func, args, max_retries=3):
 foriinrange(max_retries +1):
    result =awaittool_func(args)

   ifresult["success"]:
     returnresult

   ifnotcan_retry(result["error_code"]):
     returnresult

   ifi == max_retries:
     return{
       "success":False,
       "error_code":"RETRY_EXHAUSTED",
       "message":"多次重试后仍然失败"
      }

   awaitasyncio.sleep(0.5* (2** i) + random.random() *0.2)

这里的重点不是代码,而是思路:

重试是有限的,失败后必须有下一步方案。


第六层:降级兜底,比重试更重要

工具调用失败后,最差的处理方式是直接甩一句:

系统异常,请稍后再试。

用户体验非常差。

更好的做法是根据场景降级。

比如用户问订单状态,订单系统超时了。

你可以返回缓存数据

当前订单系统响应较慢,我先为你展示最近一次同步的订单状态:待发货。该状态更新时间为 2026-05-09 10:30,可能不是最新结果。

如果没有缓存,也可以引导用户:

当前订单系统暂时不可用,我可以帮你创建一个催发货工单,是否需要?

常见降级策略有这些:

生产级 Agent 一定要能“优雅失败”。

所谓优雅失败,就是:

  • 不胡编;

  • 不卡死;

  • 不重复执行;

  • 能解释原因;

  • 能给用户下一步选择。


第七层:限制工具调用次数,防止 Agent 死循环

Agent 很容易出现一种情况:

一直调用同一个工具,但一直拿不到想要的结果。

比如投诉查询工具返回空,模型不死心,又换个参数查一次,还是空,又查一次。

最后用户等了半天,系统调了十几次工具。

所以一定要限制工具调用次数。

MAX_TOOL_CALLS =5

asyncdefrun_agent(query):
  tool_call_count =0

 whileTrue:
    response =awaitllm.chat(query, tools=tools)

   ifnotresponse.tool_call:
     returnresponse.content

   iftool_call_count >= MAX_TOOL_CALLS:
     return"当前任务需要多次工具调用,系统已暂停自动执行,请补充信息或转人工处理。"

    result =awaitexecute_tool(response.tool_call)
    tool_call_count +=1

除了总次数限制,还要限制:

  • 同一个工具最多调用几次;

  • 相同参数不能重复调用;

  • 写操作不能重复执行;

  • 高风险操作必须确认。

尤其是创建工单、退款、发通知、修改数据这种写操作,一定要做幂等。

否则 Agent 重复调用两次,就可能创建两个工单,甚至重复退款。


面试里怎么回答这个问题?

面试官问:

你的 Agent 工具调用失败怎么办?

不要只说:

我们会重试。

这个回答太浅。

比较完整的回答可以这样说:

我们没有让模型直接调用工具,而是做了一层统一的 Tool Executor。模型只负责选择工具和生成参数,真正执行前会做参数校验、权限校验和风险判断。

工具调用时会设置超时时间,避免 Agent 卡死。失败后会根据错误码分类处理,像网络超时、服务不可用这类可重试错误,会做有限次数的指数退避重试;像参数错误、权限不足、业务对象不存在这类不可重试错误,就不会重试,而是让模型追问用户或直接提示原因。

如果多次重试仍失败,会进入降级策略,比如返回缓存、切换备用接口、创建人工工单或者转人工处理。同时我们会记录完整的工具调用日志,包括 trace_id、tool_name、arguments、耗时、错误码、重试次数和最终结果,方便线上排查。

对于退款、删除、修改权限这类高风险工具,还会做用户二次确认,必要时走人工审批。

这个回答就比较像真正做过项目的人。

它体现了四个关键词:

可控、可重试、可降级、可追踪。


最容易翻车的 3 个点

第一个:把 Function Calling 当成 Agent 工程化。

Function Calling 只是模型调用工具的入口,不代表系统稳定。

面试官真正关心的是:参数怎么校验?失败怎么处理?权限怎么控?日志怎么看?

第二个:把安全控制写在 Prompt 里。

Prompt 只能提醒模型,不能作为安全边界

权限、风控、二次确认,必须在后端系统里做。

第三个:没有日志追踪。

线上用户反馈“刚才 AI 没处理成功”,你怎么排查?

必须有 trace_id,能看到模型调了哪个工具、传了什么参数、耗时多少、失败原因是什么、重试了几次、最后给用户回复了什么。

没有这些日志,Agent 线上问题基本查不动。


写在最后

现在很多人做 Agent,喜欢展示“模型会自动调用工具”。

但生产环境真正考验的不是成功路径,而是失败路径。

成功的时候,谁都能演示。

真正拉开差距的是:

  • 参数错了怎么办?

  • 工具超时怎么办?

  • 用户没权限怎么办?

  • 下游接口挂了怎么办?

  • Agent 重复调用怎么办?

  • 高风险操作怎么确认?

  • 出问题后怎么排查?

Agent 不是越自主越好,而是越可控越好。

Demo 里的 Agent,可以像一个聪明但莽撞的实习生。

生产环境里的 Agent,必须像一个受过训练的员工:

知道自己能做什么,也知道自己不能做什么;信息不足会追问,权限不够会拒绝,操作失败会解释,高风险动作会确认,每一步都有记录。

所以以后面试官再问:

你的 Agent 工具调用失败怎么办?

不要只回答“加重试”。

你要回答:

我们做的是一整套工具调用治理体系

这句话,才是真正拉开差距的地方。

点个关注,学习更多 AI 应用开发知识。


最后,如果你也在准备大模型应用开发岗位,或者想系统做一个能写进简历、经得住面试追问的 RAG / Agent 项目,欢迎了解IT枫斗者 AI 应用开发训练营

我们会带你从 0 到 1 做真实项目,不只是跑通 Demo,而是重点讲清楚:

  1. RAG 企业知识库项目文档解析、切分、Embedding、向量检索、Rerank、缓存、流式输出、权限和性能优化

  2. Agent 工程化项目:Function Calling、工具注册、参数校验、权限控制、重试降级、日志追踪、高风险确认。

  3. 面试项目表达:把项目讲成真实上线系统,而不是“我调用了某某大模型 API”。

  4. 简历和面试辅导:帮你把项目难点、工程细节、优化数据讲清楚。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐