☰
企业AI落地实战:从只会聊天到能干活的三层架构
2026/10/13 14:21:40 网站建设 项目流程

1. 从"只会聊天"到"能干活":企业AI落地的真实断层在哪里

过去两年,几乎每家公司都在内部试过把大模型接进工作流。最常见的做法是搭一个对话框,员工输入问题,模型给出回答。用起来挺新鲜,但用不了多久,大家就发现一个问题:它除了聊天,什么也干不了。你问它"帮我查一下上个月的报销单状态",它只能告诉你"我无法访问你的系统";你让它"把这份合同里的关键条款整理成表格",它倒是能整理,但整理完你还得手动复制到文档里,再手动发给相关同事。整个流程下来,省下的时间还不如自己动手快。

这就是当前企业AI落地最真实的断层:模型有理解能力,但没有执行能力。它能听懂你说什么,但它碰不到你的业务系统、读不了你的数据库、发不了你的邮件、改不了你的工单。它像一个知识渊博但被绑住手脚的顾问,只能动嘴,不能动手。

我所在的团队从去年开始就在琢磨这件事。我们试过几种方案:第一种是给模型挂一堆API,让它自己决定调哪个。结果发现模型经常选错工具,或者把参数传得乱七八糟,稳定性极差。第二种是写死流程,比如"查报销"就走A接口,"发通知"就走B接口,模型只负责填参数。这种方案倒是稳定,但每加一个新场景就要改一次代码,扩展成本太高。第三种是让模型生成代码,然后执行代码去操作业务系统。这个思路听起来很美好,但安全风险太大,万一模型生成了一段删除数据的代码,后果不堪设想。

折腾了大半年,我们最终沉淀出一套相对靠谱的架构。核心思路是:把企业里的每一个操作都封装成"技能",模型只负责理解意图和编排技能,实际执行交给确定性的代码。这样既保留了模型的灵活性,又保证了执行的安全性和稳定性。这套东西我们内部叫它"企业工作伙伴",后来决定把它开源出来,让更多团队少走弯路。

这篇文章不讲空泛的概念,只讲我们踩过的坑、做过的取舍、以及最终跑通的方案。如果你正在负责公司内部的AI落地,或者你是一个开发者想做一个能真正干活的AI助手,下面的内容应该能帮你省下至少三个月的试错时间。

2. 为什么"给模型挂API"这条路走不通

2.1 模型选工具的随机性远超你的想象

刚开始做的时候,我们想得很简单:把公司内部的API都整理出来,写成工具描述,让模型自己选。比如用户说"帮我查一下张三的工单",模型应该选"查询工单"这个工具,参数填"张三"。听起来很合理对吧?实际跑起来完全不是这么回事。

我们当时挂了大概二十个工具,包括查工单、查报销、查考勤、发通知、建群、改权限等等。测试的时候发现,模型选错的概率大概在15%左右。最离谱的一次,用户说"帮我看看张三最近有没有提交报销",模型选了"查询考勤"工具,参数填了"张三"。你问它为什么选错,它给出的理由是"报销和考勤都是员工行为记录,我判断查询考勤也能间接反映报销情况"。这个逻辑你不能说它完全错,但结果就是错的。

更麻烦的是参数填充。有些工具的参数字段名很相似,比如"员工姓名"和"申请人姓名",模型经常搞混。还有些工具需要传日期范围,模型有时候传"上个月",有时候传"2024-05-01到2024-05-31",格式不统一,后端解析经常报错。

2.2 工具数量超过一定阈值后,准确率断崖式下跌

我们做过一组对比测试,结果如下:

工具数量意图识别准确率参数填充准确率端到端成功率
5个96%94%91%
10个92%89%83%
20个85%78%67%
40个72%61%45%

这张表的数据很能说明问题。当工具数量从5个增加到40个时,端到端成功率从91%暴跌到45%。也就是说,超过一半的请求会失败。这个失败率在企业场景里是完全不可接受的,因为员工用两次发现不好用,就再也不会用了。

