Agent工具接口与错误处理
接口定义、参数规范与错误处理策略详解
原题:在构建智能体(Agent)系统时,如何设计和实现其可调用的外部工具(Tools),包括工具的接口定义、参数规范、执行机制以及错误处理策略?请结合实际场景说明设计思路。
Agent · 美团真题
30 秒回答
- 工具接口需标准化(名称+描述+参数Schema)
- 参数设计要兼顾LLM理解和程序校验
- 执行机制需解耦同步/异步调用
- 错误处理要分层(参数校验/执行异常/结果解析)
回答与解析
答案要点
- 工具接口需标准化(名称+描述+参数Schema)
- 参数设计要兼顾LLM理解和程序校验
- 执行机制需解耦同步/异步调用
- 错误处理要分层(参数校验/执行异常/结果解析)
- 实际场景举例说明设计权衡
一、工具接口定义(Function Schema)
采用类OpenAI Function Calling的标准格式,让LLM和程序都能理解:
{
"name": "hotel_search",
"description": "搜索酒店,返回价格、评分、位置信息",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "enum": ["北京","上海"]},
"check_in": {"type": "string", "format": "date"},
"price_max": {"type": "number", "description": "最高价格,单位元"}
},
"required": ["city", "check_in"]
}
}
设计要点:description要写给LLM看(说明业务含义),enum/format约束减少幻觉,避免自由文本参数。
二、执行机制设计
注册与路由
class ToolRegistry:
def __init__(self):
self._tools: Dict[str, Callable] = {}
self._schemas: List[dict] = []
def register(self, func, schema):
self._tools[schema["name"]] = func
self._schemas.append(schema)
执行层解耦
- 同步工具:直接调用,如计算器、数据库查询
- 异步工具:提交任务返回task_id,轮询或回调获取结果(如生成报告、复杂计算)
- 敏感工具:增加人工确认层(如支付、删除操作)
三、错误处理策略(三层防护)
| 层级 | 处理内容 | 示例 |
|---|---|---|
| 参数校验层 | JSON Schema校验 + 业务规则检查 | 日期格式非法、城市不在服务范围 |
| 执行异常层 | 超时/重试/降级 | API超时→重试2次→返回友好提示 |
| 结果解析层 | 空结果/格式异常处理 | 搜索无结果时返回结构化空值,非抛异常 |
关键原则:错误信息要回传给LLM,让其决定是否重试、换工具或向用户澄清。
四、实际场景:美团酒店预订Agent
场景:用户说"帮我订明天北京国贸附近的酒店,预算500以内"
设计权衡:
- 工具拆分:拆为
hotel_search→hotel_detail→hotel_book三步,降低单工具复杂度 - 参数填充:LLM提取"明天"→日期,"国贸附近"→坐标+半径,缺失参数主动询问
- 错误示例:搜索无结果时,工具返回
{"hotels": [], "suggestion": "扩大搜索范围或调整日期"},LLM据此引导用户而非直接报错
口语版讲法(约4分钟)
- 工具设计的本质是让LLM和系统对齐
- 接口定义:schema写给LLM看,约束给程序用
- 执行机制:按同步/异步/人工确认拆解,别一把梭
- 错误处理:错误信息要喂回给LLM,让它决策
- 真实场景:酒店预订Agent的设计权衡与坑
这道题其实问的是,当LLM要调用外部能力时,怎么设计一套让模型和系统都能理解、不出错的接口和执行机制。核心是解决对齐问题,LLM是概率模型,系统是确定性的,中间怎么搭桥。
先说接口定义。我会用类OpenAI Function Calling的schema格式,里面最重要的不是参数类型,而是description字段,这是写给LLM看的,要说明业务含义和边界。比如一个酒店搜索工具,参数里有个city字段,我会用enum限定北京上海,而不是让LLM自由填文本,不然它可能给你填个'北上广深',系统就崩了。再一个,参数里format标注date,配合校验层,能大幅降低Hallucination。说白了,schema是LLM和程序之间的契约,LLM看description,程序看type和constraints。
接着说执行机制。我不会把所有工具都用一个函数搞定,而是按调用方式拆成三类:同步的,比如计算器、数据库查询,直接等结果;异步的,比如生成报告,提交后返回task id,轮询或回调拿结果;敏感的,比如支付、删除,必须加人工确认层,哪怕LLM已经调用了,也要hold住等用户点确认。这里有个坑:别把所有工具都设计成同步的,否则遇到长耗时任务,整个Agent会卡死。我会用一个ToolRegistry统一注册,每个工具配一个schema和一个handler,路由的时候按name匹配。
错误处理这块,我的原则是分层兜底,但核心是错误信息要回传给LLM,让它来做决策。第一层是参数校验,比如日期格式不对、城市不在服务范围,直接返回结构化的错误码和提示,LLM看到后可以自己修正再试。第二层是执行异常,比如API超时,我会重试两次,还不行就降级,比如搜索酒店失败,返回'当前服务繁忙,建议稍后再试',而不是抛异常让系统挂掉。第三层是结果解析,比如搜索无结果,我返回{"hotels": [], "suggestion": "扩大范围或调整日期"},LLM看到空数组和suggestion,就知道该怎么引导用户。关键是把错误当成正常输出,LLM不是程序员,它不会看日志,你给它什么,它就基于什么决策。
举个例子,美团酒店预订Agent。用户说'帮我订明天北京国贸附近的酒店,预算500以内'。我会把整个流程拆成三步:hotel search → hotel detail → hotel book,每一步都是独立的工具。hotel search负责搜,返回候选列表;hotel detail查具体信息;hotel book做预订。这样每个工具职责单一,LLM容易理解,也方便复用。参数填充上,LLM要自己解析'明天'转成日期,'国贸附近'转成坐标加半径,缺失的比如入住人数,它得主动反问用户。这里有个常见失败场景:搜索无结果时,如果工具直接抛异常,LLM就傻眼了。所以我会让工具返回'hotels: [], suggestion: 扩大范围',LLM看到后会说'附近没有符合条件的酒店,要不要看看其他区域?',这才是好的交互。
还有一个延伸点:当工具数量变多,比如超过20个,LLM选错工具的概率会飙升。我见过一个方案是分层路由,先让LLM决定去哪一个大类,再在类内选具体工具。但这样多了决策跳数,延迟和错误率如何平衡,其实值得细聊。
所以整体上,我把工具设计看成是给LLM搭脚手架,不是让它自由发挥,而是给它清晰的路径和兜底,让它能在可控范围内做对的事。这也是Agent落地里最容易被低估的一环。
关键一句:当工具数量超过20个时,LLM选错工具的概率飙升,可以用分层路由降低错误率,但会增加延迟和决策跳数。
面试官还可能这样问
- 问法 1 · 场景切入
假设你在做一个订单管理的智能助手,用户问“帮我查一下上个月订单”,然后Agent需要调用API查数据库。你准备怎么设计这个工具的定义和调用流程,让LLM能准确理解参数、也能处理好各种异常?
- 问法 2 · 层层追问
Agent调用外部工具时,你怎么保证LLM能正确选择工具并填好参数?……如果参数填错了或者API超时了,你打算怎么处理?……那如果工具是异步的,比如生成一个耗时报表,你的执行机制怎么设计?
- 问法 3 · 直球架构
设计一个Agent的外部工具系统,要求包括:工具接口定义(名称、描述、参数Schema)、执行机制(同步/异步、注册路由)和错误处理策略(参数校验、执行异常、结果解析)。请直接说你的整体设计方案。