
1. 一次“反向面试”引发的思考当面试官被问到技术细节最近在技术圈里一个关于面试的段子挺火大意是面试者去腾讯面试面对面试官抛出的问题他反手就是一个“灵魂拷问”“你说你们在做Agent项目说说 SubAgent、Plan 模式、Skill 调用这些你们都是怎么做的” 据说面试官当场就有点冒汗。这个故事的真实性我们无从考证但它精准地戳中了一个现象随着AI Agent概念的爆火相关技术名词如SubAgent、Plan、Skill等已经从研究论文和极客圈子迅速下沉到了招聘面试的八股题库里。很多人可能只是背了几个名词看了几篇博客就敢在简历上写“精通Agent开发”但真要深究其实现细节、设计权衡和落地难点恐怕能说清楚的人并不多。这恰恰是我想聊的。今天我们不谈怎么应付面试也不去复述那些随处可见的概念定义。我想从一个实际参与过Agent项目落地的开发者角度把这些听起来高大上的术语“拉下神坛”拆解成我们每天在代码里要面对的具体问题。SubAgent怎么划分边界才不会互相“打架”Plan生成器写出来的计划如果太“天真”怎么办Skill调用时如何管理那些千奇百怪的第三方API这些才是决定一个Agent项目是玩具Demo还是真正可用的产品的关键。如果你也对Agent开发感兴趣或者正准备面试相关岗位希望这篇从实战中总结的“内幕”能给你带来一些不一样的视角让你下次聊起Agent时肚子里有货心里不慌。2. SubAgent设计不是简单的“分而治之”而是权责清晰的“微服务”一提到SubAgent很多人的第一反应就是“把大任务拆成小任务分给不同的AI去处理”。这个理解方向没错但过于简化在实际工程中会踩很多坑。SubAgent的核心不是“分工”而是“分治”重点在于如何定义清晰的边界和交互协议这更像是在设计一个微服务架构。2.1 划分依据按能力、按领域还是按状态首先SubAgent不能随便分。常见的划分维度有三种各有其适用场景和陷阱。按能力划分是最直观的。比如一个写作Agent可以拆分为“资料搜集SubAgent”、“大纲生成SubAgent”、“文案润色SubAgent”。这种划分的优点是每个SubAgent职责单一易于训练和优化。但缺点是容易形成“流水线僵化”。比如润色Agent可能觉得某段资料引用不当但它无权直接指挥搜集Agent重新找资料必须层层上报给主Agent协调效率低下。我们在早期一个项目里就遇到过一个简单的修改请求在几个SubAgent之间传递了四五轮耗时惊人。按领域划分适用于复杂业务。比如一个电商客服Agent可以按商品、订单、售后等业务领域划分SubAgent。每个SubAgent对自己领域的数据和规则有最深的理解。这种划分的挑战在于“领域交叉问题”。用户问“我买的XX手机商品领域的订单订单领域为什么还没发货物流领域”这就需要多个SubAgent协同对它们之间的通信和数据一致性要求极高。按状态划分是一种更动态的思路。比如一个对话Agent可以设置“闲聊SubAgent”、“任务处理SubAgent”、“紧急情况处理SubAgent”。主Agent根据对话状态和用户意图动态路由到不同的SubAgent。这种模式灵活性高但对状态判断的准确性要求极高一旦路由错误用户体验会非常割裂。实操心得不要追求理论上最完美的划分。我们的经验是初期可以按能力粗粒度划分快速跑通流程。随着业务复杂再逐步引入按领域的SubAgent处理特定复杂场景。最关键的是要为每个SubAgent定义明确的“输入输出契约”和“能力边界文档”并且这个文档是所有开发者的共识而不是某个人的隐性知识。2.2 通信与协同避免SubAgent陷入“扯皮”循环SubAgent之间如何沟通是设计中的最大难点。让它们直接对话那会乱套。通常需要一个协调者Orchestrator也就是主Agent的核心组件之一。中心化调度模式是最常见的。所有SubAgent只与主Agent通信由主Agent决定任务分配、结果汇总和冲突裁决。这就像公司里的项目经理。好处是控制力强全局状态清晰。坏处是主Agent容易成为瓶颈和单点故障而且所有决策逻辑都集中在主Agent会变得非常臃肿。去中心化协商模式更高级也更有挑战。SubAgent之间可以直接交换信息和提案通过某种协商机制如基于规则的投票、简单的竞价机制达成一致。这类似于敏捷团队。它的优点是灵活、健壮单个SubAgent失效不影响全局。但实现极其复杂需要设计良好的通信协议和共识机制否则极易陷入无限循环的“扯皮”状态。在实际项目中我们采用了一种混合模式。对于有明确上下游关系的任务如先搜集再写作采用中心化调度确保流程可控。对于需要多角度决策的任务如评估一个方案的风险则让相关的几个SubAgent并行工作生成自己的评估报告和置信度再由一个轻量级的“仲裁SubAgent”进行汇总和判断。这个仲裁SubAgent本身逻辑很简单但它定义了清晰的投票和权重规则。# 一个简化的仲裁SubAgent逻辑示例 def arbitrate_subagent(proposals): proposals: List[Dict] 每个SubAgent的提案 格式{agent_name: RiskEvaluator, decision: high_risk, confidence: 0.8, evidence: ...} # 规则1如果某个SubAgent置信度极高0.9且无强烈反对则采纳 high_confidence [p for p in proposals if p[confidence] 0.9] if len(high_confidence) 1: low_confidence_opposite [p for p in proposals if p[decision] ! high_confidence[0][decision] and p[confidence] 0.6] if not low_confidence_opposite: return high_confidence[0] # 规则2否则按置信度加权投票 decision_scores {} for p in proposals: key p[decision] decision_scores[key] decision_scores.get(key, 0) p[confidence] # 返回得分最高的决策 final_decision max(decision_scores, keydecision_scores.get) # 找到对应提案可能取第一个 for p in proposals: if p[decision] final_decision: return p return None这个简单的例子说明SubAgent协同的核心是规则化、可观测。所有交互必须有日志所有决策应有依据置信度方便事后复盘和调试。3. Plan模式解析从“空想蓝图”到“可执行工单”Plan即规划是Agent的“大脑皮层”。它决定了Agent如何思考步骤、拆解目标。很多人以为Plan就是让LLM列一个TODO List但真正的挑战在于如何让这个List具备可执行性、可应对变化。3.1 主流Plan模式对比ReAct、CoT、HuggingGPT面试时你可能会被问到几种不同的Plan模式了解它们的本质区别很重要。Chain-of-Thought (CoT)思维链。严格来说CoT是一种推理模式不是完整的规划框架。它鼓励LLM“一步一步想”把推理过程展示出来。在Agent中CoT常被用于单个复杂步骤的思考比如让代码生成SubAgent先解释逻辑再写代码。它的输出是“理由”而不是“动作指令”。ReAct (Reason Act)这是目前最主流的Agent规划范式之一。其核心循环是思考(Thought) - 行动(Action) - 观察(Observation)。Agent先根据当前状态思考下一步该做什么Thought然后执行一个具体的动作如调用一个SkillAction最后观察环境返回的结果Observation并进入下一轮循环。它的优势在于将推理和行动紧密结合能处理动态环境。但缺点也很明显效率可能较低每一步都要“想一下”并且严重依赖Thought的质量如果Thought跑偏整个任务就失败了。HuggingGPT/Task-Driven这类模式可以称为“任务驱动型规划”。它首先让LLM根据用户目标一次性生成一个结构化的任务列表Plan每个任务有明确的描述、输入输出和依赖关系。然后由一个调度器Scheduler按依赖顺序或并行地执行这些任务。这就像项目经理先做出完整的WBS工作分解结构再分派下去。它的优点是规划阶段可以通盘考虑整体更优执行阶段高效无需每一步都推理。缺点是缺乏灵活性如果某个任务执行失败或者环境与预期不符整个Plan可能就需要推倒重来。在我们的项目中并没有死守某一种模式而是分层混合使用。对于目标明确、步骤可预见的任务如“生成一份包含数据图表的周报”我们采用HuggingGPT模式先让一个“规划SubAgent”生成详细任务流。对于探索性、交互式的任务如“帮我调试这个API错误”则采用ReAct模式让Agent在调试过程中与环境实时交互。3.2 Plan的生成与修正让AI学会“动态调整”生成Plan只是第一步更重要的是Plan的修正Plan Refinement。一个不会根据实际情况调整计划的Agent是愚蠢的。触发修正的时机我们设定了几个关键触发器1某个Skill执行失败或返回异常2执行结果与预期偏差超过阈值比如让搜索Skill找资料但返回结果为空或完全不相关3执行时间远超预估4用户中途改变了需求。修正策略修正不是简单地让LLM重新生成整个Plan那样成本高且可能丢失已有进展。我们实现了以下几种策略局部回滚与重试如果只是某个Skill临时失败如网络超时则自动重试该Skill。替代方案选择如果某个Skill确实无法完成子任务则在Plan的知识库中寻找功能相似的替代Skill替换后继续。子目标重组如果发现当前步骤无法推进则让“规划SubAgent”重新评估剩余目标生成一个新的、从当前状态开始的子Plan。人类求助当自动修正尝试超过一定次数或遇到无法理解的错误时将当前状态、已尝试的方案和阻塞原因清晰地呈现给用户请求指导。这里有一个常见的坑过度修正。Agent可能因为一次小的失败就全盘否定原有Plan陷入“生成-失败-再生成”的死循环。我们的经验是为修正机制加上“惯性”。例如记录每个子步骤的历史成功率对于高成功率的步骤即使偶尔失败也优先尝试重试或微调而不是直接替换。4. Skill调用与管理构建稳定可靠的“技能仓库”Skill是Agent的“手和脚”是与外部世界交互的具体能力。管理好Skill是Agent项目稳定的基石。这不仅仅是封装一个API调用那么简单。4.1 Skill的标准化描述让AI理解“能干什么”和“怎么用”要让Agent尤其是规划模块能自动调用合适的Skill首先必须用机器可读的方式清晰地描述每个Skill。我们借鉴了OpenAI的Function Calling格式但做了大量扩展形成内部的Skill Schema。{ skill_name: web_search, description: 使用搜索引擎在互联网上查找信息。适用于查找实时信息、事实核查、获取最新资讯。, parameters: { query: { type: string, description: 搜索关键词应尽可能具体明确。, required: true }, max_results: { type: integer, description: 返回的最大结果数量默认5。, required: false, default: 5 } }, returns: { type: array, description: 搜索结果列表每个结果包含标题、摘要和链接。, items: { type: object, properties: { title: {type: string}, snippet: {type: string}, url: {type: string} } } }, error_handling: [ { error_type: NetworkError, suggested_action: retry, max_retries: 2 }, { error_type: RateLimitError, suggested_action: fallback, fallback_skill: offline_knowledge_search } ], cost_estimate: { time: 2-5s, monetary: low }, privacy_level: medium // 用于判断是否处理敏感信息 }这个Schema的关键扩展在于error_handling和cost_estimate。error_handling让规划器在调用前就知道可能出什么错以及推荐的应对策略重试、降级、报错。cost_estimate则让规划器在多个可选Skill之间做出权衡比如是调用一个准确但慢且贵的专业API还是一个快但可能不精确的免费接口。4.2 Skill的注册、发现与版本管理当Skill数量成百上千时需要一个Skill注册中心。它不仅仅是一个列表更是一个元数据仓库。每个Skill上线时必须向注册中心提交完整的Schema。Agent在规划时会向注册中心查询“我需要一个能处理‘图像识别’、速度要求‘快’、成本要求‘低’的Skill”。注册中心根据Schema中的描述、标签和性能指标进行匹配和推荐。版本管理至关重要。当你优化了一个Skill比如改进了搜索算法你不能直接覆盖旧版本因为可能有的线上Agent的Plan还在依赖旧版本的某些行为。我们的做法是新Skill以新版本号如web_search_v2注册并在Schema中声明与旧版本的兼容性。规划器可以选择使用最新版或显式指定某个版本。4.3 Skill调用的稳定性保障超时、重试与熔断这是工程上最琐碎也最重要的一环。直接调用第三方API或内部服务你一定会遇到超时、限流、临时故障等问题。超时控制每个Skill必须在Schema中声明预期的执行时间。调用时设置一个合理的超时通常是声明的2-3倍。超时后立即触发错误处理流程而不是无限等待。智能重试不是所有失败都值得重试。我们根据错误类型决定网络抖动、5xx服务器错误立即重试1-2次。4xx客户端错误如参数错误不重试直接报错因为重试没用。速率限制429错误按照响应头中的Retry-After提示进行延迟重试。熔断机制如果一个Skill在短时间内失败率过高例如10次调用失败8次则触发熔断。在接下来的一段时间内如1分钟所有对该Skill的调用直接快速失败不再请求下游服务给服务恢复的时间。熔断器需要设置半开状态熔断一段时间后允许少量请求通过如果成功则关闭熔断恢复服务。降级方案对于关键Skill必须设计降级方案。比如实时搜索Skill熔断后可以降级到查询内部知识库的Skill虽然信息可能不是最新但保证了核心流程不中断。这些机制不应该硬编码在每个Skill的实现里而是应该由统一的Skill调用中间件来实现。这个中间件负责加载Schema、管理连接池、执行超时、重试、熔断逻辑让Skill开发者只需关注业务逻辑本身。5. 面试官视角如何考察一个候选人的Agent实战能力回到开头的故事如果我是那个被反问的面试官一个能问出这种细节问题的候选人我会非常兴奋。但仅仅知道名词是不够的我会顺着他的问题往下挖来考察他的真实经验深度。这里也分享给大家可以自测一下。关于SubAgent“除了按功能划分你在实际项目中还考虑过哪些划分维度遇到过什么挑战”考察是否有多维思考“SubAgent之间如果出现循环依赖或死锁你有什么调试思路和预防手段”考察实际问题解决能力“如何评估一个SubAgent的独立性和内聚性有量化的指标吗”考察工程度量思维关于Plan模式“在ReAct循环中如果LLM的‘Thought’部分持续输出无意义或重复内容除了提示工程优化在系统设计层面有什么兜底策略”考察对故障模式的预见性“对比一次生成完整Plan和逐步ReAct在资源消耗Token、延迟和任务成功率上你们做过哪些实际的对比实验数据结论是什么”考察数据驱动和实验精神“如何让Plan具备‘学习’能力比如某个步骤经常失败能否自动优化后续的Plan生成”考察对系统演进的前瞻性关于Skill调用“如果一个Skill的响应格式突然变化比如第三方API升级如何最快地发现并定位到是这个问题有什么监控或测试机制”考察运维和监控意识“设计Skill的权限模型时如何控制不同Agent或用户对敏感Skill如删除数据、发送消息的访问”考察安全思维“如何管理Skill的依赖比如Skill A依赖一个内部库这个库升级了如何确保所有相关Skill得到测试和更新”考察大型项目管理能力能回答好这些问题的人绝不是仅仅看过几篇教程而是真正在复杂的系统里摸爬滚打过思考过如何让这些聪明的“AI组件”可靠地协同工作。Agent项目的魅力在于它处于AI研究与软件工程的交叉点既需要你对LLM的能力和局限有深刻理解又需要你具备构建复杂、稳定分布式系统的工程能力。所以下次当你准备面试或讨论Agent项目时不妨多想想这些名词背后的“工程实现”和“踩坑经验”。这不仅能让你在对话中更有底气更能帮助你设计出真正鲁棒、可用的智能系统。毕竟让一个Demo跑起来很简单但让它持续、稳定、安全地解决实际问题才是真正的挑战所在。