






















本文介绍基于 Slickflow.NET 工作流引擎与 AI 大模型 实现的 智能客服多轮问答系统。该系统由前端 aichatapp(基于 React 的单页应用,使用纯 JS + JSX 组件)与后端 aichatbackend(ASP.NET Core WebAPI)组成,核心能力包括:
biz_customer,供后续 CRM 或运营使用。industry / industry_id 区分不同业务线,知识库与客户数据均可按行业隔离。智能问答的完整交互过程由 Slickflow 的「流程自动化运行」机制驱动:一次用户提问对应一次流程实例的启动与执行,流程内各节点(查询客户、加载历史、RAG 检索、LLM 生成、联系方式提取、保存会话等)按 BPMN 定义顺序自动执行,无需人工干预。这与传统人工审批流程「每步等人办理」形成鲜明对比,适合客服、导购、知识问答等自动化场景。
POST /api/AiChatApp/GetChatMessage,传入 Message、SessionId、CustomerId、Industry 等。WorkflowExecutor 启动流程,将 user_message、customer_id、session_id、industry_id 等写入流程变量,并调用 Run()。isNotifyClient: true,通过 SSE 将生成中的内容推送到前端;流程结束后再推送 workflow_completed。智能客服流程图如下图所示:

BPMN 定义(Process_RAG智能客服)节点顺序如下:
| 顺序 | 节点名称 | 类型 | 作用简述 |
|---|---|---|---|
下文对大模型节点(RAG、LLM)的配置与调用方式、本地服务节点的入参/出参及代码实现做说明,便于开发人员上手与二次开发。
流程中有两类 AI 节点,均在 BPMN 的 extensionElements 中通过 sf:aiServices 声明:
sf:aiService type="RAG")
ai_activity_config(或等效配置)中按流程 ID + 活动 ID 读取该节点的配置,包括:
rag_similarity_threshold)、检索条数(rag_search_count)、行业过滤(结合 industry_id)等。ai_response;若配置了 isNotifyClient: true,则通过 SSE 推送到前端。
sf:aiService type="LLM")
ai_activity_config,可配置 SystemPrompt 要求输出 JSON 格式(如:只输出 name/mobile/phone_number/wechat/email 等字段,无则 null)。contact_json,供下一节点「解析并保存客户联系数据」使用。提示词设计建议:
所有本地服务节点均通过 BPMN 的 sf:services 声明为 methodType="LocalService",并指定 expression 为实现了 IExternalService 的类名,引擎在运行到该节点时通过反射创建实例并调用 Execute()。入参由 argus 列出流程变量名,引擎从 EventService(流程变量)中按名读取并注入;出参通过 EventService.SaveVariable 写回流程变量。
从继承关系上看,本系统中的本地服务类(如 CustomerLoadService 等)通常遵循如下结构:
┌────────────────────────────┐
│ IExecutable │ (引擎内部可执行接口)
└──────────────▲─────────────┘
│
┌──────────────┴─────────────────────┐
│ ExternalServiceBase │ (抽象基类,封装 IEventService 注入)
│ - IDictionary DynamicVariables │
│ - IEventService EventService │
│ - void Executable(IEventService) │
│ - abstract void Execute() │
└──────────────▲─────────────────────┘
│ 实现 IExternalService.Execute()
┌──────────────┴─────────────────────────────────────────────────────┐
│ CustomerLoadService : ExternalServiceBase, IExternalService │
│ ConversationHistoryService : ExternalServiceBase, IExternalService │
│ CustomerContactService : ExternalServiceBase, IExternalService │
│ ConversationService : ExternalServiceBase, IExternalService │
└────────────────────────────────────────────────────────────────────┘
IExternalService:仅定义 void Execute(),表示“外部服务”统一入口。ExternalServiceBase:实现了引擎内部的 IExecutable 接口,在 Executable(IEventService) 中注入 EventService 后调用抽象 Execute(),方便子类访问/读写流程变量。CustomerLoadService 等,统一继承 ExternalServiceBase 并实现 IExternalService,只需关注业务逻辑,使用 EventService.GetVariable/SaveVariable 就能完成与流程上下文的数据交互。<sf:service methodType="LocalService" argus="customer_id" expression="Slickflow.Module.External.Customer.CustomerLoadService" />customer_id,调用 SupabaseCustomerRepository.GetByIdAsync 查询 Supabase 表 biz_customer;若查到则将该客户实体序列化为 JSON 写入变量 customer,并确保 customer_id 与库中一致。customer_id 或查不到则跳过写变量。<sf:service methodType="LocalService" argus="customer_id,session_id" expression="Slickflow.Module.External.Customer.ConversationHistoryService" />customer_id + session_id 从 biz_conversation 查询最近若干条会话(如 40 条),按时间正序组装为 [{ "role": "user"|"assistant", "content": "..." }, ...],序列化后写入流程变量 chat_history。chat_history 读取多轮历史,实现多轮对话与上下文连贯。<sf:service methodType="LocalService" argus="contact_json" expression="Slickflow.Module.External.Customer.CustomerContactService" />contact_json(由上一步 LLM 节点输出的 JSON 字符串)。customer_id,则按该 ID 查询 biz_customer,存在则更新、不存在则插入并沿用该 ID;customer_id,则按 wechat/phone 查重,有则更新、无则插入并生成新 customer_id。industry_id 从流程变量写入客户实体(便于按行业筛选客户列表)。customer,并写回 customer_id。chat_history 一条 system 消息,便于后续轮次中模型「已知哪些联系方式已收集」。<sf:service methodType="LocalService" argus="user_message, ai_response,customer" expression="Slickflow.Module.External.Customer.ConversationService" />user_message、ai_response、customer_id(或从 customer JSON 中解析)、session_id、industry_id,构造 BizConversationEntity 并调用 SupabaseConversationRepository.InsertAsync 写入表 biz_conversation。以上四类服务的调用方式统一为:引擎在流程运行时根据 BPMN 中 expression 反射得到服务类,注入 IEventService(访问流程变量与流程实例 ID),然后执行 Execute();无需在代码中显式注册,只要程序集被加载即可。
系统使用向量知识库实现 RAG:将业务文档切成片段,通过嵌入模型转为高维向量并存储;用户提问时先将问题向量化,再在向量库中做相似度检索,将检索到的片段作为上下文交给大模型生成回答。
biz_match_documents_optimized 完成。SupabaseRagService.MatchDocumentsOptimizedAsync 语义一致的接口(输入:查询向量、阈值、条数、可选 industry_id;输出:文档 id、content、metadata、similarity),并在 RAG 消息构建处注入该实现即可。常见选择包括:
embedding 列。industry_id,便于检索时按行业过滤。QWen3EmbeddingGenerator 调用阿里云 DashScope 兼容的 Embedding API;向量维度与模型配置一致(如 1536 维)。也可配置为 OpenAI 兼容的 Embedding API(如 text-embedding-3-small),由 EmbeddingGenUtility 或对应实现类完成调用。<=>:(1 - (embedding <=> query_embedding)) 即为余弦相似度,取值约 [0,1],越大越相似。biz_match_documents_optimized 对应):
query_embedding、高/低相似度阈值(如 0.8 / 0.6)、高/低阈值各取几条(如 5/3)、可选 filter_industry_id。biz_documents 中筛选:embedding 非空、相似度 ≥ 低阈值,且当 filter_industry_id 非空时只保留该行业。match_count_high 条返回,供 RAG 拼入 Context。{ "name": "张三", "mobile": "13800138000", "phone_number": null, "wechat": "wxid_xxx", "email": "zhangsan@example.com" }null 或省略。cust-{guid})。ai_response)。?industry=xxx 区分;后端将 industry 解析为 industry_id 写入流程变量,RAG 与客户数据即可按行业隔离。MatchDocumentsOptimizedAsync 同语义的检索接口,并在 RAG 消息构建处切换实现;嵌入模型与维度需与知识库一致。IExternalService,在 BPMN 中通过 sf:services 的 expression 指定类名,argus 列出所需流程变量名即可。当前示例项目在 aichatapp 中预置了多个行业入口,便于演示“同一套智能客服引擎,面向不同行业知识库与客户数据”的效果。典型访问地址(以本地开发环境为例)如下:
https://demo.slickflow.com/aichatapp/?industry=evhttps://demo.slickflow.com/aichatapp/?industry=psychologyhttps://demo.slickflow.com/aichatapp/?industry=medical_beautyhttps://demo.slickflow.com/aichatapp/?industry=pet_hosting(如需在本地或自有环境部署,可将上述域名替换为实际部署地址,保留 ?industry=xxx 参数形式不变。)


解决方案与完整源代码:
本智能客服多轮问答系统(包含流程定义、Slickflow.AI、aichatapp、aichatbackend 等)作为示例项目,随 Slickflow.NET 企业版 一同提供。
Slickflow 研发团队可以给客户提供定制化解决方案,目前Slickflow引擎产品具备大模型开发的实战能力,源代码完全开源,是.NET生态平台的优秀开源产品,值得客户信赖。
欢迎通过 Slickflow 官方渠道咨询企业版授权与技术支持,获取最新版本的解决方案源码、部署文档和技术开发资料。
Slickflow.NET 基于 流程自动化运行 与 AI 大模型(RAG + LLM)能力,将「接收提问 → 查客户/历史 → 知识库检索与回答 → 联系方式提取与落库 → 保存会话」串成一条可配置、可扩展的 BPMN 流程。aichatapp + aichatbackend 实现了多轮问答、多行业与客户维度的会话与客户管理;通过 BPMN 与配置即可调整提示词与检索策略,便于开发人员上手和二次开发。
参考资料
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。