17.人工智能实战:Agent 工具调用总是乱选?从意图识别到 Tool Router 的可靠调用架构设计
人工智能实战:Agent 工具调用总是乱选?从意图识别到 Tool Router 的可靠调用架构设计
一、问题场景:Agent 看起来聪明,但一用工具就翻车
很多团队在大模型能力稳定后,会继续做 Agent。
典型需求包括:
1. 查询订单 2. 调用数据库 3. 读取知识库 4. 发送邮件 5. 创建工单 6. 调用搜索接口初版 Agent 通常是:
用户输入 ↓ 大模型判断要不要调用工具 ↓ 执行工具 ↓ 返回结果Demo 阶段效果很好。
但一上线就会出现:
1. 用户只是普通咨询,Agent 却调用了数据库 2. 应该查订单,却调用了知识库 3. 工具参数缺字段 4. 工具调用顺序错误 5. 同一个问题,有时调用工具,有时不调用 6. 工具失败后模型继续编答案这类问题非常危险。
因为工具调用不同于聊天。
聊天答错只是内容问题。
工具调用错了,可能变成:
查错数据 发错消息 创建错误工单 触发错误业务动作这篇文章解决的问题是:
如何让 Agent 工具调用从“模型自由发挥”变成“可控的工程流程”。二、错误架构:让模型直接决定一切
很多初版 Agent 会把所有工具描述塞进 Prompt:
你可以使用以下工具: 1. search_docs 2. query_order 3. send_email 4. create_ticket然后让模型自己决定。
问题是:
模型不是调度系统。它可能因为语义相似选错工具。
例如用户问:
我的订单怎么退款?这可能是:
知识库问题:查询退款规则也可能是:
订单问题:查询具体订单状态如果没有明确路由策略,模型会不稳定。
三、正确思路:Tool Router 独立出来
生产级 Agent 不建议让模型直接随意调用工具。
推荐架构:
用户输入 ↓ 意图识别 Intent Classifier ↓ Tool Router ↓ 参数抽取 ↓ 参数校验 ↓ 工具执行 ↓ 结果总结核心变化:
工具调用不再是自由生成,而是受控流程。四、定义工具 Schema
TOOLS={"search_docs":{"description":"查询知识库文档,适合规则、流程、说明类问题","required_params":["query"]},"query_order":{"description":"查询用户订单状态,适合具体订单相关问题","required_params":["order_id"]},"create_ticket":{"description":"创建人工工单,适合系统无法解决或用户明确要求人工处理","required_params":["user_id","description"]}}五、意图分类设计
先定义意图,而不是直接定义工具。
INTENTS={"knowledge_query":"规则、政策、流程、说明类问题","order_query":"具体订单状态、物流、退款进度","human_support":"需要人工处理的问题","general_chat":"普通聊天,不需要工具"}意图和工具映射:
INTENT_TO_TOOL={"knowledge_query":"search_docs","order_query":"query_order","human_support":"create_ticket","general_chat":None}六、可复现意图识别
为了方便复现,先用规则版本。
defclassify_intent(user_input:str):if"订单"inuser_inputor"物流"inuser_inputor"退款进度"inuser_input:return"order_query"if"人工"inuser_inputor"客服"inuser_inputor"投诉"inuser_input:return"human_support"if"规则"inuser_inputor"流程"inuser_inputor"怎么"inuser_input:return"knowledge_query"return"general_chat"生产环境可以换成:
LLM 分类 小模型分类 规则 + 模型混合分类但无论哪种方式,都建议输出:
intent + confidence七、参数抽取
importredefextract_params(intent:str,user_input:str,user_id:str=None):ifintent=="order_query":match=re.search(r"\d{6,}",user_input)return{"order_id":match.group(0)ifmatchelseNone}ifintent=="knowledge_query":return{"query":user_input}ifintent=="human_support":return{"user_id":user_id,"description":user_input}return{}八、参数校验
defvalidate_params(tool_name:str,params:dict):required=TOOLS[tool_name]["required_params"]missing=[]forkeyinrequired:ifnotparams.get(key):missing.append(key)ifmissing:returnFalse,missingreturnTrue,[]如果缺参数,不能硬调工具。
应该反问用户:
ifnotvalid:return{"action":"ask_followup","message":f"缺少必要信息:{missing}"}九、工具实现
defsearch_docs(query:str):return{"type":"doc_result","content":f"知识库中关于【{query}】的结果"}defquery_order(order_id:str):return{"type":"order_result","order_id":order_id,"status":"退款处理中"}defcreate_ticket(user_id:str,description:str):return{"type":"ticket_result","ticket_id":"T202605010001","status":"created"}十、Tool Router 完整实现
defexecute_tool(tool_name:str,params:dict):iftool_name=="search_docs":returnsearch_docs(params["query"])iftool_name=="query_order":returnquery_order(params["order_id"])iftool_name=="create_ticket":returncreate_ticket(params["user_id"],params["description"])raiseValueError(f"unknown tool:{tool_name}")defagent_router(user_input:str,user_id:str=None):intent=classify_intent(user_input)tool_name=INTENT_TO_TOOL[intent]iftool_nameisNone:return{"action":"direct_answer","message":"这是普通对话,不需要调用工具。"}params=extract_params(intent,user_input,user_id)valid,missing=validate_params(tool_name,params)ifnotvalid:return{"action":"ask_followup","intent":intent,"tool":tool_name,"missing":missing,"message":f"为了继续处理,请补充:{missing}"}tool_result=execute_tool(tool_name,params)return{"action":"tool_result","intent":intent,"tool":tool_name,"params":params,"result":tool_result}十一、测试
cases=["退款规则是什么?","帮我查一下订单123456789的退款进度","我要投诉,转人工客服","你好,今天天气不错"]forcaseincases:print(case)print(agent_router(case,user_id="u001"))print("-"*50)预期:
退款规则是什么? → search_docs 订单123456789 → query_order 投诉转人工 → create_ticket 普通聊天 → 不调用工具十二、为什么要记录决策过程?
工具调用必须记录:
1. 原始用户输入 2. 识别意图 3. 选择工具 4. 抽取参数 5. 校验结果 6. 工具返回日志示例:
{"user_input":"帮我查一下订单123456789的退款进度","intent":"order_query","tool":"query_order","params":{"order_id":"123456789"},"status":"success"}如果用户投诉“查错了”,你可以回溯。
十三、踩坑记录
坑 1:让模型直接调用高风险工具
例如:
发送邮件 删除数据 退款操作这类工具必须有人审或二次确认。
坑 2:缺参数也调用工具
参数不完整时,必须反问。
不要让模型猜。
坑 3:没有工具白名单
工具必须注册,不允许模型生成任意函数名。
坑 4:工具失败后模型编结果
工具失败时必须明确告诉用户失败,不允许模型伪造结果。
坑 5:不记录调用日志
Agent 系统一定要可审计。
十四、适合收藏的 Agent 工具调用 Checklist
工具定义: [ ] 是否有工具白名单 [ ] 是否定义 required_params [ ] 是否区分高风险工具 [ ] 是否有工具描述 路由: [ ] 是否先识别 intent [ ] 是否有 intent 到 tool 的映射 [ ] 是否有 confidence [ ] 低置信度是否反问 参数: [ ] 是否抽取参数 [ ] 是否校验缺失参数 [ ] 是否禁止模型猜参数 执行: [ ] 是否捕获工具异常 [ ] 是否有超时控制 [ ] 是否有重试限制 [ ] 是否记录工具日志 安全: [ ] 高风险操作是否二次确认 [ ] 是否支持人工介入 [ ] 是否禁止任意工具调用十五、经验总结
Agent 的核心不是让模型“想干什么就干什么”。
真正可上线的 Agent 必须是:
模型理解意图 工程控制动作 工具提供结果 系统负责审计一句话总结:
Agent 不是聊天机器人加几个函数,而是一个受控的任务执行系统。十六、优化建议
后续可以继续做:
1. 使用 LLM 做 intent 分类 2. 加入置信度机制 3. 高风险工具二次确认 4. 工具调用超时和熔断 5. 工具结果二次总结 6. 构建工具调用评测集 7. 增加多工具编排能力 8. 接入审计日志最后一句经验:
Agent 能不能上线,不取决于它多聪明,而取决于它是否可控。