Files
live-call-asr-monitor/README.md

275 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 实时通话 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 或 PostgreSQLJPA 领域模型和服务层不需要大幅调整。
### 扩展为多实例部署
当前通话上下文保存在单机 JVM 内存。多实例部署时需要选择以下方案之一:
-`callId` 做一致性路由,保证同一通话始终进入同一实例
- 将会话上下文和幂等状态迁移到 Redis 等共享存储
- 使用分布式事件流按 `callId` 分区处理
### 安全与治理
生产环境建议增加管理员认证、规则变更审计、接口限流、数据库迁移工具,以及历史版本保留策略。
## 其他说明
- 关键词模式下,前端对话中的关键词高亮只是本地视觉提示;大模型模式不做本地关键词高亮。
- 真实告警始终以后端 `/api/v1/asr-events` 响应为准。
- 更完整的设计背景见 `asr_event_monitor_confirmed_technical_solution.md`