Merge remote-tracking branch 'origin/develop' into refactor/memory-config-management

This commit is contained in:
Ke Sun
2025-12-24 16:07:27 +08:00
24 changed files with 365 additions and 202 deletions

View File

@@ -131,6 +131,18 @@ def main():
# Get MCP port from environment (default: 8081)
mcp_port = int(os.getenv("MCP_PORT", "8081"))
logger.info(f"Starting MCP server on {settings.SERVER_IP}:{mcp_port} with SSE transport")
# Configure DNS rebinding protection for Docker container compatibility
from mcp.server.fastmcp.server import TransportSecuritySettings
# Disable DNS rebinding protection to allow Docker container hostnames
# This allows containers to connect using service names like 'mcp-server'
mcp.settings.transport_security = TransportSecuritySettings(
enable_dns_rebinding_protection=False,
)
logger.info("DNS rebinding protection: disabled for Docker container compatibility")
# logger.info(f"Starting MCP server on {settings.SERVER_IP}:{mcp_port} with SSE transport")
# Run the server with SSE transport for HTTP connections

View File

@@ -50,9 +50,7 @@
"entity2_name": "用户",
"entity2": {
"description": "叙述者,讲述个人工作与生活经历的个体",
"statement_id": "62beac695b1346f4871740a45db88782",
"name": "用户",
"id": "3d3896797b334572a80d57590026063d"
"name": "用户"
}
},
{
@@ -62,9 +60,7 @@
"entity2_name": "身份信息",
"entity2": {
"description": "用于个人身份识别的数据",
"statement_id": "030afd362e9b4110b139e68e5d3e7143",
"name": "身份信息",
"id": "aa766a517e82490599a9b3af54cfd933"
"name": "身份信息"
}
},
{
@@ -74,9 +70,7 @@
"entity2_name": "6222023847595898",
"entity2": {
"description": "用户的银行卡号码",
"statement_id": "6c7567cd1f3c478bb42d1b65383e6f2f",
"name": "6222023847595898",
"id": "610ba361918f4e68a65ce6ad06e5c7a0"
"name": "6222023847595898"
}
},
{
@@ -88,9 +82,7 @@
"entity_idx": 1,
"aliases": ["上海办"],
"description": "位于上海的工作办公场所",
"statement_id": "8b1b12e23b844b8088dfeb67da6ad669",
"name": "上海办公室",
"id": "fb702ef695c14e14af3e56786bc8815b"
"name": "上海办公室"
}
},
{
@@ -101,9 +93,7 @@
"entity2": {
"aliases": ["京", "京城", "北平"],
"description": "中国的首都城市,用户主要工作和生活所在地",
"statement_id": "62beac695b1346f4871740a45db88782",
"name": "北京",
"id": "81b2d1a571bb46a08a2d7a1e87efb945"
"name": "北京"
}
},
{
@@ -113,9 +103,7 @@
"entity2_name": "身份证号",
"entity2": {
"description": "中华人民共和国公民的身份号码",
"statement_id": "030afd362e9b4110b139e68e5d3e7143",
"name": "身份证号",
"id": "3e5f920645b2404fadb0e9ff60d1306e"
"name": "身份证号"
}
}
]

View File

