若查询天气后,还要根据天气推荐买伞这类服务,大模型如何按顺序调用多个服务?如果有七八项服务,每个服务的调用逻辑都要单独写吗
1️⃣ 考察意图
面试官想考察你对 Agent 系统中多工具编排的设计能力,而非单纯背 Function Calling 概念。刁钻点在于:从“天气→买伞”的简单顺序调用,扩展到“七八项服务”的规模化问题,看你能否区分硬编码与模型自主规划的取舍。答好了能展示你对 ReAct、Plan-and-Execute、工具注册表等架构的实战理解,以及处理动态调用链的工程经验。
2️⃣ 标准答
核心思路:不写死调用逻辑,而是让模型自主生成计划,由执行引擎调度。具体分三步:
1. 确定服务调用模式
- 顺序调用:如“查天气→推荐商品”,依赖前一步输出。
- 条件调用:如“若下雨则调用买伞服务,否则推荐防晒霜”。
- 并行调用:如同时查天气和用户位置,减少延迟。
- 工程取舍:顺序调用简单但低效,并行调用需处理依赖关系。实际用有向无环图(DAG) 描述任务依赖,执行引擎按拓扑排序调度。
2. 框架选择:ReAct vs. Plan-and-Execute
- ReAct(推理+行动):模型每步输出一个工具调用,适合步骤不确定的场景。例如 OpenAI Function Calling 中,模型输出
{"tool":"get_weather","args":{"city":"北京"}},执行后结果喂回模型,再决定下一步。 - Plan-and-Execute:模型先输出完整计划(如 JSON 步骤列表),再逐步执行。适合步骤明确的场景,如“天气→推荐→下单”。实际落地的坑:模型可能生成无效计划(如循环依赖),需加计划校验器,检查步骤是否可执行、参数是否完整。
- 我的选择:对于七八项服务,用 Plan-and-Execute 更可控,因为模型一次生成计划,减少多轮推理的 Token 消耗和幻觉风险。
3. 工具注册表与调度器
- 无需单独写每个调用逻辑:定义统一的工具注册表,每个工具暴露名称、描述、输入输出 Schema(如 JSON Schema)。模型根据任务描述动态选择工具,调度器解析模型输出并执行。
- 示例:注册表包含
get_weather、recommend_umbrella、place_order。模型输出计划:
[ {"tool":"get_weather", "args":{"city":"北京"}}, {"tool":"recommend_umbrella", "args":{"weather":"${step1.result}"}}, {"tool":"place_order", "args":{"product":"${step2.result}"}} ] 调度器解析 step1.result 等变量,按顺序执行。
- 实际落地的坑:工具描述不清晰导致模型选错工具。解法:工具描述加示例,如
get_weather描述写“返回城市天气,示例:get_weather(city='北京') -> {'rain': True}`。
4. 规模化扩展
- 七八项服务无需硬编码,但需考虑工具冲突(如两个工具都叫
search)。解法:工具命名空间,如weather_searchvsproduct_search。 - 性能优化:用 HNSW 索引 加速工具选择(当工具数 > 50 时),或基于 BM25 检索工具描述,减少模型输入长度。
3️⃣ 答题模板(30 秒电梯版)
“这个问题我从三个层面回答:第一,调用模式上,区分顺序、条件、并行,用 DAG 描述依赖;第二,框架上,用 Plan-and-Execute 让模型先生成计划,再用调度器执行,避免硬编码;第三,规模化上,定义统一的工具注册表,模型根据描述动态选择工具,七八项服务只需注册一次。总结一句:核心是让模型自主规划,执行引擎负责调度,而不是写死每个调用逻辑。”
4️⃣ 高频追问 & 应对
追问 1:如果模型生成的计划有循环依赖(如 A 依赖 B,B 依赖 A),你怎么处理?
在计划校验器中加依赖图检测:用拓扑排序检查是否有环。若有环,回退到 ReAct 模式,让模型单步推理。实际工程中,我会在计划 Schema 中限制
depends_on字段只能引用已完成的步骤,并设置最大步骤数(如 10 步),防止无限循环。
追问 2:七八项服务中,如果某个服务调用失败(如天气 API 超时),整个流程怎么恢复?
设计重试+降级机制:对每个工具调用设置超时(如 5 秒)和重试次数(如 3 次)。若失败,调度器返回错误给模型,让模型重新规划(如跳过该步骤或换工具)。例如天气 API 失败,模型可调用
get_weather_from_backup。工程取舍:重试增加延迟,但提高成功率;降级可能降低结果质量。
追问 3:模型生成的计划中,参数引用(如 ${step1.result})如何解析?
用变量替换引擎:执行完 step1 后,将结果存入上下文(如
{"step1": {"rain": True}}),然后替换 step2 参数中的${step1.result.rain}为True。注意处理嵌套 JSON 路径,用类似jq的语法。实际坑:模型可能引用不存在的字段,需加字段存在性检查,若缺失则报错并让模型重新生成。
5️⃣ 避坑 · 常见错误答法
- ❌ “用 if-else 写死每个调用逻辑,七八项服务就写七八个 if 块。” → ✅ “用工具注册表+调度器,模型动态选择工具,避免硬编码。if-else 无法应对服务增减或参数变化。”
- ❌ “让模型一次输出所有工具调用,然后并行执行。” → ✅ “需考虑依赖关系,用 DAG 描述。并行执行无依赖步骤,顺序执行有依赖步骤,否则结果错误。”
- ❌ “用 ReAct 框架,模型每步输出一个工具调用,简单可靠。” → ✅ “ReAct 适合步骤不确定的场景,但七八项服务时多轮推理 Token 消耗大,Plan-and-Execute 更高效。需根据场景选择。”
6️⃣ 简历呼应
- 如果你有 Agent 项目:从“实际落地中如何设计工具注册表”切入,举例你如何用 JSON Schema 描述工具,并处理模型选错工具的 case。
- 如果你只做过传统 NLP:用“工作流引擎”类比,如 Airflow 的 DAG 调度,说明 Agent 的 Plan-and-Execute 类似但由模型动态生成计划。
- 如果你是校招无项目:聚焦论文复现,如 ReAct 论文(arXiv:2210.03629)中如何用 CoT 推理+工具调用,并实现一个天气+推荐的 demo。
- ReAct: Synergizing Reasoning and Acting in Language Models (arXiv:2210.03629)
- Plan-and-Solve Prompting: Improving Zero-Shot Chain-of-Thought Reasoning (arXiv:2305.04091)
- Toolformer: Language Models Can Teach Themselves to Use Tools (arXiv:2302.04761)
- OpenAI Function Calling 官方文档:如何定义工具 Schema
- LangChain Agent 源码:工具注册表与调度器实现