为什么会这样?核心原因是模型的注意力被稀释了。工具描述越多,模型在选工具时需要考虑的维度就越多,相似工具之间的干扰就越严重。而且很多工具的描述文本本身就存在语义重叠,模型很难区分。

2.3 纯API方案缺少"上下文记忆"和"多步编排"

还有一个更深层的问题:企业里的很多任务不是单步操作,而是多步编排。比如"帮我把这个月的部门报销汇总一下,发给财务,并抄送给我"。这个任务拆开来看至少需要四步:查询报销数据、按部门汇总、生成报表、发送邮件。每一步都依赖上一步的输出,而且中间可能需要人工确认。

纯API方案只能处理单步调用,模型调完一个工具拿到结果后,要么直接返回给用户,要么再调下一个工具。但模型在多轮调用中很容易"忘记"之前的上下文,或者把中间结果搞丢。我们测试过让模型连续调三个工具完成一个任务,成功率不到30%。

所以,"给模型挂API"这条路,在工具数量少、任务简单的场景下可以凑合用,但一旦要覆盖企业里的真实工作流,就会立刻崩掉。这不是模型能力的问题,而是架构设计的问题。

3. 我们最终采用的架构:技能层 + 编排层 + 执行层

3.1 三层架构的分工逻辑

踩了上面那些坑之后,我们重新设计了一套架构。核心思路是把"理解"和"执行"彻底分开,中间加一层确定性的编排逻辑。整个架构分三层:

第一层是技能层。我们把企业里的每一个原子操作都封装成一个"技能",每个技能有明确的输入输出定义、参数校验规则、以及执行逻辑。技能层不依赖模型,它是纯代码实现的,可以单独测试、单独部署。比如"查询员工信息"是一个技能,"发送邮件"是一个技能,"创建工单"是一个技能。

第二层是编排层。这一层负责理解用户意图,然后把意图拆解成技能调用序列。编排层是模型和规则引擎的结合体:模型负责理解自然语言,规则引擎负责校验和补全。比如用户说"帮我查一下张三的工单",模型识别出意图是"查询工单",实体是"张三",然后规则引擎会检查"查询工单"这个技能是否存在、参数是否完整、当前用户是否有权限调用。

第三层是执行层。这一层就是实际调用技能的地方,它按照编排层给出的序列依次执行,处理异常和重试,最后把结果汇总返回给用户。执行层完全不涉及模型,它是确定性的代码逻辑。

这三层分开之后,每一层都可以独立优化。技能层可以不断增加新技能而不影响其他层;编排层可以换模型、调提示词而不影响执行;执行层可以加监控、加重试而不影响理解。整个系统的可维护性大幅提升。

3.2 技能封装的具体规范

技能封装看起来简单,实际上有很多细节要注意。我们内部定了一套规范,每个技能必须包含以下字段:

{ "skill_id": "query_ticket", "skill_name": "查询工单", "description": "根据员工姓名或工单编号查询工单状态和详情", "parameters": [ { "name": "employee_name", "type": "string", "required": false, "description": "员工姓名,与工单编号二选一" }, { "name": "ticket_id", "type": "string", "required": false, "description": "工单编号,与员工姓名二选一" } ], "permissions": ["ticket_read"], "handler": "handlers.ticket.query_ticket" }

这里有几个关键点。第一,description必须写得非常精确,不能有歧义。我们之前吃过亏,有个技能的描述写的是"查询员工相关信息",结果模型把它当成了万能查询工具,什么请求都往这里塞。后来改成"根据员工姓名查询工单状态和详情",准确率立刻上来了。

第二,参数设计要尽量扁平化,避免嵌套结构。模型对嵌套参数的处理能力很弱,如果参数是一个对象数组,模型经常填错。我们现在的做法是,如果确实需要复杂参数,就拆成多个技能,或者用字符串拼接的方式传参,后端再解析。