@@ -269,8 +269,6 @@ class ReflectionEngine:
# # 检查是否真的有冲突
conflicts_found=''
# 记录冲突数据
await self._log_data("conflict", conflict_data)
conflicts_found=''
# 3. 解决冲突
solved_data = await self._resolve_conflicts(conflict_data, statement_databasets)
@@ -288,8 +286,6 @@ class ReflectionEngine:
conflicts_resolved = len(solved_data)
logging.info(f"解决了 {conflicts_resolved} 个冲突")
# 记录解决方案
await self._log_data("solved_data", solved_data)
# 4. 应用反思结果(更新记忆库)
memories_updated=await self._apply_reflection_results(solved_data)
@@ -390,14 +386,7 @@ class ReflectionEngine:
memory_verifies.append(item['memory_verify'])
result_data['memory_verifies'] = memory_verifies
result_data['quality_assessments'] = quality_assessments
# 检查是否真的有冲突
has_conflict = conflict_data[0].get('conflict', False)
conflicts_found = len(conflict_data[0]['data']) if has_conflict else 0
logging.info(f"冲突状态: {has_conflict}, 发现 {conflicts_found} 个冲突")
# 记录冲突数据
await self._log_data("conflict", conflict_data)
conflicts_found=''
# Clearn conflict_dataAnd memory_verify和quality_assessment
cleaned_conflict_data = []
@@ -407,6 +396,7 @@ class ReflectionEngine:
'conflict': item['conflict']
}
cleaned_conflict_data.append(cleaned_item)
# 3. 解决冲突
solved_data = await self._resolve_conflicts(cleaned_conflict_data, source_data)
if not solved_data:
@@ -645,26 +635,7 @@ class ReflectionEngine:
success_count = await neo4j_data(changes)
return success_count
async def _log_data(self, label: str, data: Any) -> None:
"""
记录数据到文件
Args:
label: 数据标签
data: 要记录的数据
"""
def _write():
try:
with open("reflexion_data.json", "a", encoding="utf-8") as f:
f.write(f"### {label} ###\n")
json.dump(data, f, ensure_ascii=False, indent=4)
f.write("\n\n")
except Exception as e:
logging.warning(f"记录数据失败: {e}")
# 在后台线程中执行写入,避免阻塞事件循环
await asyncio.to_thread(_write)
# 基于时间的反思方法
async def time_based_reflection(
@@ -753,4 +724,3 @@ class ReflectionEngine:
raise ValueError(f"未知的反思基线: {self.config.baseline}")

View File

@@ -17,10 +17,12 @@
- **日期属性冲突**: 同一人的生日等单值属性出现多值
- **先后约束违反**: 存在A→B约束但t(A)>t(B)(如入学>毕业)
- **互斥重叠**: 同一时间出现在不同地点等互斥事件
- **隐私审核**: 存在隐私信息也作为冲突输出当{{ memory_verify }}是true的时候
### 事实冲突
- **属性互斥**: 同一实体的相反属性(喜欢↔不喜欢)
- **关系矛盾**: 同一实体在相同语境下的不同关系描述
- **身份冲突**: 同一实体被赋予不同类型或角色
- **隐私审核**: 存在隐私信息也作为冲突输出当{{ memory_verify }}是true的时候
### 混合冲突
检测所有逻辑不一致或相互矛盾的记录。
**检测原则**:

View File

@@ -171,7 +171,6 @@
]
}
```
**输出要求**:
- 只输出JSON不添加解释文本
- 使用标准双引号,必要时转义

View File

@@ -7,7 +7,7 @@ from typing import List, Dict, Any
prompt_dir = os.path.join(os.path.dirname(__file__), "prompts")
prompt_env = Environment(loader=FileSystemLoader(prompt_dir))
async def render_evaluate_prompt(evaluate_data: List[Any], schema: Dict[str, Any],
async def render_evaluate_prompt(evaluate_data: List[Any], schema: Any,
baseline: str = "TIME",
memory_verify: bool = False,quality_assessment:bool = False,
statement_databasets: List[str] = [],language_type:str = "zh") -> str:
@@ -16,7 +16,7 @@ async def render_evaluate_prompt(evaluate_data: List[Any], schema: Dict[str, Any
Args:
evaluate_data: The data to evaluate
schema: The JSON schema to use for the output.
schema: The Pydantic model class or JSON schema to use for the output.
baseline: The baseline type for conflict detection (TIME/FACT/TIME-FACT)
memory_verify: Whether to enable memory verification for privacy detection
@@ -25,9 +25,17 @@ async def render_evaluate_prompt(evaluate_data: List[Any], schema: Dict[str, Any
"""
template = prompt_env.get_template("evaluate.jinja2")
# Convert Pydantic model to JSON schema if needed
if hasattr(schema, 'model_json_schema'):
json_schema = schema.model_json_schema()
elif hasattr(schema, 'schema'):
json_schema = schema.schema()
else:
json_schema = schema
rendered_prompt = template.render(
evaluate_data=evaluate_data,
json_schema=schema,
json_schema=json_schema,
baseline=baseline,
memory_verify=memory_verify,
quality_assessment=quality_assessment,
@@ -36,14 +44,15 @@ async def render_evaluate_prompt(evaluate_data: List[Any], schema: Dict[str, Any
)
return rendered_prompt
async def render_reflexion_prompt(data: Dict[str, Any], schema: Dict[str, Any], baseline: str, memory_verify: bool = False,
async def render_reflexion_prompt(data: Dict[str, Any], schema: Any, baseline: str, memory_verify: bool = False,
statement_databasets: List[str] = [],language_type:str = "zh") -> str:
"""
Renders the reflexion prompt using the reflexion_optimized.jinja2 template.
Args:
data: The data to reflex on.
schema: The JSON schema to use for the output.
schema: The Pydantic model class or JSON schema to use for the output.
baseline: The baseline type for conflict resolution.
Returns:
@@ -51,7 +60,15 @@ async def render_reflexion_prompt(data: Dict[str, Any], schema: Dict[str, Any],
"""
template = prompt_env.get_template("reflexion.jinja2")
rendered_prompt = template.render(data=data, json_schema=schema,
# Convert Pydantic model to JSON schema if needed
if hasattr(schema, 'model_json_schema'):
json_schema = schema.model_json_schema()
elif hasattr(schema, 'schema'):
json_schema = schema.schema()
else:
json_schema = schema
rendered_prompt = template.render(data=data, json_schema=json_schema,
baseline=baseline,memory_verify=memory_verify,
statement_databasets=statement_databasets,language_type=language_type)