资讯动态

Agent多业务分层定制:知识库与控制器动态装配

发布时间:2026/10/19 12:55:35 来源:尧图企业网站定制
1. 开头一个业务系统太多Agent 帮手反而变笨了接触过这类项目的人都懂真正推动我去做「分层定制」的不是技术炫技而是被实际业务痛到不行。之前给某公司内部做统一的 AI 助手时最初的想法很简单把所有业务知识塞进一个知识库把所有能用得上的工具全部注册成控制器让大模型在 browser-use WebUI 里统一调度。结果上线没两周就翻车了——客服同学问订单问题时模型把另一套财务系统的报销术语也带了出来运维同事让它操作服务器工具列表里居然混着市场部门的营销文案模板。知识互相污染、工具彼此冲突、上下文被不相关的内容挤爆这是所有想在浏览器自动化场景里做业务定制的人早晚要撞上的墙。所以这个标题其实戳中了一个很核心的工程问题当 browser-use WebUI 需要服务的不只是一个系统而是多个业务系统且每个系统在知识库和控制器上都有完全不同的要求时怎么做才能让同一个 Agent「见人说人话、见鬼说鬼话」答案就是标题里说的「分层定制」按照业务系统把知识库拆开、把控制器拆开运行时判断当前在哪个系统再动态加载对应的那套配置。这篇文章我会把完整思路、架构设计和落地时踩过的坑都写清楚适合正在用 browser-use、想在 WebUI 之上做多业务定制的人参考也适合准备把 Agent 工程化落地的团队看看。需要先交代一个概念免得后面混乱这里说的知识库指的是喂给大模型做检索增强RAG的文档/向量数据控制器指的是给大模型调用浏览器、点击、输入、读取页面等能力的工具集也可以理解成技能插件。分层定制的目标就是让这两样东西都跟着“当前正在访问的页面/业务系统”走。2. 为什么单一知识库 全量控制器撑不住多业务2.1 知识混在一起检索出来的答案必然是“串味”的把不同业务系统的操作手册、FAQ、规则说明全部塞进同一个向量库是直觉上最省事的做法但工程上几乎一定会失败。原因不在于向量检索能力不行而在于相似度检索天然不看业务边界。你搜「如何发起审批」的时候向量距离最近的可能是采购审批的文档也可能是行政用印的流程模型拿到混合结果后只能靠猜。一旦猜错整个对话的置信度就崩了。举个实际例子。某公司同时跑着三类系统CRM 客户管理、ERP 进销存、OA 审批流。统一知识库里这三块文档比例相当。测试时问「驳回一笔订单需要谁审批」模型检索出的 Top 5 片段可能两段来自 ERP 订单流程、两段来自 OA 审批制度、一段来自 CRM 合同条款。结果它为了“全面”把三个系统的规则揉成了一段四不像的答复。用户当场就发懵。这不是模型笨而是我们的知识组织方式没给它边界感。2.2 控制器全量注册决策效率和安全性都大打折扣控制器是另一个大坑。browser-use 这类浏览器自动化框架允许注册一系列动作比如点击元素、表单填写、页面导航、截图分析、读取表格等等。如果 10 个业务系统各有 10 个专属控制器加起来 100 个工具全塞给大模型会发生什么模型每次决策都要把所有工具的 description 过一遍。工具列表过长时有两个问题一是选择准确率下降模型更容易在相似名称的工具之间点错二是上下文窗口被无意义占用每个工具的 JSON Schema 描述动辄几百 token100 个工具光定义就占掉数万 token真正留给任务推理的空间少了一大截。更严重的是安全风险——财务系统的「发起转账」控制器在 CRM 页面里也能被调用一旦路由判断失误轻则报错重则操作落到不该操作的系统上。2.3 从一次真实故障看不隔离边界Agent 就是事故发动机那次让人印象很深的故障是这样的用户让助手在 OA 系统里查会议室预订记录结果模型看到工具列表里有一个不在 OA 业务域内的「批量导出客户联系方式」控制器竟然真的发起调用。页面跳转到 CRM 后模型发现自己跑错了系统又手忙脚乱往回跳。整个过程日志里写得明明白白模型不是故意越权而是它根本不知道哪些控制器是当前业务系统允许用的。这次之后我们就定了一个原则Agent 能用的工具必须由运行环境显式注入而不是由模型自己从全集里挑。应该说清楚一个反直觉的点很多人以为「模型能力越强越不需要人为限定工具集」。实际恰恰相反模型越强它越会积极尝试调用各种工具越需要外部系统帮它划好边界。分层定制的本质不是限制模型而是把「当前业务场景的知识和工具白名单」替模型提前准备好让它在清晰的边界内发挥全部推理能力。3. 分层定制的整体架构路由、知识、控制三层各自干什么3.1 分层不是简单的“多建几个库”而是把「业务系统」变成一等的定制维度在动手改代码之前先把架构想清楚。我的做法是把整个定制过程拆成三个层次每一层只负责一件事层与层之间通过一个「当前业务系统身份」的公共变量联动。路由层负责在会话开始时判断「现在正在访问哪个业务系统」。依据可以是 URL 域名、页面标题、URL 路径参数、登录用户所属角色或者这几者的组合。知识层负责按业务系统组织知识决定当前会话可以检索哪些知识库切片。知识库不再是「一个大池子」而是按业务域拆成多个独立命名空间可以交叉引用但默认隔离。控制层负责按业务系统装配控制器。每个控制器声明自己适用的业务系统运行时只把当前系统白名单里的控制器注入给大模型。这个设计的核心变化在于以前我们按「功能」维度组织 Agent 的能力一堆知识 一堆工具现在改成按「业务系统」维度组织。功能只是能力本身的标签业务系统才是决定「能力何时可用」的钥匙。3.2 路由层判断业务系统身份是整个动态加载的触发器路由层是所有动态加载的第一步也是决定后面两层能不能正确工作的前提。我把它做成一个轻量级的判定器放在 browser-use 的初始导航完成之后、大模型第一次决策之前触发。判断依据优先级从高到低如下表所示判定依据示例特点URL 域名crm.xxx.com / erp.xxx.com最可靠、成本最低一般域名不会串URL 路径前缀/oa/approval、/erp/stock适合同一域名下多个子系统的场景登录态/用户角色当前会话中的用户部门适合同一系统不同角色需要不同工具的场景页面关键元素标题、Logo、特定按钮文案作为兜底域名规则失效时使用路由判定器输出一个标准化的业务系统标识比如crm、erp、oa、hr。之后的逻辑里不管是加载知识库还是加载控制器都以这个标识为查询键。如果识别不出来不要硬猜直接拒绝执行并提示用户手动指定业务系统宁可停下来也不要拿错配置。有个容易忽略的细节真实环境下 URL 可能变化比如从erp.xxx.com/stock跳转到erp.xxx.com/sale虽然仍是同一业务系统但页面语义已经变了控制器白名单可能需要收窄。所以路由层建议做成可被页面变化触发的二次判定逻辑而不仅仅是会话开始判定一次。3.3 知识层与控制层用「按需装配」替代「全量常驻」在传统实现里知识库检索和控制器定义通常是全局的Agent 每次决策都能访问。分层定制要求反过来默认不加载路由判定后按需装配。当路由层输出业务系统标识后由装配器读取「系统-配置」映射表把对应的知识库配置和控制器白名单加载到本次会话的上下文中。这个「按需装配」的设计带来的直接好处有三个上下文干净、决策更快、权限边界清晰。知识库里不会出现别的系统的内容来干扰检索控制器列表里不会出现别的系统的工具来诱导模型误操作即使模型出现幻觉它能拿到的工具从物理层面就被限定了无法越权动作。后面我会分别把知识层和控制层的落地细节展开说。4. 知识库动态加载先拆库再按业务系统挂载4.1 拆库粒度一个业务系统一个命名空间必要时再按子域细分知识库拆分的粒度直接决定后期维护成本。我的经验是至少按业务系统一级拆分也就是每个系统拥有独立的知识库集合或索引命名空间如果某个系统内部的流程差异极大比如 ERP 里的采购流程和财务流程完全不同再往下按子域拆也可以但要避免拆得过碎。拆碎的下场就是维护地狱。比如把「订单页常见问题」「订单页按钮说明」「订单页字段含义」拆成三个库看起来很精细实际上检索时要么三库都要查要么经常漏查关键的。更合理的粒度是「一个业务域一个库」库内部用文档的元数据字段业务域、文档类型、更新时间做二次过滤。以某公司为例我们的知识库拆分方案是kb_crm客户管理相关的客户分级、商机阶段、跟进规则、合同模板要点。kb_erp进销存相关的商品管理、采购入库、销售出库、库存盘点操作流程。kb_oa审批流、会议室、公告、考勤相关的制度和操作说明。每个库在向量数据库里对应独立的 collection 或索引前缀检索时按 collection 隔离互不干扰。4.2 绑定关系配置一份可读的映射表是命脉拆完库之后需要一个地方维护「哪个业务系统挂哪个知识库」的映射。我建议用 YAML 或者 JSON 配置而不是在代码里硬编码。一份最小可用的配置长这样business_systems: crm: display_name: 客户管理系统 kb_collections: - kb_crm controllers: - crm_contact_search - crm_customer_detail - browser_core erp: display_name: 进销存系统 kb_collections: - kb_erp controllers: - erp_sku_search - erp_stock_query - browser_core oa: display_name: OA办公系统 kb_collections: - kb_oa controllers: - oa_approval_query - oa_meeting_book - browser_core注意一个细节每个业务系统都配了browser_core控制器集合。这是浏览器自动化的基础能力比如打开页面、滚动、截图等所有系统都需要属于公共控制器。分层定制不是要把公共能力也拆掉而是「公共能力默认有业务专属能力按需加」。4.3 挂载过程与检索策略会话初始化时绑定检索时限定集合知识库的动态加载在工程上其实是「配置驱动 运行时绑定」。当路由层判定当前业务系统为erp后装配器执行两件事第一读取映射表获得kb_erp的集合名称和连接配置第二在这个会话里初始化一个只指向kb_erp的检索器。后续用户提问时检索器的相似度搜索只会在这个集合内执行。检索策略方面我强烈建议采用「混合检索 轻量重排」。混合检索指同时用向量相似度和关键词匹配BM25各自召回一批再用一个轻量级的交叉编码器把两路结果合并排序。原因在于向量检索擅长语义相似但措辞不同的查询关键词检索擅长精确匹配专有名词比如系统里的单据编号、特定按钮名称。光靠向量检索遇到「SP-2024-0912 这张出库单卡在哪一步」这种问题容易被编号干扰加上关键词召回后准确率高很多。重排模型不用选太大的百来 MB 的双塔或者小型交叉编码器就够了。这一步对最终回答质量有决定性影响——Top 5 片段里只要有一条是别的业务域的大模型就可能被带偏。有了重排检索结果才能稳定控制在当前业务域的文档里。这里再给一个容易踩的坑不要把知识库的「集合权限」和「API 密钥权限」混为一谈。即使你的向量库支持按集合做 API Key 隔离也最好在应用层再校验一次当前会话的业务系统标识与目标集合是否匹配。安全永远多一层保险尤其涉及敏感业务数据时。5. 控制器动态装配注册表、过滤器、上下文注入5.1 控制器的本质与注册声明让工具自己说清楚「我属于谁」控制器在代码层面就是一组可被大模型调用的函数或工具声明。在 browser-use WebUI 的场景里控制器可以是独立的技能包每个技能包包含工具函数的实现、工具的 JSON Schema 描述包含参数、返回值、触发条件、以及运行时元数据。为了支持动态装配每个控制器在注册时必须声明两个额外的字段allowed_business_systems允许哪些业务系统调用和required_kb如果需要知识库辅助依赖哪个知识库集合。这样做的好处是业务系统与控制器之间的绑定关系不再是某个人脑里的记忆而是一份可以被程序检查和测试的数据。一个控制器注册表的示例结构如下CONTROLLER_REGISTRY { crm_contact_search: { module: controllers.crm.contact_search, function: search_contact, description: 在CRM系统中按姓名/电话搜索客户联系人返回联系人详情列表。, parameters: { type: object, properties: { keyword: {type: string, description: 联系人姓名或电话关键字} }, required: [keyword] }, allowed_business_systems: [crm], required_kb: kb_crm, danger_level: medium }, browser_core: { # 浏览器公共能力所有系统可用 allowed_business_systems: [*] } }5.2 动态装配的执行逻辑白名单过滤 角色二次过滤控制器装配的运行时逻辑不复杂却需要严谨。我从路由层拿到业务系统标识后先做一次「系统 → 控制器」的白名单过滤把标记为允许当前系统的控制器全部捞出来然后做一次「用户角色 → 控制器」的二次过滤这一步专门处理同一系统内不同岗位权限不同的情况。举个例子同在一个 CRM 系统里销售专员可以使用crm_contact_search但不能使用crm_price_adjust改价权限销售主管则两者都可以。角色信息可以从登录态里拿在装配控制器时作为附加过滤条件。经过两次过滤后形成的最终控制器列表连同知识库配置一起注入大模型的 system prompt 和 tools 参数里。从代码层面看核心过滤逻辑就几行但边界检查要做足def assemble_controllers(business_system: str, user_roles: list[str]) - list[ToolDefinition]: eligible [] for name, meta in CONTROLLER_REGISTRY.items(): allowed_systems meta[allowed_business_systems] if * not in allowed_systems and business_system not in allowed_systems: continue required_roles meta.get(allowed_roles) if required_roles and not any(role in required_roles for role in user_roles): continue eligible.append(load_tool_definition(name, meta)) return eligible5.3 命名空间与描述规范防止模型在有边界的情况下依然点错工具动态装配解决了「能调用哪些工具」的问题但还有一个隐形问题工具名称和描述如果含糊模型即使在白名单内也可能选错。比如 CRM 里有个search_contactERP 里也有个search_supplier名字都很像「搜索」模型如果不细看描述容易被误导。我的做法是强制规定控制器命名加业务前缀并在描述里把业务域、触发条件、妥协同义词都写明白。例如crm_search_contact仅在 CRM 系统内按姓名/电话/公司名搜索客户联系人。erp_search_supplier仅在 ERP 系统内按供应商编码/名称搜索供应商档案。oa_book_meeting_room仅在 OA 系统内按时间与人数预订空闲会议室。还有一个细节值得注意不要给多个控制器重复声明极其相似的触发条件。模型读工具描述就像人看菜单如果两道菜名字和描述都接近点错概率很高。宁可让描述长一点、触发条件具体一点也不要为了省 token 写得模棱两可。5.4 控制器之间的依赖关系也要考虑有些控制器单独没用必须配合另一个控制器使用。比如「导出报表」通常建立在「筛选列表」成功之后先拿到筛选结果才能导出。这种依赖如果靠模型自己摸索往往要浪费好几轮试错。我习惯在控制器注册表里加一个depends_on字段装配时如果发现当前业务系统需要依赖某个前置控制器会自动带上。比如{ name: erp_export_stock_report, allowed_business_systems: [erp], depends_on: [erp_stock_query, browser_core] }这样装配器在注入工具时会确保下游工具所依赖的上游工具也同时在列表中避免模型找到导出按钮却因为没有筛选能力而无法完成前置操作。6. 在 browser-use WebUI 里的配置化落地6.1 把「业务系统-知识库-控制器」绑定做成可视化配置前面讲的是架构这一节讲怎么把这些落在 browser-use WebUI 这个具体载体上。browser-use WebUI 本质上是一个可视化操作界面用户可以在浏览器页面里创建任务、查看 Agent 的操作轨迹、管理配置。我们要做的是把分层定制的映射表放到这个 WebUI 的配置层里让非纯技术背景的业务同学也能维护。我们当时在页面上做了一个「业务系统配置」的板块左侧列出所有业务系统右侧分别展示这个系统的知识库挂载列表和控制器开关列表。配置界面的字段大致如下配置字段类型说明业务系统标识文本路由层输出的一致标识如 erp系统域名/URL 规则正则或文本路由层判定该系统的依据挂载知识库多选从已有知识库集合中选择一个或多个可用控制器多选从注册表中选择当前系统允许的工具允许的角色多选哪些角色可使用这套配置兜底知识库单选项路由识别失败时是否允许使用通用知识库把配置做成可视化不是为了花哨而是为了让「加一个新业务系统」变成一次纯配置操作不用改代码。实际效果是后来某业务部门要接入一套新的项目管理系统迭代流程从「开发介入 两轮代码发版」缩短到「业务人员在 WebUI 里花半小时把知识库和控制器勾选好」。6.2 配置版本化把数据库里的配置同步到 Git 仓库可视化配置带来一个副作用配置变更没有版本记录。某天知识库挂错了集合或者控制器开关被改动事后连回滚都找不到依据。我的建议是让 WebUI 在保存配置时生成一份 YAML 文件同时 push 到 Git 仓库做版本管理WebUI 数据库里只存「当前生效版本」的引用。这样改坏了可以随时 diff 回滚。Git 仓库里的完整配置结构大概是这样agent-configs/ ├── systems/ │ ├── crm.yaml │ ├── erp.yaml │ └── oa.yaml ├── knowledge/ │ └── collection-mapping.yaml └── controllers/ └── controller-registry.yaml配置与代码分开版本化还有一个额外好处审计更清晰。查「上周三那次误操作是谁改的控制器开关」时直接看 Git 提交记录即可不需要翻数据库操作日志。6.3 会话级装配示例一次完整请求的加载序列把第 4 节和第 5 节的内容串起来一次完整的 browser-use 会话装配流程是这样的用户在 WebUI 里输入一个任务比如「在 ERP 里查一下库存低于 10 的 SKU并生成提醒表格」。browser-use 启动浏览器导航到 ERP 页面。路由层读取当前页面 URL判定业务系统为erp并读取当前用户角色。装配器读取erp.yaml配置挂载kb_erp知识库集合过滤出browser_core、erp_sku_search、erp_stock_query等控制器。大模型在这个受限的上下文里开始执行任务每一步都在 ERP 知识库和 ERP 工具集内决策。如果用户中途说「顺便看看 OA 的会议室」路由层检测到 URL 变化为 OA重新触发装配流程切换知识库与控制器。这个流程里最关键的一点是第 6 步动态加载不是一次性的而是一个随路由状态反复触发的过程。多系统穿梭是真实业务里很常见的需求如果加载逻辑只在会话开始时执行一次那跨系统任务还是会出错。所以我们的装配器设计成「订阅路由状态变化」页面 URL 每变一次就重新评估一次。7. 踩坑实录动态加载项目里最常见的五个问题及解法7.1 知识库“串味”不是检索质量问题而是边界没有下放我们最初也怀疑过是 embedding 模型选得不好导致跨域混淆后来发现根因在配置层某业务系统的挂载集合里被人手动多加了一个不属于它的「通用文档集合」。这个集合里正好有几十篇客户合同相关的材料导致 CRM 场景的检索结果里频繁混入合同条款。排查办法也不复杂——在测试环境里对每个业务系统单独跑一批预设问题人工检查每道题检索出来的 Top 3 片段是否都落在对应的知识库集合内。发现疑似串味先查配置再查检索策略不要上来就换模型。7.2 工具同名冲突换一个函数名拯救一整晚的调试时间在控制器注册表合并时我们发现两个子团队分别提交了名称完全相同的send_notification控制器一个发企业微信通知一个发邮件通知allowed_business_systems 还都写了同一个系统。装配器按名称去重时直接覆盖了其中一个导致模型实际调用的根本不是用户预期的那个。排查了很久才发现是注册表里名称碰撞。这个问题的教训是控制器注册表必须以全局唯一键为准不允许同名存在哪怕功能相似也不许「发送企业微信通知」和「发送邮件通知」就应该叫两个完全不同的名字。后来我们在注册表加载时加了启动校验同名直接报错宁可发布失败也不带着隐患上线。7.3 工具列表过长依然会发生公共控制器也要做裁剪虽然按业务系统过滤后列表短了不少但公共控制器browser_core里塞了太多通用动作滑动、截图、缩放、切换 Tab、刷新、后退……加到一起还是有二十多个。模型在需要「截个图我看下」这种简单操作时往往会在好几个截图相关的公共工具之间犹豫。解决办法是把公共控制器也做一次「按任务阶段精简」——不是所有任务都需要 Tab 切换能力装配时可以根据任务的初步意图再收窄一步。比如任务是「查询并整理数据」就只保留滚轮、截屏、读取表格这几个基础操作把刷新、后退这类导航类控制器过滤掉。7.4 路由识别失败宁可停下来也不要靠猜有时页面加载慢URL 还没变成目标域名或者单页应用里的路由切换不会改变域名路由层就会拿不到业务系统标识。一开始我们的兜底逻辑是「取最近一次成功识别的业务系统继续跑」结果翻过车——用户明明已经跳到了 OA控制器还停留在 ERP 白名单模型拿着 ERP 的工具去操作 OA 页面一顿操作全打在错误元素上。后来改成识别失败时暂停任务弹出一个选择框让用户手动确认当前系统。虽然多了一步交互但准确性提升明显。记住在 Agent 的世界里「我不知道」比「我装知道」安全得多。7.5 重新装配时的上下文残留旧工具描述要清理干净动态装配最容易忽略的是上下文清理。我们曾经在系统切换时把新的控制器和知识库配置追加到了 system prompt 里但旧的控制器描述还留在消息历史中模型继续看到了两种系统的工具又把工具点混了。后来我们规定每次重新装配system prompt 必须整体重写历史消息只保留用户问题和 Agent 对页面状态的描述不保留任何工具列表相关的旧内容。这个细节直接决定跨系统切换的稳定性。8. 落地效果的验证方法让每次改动都有数可依分层定制上线后验证不能只靠「我觉得效果变好了」。我建议建立一套针对每个业务系统的独立评估集每条测试用例包含用户请求、预期知识域、允许使用的控制器范围、预期操作路径。每周跑一遍回归对比以下指标指标计算方式目标知识域命中率检索 Top 5 片段中属于当前业务域的比例不低于 95%工具选择准确率模型实际调用工具与预期工具的匹配度不低于 90%跨系统切换成功率模拟 A→B 系统连续任务的成功完成比例不低于 88%越权调用次数模型调用非当前系统白名单内工具的次数必须为 0平均决策耗时的变化同一组任务在单库与分层配置下的耗时对比下降 30% 以上从我们的实测看分层定制在知识域和工具准确率方面的提升最明显没做之前混合知识库和全量控制器状态下订单查询类任务的正确率大概在 70% 上下做了按系统动态装配后单业务系统场景下正确率能到 90% 以上。决策耗时也明显下降原因是工具列表短了模型思考负担轻了上下文里噪声少了。验证过程中还有一个容易被忽视的点不要只测「正确任务」更要测「危险任务」。专门构造一些跨权限请求比如用销售专员身份请求调用改价控制器或者在一个系统里请求另一个系统的数据。这类测试才能验证装配器的边界是真的有效而不是停留在纸面设计上。最后分享一个持续迭代的思路把每次「配置变更 评估结果」绑定记录到一个统一看板哪个系统加了新知识库、哪个控制器改了描述、哪次改动导致某个指标下滑全部有迹可循。我们这个项目做到后面基本每个季度只需要花一天时间做一次全业务域的回归评估剩下的时间都在处理新增业务接入的配置工作而不是在救火。反过来说如果某天你发现自己的 Agent 项目天天在处理跨域污染、工具点错、权限失控的紧急问题大概率不是模型不够强而是缺少了这层「围绕业务系统的动态装配能力」。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