harikavaleti/Call-Center-Intelligence-System
GitHub: harikavaleti/Call-Center-Intelligence-System
基于多 Agent 编排的呼叫中心智能分析系统,自动完成语音转写、PII 脱敏、合规检测和五维度质量评分,将人工质检覆盖率从5%提升到100%。
Stars: 0 | Forks: 0
# 🎯 呼叫中心智能系统
[](https://www.python.org/downloads/)
[](#testing)
[](LICENSE)
## 📋 目录
- [这是什么项目?](#-what-is-this-project)
- [我们正在解决的问题](#-the-problem-were-solving)
- [工作原理](#-how-it-works)
- [系统架构](#-system-architecture)
- [技术栈及选择原因](#-tech-stack--why-each-choice)
- [项目结构](#-project-structure)
- [快速开始](#-quick-start)
- [配置](#-configuration)
- [UI 规范](#-ui-specification)
- [使用指南](#-usage-guide)
- [测试](#-testing)
- [Docker 部署](#-docker-deployment)
- [GPU 部署](#-gpu-deployment)
- [关键设计决策](#-key-design-decisions)
- [数据模型](#-data-models)
- [安全特性](#-security-features)
- [QA 评分系统](#-qa-scoring-system)
- [可观测性](#-observability)
- [故障排除](#-troubleshooting)
- [未来扩展](#-future-expansion)
- [API 参考](#-api-reference)
## 🎯 这是什么项目?
这是一个**生产级 Web 应用程序**,它接收原始的呼叫中心录音并自动生成:
| 输出 | 描述 |
|--------|-------------|
| 🎙️ **带说话人标签的录音文本** | 坐席 vs. 客户,包含 `[MM:SS]` 时间戳和置信度标记 |
| 📝 **执行摘要** | 通话目的、关键讨论点、行动项、情绪轨迹 |
| 📊 **质量记分卡** | 5 维度加权评分(每项 1-5 分)及评分理由 |
| 🚨 **合规报告** | 带有严重程度级别的违规标记(低 → 严重) |
| 📄 **可下载报告** | 每次分析的通话均可生成 PDF 和 JSON 产物 |
| 📈 **可观测性仪表盘** | Pipeline 健康指标、审计日志、LangSmith 追踪状态 |
把它想象成替代那些人工听取录音并填写记分卡的 QA 审核员——但它能处理 **100% 的通话**而不是 5%,在几分钟内完成**而不是每通电话需要 15 分钟**,并提供**确定且可审计的评分**。
## 🔥 我们正在解决的问题
一个中型呼叫中心每天处理约 5,000 通电话。QA 团队人工审核的通话不到 5%,每次审核大约花费 15 分钟。这造成了三个系统性故障:
| 故障 | 影响 | 我们的解决方案 |
|---------|--------|-------------|
| **覆盖盲区** — 95% 的通话未被审核 | 坐席错误和指导机会未被发现 | 自动分析每一通电话 |
| **一致性差距** — 人工审核员的一致性仅为 40-60% | 不公平的评分,无法经受监管审查 | 确定性加权公式(可复现,可审计) |
| **延迟差距** — 审核在几天后才暴露问题 | 进行指导、纠正或防止损害为时已晚 | 数分钟内实时分析 |
### 解决的其他痛点
- **人工 QA 无法扩展** — 自动化系统只需几分钟即可完成,且成本仅为一小部分
- **通用 LLM 会产生幻觉** — 我们的系统将所有分析立足于实际的录音文本证据
- **单体系统容易崩溃** — 7 个边界清晰的专业 Agent 更可靠且易于测试
- **没有审计跟踪** — 每个 Pipeline 事件都带有时间戳记录到只追加的审计表中
- **没有成本控制** — 多 Provider 工厂模式允许您通过一个环境变量从 $0.03/通话 切换到 $0/通话
## ⚙️ 工作原理
当您上传音频文件并点击 "Analyze Call" 时,系统会运行由 LangGraph 状态机编排的 **7 个顺序 Pipeline 阶段**:
```
┌─────────────────────────────────────────────────────────────────────┐
│ USER UPLOADS AUDIO │
└──────────────────────────────┬──────────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────────────────┐
│ STAGE 1: INTAKE VALIDATION │
│ • Detect format by magic bytes (first 12 bytes, not file extension)│
│ • Reject if >50MB or >60 minutes │
│ • Extract audio properties (duration, sample rate, channels) │
│ • Scan metadata (caller_id, department) for PII │
│ • Write validated audio to temp file │
├──────────────────────────────┬───────────────────────────────────────┤
│ ✅ Valid │ ❌ Invalid → ERROR NODE │
└──────────────────────────────┼───────────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────────────────┐
│ STAGE 2: TRANSCRIPTION (faster-whisper) │
│ • Check SHA-256 cache → return instantly if seen before │
│ • Whisper model loaded once as singleton (never per-request) │
│ • Greedy decoding (beam_size=1), VAD filtering, no prev text cond │
│ • Heuristic speaker diarization (Agent/Customer) │
│ • Clean artifacts: BLANK_AUDIO, repeated phrases, YouTube footers │
│ • Compute per-segment confidence from avg_logprob + no_speech_prob │
│ • Cache result by SHA-256 hash for future lookups │
└──────────────────────────────┬───────────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────────────────┐
│ STAGE 3: PROMPT INJECTION DETECTION │
│ • Scan transcript against 22+ regex patterns │
│ • Covers: ignore-instructions, role-switching, DAN mode, │
│ system-tag injection, jailbreak, conversation injection, etc. │
│ • If detected → route to ERROR NODE (no LLM ever sees the text) │
├──────────────────────────────┬───────────────────────────────────────┤
│ ✅ Clean │ ❌ Injection → ERROR NODE │
└──────────────────────────────┼───────────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────────────────┐
│ STAGE 4: PII REDACTION │
│ • Detect SSN, credit card, email, phone in transcript │
│ • Replace with labeled placeholders: [REDACTED_SSN], etc. │
│ • Right-to-left replacement to preserve string positions │
│ • Applied to BOTH full_text AND every individual segment │
│ • ⚠️ LLM NEVER sees raw PII — this runs BEFORE any LLM call │
└──────────────────────────────┬───────────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────────────────┐
│ STAGE 5: SUMMARIZATION (LLM) │
│ • Extract: call_purpose, key_discussion_points (3-7 items), │
│ action_items (with owner + deadline), resolution_status, │
│ sentiment_trajectory, named entities │
│ • Structured output validated by Pydantic SummaryResult model │
│ • Exponential backoff retry (up to 3 attempts) │
└──────────────────────────────┬───────────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────────────────┐
│ STAGE 6: QA SCORING (LLM) │
│ • Receives transcript + summary context for better accuracy │
│ • Scores 5 weighted dimensions (1-5 each) with justifications │
│ • Identifies compliance flags with severity levels │
│ • ⚠️ overall_score ALWAYS recomputed by weighted formula │
│ (LLM's own overall score is DISCARDED — deterministic guardrail) │
├──────────────────────────────┬───────────────────────────────────────┤
│ No critical flags│ 🚨 Critical flag → SUPERVISOR NODE │
└──────────────────────────────┼───────────────────────────────────────┘
▼
┌──────────────────────────────────────────────────────────────────────┐
│ STAGE 7: REPORT GENERATION │
│ • Compile CallReport from all upstream results │
│ • Generate PDF report (ReportLab) with summary, scores, flags │
│ • Generate JSON report (Pydantic serialization) │
│ • Persist to SQLite (call record, audit log, transcription cache) │
│ • Return downloadable artifacts to the UI │
└──────────────────────────────────────────────────────────────────────┘
```
### 终端节点
- **Error Node**:捕获任何阶段的故障,记录错误,将状态设置为 `"failed"`
- **Supervisor Review Node**:当任何合规性标记的 `severity == "critical"` 时触发,将状态设置为 `"flagged_for_review"`
## 🏗️ 系统架构
### 五层架构
代码库在 `src/` 下组织成五个清晰的层,每层具有单一职责:
```
call-center-intelligence/
│
├── app.py # Thin ~50-line entrypoint
│
├── src/
│ ├── agents/ # 🤖 Pipeline Stage Logic
│ │ ├── intake.py # Audio validation & metadata scanning
│ │ ├── transcription.py # faster-whisper + diarization + SHA-256 cache
│ │ ├── summarization.py # LLM summarization with structured output
│ │ ├── qa_scoring.py # LLM QA scoring + deterministic recomputation
│ │ └── report.py # PDF/JSON generation + database persistence
│ │
│ ├── graph/ # 🔀 LangGraph Orchestration
│ │ ├── state.py # 14 Pydantic models + PipelineState TypedDict
│ │ ├── edges.py # Conditional routing functions
│ │ └── workflow.py # StateGraph definition + node wiring
│ │
│ ├── security/ # 🔒 Security Components
│ │ ├── injection_detector.py # 22+ regex patterns for prompt injection
│ │ ├── pii_redactor.py # SSN, credit card, email, phone redaction
│ │ └── audit.py # Append-only audit event logger
│ │
│ ├── services/ # 🔧 Business Logic Layer
│ │ ├── pipeline.py # Gradio ↔ pipeline bridge + temp file mgmt
│ │ ├── observability.py # Dashboard metrics queries
│ │ └── history.py # Call history browsing
│ │
│ ├── database/ # 💾 Persistence Layer
│ │ ├── models.py # SQLAlchemy ORM (3 tables)
│ │ └── connection.py # Engine, session factory, session_scope
│ │
│ ├── ui/ # 🖥️ Gradio Interface
│ │ ├── theme.py # Custom CSS theme (dark/light mode)
│ │ ├── html_formatters.py # HTML rendering helpers (metric cards, tables, etc.)
│ │ └── tabs/
│ │ ├── analyze.py # "🎙️ Analyze Call" tab
│ │ ├── history.py # "📋 Call History" tab
│ │ └── observability.py # "📊 Observability" tab
│ │
│ └── utils/ # 🛠️ Shared Utilities
│ ├── config.py # Environment variable loader (frozen dataclass)
│ ├── audio.py # Magic-byte detection, validation, properties
│ ├── llm_factory.py # Multi-provider LLM factory
│ └── formatters.py # Markdown formatters for UI display
│
├── tests/ # ✅ 394+ Automated Tests
│ ├── conftest.py # Shared fixtures (db_engine, make_wav_bytes)
│ ├── unit/ # Agent, model, formatter, edge tests
│ ├── integration/ # End-to-end pipeline, database tests
│ ├── security/ # PII format coverage, injection pattern tests
│ └── scenarios/ # 53 tests × 15 real-world pipeline path scenarios
│
├── data/ # 📁 Runtime Data (gitignored)
│ ├── samples/ # Sample audio files for testing
│ └── calls.db # SQLite database (created at runtime)
│
├── Dockerfile # 🐳 Container deployment
├── Makefile # 🔨 Build/test/run targets
├── .env.example # 📋 Environment variable template
├── .gitignore # 🚫 Exclusion rules
├── pyproject.toml # 📦 Project metadata + dependencies
└── requirements.txt # 📦 Pinned dependencies
```
### 数据库 Schema (3 个表)
| 表 | 目的 | 关键列 |
|-------|---------|-------------|
| `call_records` | 主要分析结果 | `call_id` (unique), `status`, `transcript_text`, `summary_json`, `qa_scores_json`, `report_json`, `processed_at` |
| `transcription_cache` | SHA-256 音频哈希 → 缓存的录音文本 | `audio_hash` (unique), `transcription_json`, `created_at` |
| `audit_log` | 只追加的 Pipeline 事件日志 | `call_id`, `action`, `user`, `timestamp`, `details` (JSON) |
## 🛠️ 技术栈及选择原因
| 层 | 技术 | 为什么选择它而不是替代方案 |
|-------|-----------|---------------------------|
| **语言** | Python 3.11+ | AI/ML 生态系统成熟;所有库均支持 |
| **编排** | LangGraph 0.4+ | 具有条件路由、错误隔离和 LangSmith 追踪的类型化状态机——相比之下,普通函数链无法进行分支或隔离故障 |
| **语音转文本** | faster-whisper | 通过 CTranslate2 int8 量化比原版 Whisper 快 2-4 倍。在每天 5,000 通电话的情况下,这是仅需 CPU 部署与需要 GPU 之间的区别 |
| **LLM (付费)** | GPT-4o via langchain-openai | 最佳的结构化输出质量(约 $0.03/通话) |
| **LLM (免费)** | Gemini 2.0 Flash via langchain-google-genai | 每天 1,500 次免费请求;良好的结构化输出支持 |
| **LLM (免费)** | Groq Llama 3.3 70B via langchain-groq | 免费层级 30 RPM;免费层级中最快的推理速度 |
| **音频解析** | mutagen | 可靠的 MP3/FLAC/M4A 元数据提取 |
| **数据模型** | Pydantic v2 | 阶段之间有 14 个类型化契约;结构化 LLM 输出验证可捕获格式错误的 AI 响应 |
| **数据库** | SQLite + SQLAlchemy | 单文件持久化,零设置,通过 cached sessionmaker 进行连接池管理 |
| **Web UI** | Gradio 5.x | 具有音频上传、Markdown 渲染、文件下载的多标签界面 |
| **PDF 报告** | ReportLab | 程序化 PDF 生成,无外部依赖 |
| **可观测性** | LangSmith (可选) | 记录每个 LLM 调用的完整追踪,包含 token 计数和延迟 |
| **测试** | pytest | 跨单元/集成/安全套件的 335+ 项测试,带有 fixtures 和 parametrize |
| **Linting** | ruff | 快速的 Python 代码检查和自动格式化 |
## 🚀 快速开始
### 前置条件
- **Python 3.11+**(也支持 Python 3.12;3.13 尚未被所有音频依赖项支持)
- **ffmpeg** 已安装在您的系统上(用于音频处理)
- macOS: `brew install ffmpeg`
- Ubuntu: `sudo apt-get install ffmpeg`
- Windows: 从 https://ffmpeg.org/download.html 下载
- **至少一个 LLM API 密钥**(参见[配置](#-configuration))
### 选项 1: 快速设置
```
# 克隆仓库
git clone
cd call-center-intelligence
# 创建虚拟环境
python3 -m venv venv
source venv/bin/activate # macOS/Linux
# venv\Scripts\activate # Windows
# 安装依赖
pip install -r requirements.txt
# 配置环境
cp .env.example .env
# 使用你的 API key(s) 编辑 .env —— 见下方的配置部分
# 运行应用
python app.py
# 在 http://localhost:7860 打开
```
### 选项 2: 使用 Make
```
make install # Creates venv + installs everything
cp .env.example .env
# 使用你的 API key(s) 编辑 .env
make run # Starts the app
```
### 选项 3: 使用 Docker
```
docker build -t call-center-intelligence .
docker run -p 7860:7860 --env-file .env call-center-intelligence
# 在 http://localhost:7860 打开
```
## ⚙️ 配置
### 环境变量
将 `.env.example` 复制到 `.env` 并进行配置:
```
cp .env.example .env
```
#### 必填项: LLM Provider (选择其一)
| 变量 | 描述 | 如何获取 |
|----------|-------------|-----------|
| `LLM_PROVIDER` | 要使用的 Provider:`openai`、`gemini` 或 `groq` | 根据您拥有的密钥进行设置 |
| `OPENAI_API_KEY` | OpenAI API 密钥(约 $0.03/通话) | https://platform.openai.com/api-keys |
| `GOOGLE_API_KEY` | Gemini API 密钥(免费:1,500 次/天) | https://aistudio.google.com |
| `GROQ_API_KEY` | Groq API 密钥(免费:30 RPM) | https://console.groq.com |
#### 可选项: Whisper 配置
| 变量 | 默认值 | 描述 |
|----------|---------|-------------|
| `WHISPER_MODEL_SIZE` | `tiny` | 模型大小:`tiny` (39MB,快速), `base` (74MB), `small`, `medium`, `large-v3` (1.5GB,需要 GPU) |
| `CONFIDENCE_THRESHOLD` | `0.6` | 低于此置信度的片段将被标记为 `[LOW CONF]` |
| `LOW_CONFIDENCE_HALT_RATIO` | `0.5` | 如果超过 50% 的片段置信度较低,则标记整通电话 |
#### 可选项: Pipeline & 数据库
| 变量 | 默认值 | 描述 |
|----------|---------|-------------|
| `DB_PATH` | `data/calls.db` | SQLite 数据库文件路径 |
| `DB_ENCRYPTION_KEY` | _(空)_ | 可选的 SQLite 加密密钥 |
| `MAX_RETRIES_PER_NODE` | `3` | 每次 LLM 调用的最大重试次数(带有指数退避) |
| `LLM_TIMEOUT_SECONDS` | `60` | 每次 LLM API 调用的超时时间(如果发生超时,请增加到 120) |
#### 可选项: LangSmith 可观测性
| 变量 | 默认值 | 描述 |
|----------|---------|-------------|
| `LANGCHAIN_TRACING_V2` | `false` | 启用 LangSmith 追踪 (`true`/`false`) |
| `LANGCHAIN_API_KEY` | _(空)_ | 来自 https://smith.langchain.com 的 LangSmith API 密钥 |
| `LANGCHAIN_PROJECT` | `call-center-intelligence` | LangSmith 项目名称 |
### 切换 LLM Provider
在 `.env` 中更改一行——零代码修改:
```
# 使用 OpenAI GPT-4o (~$0.03/调用, 最佳质量)
LLM_PROVIDER=openai
# 使用 Gemini 2.0 Flash (免费, 1,500 次请求/天)
LLM_PROVIDER=gemini
# 使用 Groq Llama 3.3 70B (免费, 30 RPM, 最快推理)
LLM_PROVIDER=groq
```
## 🖥️ UI 规范
应用程序提供了一个带有深色/浅色主题切换的**三标签 Gradio 界面**。每个标签服务于不同的用户工作流。以下是每个 UI 元素、其功能及使用方法的详细规范。
### 应用程序标题
| 元素 | 描述 |
|---------|-------------|
| **🎯 Call Center Intelligence System** | 应用程序标题 |
| **AI-powered call quality analysis** | 副标题 |
| **🌙 / ☀️ 切换** | 点击以在深色模式和浅色模式之间切换 |
### 标签 1: 🎙️ Analyze Call
**目的**:上传或录制通话录音并运行完整的 AI 分析 Pipeline。
#### 左侧面板 — 输入控件
| 元素 | 类型 | 描述 | 必填 |
|---------|------|-------------|----------|
| **Upload Audio** | 文件上传 / 麦克风 | 接受最大 50MB、60 分钟的 WAV、MP3、FLAC、M4A 文件。也支持实时麦克风录音。 | ✅ 是 |
| **Caller ID** | 文本输入 | 呼叫者的可选标识符(例如,`CUST-48291`)。用于跟踪。⚠️ 请勿输入真实的 SSN 或信用卡——PII 扫描会将其标记出来。 | ❌ 可选 |
| **Department** | 文本输入 | 可选的部门名称(例如,`Billing Support`)。与通话记录一起存储以用于过滤。 | ❌ 可选 |
| **🔍 Analyze Call** | 按钮 (主要) | 启动 7 阶段分析 Pipeline。处理期间禁用。 | — |
| **Pipeline Progress** | 状态面板 | 显示所有 7 个阶段的实时进度,带有绿/黄/灰点及每个阶段的耗时。 | — |
#### 右侧面板 — 分析结果 (5 个子标签)
点击 "Analyze Call" 后,结果将显示在这些子标签中:
##### 📝 Transcript 子标签
| 元素 | 描述 |
|---------|-------------|
| **聊天气泡** | 带有说话人标签的对话,包含坐席(绿色)和客户(琥珀色)气泡 |
| **时间戳** | 个气泡上的 `[MM:SS]` 时间戳 |
| **置信度标记** | 置信度低于阈值的片段上的 `[LOW CONF]` 徽章 |
| **PII 徽章** | `[REDACTED_SSN]`、`[REDACTED_CREDIT_CARD]` 等显示为高亮徽章 |
| **录音文本统计** | 总片段数、平均置信度、检测到的语言 |
##### 📋 Summary 子标签
| 元素 | 描述 |
|---------|-------------|
| **Call Purpose** | 客户致电原因的一句话描述 |
| **Key Discussion Points** | 涵盖主要主题的 3-7 个要点 |
| **Action Items** | 包含描述、负责人 (坐席/客户) 和截止日期的表格 |
| **Resolution Status** | 药丸形徽章:`Resolved` (绿色), `Unresolved` (红色), 或 `Escalated` (琥珀色) |
| **Sentiment Trajectory** | 显示情绪轨迹的箭头表示法(例如,"Frustrated → Satisfied") |
| **Named Entities** | 提及的公司、产品、人物及其上下文 |
##### 📊 QA Scorecard 子标签
| 元素 | 描述 |
|---------|-------------|
| **Overall Score** | 大号数字(例如,`3.8 / 5.0`),由确定性加权公式计算得出 |
| **Formula badge** | 显示 "weighted formula" 以表明分数是确定性的,而不是 LLM 生成的 |
| **Dimension bars** | 5 个带有分数的水平进度条: |
| | • **Problem Resolution (30%)** — 问题是否得到解决? |
| | • **Empathy (20%)** — 坐席是否表现出理解? |
| | • **Compliance (20%)** — 是否遵守了程序? |
| | • **Professionalism (15%)** — 坐席是否礼貌? |
| | • **Communication Clarity (15%)** — 坐席表达是否清晰? |
| **Color coding** | 每个维度条的颜色:绿色 (4-5),琥珀色 (3),红色 (1-2) |
| **Justifications** | 每个维度分数的文本解释 |
##### 🛡️ Compliance 子标签
| 元素 | 描述 |
|---------|-------------|
| **Compliance flags** | 带有严重程度颜色边框的卡片: |
| | • 🔴 **CRITICAL** — 红色边框(例如,"Skipped identity verification") |
| | • 🟠 **HIGH** — 橙色边框(例如,"Didn't confirm refund amount") |
| | • 🟡 **MEDIUM** — 琥珀色边框 |
| | • ⚪ **LOW** — 灰色边框 |
| **Timestamp references** | 每个标记包含发生违规的 `[MM:SS]` 范围 |
| **No flags message** | 当通话没有问题时显示 "No compliance issues detected" |
##### ⬇️ Download 子标签
| 元素 | 描述 |
|---------|-------------|
| **📄 PDF Report** | 可下载的 PDF,包含完整分析(摘要、分数、标记、录音文本摘录) |
| **📋 JSON Report** | 可下载的 JSON,包含所有结构化数据以便于编程访问 |
### 标签 2: 📋 Call History
**目的**:浏览、搜索和查看所有以前分析过的通话。
#### 顶部控件
| 元素 | 类型 | 描述 |
|---------|------|-------------|
| **Search** | 文本输入 | 按通话 ID、文件名或部门搜索。实时过滤列表。 |
| **Outcome** | 下拉菜单 | 过滤依据:`All outcomes`、`Completed`、`Failed`、`Flagged for review` |
#### 左侧面板 — 通话列表
| 元素 | 描述 |
|---------|-------------|
| **Source icon** | 📁 = 上传的文件, 🎤 = 通过麦克风录制 |
| **Call ID** | 唯一标识符(显示前 20 个字符) |
| **Filename & timestamp** | 原始文件名和处理日期 |
| **Status pill** | 颜色编码:`Report generated` (绿色), `Error` (红色), `Supervisor review` (琥珀色) |
| **QA Score** | 满分 5 分的得分(例如,`3.1/5`),如果分析失败则为 `N/A` |
| **Pagination** | `← Prev` / `Next →` 按钮带有页码和总计数 |
| **🔄 Refresh List** | 重新加载通话列表(切换到此标签时自动刷新) |
#### 右侧面板 — 通话详情
| 元素 | 描述 |
|---------|-------------|
| **Select Call ID** | 从当前列表中选择通话的下拉菜单 |
| **Header** | 通话 ID + 状态药丸 + 文件名 + 处理时间戳 |
| **Transcript Preview** | 录音文本的前约 300 个字符(等宽字体,可滚动) |
| **QA Scorecard** | 与 Analyze 标签相同的 5 维度条形图,带有总分 |
| **Compliance Flags** | 严重程度颜色编码的标记卡片(格式与 Analyze 标签相同) |
### 标签 3: 📊 Observability
**目的**:监控 Pipeline 健康状况,查看聚合分析,并查看审计日志。
#### 指标卡片 (顶行 — 4 张卡片)
| 卡片 | 描述 | 示例 |
|------|-------------|---------|
| **Total Calls Processed** | 曾分析过的所有通话计数 | `8` |
| **Success Rate** | 成功完成的通话百分比 | `75.0%` |
| **Avg QA Score** | 已完成通话的平均总体 QA 分数 | `2.62` |
| **Compliance Flags** | 所有通话中的合规性标记总数 | `5` |
#### 通话分析表
| 列 | 描述 |
|--------|-------------|
| **Call ID** | 唯一标识符 |
| **Timestamp** | 通话处理的时间 |
| **Source** | 📁 上传或 🎤 麦克风 |
| **Status** | Completed / Failed / Flagged |
| **QA Score** | 总体加权分数 |
| **Compliance** | 标记数量或 "Clean" |
#### 左侧面板 — Pipeline 健康状况
| 组件 | 状态 | 描述 |
|-----------|--------|-------------|
| **LangGraph pipeline** | 🟢 Active | 工作流引擎状态 |
| **faster-whisper** | 🟢 Active | 语音转文本模型已加载 |
| **LLM Provider** | 🟢 Active · openai/gemini/groq | 配置了哪个 LLM |
| **SQLite database** | 🟢 Active · N records | 数据库连接 + 记录数 |
| **LangSmith tracing** | 🟢 Enabled / 🔴 Disabled | 是否开启了可观测性追踪 |
| **SHA-256 cache** | 🟢 Active | 录音文本缓存状态 |
#### 左侧面板 — 阶段延迟
| 阶段 | 描述 | 典型耗时 |
|-------|-------------|-------------|
| **Intake & validation** | 音频格式检查、大小检查、PII 扫描 | ~0.3s |
| **Transcription** | Whisper 语音转文本 | ~14s (CPU tiny 模型) |
| **Injection detection** | 正则表达式模式扫描 | ~0.1s |
| **PII redaction** | SSN/信用卡/电子邮件/电话替换 | ~0.2s |
| **Summarization** | 用于摘要的 LLM 调用 | ~3.1s |
| **QA scoring** | 用于评分的 LLM 调用 | ~3.8s |
| **Report generation** | PDF/JSON + 数据库持久化 | ~0.8s |
#### 右侧面板 — 审计日志
| 元素 | 描述 |
|---------|-------------|
| **20 most recent events** | Pipeline 事件的可滚动列表 |
| **Color-coded entries** | 🟢 绿色边框 = 已完成,🔴 红色边框 = 失败/注入,🟡 琥珀色边框 = 已标记 |
| **Timestamp** | 事件发生的时间 |
| **Description** | 发生了什么(例如,"Pipeline completed", "Injection detected") |
#### 控件
| 元素 | 描述 |
|---------|-------------|
| **🔄 Refresh Dashboard** | 重新加载所有指标、分析表、健康状态、延迟和审计日志 |
### 主题和样式
UI 使用具有以下功能的自定义 CSS 主题:
| 特性 | 描述 |
|---------|-------------|
| **Dark mode** (默认) | 深色背景 (`#0f1419`),浅色文本,蓝色点缀 |
| **Light mode** | 白色背景,深色文本,蓝色点缀 |
| **Responsive** | 指标卡片在移动端从 4 列切换为 2 列 |
| **Status pills** | 绿色 (已完成),红色 (失败),琥珀色 (已标记) |
| **Score colors** | 绿色 (4-5),琥珀色 (3),红色 (1-2) |
| **Chat bubbles** | 绿色 (坐席),琥珀色 (客户) |
## 📖 使用指南
### 分步说明:分析通话
1. 在 `http://localhost:7860` **打开应用程序**
2. 点击 **🎙️ Analyze Call** 标签(默认选中)
3. **上传**音频文件(拖放或点击浏览)——或点击**麦克风图标**进行实时录制
4. 可选择填写 **Caller ID** 和 **Department**
5. 点击 **🔍 Analyze Call**
6. 观察 **Pipeline Progress** 面板——每个阶段完成时会亮起绿灯
7. 完成后(在 CPU 上约 1-2 分钟),结果将显示在 5 个子标签中:
- 在 **Transcript**、**Summary**、**QA Scorecard**、**Compliance** 和 **Download** 之间切换
8. 从 ⬇️ Download 子标签下载 **PDF** 或 **JSON** 报告
### 分步说明:查看通话历史
1. 点击 **📋 Call History** 标签
2. 通话列表会自动加载(或点击 **🔄 Refresh List**)
3. 使用 **Search** 按通话 ID、文件名或部门查找特定通话
4. 使用 **Outcome** 下拉菜单按状态进行过滤
5. 从右侧的下拉菜单中选择一个 **Call ID** 以查看完整详情
6. 查看 QA 记分卡、合规性标记和录音文本预览
### 分步说明:监控 Pipeline 健康状况
1. 点击 **📊 Observability** 标签
2. 点击 **🔄 Refresh Dashboard** 以加载当前数据
3. 查看 **4 张指标卡片**以了解高层 KPI
4. 检查 **Call Analytics Table** 以获取每次通话的详细分解
5. 验证 **Pipeline Health** ——所有组件都应显示 🟢 Active
6. 查看 **Stage Latency** 以识别瓶颈
7. 检查 **Audit Log** 以获取最近事件和任何错误
### 示例场景
| 场景 | 会发生什么 |
|----------|-------------|
| 上传有效的 5 分钟 MP3 | 完整分析:录音文本 → 摘要 → QA 分数 → PDF/JSON |
| 客户读出信用卡号 | 该号码在 LLM 看到之前被替换为 `[REDACTED_CREDIT_CARD]` |
| 坐席跳过身份验证 | CRITICAL 合规标记 → 路由至 Supervisor Review |
| 音频包含 "Ignore all previous instructions" | 检测到注入 → Pipeline 阻止 → 返回错误 |
| 上传 .ogg 文件 | 在接收阶段被拒绝并显示 "Unsupported format" 消息 |
| 上传相同音频两次 | 第二次调用立即返回缓存的录音文本(SHA-256 匹配) |
| 上传 60MB 文件 | 在接收阶段被拒绝——超出 50MB 限制 |
| 上传 90 分钟的录音 | 在接收阶段被拒绝——超出 60 分钟限制 |
| 坐席粗鲁,未解决问题 | 低 QA 分数 (< 3.0),每个维度都有详细的理由 |
| 通话被升级至主管 | 摘要显示 `resolution_status: escalated` |
## ✅ 测试
### 运行所有测试 (388+)
```
# 所有测试 — 无需 API keys (均为模拟)
pytest tests/ -v
# 包含覆盖率报告
pytest tests/ -v --cov=src --cov-report=term-missing
```
### 运行特定套件
```
# 单元测试 (agents, models, formatters, edges)
pytest tests/unit/ -v
# 安全测试 (PII 格式覆盖, 注入模式覆盖)
pytest tests/security/ -v
# 集成测试 (端到端 pipeline, 数据库持久化)
pytest tests/integration/ -v
# 场景测试 (happy path 之外的所有 pipeline 路径)
pytest tests/scenarios/ -v
```
### 使用 Make
```
make test # Unit + security tests (fast)
make test-integration # Integration tests
make test-all # Everything
```
### 测试组织
| 套件 | 数量 | 涵盖范围 |
|-------|-------|---------------|
| `tests/unit/` | ~250+ | 所有 Agent (intake、transcription、summarization、QA、report)、Pydantic 模型验证、graph 路由边、显示格式化器 |
| `tests/security/` | ~50+ | 单独测试 22+ 种注入模式、5+ 种电话格式、3+ 种电子邮件格式、2+ 种 SSN 格、3+ 种信用卡格式、嵌入在对话文本中的 PII |
| `tests/integration/` | ~35+ | 带有模拟 LLM/Whisper 的端到端 Pipeline、通话记录和审计日志的数据库持久化 |
| `tests/scenarios/` | 53 | 涵盖每条 Pipeline 路径的 15 个真实场景(见下表) |
### 场景测试覆盖 (53 项测试,15 个场景)
这些测试验证了**超出**正常路径(客户问题得到解决)的每条 Pipeline 路径:
| # | 场景 | 测试数 | 测试的 Pipeline 路径 |
|---|----------|-------|---------------------|
| 1 | 无效音频文件 | 3 | 文本文件 → intake 拒绝 → 路由至 error |
| 2 | 静音/空音频 | 3 | 静音 WAV → 通过 intake → 低置信度标记 |
| 3 | Prompt 注入 | 6 | 恶意文本 → 注入检测器阻止 → error |
| 4 | 元数据中的 PII | 4 | caller_id 中的 SSN/email/CC → intake PII 扫描检测到 |
| 5 | 录音文本中的 PII | 6 | 客户读出 SSN/CC/email/电话 → 全部被编辑 |
| 6 | 未解决的问题 | 3 | 坐席无法解决 → resolution="unresolved" → 较低的分数 |
| 7 | 升级的通话 | 3 | 坐席升级 → resolution="escalated" → PDF/JSON |
| 8 | 严重合规问题 | 4 | 跳过验证 → critical 标记 → supervisor_review |
| 9 | 低 QA 分数 | 3 | 粗鲁的坐席 → 所有维度都低 → 总分 < 3.0 |
| 10 | 超大音频 (>50MB) | 2 | 60MB 文件 → intake 在处理前拒绝 |
| 11 | 音频过长 (>60 分钟) | 2 | 90 分钟录音 → intake 拒绝 |
| 12 | 麦克风录音 | 2 | input_source="microphone" 在 state 中被跟踪 |
| 13 | 重复音频 (缓存) | 3 | 相同文件上传两次 → SHA-256 缓存命中 |
| 14 | 多个合规标记 | 4 | 混合严重级别标记 → 全部保留,critical 优先路由 |
| 15 | 错误传播 | 5 | state 中的错误 → 路由至 error,处理 None 字段 |
**所有测试均无需 API 密钥即可运行** —— LLM 和 Whisper 调用完全使用 `unittest.mock` 进行模拟。
## 🐳 Docker 部署
### 构建并运行
```
# 构建镜像
docker build -t call-center-intelligence .
# 使用环境文件运行
docker run -p 7860:7860 --env-file .env call-center-intelligence
# 使用持久化数据库运行 (推荐)
docker run -p 7860:7860 \
--env-file .env \
-v $(pwd)/data:/app/data \
call-center-intelligence
```
### Docker 详情
- **基础镜像**:`python:3.11-slim`
- **系统依赖**:`ffmpeg` (通过 apt-get 安装)
- **端口**:7860 (Gradio 默认)
- **数据库**:容器内的 `/app/data/calls.db` (挂载卷以持久化)
- **Whisper 模型**:首次运行时下载(`tiny` 约 39MB)
## 🖥️ GPU 部署
系统**自动检测**最佳可用设备:
| 设备 | 计算类型 | 检测方式 |
|--------|-------------|-------------------|
| **NVIDIA GPU (CUDA)** | `float16` | `torch.cuda.is_available() == True` |
| **Apple Silicon (MPS)** | `int8` (CPU 回退) | 检测到 MPS 但 CTranslate2 不支持它 |
| **CPU** | `int8` | 默认回退 |
### Whisper 模型推荐
| 环境 | 模型 | 大小 | 速度 (5 分钟通话) | 准确率 |
|-------------|-------|------|-------------------|----------|
| **开发 (CPU)** | `tiny` | 39 MB | ~1 分钟 | 足够用于测试 |
| **开发 (CPU)** | `base` | 74 MB | ~2 分钟 | 更好的准确率 |
| **生产 (GPU)** | `large-v3` | 1.5 GB | ~10 秒 | 最佳准确率 |
```
# 开发
WHISPER_MODEL_SIZE=tiny
# 使用 GPU 的生产环境
WHISPER_MODEL_SIZE=large-v3
```
### HuggingFace Spaces 部署
1. 创建一个 Gradio SDK Space
2. 将 API 密钥添加为 Space Secrets
3. 为免费 CPU 层设置 `WHISPER_MODEL_SIZE=tiny`
4. 应用程序会自动检测 `SPACE_ID` 并绑定到 `0.0.0.0`
## 🔑 关键设计决策
### 1. LLM 调用前的 PII 编辑
**原因**:GDPR/CCPA 合规性。客户的 SSN、信用卡、电子邮件和电话号码绝不能离开您的安全边界。LLM 仅分析编辑后的文本。
**做法**:正则表达式模式检测 4 种 PII 类型 → 从原始文本中收集匹配项 → 从右到左替换(保留字符串位置) → 应用于 `full_text` 和每个单独的片段。
### 2. 确定性 QA 分数覆盖
**原因**:LLM 是非确定性的。即使 `temperature=0`,相同的输入也可能产生不同的总分。监管审查需要可复现的数字。
**做法**:LLM 对 5 个维度进行评分(每项 1-5 分)。您的代码计算:
```
overall = 0.15×Professionalism + 0.20×Empathy + 0.30×Resolution
+ 0.20×Compliance + 0.15×Clarity
```
LLM 自己的 `overall_score` 会被**直接丢弃**。
### 3. SHA-256 录音文本缓存
**原因**:在每天 5,000 通电话的情况下,重复上传的情况时有发生(主管审核、QA 检查)。如果没有缓存,每次重复上传会花费 1-10 分钟的 CPU 时间。
**做法**:音频字节的 SHA-256 哈希 → 检查 `transcription_cache` 表 → 缓存命中在几毫秒内返回存储的 `TranscriptionResult`。
### 4. Magic-Byte 格式检测
**原因**:永远不要信任文件扩展名。一个 `.wav` 文件可能包含 MP3 数据。重命名为 `.wav` 的文本文件应该被拒绝。
**做法**:读取前 12 个字节:`RIFF...WAVE` → WAV,`ID3` 或 `0xFF+0xE0` → MP3,`fLaC` → FLAC,偏移量 4 处的 `ftyp` → M4A。
### 5. Whisper 模型单例
**原因**:加载 Whisper 模型需要 5-30 秒。按请求加载会使每次通话分析以 30 秒的延迟开始。
**做法**:模块级别的 `_model` 全局变量,在启动时由 `_get_whisper_model()` 加载一次,为所有请求重用。
### 6. Summary → QA 顺序执行 (而非并行)
**原因**:QA 评分接收摘要作为上下文。了解 `resolution_status` 和 `sentiment_trajectory` 有助于更准确地对 Problem Resolution (30% 权重) 和 Empathy (20% 权重) 进行评分。
**权衡**:额外增加一次 LLM 调用的延迟。在占总权重 50% 的部分上获得的准确率提升是值得的。
### 7. LangGraph 与普通函数调用的对比
**原因**:普通的顺序调用无法进行条件路由(错误 → 错误节点,严重标记 → 主管审查)。LangGraph 提供了类型化状态、分支、错误隔离和免费的 LangSmith 追踪。
## 📊 数据模型
14 个类型化的 Pydantic 模型构成了 Pipeline 阶段之间的契约:
| 模型 | 目的 |
|-------|---------|
| `AudioInput` | 原始音频字节、文件名、可选元数据 |
| `AudioProperties` | 时长、采样率、声道 |
| `PIIScanResult` | 是否在元数据字段中发现 PII |
| `IntakeResult` | 验证结果 + 提取的属性 |
| `TranscriptionSegment` | 说话人、文本、时间戳、置信度 (0.0-1.0) |
| `TranscriptionResult` | 所有片段 + 完整文本 + 标记状态 |
| `ResolutionStatus` | 枚举:`resolved` / `unresolved` / `escalated` |
| `ActionItem` | 描述、负责人、可选截止日期 |
| `Entity` | 带有类型和值的命名实体 |
| `SummaryResult` | 通话目的、要点、行动项、情绪、实体 |
| `QADimensionScore` | 维度名称、分数 (1-5)、理由 |
| `ComplianceFlag` | 违规描述、严重程度、时间戳参考 |
| `QAScoreResult` | 5 个维度分数 + 合规标记 + 加权总分 |
| `CallReport` | 由所有上游结果组成的完整汇总报告 |
### PipelineState (TypedDict)
```
class PipelineState(TypedDict, total=False):
audio_input: AudioInput
intake: IntakeResult
transcription: TranscriptionResult
summary: SummaryResult
qa_scores: QAScoreResult
report: CallReport
error: str
status: str
```
每个节点接收完整状态并返回部分更新。LangGraph 会自动合并它。
## 🔒 安全特性
### Prompt 注入检测 (22+ 种模式)
注入检测器在任何 LLM 调用之前扫描录音文本:
| 类别 | 示例模式 |
|----------|-----------------|
| 忽略指令 | "ignore previous instructions", "disregard prior" |
| 角色切换 | "you are now", "act as", "pretend to be" |
| DAN 模式 | "DAN mode", "jailbreak" |
| 系统标签注入 | `<>`, `[INST]`, `` |
| Prompt 泄露 | "show me your system prompt", "what are your instructions" |
| 社会工程 | "as a developer", "in debug mode" |
| 安全覆盖 | "override safety", "ignore safety" |
如果任何模式匹配,Pipeline 会在**任何 LLM 调用之前阻止**并返回匹配的模式名称。
### PII 编辑 (4 种类型)
| PII 类型 | 占位符 | 示例 |
|----------|-------------|---------|
| SSN | `[REDACTED_SSN]` | `123-45-6789` |
| 信用卡 | `[REDACTED_CREDIT_CARD]` | `4111 1111 1111 1111` |
| 电子邮件 | `[REDACTED_EMAIL]` | `john@example.com` |
| 电话 | `[REDACTED_PHONE]` | `(555) 123-4567` |
### 审计日志
每个 Pipeline 事件都记录在只追加的 `audit_log` 表中。记录**永远不会被删除或修改**。
## 📊 QA 评分系统
### 确定性公式
```
overall_score = 0.15 × Professionalism + 0.20 × Empathy + 0.30 × Problem Resolution
+ 0.20 × Compliance + 0.15 × Communication Clarity
```
LLM 自己的 `overall_score` 会被**直接丢弃**并替换为此公式。
## 📈 可观测性
启用 LangSmith 追踪:在 `.env` 中设置 `LANGCHAIN_TRACING_V2=true`。
## 🔧 故障排除
| 问题 | 解决方案 |
|---------|----------|
| 401 API 密钥错误 | 在提供商仪表板验证密钥,检查 `.env` 中是否有多余的空格 |
| 429 速率限制 | 切换提供商或等待配额重置 |
| LLM 超时 | 增加 `LLM_TIMEOUT_SECONDS=120` |
| Docker 崩溃 | 确保传递了 `--env-file .env`,检查 `DB_PATH` 是否可写 |
## 🚀 未来扩展
- 使用 `pyannote-audio` 的**真实说话人分离**
- 使用 Redis/Celery 队列的**批量处理**
- 每个部门的**自定义 QA 评分标准**
- 通过 WebSocket 的**实时流式处理**
- 带有分数趋势的**坐席辅导仪表盘**
- **多语言支持** (Whisper 支持 99 种语言)
- 用于多实例部署的 **PostgreSQL 迁移**
## 📄 许可证
MIT
**用 ❤️ 构建,作为一个展示生产级 AI 工程的毕业设计项目。**
标签:API集成, CISA项目, Faster-Whisper, Gemini, Gradio, LangGraph, MLOps, NLP, OpenAI, PDF报告生成, PII过滤, Prompt注入防御, PyRIT, Python, QA系统, ReportLab, SQLite, STT, 个人信息脱敏, 人工智能, 内存规避, 可观测性, 呼叫中心分析, 多平台LLM支持, 多智能体系统, 多维评分, 大模型安全, 客户服务, 对话智能, 情感分析, 数据合规, 文本摘要, 无后门, 智能体编排, 机器学习运维, 生产级应用, 用户模式Hook绕过, 联络中心系统, 语音识别, 语音转文本, 请求拦截, 质量保证评分, 逆向工具