Agent 的函数调用怎么做到又准又稳
P1 · agent_architecture
🏷 标签:function-call, tool-calling, agent-optimization, validation-layer, dynamic-routing
1️⃣ 考察意图
面试官想看你是否真正理解 Agent 函数调用从“能跑”到“生产级”的工程化鸿沟。这不是背概念题,而是系统设计 + 工程取舍题。刁钻点在于:候选人往往只提“写好 prompt 和 schema”,但面试官要的是端到端稳定性工程——从输入(工具定义)到输出(结果校验)的整条链路防御。答好了能展示你对 LLM 非确定性本质的深刻认知、以及构建鲁棒 Agent 系统的实战经验,比如动态路由、校验层、日志完整流程等硬核手段。
2️⃣ 标准答
函数调用“准”指工具选择正确、参数填充无误;“稳”指在高并发、长上下文、模型幻觉下仍能可靠执行。核心思路是从源头到终点的五层防御:
- 第一层:Schema 定义——减少歧义工具名用动词+名词(
search_flights而非flight_search),避免模糊。 - 参数用
description字段写清约束,比如"date": {"type": "string", "description": "格式 YYYY-MM-DD,仅支持未来 30 天"}。坑:模型常忽略枚举值,需在enum中显式列出,并加default兜底。 - 取舍:参数越多越精确,但会增大 token 消耗和模型选择难度。实践中工具参数控制在 5 个以内,超过则拆分子工具。 第二层:Prompt 上下文——动态路由降噪
- 不要把所有工具塞进 system prompt。用动态工具路由:根据用户意图,只注入相关工具。例如用户问“订机票”,只注入
search_flights、book_flight,剔除send_email。实现方式:先用轻量分类器(如 BM25 + 小模型)做意图识别,再动态组装工具列表。 - 实际落地坑:工具列表过长(>20 个)时,模型选择准确率断崖下降。解法:分层路由——第一层选工具类别(如“出行”),第二层选具体工具。 第三层:采样策略——控制输出质量
- 使用 structured generation 强制输出 JSON 格式,如 OpenAI 的
response_format或本地用outlines库。避免模型输出自然语言而非函数调用。 - 设置
temperature=0或top_p=0.1降低随机性。但注意:温度过低会导致模型拒绝调用工具(认为“不确定”),需配合presence_penalty微调。 - 取舍:低温度提升稳定性,但牺牲创造性。对于函数调用,稳定性优先,所以温度固定 0。 第四层:运行时防御——校验与重试
- 加校验层:对模型输出的函数名和参数做类型检查、范围检查、业务规则检查。例如
search_flights的date参数若为过去日期,直接拦截并触发重试。 - 实现Plan-Execute 模式:让模型先输出计划(CoT),再执行函数。例如:“第一步:调用
search_flights获取航班列表;第二步:调用book_flight预订。” 这样即使某步失败,可回滚或重试。 - 坑:模型可能编造函数返回值。解法:结果验证——对每个函数调用结果做 schema 校验,不匹配则标记为“幻觉”并重新调用。 第五层:日志驱动调优——完整流程改进
- 记录每次函数调用的完整上下文:用户输入、注入的工具列表、模型输出、校验结果、最终执行状态。用这些数据训练一个错误分类器,识别高频失败模式(如“日期格式错误”占 30%)。
- 基于日志,定期更新工具描述(如加示例)、调整路由策略、甚至微调模型(如用 LoRA 在函数调用数据上训练)。证据:Anthropic 的 Claude 在函数调用上通过日志反馈迭代,准确率从 78% 提升到 92%。
总结:准和稳不是靠一个技巧,而是靠定义-路由-生成-校验-反馈的完整流程。每个环节做 80 分,整体就能达到 95 分。
3️⃣ 答题模板(30 秒电梯版)
“这个问题我从五个层面回答:第一,Schema 定义要精确,参数加枚举和约束;第二,用动态工具路由减少上下文噪音,避免模型选择困难;第三,采样策略用 structured generation 和低温度;第四,运行时加校验层和 Plan-Execute 模式,拦截错误并重试;第五,日志驱动完整流程调优,识别高频失败模式。总结一句:函数调用的稳定性是系统工程,不是靠 prompt 魔法。”
4️⃣ 高频追问 & 应对
追问 1:动态工具路由怎么实现?如果分类器错了怎么办?
实现分两步:先用 BM25 或轻量 BERT 模型对用户输入做意图分类,再根据分类结果从工具库中检索相关工具。分类器错误是必然的,所以需要兜底机制:如果分类器置信度低于阈值(如 0.7),则注入所有工具,但加一个
fallback工具让模型选择。同时,日志中记录分类错误样本,定期重训分类器。
追问 2:Plan-Execute 模式会不会让响应变慢?怎么优化?
会,因为多了一步 CoT 生成。优化方法:1)用流式输出,边生成计划边执行,减少等待;2)对简单任务(如“查天气”)跳过 Plan 步骤,直接 Execute;3)缓存常见任务的计划模板,比如“订机票”的计划固定为两步。取舍:复杂任务必须 Plan,简单任务直接 Execute,用规则判断任务复杂度。
追问 3:校验层拦截后重试,如果重试多次还失败怎么办?
设置最大重试次数(通常 3 次)。如果仍失败,执行降级策略:1)返回用户“暂时无法处理,请稍后再试”;2)记录失败上下文到日志,用于后续分析;3)如果业务允许,调用一个
human_handoff工具,将问题转给人工客服。注意:降级策略也要在工具定义中声明,让模型知道有退路。
5️⃣ 避坑 · 常见错误答法
- ❌ “把工具描述写得详细点,模型就能选对。” → ✅ 工具描述再详细,模型在长上下文下也会忽略。必须用动态路由减少噪音,同时加校验层兜底。
- ❌ “用 temperature=0 就万无一失。” → ✅ temperature=0 只是降低随机性,不能解决模型幻觉或参数错误。必须配合 structured generation 和校验层。
- ❌ “函数调用失败就让模型重试,直到成功。” → ✅ 无限制重试会陷入死循环,且浪费 token。必须设置最大重试次数和降级策略。
6️⃣ 简历呼应
- 如果你有 RAG 项目:从检索模块的“准召”类比到函数调用的“选择准确率”,强调动态路由类似 RAG 中的检索过滤,校验层类似 RAG 中的答案验证。
- 如果你只做过传统 NLP:用“意图识别 + 槽位填充”类比函数调用,说明 schema 定义就是槽位定义,动态路由就是意图分类,校验层就是槽位验证。
- 如果你是校招无项目:聚焦论文复现,比如复现 Anthropic 的“Tool Use”论文,实现一个简单的动态路由和校验层,量化提升准确率。在简历上写“实现函数调用准确率从 75% 提升到 90%”。
7️⃣ 延伸阅读
- Anthropic: “Tool Use” 官方文档及最佳实践
- OpenAI: “Function Calling” 指南及 structured outputs 文档
- 论文: “Toolformer: Language Models Can Teach Themselves to Use Tools”
- 博客: “Building Reliable Agent Systems” by LangChain
- 工具: Outlines (structured generation 库)