Sunday 的面试指南

Agent 的多个工具可以并行调用吗?什么时候必须串行?

🧑‍💻 面试官:Agent 处理退款时,需要查物流、查支付,再执行退款。这几个工具可以一起调用吗?

🙋‍♂️ 我:查物流和查支付可以并行,退款要等查询结果出来以后再执行。

🧑‍💻 面试官:查物流需要运单号,查支付需要支付流水号。但用户只给了订单号,这时候怎么并行?

🙋‍♂️ 我:那就需要先查订单,拿到这两个编号,再同时查物流和支付。

🧑‍💻 面试官:如果物流已经查到了,支付接口却超时了呢?这一轮是不是全部重跑?还能不能继续退款?

这道题先抓住一个词:「依赖」。后一步需要前一步的结果,就必须等;互不依赖的调用可以考虑并行,但还要检查数据冲突和失败后的处理。

面试速答(60 秒版)

Agent 的多个工具可以并行调用,但要先看它们之间有没有依赖,以及同时执行会不会发生冲突。

例如,拿到运单号和支付流水号以后,查物流和查支付通常可以同时进行。但如果这两个编号还需要通过查订单获得,就必须先查订单,不能让模型自己猜参数。

同时,模型一次返回多个工具请求,也不代表这些请求都应该一起执行。运行器需要根据工具的规则和当前状态,决定哪些可以并行、哪些需要等待。

如果涉及退款这类操作,还要等必要信息齐全、业务校验和用户确认通过以后再执行。某个查询失败时,可以保留其他有效结果,但不能把缺失的信息当成已经查到了。

编号齐全且互不依赖时可以并行查询;缺少运单号时,先等订单查询返回结果

知识点详解:怎样安排工具调用的执行顺序?

模型提出几个调用,程序就要同时执行几个吗?

不是。

模型返回的工具调用,主要是在告诉应用:“我想使用这个工具,参数是这些。”真正连接业务系统、发起请求的,仍然是应用中的工具执行器。

因此,这里有两件不同的事:模型可以一次提出多个调用;程序则需要判断,这些调用应该怎样执行。

Anthropic 的并行工具文档也明确区分了这两件事:对于应用执行的工具,一次响应中出现多个调用,并没有规定它们必须按某种顺序执行。应用可以根据工具要求,选择并行、串行或者两者结合。

但是,“顺序由应用决定”也不是说可以随便排序。工具需要什么参数、会修改什么数据、前面有没有必须完成的操作,这些都要算进去。

先顺着一个退款任务,看清楚依赖在哪里

假设用户说:“帮我看看这笔订单能不能退款。”目前,用户只提供了订单号。

这个业务规定,订单未发货,并且支付记录允许退款,才可以进入退款流程。下面的工具也是为了讲解而假设的,不是某个框架自带的 API。

第一步,Agent 调用 get_order 查询订单。工具返回订单信息,其中包含运单号 shipment_id 和支付流水号 payment_id。

拿到这些信息以后,才能分别调用 get_shipment 查询物流、调用 get_payment 查询支付。

为什么不能把这三个查询一起发出去?

因为后两个工具需要的编号,还在第一个工具的结果里面。第一个查询没有完成,后两个查询就缺少必要参数。这种“后一步需要前一步提供信息”的关系,就是数据依赖。

不过,查物流不需要等待支付结果,查支付也不需要等待物流结果。因此,订单查询成功、参数准备好以后,这两个查询就可以并行。

等两个结果都返回,再由业务代码检查退款条件。符合条件时,向用户说明金额并请求确认;用户确认后,才可以请求执行退款。退款服务还需要重新检查权限和当前业务状态,避免查询期间订单已经发生变化。

所以,整个任务并不是只能选择“全部串行”或者“全部并行”。同一个任务里面,有些步骤要按顺序执行,中间的一部分则可以同时进行。

如果用户已经提供了可信、完整的查询参数,也不需要为了形式,再增加一次前置查询。判断依赖,要看当前到底缺什么,而不是把案例中的步骤当成固定模板。

下面这张图把整个过程放在一起。中间的两路查询可以同时进行,但前面的参数准备、后面的校验和确认,仍然有先后关系。

