hy-memory 1.0.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.
Files changed (88) hide show
  1. hy_memory/__init__.py +146 -0
  2. hy_memory/agent/__init__.py +99 -0
  3. hy_memory/agent/abstractor.py +300 -0
  4. hy_memory/agent/emotion_analyzer.py +284 -0
  5. hy_memory/agent/extractor.py +558 -0
  6. hy_memory/agent/intention_detector.py +328 -0
  7. hy_memory/agent/llm_provider.py +606 -0
  8. hy_memory/agent/mem_agent.py +377 -0
  9. hy_memory/agent/prompts_zh.py +316 -0
  10. hy_memory/agent/reconciler.py +999 -0
  11. hy_memory/agent/reflector.py +480 -0
  12. hy_memory/agent/summarizer.py +169 -0
  13. hy_memory/agent/tools/__init__.py +43 -0
  14. hy_memory/agent/tools/base.py +237 -0
  15. hy_memory/agent/tools/basic_profile.py +388 -0
  16. hy_memory/client.py +2238 -0
  17. hy_memory/config.py +675 -0
  18. hy_memory/core/__init__.py +20 -0
  19. hy_memory/core/embed_service.py +395 -0
  20. hy_memory/core/merger.py +324 -0
  21. hy_memory/core/scorer.py +254 -0
  22. hy_memory/data/__init__.py +50 -0
  23. hy_memory/data/cache.py +77 -0
  24. hy_memory/data/cache_base.py +285 -0
  25. hy_memory/data/cache_disabled.py +259 -0
  26. hy_memory/data/cache_memory.py +413 -0
  27. hy_memory/data/cache_redis.py +836 -0
  28. hy_memory/data/cache_sqlite.py +892 -0
  29. hy_memory/data/graph_store.py +57 -0
  30. hy_memory/data/graph_store_base.py +336 -0
  31. hy_memory/data/graph_store_kuzu.py +1374 -0
  32. hy_memory/data/graph_store_neo4j.py +1185 -0
  33. hy_memory/data/history_store.py +362 -0
  34. hy_memory/data/kv_store.py +357 -0
  35. hy_memory/data/rdb.py +193 -0
  36. hy_memory/data/storage_interface.py +432 -0
  37. hy_memory/data/vector_store.py +63 -0
  38. hy_memory/data/vector_store_base.py +374 -0
  39. hy_memory/data/vector_store_chroma.py +529 -0
  40. hy_memory/data/vector_store_faiss.py +553 -0
  41. hy_memory/data/vector_store_qdrant.py +837 -0
  42. hy_memory/inspector.py +445 -0
  43. hy_memory/models/__init__.py +178 -0
  44. hy_memory/models/memory.py +1213 -0
  45. hy_memory/models/requests.py +745 -0
  46. hy_memory/pipelines/__init__.py +49 -0
  47. hy_memory/pipelines/_retrieval/__init__.py +15 -0
  48. hy_memory/pipelines/_retrieval/bm25.py +115 -0
  49. hy_memory/pipelines/_retrieval/config.py +133 -0
  50. hy_memory/pipelines/_retrieval/evolution.py +242 -0
  51. hy_memory/pipelines/_retrieval/intent.py +155 -0
  52. hy_memory/pipelines/_retrieval/rrf.py +94 -0
  53. hy_memory/pipelines/_retrieval/tag_index.py +199 -0
  54. hy_memory/pipelines/_retrieval/trace.py +639 -0
  55. hy_memory/pipelines/base.py +373 -0
  56. hy_memory/pipelines/cross_domain_sweeper.py +679 -0
  57. hy_memory/pipelines/lite/_retrieval/__init__.py +15 -0
  58. hy_memory/pipelines/lite/_retrieval/bm25.py +115 -0
  59. hy_memory/pipelines/lite/_retrieval/config.py +132 -0
  60. hy_memory/pipelines/lite/_retrieval/evolution.py +242 -0
  61. hy_memory/pipelines/lite/_retrieval/intent.py +155 -0
  62. hy_memory/pipelines/lite/_retrieval/rrf.py +94 -0
  63. hy_memory/pipelines/lite/_retrieval/tag_index.py +199 -0
  64. hy_memory/pipelines/lite/_retrieval/trace.py +484 -0
  65. hy_memory/pipelines/lite/reader_hybrid.py +574 -0
  66. hy_memory/pipelines/lite/reader_hybrid_tag.py +467 -0
  67. hy_memory/pipelines/lite/reader_legacy.py +498 -0
  68. hy_memory/pipelines/reader.py +112 -0
  69. hy_memory/pipelines/reader_exhaustive.py +620 -0
  70. hy_memory/pipelines/reader_hybrid.py +574 -0
  71. hy_memory/pipelines/reader_hybrid_tag.py +467 -0
  72. hy_memory/pipelines/reader_legacy.py +793 -0
  73. hy_memory/pipelines/registry.py +190 -0
  74. hy_memory/pipelines/system2_agent.py +801 -0
  75. hy_memory/pipelines/system2_tools.py +466 -0
  76. hy_memory/pipelines/system2_writer.py +697 -0
  77. hy_memory/pipelines/writer.py +1057 -0
  78. hy_memory/server.py +375 -0
  79. hy_memory/utils/lang_detect.py +165 -0
  80. hy_memory/utils/log_setup.py +170 -0
  81. hy_memory/utils/metrics.py +270 -0
  82. hy_memory/utils/time_window.py +169 -0
  83. hy_memory/utils/tracer.py +381 -0
  84. hy_memory-1.0.0.dist-info/METADATA +136 -0
  85. hy_memory-1.0.0.dist-info/RECORD +88 -0
  86. hy_memory-1.0.0.dist-info/WHEEL +5 -0
  87. hy_memory-1.0.0.dist-info/licenses/LICENSE +21 -0
  88. hy_memory-1.0.0.dist-info/top_level.txt +1 -0
