这道题其实问的是,当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落地里最容易被低估的一环。