Taylent Labs
返回博客列表
LLMFunction CallingAgent架构设计

LLM 应用的函数调用设计模式:从单次调用到多轮规划

系统梳理 Function Calling 的三种典型模式——单次调用、顺序链式与并行规划,分析各自适用场景与实现要点,帮助工程师选择合适的架构方案。

Function Calling 是让 LLM 应用从对话工具变成实际执行系统的关键能力。但在实际工程中,「调用函数」这件事远比 API 文档里的示例复杂:单次调用、链式执行、并行规划各有适用边界,选错模式会让系统既慢又脆弱。

单次调用:确定性任务的最优解

最简单的模式是用户意图明确、只需调用一个函数的场景。假设一个客服系统需要查询订单状态,用户问「我的订单 #12345 发货了吗」,LLM 解析出 query_order_status(order_id="12345") 后直接执行并返回结果。

这种模式的优势是延迟可控(一次 LLM 推理 + 一次函数执行)、成本固定、易于调试。关键实现要点:

  • 函数定义要严格:参数类型、枚举值、必填项都要在 schema 里明确,避免 LLM 生成无效调用
  • 立即执行不等待:拿到函数调用就执行,不要再让 LLM 二次确认(那会多一轮推理成本)
  • 结果直接返回:除非业务要求二次加工(如翻译成更友好的话术),否则函数返回值就是最终答案

适用场景:查询类工具(天气、汇率、库存)、单步操作(发邮件、创建工单)、确定性强的业务流程。

顺序链式:依赖关系明确的多步任务

当任务需要多个函数且存在数据依赖时,就需要链式调用。假设一个报表生成场景:先调用 get_sales_data(region="华东") 获取原始数据,再调用 generate_chart(data=..., type="bar") 生成图表,最后调用 send_email(attachment=...) 发送。

工程上有两种实现路径:

LLM 驱动链式:每次函数执行后把结果返回给 LLM,让它决定下一步。优点是灵活(LLM 可根据中间结果调整策略),缺点是多轮推理累积延迟和成本。

预定义工作流:如果步骤固定,可以在应用层写死 DAG(有向无环图),LLM 只负责填参数。假设「生成周报并发送」是高频需求,直接把三个函数编排成流程,LLM 调用 generate_weekly_report(region=...) 这一个入口函数即可。

选择标准:步骤越固定越倾向预定义工作流,中间分支越多越需要 LLM 动态决策。

并行规划:复杂目标的分解与协同

最复杂的模式是用户给出模糊目标,需要 LLM 自主拆解成多个可并行的子任务。假设用户说「帮我准备明天去上海的行程」,系统需要同时查询航班、酒店、天气、会议日程,这些调用之间没有依赖关系,可以并发执行。

实现要点:

  • 规划阶段与执行阶段分离:先让 LLM 输出完整的函数调用列表(可以是 JSON 数组),再批量执行,避免边规划边执行导致的上下文混乱
  • 并行执行要有超时与降级:某个函数卡住不应阻塞整体,设置合理的超时(如 5 秒),失败的调用返回 {"error": "timeout"} 让 LLM 基于部分结果继续
  • 结果聚合交给 LLM:多个函数返回后一次性喂给 LLM,让它综合成用户友好的回答,而不是简单拼接

这种模式的成本高(规划推理 + 结果聚合推理),但对复杂任务体验提升明显。判断是否需要它的标准:用户意图是否需要跨多个数据源、子任务是否可独立完成、并行执行能否显著减少总耗时。

工程实践中的通用建议

无论哪种模式,都要处理好这些共性问题:

  • 函数执行失败的处理:返回结构化错误(错误码 + 可读消息),让 LLM 有机会重试或换策略,而不是直接抛异常中断流程
  • 上下文窗口管理:多轮调用会快速消耗 token,对历史消息做截断(保留系统提示词 + 最近 N 轮对话),或者用摘要压缩早期轮次
  • 可观测性:记录每次函数调用的参数、返回值、耗时,出问题时能快速定位是 LLM 规划错了还是函数执行失败

如果你的团队正在搭建复杂的 LLM 应用,需要在架构选型、成本优化、可靠性保障上获得支持,欢迎联系 Taylent Labs 讨论具体方案。