# 实时通话 ASR 事件监控 一个基于 Spring Boot 和 React 的实时通话事件监控系统。 前端持续提交市民与坐席的 ASR Final 文本,后端按通话维护共享上下文,可选择 AC 关键词匹配或大模型事件匹配,并返回本次新增告警和通话累计结果。 ## 技术栈 | 模块 | 技术 | | --- | --- | | 后端 | Java 21、Spring Boot 4、Spring MVC、Spring Data JPA、Spring AI 2 | | 匹配 | Aho-Corasick 自动机 / OpenAI 兼容大模型 | | 数据库 | H2 文件数据库 | | 前端 | React 19、TypeScript、Vite、Tailwind CSS、Motion | | Excel | ExcelJS | ## 目录结构 ```text . ├── frontend/ # React 前端 ├── src/main/java/com/example/demo/ │ ├── api/ # REST 接口 │ ├── application/ # 监控、规则和会话服务 │ ├── domain/ # 请求、响应和领域模型 │ ├── matcher/ # AC、LLM 匹配器及路由 │ ├── repository/ # 规则版本和会话存储 │ ├── job/ # 过期会话清理 │ └── support/ # 异常、文本标准化等 ├── src/main/resources/ │ ├── application.yml # 服务配置 │ └── rules/default-rules.json # 初始规则 └── pom.xml ``` ## 本地运行 ### 环境要求 - JDK 21 - Node.js 18 或更高版本 - npm ### 1. 启动后端 在项目根目录执行: ```bash ./mvnw spring-boot:run ``` 如需使用“大模型事件匹配”,先设置模型服务的 API Key: ```bash export LLM_API_KEY="your-api-key" ./mvnw spring-boot:run ``` API Key 只从后端环境变量读取,不会进入浏览器、规则数据库或版本历史。模型服务地址、模型名、超时、最大输出 Token 和提示词在前端页面配置。 后端默认地址:`http://localhost:8080` 健康检查: ```text http://localhost:8080/actuator/health ``` ### 2. 启动前端 另开一个终端: ```bash cd frontend npm install npm run dev ``` 访问:`http://localhost:3000` 开发环境下,Vite 会将 `/api` 自动代理到 `http://localhost:8080`。 ## 打包为单个 Spring Boot JAR 先构建前端并复制静态文件: ```bash cd frontend npm install npm run build cd .. cp -R frontend/dist/. src/main/resources/static/ ``` 再打包和启动后端: ```bash ./mvnw clean package java -jar target/demo-0.0.1-SNAPSHOT.jar ``` 访问:`http://localhost:8080` ## ASR 接口 提交一条 ASR Final: ```http POST /api/v1/asr-events Content-Type: application/json ``` ```json { "callId": "call-001", "seq": 1, "speaker": "citizen", "text": "我的顺丰快递一直没有收到", "final": true } ``` `speaker` 只支持: - `citizen`:市民 - `agent`:坐席 同一 `callId` 下,两个角色必须共享一套全局唯一的 `seq`: ```text seq 1 citizen 市民发言 seq 2 agent 坐席发言 seq 3 citizen 市民发言 seq 4 agent 坐席发言 ``` 响应中的主要字段: - `newAlerts`:本次新触发、需要前端提醒的事件 - `currentResults`:该通话当前累计命中的事件 - `duplicate`:是否为重复的 `callId + seq` - `activeRuleVersion`:本次匹配使用的规则版本 通话结束后应主动释放会话: ```http POST /api/v1/calls/{callId}/close ``` ## 算法流程 ```mermaid flowchart TD A["接收 ASR 请求"] --> B{"final=true?"} B -- 否 --> C["返回当前结果,不写入上下文"] B -- 是 --> D{"callId + seq 是否重复?"} D -- 是 --> E["返回 duplicate=true"] D -- 否 --> F["写入该通话的共享上下文窗口"] F --> G{"当前匹配方式"} G -- AC --> H["拼接、标准化并扫描关键词"] G -- LLM --> I["注入规则、已发送事件和带角色上下文"] H --> J["还原业务事件"] I --> J J --> K["后端进行通话级最终去重"] K --> L["返回 newAlerts 和 currentResults"] ``` ### 1. 通话隔离与并发 每个 `callId` 拥有独立会话状态和锁。同一通话按锁串行处理,不同通话可以并行处理。 ### 2. 共享上下文窗口 市民和坐席文本进入同一个、按 `seq` 排序的通话上下文,默认最多保留 200 轮。AC 只扫描最近 5 轮,能够识别被 ASR 切分到相邻 Final 中的关键词;LLM 使用当前保留的完整上下文。 ### 3. 文本标准化 匹配前会进行 Unicode NFKC 标准化、转小写,并移除空白和常见中英文标点。例如: ```text E M S → ems 顺丰,快递 → 顺丰快递 ``` ### 4. AC 自动机匹配 所有已启用关键词被一次性构建为不可变 AC 自动机快照。每条匹配文本只需扫描一次即可发现多个关键词,适合规则和关键词数量持续增加的场景。 ### 5. 告警去重 匹配结果按业务事件聚合。同一个事件在同一次通话中只进入一次 `newAlerts`,重复命中仍保留在累计状态中,但不会重复提醒。 ### 6. 大模型事件匹配 每条规则包含两个标识: - `id`:系统内部 UUID,用于规则管理和版本关联 - `eventId`:简短、稳定的业务事件 ID,例如 `E001` 后端把启用规则压缩为 `事件ID|名称|辅助关键词`,并把本通话已经发送的事件 ID 一并放入提示词。模型只允许输出 JSON 字符串数组,例如 `["E001"]` 或 `[]`,不输出置信度、证据和原因。后端校验短 ID、还原事件名称,并继续执行权威去重。 为提高支持自动 Prompt/KV Cache 的模型服务的缓存命中率,后端会把规则和指令放在稳定前缀中,把每次变化的通话上下文强制追加到提示词最末尾。上下文格式为: ```text 1|citizen|市民发言 2|agent|坐席发言 3|citizen|市民发言 ``` ## 规则管理与版本回溯 规则保存采用完整文档发布,并携带 `baseVersion` 做乐观并发控制。匹配方式和大模型配置与规则一起版本化;事务提交成功后才切换运行时快照。 主要接口: | 方法 | 路径 | 说明 | | --- | --- | --- | | GET | `/api/v1/admin/rules` | 获取当前生效规则 | | PUT | `/api/v1/admin/rules` | 保存并发布新版本 | | GET | `/api/v1/admin/rules/versions?limit=20` | 获取历史版本 | | POST | `/api/v1/admin/rules/versions/{version}/restore` | 回溯历史版本 | 回溯不会修改或删除旧记录。例如当前 V8 回溯到 V3,系统会复制 V3 的内容并创建新的 V9,然后切换 V9 为生效版本。 ## 配置 主要配置位于 `src/main/resources/application.yml`: | 配置 | 默认值 | 说明 | | --- | --- | --- | | `server.port` | `8080` | HTTP 端口 | | `monitor.recent-final-window-size` | `5` | AC 每次扫描的最近 Final 数量 | | `monitor.max-conversation-turns` | `200` | 每通话最多保留的共享上下文轮数 | | `monitor.max-processed-seqs` | `500` | 幂等序列号历史上限 | | `monitor.session-ttl` | `PT2H` | 会话空闲过期时间 | | `monitor.session-cleanup-interval` | `PT10M` | 过期会话清理周期 | | `monitor.llm.api-key` | 环境变量 `LLM_API_KEY` | 大模型服务密钥 | 规则数据库默认保存在项目运行目录的 `data/rules.mv.db`。 ## 扩展性 ### 扩展规则 直接通过前端页面或 Excel 导入新增关键词规则,无需修改匹配代码。发布后自动构建新快照并热切换。 ### 扩展匹配算法 当前支持 `ac-keyword` 和 `llm`。匹配器由统一路由调用,后续可以继续增加正则、高频事件分类、向量检索或组合策略。大模型当前采用同步调用,适合单实例、低流量场景;流量增加后可增加超时降级、隔离线程池、限流、指标和异步结果通道。 ### 扩展事件处理 可以在产生 `newAlerts` 后增加消息队列、WebSocket、工单、短信或外部系统通知。建议通过领域事件异步处理,避免阻塞 ASR 接口。 ### 扩展存储 开发环境使用 H2。生产环境可以迁移到 MySQL 或 PostgreSQL;JPA 领域模型和服务层不需要大幅调整。 ### 扩展为多实例部署 当前通话上下文保存在单机 JVM 内存。多实例部署时需要选择以下方案之一: - 按 `callId` 做一致性路由,保证同一通话始终进入同一实例 - 将会话上下文和幂等状态迁移到 Redis 等共享存储 - 使用分布式事件流按 `callId` 分区处理 ### 安全与治理 生产环境建议增加管理员认证、规则变更审计、接口限流、数据库迁移工具,以及历史版本保留策略。 ## 其他说明 - 关键词模式下,前端对话中的关键词高亮只是本地视觉提示;大模型模式不做本地关键词高亮。 - 真实告警始终以后端 `/api/v1/asr-events` 响应为准。 - 更完整的设计背景见 `asr_event_monitor_confirmed_technical_solution.md`。