docs: add design document (Phase 2)

- 架构设计:MCP Server + Wiki Skills 混合架构
- 模块设计:4 层架构(Protocol/Tool/Service/Storage)
- 数据模型:WikiPage 和 WikiIndex
- 接口设计:MCP Tool 接口规范
- 核心算法:增量更新、查询、cross_linker
- 配置设计:YAML 配置 + 环境变量
- 错误处理:5 类错误处理策略
- 性能优化:FTS5、缓存、WAL 并发优化
- Wiki Skills 设计:11 个 Skills 优先级划分
- 测试设计:单元/集成/E2E 三层测试
- 部署设计:开发 + 生产环境配置

Phase 2: 设计评审

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-26 10:11:41 +08:00
parent ed58d12c7e
commit 22932e34eb
2 changed files with 555 additions and 3 deletions
+3 -3
View File
@@ -4,7 +4,7 @@
## 状态
🚧 开发中 - Phase 1: 需求评审
🚧 开发中 - Phase 2: 设计评审
## 项目概述
@@ -52,8 +52,8 @@ python -m mcp_server.main
## 文档
- [需求文档](docs/01-requirements.md)
- [设计文档](docs/02-design.md) - 待完成
- [需求文档 v1.1](docs/01-requirements.md) ✅ 评审通过
- [设计文档 v1.0](docs/02-design.md) 🚧 评审中
## 开发流程
+552
View File
@@ -0,0 +1,552 @@
# sanguo_llmwiki 设计文档
## 1. 架构设计
### 1.1 系统架构
```
┌─────────────────────────────────────────────────────────────┐
│ Claude Code │
│ │
│ ┌─────────────────────┐ ┌─────────────────────────┐ │
│ │ Wiki Skills (11) │ │ Wiki MCP Server │ │
│ │ (一次性操作) │ │ (Python 服务) │ │
│ └─────────────────────┘ └─────────────────────────┘ │
│ │ │
└───────────────────────────────────────┼─────────────────────┘
│ MCP 协议
│ (stdio/SSE)
┌───────────────────────────────────────▼─────────────────────┐
│ Wiki MCP Server │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ MCP Protocol Layer │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────▼───────────────────────────────┐ │
│ │ Tool Layer │ │
│ │ query │ status │ lint │ linker │ taxonomy │ synthesize│ │
│ └───────────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌───────────────────────▼───────────────────────────────┐ │
│ │ Service Layer │ │
│ │ indexer │ cache │ graph │ parser │ │
│ └───────────────────────┬───────────────────────────────┘ │
│ │ │
│ ┌───────────────────────▼───────────────────────────────┐ │
│ │ Storage Layer │ │
│ │ SQLite (WAL 模式) │ │
│ └─────────────────────────────────────────────────────┘ │
└───────────────────────────────────────┼─────────────────────┘
┌───────────────────────────────────────▼─────────────────────┐
│ Obsidian Wiki Vault │
│ /Volumes/KnowledgeBase/wiki-vault │
│ │
│ practices/ │ concepts/ │ entities/ │ projects/ │ skills/ │
└─────────────────────────────────────────────────────────────┘
```
### 1.2 部署架构
**开发阶段:**
```
Claude Code --stdio--> Wiki MCP Server (手动启动)
```
**生产阶段:**
```
PM2 --> Wiki MCP Server (SSE 模式)
└──> Claude Code --SSE--> Wiki MCP Server
```
---
## 2. 模块设计
### 2.1 MCP Protocol Layer
**职责:**
- MCP 协议解析和封装
- 工具注册和路由
- 错误处理和日志
**接口:**
```python
class MCPServer:
def register_tool(self, name: str, handler: Callable)
def handle_call(self, name: str, params: dict) -> dict
def log(self, level: str, message: str)
```
### 2.2 Tool Layer
**工具列表:**
| 工具 | 输入 | 输出 | 实现模块 |
|------|------|------|----------|
| wiki_query | query, tags, limit | results, citations | QueryTool |
| memory_bridge | tool_name, date_range | entries | MemoryTool |
| wiki_status | - | stats, pending | StatusTool |
| wiki_lint | path, level | issues, fixes | LintTool |
| cross_linker | path, dry_run | missing_links | LinkerTool |
| tag_taxonomy | path, enforce | conflicts | TaxonomyTool |
| wiki_synthesize | concepts, threshold | synthesis | SynthesizeTool |
| daily_update | - | updated, new | DailyTool |
### 2.3 Service Layer
**IndexerService(索引服务):**
```python
class IndexerService:
def index_page(self, path: str) -> None
def index_batch(self, paths: List[str]) -> None
def rebuild_index(self) -> None
def get_dirty_pages(self) -> List[str] # 增量更新
```
**CacheService(缓存服务):**
```python
class CacheService:
def get(self, key: str) -> Optional[Any]
def set(self, key: str, value: Any, ttl: int)
def invalidate(self, pattern: str)
```
**GraphService(图服务):**
```python
class GraphService:
def get_links(self, path: str) -> Set[str]
def get_backlinks(self, path: str) -> Set[str]
def find_orphans(self) -> Set[str]
def find_missing_links(self) -> List[Tuple[str, str]]
```
**ParserService(解析服务):**
```python
class ParserService:
def parse_frontmatter(self, content: str) -> dict
def extract_links(self, content: str) -> List[str]
def validate_page(self, path: str) -> List[str] # 返回问题列表
```
### 2.4 Storage Layer
**数据库连接(带并发保护):**
```python
class Database:
def __init__(self, path: str):
self.conn = sqlite3.connect(path, check_same_thread=False)
self.conn.execute("PRAGMA journal_mode=WAL")
self.conn.execute("PRAGMA busy_timeout=10000") # 10s
self.lock = asyncio.Lock()
async def execute(self, sql: str, params: tuple):
async with self.lock:
return self.conn.execute(sql, params)
```
---
## 3. 数据模型
### 3.1 WikiPage(页面模型)
```python
@dataclass
class WikiPage:
path: str # wiki 相对路径
title: str # 标题
category: str # 分类(practices/concepts/...
tags: List[str] # 标签列表
summary: str # 摘要(≤200 字符)
content_hash: str # MD5 哈希
lifecycle: str # draft/verified/archived/disputed
sources: List[str] # 来源页面
created_at: datetime
updated_at: datetime
indexed_at: datetime
def is_stale(self, days: int = 90) -> bool:
return (datetime.now() - self.updated_at).days > days
```
### 3.2 WikiIndex(索引模型)
```python
@dataclass
class WikiIndex:
pages: Dict[str, WikiPage]
links: Dict[str, Set[str]] # source -> {targets}
backlinks: Dict[str, Set[str]] # target -> {sources}
tags: Dict[str, Set[str]] # tag -> {pages}
orphans: Set[str] # 无反向链接的页面
stats: IndexStats
@dataclass
class IndexStats:
total_pages: int
total_links: int
total_tags: int
last_indexed: datetime
dirty_pages: int
```
---
## 4. 接口设计
### 4.1 MCP Tool 接口
**wiki_query:**
```json
{
"name": "wiki_query",
"inputSchema": {
"type": "object",
"properties": {
"query": {"type": "string"},
"tags": {"type": "array", "items": {"type": "string"}},
"limit": {"type": "integer", "default": 10}
}
}
}
```
**wiki_status:**
```json
{
"name": "wiki_status",
"inputSchema": {
"type": "object",
"properties": {}
}
}
```
### 4.2 内部服务接口
```python
# IndexerService
async def index_page(path: str) -> IndexResult
async def get_dirty_pages() -> List[str]
# QueryService
async def search(query: str, limit: int) -> List[WikiPage]
async def search_by_tags(tags: List[str]) -> List[WikiPage]
# GraphService
async def get_links(path: str) -> Set[str]
async def find_orphans() -> Set[str]
```
---
## 5. 核心算法
### 5.1 增量更新算法
```python
async def incremental_update():
# 1. 获取所有 wiki 页面
all_pages = scan_wiki_vault()
# 2. 检查每个页面的哈希
for page in all_pages:
current_hash = md5(page.content)
stored = db.get_page_hash(page.path)
if stored != current_hash:
# 3. 只重索引变化的页面
await index_page(page)
# 4. 处理删除的页面
indexed_paths = db.get_all_indexed_paths()
for path in indexed_paths:
if path not in all_pages:
db.delete_page(path)
```
### 5.2 查询算法
```python
async def wiki_query(query: str, tags: List[str], limit: int):
# 1. FTS5 全文搜索
if query:
results = fts_search(query, limit)
# 2. 标签过滤
if tags:
results = filter_by_tags(results, tags)
# 3. 按相关性排序
sorted_results = rank_by_relevance(results, query)
# 4. 返回带 [[wikilink]] 的结果
return format_results(sorted_results[:limit])
```
### 5.3 cross_linker 算法
```python
async def find_missing_links():
# 1. 获取所有页面内容
pages = load_all_pages()
# 2. 提取所有 [[wikilinks]]
all_links = extract_all_links(pages)
# 3. 找出缺失的链接
missing = []
for source, targets in all_links.items():
for target in targets:
if not page_exists(target):
missing.append((source, target))
return missing
```
---
## 6. 配置设计
### 6.1 配置文件结构
```yaml
# ~/.sanguo-llmwiki/config.yaml
wiki:
vault_path: "/Volumes/KnowledgeBase/wiki-vault"
index_path: "~/.sanguo-llmwiki/index.db"
max_page_size_kb: 500
mcp:
mode: "stdio" # stdio 或 SSE
host: "localhost"
port: 8080
performance:
query_timeout_ms: 5000
cache_ttl_seconds: 3600
fts_cache_size_mb: 100
logging:
level: "INFO"
file: "~/.sanguo-llmwiki/wiki-mcp.log"
```
### 6.2 环境变量
```bash
# 环境变量优先级高于配置文件
WIKI_VAULT_PATH=/custom/path
WIKI_INDEX_PATH=/custom/index.db
MCP_MODE=sse
LOG_LEVEL=DEBUG
```
---
## 7. 错误处理
### 7.1 错误分类
| 错误类型 | 处理方式 |
|----------|----------|
| Wiki 路径不存在 | 启动失败,返回友好错误 |
| 索引文件损坏 | 自动重建 + WARN 日志 |
| SQLite 写入失败 | 回滚事务 + 重试 1 次 |
| 页面解析失败 | 记录日志 + 跳过该页面 |
| MCP 协议错误 | 返回标准错误格式 |
| 查询超时 | 返回部分结果 + WARN |
### 7.2 错误响应格式
```json
{
"success": false,
"error": {
"code": "INDEX_CORRUPTED",
"message": "索引文件损坏,正在自动重建",
"details": {"rebuilding": true}
}
}
```
---
## 8. 安全考虑
虽然是本地系统,但仍需考虑:
1. **路径安全**:验证路径在 wiki vault 范围内(防止路径遍历)
2. **资源限制**:限制查询返回数量、内存使用
3. **日志脱敏**:日志中不记录敏感内容
---
## 9. 性能优化
### 9.1 索引优化
- 使用 FTS5 全文搜索索引
- 标签单独建立索引
- 定期 VACUUM(每周)
### 9.2 查询优化
- 查询结果缓存(TTL 1 小时)
- 限制返回数量(默认 10
- 使用 prepared statements
### 9.3 并发优化
- SQLite WAL 模式
- asyncio.Lock 写入串行化
- busy_timeout=10s
---
## 10. Wiki Skills 设计
### 10.1 Skill 模板
每个 Skill 遵循统一结构:
```markdown
---
name: wiki-xxx
description: >
简短描述(1-2 句)
触发条件
---
# Wiki XXX
## 使用场景
用户何时触发这个 Skill
## 操作步骤
1. ...
2. ...
## 输出格式
...
```
### 10.2 Skills 列表
**优先级 P0(核心):**
1. wiki-setup - 初始化 wiki
2. wiki-ingest - 蒸馏文档
3. wiki-capture - 保存对话
**优先级 P1(重要):**
4. wiki-rebuild - 重建 wiki
5. data-ingest - 录入数据
6. ingest-url - 抓取 URL
7. wiki-agent - 录入历史
8. wiki-export - 导出
**优先级 P2(可选):**
9. wiki-research - 研究
10. impl-validator - 验证
11. graph-colorize - 着色
---
## 11. 测试设计
### 11.1 单元测试
覆盖所有 Service 层的核心逻辑:
- IndexerService 测试
- QueryService 测试
- GraphService 测试
- ParserService 测试
### 11.2 集成测试
- MCP 协议层测试(使用 MCP SDK mock
- SQLite 操作测试
- Wiki 解析测试
### 11.3 E2E 测试
使用真实 wiki 数据集测试:
- 查询场景
- 搜索场景
- 索引更新场景
---
## 12. 部署设计
### 12.1 开发部署
```bash
# 手动启动
cd ~/.openclaw/sanguo_projects/sanguo_llmwiki
python -m mcp_server.main
```
### 12.2 生产部署
```bash
# PM2 配置
cat > ecosystem.config.cjs << 'EOF'
module.exports = {
apps: [{
name: 'wiki-mcp',
script: 'python',
args: '-m mcp_server.main',
cwd: '/Users/chufeng/.openclaw/sanguo_projects/sanguo_llmwiki',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '500M',
env: {
PYTHONUNBUFFERED: '1'
}
}]
}
EOF
pm2 start ecosystem.config.cjs
pm2 save
```
### 12.3 MCP 配置
**stdio 模式(开发):**
```json
{
"mcpServers": {
"wiki": {
"command": "python",
"args": ["-m", "mcp_server.main"],
"cwd": "/Users/chufeng/.openclaw/sanguo_projects/sanguo_llmwiki",
"env": {
"WIKI_VAULT_PATH": "/Volumes/KnowledgeBase/wiki-vault"
}
}
}
}
```
**SSE 模式(生产):**
```json
{
"mcpServers": {
"wiki": {
"type": "sse",
"url": "http://localhost:8080/sse"
}
}
}
```
---
*文档版本:v1.0*
*创建时间:2026-06-26*