工程设计

技术选型、设计模式、并发控制和系统可靠性的工程决策。

技术栈 Tech Stack

Py

Python 后端

Python 3.13 + FastAPI + SQLAlchemy 2.0

异步优先架构。FastAPI 提供自动 OpenAPI 文档和类型验证,SQLAlchemy 2.0 的 async 支持配合 asyncpg 驱动。

PG

PostgreSQL + pgvector

PostgreSQL 17 + pgvector extension

关系型数据与向量索引统一存储。无需额外的向量数据库,降低运维复杂度。支持 cosine distance 索引加速。

AI

LLM / Embedding

vLLM / OpenRouter — OpenAI-compatible API

通过 Provider 工厂模式抽象,支持本地 vLLM 部署和云端 OpenRouter。统一的 OpenAI 兼容协议。

Re

React 前端

React 19 + Vite 8 + Tailwind CSS v4 + Bun

Neo-brutalist 设计风格。Tailwind v4 CSS-first 配置,Zustand 状态管理,SSE 流式渲染。

Provider 工厂模式 Design Pattern

可插拔的 LLM 和 Embedding 提供者

通过抽象基类 + 工厂注册表实现 Provider 的热插拔,新增 Provider 只需实现接口并注册。

LLMProvider

abstract base class

generate(prompt) → str

VLLMProvider

OpenAI-compatible

OpenRouterProvider

extends VLLM

Factory

_PROVIDER_REGISTRY

get_llm_provider()

Config

settings.llm.provider

"vllm" | "openrouter"

# providers/llm_provider.py
class LLMProvider(ABC):
    async def generate(self, prompt, *, temperature, max_tokens) -> str: ...

_PROVIDER_REGISTRY = {
    "vllm": VLLMProvider,
    "openai": VLLMProvider,  # 同协议
    "openrouter": OpenRouterProvider,
}

def get_llm_provider() -> LLMProvider:
    cls = _PROVIDER_REGISTRY[settings.llm.provider]
    return cls(settings.llm)  # 单例缓存

异步任务管理 Async Tasks

后台语义压缩

聊天后自动检查 Token 阈值,超过时 fire-and-forget 启动后台压缩任务,不阻塞用户响应。

asyncio.create_task()

手动压缩任务

API 立即返回 task_id,客户端轮询 GET /tasks/{id} 获取进度。支持 processing / completed / failed 状态。

TaskManager

自动提取调度器

每小时扫描不活跃会话(24h+),自动提取未处理消息的记忆。后台 while True 循环。

asyncio.sleep(3600)
# 异步任务生命周期
1. API 收到请求 → 创建 Task(status=pending)
2. asyncio.create_task() → status=processing
3. 后台任务独立 DB session → 避免连接冲突
4. 完成 → status=completed + result JSON
5. 失败 → status=failed + error message

并发控制 Concurrency

防止重复压缩的锁机制

多个请求可能同时触发同一会话的压缩。系统使用 PostgreSQL 行级锁确保同一时刻只有一个压缩任务在执行。

  • SELECT ... FOR UPDATE — 获取会话行的排他锁
  • skip_locked=True — 如果已被锁定,立即跳过而不等待
  • 后台任务使用独立的 async_session() 避免与请求共享连接
# 并发安全的压缩检查
locked = await db.execute(
    select(Session)
    .where(Session.id == session.id)
    .with_for_update(skip_locked=True)
)
if locked.scalar_one_or_none() is None:
    # 已被其他任务锁定,安全跳过
    return

配置系统 Configuration

1

YAML 基础配置

config/settings.yaml — 所有配置的主要来源。分为 llm / embedding / memory / compaction / chunking / search 六个区块。

2

Pydantic Settings 验证

Settings(BaseSettings) — 嵌套 BaseModel 子配置,提供类型验证、默认值和属性访问器。

3

环境变量覆盖

前缀 REPLICA_ 的环境变量可覆盖任何配置项。优先级:环境变量 > YAML > 默认值。

# config/settings.yaml 结构
database:
  url: postgresql+asyncpg://...
llm:
  provider: vllm
  model: Qwen/Qwen3-4B
  temperature: 0.3
embedding:
  provider: vllm
  model: Qwen/Qwen3-Embedding-4B
  dimensions: 1024
memory:
  language: en
  min_messages_for_extraction: 3
search:
  vector_weight: 0.7
  mmr_enabled: true

数据库迁移 Alembic

Alembic 版本化迁移

使用 Alembic 管理数据库 schema 变更,确保开发和生产环境的数据库结构一致。

  • 迁移脚本存储在 alembic/versions/
  • 自动检测 SQLAlchemy 模型变更生成迁移
  • pgvector extension 在应用启动时自动创建
  • 支持 upgrade / downgrade 双向迁移

前端架构 Frontend

Views

ChatView — 主聊天界面
AdminView — 数据库管理

Components

SessionSidebar
ChatPanel
MemoryPanel
TokenProgress

Store

Zustand app store
用户、会话、消息状态
选中态管理

API Layer

chat / memory / sessions
users / admin / health
SSE 流式客户端

前端关键设计决策
  • SSE 流式渲染 — 聊天使用 Server-Sent Events,逐 token 渲染,用户体验流畅
  • 三栏布局 — 左侧会话列表 + 中间聊天面板 + 右侧记忆面板,可拖拽调整宽度
  • Neo-Brutalist 设计 — 粗边框、硬阴影、高对比度配色、点阵背景,风格鲜明
  • Tailwind CSS v4 — CSS-first 配置,@theme 指令定义设计 token,零 JS 配置文件
  • 实时上下文展示 — 聊天时实时显示使用了哪些 Evergreen 和 Knowledge 条目

提取器并发设计 Extractors

三提取器并发执行

从 MemCell 中并发提取三种类型的知识,最大化利用 LLM 调用时间。每个提取器独立运行,互不依赖。

# memorize_service.py — 并发提取
episode, event_log, foresights = await asyncio.gather(
    self.episode_extractor.extract_memory(req),   # → 情节记忆
    self.event_log_extractor.extract_memory(req), # → 原子事实列表
    self.foresight_extractor.extract_memory(req), # → 前瞻预测列表
)

# 全部写入统一的 knowledge_entries 表
for result in [episode, *event_log.facts, *foresights]:
    db.add(KnowledgeEntry(...))

多语言提示词 Prompts

双语提示词模板系统

所有 LLM 提示词按功能和语言组织,支持中英文切换。通过 settings.memory.language 配置切换。

  • prompts/en/ — 英文提示词(conv, episode, event_log, foresight, profile, compaction)
  • prompts/zh/ — 中文提示词(同结构镜像)
  • 每个提取器根据语言设置动态加载对应模板
  • 提示词使用 Python f-string 模板,变量通过 .format() 注入