第三,权限字段是必须的。企业场景下,不同角色的员工能调用的技能是不一样的。比如普通员工不能调用"修改薪资"技能,部门主管不能调用"查看全公司考勤"技能。权限校验放在编排层做,模型不需要知道权限细节,它只负责理解意图。

3.3 编排层的意图识别与槽位填充

编排层的核心任务是把自然语言转成结构化的技能调用请求。我们用的是"意图识别 + 槽位填充"的经典范式,但做了一些针对企业场景的优化。

意图识别方面,我们没有让模型直接输出技能ID,而是让它输出一个"意图标签",然后通过映射表找到对应的技能。这样做的好处是,意图标签可以用更自然的语言描述,模型更容易理解。比如用户说"我想看看我的报销走到哪了",模型输出意图标签"查询报销进度",映射表里"查询报销进度"对应技能"query_reimbursement_status"。

槽位填充方面,我们用了"模型抽取 + 规则校验"的双保险。模型先从用户输入里抽取参数,然后规则引擎检查参数是否完整、格式是否正确。如果参数缺失,规则引擎会生成一个追问话术,让模型去问用户。比如用户说"帮我查一下工单",模型抽取出意图"查询工单",但没抽到员工姓名或工单编号,规则引擎就会让模型追问"请问您要查谁的工单,或者提供工单编号?"

这套机制跑下来,意图识别准确率能到95%以上,槽位填充准确率能到90%左右。剩下的10%主要是用户表达太模糊,比如"帮我处理一下那个事情",这种只能靠追问来补全。

4. 多步任务编排:让AI真正完成一个完整流程

4.1 任务拆解的策略与边界

单步技能调用只能解决简单问题,企业里真正有价值的是多步任务。比如"帮我统计上个月部门的加班时长,生成报表发给HR,并抄送部门主管"。这个任务需要四步:查询加班数据、按部门汇总、生成报表文件、发送邮件。每一步都是一个独立的技能,但它们之间有依赖关系。

我们的做法是,在编排层加一个"任务规划器"。用户输入一个复杂请求后,规划器先把它拆解成技能调用序列,然后逐个执行。拆解的策略有两种:一种是模型直接生成调用序列,另一种是预定义模板匹配。我们两种都用,简单任务用模型生成,复杂任务用模板匹配。

为什么复杂任务要用模板?因为模型在生成多步序列时,经常会出现逻辑错误。比如它可能先生成报表再查询数据,或者漏掉某个必要步骤。模板匹配虽然不够灵活,但胜在稳定。我们内部维护了一个任务模板库,每个模板定义了技能调用顺序、参数传递规则、异常处理逻辑。当用户请求匹配到某个模板时,直接按模板执行,模型只负责填充参数。

4.2 步骤间的数据传递与状态管理

多步任务最麻烦的地方是数据传递。第一步的输出往往是第二步的输入,如果传递过程中丢了数据,整个任务就断了。我们一开始用模型的上下文来传递数据,结果发现模型经常"忘记"中间结果,或者把数据搞混。

后来我们改成用显式的"任务上下文"来管理数据。每个任务有一个上下文对象,每一步执行完后,把输出写入上下文,下一步从上下文里读取。上下文是一个结构化的JSON对象,不依赖模型的记忆。比如:

{ "task_id": "task_20240520_001", "steps": [ { "step": 1, "skill": "query_overtime", "input": {"department": "研发部", "month": "2024-04"}, "output": {"total_hours": 320, "details": [...]} }, { "step": 2, "skill": "generate_report", "input": {"data": "$steps[0].output", "format": "xlsx"}, "output": {"file_path": "/reports/overtime_202404.xlsx"} } ] }

注意$steps[0].output这个引用语法,它表示第二步的输入来自第一步的输出。执行层会解析这个引用,把实际数据填进去。这样做的好处是,数据传递完全由代码控制,不依赖模型的记忆,稳定性大幅提升。

4.3 异常处理与人工确认节点

