ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

字节三面挂了!多 Agent 编排四连问我都答上了,却没答到点上

字节三面挂了!多 Agent 编排四连问我都答上了,却没答到点上 我说你把面试过程尽量还原给我。他答得很细。前两轮都过了——项目、JVM、并发答得都不错。三面是架构面。面试官先让他讲手上那个 AI 项目他讲了大概十分钟——四个 Agent理解意图、检索知识库、生成回答、质量校验串起来跑。讲完面试官开始往下挖。一共四个回合第一问检索那个 Agent 如果超时了你们怎么处理他答重试一次还失败就走兜底话术。第二问重试的时候前面意图理解的结果还要重跑一遍吗他愣了一下应该不用吧我们是缓存下来的。第三问把最后的质量校验改成三路并行准确性、合规性、可读性各一路改动大吗他答那得改不少代码现在流程是写死的。第四问想让不同类型的咨询走不同链路账单走财务 Agent、技术走技术 Agent现在这套能支持吗他答可以加 if-else。四个回合他每一问都答了没有一句接不上。但面试官心里已经有判断了。最后他说了一句你搭的不是多 Agent 系统是一条写死的流水线。复盘的时候我把这四个回合记下来发现它们指向的是同一件事。他挂的不是知识盲区。五种编排模式——链式、并行、路由、层级、反思——他都能说出来自己项目用的哪一种也清楚还能讲两句为什么选它。他缺的是这些模式为什么存在以及在什么条件下该换成另一个。换句话说他知道工具箱里有什么但没想过工具箱是拿来干什么的。这一层叫编排层。编排模式解决的是「Agent 怎么连」编排层解决的是「任务怎么走」。前者是拓扑后者是策略。复盘完之后我把这四个回合的问题往上抽了一层拿去问身边做 AI 应用的团队——第一个 Agent 挂了链路怎么恢复A 的中间结果传到 E还剩多少有效信息换一类任务进来编排逻辑要不要改代码三个都能答上来的不多。这篇文章就是那次复盘的完整版。大部分多 Agent 项目不是在选错模式上翻车的是在编排层这一层翻车的。1.多 Agent 系统 ≠ 多 Agent 编排这两个词经常被混着用但它们是两件事。多 Agent 系统描述的是「有几个 Agent」。三个 Agent 互相调用就是多 Agent 系统了。门槛很低低到只要你愿意写三个类就能自称。多 Agent 编排描述的是另一组问题在什么条件下、用哪种协作方式、以什么顺序、传递什么状态、失败之后怎么办。举个不恰当但好记的类比。乐队里多坐几个人不叫交响乐。有指挥、有谱子、知道第二乐章该谁进才叫交响乐。多出来的那几个 Agent就是多坐的那几个人。谱子和指挥才是编排。怎么判断自己有没有编排层看三个特征特征落地表现动态性同一套代码能根据任务状态切换到不同的协作策略而不是换任务就改 if-else状态显式状态如何产生、如何流转、如何裁剪是写在代码里的不是藏在某个 Agent 的 prompt 里失败可恢复局部失败后重规划或降级而不是把整条任务从头再跑一遍三个都占了才谈得上编排。少一个本质上就是「多个 Agent 各干各的」。2.五种模式一张表过完先把地基铺上。多 Agent 编排的协作模式收敛下来就五种一张表能说完。模式一句话选型条件核心代价链式A→B→C 顺序传递像流水线任务有严格先后依赖且环节不超过 5 步脆弱断一环全停越靠后信息越少并行子任务同时下发汇总节点收敛子任务之间无依赖且需要多维度整合汇总 Agent 就是输出上限Token 成倍消耗路由先识别类型再对口分派专家任务类型边界清晰判错就派错跨类型需求无解层级树形管控编排器管编排器项目分阶段、复杂度高且阶段内部仍需协作延迟随层数上升极易过度设计反思执行-评审-迭代闭环质量要求极高且用户能接受等待轮次不可控评审标准偏了会越改越差五种模式画成拓扑差别一眼能看出来这张表能撑住你 80% 的选型。但请注意它回答的是「怎么连」。而系统跑不通往往是因为下面这四件事。3.真正难的是这四件事这四条选型表里一个字都不会写但它们才是你上线之后每天要面对的东西。3.1 上下文在传递中衰减链式编排最容易被忽略的问题不是慢是信息衰减。A 产出一份 3000 token 的分析B 拿到之后总结成 800 tokenC 再压缩到 200 token。等到 D 要用的那个关键数字可能在 C 那一步就被当作「细节」扔掉了。层级编排更明显。每一层抽象都在做有损压缩压三四层之后底层的事实已经变形了。这个问题的本质是你让 Agent 互相传「对话」而不是传「状态」。工程上的解法是黑板模式Blackboard。所有 Agent 读写同一个共享状态区谁需要什么自己取而不是把上游的整段上下文往下灌。public class OrchestrationContext { // 所有 Agent 共享的状态区 private final MapString, Object blackboard new ConcurrentHashMap(); // 产出写入黑板key 用「阶段.字段」命名避免撞车 public void put(String key, Object value) { blackboard.put(key, value); } // 需要什么取什么不做整段上下文传递 public T OptionalT get(String key, ClassT type) { return Optional.ofNullable(blackboard.get(key)).map(type::cast); } // 关键给 LLM 的是「按阶段裁剪过的视图」不是全量状态 public String viewFor(String stage) { return VIEW_SPEC.get(stage).stream() .map(k - k : blackboard.get(k)) .collect(Collectors.joining(\n)); } }区别就在最后那个viewFor。上游把全量状态写进黑板但每个阶段只能看到自己该看的那几个字段。既避免了链式传递的信息衰减也顺手解决了上下文窗口被无关内容占满的问题。坑黑板别做成大杂烩。字段命名一定要带阶段前缀否则三个人并行开发一星期后没人知道这个 key 是谁写的、还能不能删。3.2 失败之后是重跑还是重规划这是区分「有编排层」和「没编排层」最直接的一道题。没编排层第 7 个 Agent 报错了异常往上抛整个任务失败。用户看到「系统繁忙请重试」然后从头再跑一遍。前面 6 个 Agent 的钱白花了。有编排层第 7 个 Agent 报错了编排层知道前面 6 步的产出已经落在黑板里于是尝试换一个 Agent 兜底、或者降级输出、或者只重跑第 7 步。要做到这一点需要两个前提状态可序列化步骤尽量幂等。做不到这两条你的「重试」就只能是从头再来。所以编排层的主循环长这样public TaskResult run(Task task) { OrchestrationContext ctx new OrchestrationContext(); TaskState state TaskState.ROUTE; while (state ! TaskState.DONE state ! TaskState.FAILED) { if (budget.exhausted()) { // 预算兜底 state TaskState.DEGRADE; continue; } try { state nodes.get(state).execute(ctx); // 节点返回下一个状态 } catch (AgentException e) { state compensate(state, e); // 局部失败 - 重规划 } budget.consume(ctx.deltaUsage()); } return TaskResult.of(state, ctx); }这个循环里有两个设计值得单独说execute返回的是「下一个状态」而不是「结果」——状态推进权在编排层手里Agent 没法自己乱跑compensate把异常转成状态跳转失败就成了流程的一部分而不是流程的终点。3.3 成本必须有预算概念并行编排 Token 翻 N 倍这个大家都知道。真正失控的是反思编排。「不达标就打回重写」听着很美但它是个开环。评审 Agent 的标准只要稍微严一点迭代就停不下来。我见过一个内容生成的场景一个任务反复改了 11 轮最后产出的质量还不如第 3 轮。编排层必须给任务挂预算而且得是三重的Token 预算、时长预算、迭代轮次上限。任何一项触顶强制走降级出口——返回当前最优结果而不是继续烧。预算触顶后的降级策略也是要提前设计的是返回半成品还是返回上一轮结果还是转人工这三种在业务上的体验完全不同。3.4 可观测性多 Agent 的日志是线团单 Agent 出问题看日志就行。多 Agent 出问题你面对的是几路日志交织在一起的线团而且每路都是一个 LLM 的输入输出。最低限度你得能回答四个问题这次任务走了哪条路径状态流转轨迹每一步花了多少钱、多少时间哪一步失败了失败时黑板里有什么同一个任务重跑一次路径会不会不一样最后一条尤其重要。LLM 的输出有随机性路径不稳定意味着你的系统行为不可复现。这也是为什么很多团队最后会走回「关键节点用规则兜底、只在明确的环节放 LLM」——不是不信任模型是要保住可复现性。4.编排层的三种落地形态道理说完说说怎么落地。编排层不是非得引入什么框架它有三种形态复杂度递增。形态一硬编码状态机就是枚举 switch。状态不超过 5 个、分支不超过 10 条的时候这是最省事也最好调试的方案。别看不起它很多跑得稳的系统就这么写的。但它有个明确的崩点状态一多状态转移的合法性就得靠人脑维护漏一个分支就是线上事故。形态二图结构编排把状态机画成一张图节点是 Agent边是转移条件。图引擎帮你做拓扑校验、并行调度、断点恢复。LangGraph 这类框架走的就是这条路自研一套也不复杂。适合协作关系复杂、需要动态并行的场景。形态三声明式编排编排逻辑从代码里抽出来用 YAML 或 DSL 描述。好处很实在业务规则变了不用发版改配置就行。orchestration: order-exception steps: - id: classify agent: router next: STOCK_OUT: [checkStock, buildCompensation] PAY_TIMEOUT: [queryPayment, retryOrRefund] RISK_BLOCK: [riskReview] - id: checkStock agent: inventory parallel: [checkRisk, loadUserProfile] # 同组并行 - id: buildCompensation agent: planner review: quality-checker # 反思评审不过打回 maxRetries: 2 budget: maxTokens: 120000 maxSeconds: 60代价是调试变难了。逻辑不在代码里断点打不进去出问题只能靠链路追踪反查。选择标准状态少于 5 个用形态一别过度设计协作关系会持续变复杂直接上形态二只有「业务规则频繁变、却又不值得发版」这一个理由才值得付形态三的调试成本。5.一个完整的例子订单异常怎么编排拿电商的订单异常处理来串一遍。这个场景好在它天然有分类、有并行、有串行、有质量要求五种模式里能用到四种。场景是这样的用户下单之后订单卡住了。可能的原因有一堆——库存不足、支付超时、地址异常、风控拦截。把这四种模式串起来整条链路是这样路由异常分类 Agent 先判断类型分派到不同的处理链路。这一步不能省否则所有异常都走同一条又长又慢的路。并行库存、风控、用户画像三个查询同时发起。它们之间没有依赖串行跑纯属浪费。汇总节点收敛成一份「异常上下文」。链式补偿方案生成 → 人工审核 → 执行。这三步有严格先后依赖而且只有三步链式最合适。反思补偿话术生成之后交给评审 Agent 检查——金额算得对不对、措辞会不会引发投诉。不达标打回重写但轮次上限卡死 2 轮。你会注意到编排层在这里的角色不是「调用 Agent」而是「决定此刻该用哪种协作方式」。风控拦截的订单压根不需要走补偿方案生成直接从风险评估跳到人工介入。库存不足的订单话术要往「调货」方向走而不是「退款」方向走。这些决策都不属于任何一个 Agent只属于编排层。模式是静态的任务状态是动态的。真实系统里同一个任务在推进过程中会需要换协作方式。能在运行中做出这个切换的才是编排器做不到的只是调度器。6.选型一套顺序一句口诀最后落到可执行的东西上。选型别一上来就比框架先过下面这个顺序第一问任务之间有依赖吗有严格先后 → 链式完全独立 → 并行。第二问需要多维度整合吗需要 → 并行 汇总只需要一类专业能力 → 考虑路由。第三问复杂度是分阶段的吗是且阶段内部还要协作 → 层级。否则别上这是最容易过度设计的一档。第四问质量要求高到需要返工吗是且用户能等 → 反思但必须配轮次上限。第五问预算够吗并行翻倍、反思无上限算不清就先降级方案。如果嫌长记这五句就行——先后有依赖链式。子任务独立并行。类型有区分路由。复杂分阶段层级。追求高质感反思。但还是要补一句真实生产环境里几乎没有系统只单用一种模式。模式是零散的积木。会用积木搭出什么取决于编排层怎么决策。写在最后复盘到最后那位读者问了我一个问题那我下一轮面试该怎么答这一题我说你把回答分成两层。第一层说模式链式、并行、路由、层级、反思我们系统里用到了哪几种、为什么选它。这一层证明你知道工具箱里有什么。第二层说编排层状态放在哪、失败怎么兜、预算怎么卡、路径怎么追。这一层证明你能把工具箱用起来。只答第一层是名词解释答到第二层才是架构设计。写这篇文章的过程中我自己最大的收获也是把这两个词分开看了模式和编排层。模式是可以背的网上一搜一大把五种十种都有人总结。编排层是设计出来的它取决于你的任务长什么样、失败成本有多高、预算有多少。AI 可以帮你完成单个 Agent 的代码调用但做架构决策、场景选型、风险兜底才是技术人不可替代的那部分价值。死板的代码可以被 AI 替代灵活的架构思维才是我们的核心竞争力。资料展示下面是我整理的AI大模型 学习资料和工具包预览适合收藏后按主题逐步学习
返回列表