先查订单取得编号,物流与支付两路并行查询,核对条件并取得确认后才执行退款;支付超时则暂不退款

没有数据依赖,就一定可以并行吗?

还不一定。

前面查物流和查支付,只是在读取信息,而且分别使用自己的返回结果。这样的调用通常比较适合并行。

但如果两个工具都要修改同一个订单,情况就不一样了。

例如,一个工具要取消订单,另一个工具要把订单修改为“已发货”。它们的参数可能都已经齐全,也不需要读取对方的返回值,但这两个业务动作本身就有冲突。

这时候,不能只看参数有没有准备好。服务端需要按业务规则处理状态变更,使用事务、版本校验或合适的互斥机制,阻止不允许的操作。仅仅把两个调用排成先后顺序,也不能保证它们都会变得合法。

同时,只读工具也不等于完全没有限制。如果多个调用共用一个只能顺序操作的浏览器页面,或者下游接口已经接近限流上限,程序仍然需要控制执行顺序和并发数量。

因此,安排并行时要问清楚:它们是否互相等待结果?会不会同时影响同一个对象?当前环境能不能承受这些调用?

一个查询失败了,已经成功的结果怎么办?

咱们再回到前面的退款任务。

假设物流查询成功了,但支付查询超时。系统现在知道订单是否发货,却还不能确认这笔支付是否允许退款。

这时候,可以保存物流结果,再根据超时原因和重试规则,补查支付。没有必要因为一个调用失败,就把已经成功的调用全部重跑。

不过,保留结果也有条件。如果用户确认花了很长时间,订单状态可能已经改变,那么旧的查询结果就需要重新确认,不能一直使用。

运行器还要把每次调用的结果和对应的调用标识关联起来。例如,物流结果对应物流调用,支付错误对应支付调用,不能按照“谁先返回”,就把它当成列表里的第一个结果。模型协议使用什么字段来关联,应该遵循对应 API 的规定。

必要的支付信息没有查到,就先暂停退款这一步,向用户解释当前还缺什么,或者转人工处理。不能因为另一个查询成功,就把整个任务判断成成功。

检查这套设计时,也不要只看总耗时。应该准备正常查询、单个工具超时、结果顺序颠倒、订单状态变化等用例,检查是否拿到了正确结果、有没有执行不该执行的退款。日志中保留每次调用的开始时间、结束时间和状态,才能确认哪些调用真的重叠执行,以及失败后发生了什么。

面试官继续追问

写操作是不是都必须串行?

不必这么绝对。

例如,分别给两个互不关联的订单添加备注,如果服务支持并发、用户有相应权限,也没有共享资源冲突,就可以考虑并行。

但是,“订单编号不同”也不能单独证明互不影响。它们可能扣减同一个账户余额,或者使用同一份库存。是否可以并行,仍然要看实际影响的资源和业务约束。

工具之间互不依赖,是不是开得越多就越快?

也不是。

并行可以减少一个调用等待另一个调用的时间,但不能让下游服务拥有无限处理能力。

假设一次任务需要查很多订单,可以先设定最多同时执行几个查询,剩下的排队。具体上限要根据下游限流、连接数和压测结果确定,而不是直接把所有请求发出去。并发增加后,错误和重试也可能增加,最后反而更慢。

并行调用中有一个失败,其他调用会自动停止吗?

不能这样假设。

例如,TypeScript 常用的 Promise.all()会在一个请求报错时让等待方收到错误,但不会自动取消其他已经发起的操作。Python 的 asyncio.gather()在默认设置下,传播一个任务的异常,也不会因此取消其他任务。

因此,收到报错以后,要核对其他调用的状态。需要停止的操作,应使用对应工具支持的取消方式;已经发生的退款,也不会因为程序抛出了异常,就自动退回到执行前。

面试速记卡

  • 数据依赖:后一步需要前一步的结果,就先等待结果。
  • 并行条件:参数已准备好、调用互不依赖,还要确认资源与业务允许。
  • 执行职责:模型提出工具请求,运行器安排实际执行。
  • 失败处理:保留仍然有效的成功结果,不把缺失信息当成成功。
  • 写操作:检查真实影响的对象,串行执行也不能代替业务校验。
  • 性能判断:看总耗时、错误和重试,不只看同时调用了多少工具。
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历