WebSocket 智能语义分析服务 - 长期记忆增强版
项目概述
这是一个基于 WebSocket 和 Agent-to-Agent (A2A) 架构的智能语音识别服务,具备说话人识别和长期记忆功能。系统能够在同一场会议中,通过学习每个说话人的发言特征,持续提高说话人识别的准确率。
核心特性
1. 实时语音识别处理
- 接收前端音频流,转发到 ASR 引擎
- 支持双通道模式(2pass)和 PCM 音频格式
- 实时推送识别结果到前端
2. 多 Agent 协作架构
- AuditorAgent: 判断说话人是否完成发言
- ProfilerAgent: 识别说话人身份(支持长期记忆)
3. 长期记忆功能 ⭐
- 为每个说话人建立特征档案
- 持续学习说话人的发言风格和用词习惯
- 利用会议历史上下文提高识别准确率
4. 完善的日志系统 📝
- 自动创建日志目录,分级记录运行信息
- 控制台输出:INFO 级别(运行状态)
- 完整日志文件:DEBUG 级别(详细调试信息)
- 错误日志文件:ERROR 级别(错误和异常)
- 所有日志包含时间戳和上下文信息
日志系统说明
日志文件位置
程序运行时会在项目根目录下创建 logs 文件夹,包含以下日志文件:
logs/
├── a2a_wss.log # 完整日志(DEBUG 级别)
└── a2a_wss_error.log # 错误日志(ERROR 级别)
日志级别说明
| 级别 | 说明 | 使用场景 | 输出位置 |
|---|---|---|---|
| DEBUG | 调试信息 | 详细的程序执行流程、变量值等 | 仅日志文件 |
| INFO | 一般信息 | 关键业务流程、状态变更 | 控制台 + 日志文件 |
| ERROR | 错误信息 | 异常、错误堆栈 | 控制台 + 日志文件 + 错误日志 |
日志内容示例
2025-01-07 14:30:15 - root - INFO - 启动 WebSocket 智能语义分析服务: ws://0.0.0.0:10095
2025-01-07 14:30:15 - root - INFO - Agent 模型: Qwen3-32B
2025-01-07 14:30:15 - root - INFO - ASR 服务地址: ws://localhost:59805/ws/asr
2025-01-07 14:30:15 - root - INFO - Redis 地址: redis://localhost:6379/0
2025-01-07 14:30:20 - root - INFO - 客户端已连接
2025-01-07 14:30:20 - root - INFO - 已连接到 ASR 服务: ws://localhost:59805/ws/asr
2025-01-07 14:30:22 - root - DEBUG - 收到 ASR 识别结果: 各位好,今天我们召开月度工作总结会议...
2025-01-07 14:30:23 - root - INFO - [Auditor] 发言完成检测通过 - 会话ID: room_101
2025-01-07 14:30:23 - root - DEBUG - 获取说话人特征库 - 会话ID: room_101, 说话人数量: 0
2025-01-07 14:30:24 - root - INFO - [Profiler] 识别说话人: 主持人 - 会话ID: room_101
日志配置
日志系统在代码中自动配置(无需手动配置),包含:
- 日志格式:
时间 - 记录器名称 - 级别 - 消息 - 编码:UTF-8(支持中文)
- 自动创建目录:首次运行时自动创建
logs文件夹 - 错误追踪:ERROR 级别日志包含完整的异常堆栈信息
日志查看建议
- 实时监控:
tail -f logs/a2a_wss.log - 查看错误:
cat logs/a2a_wss_error.log - 搜索关键词:
grep "识别说话人" logs/a2a_wss.log - 统计分析:
grep "ERROR" logs/a2a_wss_error.log | wc -l
长期记忆功能详解
功能说明
长期记忆功能使得系统能够在同一场会议中,记住每个说话人的发言特征,并利用这些历史信息来辅助后续的说话人识别。
工作流程
┌─────────────┐
│ 开始会议 │
└──────┬──────┘
│
▼
┌─────────────────────┐
│ 接收语音片段 │
└──────┬──────────────┘
│
▼
┌─────────────────────┐
│ 累积到缓冲区 │
└──────┬──────────────┘
│
▼
┌─────────────────────┐
│ Auditor: 判断发言 │
│ 是否完成 │
└──────┬──────────────┘
│
▼ (发言完成)
┌──────────────────────────────┐
│ 获取长期记忆 │
│ (所有说话人的历史特征) │
└──────┬───────────────────────┘
│
▼
┌──────────────────────────────┐
│ Profiler: 识别说话人 │
│ - 分析会议历史记录 │
│ - 对比说话人特征库 │
│ - 判断对话流程和上下文 │
└──────┬───────────────────────┘
│
▼
┌──────────────────────────────┐
│ 更新长期记忆 │
│ (保存当前发言到特征库) │
└──────┬───────────────────────┘
│
▼
┌─────────────────────┐
│ 推送结果到前端 │
└─────────────────────┘
核心改进
1. Redis 存储扩展
新增方法:
-
save_speaker_profile(sid, speaker, text, features): 保存说话人特征到长期记忆- 保留每个说话人最近 10 条发言记录
- 存储发言文本片段(前 200 字符)
- 记录时间戳和可选的特征向量
-
get_speaker_profiles(sid): 获取所有说话人的历史特征- 返回字典格式:
{说话人: [历史记录列表]} - 用于 Agent 分析时参考
- 返回字典格式:
2. ProfilerAgent 增强
改进的识别逻辑:
- 历史记录分析:查看最近 15 条对话,理解会议上下文
- 对话流程分析:判断当前发言是对之前谁的话题的回应
- 说话风格匹配:对比每个角色的用词习惯、句式结构、语气
- 角色职责判断:根据发言内容是否符合角色职责范围
- 话题连贯性:当前发言与该角色历史话题的连贯性
提示词优化:
# 增强版系统提示词包含4个分析维度:
1. 对话流程分析
2. 说话风格匹配
3. 角色职责判断
4. 话题连贯性
3. A2AOrchestrator 集成
在 process_asr_fragment() 方法中集成长期记忆:
# 1. 获取长期记忆(说话人特征库)
speaker_profiles = await self.redis.get_speaker_profiles(session_id)
# 2. 使用长期记忆识别说话人
speaker = await self.profiler.identify(buf, history, speaker_profiles)
# 3. 保存到长期记忆(持续学习)
await self.redis.save_speaker_profile(session_id, speaker, buf)
配置说明
环境变量
| 变量名 | 说明 | 默认值 |
|---|---|---|
TARGET_WS_URL |
ASR 服务的 WebSocket 地址 | ws://localhost:59805/ws/asr |
REDIS_URL |
Redis 连接地址 | redis://localhost:6379/0 |
LLM_API_KEY |
大语言模型 API Key | sk-xxxx |
LLM_BASE_URL |
大语言模型服务地址 | http://172.18.127.124:9997/v1 |
LLM_MODEL |
使用的模型名称 | Qwen3-32B |
候选说话人列表
在代码中配置(CANDIDATE_SPEAKERS):
CANDIDATE_SPEAKERS = [
"局长",
"主持人",
"商务专员",
"市场专员",
"控制要素席",
"空中侦察席"
]
Redis 数据结构
键命名规范
meeting:buffer:{session_id} # 会话文本缓冲
meeting:history:{session_id} # 会话历史记录
meeting:speaker_profile:{session_id}:{speaker} # 说话人特征库
数据类型
- 缓冲区: String (累积的未完成发言)
- 历史记录: List (最多 20 条)
- 说话人特征: List (每个说话人最多 10 条)
使用示例
安装依赖
首先确保已安装 Python 3.8+,然后安装所需依赖:
# 在项目根目录下执行
pip install -r requirements.txt
启动服务
# 在 src 目录下执行
python a2a_wss.py
服务将监听 ws://0.0.0.0:10095
连接和消息格式
前端发送配置:
{
"mode": "2pass",
"chunk_size": [10, 10, 10],
"wav_format": "pcm"
}
前端发送音频: 二进制 PCM 数据
后端返回结果:
{
"mode": "offline-speaker",
"type": "asr_with_speaker",
"segments": [{
"id": 0,
"speaker": "局长",
"embedding": null,
"seek": 0,
"full_text": "今天我们讨论一下市场推广方案"
}],
"speaker": "局长"
}
长期记忆的工作示例
会议初期(无记忆)
历史记录: [暂无]
说话人特征库: [暂无]
当前发言: "各位好,今天我们召开月度工作总结会议"
识别结果: 主持人 (基于内容特征)
会议中期(有部分记忆)
历史记录:
[1] 主持人: 各位好,今天我们召开月度工作总结会议
[2] 局长: 本月工作总体进展顺利
[3] 商务专员: 我们完成了三个重要合同的签署
[4] 市场专员: 市场推广活动覆盖了五个新城市
说话人特征库:
- 【主持人】(发言1次): 各位好,今天我们召开月度工作总结会议
- 【局长】(发言1次): 本月工作总体进展顺利
- 【商务专员】(发言1次): 我们完成了三个重要合同的签署
- 【市场专员】(发言1次): 市场推广活动覆盖了五个新城市
当前发言: "关于下个月的计划,我们需要重点关注客户反馈"
识别结果: 市场专员
分析:
- 延续了市场专员之前的话题(市场推广)
- 符合市场专员的职责范围(客户反馈)
- 用词风格与历史记录匹配
会议后期(丰富记忆)
历史记录: [15条完整对话记录]
说话人特征库:
- 【局长】(发言4次): 本月工作总体进展顺利; 很好,各部门配合默契;
这次会议很有成效; 最后强调一下安全问题
- 【主持人】(发言3次): 各位好,今天我们召开月度工作总结会议;
下面请商务专员汇报; 时间关系,今天的会议就到这里
- 【商务专员】(发言5次): 我们完成了三个重要合同的签署;
这三个合同总金额达500万; 客户对我们的方案很满意;
下季度重点跟进大客户; 需要技术部门的支持
...
当前发言: "技术部门会全力支持商务工作,确保项目交付质量"
识别结果: (未出现在候选列表中,或需要进一步判断)
分析:
- 提到了"技术部门",可能是技术相关角色
- 对之前商务专员的话题做出回应
- 风式偏向技术人员的特点(强调"质量"、"交付")
性能优化
1. 数据限制
- 历史记录:最多保留 20 条
- 每个说话人特征:最多保留 10 条
- LLM 上下文:使用最近 15 条历史记录
2. 异步处理
- Agent 处理使用后台任务,不阻塞主循环
- 连接关闭时等待任务完成(最多 5 秒)
3. Redis 连接池
- 使用连接池提高并发性能
- 自动编码/解码 JSON 数据
技术栈
- Python 3.8+
- websockets: WebSocket 通信
- redis: 会话状态和长期记忆存储
- openai: 大语言模型调用
- logging: 日志记录和系统监控
- asyncio: 异步编程
代码结构
a2a_wss.py
├── 基础配置 (1-48行)
├── RedisManager 类 (52-199行)
│ ├── 会话缓冲管理
│ ├── 历史记录管理
│ └── 说话人特征库管理 ⭐新增
├── Agent 基类 (154-208行)
├── AuditorAgent 类 (211-235行)
├── ProfilerAgent 类 (238-369行) ⭐增强
│ ├── 长期记忆提示词
│ ├── 会议历史分析
│ └── 说话人特征匹配
├── A2AOrchestrator 类 (372-343行) ⭐集成
│ └── process_asr_fragment() 方法
└── WebSocket 处理 (352-450行)
注意事项
- Redis 依赖: 确保 Redis 服务正常运行
- LLM 可用性: 确保大语言模型服务可访问
- 内存管理: 长时间运行的会议会累积数据,建议定期清理
- 识别准确率: 长期记忆随时间累积,会议初期识别准确率可能较低
未来改进方向
- 跨会议记忆: 支持多场会议之间的说话人特征迁移
- 特征工程: 提取更多说话人特征(语速、停顿模式等)
- 置信度评分: 为每次识别添加置信度分数
- 自适应学习: 根据识别准确率动态调整特征权重
- 多模态融合: 结合声学特征提高识别准确率
作者和许可
本项目为智能语音识别系统的核心组件,采用 Agent-to-Agent 编排模式。
最后更新: 2025-01-07