# LiveKit Voice AI Agent - 系统架构

## 松耦合架构设计

```
┌─────────────────────────────────────────────────────────────────────────┐
│                         LiveKit Voice AI Agent                          │
│                         (agent.py / run_worker.py)                      │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
        ┌───────────────────────────┼───────────────────────────┐
        ▼                           ▼                           ▼
┌───────────────┐         ┌─────────────────┐         ┌──────────────────┐
│   STT Module  │         │   LLM Interface │         │    TTS Module    │
│  (FunASR)     │         │   (Agnes AI)    │         │   (EdgeTTS)      │
└───────┬───────┘         └────────┬────────┘         └────────┬─────────┘
        │                          │                           │
        │                          │                           │
        ▼                          ▼                           ▼
┌─────────────────────────────────────────────────────────────────────────┐
│                        Message Bus (Events)                             │
│  dialogue_event | memory_event | vision_event | user_action            │
└─────────────────────────────────────────────────────────────────────────┘
                                    │
        ┌───────────────────────────┼───────────────────────────┐
        ▼                           ▼                           ▼
┌───────────────┐         ┌─────────────────┐         ┌──────────────────┐
│  Memory Store │         │  Vector Embed   │         │  Knowledge Wiki  │
│(ProfileMgr)   │         │ (WeMM Client)   │         │   (LLM Wiki)     │
│   SQLite      │         │   HTTP API      │         │   RAG Retrieval  │
└───────────────┘         └─────────────────┘         └──────────────────┘
```

---

## 核心组件职责

### 1. Agent (agent.py)
- **职责**：实时语音对话主循环
- **依赖**：STT → LLM → TTS
- **输出**：dialogue_event（对话事件）
- **接口**：通过 Event Bus 发布事件

```python
# Agent 核心流程
async def process_audio(self, audio_frame):
    # 1. STT 转录
    text = await self.stt.transcribe(audio_frame)
    
    # 2. 发布对话事件
    self.event_bus.publish("dialogue_event", {
        "type": "user_speech",
        "text": text,
        "timestamp": time.time()
    })
    
    # 3. LLM 处理
    context = await self.get_memory_context()  # 从 Memory Store 获取
    response = await self.llm.generate(text, context)
    
    # 4. TTS 合成
    await self.tts.speak(response)
    
    # 5. 发布事件
    self.event_bus.publish("dialogue_event", {
        "type": "assistant_speech",
        "text": response,
        "timestamp": time.time()
    })
```

---

### 2. Memory Store (profile_manager.py)
- **职责**：持久化人物记忆，提供查询接口
- **依赖**：无外部依赖（SQLite 本地存储）
- **输入**：通过 Event Bus 接收事件
- **输出**：get_context() 返回人物画像

```python
# Memory Store 接入 Event Bus
class MemoryStoreHandler:
    def __init__(self, profile_mgr: ProfileManager):
        self.pm = profile_mgr
    
    async def on_dialogue_event(self, event):
        """处理对话事件，自动提取事实"""
        text = event["text"]
        speaker_id = event.get("speaker_id", "unknown")
        
        # 1. 提取事实
        facts = self.pm.extract_facts_from_dialogue(text, speaker_id)
        
        # 2. 写入记忆
        for fact in facts:
            self.pm.add_fact(
                subject_id=speaker_id,
                predicate=fact["predicate"],
                object=fact["object"],
                topic=fact.get("topic", "other"),
                who=speaker_id,
                what=f"对话中提取: {fact['predicate']}",
                time_desc=event.get("time_desc"),
                trigger_method="对话自动提取"
            )
        
        # 3. 检测矛盾
        conflicts = self.pm.detect_conflicts(speaker_id)
        if conflicts:
            self.event_bus.publish("conflict_warning", {
                "identity": speaker_id,
                "conflicts": conflicts
            })
```

---

### 3. WeMM Client (vision_fusion.py)
- **职责**：生成文本/图像向量，用于语义检索
- **依赖**：WeMM API（远程 GPU 服务或本地占位服务）
- **输入**：文本或图像字节
- **输出**：向量列表

```python
# 向量生成接口
class VectorEmbedService:
    def __init__(self, config: dict):
        self.api_url = config.get("vision.wemm_api_url", "http://localhost:8765")
        self.dimension = config.get("vision.dimension", 768)
        self.client = WeMMClient(self.api_url, self.dimension)
    
    async def embed_text(self, text: str) -> List[float]:
        """文本向量化"""
        return await self.client.encode_text(text)
    
    async def embed_image(self, image_bytes: bytes) -> List[float]:
        """图像向量化"""
        return await self.client.encode_image(image_bytes)
    
    async def search_similar(self, query_vector, target_vector) -> float:
        """计算余弦相似度"""
        dot = sum(a*b for a,b in zip(query_vector, target_vector))
        norm_q = sum(a*a for a in query_vector) ** 0.5
        norm_t = sum(b*b for b in target_vector) ** 0.5
        return dot / (norm_q * norm_t)
```

