AI智能体升级实践:从规则匹配到Function Call,准确率提升86%
“这周必须把规则匹配换成大模型方案准确率再上不去项目就黄了。”这是我上一个项目里业务负责人拍桌子说的话。当时我们做的AI智能体是面向电商客服场景的商品推荐助手底层用的是一套积累了两年多的规则匹配引擎意图模板、槽位正则、关键词映射、黑名单词表一套组合拳下来单轮推荐的准确率卡在82%左右。听起来好像还能用但真实业务里用户一句话能带出三四个意图、七八种槽位排列规则匹配根本切不动。后来我们做了技术选型调研最终决定把核心链路迁移到Function Call函数调用方案上。整个过程很折腾但效果是实打实的准确率从86%左右的线上口径提升到了接近95%相对涨幅大约86%。准确率提升86%是相对值不是绝对值后面我会用数据说明计算口径。这篇文章我不想写什么高大上的概念科普就老老实实把这次AI智能体升级的完整过程拆开为什么规则匹配撑不住了、备选方案有哪些、为什么选Function Call、架构怎么改、哪些细节决定成败、踩了哪些坑。适合正在做AI应用落地、想把LLM接进业务系统的团队参考也适合那些在“规则匹配和大模型之间反复横跳”的开发者先看完再做决定。1. 为什么规则匹配撑不住了三个真实业务场景的“死法”1.1 旧方案架构回顾它曾经也是对的两张图就能讲清楚旧链路的工作方式但这里没有流程图我直接用代码思路讲。第一批上线的规则匹配Agent是这样的intent_rules { 商品咨询: [价格, 多少钱, 怎么卖], 售后处理: [退, 换, 修, 退款], 物流查询: [到哪了, 快递, 物流, 发货], } slot_patterns { product: r(iPhone|小米|华为|耳机|充电器|...) price_range: r(\d)[-—~至](\d)元, sku_color: r(黑色|白色|蓝色|红色|...), }用户进来一句话先做意图匹配关键词命中然后做槽位抽取正则提取最后根据意图槽位组合走对应的推荐逻辑。这套架构在意图数量少、表达方式相对固定的时候非常好使开发快、可解释性强、上线即用。我们第一版冷启动就是靠它撑住了一个月大约5万次的推荐调用那时候准确率也能达到85%左右。问题不在架构本身而在业务的增长速度远超规则的膨胀速度。开始接入的只有3个类目大约200个SKU半年后扩展到12个类目、3400个SKU同时支持售前咨询、售后判断、促销推荐、比价辅助四个主流程。规则阈值一旦拉高漏召回率飙升拉低误匹配率爆炸。1.2 真实业务场景A一句话里叠加了多个意图和槽位用户原话“你们这个黑色iPhone 15 Pro 256G如果我用旧的小米11置换然后分12期最终到手多少钱”规则匹配的做法是先分词、再逐条命中。看起来“黑色”“iPhone 15 Pro 256G”都能用正则抽出来“12期”也能命中分期模板。但“旧的小米11置换”这个信息在旧模板里不存在系统先是把它当成了背景噪音丢掉结果算出来的到手价少算了一笔旧机抵扣用户实际下单时发现金额对不上直接投诉。规则匹配最大的问题就是它的“特征工程天花板”——能抽出的槽位数量取决于你提前定义了多少个正则。你不可能穷举用户所有的表达方式但用户会用无穷无尽的方式来提出需求。我当时统计过一个星期内的未命中日志大约有23%的会话因为“表达不在规则内”导致推荐结果出现明显偏差。1.3 真实业务场景B上下文依赖、指代消解规则永远追不上再来一个场景“帮我看看那款降噪耳机就是昨天你们直播里那个比现在这个便宜200的有没有白色的”这句话里有几个难点第一用户没指名SKU第二指代了“昨天直播”这个临时上下文第三还有比价需求。旧链路完全无法处理因为我们根本没有设计对话记忆模块规则引擎不会记得昨天的会话更不可能理解“那个”“这个”的指代关系。结果系统直接返回了默认爆款耳机列表用户觉得被无视会话评分掉到1星。这个场景还不能用“多写几条规则”解决因为指代对象是动态的千人千面。每多一个上下文来源规则组合爆炸的复杂度就翻一倍。我们当时估算过如果要把直播上下文、历史会话、当前会话的指代关系统统纳入规则体系至少需要新增600多条规则而且每两周要维护一轮。这人力成本是团队根本承受不起的。1.4 三个扛不住之后的“数据体检”为了说服团队和技术委员会启动重构我做了一次完整的数据体检。从线上日志里随机抽了500条推荐会话逐条人工标注推荐结果是否正确口径是“用户是否点击/点击后是否产生咨询”同时人工复核误判原因。结果很有意思规则匹配的错误来源分布大致是错误类型占比典型案例槽位抽取失败或抽错36%“帮我找300块左右的充电器”抽成“300充电器”意图误判多意图只命中一个27%“能便宜点吗顺便问问有没有银色”只识别了比价意图上下文缺失/指代不明22%“那款降噪的”没有任何SKU信息知识更新滞后10%新上架SKU没进规则表其他5%规则冲突、正则误伤这组数据给了我们两个很重要的决策依据。第一单纯优化规则只能解决“槽位抽取”和“意图误判”中的一部分指代和上下文问题无解必须换底层方案。第二规则匹配的准确率很可能是逐年下降的因为商品数量、用户表达复杂度都在涨准确率是被“稀释”的。2. 技术选型全记录为什么最终是Function Call2.1 备选方案盘点五个方向都试过说点真实感受既然决定重构第一步就是做方案选型。从当时的市场成熟度和团队技术栈出发我们认真讨论过下面几个方向。方向A微调意图分类模型 序列标注抽取思路是把“意图识别”和“槽位填充”改成两个NLP模型任务意图用BERT分类模型槽位用BERTCRF序列标注。这方案听起来中规中矩能部分解决1.1和1.2的问题但指代消解和上下文记忆它依然做不了因为这些本质上是对话管理的问题不是两个独立分类任务能覆盖的。当时我们用了开源的中文BERT模型在3000条标注语料上做了个快速实验单意图分类的F1确实能做到89%但一旦遇到多意图、套嵌槽位效果立刻回退到84%以下。而且训练数据维护成本会长期压在人身上业务规则一变语料就要重新标一轮。只能说这方案适合“意图单一、槽位固定”的场景不适合我们这个高动态推荐场景。方向BFew-shot Prompt 大模型做端到端解析这个方案简单粗暴不训练任何模型把所有用户问题拼进Prompt里让大模型直接返回JSON格式的结构化结果例如{intent: 商品咨询, slots: {...}}。我们当时试了效果在单轮场景里很惊艳意图和槽位抽取的准确率直接到了93%以上。但很快就发现它在一些“需要实时数据和工具调用”的场景里无从下手用户问“这个手机现在还有货吗”Prompt模型只能根据训练数据里的印象回答它不知道真实库存。如果强行让它编就会出现幻觉而且没有任何机制去触发库存查询动作。它适合做信息抽取但不适合做“需要执行动作的Agent”。方向CAgent Function Call最终选择这是当时OpenAI带火的范式也是我们最终选定的方向。核心思想很简单大模型不直接输出最终答案而是先输出“需要调用哪个函数、传什么参数”比如get_product_detail(product_nameiPhone 15 Pro, color黑色)然后由代码去真实的商品系统里查询查到结果后再把结果回填给大模型最终生成面向用户的推荐话术。这个方案能同时解决1.1、1.2、1.3里的绝大部分问题意图识别不用靠规则模板模型自己理解槽位抽取不用靠正则模型自己生成参数上下文记忆由调用循环承载工具能力可以无限扩展加一个函数就是加一种能力库存查询、价格批量查询、优惠券计算、直播上下文查询都可以做成函数。方向D外部NLU平台也调研过一些第三方NLU平台能提供意图识别和槽位抽取API但问题是第一数据要出域很多电商客服数据是敏感的第二它的自定义槽位语法和我们的业务系统对接成本高第三厂商封装的“泛化能力”在垂直商品领域并没有优势。最后结论是不如自己的大模型方案可控。方向E混合路由规则匹配兜底 大模型主链路这方案我们后来确实在线上用了但不是作为独立的竞争方案而是作为Function Call方案的一个降级模块。选型时的核心矛盾在于“大模型不是100%可用”总有超时、幻觉、限流情况这时候规则匹配作为兜底至少能保证基础服务不挂。所以我的建议是不要在大模型和规则之间二选一而是把规则引擎降级为“最后一道防线”。2.2 Function Call到底和普通Prompt调用差在哪很多人觉得Function Call就是“在Prompt里多写几个函数描述让模型按格式输出”。这个理解不算错但很容易低估它。常规Prompt调用是这样的请根据用户问题提取意图和对应参数返回JSON。模型输出什么样完全靠“提示词设计”它可能给你一个似懂非懂的结构然后程序解析时各种边界问题。Function Call的训练范式是让模型在预训练和指令微调阶段就见过“工具调用轨迹”它对“应该输出哪个函数、参数要合法”这件事有更强的先验约束。更重要的是调用循环本身会形成多步推理链条模型发现信息不足→调用第一个函数→拿到结果→再决定调第二个函数。这个过程不是一次Prompt能稳定完成的。在工程层面Function Call的落地形态是每个工具定义一个JSON Schema大模型在解码阶段就有“必须输出合法参数”的约束。我们当时用的是一个统一路由函数大模型先输出一个结构化的“工具调用计划”再交给执行器调用外部API返回结果后拼进对话历史模型再继续推理。这套和OpenAI Function Calling的接口语义是一致的但运行时可以完全自控。它解决的不是“单次抽取准确率”的问题而是“Agent按需获取信息再决策”的整个链路问题。2.3 选型决策表与当时最担心的三个风险最后技术委员会要求我们输出一张选型对比表我当时是这样填的维度规则匹配旧微调NLP模型常规PromptFunction Call上下文记忆基本不支持弱需自行拼接原生支持对话历史工具结果回填工具/API调用需硬编码不支持不支持原生支持动态扩展能力加规则成本高加训练数据成本极高改Prompt中等加函数描述成本低可解释性高中中中误匹配率高特征不足中中低部署复杂度低高低中推荐准确率潜力85%左右90%封顶93%单轮95%以上实测选型不是没有担忧当时最大的三个风险第一是延迟。规则匹配的P99延迟是120毫秒Function Call多了一个大模型推理和工具调用的循环P99延迟直接干到1.5秒以上。这个在推荐场景勉强可接受但我们做了异步预加载和部分缓存来对冲。第二是幻觉。模型可能在没有真实数据时“强行调用函数”并传入错误参数或者工具返回结果后模型没有正确引用而是自己编了一个价格。为了应对我们加了一层“工具结果强约束”任何商品价格、库存、优惠金额必须来自真实工具结果模型负责生成话术但不被允许在话术里自主生成这些数值。第三是成本。一次Function Call循环可能会调用2-3次大模型单次会话调用成本是规则匹配的30倍以上。这个没法消除只能通过路由策略省钱简单问题走一次轻量模型复杂问题才进Function Call循环。3. 架构重构与核心细节实现从“推荐三步走”到“Agent动态编排”3.1 新架构的分层设计编排层、工具层、策略层我们在设计新架构时没有直接照搬“大模型回复一切”的All-in-One方案而是做了拆分一共四个模块接入层负责会话管理、上下文存储、用户身份识别 编排层负责Function Call主循环决定每一步调用哪个工具、何时结束 工具层注册所有可被调用的业务函数库存、价格、优惠、物流、直播记忆等 策略层负责兜底降级、敏感词过滤、推荐结果约束这个拆法的理由很简单Function Call的“智能”在于模型的推理能力但“稳定的工程表现”来自编排层和工具层的设计。如果所有逻辑都堆在Prompt里模型一个不稳定整个系统就崩了。所以我们的原则是模型负责“理解意图和生成计划”代码负责“确定性的执行和数据正确性”。工具层是我们重点设计的部分。每个工具都是一个标准的函数描述包含名称、描述、参数Schema、执行代码、返回值格式。给模型看的“函数描述”非常关键如果描述写得含糊不清模型会犹豫该不该调用、调哪个函数直接拉低准确率。我们后来总结出一套函数描述写作模板第一句说清楚这个函数“在什么场景下用”第二句说明“它返回什么”第三句列出“必填参数”和“可选参数”如果函数有边界比如价格查询不支持模糊查询也要写明白。3.2 核心代码统一路由循环与Tools定义示例这是整个项目最核心的代码结构。我先给一个简化的工具定义示例用JSON Schema风格[ { name: get_product_detail, description: 根据商品名称、规格、颜色查询商品详细信息包括价格、库存、库存状态。适用于用户询问某款商品具体信息或问是否有货时。, parameters: { type: object, properties: { product_name: {type: string, description: 商品名称比如iPhone 15 Pro}, spec: {type: string, description: 规格描述如256G}, color: {type: string, description: 颜色} }, required: [product_name] } }, { name: calc_trade_in_price, description: 计算旧机抵扣金额适用于用户提到置换、以旧换新、旧手机抵扣等场景。, parameters: { type: object, properties: { old_device: {type: string, description: 旧设备型号如小米11}, condition: {type: string, description: 成色/状况描述} }, required: [old_device] } } ]当用户问“黑色iPhone 15 Pro 256G置换小米11分12期多少钱”时模型会输出一个工具调用计划[ {name: get_product_detail, arguments: {product_name: iPhone 15 Pro, spec: 256G, color: 黑色}}, {name: calc_trade_in_price, arguments: {old_device: 小米11}} ]执行器拿到这个计划后挨个调用真实API拿到返回值再回填给模型模型再生成最终回答。这里最关键的工程点在于执行器必须先检查参数完整性如果模型生成的参数里缺少必填项不能直接调API而是要让模型重新生成或向用户追问。因为在我们的日志里参数缺失和幻觉是非常常见的错误来源硬调API只会返回空值或异常。3.3 主循环的实现细节五个步骤一个不能少我们的Function Call主循环代码大概长这样def agent_run(user_query, session_id): # 1. 拉取该会话的上下文记忆 history memory_engine.get(session_id) # 2. 构造初始消息列表 messages build_system_prompt() history [{role: user, content: user_query}] max_steps 4 for step in range(max_steps): response llm.chat_with_tools(messages, toolsTOOL_SCHEMAS) msg response[message] # 3. 判定如果模型没有要求调用工具直接生成最终回答 if not msg.get(tool_calls): return msg[content], step 1 # 4. 执行工具调用并把结果拼接回消息列表 tool_results execute_tools(msg[tool_calls]) messages.append(msg) for result in tool_results: messages.append({ role: tool, tool_call_id: result[tool_call_id], content: json.dumps(result[data], ensure_asciiFalse) }) # 5. 超出最大步数时返回预设降级回复 return fallback_reply(user_query), max_steps一个关键细节是历史消息的长度控制。用户连续问了好几轮每轮工具结果可能都很长如果一股脑全拼进Messages会超出Token限制。我们在memory_engine里做了“窗口截断关键信息摘要”只保留最近两轮完整对话和工具结果更早的对话则让模型用一句话总结成背景上下文。这样可以既保留上下文记忆又控制Prompt长度实测能减少约22%的Token消耗同时没有明显降低准确率。3.4 关键参数调优temperature、max_tokens、函数描述长度Function Call不是“把模型接上去就行”参数调优的扣分细节非常多。Temperature在工具调用的第一步我们把它设为0因为工具选择只要确定性和正确性不要“创意”。但在最终话术生成的第二步我们会把它提到0.3让回复稍微自然一点。同一个模型实例不能同时设置两个温度所以我们实际上把任务拆成了两类请求一类是“推理调用工具”一类是“生成回复”分别走不同参数实测这个改动让最终的文案可读性提升不少。max_tokens这个参数看着不起眼但曾经让我们吃过亏。一开始max_tokens设得太小300每次模型生成工具调用JSON时中途被截断导致解析失败。后来把所有涉及工具调用的请求max_tokens调到800并且如果output出现截断标记就自动做一次“续写请求”把剩余部分补全。这个容错机制上线后工具调用解析失败率从5%降到了0.7%。函数描述长度这也是个经典权衡。如果把工具描述写得特别长模型能理解得更准确但会挤占输入Token同时也拖慢推理速度。我们的经验是每个函数描述控制在200字以内核心信息放在前50字类似“用于xxx场景返回xxx”。如果超过200字说明这个函数太复杂你应该考虑拆分成两个函数而不是写一篇小作文。有一次我把get_product_detail的描述写成了400字的“完整接口文档”结果模型开始频繁返回过于复杂的嵌套参数很多是根本不存在的字段准确率反而下降了6个百分点。我还做了一个更“偏门”的优化把相似的函数名改成语义清晰的“动宾短语”比如把query_product改成get_product_detail把calc_discount改成calc_final_price_with_promo。看着像是小事但模型的函数选择准确率确实因为这个提升了2.3%。原因不难猜模型在预训练阶段见到的自然语言描述本身就更接近“动词宾语”的表达方式函数名越容易理解它选错的可能性越低。4. 避坑实录七个坑每一个都让准确率掉过5%以上这一节是我的重点也是真正值钱的部分。如果你照着前面的方案做大概率会遇到下面这些问题。4.1 工具描述信息过载模型“挑花了眼”我们一开始把tools数组塞了20多个函数每个函数描述详细记录了所有参数、所有边界情况。结果模型开始频繁返回“参数组合正确但语义用错”的调用比如在用户问“物流”时调用了“商品推荐”函数。后来我们把工具数量精简到10个并对相似工具做了“合并入口”。比如把“价格查询”“库存查询”“规格查询”合并成一个get_product_detail让模型只需要选一次具体查哪些字段由代码里根据参数存在性决定。这个“函数瘦身”动作比我想象中更能提升准确率。原则是给模型的选项越少它选错的概率越低。4.2 工具循环“死循环”模型不断调用工具不返回最终答案上线初期我们遇到了一个特别诡异的情况模型一直在调工具一直认为信息不足比如查完库存又查价格查完价格又查优惠一轮接一轮最多能跑10步把Token烧光了还不收敛。排查后发现是两个原因叠加的结果。第一最大步数设得太大我们一开始设了10模型知道有足够步数就不着急收敛。第二部分函数返回的结果里包含“同款商品推荐”字段模型就误以为用户还在咨询其他商品继续触发推荐工具。解决方案很直接把最大步数从10降到4同时给函数返回结果里增加一个“is_relevant”标记明确告诉模型这次返回的数据是不是用户当前问题的直接答案。如果模型认为自己已经拿到了核心数据就应该停止调用、生成回复。4.3 模型“硬编”工具返回值答非所问这个问题在中文大模型里特别突出。模型调用get_product_detail后我明明在tool result里给了库存状态“out_of_stock”模型在生成回答时却说“有现货可以下单”。后来我们从Prompt和工具结果两方面做了干预。一方面在工具结果的前面加上强制提示“请严格参考以下工具返回结果其中stock_status为out_of_stock时不可声称有货。”另一方面在工具返回的JSON里我们不再用“in_stock”这种模型需要推理的字段而是直接用人类可读的“无货/现货”最大程度减少误解。这个改完价格和库存相关回答的事实准确率从89%提升到了96.5%。4.4 参数折叠模型把“不要”听成“要”用户的表达里带否定词时容易出错比如“我不要黑色的”模型在抽取槽位时直接把color设成了“黑色”。这个问题在规则匹配时代也存在但在Function Call里更有迷惑性因为模型输出了一个结构完全正常、参数却与语义相反的调用。我们的解法是在工具Schema里加了一个“参数语义提示”“当用户使用否定表达如不要、除了、不需要请把对应字段赋值为exclude值并在description里明确要求先识别否定再映射参数。”同时在系统Prompt里加了一条硬规则“如果用户原话含否定词直接在参数里输出两个字段include_color和exclude_color。优先使用exclude_color。”这算是针对电商场景的语气槽位扩展实测让否定表达的错误率从12%降到了4%左右。4.5 延迟抖动上线第一天差点被秒杀Function Call方案上线第一天真实流量一进来那叫一个惨烈。因为我们在主链路上同步调用了两次大模型一次工具决策一次生成回复加上每个工具里可能再调2-3个API最坏情况下一个会话要等6秒。用户早跑了。应对办法分了三层。第一层增加一个“意图预分类器”规则匹配的手机号不够我们直接用一个轻量的BERT分类模型做预处理如果判断是纯闲聊或不需要工具的问题直接走轻量回复不进Function Call。第二层对热门商品/高频问题做缓存把“商品详情推荐话术”的最终结果缓存5分钟命中直接返回。第三层把两次模型调用改为并行如果工具选择不依赖上下文或改成一次流式输出。最终P99延迟从1.8秒降到了900毫秒线上用户可接受。4.6 评测口径不统一说“准确率提升86%”之前先定义清楚准确率这一点可能是一半技术人容易忽略的。我们所谓准确率提升86%很多人第一反应是“你们把82%提升到了95%绝对值才13个点哪来的86%”这里需要澄清我们评测的口径是“每次会话的推荐结果与人工标注一致的占比”旧方案线上日志抽样的准确率是51.8%注意这个比之前的82%更低因为它涵盖了所有会话类型包含大量复杂多意图、指代消解场景Function Call方案在同一批500条困难样本上的准确率是96.3%。96.3-51.8/51.8 85.9%约等于86%。所以它是一个“相对提升”的数值。为什么用困难样本因为这才是升级的主要动机。如果只在简单的“价格咨询”上测旧规则也能做到94%拉不开差距。我建议任何团队在汇报准确率提升时都写明三个东西测试集怎么来的、是否包含了长尾困难样本、计算的是相对提升还是绝对提升。不然这个数字过不了复盘审计。4.7 降级策略与灰度发布经验新版上线不可能一上来就全量。我们把线上流量切成三组A组继续用规则匹配B组用Function Call但带“无结果降级”C组用Function Call全量。灰度周期是三天逐天观察次日留存、会话解决率、投诉率和Token成本。这里有一个值得分享的经验不要把降级策略放在“调用大模型失败”之后才触发而是要放在“模型不确定”之前。什么意思我们的策略层增加了一个置信度标记如果模型的工具调用计划和用户原始问题之间的语义相似度低于阈值或者工具调用结果为空系统直接走规则兜底。比如有些用户来聊“发货到XX地要多久”这不是核心推荐场景Function Call模型调了物流函数但返回为空这时候直接走规则模板给个标准话术比让模型强行圆场更安全。5. 数据复盘与迁移建议从这次升级里提炼出的可复用经验5.1 上线三个月后的数据表现上线后的三个月我们持续观测了几个核心指标指标规则匹配基线Function Call新方案困难样本推荐准确率51.8%96.3%单会话解决率73%91%用户平均对话轮数2.1轮3.4轮平均下单转化率2.8%4.6%人均Token成本约0.01元/会话约0.23元/会话成本翻了几十倍这是必须正视的现实。但放到业务大盘看多花出去的Token成本换来了近一倍的转化率提升ROI是正的。如果项目预算有限我建议先砍掉那些“高频但简单”的会话成本让简单问题走缓存或规则把预算留给复杂会话。我们后来上线了一个“成本熔断”开关当某小时Token花费超过阈值时自动把部分流量切回规则匹配由系统在优先保障成本还是优先保障体验之间自动权衡。5.2 哪些业务适合迁移到Function Call哪些不适合做个简单的判断表业务特征适合Function Call更适合其他方案用户表达多变、多意图、指代多适合不适合需要调用多个实时数据源适合不适合工具数量稳定20个适合不适合对延迟要求极端300毫秒需做缓存延迟优化空间有限规则匹配更稳完全依赖离线知识库、无实时数据可用但大材小用向量检索RAG更省强合规、数据不出域需私有化部署无我个人的判断是如果业务里“多工具编排实时决策复杂语义理解”这三个特征同时出现Function Call就是目前性价比最高的方案。如果你的场景只有“从一堆文档里找答案”那就别为了一点点智能感强行上Function Call老老实实做RAG或者规则匹配就够了。5.3 更轻量级的平替方案如果你的团队还没准备好接LLM如果你所在团队还没有接入大模型API的条件或者领导对Token成本极其敏感但又想在现有规则匹配基础上提准我的建议是按顺序做三件事第一把规则模板从“关键词匹配”升级为“正则分组槽位必填校验”至少可以解决一部分槽位抽取错误第二给每个意图增加“负向排除词表”比如用户说“不要黑色”在正向规则命中黑色时先过一遍排除表把黑名单里的参数直接删除第三做一个轻量级的“意图路由”先用规则判断大体类型再局部引入少量大模型或分类模型做二次修正。这些是“带着镣铐跳舞”的办法虽然天花板还在但成本极低可以作为过渡方案。5.4 下一步规划从Function Call到多智能体编排这次升级之后团队在思考下一步怎么走。Function Call解决的是“单个Agent如何调用工具”但实际业务里同一时刻可能跑多个Agent比如“商品推荐Agent”“售后判断Agent”“库存预警Agent”。如果每个Agent都独立和模型通信不仅成本高还会出现多个Agent对同一用户意图给出冲突结果的问题。目前我们在考虑引入一层“调度Agent”它负责看着用户原始问题决定分发给哪个子Agent执行再把结果合并成最终回复。这种设计本质上是一个多智能体编排问题和Function Call的关系是子Agent内部继续使用Function Call调度Agent则负责宏观策略。这算是一个自然的进化路径但复杂度也会明显上升如果当前系统还没稳定我建议先别all in多Agent把单Agent的工具调用链路吃透再说。结尾一点个人体会这次升级让我最深的感受是技术选型最怕的不是某个方案不够好而是团队里没有一个人敢拍板说“旧的可以不要了”。规则匹配在它合适的阶段确实是最高效的我们不是否定它而是让它退到它该在的位置当一个尽职尽责的兜底者。Function Call也不是银弹它也有幻觉、延迟和成本问题但它的价值在于让Agent的能力边界可以随工具的扩展而扩展而不是随着规则的膨胀而僵化。最后再分享一个小技巧不要直接照搬官方示例里的工具Schema一定要花时间根据自己业务的真实对话日志去“反推”工具函数的边界。你拥有的对话数据才是比任何Prompt经验都值钱的东西。先用它定义一个回归集每次改完Prompt或工具描述都在回归集上跑一遍你才能守住准确率提升的成果。