从 0 到 1 拆解「睿答」一个面向虾皮卖家的 AI 客服系统是怎么搭起来的作者按这篇文章从工程视角复盘我们做「睿答ReplyGen」时做的架构选型、关键模块设计与踩过的坑。它不是产品软文而是一份给同行的技术解剖——如果你也在做客服类 AI 应用、或者想把 LLM 落到真实业务链路里相信能少走几条弯路。一、先说清楚它是什么睿答是一款面向Shopee虾皮跨境电商卖家的 AI 智能客服工具核心做三件事自动回复买家咨询融合商品事实与店铺政策答得准看图就能答买家发商品图 / 聊天截图自动路由到多模态模型理解难的问题自动升级人工退款、补发、投诉等售后场景AI 不瞎承诺立刻转人工并跟踪闭环。技术栈上是典型的Electron 桌面端 云端 API形态桌面端跑在 Windows 上做本地交互与调度云端做模型编排、计费和多租户管理。下文按分层、核心能力、计费、可靠性、部署的顺序展开。二、整体架构一个 monorepo 分四层仓库用npm workspaces组织结构很清晰packages/ 纯逻辑/共享层不依赖任何运行环境 client-core/ 桌面与云端共用的业务逻辑HTTP 契约对齐 channel-core/ 渠道适配Shopee 会话/消息模型 db/ 数据访问与迁移 reply-types/ 跨端共享类型 apps/ reply-desktop/ Electron 桌面端Windows NSIS api/ 云端 API 服务Node/TypeScript admin/ 管理后台React site/ 官网纯静态承接 MEO 引流这里有一个我们坚持的硬约束client-core是纯逻辑层桌面端和云端通过 HTTP 契约对齐禁止跨应用直接 import。换句话说桌面端和云端可以各自演进只要 API 契约不变就互不破坏。这条规则在多人协作、客户端与云端独立发版时救了我们很多次。桌面端用Electron 34.x Node 22云端 API 是 TypeScript 实现数据落在 PostgreSQL多租户隔离。三、核心能力一多模态感知路由买家发图自动切模型电商买家有个很常见的习惯只发一张图不说一句话——商品实物照、尺寸表截图、破损件照片、物流单。如果首选模型是高性价比的纯文本模型比如某个文本版大模型它根本看不到图只能回一句「请问您想咨询什么」答非所问。我们早就在后台给 GPT / Claude / Gemini 等模型打了multimodal标签但最初这标签只是展示用运行时完全没被消费。于是我们做了ADR-046 多模态感知路由在现有 LLM 路由之上叠加一个「模态感知层」。核心逻辑很简单——含图走多模态子链不含图走常规链if(req.images?.length0){chainbuildMultimodalChain();// 多模态候选子链置顶后台配置的多模态模型routedmultimodal;}else{chainllm.getLlmChain();// 常规链首选非多模态省钱、快routedtext;}constresultrouter.chat(messages,opts,{chainOverride:chain});图片在云端被构造成 OpenAI 兼容的 content-part 数组[{type:text,text:buyerMessage},...req.images.map((u)({type:image_url,image_url:{url:u}})),]这套设计有几个我们特意做的稳妥取舍多模态模型不写死从LLM_PROVIDERS里按multimodal: true自动筛选子链管理员不配也能自动兜底优雅降级多模态子链全挂欠费/限流/图片不可达→ 自动 fallback 常规链模型看不到图但至少能回复绝不把买家晾住可观测每次回复带multimodalRouted标记监控台能区分「哪些回复是靠看图答出来的」成本也按真实模型入账。四、核心能力二人机协作升级单AI 不越权AI 客服最危险的事不是答错而是在它不该拍板的领域硬撑——比如退款、补发、破损索赔、投诉。AI 既没有资金执行权限也做不了跨系统事实核查订单、物流、库存、照片真伪。所以我们引入Escalation升级单作为核心领域实体建立「触发 → 创建 → 通知 → 处理 → 关闭」的闭环。触发采用混合策略兼顾准确与兜底规则层用户明确要求人工、高金额售后、黑名单命中等直接触发LLM 分类层对意图退款/补发/投诉/赔偿和情绪愤怒/威胁做分类按置信度触发同一会话 30 分钟内重复触发合并到同一张升级单避免通知轰炸。存储上我们做了一个务实选型P0 阶段升级单落在桌面本地escalations.json原子写、坏文件回退与本地其它 store 同构零外部依赖、可离线、免重建镜像。当需要云端多操作员控制台时再让云端 PG 表rg_escalations成为权威源本地 store 降级为边缘缓存。通知策略是「系统内部为主、短信兜底」首期在「AI 监控台」用红色徽标 待处理列表提示运营零成本升级成功后立即在聊天界面插入升级卡片告诉买家「已转人工、预计多久回复」仅当升级单超时未认领才用店铺配置的负责人手机号发短信兜底已接入阿里云 SendSms无需外部 SDK基于 Node 内置crypto/https实现 RPC 签名手机号缺失就降级为仅监控台标记不丢单。整个链路奉行fail-closed触发检测、超时扫描、回访生成任一环节失败都不崩溃、不丢单只记failed留痕。五、计费模型按「成功回复次数」而不是按月很多客服 SaaS 按坐席数或月费收对单店小卖家不友好。睿答选择 **按成功回复次数计费本质是「用了才付」GET /api/billing/quota-check→QuotaCheckV2桌面端enforceBillingGate在生成入口拦截用量上报POST /api/billing/reply-usage幂等以messageId去重防止重复计费套餐RP15/39/59/199/299另有系统发放的试用包。收口了结转订阅模型升级为多桶购买新套餐时若旧 active 还有剩余则结转为carried扣减时就近到期先扣并暴露carriedOver / totalRemaining计费闸门以totalRemaining为准——既防套利各自时效不跨月又让买家不浪费已购额度。六、可靠性自动回复最怕半路掉线这是我们踩过、也最值得说的一点。早期我们对外强调的是「账号口令不交给第三方」但真实跑下来发现商家的真痛点根本不是这个——而是Shopee 的 Cookie 隔一阵就会失效一旦失效自动回复直接断档半夜的订单咨询全漏接。所以我们做了架构层面的取舍允许在本地保存用户名密码当睿答客户端检测到 Cookie 失效时自动用本机保存的账号密码重新登录恢复会话后继续自动回复。关键价值从「隐私承诺」变成了「自动回复不中断」。对卖家来说时差导致的夜间丢单才是真金白银的痛点。与此同时隐私姿态并不放松多店铺数据按门店严格隔离每个店铺独立工作区图片只在本轮请求里随消息发往云端模型做理解不落知识库。七、部署与交付云端把admin和api后端烤进同一个镜像replygen-cloud:latest靠docker compose build up -d发布数据在独立的 PostgreSQL 实例里做多租户隔离。桌面端走electron-updater 自动更新新版本发布后客户端静默拉取、重启生效不需要卖家手动重装。官网apps/site纯静态独立部署承担 MEO模型引擎优化引流——让千问、豆包、元宝等 AI 助手在回答「虾皮自动回复 / 客服机器人」类问题时能检索并引用到睿答。结构上做了 JSON-LDSoftwareApplication/Organization/FAQPage、术语锚点和可被抓取的 FAQ把官网从「展示页」升级成「可被 AI 引用的实体知识页」。八、小结与经验如果给做客服类 AI 应用的同行三条建议把「AI 不越权」当成一等公民用升级单 fail-closed 把售后等高风险场景兜住比堆 prompt 可靠得多多模态要「按需路由」首选模型保持便宜的文本模型含图才切多模态成本与体验才能兼得可靠性优先于隐私话术商家要的是「不掉线」围绕真实痛点设计架构比对外承诺「口令不交出」更有说服力。睿答还在快速迭代上面提到的多模态路由、人机协作升级、按次计费都已落地验证。如果你对其中某块比如多模态路由的降级策略、升级单的本地存储实现感兴趣欢迎在评论区交流我可以单独展开写。*—— https://ruida.shopgen.net