feat(§03): 实现 MCP Server 核心 - Storage/Service/Tool/MCP Protocol Layers
**Storage Layer:** - Database 类(aiosqlite + WAL + 并发保护) - WikiPage 数据模型 - fix_dirty_states 恢复机制 - FTS5 全文搜索支持 - 完整的 SQLite 表结构 **Service Layer:** - CacheService(LRU 缓存 + TTL + 大小限制) - QueryService(查询服务) - ParserService(Markdown 解析) - IndexerService(索引服务) - GraphService(链接图服务) **Tool Layer (8 个 MCP Tools):** - wiki_query - FTS5 全文搜索 + 标签过滤 - memory_bridge - 按工具来源浏览 - wiki_status - 索引状态 - wiki_lint - 健康审计 - cross_linker - 缺失链接发现 - tag_taxonomy - 标签一致性 - wiki_synthesize - 跨概念综合分析 - daily_update - 日常维护 + hot.md 生成 **MCP Protocol Layer:** - MCP 协议解析和封装 - 工具注册和路由 - 错误处理和日志 - stdio 模式支持 **配置和部署:** - requirements.txt - config.example.yaml - ecosystem.config.cjs (PM2) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
"""
|
||||
Tool Layer - wiki_synthesize 工具
|
||||
|
||||
发现跨概念的综合分析机会,生成 synthesis 页面。
|
||||
|
||||
参考设计文档:第 2.2 节
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Dict, Any, List
|
||||
from ..services import QueryService, GraphService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class WikiSynthesizeTool:
|
||||
"""wiki_synthesize 工具实现"""
|
||||
|
||||
def __init__(self, query_service: QueryService, graph_service: GraphService):
|
||||
self.query_service = query_service
|
||||
self.graph_service = graph_service
|
||||
|
||||
async def handle(self, concepts: List[str] = None, threshold: float = 0.3) -> Dict[str, Any]:
|
||||
"""
|
||||
发现跨概念的综合分析机会
|
||||
|
||||
Args:
|
||||
concepts: 概念列表(空表示自动发现)
|
||||
threshold: 相关性阈值
|
||||
|
||||
Returns:
|
||||
{
|
||||
"synthesis": [
|
||||
{
|
||||
"concept_a": "SQLite",
|
||||
"concept_b": "Concurrency",
|
||||
"common_references": ["page1", "page2"],
|
||||
"strength": 0.8,
|
||||
"suggestion": "Consider creating synthesis page: SQLite & Concurrency"
|
||||
}
|
||||
],
|
||||
"total": 5
|
||||
}
|
||||
"""
|
||||
synthesis = []
|
||||
|
||||
# 如果未提供概念,自动发现高相关性概念
|
||||
if not concepts:
|
||||
# 获取高度连接的页面作为候选
|
||||
highly_connected = await self.graph_service.get_highly_connected_pages(threshold=10)
|
||||
concepts = [item["title"] for item in highly_connected[:10]]
|
||||
|
||||
# 分析概念间的关联
|
||||
for i, concept_a in enumerate(concepts):
|
||||
for concept_b in concepts[i + 1:]:
|
||||
# 查找同时引用两个概念的页面
|
||||
pages_a = await self.query_service.search(concept_a, limit=50)
|
||||
pages_b = await self.query_service.search(concept_b, limit=50)
|
||||
|
||||
paths_a = {p.path for p in pages_a}
|
||||
paths_b = {p.path for p in pages_b}
|
||||
|
||||
common = paths_a & paths_b
|
||||
|
||||
if len(common) >= 2: # 至少 2 个共同引用
|
||||
strength = len(common) / max(len(paths_a), len(paths_b))
|
||||
|
||||
if strength >= threshold:
|
||||
synthesis.append({
|
||||
"concept_a": concept_a,
|
||||
"concept_b": concept_b,
|
||||
"common_references": sorted(list(common)),
|
||||
"strength": round(strength, 2),
|
||||
"suggestion": f"Consider creating synthesis page: {concept_a} & {concept_b}"
|
||||
})
|
||||
|
||||
# 按关联强度排序
|
||||
synthesis.sort(key=lambda x: x["strength"], reverse=True)
|
||||
|
||||
return {
|
||||
"synthesis": synthesis[:20],
|
||||
"total": len(synthesis)
|
||||
}
|
||||
|
||||
def get_schema(self) -> dict:
|
||||
"""返回 MCP Tool schema"""
|
||||
return {
|
||||
"name": "wiki_synthesize",
|
||||
"description": "发现跨概念的综合分析机会,生成 synthesis 页面",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"concepts": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "概念列表(空表示自动发现)"
|
||||
},
|
||||
"threshold": {
|
||||
"type": "number",
|
||||
"default": 0.3,
|
||||
"description": "相关性阈值"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user