多步任务执行过程中,难免会遇到异常。比如查询数据时发现没有权限,或者生成报表时文件写入失败。我们的处理策略是:能自动重试的自动重试,不能自动处理的转人工确认。

自动重试主要针对网络超时、临时性错误。我们给每个技能调用设置了重试次数和退避策略,比如第一次失败后等1秒重试,第二次失败后等3秒重试,第三次还失败就放弃。

人工确认主要针对两种情况:一是权限不足,需要用户申请权限或换人操作;二是关键操作,比如发送邮件、修改数据,需要用户确认后才能执行。我们在编排层加了"确认节点"的概念,当任务执行到确认节点时,系统会暂停,给用户发一条确认消息,用户确认后才继续执行。

这个设计在实际使用中非常受欢迎。员工反馈说,以前用其他AI工具,最怕它自作主张把邮件发出去了,现在有了确认节点,心里踏实多了。

5. 开源过程中踩过的坑与最终取舍

5.1 模型选型:不是越大越好

开源的时候,很多人问我们用的什么模型。我们试过好几种,包括一些参数很大的模型和一些轻量级模型。结论可能有点反直觉:在企业工作伙伴这个场景下,模型的大小不是决定性因素,提示词工程和技能设计才是。

我们做过对比测试,用同一个技能库和同一套提示词,分别接不同规模的模型,端到端成功率差距在5%以内。大模型在理解复杂意图时确实略好一些,但在标准化的企业场景下,用户表达通常比较规范,轻量级模型完全够用。而且轻量级模型响应更快、成本更低,更适合企业内部高频使用。

最终我们开源的版本支持多种模型接入,用户可以根据自己的场景选择。如果任务简单、并发高,用轻量级模型;如果任务复杂、对准确率要求极高,用大模型。架构上做了抽象,换模型只需要改配置,不需要改代码。

5.2 技能粒度:太细和太粗都难受

技能粒度是我们纠结最久的问题。粒度太细,比如把"查询工单"拆成"查询工单基本信息"和"查询工单处理记录",模型需要调两次,编排复杂度上升。粒度太粗,比如把"查询工单"和"修改工单"合并成一个"工单管理"技能,模型又容易搞混。

我们最后定的原则是:一个技能只做一件事,但这件事的边界要清晰。具体来说,如果两个操作经常一起出现,而且共享大部分参数,就合并成一个技能;如果两个操作逻辑独立,只是领域相同,就分开。比如"查询工单"和"修改工单"虽然都是工单操作,但一个读一个写,权限要求也不同,就分成两个技能。

另外,我们给每个技能加了"别名"机制。同一个技能可以有多个别名,模型可以用任意别名调用。比如"查询工单"的别名包括"查工单""看工单""工单状态查询"等。这样模型不需要记住精确的技能名,用自然语言描述也能匹配到。

5.3 权限控制:模型不该知道的事就别让它知道

企业场景下,权限控制是红线。我们一开始的设计是,把权限信息也写进技能描述里,让模型自己判断。比如技能描述里写"仅限HR角色调用",模型在选技能时会考虑当前用户的角色。结果发现,模型经常忽略权限限制,或者判断错误。

后来我们改成:权限校验完全在编排层做,模型不接触权限信息。模型只负责理解意图和选技能,选完之后,编排层检查当前用户是否有权限调用这个技能。如果没有,直接返回"您没有权限执行此操作",不执行技能。这样做的好处是,权限逻辑是确定性的代码,不会出错;模型也不需要处理它不擅长的权限判断。

这个设计还有一个额外好处:技能描述可以写得更简洁,不需要包含权限信息,减少了模型的认知负担,意图识别准确率反而提升了。

6. 实际跑起来之后,哪些设计最值钱

6.1 技能注册中心:让扩展变得像搭积木

我们内部最满意的设计是"技能注册中心"。所有技能都注册在一个中心化的地方,新增技能只需要写一个配置文件和一个处理函数,不需要改编排层和执行层的代码。编排层启动时从注册中心拉取技能列表,自动生成提示词和映射表。