---

### 4. Knowledge Wiki (llm_wiki_integration.md)
- **职责**：RAG 检索，提供背景知识
- **依赖**：WeMM Client（获取向量）+ SQLite（存储文档）
- **输入**：用户问题
- **输出**：相关文档片段

```python
# RAG 检索流程
async def retrieve_context(self, query: str, top_k: int = 3) -> str:
    # 1. 向量查询
    query_vec = await self.vector_service.embed_text(query)
    
    # 2. 相似度搜索
    results = await self.wiki_store.search(query_vec, top_k=top_k)
    
    # 3. 拼接上下文
    context = "\n".join([r["content"] for r in results])
    return context
```

---

## 事件总线设计

```python
# event_bus.py - 松耦合的事件总线
import asyncio
from typing import Dict, Callable, List
from dataclasses import dataclass
from datetime import datetime

@dataclass
class EventBusEvent:
    type: str
    data: dict
    timestamp: float
    source: str

class EventBus:
    def __init__(self):
        self._handlers: Dict[str, List[Callable]] = {}
    
    def subscribe(self, event_type: str, handler: Callable):
        if event_type not in self._handlers:
            self._handlers[event_type] = []
        self._handlers[event_type].append(handler)
    
    def publish(self, event_type: str, data: dict, source: str = "unknown"):
        event = EventBusEvent(
            type=event_type,
            data=data,
            timestamp=time.time(),
            source=source
        )
        
        if event_type in self._handlers:
            for handler in self._handlers[event_type]:
                asyncio.create_task(handler(event))
```

---

## 启动流程

```
1. 加载配置 (config.yaml)
   ├── agent.name
   ├── stt.endpoint
   ├── llm.model
   ├── memory.enabled
   └── vision.wemm_api_url

2. 初始化组件
   ├── MemoryStore (SQLite)
   ├── WeMMService (向量生成)
   └── EventBus (消息总线)

3. 注册事件处理器
   ├── EventBus.subscribe("dialogue_event", MemoryStoreHandler)
   └── EventBus.subscribe("vision_event", WeMMClient)

4. 启动 Agent
   └── LiveKit JobContext
```

---

## 配置驱动替换

```yaml
# config.yaml - 通过配置替换组件实现

components:
  stt:
    backend: funasr          # 可选: funasr, whisper, azure
    endpoint: http://localhost:8080
  
  llm:
    backend: agnes           # 可选: agnes, openai, anthropic
    model: agnes-2.5-flash
  
  tts:
    backend: edge_tts        # 可选: edge_tts, azure, elevenlabs
    voice: zh-CN-XiaoxiaoNeural
  
  memory:
    enabled: true
    max_entries: 100
  
  vision:
    enabled: true
    mode: remote             # remote 或 local
    wemm_api_url: http://localhost:8765
    dimension: 768
```

---

## 错误隔离

```
┌─────────────────────────────────────────────────────────┐
│                      Agent 主循环                        │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐   │
│  │   STT   │→│   LLM   │→│  Memory │→│   TTS   │   │
│  └────┬────┘  └────┬────┘  └────┬────┘  └────┬────┘   │
│       │            │            │            │         │
│       ▼            ▼            ▼            ▼         │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐   │
│  │  Fallback│  │  Fallback│ │  Fallback│ │  Fallback│   │
│  │  Silero  │  │  Default │ │  Cache   │ │  Local   │   │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘   │
└─────────────────────────────────────────────────────────┘
```

每个组件都有 fallback 实现，单个组件失败不影响整体流程。

---

## 数据流图

```
用户语音
    │
    ▼
┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐
│  STT    │────▶│  Event  │────▶│ Memory  │────▶│  LLM    │
│ FunASR  │     │  Bus    │     │  Store  │     │ Agnes   │
└─────────┘     └─────────┘     └─────────┘     └────┬────┘
                                                      │
                                                      ▼
                                               ┌─────────────┐
                                               │  TTS Output │
                                               │  EdgeTTS    │
                                               └─────────────┘
                                                      │
                                                      ▼
                                               ┌─────────────┐
                                               │  Response   │
                                               │   Audio     │
                                               └─────────────┘
```

---

## 松耦合原则

| 原则 | 实现方式 |
|------|---------|
| **依赖注入** | 所有组件通过构造函数传入，不硬编码 |
| **接口抽象** | 定义统一接口，不同实现可替换 |
| **事件驱动** | 组件间通过 Event Bus 通信，不直接调用 |
| **配置驱动** | 行为由 config.yaml 控制，无需改代码 |
| **错误隔离** | 每个组件有 try-catch，失败不影响主流程 |
| **单点故障** | 各组件独立启动/停止，可单独替换 |
