资讯详情 WorkBuddy企业版套件化:一个Agent底座统管五个产品的架构设计与实践
📅 2026/10/25 17:48:17
1. 从五个产品到一套底座WorkBuddy 企业版套件化的核心命题第一次看到“WorkBuddy 企业版套件化一个 Agent 底座统管五个产品”这个标题我脑子里蹦出来的第一个画面不是架构图而是一个很具体的运维场景公司内部同时跑着五套 AI 工具每套都有自己的账号体系、自己的模型配置、自己的日志格式运维同事每天在五个后台之间来回切换改一个超时参数要登录五次。这种“烟囱式”的 AI 工具堆叠在 2024 年到 2025 年之间几乎成了中大型团队的标配痛点。WorkBuddy 企业版做的事情本质上就是把这五套东西的“地基”抽出来做成一个统一的 Agent 底座让上层五个产品变成这个底座上的“租户”或者“插件”。这个思路听起来简单但真正落地的时候涉及的问题远比“抽个公共库”复杂得多五个产品的 Agent 能力边界不一样有的偏代码生成有的偏工作流编排有的偏数据分析怎么用一个底座同时满足底座的抽象层次定在哪里才不会既管不住上层、又把自己撑爆我先把结论放在前面套件化的关键不在于“统一”而在于“分层”。一个 Agent 底座要统管五个产品它必须把“所有产品都一样的部分”和“每个产品都不一样”的部分切得足够干净。切错了底座要么变成一坨谁都不敢改的巨石要么变成一层薄得没有价值的壳。1.1 为什么是“一个底座”而不是“一套微服务”很多人第一反应是五个产品那就拆成五个微服务共享一个网关不就行了这个方案在传统业务系统里没问题但在 Agent 场景下会踩坑。原因是 Agent 的核心资源不是 CPU 和内存而是模型调用配额、上下文窗口、工具Skill注册表、会话状态。这四样东西如果每个产品各管各的会出现三个致命问题。第一配额打架。五个产品各自持有模型 API Key各自限流结果就是 A 产品把配额跑满了B 产品直接 429。企业版必须有一个统一的配额池和调度器才能把有限的 token 预算按优先级分配。第二Skill 重复注册。热词里反复出现skill、skill插件、agent skill说明 Skill 机制是这个体系的核心。如果五个产品各自维护一套 Skill 注册表同一个“查询数据库”的 Skill 会被写五遍改一次要改五处。底座必须提供统一的 Skill Registry。第三会话状态割裂。用户在 A 产品里跟 Agent 聊到一半切到 B 产品上下文全丢了。企业级体验要求跨产品的会话连续性这只能靠底座统一管理 session。所以“一个底座”不是架构洁癖而是被 Agent 的资源特性逼出来的必然选择。微服务那套“每个服务自治”的理念在共享稀缺模型资源的前提下会直接失效。1.2 五个产品到底共享了什么我把这套套件化拆解下来底座真正需要统管的东西其实就五类我习惯叫它“五件套”共享层具体内容不共享会怎样模型接入层多模型路由、配额、重试、降级配额打架、成本失控Skill 注册中心Skill 定义、版本、权限、发现Skill 重复开发、版本混乱会话与上下文Session、Memory、上下文压缩跨产品体验断裂身份与权限租户、用户、产品级 RBAC权限模型五套、审计困难可观测性日志、Trace、Token 计量出问题无法定位、成本无法归因这五类里模型接入层和 Skill 注册中心是底座的技术核心身份和可观测性是工程保障会话与上下文是最容易被低估、但用户感知最强的一层。后面我会逐个展开。1.3 套件化之后五个产品变成了什么这是理解整个架构的关键。套件化不是把五个产品合并成一个而是让它们从“独立应用”降级为“底座上的配置 少量专属逻辑”。用一句话概括产品 底座能力 产品专属的 Prompt 策略 产品专属的 Skill 组合 产品专属的 UI。举个具体例子。假设五个产品里有一个偏代码的类似 CodeBuddy 的定位一个偏通用办公的WorkBuddy 本体一个偏数据分析的一个偏科研文献的一个偏工作流自动化的。套件化之后代码产品 底座 代码类 Skill 集 代码专用系统提示词 IDE 插件 UI办公产品 底座 文档类 Skill 集 办公提示词 对话式 UI数据产品 底座 SQL/图表 Skill 集 分析提示词 看板 UI你会发现产品之间的差异被压缩到了“Skill 组合 提示词 UI”这三样。底座承担了 80% 的复杂度产品只负责 20% 的差异化。这就是套件化的价值新增一个产品从“重写一个 Agent 系统”变成“配置一套 Skill 和提示词”。但这里有个陷阱我必须提醒不是所有产品都适合塞进同一个底座。如果两个产品的 Agent 交互范式差异过大比如一个是纯对话一个是纯批处理流水线强行统一底座会导致抽象层被迫做得极其宽泛最后谁都用得不顺手。判断标准是它们的“模型调用 Skill 调用 会话管理”这三件事的形态是否一致。一致就能共享底座不一致就该独立。2. Agent 底座的分层设计与 Skill 机制拆解底座怎么分层直接决定了它能撑多久。我见过太多“统一底座”项目死在第二层——抽象做浅了上层产品各自绕过底座直连模型抽象做深了底座变成一个改不动的黑盒。WorkBuddy 这套体系能统管五个产品说明它的分层是经过实战检验的。我按自己的理解把它拆成四层并重点讲 Skill 机制因为热词里skill出现的频率高得离谱这一定是整个体系的重心。2.1 四层架构接入层、编排层、能力层、资源层接入层负责协议适配。企业里五个产品可能用不同的调用方式有的走 HTTP OpenAPI有的走 WebSocket 长连接有的走 SDK。接入层要把这些协议统一成内部的 Agent 请求格式。热词里OpenAPI反复出现说明对外暴露标准 OpenAPI 是这套体系的重要能力——第三方系统可以通过 OpenAPI 直接调用底座能力而不需要理解内部协议。编排层是 Agent 的大脑负责决定“这一步该调模型还是调 Skill”“上下文怎么组装”“多轮怎么推进”。这一层是产品差异化的主要战场但底座要提供的是编排原语而不是替产品做编排决策。比如底座提供“条件分支”“并行调用”“重试”这些原语产品用它们拼出自己的流程。能力层就是 Skill 层。所有可被 Agent 调用的能力——查数据库、调 API、读文件、画图、跑代码——都注册在这里。这一层是底座最核心的资产。资源层是模型、向量库、存储、计算资源的抽象。这一层要屏蔽具体供应商差异让上层不关心用的是哪个模型。这四层里编排层和能力层的边界最容易画错。我的经验是编排层只负责“怎么调”能力层只负责“调什么”。一旦编排层开始关心具体 Skill 的业务逻辑或者能力层开始关心调用顺序边界就破了。2.2 Skill 机制底座的能力单元热词里有一堆关于 Skill 的搜索skill插件、agent skill、workbuddy skill、skill编码193、skill编码247、测试skill、豆包skill、codex skill、codex论文skill、打斗动作提示词skill、gemini反重力skill。这些词说明 Skill 已经形成了一个生态不同来源、不同用途的 Skill 都在往这个体系里接。Skill 的本质是给 Agent 用的函数。它和普通函数调用的区别在于三点第一Skill 必须能被模型“理解”所以它需要自然语言描述description第二Skill 的输入输出要能被模型消费所以通常是结构化的 JSON Schema第三Skill 要有权限和配额因为 Agent 可能被诱导调用危险操作。一个 Skill 的标准定义大概长这样{ name: query_sales_data, description: 查询指定时间范围内的销售数据返回汇总结果, version: 1.2.0, parameters: { type: object, properties: { start_date: {type: string, description: 开始日期 YYYY-MM-DD}, end_date: {type: string, description: 结束日期 YYYY-MM-DD}, region: {type: string, description: 区域可选} }, required: [start_date, end_date] }, permissions: [sales:read], timeout_ms: 10000 }这里有几个设计要点值得展开。description 的写法直接决定模型能不能正确调用。我踩过的坑是description 写得太技术化模型理解不了业务语义写得太模糊模型会乱调。好的 description 是“业务语义 边界条件”比如“查询销售数据仅支持最近两年超过范围会报错”。version 字段是必须的。Skill 会迭代如果没版本管理某个产品依赖旧行为、另一个产品依赖新行为就会互相打架。底座要支持多版本共存产品按需锁定版本。permissions 是安全底线。热词里有agent安全这不是空话。Agent 被 prompt injection 攻击时最危险的就是它调用了不该调的 Skill。底座必须在 Skill 调用前做权限校验而不是信任模型的判断。2.3 Skill 的注册、发现与隔离五个产品共享一个 Skill 注册中心但不是所有 Skill 对所有产品可见。这里需要三层隔离全局 Skill所有产品都能用比如“获取当前时间”“通用搜索”。产品级 Skill只有特定产品能用比如代码产品的“执行单元测试”。租户级 Skill企业客户自己上传的私有 Skill只对该租户可见。隔离靠的是 Skill 的 namespace 和权限标签。产品在初始化时声明自己需要哪些 namespace底座只返回可见的 Skill 列表。这样既保证了共享又避免了污染。Skill 的发现机制有两种静态注册和动态发现。静态注册是启动时加载配置文件适合稳定的核心 Skill动态发现是运行时从注册中心拉取适合频繁更新的 Skill。企业版通常两者结合核心 Skill 静态加载保证启动速度扩展 Skill 动态拉取保证灵活性。注意动态发现 Skill 时一定要做签名校验。我见过有团队为了图方便允许从任意 URL 加载 Skill 定义结果被注入了一个“读取环境变量”的恶意 Skill。Skill 的来源必须可信加载前必须验签。2.4 上下文管理最容易被低估的一层会话与上下文管理是套件化里最不显眼但用户感知最强的一层。五个产品共享会话意味着用户在代码产品里说“帮我看看昨天那个 bug”切到办公产品时 Agent 还能记得“昨天那个 bug”指的是什么。这需要底座维护一个跨产品的 Memory 层。Memory 的设计有两个流派全量保留和摘要压缩。全量保留简单但 token 成本爆炸摘要压缩省钱但会丢信息。我的实践是分层 Memory最近 N 轮对话全量保留更早的对话做摘要关键实体人名、项目名、文件路径单独抽取成结构化记忆。这样既控制了 token又保住了关键信息。上下文组装的时候还有个细节不同产品的系统提示词要注入到同一个上下文里。如果处理不好会出现“代码产品的提示词污染了办公产品的对话”。解决办法是给每段上下文打上来源标签组装时按产品过滤。3. 从零搭建底座核心模块的实操过程前面讲的是设计思路这一节我讲具体怎么落地。我会按“模型接入层 → Skill 注册中心 → 会话管理 → OpenAPI 暴露”的顺序给出可参考的实现方案。这些方案是我基于常见企业级 Agent 平台的实践总结具体参数需要根据你的模型供应商和团队规模调整。3.1 模型接入层多模型路由与配额池模型接入层的核心是统一接口 智能路由 配额管理。统一接口让上层不关心具体模型智能路由根据任务类型、成本、延迟选择模型配额管理防止某个产品把预算跑光。先看统一接口的设计。我建议定义一个内部模型调用协议所有模型都适配到这个协议class ModelRequest: def __init__(self, messages, model_hintNone, max_tokens4096, temperature0.7, toolsNone, tenant_idNone, product_idNone): self.messages messages self.model_hint model_hint # 上层可以给建议但路由层有最终决定权 self.max_tokens max_tokens self.temperature temperature self.tools tools # Skill 列表转成模型的 function calling 格式 self.tenant_id tenant_id self.product_id product_id路由逻辑我通常分三级任务类型匹配 → 成本约束 → 可用性降级。任务类型匹配是看这个请求是代码生成、长文本理解还是简单问答不同任务用不同模型成本约束是看当前租户的预算余额余额低就切便宜模型可用性降级是主模型超时或报错时自动切备用模型。配额池的实现要点是按租户 产品双维度计量。只按租户计量无法知道哪个产品在烧钱只按产品计量无法做租户级预算。两个维度都要有才能既做成本归因又做预算控制。# 配额检查的简化逻辑 def check_quota(tenant_id, product_id, estimated_tokens): tenant_quota get_tenant_quota(tenant_id) product_quota get_product_quota(tenant_id, product_id) if tenant_quota.remaining estimated_tokens: raise QuotaExceeded(租户配额不足) if product_quota.remaining estimated_tokens: raise QuotaExceeded(产品配额不足) return True实操心得配额检查一定要在调用模型之前做而且要预留 buffer。我见过有团队在调用后才扣减配额结果并发请求同时通过了检查实际消耗远超预算。正确做法是调用前预扣、调用后按实际用量结算。3.2 Skill 注册中心从定义到执行Skill 注册中心要解决四个问题定义、存储、发现、执行。定义用 JSON Schema存储用数据库或配置中心发现靠 namespace 过滤执行靠沙箱隔离。执行环节是最需要小心的。Skill 本质上是执行任意代码或调用外部系统如果不隔离一个恶意 Skill 就能拿到整个底座的权限。我的方案是进程级隔离 能力白名单每个 Skill 在独立进程或容器里跑只能访问白名单里的资源比如指定的数据库连接、指定的 API 域名。# Skill 执行的沙箱包装 class SkillExecutor: def execute(self, skill_name, params, context): skill self.registry.get(skill_name, context.product_id) if not self.check_permission(skill, context.user): raise PermissionDenied() # 在隔离环境中执行 with self.sandbox(skill.timeout_ms, skill.resource_limits): result skill.handler(params) # 记录审计日志 self.audit_log(skill_name, params, context) return result审计日志这块我要多说一句。热词里有agent安全企业级 Agent 的安全审计不是可选项。每次 Skill 调用都要记录谁调的、调了什么、参数是什么、结果是什么、耗时多少。出安全事件时这份日志是唯一的追溯依据。3.3 会话管理跨产品的上下文连续性会话管理的核心数据结构是 Session。一个 Session 包含会话 ID、租户 ID、参与的产品列表、消息历史、结构化记忆、创建和更新时间。跨产品连续性的实现关键是Session 与 Product 解耦。Session 属于用户不属于产品。用户在产品 A 创建的 Session切到产品 B 时可以通过 Session ID 继续。产品 B 拿到 Session 后按自己的系统提示词重新组装上下文。class Session: def __init__(self, session_id, tenant_id, user_id): self.session_id session_id self.tenant_id tenant_id self.user_id user_id self.messages [] # 全量消息 self.summary # 历史摘要 self.entities {} # 结构化记忆 self.products set() # 参与过的产品 def add_message(self, role, content, product_id): self.messages.append({ role: role, content: content, product_id: product_id, ts: now() }) # 超过阈值触发摘要 if len(self.messages) 50: self.compress()上下文压缩的触发阈值需要调。太小频繁压缩丢信息太大token 成本高。我的经验值是保留最近 20 到 30 轮全量更早的做摘要。摘要用便宜的小模型做成本可控。3.4 OpenAPI 暴露让第三方接入底座热词里OpenAPI出现多次说明对外暴露标准接口是刚需。底座的能力要通过 OpenAPI 暴露给第三方系统让它们能像调用普通 API 一样调用 Agent。OpenAPI 设计有三个要点。第一认证用标准方案比如 OAuth2 或 API Key不要自创。第二接口要幂等Agent 调用可能重试非幂等接口会出问题。第三流式响应要支持Agent 的输出是逐字生成的用 SSE 或 WebSocket 推送体验最好。# OpenAPI 片段示例 paths: /v1/agent/chat: post: summary: 发起一次 Agent 对话 security: - ApiKeyAuth: [] requestBody: content: application/json: schema: type: object properties: session_id: {type: string} message: {type: string} product_id: {type: string} stream: {type: boolean, default: true} responses: 200: description: 流式返回 Agent 响应注意OpenAPI 暴露的接口一定要做速率限制和配额绑定。第三方系统可能写出死循环调用没有限流会把底座打垮。每个 API Key 绑定一个配额池超限直接拒绝。4. 常见问题与排查技巧实录套件化落地过程中问题往往不在设计阶段而在联调和运维阶段。我把踩过的坑整理成速查表覆盖模型、Skill、会话、性能四类问题。4.1 模型接入类问题问题现象可能原因排查方法解决某产品突然大量 429配额被其他产品抢占查配额池实时用量按产品设独立配额上限响应变慢但无报错路由到了慢模型查路由日志的模型选择调整路由权重或加超时成本突然飙升上下文没压缩查平均 token 数调低压缩阈值模型返回格式错乱提示词与模型不匹配对比不同模型的输出按模型定制提示词模板这里重点说 429 问题。多产品共享配额池最容易出现的就是“一个产品把配额跑满其他产品饿死”。解决办法不是简单加配额而是分级配额给每个产品设保底配额保证基本可用和弹性配额空闲时可用。保底配额之和不超过总配额弹性配额按优先级分配。4.2 Skill 调用类问题Skill 相关的问题最隐蔽因为模型可能“静默失败”——它调用了 Skill 但没告诉用户。常见问题包括Skill 不被调用description 写得太差模型没理解。解决是把 description 改成业务语言并加 few-shot 示例。Skill 被错误调用多个 Skill 的 description 太相似模型分不清。解决是明确每个 Skill 的边界在 description 里写“仅用于 X不用于 Y”。Skill 超时外部依赖慢。解决是设合理超时超时后返回降级结果而不是报错。Skill 权限报错产品没声明对应 namespace。解决是检查产品的 Skill 声明配置。实操心得调试 Skill 调用时一定要打开模型的 function calling 日志。很多时候模型“看起来没调 Skill”其实是调了但参数错了。日志里能看到模型生成的原始参数这是定位问题的关键。4.3 会话与上下文类问题跨产品会话最容易出的问题是上下文污染。产品 A 的系统提示词被带到了产品 B 的对话里导致 Agent 行为异常。根因是上下文组装时没做来源过滤。解决办法是给每条消息打 product_id 标签组装时只保留当前产品的系统提示词历史消息按需保留。另外结构化记忆要做租户隔离不同租户的实体不能混。还有一个坑是会话过期策略。会话不能永久保留否则存储爆炸。我的方案是活跃会话保留 30 天过期会话归档到冷存储只保留摘要。用户主动删除的会话立即清除。4.4 性能与稳定性问题套件化之后底座成了单点。底座挂了五个产品全挂。所以高可用是硬要求。关键措施有三个。第一无状态化底座的服务实例不保存状态状态全放 Redis 或数据库这样实例可以随意扩缩容。第二熔断降级某个模型供应商挂了自动切备用某个 Skill 超时率高自动熔断。第三限流保护入口做全局限流防止突发流量打垮底座。# 熔断器简化实现 class CircuitBreaker: def __init__(self, failure_threshold5, recovery_time60): self.failures 0 self.threshold failure_threshold self.recovery_time recovery_time self.opened_at None def call(self, func, *args, **kwargs): if self.is_open(): raise CircuitOpen(熔断中请稍后重试) try: result func(*args, **kwargs) self.failures 0 return result except Exception as e: self.failures 1 if self.failures self.threshold: self.opened_at now() raise注意熔断阈值不要设得太敏感。Agent 调用本身就有一定失败率模型超时、Skill 抖动阈值太低会导致频繁熔断反而影响可用性。我的经验是连续 5 次失败才熔断恢复时间 60 秒起步。5. 套件化的边界与扩展什么时候该拆什么时候该合写到这儿我想聊聊套件化的边界问题。因为“一个底座统管五个产品”听起来很美好但不是所有团队都适合。我见过强行套件化最后失败的案例也见过该合没合、维护成本爆炸的案例。判断标准其实就一条产品之间的共享收益是否大于耦合成本。5.1 适合套件化的三个信号信号一产品间共享大量 Skill。如果五个产品里有 60% 以上的 Skill 是重叠的套件化收益巨大。反之如果每个产品的 Skill 都是独有的共享底座的价值就只剩模型接入和会话管理收益有限。信号二有统一的租户和权限体系。企业客户买的是“一套 WorkBuddy”而不是“五个独立工具”。如果产品各自有独立的账号体系客户要管理五套权限体验很差。套件化能统一身份这是企业版的刚需。信号三团队有能力维护底座。底座是一个长期投入的基础设施需要专门的团队维护。如果团队规模小五个产品都靠同一批人开发套件化反而增加协调成本。这种情况下先做“共享库”而不是“共享底座”更务实。5.2 底座不该管的三件事套件化最容易犯的错是底座管太多。有三件事底座不该管第一产品的业务逻辑。底座提供 Skill 和编排原语但“这个产品的 Agent 该怎么回复用户”是产品的事。底座一旦开始关心业务语义就会变成改不动的巨石。第二产品的 UI 和交互。底座只提供 API不提供界面。界面是产品差异化的核心底座不该碰。第三产品的专属数据。底座管会话和记忆但产品自己的业务数据比如代码产品的代码库索引应该产品自己管。底座只提供存储抽象不提供具体存储。5.3 扩展新产品的标准流程套件化的最大价值是降低新增产品的成本。我总结了一个标准流程新增一个产品大概分四步定义产品画像这个产品面向什么场景、用什么模型、需要哪些 Skill。配置 Skill 组合从 Skill 注册中心挑选需要的 Skill声明 namespace。编写系统提示词这是产品差异化的核心决定 Agent 的行为风格。接入 OpenAPI用底座的 OpenAPI 实现产品后端前端自己开发。这四步里系统提示词是最花时间的。我见过有团队以为套件化之后新产品一周就能上线结果提示词调了两周。提示词不是写一次就完要反复测试、迭代。建议给每个产品建一个提示词测试集每次改动都跑一遍回归。5.4 一个真实的扩展案例假设要新增一个“科研文献助手”产品热词里有workbuddy 科研。按套件化流程产品画像面向科研人员需要文献检索、摘要生成、引用格式化能力。Skill 组合复用底座的“通用搜索”Skill新增“文献库检索”“引用格式化”两个专属 Skill。系统提示词强调学术严谨性要求引用必须标注来源不确定的内容要明确说明。OpenAPI 接入用底座的 chat 接口前端做一个文献管理界面。整个过程底座代码零改动只新增了两个 Skill 和一套提示词。这就是套件化的威力——新增产品从“造轮子”变成“拼积木”。6. 我在这套体系里踩过的坑和总结的经验最后这部分我想抛开架构聊点更实在的东西。套件化这件事技术方案可以抄但经验抄不来。我把自己踩过的坑列出来希望能帮你少走弯路。第一个坑过早抽象。项目刚开始就想着“要统管五个产品”把底座抽象做得极其宽泛结果每个产品接入时都要写一堆适配代码。正确做法是先让两个产品跑通再抽象。两个产品的共性才是真共性五个产品的共性往往是想象出来的。第二个坑Skill 没有版本管理。早期觉得 Skill 改了就改了结果一个产品依赖旧行为另一个依赖新行为互相打架。后来加了版本字段产品锁定版本问题才解决。Skill 一旦发布就不能改行为只能发新版本。第三个坑忽略可观测性。上线初期没做 Trace出问题只能靠猜。后来补了全链路 Trace才发现很多问题出在上下文组装而不是模型本身。可观测性不是上线后补的是设计时就要留的。第四个坑配额没做预扣。并发请求同时通过配额检查实际消耗超预算。改成预扣 结算后解决。这个坑很隐蔽因为单请求测试永远发现不了。第五个坑会话没做租户隔离。测试时用同一个租户没发现问题。上线后多租户发现结构化记忆串了。所有涉及数据的地方都要先问一句“租户隔离了吗”。这套体系跑下来我最大的体会是套件化的难点不在技术而在边界。技术方案网上都能搜到但“什么该共享、什么该独立”这个判断只能靠对业务的深刻理解。底座做得太厚产品失去灵活性做得太薄共享价值不足。这个平衡点每个团队都不一样只能自己摸索。如果让我给正在考虑套件化的团队一个建议那就是先从共享模型接入和 Skill 注册中心开始这两块收益最明确、风险最低。会话管理和身份体系可以第二步做。至于产品专属逻辑永远不要往底座里塞。守住这条线底座就能活得久。