这个设计让扩展变得极其简单。我们有个同事,花了一个下午就接了五个新技能,包括"查询会议室预订""申请门禁权限""提交IT工单"等。他只需要写技能定义和处理逻辑,剩下的交给框架。这种低门槛的扩展方式,让整个系统的技能数量在三个月内从20个增长到80多个,覆盖了公司内部大部分高频操作。

6.2 对话日志回放:排查问题的最佳工具

企业场景下,出问题是常态。用户说"它没理解我的意思",你得能复现当时的情况。我们做了一个对话日志回放功能,把每次交互的完整链路都记录下来:用户输入、模型输出、意图识别结果、槽位填充结果、技能调用序列、每步的输入输出、最终返回结果。

这个功能在排查问题时极其有用。有一次用户反馈"查报销一直失败",我们回放日志发现,模型把"报销"识别成了"报考勤",因为两个词的拼音很像,模型在语音输入场景下搞混了。后来我们在意图识别里加了拼音纠错,问题就解决了。

如果没有日志回放,这种问题根本没法定位。所以我的建议是,从第一天就把日志做全,不要等出问题了再补。

6.3 灰度发布与A/B测试:让优化有数据支撑

我们每次调整提示词或技能定义,都会先在小范围灰度发布,观察一周的数据再全量。灰度期间,我们会对比新旧版本的端到端成功率、平均响应时间、用户满意度等指标。只有新版本在各项指标上都不差于旧版本,才会全量。

这个流程看起来麻烦,但实际省了很多事。有一次我们改了一个技能的描述,灰度期间发现准确率反而下降了3%,赶紧回滚。如果没有灰度,直接全量,可能就要面对大量用户投诉了。

A/B测试我们也做,主要针对提示词的不同写法。比如同一个意图,用"查询工单"和"获取工单信息"两种描述,哪个准确率高?这种问题只能靠数据回答,拍脑袋是不行的。

7. 如果你也想做一个,我的几点实在建议

第一,不要一上来就追求大而全。我们最开始想做一个能处理所有企业事务的万能助手,结果什么都做不好。后来收缩到只做高频的十几个场景,反而用起来了。先跑通一个场景,让用户感受到价值,再逐步扩展。

第二,技能设计比模型选型重要十倍。我见过太多团队花大量时间对比模型,却不愿意花时间打磨技能描述和参数设计。实际上,在企业场景下,技能设计的质量直接决定了系统的上限。一个好的技能设计,用轻量级模型也能跑出很好的效果;一个糟糕的技能设计,用再大的模型也救不回来。

第三,权限和审计从第一天就要做。企业场景和个人场景最大的区别就是权限。个人助手可以随便调工具,企业助手必须严格控制。而且审计日志不仅是排查问题的工具,也是合规的要求。哪些人、在什么时间、调用了什么技能、传了什么参数、返回了什么结果,这些都要记录。

第四,人工确认节点不是累赘,是信任的基石。很多团队觉得人工确认影响效率,想全部自动化。但在企业场景下,用户对AI的信任是一点点建立的。有了确认节点,用户才敢用;用多了,发现AI靠谱,才会逐渐放开权限。这是一个渐进的过程,急不得。

第五,开源不是终点,是起点。我们把代码开源出来,不是因为它完美了,而是希望更多人一起把它做得更好。企业AI落地是一个巨大的工程,没有哪个团队能独自解决所有问题。开源之后,我们收到了很多有价值的反馈和贡献,有些是我们自己完全没想到的场景和用法。这种社区的力量,比闭门造车强太多了。

最后说一个我个人的体会:做企业AI,最难的从来不是技术,而是理解业务。模型、架构、工具都是手段,真正重要的是搞清楚企业里的工作流是怎么跑的、痛点在哪里、哪些环节适合AI介入、哪些环节必须人工把关。把这些想清楚了,技术方案自然就出来了。反过来,如果业务没想清楚,技术再先进也是白搭。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询