一、问题分析
Agent 声称已经调用工具,或者告诉用户任务已完成,但实际上可能存在三种情况:
- 工具没有执行:模型只输出“已完成”,没有产生真实的工具调用。
- 工具执行失败:已经调用工具,但参数错误、权限不足、接口超时或服务异常。
- 工具执行成功,但任务没有完成:工具返回成功,但没有达到用户要求的业务结果。
解决思路:不能直接相信 Agent 的自然语言回复,而要根据真实执行记录、工具返回结果和业务验收结果判断任务是否完成。
二、整体工程方案
用户提出任务 ↓Agent 生成结构化 Tool Call ↓检查是否产生真实工具调用 ├── 没有 Tool Call │ ↓ │ 不允许判定成功 │ 要求继续执行或返回未完成 │ └── 存在 Tool Call ↓ Tool Executor 执行工具 ↓ 记录真实执行结果 ↓ 根据结果分类处理 ├── 参数错误 → 修正参数后重试 ├── 临时错误 → 有限次退避重试 ├── 超时未知 → 查询业务状态 └── 执行成功 → 业务结果验收 ↓ 验收通过才算任务完成三、具体工程实现
1. 工具调用:使用现成框架管理执行
可以参考 LangGraph 的 ToolNode 和 tools_condition。
- Agent 负责生成结构化工具调用请求。
ToolNode根据工具名称找到对应实现并执行。tools_condition根据模型消息中是否存在 Tool Call 进行路由。- 工具执行结果返回给模型,让 Agent 根据结果继续处理。
注意:模型输出“我已经调用工具”只是普通文本,不代表真的发生了工具调用。
如果没有产生 Tool Call,系统不能将任务标记为成功;如果有 Tool Call,还需要确认执行器确实运行并返回了结果。
参考:
2. 执行记录:确认工具是否真的执行
后端可以建立 agent_tool_execution 表,记录:
| 字段 | 作用 |
|---|---|
task_id | 所属 Agent 任务 |
tool_call_id | 本次工具调用的唯一标识 |
tool_name | 工具名称 |
arguments | 工具调用参数 |
status | 执行状态 |
result | 工具真实返回结果 |
error_code | 错误类型 |
duration_ms | 执行耗时 |
执行器在调用前创建记录,执行后更新状态。
可以使用以下状态:
PENDING:等待执行RUNNING:正在执行SUCCEEDED:工具执行成功FAILED:明确执行失败UNKNOWN:结果暂时无法确认
通过执行记录和运行轨迹,可以区分模型没有发起调用、执行器没有正常运行,以及外部 API 执行失败等问题。
参考:
3. 错误恢复:将真实错误反馈给 Agent
不能所有错误都采用同一种重试方式,需要根据错误类型分类处理。
| 错误情况 | 处理方式 |
|---|---|
| 参数错误 | 将具体错误反馈给 Agent,修正参数后重试 |
| 临时限流或服务异常 | 由执行器按照退避策略有限次重试 |
| 权限不足 | 停止重试,提示用户授权 |
| 工具返回业务失败 | 分析错误原因,决定是否更换工具或调整方案 |
| 请求超时,结果未知 | 先查询业务状态,避免重复执行 |
| 超过最大重试次数 | 停止自动纠错,返回明确失败原因 |
重试时需要设置最大次数和整体执行时限,避免 Agent 无限循环。
对于创建工单、创建待办、扣费等有副作用的操作,还需要使用幂等键、业务唯一标识或结果查询,避免重复执行。
4. 业务验收:工具成功不等于任务完成
例如,用户要求创建一条飞书待办。
不能只检查创建接口是否返回成功,还可以根据返回的 todo_id 查询实际记录,并检查:
- 待办是否真实存在。
- 标题和负责人是否符合要求。
- 是否满足用户提出的其他业务条件。
建议区分两个状态:
tool_status:工具执行是否成功。task_status:用户要求的任务是否完成。
例如:
tool_status = SUCCEEDEDtask_status = VERIFYING验收通过后:
tool_status = SUCCEEDEDtask_status = SUCCEEDED如果工具执行成功,但业务验收失败,则不能把任务标记为完成。
注意:只有外部系统支持查询或提供足够的结果证据时,才能验证实际业务状态;不能声称完成了无法执行的检查。
四、完整故障处理示例
场景:用户要求 Agent 创建飞书待办,但 Agent 直接回复“创建成功”。
情况一:没有真实工具调用
- 模型只返回普通文本,没有 Tool Call。
- 后端发现没有对应的工具执行记录。
- 不允许任务进入
SUCCEEDED。 - 系统要求 Agent 继续执行,或向用户明确说明任务尚未完成。
- 如果达到执行上限,则停止并报告失败。
情况二:工具执行失败
- Agent 调用
create_todo。 - 后端执行器实际调用飞书 API。
- 飞书返回
INVALID_ASSIGNEE,说明负责人 ID 无效。 - 执行器记录失败状态,并将错误反馈给 Agent。
- Agent 查询合法的负责人 ID,再重新调用创建工具。
- 重试次数受限制,最终结果仍由后端验收。
情况三:工具超时
- 后端发起创建请求。
- 请求超时,无法确定飞书是否已经创建待办。
- 将执行状态标记为
UNKNOWN,而不是直接认定失败。 - 根据业务唯一标识或查询接口确认是否已创建。
- 确认未创建后再决定是否重试,避免重复创建。
五、面试口播
如果遇到 Agent 声称调用了工具,但实际没有解决问题,我会先区分三种情况:工具没有真正执行、工具执行失败,以及工具执行成功但业务任务没有完成。
首先,在执行链路上,我会使用 LangGraph 的 ToolNode 这类工具执行机制,将模型生成的结构化 Tool Call 交给后端执行,而不是直接相信模型输出的成功话术。
其次,我会通过工具执行日志和运行轨迹,记录调用参数、执行状态和返回结果。如果没有真实的执行记录,就不能认定工具调用成功;如果执行失败,就将具体错误反馈给 Agent,让它修正参数或更换工具,并限制重试次数。
最后,我会增加业务结果校验。例如创建飞书待办,不仅检查 API 是否返回成功,还可以根据待办 ID 查询记录是否真实存在。
对于超时场景,还需要先确认外部操作是否已经成功,避免盲目重试造成重复执行。
这样就形成了从工具调用、执行监控、错误纠正到业务验收的完整闭环。核心是由后端掌握工具执行和任务成功状态的判定权,而不是依赖 Agent 自己声称任务已经完成。
六、核心记忆点
- 工具调用:使用结构化 Tool Call 和执行节点,不能依赖普通文本。
- 执行监控:通过执行记录和 Tracing 还原真实调用过程。
- 错误纠正:将错误反馈给 Agent,分类处理并限制重试。
- 业务验收:工具执行成功不代表任务完成。
- 异常安全:超时结果未知时先查状态,防止重复执行。
一句话总结:现成框架负责工具调度和执行观测,自定义逻辑负责错误恢复与业务验收。