hy_memory/__init__.py ADDED
@@ -0,0 +1,146 @@
1
+ """
2
+ HY Memory - 核心 SDK
3
+
4
+ 工业级智能体记忆系统核心框架。
5
+
6
+ 快速开始:
7
+ export OPENAI_API_KEY="sk-your-key-here"
8
+
9
+ from hy_memory import HyMemoryClient
10
+
11
+ # 最简用法 — 只需设置 OPENAI_API_KEY 环境变量
12
+ client = HyMemoryClient(user_id="test_user")
13
+ client.add("用户喜欢科幻电影")
14
+ results = client.search("用户喜欢什么?")
15
+ client.close()
16
+
17
+ 默认配置:
18
+ - embedder: OpenAI text-embedding-3-small (1536 维)
19
+ - llm: OpenAI gpt-4.1-nano
20
+ - vector_store: Chroma 本地嵌入式 (零外部依赖)
21
+
22
+ 只需设置 OPENAI_API_KEY 环境变量即可运行。
23
+
24
+ # 自定义配置
25
+ client = HyMemoryClient.from_config({
26
+ "vector_store": {"provider": "qdrant"},
27
+ "graph_store": {
28
+ "provider": "neo4j",
29
+ "url": "bolt://localhost:7687",
30
+ "username": "neo4j",
31
+ "password": "password",
32
+ },
33
+ "enable_graph": True,
34
+ }, user_id="test_user")
35
+
36
+ 数据隔离 (两级):
37
+ - user_id: 一级 key — 每个用户唯一的记忆库
38
+ - agent_id: 二级 key — 同一用户下不同 Agent 场景的隔离
39
+
40
+ 安装方式:
41
+ pip install hy-memory # 核心依赖 (含 Chroma,开箱即用)
42
+ pip install hy-memory[qdrant] # + Qdrant 向量库
43
+ pip install hy-memory[faiss] # + FAISS 向量库
44
+ pip install hy-memory[all] # 包含所有可选依赖
45
+ """
46
+
47
+ try:
48
+ from importlib.metadata import version as _get_version
49
+ __version__ = _get_version("hy-memory")
50
+ except Exception:
51
+ __version__ = "1.0.0"
52
+
53
+ # ====== 用户级 API(推荐) ======
54
+ from .client import HyMemoryClient
55
+ from .inspector import MemoryInspector
56
+
57
+ # ====== 配置 ======
58
+ from .config import MemoryConfig
59
+
60
+ # ====== 高级 API(按需使用) ======
61
+ from .pipelines import (
62
+ ComponentFactory,
63
+ PipelineConfig,
64
+ WritePipeline,
65
+ ReadPipeline,
66
+ ChatMessage,
67
+ WriteRequest,
68
+ WriteResponse,
69
+ ReadRequest,
70
+ ReadResponse,
71
+ )
72
+
73
+ # ====== 数据模型 ======
74
+ from .models import (
75
+ MemoryLayer,
76
+ MemoryNode,
77
+ MemoryEntry,
78
+ MemoryMetadata,
79
+ MemoryScore,
80
+ MemoryInputType,
81
+ AgentProcessMode,
82
+ TaskStatus,
83
+ DeleteScope,
84
+ QAPair,
85
+ AddRequest,
86
+ AddResponse,
87
+ AsyncAddResponse,
88
+ RecallRequest,
89
+ RecallResponse,
90
+ UpdateRequest,
91
+ UpdateResponse,
92
+ DeleteRequest,
93
+ DeleteResponse,
94
+ BatchDeleteRequest,
95
+ BatchDeleteResponse,
96
+ GetRequest,
97
+ GetResponse,
98
+ ListRequest,
99
+ ListResponse,
100
+ )
101
+
102
+
103
+ __all__ = [
104
+ "__version__",
105
+ # 用户级 API
106
+ "HyMemoryClient",
107
+ "MemoryInspector",
108
+ # 配置
109
+ "MemoryConfig",
110
+ # 高级 API
111
+ "ComponentFactory",
112
+ "PipelineConfig",
113
+ "WritePipeline",
114
+ "ReadPipeline",
115
+ "ChatMessage",
116
+ "WriteRequest",
117
+ "WriteResponse",
118
+ "ReadRequest",
119
+ "ReadResponse",
120
+ # 数据模型
121
+ "MemoryLayer",
122
+ "MemoryNode",
123
+ "MemoryEntry",
124
+ "MemoryMetadata",
125
+ "MemoryScore",
126
+ "MemoryInputType",
127
+ "AgentProcessMode",
128
+ "TaskStatus",
129
+ "DeleteScope",
130
+ "QAPair",
131
+ "AddRequest",
132
+ "AddResponse",
133
+ "AsyncAddResponse",
134
+ "RecallRequest",
135
+ "RecallResponse",
136
+ "UpdateRequest",
137
+ "UpdateResponse",
138
+ "DeleteRequest",
139
+ "DeleteResponse",
140
+ "BatchDeleteRequest",
141
+ "BatchDeleteResponse",
142
+ "GetRequest",
143
+ "GetResponse",
144
+ "ListRequest",
145
+ "ListResponse",
146
+ ]
@@ -0,0 +1,99 @@
1
+ """
2
+ Agent Memory - 智能层 (Agent Layer)
3
+
4
+ 基于 LLM 的智能处理能力,提供语义理解、信息提取、推理判断等功能。
5
+ 该层是可选的,关闭后系统仍能正常工作。
6
+
7
+ 包含模块:
8
+ - MemAgent: 智能体协调器,统一入口
9
+ - Summarizer: Lite+Agent pipeline 摘要生成器 (L3_SUMMARY)
10
+ - Abstractor: System 2 全量摘要智能体 (Session摘要/Schema归纳/Profile摘要)
11
+ - Extractor: 提取智能体,提取结构化信息 (V2: 轻量提取/深度提取双模式)
12
+ - Reflector: 反思智能体,检测冲突和更新 (V2: UpdateType分类/冲突检测/隐式推断)
13
+ - EmotionAnalyzer: 情绪分析智能体,valence + arousal 双维标注
14
+ - IntentionDetector: 意图检测智能体,前瞻性记忆 + 主动关怀
15
+ - LLMProvider: LLM 提供器,统一的模型调用接口
16
+ """
17
+
18
+ # Lite+Agent pipeline
19
+ from .mem_agent import MemAgent, AgentResult, ProcessMode
20
+ from .summarizer import Summarizer, SummaryResult
21
+ from .extractor import Extractor, ExtractResult
22
+ from .reflector import Reflector, ReflectResult, ConflictType, ConflictAction
23
+ from .llm_provider import LLMProvider, LLMResponse, LLMConfig, LLMBackend
24
+
25
+ # V2 Extractor
26
+ from .extractor import ExtractMode, V2ExtractResult
27
+
28
+ # System 2 / Pro Pipeline Abstractor
29
+ from .abstractor import Abstractor, SessionSummaryResult, SchemaAbstractResult, ProfileSummaryResult
30
+
31
+ # V2 Reflector
32
+ from .reflector import (
33
+ V2ConflictType,
34
+ UpdateTypeResult,
35
+ ConflictDetectionResult,
36
+ ImplicitSignal,
37
+ ImplicitInferenceResult,
38
+ )
39
+
40
+ # V2 Emotion Analyzer
41
+ from .emotion_analyzer import EmotionAnalyzer, EmotionAnalysisConfig, EmotionResult
42
+
43
+ # V2 Intention Detector
44
+ from .intention_detector import (
45
+ IntentionDetector,
46
+ IntentionDetectorConfig,
47
+ DetectedIntention,
48
+ IntentionDetectResult,
49
+ TriggeredIntentionItem,
50
+ IntentionTriggerResult,
51
+ )
52
+
53
+ __all__ = [
54
+ # MemAgent
55
+ "MemAgent",
56
+ "AgentResult",
57
+ "ProcessMode",
58
+ # Summarizer (Lite+Agent)
59
+ "Summarizer",
60
+ "SummaryResult",
61
+ # Abstractor (System 2)
62
+ "Abstractor",
63
+ "SessionSummaryResult",
64
+ "SchemaAbstractResult",
65
+ "ProfileSummaryResult",
66
+ # Extractor (V1)
67
+ "Extractor",
68
+ "ExtractResult",
69
+ # Extractor (V2)
70
+ "ExtractMode",
71
+ "V2ExtractResult",
72
+ # Reflector (V1)
73
+ "Reflector",
74
+ "ReflectResult",
75
+ "ConflictType",
76
+ "ConflictAction",
77
+ # Reflector (V2)
78
+ "V2ConflictType",
79
+ "UpdateTypeResult",
80
+ "ConflictDetectionResult",
81
+ "ImplicitSignal",
82
+ "ImplicitInferenceResult",
83
+ # Emotion Analyzer (V2)
84
+ "EmotionAnalyzer",
85
+ "EmotionAnalysisConfig",
86
+ "EmotionResult",
87
+ # Intention Detector (V2)
88
+ "IntentionDetector",
89
+ "IntentionDetectorConfig",
90
+ "DetectedIntention",
91
+ "IntentionDetectResult",
92
+ "TriggeredIntentionItem",
93
+ "IntentionTriggerResult",
94
+ # LLMProvider
95
+ "LLMProvider",
96
+ "LLMResponse",
97
+ "LLMConfig",
98
+ "LLMBackend",
99
+ ]
@@ -0,0 +1,300 @@
1
+ """
2
+ Agent Memory V2 - Abstractor 摘要智能体 (System 2 Pro Pipeline)
3
+
4
+ 负责 System 2 pro pipeline 的高阶摘要能力:
5
+ 1. Session 摘要生成 (L3 层 — System 2 Sleep Replay 调用)
6
+ 2. Schema 归纳 (L5 层 — System 2 Schema Miner 调用)
7
+ 3. Profile 摘要生成 (Context Assembly 调用)
8
+
9
+ 注意:lite+agent pipeline 的 L3_SUMMARY 生成由 summarizer.py 的 Summarizer 负责。
10
+ """
11
+
12
+ from typing import Dict, Any, Optional, List
13
+ from dataclasses import dataclass, field
14
+ import json
15
+ import logging
16
+
17
+ from .llm_provider import LLMProvider
18
+ from ..config import LLMConfig as GlobalLLMConfig
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ # ================================================================
24
+ # 数据结构
25
+ # ================================================================@dataclass
26
+ class SessionSummaryResult:
27
+ """Session 摘要结果 (V2)"""
28
+ success: bool
29
+ summary: str = ""
30
+ key_topics: List[str] = field(default_factory=list)
31
+ emotional_tone: str = ""
32
+ new_facts_count: int = 0
33
+ tokens_used: int = 0
34
+ error: Optional[str] = None
35
+
36
+
37
+ @dataclass
38
+ class SchemaAbstractResult:
39
+ """Schema 归纳结果 (V2)"""
40
+ success: bool
41
+ central_proposition: str = ""
42
+ supporting_summary: str = ""
43
+ expected_inferences: List[str] = field(default_factory=list)
44
+ confidence: float = 0.0
45
+ tokens_used: int = 0
46
+ error: Optional[str] = None
47
+
48
+
49
+ @dataclass
50
+ class ProfileSummaryResult:
51
+ """Profile 摘要结果 (V2)"""
52
+ success: bool
53
+ core: str = ""
54
+ personality: str = ""
55
+ active_schemas: List[str] = field(default_factory=list)
56
+ gotchas: List[str] = field(default_factory=list)
57
+ note: str = ""
58
+ tokens_used: int = 0
59
+ error: Optional[str] = None
60
+
61
+
62
+ # ================================================================
63
+ # Prompt 模板
64
+ # ================================================================
65
+
66
+ SESSION_SUMMARY_PROMPT = """Generate a summary of the following conversation session. The summary language MUST match the conversation language.
67
+
68
+ Session content:
69
+ ---
70
+ {session_content}
71
+ ---
72
+
73
+ Existing user profile:
74
+ {user_profile}
75
+
76
+ Current time: {current_time}
77
+
78
+ Output in JSON format:
79
+ {{
80
+ "summary": "A brief session summary (max 200 words, in the same language as the conversation)",
81
+ "key_topics": ["key topic 1", "topic 2"],
82
+ "emotional_tone": "overall emotional tone (e.g., positive/neutral/anxious/happy)",
83
+ "new_facts_count": 0
84
+ }}"""
85
+
86
+ SCHEMA_ABSTRACT_PROMPT = """Below is a set of related facts mentioned by the user across multiple sessions. Induce an abstract "mental model" (Schema).
87
+
88
+ Related facts:
89
+ {facts}
90
+
91
+ A good Schema should:
92
+ - Describe a recurring behavioral pattern or thinking style of the user
93
+ - Not be a simple enumeration of facts, but an abstract pattern
94
+ - Help predict how the user would react in similar situations
95
+
96
+ Output in JSON format:
97
+ {{
98
+ "central_proposition": "core proposition (one sentence describing this pattern)",
99
+ "supporting_summary": "evidence overview (why you believe this pattern exists)",
100
+ "expected_inferences": ["expected inference based on this pattern 1", "inference 2"],
101
+ "confidence": 0.0-1.0
102
+ }}"""
103
+
104
+ PROFILE_SUMMARY_PROMPT = """Generate a structured user profile summary based on the following data. The summary language MUST match the profile data language.
105
+
106
+ Profile data:
107
+ {profile_data}
108
+
109
+ Active mental models:
110
+ {active_schemas}
111
+
112
+ Known gotchas/notes:
113
+ {gotchas}
114
+
115
+ Output in JSON format:
116
+ {{
117
+ "core": "core description (e.g., name, age, location, occupation)",
118
+ "personality": "personality/style description (e.g., pragmatic, tech-oriented)",
119
+ "active_schemas": ["active behavioral patterns"],
120
+ "gotchas": ["gotchas/safety notes to be aware of"],
121
+ "note": "other notes"
122
+ }}"""
123
+
124
+
125
+ # ================================================================
126
+ # 核心实现
127
+ # ================================================================
128
+
129
+ class Abstractor:
130
+ """
131
+ 摘要智能体 (System 2 Pro Pipeline)
132
+
133
+ 负责 System 2 的高阶摘要:Session 摘要 / Schema 归纳 / Profile 摘要。
134
+ lite+agent pipeline 的 L3_SUMMARY 由 Summarizer(summarizer.py)负责。
135
+ """
136
+
137
+ def __init__(
138
+ self,
139
+ llm_provider: LLMProvider,
140
+ llm_config: Optional[GlobalLLMConfig] = None,
141
+ ):
142
+ self.llm = llm_provider
143
+ self._llm_config = llm_config or GlobalLLMConfig()
144
+ self._call_count = 0
145
+ self._total_tokens = 0
146
+ logger.debug("Abstractor initialized")
147
+
148
+ async def generate_session_summary(
149
+ self,
150
+ session_content: str,
151
+ user_profile: str = "",
152
+ current_time: str = "", # 由调用方传入,不传则为空字符串
153
+ ) -> SessionSummaryResult:
154
+ """
155
+ 生成 Session 摘要 (L3 层)。
156
+ 由 System 2 Sleep Replay Worker 调用。
157
+ """
158
+ try:
159
+ prompt = SESSION_SUMMARY_PROMPT.format(
160
+ session_content=session_content,
161
+ user_profile=user_profile or "(暂无画像)",
162
+ current_time=current_time, # 由调用方决定,不传则为空字符串
163
+ )
164
+ response = await self.llm.complete(
165
+ prompt=prompt,
166
+ max_tokens=self._llm_config.agent_max_tokens,
167
+ temperature=0.3,
168
+ )
169
+ self._call_count += 1
170
+ self._total_tokens += response.tokens_used
171
+
172
+ data = self._parse_json(response.content)
173
+
174
+ return SessionSummaryResult(
175
+ success=True,
176
+ summary=data.get("summary", response.content.strip()),
177
+ key_topics=data.get("key_topics", []),
178
+ emotional_tone=data.get("emotional_tone", "中性"),
179
+ new_facts_count=data.get("new_facts_count", 0),
180
+ tokens_used=response.tokens_used,
181
+ )
182
+ except Exception as e:
183
+ logger.error(f"generate_session_summary failed: {e}")
184
+ return SessionSummaryResult(success=False, error=str(e))
185
+
186
+ # ================================================================
187
+ # V2 Schema 归纳 (L4.5)
188
+ # ================================================================
189
+
190
+ async def abstract_schema(
191
+ self,
192
+ facts: List[str],
193
+ ) -> SchemaAbstractResult:
194
+ """
195
+ 从一组关联事实中归纳 Schema (心智模型)。
196
+ 由 System 2 Schema Miner 调用。
197
+ """
198
+ try:
199
+ facts_text = "\n".join(f" - {f}" for f in facts)
200
+ prompt = SCHEMA_ABSTRACT_PROMPT.format(facts=facts_text)
201
+
202
+ response = await self.llm.complete(
203
+ prompt=prompt,
204
+ max_tokens=self._llm_config.agent_max_tokens,
205
+ temperature=0.4,
206
+ )
207
+ self._call_count += 1
208
+ self._total_tokens += response.tokens_used
209
+
210
+ data = self._parse_json(response.content)
211
+
212
+ return SchemaAbstractResult(
213
+ success=True,
214
+ central_proposition=data.get("central_proposition", ""),
215
+ supporting_summary=data.get("supporting_summary", ""),
216
+ expected_inferences=data.get("expected_inferences", []),
217
+ confidence=float(data.get("confidence", 0.5)),
218
+ tokens_used=response.tokens_used,
219
+ )
220
+ except Exception as e:
221
+ logger.error(f"abstract_schema failed: {e}")
222
+ return SchemaAbstractResult(success=False, error=str(e))
223
+
224
+ # ================================================================
225
+ # V2 Profile 摘要 (L5)
226
+ # ================================================================
227
+
228
+ async def generate_profile_summary(
229
+ self,
230
+ profile_data: str,
231
+ active_schemas: str = "",
232
+ gotchas: str = "",
233
+ ) -> ProfileSummaryResult:
234
+ """
235
+ 生成 Profile 摘要,用于 Memory Context Package 的 Layer 0。
236
+ 由 Context Assembly 调用。
237
+ """
238
+ try:
239
+ prompt = PROFILE_SUMMARY_PROMPT.format(
240
+ profile_data=profile_data or "(暂无画像数据)",
241
+ active_schemas=active_schemas or "(无)",
242
+ gotchas=gotchas or "(无)",
243
+ )
244
+ response = await self.llm.complete(
245
+ prompt=prompt,
246
+ max_tokens=self._llm_config.agent_max_tokens,
247
+ temperature=0.2,
248
+ )
249
+ self._call_count += 1
250
+ self._total_tokens += response.tokens_used
251
+
252
+ data = self._parse_json(response.content)
253
+
254
+ return ProfileSummaryResult(
255
+ success=True,
256
+ core=data.get("core", ""),
257
+ personality=data.get("personality", ""),
258
+ active_schemas=data.get("active_schemas", []),
259
+ gotchas=data.get("gotchas", []),
260
+ note=data.get("note", ""),
261
+ tokens_used=response.tokens_used,
262
+ )
263
+ except Exception as e:
264
+ logger.error(f"generate_profile_summary failed: {e}")
265
+ return ProfileSummaryResult(success=False, error=str(e))
266
+
267
+ # ================================================================
268
+ # 工具方法
269
+ # ================================================================
270
+
271
+ @staticmethod
272
+ def _parse_json(text: str) -> Dict[str, Any]:
273
+ """从 LLM 输出中解析 JSON"""
274
+ text = text.strip()
275
+ if "```json" in text:
276
+ text = text.split("```json")[1].split("```")[0].strip()
277
+ elif "```" in text:
278
+ text = text.split("```")[1].split("```")[0].strip()
279
+ try:
280
+ return json.loads(text)
281
+ except json.JSONDecodeError:
282
+ import re
283
+ match = re.search(r'\{[\s\S]*\}', text)
284
+ if match:
285
+ try:
286
+ return json.loads(match.group())
287
+ except json.JSONDecodeError:
288
+ pass
289
+ return {}
290
+
291
+ def get_stats(self) -> Dict[str, Any]:
292
+ """获取统计信息"""
293
+ return {
294
+ "call_count": self._call_count,
295
+ "total_tokens": self._total_tokens,
296
+ "avg_tokens_per_call": (
297
+ self._total_tokens / self._call_count
298
+ if self._call_count > 0 else 0
299
+ ),
300
+ }