iflow-mcp_hanw39_reasoning-bank-mcp 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iflow_mcp_hanw39_reasoning_bank_mcp-0.2.0.dist-info/METADATA +599 -0
- iflow_mcp_hanw39_reasoning_bank_mcp-0.2.0.dist-info/RECORD +55 -0
- iflow_mcp_hanw39_reasoning_bank_mcp-0.2.0.dist-info/WHEEL +4 -0
- iflow_mcp_hanw39_reasoning_bank_mcp-0.2.0.dist-info/entry_points.txt +2 -0
- iflow_mcp_hanw39_reasoning_bank_mcp-0.2.0.dist-info/licenses/LICENSE +21 -0
- src/__init__.py +16 -0
- src/__main__.py +6 -0
- src/config.py +266 -0
- src/deduplication/__init__.py +19 -0
- src/deduplication/base.py +88 -0
- src/deduplication/factory.py +60 -0
- src/deduplication/strategies/__init__.py +1 -0
- src/deduplication/strategies/semantic_dedup.py +187 -0
- src/default_config.yaml +121 -0
- src/initializers/__init__.py +50 -0
- src/initializers/base.py +196 -0
- src/initializers/embedding_initializer.py +22 -0
- src/initializers/llm_initializer.py +22 -0
- src/initializers/memory_manager_initializer.py +55 -0
- src/initializers/retrieval_initializer.py +32 -0
- src/initializers/storage_initializer.py +22 -0
- src/initializers/tools_initializer.py +48 -0
- src/llm/__init__.py +10 -0
- src/llm/base.py +61 -0
- src/llm/factory.py +75 -0
- src/llm/providers/__init__.py +12 -0
- src/llm/providers/anthropic.py +62 -0
- src/llm/providers/dashscope.py +76 -0
- src/llm/providers/openai.py +76 -0
- src/merge/__init__.py +22 -0
- src/merge/base.py +89 -0
- src/merge/factory.py +60 -0
- src/merge/strategies/__init__.py +1 -0
- src/merge/strategies/llm_merge.py +170 -0
- src/merge/strategies/voting_merge.py +108 -0
- src/prompts/__init__.py +21 -0
- src/prompts/formatters.py +74 -0
- src/prompts/templates.py +184 -0
- src/retrieval/__init__.py +8 -0
- src/retrieval/base.py +37 -0
- src/retrieval/factory.py +55 -0
- src/retrieval/strategies/__init__.py +8 -0
- src/retrieval/strategies/cosine_retrieval.py +47 -0
- src/retrieval/strategies/hybrid_retrieval.py +155 -0
- src/server.py +306 -0
- src/services/__init__.py +5 -0
- src/services/memory_manager.py +403 -0
- src/storage/__init__.py +45 -0
- src/storage/backends/json_backend.py +290 -0
- src/storage/base.py +150 -0
- src/tools/__init__.py +8 -0
- src/tools/extract_memory.py +285 -0
- src/tools/retrieve_memory.py +139 -0
- src/utils/__init__.py +7 -0
- src/utils/similarity.py +54 -0
src/default_config.yaml
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# LLM 配置
|
|
2
|
+
llm:
|
|
3
|
+
provider: "dashscope" # dashscope | openai | anthropic
|
|
4
|
+
|
|
5
|
+
# DashScope (通义千问) 配置
|
|
6
|
+
dashscope:
|
|
7
|
+
api_key: "${DASHSCOPE_API_KEY}"
|
|
8
|
+
base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
9
|
+
chat_model: "qwen-turbo" # qwen-turbo | qwen-plus | qwen-max
|
|
10
|
+
temperature: 0.7
|
|
11
|
+
max_tokens: 4096
|
|
12
|
+
|
|
13
|
+
# OpenAI 配置
|
|
14
|
+
openai:
|
|
15
|
+
api_key: "${OPENAI_API_KEY?}" # 可选,未设置时为空
|
|
16
|
+
base_url: "https://api.openai.com/v1"
|
|
17
|
+
chat_model: "gpt-4o-mini"
|
|
18
|
+
temperature: 0.7
|
|
19
|
+
max_tokens: 4096
|
|
20
|
+
|
|
21
|
+
# Anthropic 配置
|
|
22
|
+
anthropic:
|
|
23
|
+
api_key: "${ANTHROPIC_API_KEY?}" # 可选,未设置时为空
|
|
24
|
+
chat_model: "claude-3-5-sonnet-20241022"
|
|
25
|
+
temperature: 0.7
|
|
26
|
+
max_tokens: 4096
|
|
27
|
+
|
|
28
|
+
# Embedding 配置
|
|
29
|
+
embedding:
|
|
30
|
+
provider: "dashscope" # dashscope | openai
|
|
31
|
+
|
|
32
|
+
dashscope:
|
|
33
|
+
api_key: "${DASHSCOPE_API_KEY}"
|
|
34
|
+
base_url: "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
35
|
+
model: "text-embedding-v3"
|
|
36
|
+
|
|
37
|
+
openai:
|
|
38
|
+
api_key: "${OPENAI_API_KEY?}" # 可选,未设置时为空
|
|
39
|
+
base_url: "https://api.openai.com/v1"
|
|
40
|
+
model: "text-embedding-3-small"
|
|
41
|
+
|
|
42
|
+
# 检索配置
|
|
43
|
+
retrieval:
|
|
44
|
+
strategy: "hybrid" # cosine | hybrid | llm_assisted
|
|
45
|
+
default_top_k: 1
|
|
46
|
+
max_top_k: 10
|
|
47
|
+
min_score_threshold: 0.85 # 最小相关度阈值,低于此值的记忆不会被返回
|
|
48
|
+
|
|
49
|
+
# Hybrid 策略配置
|
|
50
|
+
hybrid:
|
|
51
|
+
weights:
|
|
52
|
+
semantic: 0.6 # 语义相似度权重
|
|
53
|
+
confidence: 0.2 # 置信度权重
|
|
54
|
+
success: 0.15 # 成功偏好权重
|
|
55
|
+
recency: 0.05 # 时效性权重
|
|
56
|
+
time_decay_halflife: 30 # 时间衰减半衰期(天)
|
|
57
|
+
|
|
58
|
+
# 存储配置
|
|
59
|
+
storage:
|
|
60
|
+
backend: "json" # json | sqlite | chroma
|
|
61
|
+
|
|
62
|
+
json:
|
|
63
|
+
memories_path: "~/.reasoningbank/data/memories.json"
|
|
64
|
+
embeddings_path: "~/.reasoningbank/data/embeddings.json"
|
|
65
|
+
archived_path: "~/.reasoningbank/data/archived_memories.json"
|
|
66
|
+
# memories_path: "/Users/hanw/data/memories.json"
|
|
67
|
+
# embeddings_path: "/Users/hanw/data/embeddings.json"
|
|
68
|
+
|
|
69
|
+
sqlite:
|
|
70
|
+
db_path: "~/.reasoningbank/data/reasoning_bank.db"
|
|
71
|
+
|
|
72
|
+
# 记忆提取配置
|
|
73
|
+
extraction:
|
|
74
|
+
max_memories_per_trajectory: 3 # 每个轨迹最多提取记忆数
|
|
75
|
+
judge_temperature: 0.0 # 判断轨迹成功/失败的温度
|
|
76
|
+
extract_temperature: 1.0 # 提取记忆的温度
|
|
77
|
+
async_by_default: true # 默认异步处理
|
|
78
|
+
|
|
79
|
+
# MCP 服务器配置
|
|
80
|
+
server:
|
|
81
|
+
name: "reasoning-bank"
|
|
82
|
+
version: "0.1.0"
|
|
83
|
+
log_level: "INFO" # DEBUG | INFO | WARNING | ERROR
|
|
84
|
+
|
|
85
|
+
# 记忆管理配置
|
|
86
|
+
memory_manager:
|
|
87
|
+
enabled: true # 是否启用记忆管理器
|
|
88
|
+
|
|
89
|
+
# 去重配置
|
|
90
|
+
deduplication:
|
|
91
|
+
strategy: "semantic" # semantic (语义去重)
|
|
92
|
+
on_extraction: true # 在提取时实时去重
|
|
93
|
+
|
|
94
|
+
# 语义去重配置
|
|
95
|
+
semantic:
|
|
96
|
+
threshold: 0.90 # 相似度阈值(0-1)
|
|
97
|
+
top_k_check: 1 # 检查最相似的前K条记忆
|
|
98
|
+
|
|
99
|
+
# 合并配置
|
|
100
|
+
merge:
|
|
101
|
+
strategy: "llm" # llm | voting | template
|
|
102
|
+
auto_execute: true # 自动执行合并(后台)
|
|
103
|
+
|
|
104
|
+
# 触发条件
|
|
105
|
+
trigger:
|
|
106
|
+
min_similar_count: 3 # 最少相似记忆数
|
|
107
|
+
similarity_threshold: 0.85 # 相似度阈值
|
|
108
|
+
|
|
109
|
+
# LLM合并配置
|
|
110
|
+
llm:
|
|
111
|
+
temperature: 0.7
|
|
112
|
+
|
|
113
|
+
# Voting合并配置
|
|
114
|
+
voting:
|
|
115
|
+
min_group_size: 2
|
|
116
|
+
|
|
117
|
+
# 原记忆处理
|
|
118
|
+
original_handling: "archive" # archive | delete | mark
|
|
119
|
+
archive:
|
|
120
|
+
keep_embeddings: false # 归档时是否保留embedding
|
|
121
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""组件初始化器模块
|
|
2
|
+
|
|
3
|
+
提供自动化的组件初始化和依赖管理功能。
|
|
4
|
+
|
|
5
|
+
使用方式:
|
|
6
|
+
from initializers import InitializerRegistry
|
|
7
|
+
from initializers import (
|
|
8
|
+
StorageInitializer,
|
|
9
|
+
LLMInitializer,
|
|
10
|
+
EmbeddingInitializer,
|
|
11
|
+
RetrievalInitializer,
|
|
12
|
+
MemoryManagerInitializer,
|
|
13
|
+
ToolsInitializer
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
# 创建注册表
|
|
17
|
+
registry = InitializerRegistry()
|
|
18
|
+
|
|
19
|
+
# 自动注册所有初始化器
|
|
20
|
+
registry.auto_register([
|
|
21
|
+
StorageInitializer,
|
|
22
|
+
LLMInitializer,
|
|
23
|
+
EmbeddingInitializer,
|
|
24
|
+
RetrievalInitializer,
|
|
25
|
+
MemoryManagerInitializer,
|
|
26
|
+
ToolsInitializer
|
|
27
|
+
], config)
|
|
28
|
+
|
|
29
|
+
# 自动初始化所有组件
|
|
30
|
+
components = await registry.initialize_all(config)
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
from .base import ComponentInitializer, InitializerRegistry
|
|
34
|
+
from .storage_initializer import StorageInitializer
|
|
35
|
+
from .llm_initializer import LLMInitializer
|
|
36
|
+
from .embedding_initializer import EmbeddingInitializer
|
|
37
|
+
from .retrieval_initializer import RetrievalInitializer
|
|
38
|
+
from .memory_manager_initializer import MemoryManagerInitializer
|
|
39
|
+
from .tools_initializer import ToolsInitializer
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"ComponentInitializer",
|
|
43
|
+
"InitializerRegistry",
|
|
44
|
+
"StorageInitializer",
|
|
45
|
+
"LLMInitializer",
|
|
46
|
+
"EmbeddingInitializer",
|
|
47
|
+
"RetrievalInitializer",
|
|
48
|
+
"MemoryManagerInitializer",
|
|
49
|
+
"ToolsInitializer",
|
|
50
|
+
]
|
src/initializers/base.py
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"""组件初始化器基类"""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from typing import Any, Dict, List, Optional, Type
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger("reasoning-bank-mcp")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ComponentInitializer(ABC):
|
|
11
|
+
"""组件初始化器基类
|
|
12
|
+
|
|
13
|
+
每个组件(如 Storage、LLM、Embedding 等)都应该实现自己的初始化器。
|
|
14
|
+
初始化器负责:
|
|
15
|
+
1. 声明组件名称
|
|
16
|
+
2. 声明依赖的其他组件
|
|
17
|
+
3. 从配置中读取必要的配置项
|
|
18
|
+
4. 执行初始化逻辑
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, config: Any):
|
|
22
|
+
"""初始化器构造函数
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
config: 配置对象
|
|
26
|
+
"""
|
|
27
|
+
self.config = config
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def name(self) -> str:
|
|
32
|
+
"""组件名称,用于标识和日志输出"""
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def dependencies(self) -> List[str]:
|
|
37
|
+
"""依赖的其他组件名称列表,确保按依赖顺序初始化"""
|
|
38
|
+
return []
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def enabled(self) -> bool:
|
|
42
|
+
"""组件是否启用,默认启用。可被子类重写以支持条件初始化"""
|
|
43
|
+
return True
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
async def initialize(self, context: Dict[str, Any]) -> Any:
|
|
47
|
+
"""执行初始化逻辑
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
context: 初始化上下文,包含 config 和已初始化的其他组件
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
初始化后的组件实例
|
|
54
|
+
"""
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
def _get_config(self, context: Dict[str, Any]) -> Any:
|
|
58
|
+
"""从上下文获取配置对象"""
|
|
59
|
+
return context.get("config")
|
|
60
|
+
|
|
61
|
+
def _get_component(self, context: Dict[str, Any], name: str) -> Optional[Any]:
|
|
62
|
+
"""从上下文获取已初始化的组件"""
|
|
63
|
+
return context.get(name)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class InitializerRegistry:
|
|
67
|
+
"""初始化器注册表
|
|
68
|
+
|
|
69
|
+
负责:
|
|
70
|
+
1. 注册所有组件初始化器
|
|
71
|
+
2. 解析依赖关系
|
|
72
|
+
3. 按正确顺序执行初始化
|
|
73
|
+
4. 管理初始化上下文
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
def __init__(self):
|
|
77
|
+
self._initializers: Dict[str, ComponentInitializer] = {}
|
|
78
|
+
self._initialized_components: Dict[str, Any] = {}
|
|
79
|
+
|
|
80
|
+
def register(self, initializer: ComponentInitializer):
|
|
81
|
+
"""注册一个初始化器"""
|
|
82
|
+
self._initializers[initializer.name] = initializer
|
|
83
|
+
logger.debug(f"已注册初始化器: {initializer.name}")
|
|
84
|
+
|
|
85
|
+
def register_many(self, initializers: List[ComponentInitializer]):
|
|
86
|
+
"""批量注册初始化器"""
|
|
87
|
+
for initializer in initializers:
|
|
88
|
+
self.register(initializer)
|
|
89
|
+
|
|
90
|
+
def auto_register(self, initializer_classes: List[Type[ComponentInitializer]], config: Any):
|
|
91
|
+
"""自动注册初始化器类
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
initializer_classes: 初始化器类列表
|
|
95
|
+
config: 配置对象,将传递给初始化器构造函数
|
|
96
|
+
"""
|
|
97
|
+
for initializer_class in initializer_classes:
|
|
98
|
+
initializer = initializer_class(config)
|
|
99
|
+
if initializer.enabled:
|
|
100
|
+
self.register(initializer)
|
|
101
|
+
else:
|
|
102
|
+
logger.info(f"跳过禁用的组件: {initializer.name}")
|
|
103
|
+
|
|
104
|
+
async def initialize_all(self, config: Any) -> Dict[str, Any]:
|
|
105
|
+
"""按依赖顺序初始化所有组件
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
config: 配置对象
|
|
109
|
+
|
|
110
|
+
Returns:
|
|
111
|
+
所有已初始化的组件字典
|
|
112
|
+
"""
|
|
113
|
+
# 初始化上下文
|
|
114
|
+
context = {
|
|
115
|
+
"config": config
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
# 拓扑排序,解析依赖顺序
|
|
119
|
+
sorted_names = self._topological_sort()
|
|
120
|
+
|
|
121
|
+
# 按顺序初始化
|
|
122
|
+
for name in sorted_names:
|
|
123
|
+
initializer = self._initializers[name]
|
|
124
|
+
|
|
125
|
+
logger.info(f"正在初始化 {initializer.name}...")
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
# 执行初始化
|
|
129
|
+
component = await initializer.initialize(context)
|
|
130
|
+
|
|
131
|
+
# 保存到上下文
|
|
132
|
+
context[name] = component
|
|
133
|
+
self._initialized_components[name] = component
|
|
134
|
+
|
|
135
|
+
logger.info(f"✓ {initializer.name} 初始化完成")
|
|
136
|
+
|
|
137
|
+
except Exception as e:
|
|
138
|
+
logger.error(f"✗ {initializer.name} 初始化失败: {e}")
|
|
139
|
+
raise
|
|
140
|
+
|
|
141
|
+
return self._initialized_components
|
|
142
|
+
|
|
143
|
+
def _topological_sort(self) -> List[str]:
|
|
144
|
+
"""拓扑排序,解析依赖关系
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
排序后的组件名称列表
|
|
148
|
+
|
|
149
|
+
Raises:
|
|
150
|
+
ValueError: 如果存在循环依赖
|
|
151
|
+
"""
|
|
152
|
+
# 构建依赖图和入度表
|
|
153
|
+
graph = {}
|
|
154
|
+
in_degree = {}
|
|
155
|
+
|
|
156
|
+
# 初始化图结构
|
|
157
|
+
for name, initializer in self._initializers.items():
|
|
158
|
+
graph[name] = initializer.dependencies
|
|
159
|
+
in_degree[name] = 0
|
|
160
|
+
|
|
161
|
+
# 计算入度
|
|
162
|
+
for name, deps in graph.items():
|
|
163
|
+
for dep in deps:
|
|
164
|
+
if dep not in self._initializers:
|
|
165
|
+
raise ValueError(f"组件 '{name}' 依赖的组件 '{dep}' 未注册")
|
|
166
|
+
in_degree[name] = in_degree.get(name, 0) + 1
|
|
167
|
+
|
|
168
|
+
# Kahn 算法进行拓扑排序
|
|
169
|
+
queue = [name for name, degree in in_degree.items() if degree == 0]
|
|
170
|
+
result = []
|
|
171
|
+
|
|
172
|
+
while queue:
|
|
173
|
+
# 选择入度为0的节点
|
|
174
|
+
current = queue.pop(0)
|
|
175
|
+
result.append(current)
|
|
176
|
+
|
|
177
|
+
# 减少依赖当前节点的其他节点的入度
|
|
178
|
+
for name in self._initializers.keys():
|
|
179
|
+
if current in graph[name]:
|
|
180
|
+
in_degree[name] -= 1
|
|
181
|
+
if in_degree[name] == 0:
|
|
182
|
+
queue.append(name)
|
|
183
|
+
|
|
184
|
+
# 检查是否存在循环依赖
|
|
185
|
+
if len(result) != len(self._initializers):
|
|
186
|
+
raise ValueError("存在循环依赖,无法初始化")
|
|
187
|
+
|
|
188
|
+
return result
|
|
189
|
+
|
|
190
|
+
def get_component(self, name: str) -> Optional[Any]:
|
|
191
|
+
"""获取已初始化的组件"""
|
|
192
|
+
return self._initialized_components.get(name)
|
|
193
|
+
|
|
194
|
+
def get_all_components(self) -> Dict[str, Any]:
|
|
195
|
+
"""获取所有已初始化的组件"""
|
|
196
|
+
return self._initialized_components.copy()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Embedding Provider 初始化器"""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
from .base import ComponentInitializer
|
|
5
|
+
from ..llm import EmbeddingFactory
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class EmbeddingInitializer(ComponentInitializer):
|
|
9
|
+
"""Embedding Provider 初始化器"""
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def name(self) -> str:
|
|
13
|
+
return "embedding"
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def dependencies(self):
|
|
17
|
+
return [] # 无依赖
|
|
18
|
+
|
|
19
|
+
async def initialize(self, context: Dict[str, Any]) -> Any:
|
|
20
|
+
"""初始化 Embedding Provider"""
|
|
21
|
+
embedding_config = self.config.get_embedding_config()
|
|
22
|
+
return EmbeddingFactory.create(embedding_config)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""LLM Provider 初始化器"""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
from .base import ComponentInitializer
|
|
5
|
+
from ..llm import LLMFactory
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LLMInitializer(ComponentInitializer):
|
|
9
|
+
"""LLM Provider 初始化器"""
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def name(self) -> str:
|
|
13
|
+
return "llm"
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def dependencies(self):
|
|
17
|
+
return [] # 无依赖
|
|
18
|
+
|
|
19
|
+
async def initialize(self, context: Dict[str, Any]) -> Any:
|
|
20
|
+
"""初始化 LLM Provider"""
|
|
21
|
+
llm_config = self.config.get_llm_config()
|
|
22
|
+
return LLMFactory.create(llm_config)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""记忆管理器初始化器"""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any, Dict
|
|
5
|
+
from .base import ComponentInitializer
|
|
6
|
+
from ..services import MemoryManager
|
|
7
|
+
from ..deduplication import DeduplicationFactory
|
|
8
|
+
from ..merge import MergeFactory
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger("reasoning-bank-mcp")
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MemoryManagerInitializer(ComponentInitializer):
|
|
14
|
+
"""记忆管理器初始化器"""
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def name(self) -> str:
|
|
18
|
+
return "memory_manager"
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def dependencies(self):
|
|
22
|
+
return ["storage", "llm", "embedding"] # 依赖这三个组件
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def enabled(self) -> bool:
|
|
26
|
+
"""根据配置判断是否启用"""
|
|
27
|
+
return self.config.get("memory_manager", "enabled", default=True)
|
|
28
|
+
|
|
29
|
+
async def initialize(self, context: Dict[str, Any]) -> Any:
|
|
30
|
+
"""初始化记忆管理器"""
|
|
31
|
+
# 获取依赖组件
|
|
32
|
+
storage = self._get_component(context, "storage")
|
|
33
|
+
llm = self._get_component(context, "llm")
|
|
34
|
+
embedding = self._get_component(context, "embedding")
|
|
35
|
+
|
|
36
|
+
# 创建去重策略(传递 Config 对象)
|
|
37
|
+
dedup_strategy = DeduplicationFactory.create(self.config)
|
|
38
|
+
|
|
39
|
+
# 创建合并策略(传递 Config 对象)
|
|
40
|
+
merge_strategy = MergeFactory.create(self.config)
|
|
41
|
+
|
|
42
|
+
# 创建记忆管理器
|
|
43
|
+
memory_manager = MemoryManager(
|
|
44
|
+
storage_backend=storage,
|
|
45
|
+
dedup_strategy=dedup_strategy,
|
|
46
|
+
merge_strategy=merge_strategy,
|
|
47
|
+
embedding_provider=embedding,
|
|
48
|
+
llm_provider=llm,
|
|
49
|
+
config=self.config.all
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
logger.info(f" - 去重策略: {dedup_strategy.name}")
|
|
53
|
+
logger.info(f" - 合并策略: {merge_strategy.name}")
|
|
54
|
+
|
|
55
|
+
return memory_manager
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""检索策略初始化器"""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
from .base import ComponentInitializer
|
|
5
|
+
from ..retrieval import RetrievalFactory
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RetrievalInitializer(ComponentInitializer):
|
|
9
|
+
"""检索策略初始化器"""
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def name(self) -> str:
|
|
13
|
+
return "retrieval"
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def dependencies(self):
|
|
17
|
+
return ["storage"] # 依赖 storage,因为需要注入到 storage 中
|
|
18
|
+
|
|
19
|
+
async def initialize(self, context: Dict[str, Any]) -> Any:
|
|
20
|
+
"""初始化检索策略"""
|
|
21
|
+
retrieval_config = self.config.get_retrieval_config()
|
|
22
|
+
retrieval = RetrievalFactory.create(
|
|
23
|
+
retrieval_config["strategy"],
|
|
24
|
+
retrieval_config.get("strategy_config")
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# 注入 retrieval_strategy 到 storage(用于语义去重)
|
|
28
|
+
storage = self._get_component(context, "storage")
|
|
29
|
+
if storage:
|
|
30
|
+
storage.retrieval_strategy = retrieval
|
|
31
|
+
|
|
32
|
+
return retrieval
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""存储后端初始化器"""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
from .base import ComponentInitializer
|
|
5
|
+
from ..storage import StorageFactory
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class StorageInitializer(ComponentInitializer):
|
|
9
|
+
"""存储后端初始化器"""
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def name(self) -> str:
|
|
13
|
+
return "storage"
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def dependencies(self):
|
|
17
|
+
return [] # 无依赖
|
|
18
|
+
|
|
19
|
+
async def initialize(self, context: Dict[str, Any]) -> Any:
|
|
20
|
+
"""初始化存储后端"""
|
|
21
|
+
storage_config = self.config.get_storage_config()
|
|
22
|
+
return StorageFactory.create(storage_config)
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""MCP 工具初始化器"""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
from .base import ComponentInitializer
|
|
5
|
+
from ..tools import RetrieveMemoryTool, ExtractMemoryTool
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ToolsInitializer(ComponentInitializer):
|
|
9
|
+
"""MCP 工具初始化器"""
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def name(self) -> str:
|
|
13
|
+
return "tools"
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def dependencies(self):
|
|
17
|
+
# tools 依赖所有其他组件
|
|
18
|
+
return ["storage", "llm", "embedding", "retrieval", "memory_manager"]
|
|
19
|
+
|
|
20
|
+
async def initialize(self, context: Dict[str, Any]) -> Any:
|
|
21
|
+
"""初始化 MCP 工具"""
|
|
22
|
+
# 获取依赖组件
|
|
23
|
+
storage = self._get_component(context, "storage")
|
|
24
|
+
llm = self._get_component(context, "llm")
|
|
25
|
+
embedding = self._get_component(context, "embedding")
|
|
26
|
+
retrieval = self._get_component(context, "retrieval")
|
|
27
|
+
memory_manager = self._get_component(context, "memory_manager")
|
|
28
|
+
|
|
29
|
+
# 创建工具实例
|
|
30
|
+
retrieve_tool = RetrieveMemoryTool(
|
|
31
|
+
self.config,
|
|
32
|
+
storage,
|
|
33
|
+
embedding,
|
|
34
|
+
retrieval
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
extract_tool = ExtractMemoryTool(
|
|
38
|
+
self.config,
|
|
39
|
+
storage,
|
|
40
|
+
llm,
|
|
41
|
+
embedding,
|
|
42
|
+
memory_manager
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
"retrieve_tool": retrieve_tool,
|
|
47
|
+
"extract_tool": extract_tool
|
|
48
|
+
}
|
src/llm/__init__.py
ADDED
src/llm/base.py
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""LLM Provider 抽象基类"""
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from typing import List, Dict, Any
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class LLMProvider(ABC):
|
|
7
|
+
"""LLM 聊天接口抽象基类"""
|
|
8
|
+
|
|
9
|
+
@abstractmethod
|
|
10
|
+
async def chat(
|
|
11
|
+
self,
|
|
12
|
+
messages: List[Dict[str, str]],
|
|
13
|
+
temperature: float = 0.7,
|
|
14
|
+
max_tokens: int = 4096,
|
|
15
|
+
**kwargs
|
|
16
|
+
) -> str:
|
|
17
|
+
"""
|
|
18
|
+
聊天完成接口
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
messages: 消息列表 [{"role": "user", "content": "..."}, ...]
|
|
22
|
+
temperature: 采样温度
|
|
23
|
+
max_tokens: 最大生成 token 数
|
|
24
|
+
**kwargs: 其他参数
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
生成的文本
|
|
28
|
+
"""
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
@abstractmethod
|
|
32
|
+
def get_provider_name(self) -> str:
|
|
33
|
+
"""返回 Provider 名称"""
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class EmbeddingProvider(ABC):
|
|
38
|
+
"""Embedding 接口抽象基类"""
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
async def embed(self, text: str) -> List[float]:
|
|
42
|
+
"""
|
|
43
|
+
文本嵌入接口
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
text: 输入文本
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
嵌入向量
|
|
50
|
+
"""
|
|
51
|
+
pass
|
|
52
|
+
|
|
53
|
+
@abstractmethod
|
|
54
|
+
def get_provider_name(self) -> str:
|
|
55
|
+
"""返回 Provider 名称"""
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
@abstractmethod
|
|
59
|
+
def get_embedding_dim(self) -> int:
|
|
60
|
+
"""返回嵌入维度"""
|
|
61
|
+
pass
|