Browse Source

循环游走

丁云鹏 1 day ago
parent
commit
4aeb0b75d5

+ 1 - 0
.gitignore

@@ -54,6 +54,7 @@ debug.log
 info.log
 .cache
 output
+.logs
 
 
 

+ 1 - 1
examples/create/config.py

@@ -47,4 +47,4 @@ SKILLS_DIR = "./skills"
 TRACE_STORE_PATH = ".trace"
 DEBUG = True
 LOG_LEVEL = "INFO"
-LOG_FILE = None  # 设置为文件路径可以同时输出到文件
+LOG_FILE = ".logs/log"  # 设置为文件路径可以同时输出到文件

+ 2 - 3
examples/create/presets.json

@@ -5,9 +5,8 @@
     "skills": [
       "core",
       "planning",
-      "research",
-      "browser",
-      "topic_search"
+      "search_point_by_element_from_full_all_levels",
+      "search_point_by_path_from_full_all_levels"
     ],
     "description": "默认 Agent,拥有全部工具权限"
   }

+ 141 - 140
examples/create/run.py

@@ -15,10 +15,13 @@ import os
 import sys
 from pathlib import Path
 from typing import Any
+import logging
 
 # Clash Verge TUN 模式兼容:禁止 httpx/urllib 自动检测系统 HTTP 代理
 os.environ.setdefault("no_proxy", "*")
 
+logger = logging.getLogger(__name__)
+
 # 添加项目根目录到 Python 路径
 sys.path.insert(0, str(Path(__file__).parent.parent.parent))
 
@@ -49,24 +52,24 @@ def _format_json(obj: Any, indent: int = 2) -> str:
 
 def _print_message_details(message: Message):
     """完整打印消息的详细信息"""
-    print("\n" + "=" * 80)
-    print(f"[Message #{message.sequence}] {message.role.upper()}")
-    print("=" * 80)
+    logger.info("\n" + "=" * 80)
+    logger.info(f"[Message #{message.sequence}] {message.role.upper()}")
+    logger.info("=" * 80)
 
     if message.goal_id:
-        print(f"Goal ID: {message.goal_id}")
+        logger.info(f"Goal ID: {message.goal_id}")
     if message.parent_sequence is not None:
-        print(f"Parent Sequence: {message.parent_sequence}")
+        logger.info(f"Parent Sequence: {message.parent_sequence}")
     if message.tool_call_id:
-        print(f"Tool Call ID: {message.tool_call_id}")
+        logger.info(f"Tool Call ID: {message.tool_call_id}")
 
     if message.role == "user":
-        print("\n[输入内容]")
-        print("-" * 80)
+        logger.info("\n[输入内容]")
+        logger.info("-" * 80)
         if isinstance(message.content, str):
-            print(message.content)
+            logger.info(message.content)
         else:
-            print(_format_json(message.content))
+            logger.info(_format_json(message.content))
     elif message.role == "assistant":
         content = message.content
         if isinstance(content, dict):
@@ -74,93 +77,93 @@ def _print_message_details(message: Message):
             tool_calls = content.get("tool_calls")
 
             if text:
-                print("\n[LLM 文本回复]")
-                print("-" * 80)
-                print(text)
+                logger.info("\n[LLM 文本回复]")
+                logger.info("-" * 80)
+                logger.info(text)
 
             if tool_calls:
-                print(f"\n[工具调用] (共 {len(tool_calls)} 个)")
-                print("-" * 80)
+                logger.info(f"\n[工具调用] (共 {len(tool_calls)} 个)")
+                logger.info("-" * 80)
                 for idx, tc in enumerate(tool_calls, 1):
                     func = tc.get("function", {})
                     tool_name = func.get("name", "unknown")
                     tool_id = tc.get("id", "unknown")
                     arguments = func.get("arguments", {})
 
-                    print(f"\n工具 #{idx}: {tool_name}")
-                    print(f"  Call ID: {tool_id}")
-                    print("  参数:")
+                    logger.info(f"\n工具 #{idx}: {tool_name}")
+                    logger.info(f"  Call ID: {tool_id}")
+                    logger.info("  参数:")
                     if isinstance(arguments, str):
                         try:
                             parsed_args = json.loads(arguments)
-                            print(_format_json(parsed_args, indent=4))
+                            logger.info(_format_json(parsed_args, indent=4))
                         except json.JSONDecodeError:
-                            print(f"    {arguments}")
+                            logger.info(f"    {arguments}")
                     else:
-                        print(_format_json(arguments, indent=4))
+                        logger.info(_format_json(arguments, indent=4))
         elif isinstance(content, str):
-            print("\n[LLM 文本回复]")
-            print("-" * 80)
-            print(content)
+            logger.info("\n[LLM 文本回复]")
+            logger.info("-" * 80)
+            logger.info(content)
         else:
-            print("\n[内容]")
-            print("-" * 80)
-            print(_format_json(content))
+            logger.info("\n[内容]")
+            logger.info("-" * 80)
+            logger.info(_format_json(content))
 
         if message.finish_reason:
-            print(f"\n完成原因: {message.finish_reason}")
+            logger.info(f"\n完成原因: {message.finish_reason}")
     elif message.role == "tool":
         content = message.content
-        print("\n[工具执行结果]")
-        print("-" * 80)
+        logger.info("\n[工具执行结果]")
+        logger.info("-" * 80)
         if isinstance(content, dict):
             tool_name = content.get("tool_name", "unknown")
             result = content.get("result", content)
-            print(f"工具名称: {tool_name}")
-            print("\n返回结果:")
+            logger.info(f"工具名称: {tool_name}")
+            logger.info("\n返回结果:")
             if isinstance(result, str):
-                print(result)
+                logger.info(result)
             elif isinstance(result, list):
                 for idx, item in enumerate(result, 1):
                     if isinstance(item, dict) and item.get("type") == "image_url":
-                        print(f"  [{idx}] 图片 (base64, 已省略显示)")
+                        logger.info(f"  [{idx}] 图片 (base64, 已省略显示)")
                     else:
-                        print(f"  [{idx}] {item}")
+                        logger.info(f"  [{idx}] {item}")
             else:
-                print(_format_json(result))
+                logger.info(_format_json(result))
         else:
-            print(str(content) if content is not None else "(无内容)")
+            logger.info(str(content) if content is not None else "(无内容)")
     elif message.role == "system":
-        print("\n[系统提示]")
-        print("-" * 80)
+        logger.info("\n[系统提示]")
+        logger.info("-" * 80)
         if isinstance(message.content, str):
-            print(message.content)
+            logger.info(message.content)
         else:
-            print(_format_json(message.content))
+            logger.info(_format_json(message.content))
 
     if message.prompt_tokens is not None or message.completion_tokens is not None:
-        print("\n[Token 使用]")
-        print("-" * 80)
+        logger.info("\n[Token 使用]")
+        logger.info("-" * 80)
         if message.prompt_tokens is not None:
-            print(f"  输入 Tokens: {message.prompt_tokens:,}")
+            logger.info(f"  输入 Tokens: {message.prompt_tokens:,}")
         if message.completion_tokens is not None:
-            print(f"  输出 Tokens: {message.completion_tokens:,}")
+            logger.info(f"  输出 Tokens: {message.completion_tokens:,}")
         if message.reasoning_tokens is not None:
-            print(f"  推理 Tokens: {message.reasoning_tokens:,}")
+            logger.info(f"  推理 Tokens: {message.reasoning_tokens:,}")
         if message.cache_creation_tokens is not None:
-            print(f"  缓存创建 Tokens: {message.cache_creation_tokens:,}")
+            logger.info(f"  缓存创建 Tokens: {message.cache_creation_tokens:,}")
         if message.cache_read_tokens is not None:
-            print(f"  缓存读取 Tokens: {message.cache_read_tokens:,}")
+            logger.info(f"  缓存读取 Tokens: {message.cache_read_tokens:,}")
         if message.tokens:
-            print(f"  总计 Tokens: {message.tokens:,}")
+            logger.info(f"  总计 Tokens: {message.tokens:,}")
 
     if message.cost is not None:
-        print(f"\n[成本] ${message.cost:.6f}")
+        logger.info(f"\n[成本] ${message.cost:.6f}")
 
     if message.duration_ms is not None:
-        print(f"[执行时间] {message.duration_ms}ms")
+        logger.info(f"[执行时间] {message.duration_ms}ms")
 
-    print("=" * 80 + "\n")
+    logger.info("=" * 80 + "\n")
 
 
 def _apply_prompt_placeholders(base_dir: Path, prompt: SimplePrompt, persona_dir: str = None):
@@ -177,7 +180,7 @@ def _apply_prompt_placeholders(base_dir: Path, prompt: SimplePrompt, persona_dir
         if "system" in prompt._messages and "{system}" in prompt._messages["system"]:
             prompt._messages["system"] = prompt._messages["system"].replace("{system}", system_content)
     else:
-        print(f"   - 警告: system.md 文件不存在: {system_md_path}")
+        logger.warning(f"   - 警告: system.md 文件不存在: {system_md_path}")
 
     # 优先使用 v2 版本,如果不存在则使用原版本
     create_process_md_path = base_dir / "PRD" / "create_process_v2.md"
@@ -188,11 +191,11 @@ def _apply_prompt_placeholders(base_dir: Path, prompt: SimplePrompt, persona_dir
         create_process_content = create_process_md_path.read_text(encoding="utf-8")
         if "system" in prompt._messages and "{create_process}" in prompt._messages["system"]:
             prompt._messages["system"] = prompt._messages["system"].replace("{create_process}", create_process_content)
-            print(f"   - 已替换 {create_process_md_path.name} 内容到 prompt")
+            logger.info(f"   - 已替换 {create_process_md_path.name} 内容到 prompt")
         else:
-            print("   - 警告: prompt 中未找到 {create_process} 占位符")
+            logger.warning("   - 警告: prompt 中未找到 {create_process} 占位符")
     else:
-        print(f"   - 警告: create_process.md 文件不存在: {create_process_md_path}")
+        logger.warning(f"   - 警告: create_process.md 文件不存在: {create_process_md_path}")
 
     # 替换人设树数据
     if persona_dir:
@@ -213,38 +216,38 @@ def _apply_prompt_placeholders(base_dir: Path, prompt: SimplePrompt, persona_dir
                     # 在 system 消息中替换
                     if "system" in prompt._messages and placeholder in prompt._messages["system"]:
                         prompt._messages["system"] = prompt._messages["system"].replace(placeholder, tree_content)
-                        print(f"   - 已替换 {var_name} 数据到 prompt")
+                        logger.info(f"   - 已替换 {var_name} 数据到 prompt")
 
                     # 在 user 消息中替换
                     if "user" in prompt._messages and placeholder in prompt._messages["user"]:
                         prompt._messages["user"] = prompt._messages["user"].replace(placeholder, tree_content)
-                        print(f"   - 已替换 {var_name} 数据到 prompt (user)")
+                        logger.info(f"   - 已替换 {var_name} 数据到 prompt (user)")
                 else:
-                    print(f"   - 警告: 树文件不存在: {tree_path}")
+                    logger.warning(f"   - 警告: 树文件不存在: {tree_path}")
         else:
-            print(f"   - 警告: 人设树目录不存在: {tree_dir}")
+            logger.warning(f"   - 警告: 人设树目录不存在: {tree_dir}")
 
     input_md_path = base_dir / "PRD" / "input.md"
     if input_md_path.exists():
         user_content = input_md_path.read_text(encoding="utf-8")
         if "user" in prompt._messages and "{input}" in prompt._messages["user"]:
             prompt._messages["user"] = prompt._messages["user"].replace("{input}", user_content)
-            print("   - 已替换 input.md 内容到 prompt")
+            logger.info("   - 已替换 input.md 内容到 prompt")
         else:
-            print("   - 警告: prompt 中未找到 {input} 占位符")
+            logger.warning("   - 警告: prompt 中未找到 {input} 占位符")
     else:
-        print(f"   - 警告: input.md 文件不存在: {input_md_path}")
+        logger.warning(f"   - 警告: input.md 文件不存在: {input_md_path}")
 
     output_md_path = base_dir / "PRD" / "output.md"
     if output_md_path.exists():
         output_content = output_md_path.read_text(encoding="utf-8")
         if "user" in prompt._messages and "{output}" in prompt._messages["user"]:
             prompt._messages["user"] = prompt._messages["user"].replace("{output}", output_content)
-            print("   - 已替换 output.md 内容到 prompt")
+            logger.info("   - 已替换 output.md 内容到 prompt")
         else:
-            print("   - 警告: prompt 中未找到 {output} 占位符")
+            logger.warning("   - 警告: prompt 中未找到 {output} 占位符")
     else:
-        print(f"   - 警告: output.md 文件不存在: {output_md_path}")
+        logger.warning(f"   - 警告: output.md 文件不存在: {output_md_path}")
 
 
 async def main():
@@ -270,37 +273,37 @@ async def main():
 
     setup_logging(level=LOG_LEVEL, file=LOG_FILE)
 
-    print("2. 加载 presets...")
+    logger.info("2. 加载 presets...")
     presets_path = base_dir / "presets.json"
     if presets_path.exists():
         with open(presets_path, "r", encoding="utf-8") as f:
             project_presets = json.load(f)
         for name, cfg in project_presets.items():
             register_preset(name, AgentPreset(**cfg))
-        print(f"   - 已加载项目 presets: {list(project_presets.keys())}")
+        logger.info(f"   - 已加载项目 presets: {list(project_presets.keys())}")
 
-    print("3. 加载 prompt...")
+    logger.info("3. 加载 prompt...")
     prompt = SimplePrompt(prompt_path)
     _apply_prompt_placeholders(base_dir, prompt, persona_dir=args.persona)
 
-    print("\n替换后的 prompt:")
-    print("=" * 60)
-    print("System:")
-    print("-" * 60)
-    print(prompt._messages.get("system", ""))
-    print("=" * 60)
+    logger.info("\n替换后的 prompt:")
+    logger.info("=" * 60)
+    logger.info("System:")
+    logger.info("-" * 60)
+    logger.info(prompt._messages.get("system", ""))
+    logger.info("=" * 60)
     if "user" in prompt._messages:
-        print("\nUser:")
-        print("-" * 60)
-        print(prompt._messages["user"])
-        print("=" * 60)
-    print()
+        logger.info("\nUser:")
+        logger.info("-" * 60)
+        logger.info(prompt._messages["user"])
+        logger.info("=" * 60)
+    logger.info("")
 
-    print("4. 构建任务消息...")
+    logger.info("4. 构建任务消息...")
     messages = prompt.build_messages()
 
-    print("5. 创建 Agent Runner...")
-    print("   - 加载自定义工具: topic_search")
+    logger.info("5. 创建 Agent Runner...")
+    logger.info("   - 加载自定义工具: topic_search")
     import examples.create.tool  # noqa: F401
 
     model_from_prompt = prompt.config.get("model")
@@ -309,8 +312,8 @@ async def main():
     model = model_from_prompt or default_model
 
     skills_dir = str((base_dir / SKILLS_DIR).resolve()) if not Path(SKILLS_DIR).is_absolute() else SKILLS_DIR
-    print(f"   - Skills 目录: {skills_dir}")
-    print(f"   - 模型: {model}")
+    logger.info(f"   - Skills 目录: {skills_dir}")
+    logger.info(f"   - 模型: {model}")
 
     store = FileSystemTraceStore(base_path=TRACE_STORE_PATH)
     runner = AgentRunner(
@@ -327,27 +330,27 @@ async def main():
     )
 
     task_name = RUN_CONFIG.name or base_dir.name
-    print("=" * 60)
-    print(task_name)
-    print("=" * 60)
-    print("💡 交互提示:")
-    print("   - 执行过程中输入 'p' 或 'pause' 暂停并进入交互模式")
-    print("   - 执行过程中输入 'q' 或 'quit' 停止执行")
-    print("=" * 60)
-    print()
+    logger.info("=" * 60)
+    logger.info(task_name)
+    logger.info("=" * 60)
+    logger.info("💡 交互提示:")
+    logger.info("   - 执行过程中输入 'p' 或 'pause' 暂停并进入交互模式")
+    logger.info("   - 执行过程中输入 'q' 或 'quit' 停止执行")
+    logger.info("=" * 60)
+    logger.info("")
 
     resume_trace_id = args.trace
     if resume_trace_id:
         existing_trace = await store.get_trace(resume_trace_id)
         if not existing_trace:
-            print(f"\n错误: Trace 不存在: {resume_trace_id}")
+            logger.error(f"\n错误: Trace 不存在: {resume_trace_id}")
             sys.exit(1)
-        print(f"恢复已有 Trace: {resume_trace_id[:8]}...")
-        print(f"   - 状态: {existing_trace.status}")
-        print(f"   - 消息数: {existing_trace.total_messages}")
+        logger.info(f"恢复已有 Trace: {resume_trace_id[:8]}...")
+        logger.info(f"   - 状态: {existing_trace.status}")
+        logger.info(f"   - 消息数: {existing_trace.total_messages}")
     else:
-        print("启动新 Agent...")
-    print()
+        logger.info("启动新 Agent...")
+    logger.info("")
 
     final_response = ""
     current_trace_id = resume_trace_id
@@ -377,11 +380,11 @@ async def main():
                 check_trace = await store.get_trace(current_trace_id)
                 if check_trace and check_trace.status in ("completed", "failed"):
                     if check_trace.status == "completed":
-                        print("\n[Trace] ✅ 已完成")
-                        print(f"  - Total messages: {check_trace.total_messages}")
-                        print(f"  - Total cost: ${check_trace.total_cost:.4f}")
+                        logger.info("\n[Trace] ✅ 已完成")
+                        logger.info(f"  - Total messages: {check_trace.total_messages}")
+                        logger.info(f"  - Total cost: ${check_trace.total_cost:.4f}")
                     else:
-                        print(f"\n[Trace] ❌ 已失败: {check_trace.error_message}")
+                        logger.error(f"\n[Trace] ❌ 已失败: {check_trace.error_message}")
                     current_sequence = check_trace.head_sequence
 
                     menu_result = await interactive.show_menu(current_trace_id, current_sequence)
@@ -400,14 +403,14 @@ async def main():
 
                 initial_messages = []
 
-            print(f"{'▶️ 开始执行...' if not current_trace_id else '▶️ 继续执行...'}")
+            logger.info(f"{'▶️ 开始执行...' if not current_trace_id else '▶️ 继续执行...'}")
 
             paused = False
             try:
                 async for item in runner.run(messages=initial_messages, config=run_config):
                     cmd = interactive.check_stdin()
                     if cmd == "pause":
-                        print("\n⏸️ 正在暂停执行...")
+                        logger.info("\n⏸️ 正在暂停执行...")
                         if current_trace_id:
                             await runner.stop(current_trace_id)
                         await asyncio.sleep(0.5)
@@ -431,7 +434,7 @@ async def main():
                             break
 
                     elif cmd == "quit":
-                        print("\n🛑 用户请求停止...")
+                        logger.info("\n🛑 用户请求停止...")
                         if current_trace_id:
                             await runner.stop(current_trace_id)
                         should_exit = True
@@ -440,16 +443,16 @@ async def main():
                     if isinstance(item, Trace):
                         current_trace_id = item.trace_id
                         if item.status == "running":
-                            print(f"[Trace] 开始: {item.trace_id[:8]}...")
+                            logger.info(f"[Trace] 开始: {item.trace_id[:8]}...")
                         elif item.status == "completed":
-                            print("\n[Trace] ✅ 完成")
-                            print(f"  - Total messages: {item.total_messages}")
-                            print(f"  - Total tokens: {item.total_tokens}")
-                            print(f"  - Total cost: ${item.total_cost:.4f}")
+                            logger.info("\n[Trace] ✅ 完成")
+                            logger.info(f"  - Total messages: {item.total_messages}")
+                            logger.info(f"  - Total tokens: {item.total_tokens}")
+                            logger.info(f"  - Total cost: ${item.total_cost:.4f}")
                         elif item.status == "failed":
-                            print(f"\n[Trace] ❌ 失败: {item.error_message}")
+                            logger.error(f"\n[Trace] ❌ 失败: {item.error_message}")
                         elif item.status == "stopped":
-                            print("\n[Trace] ⏸️ 已停止")
+                            logger.info("\n[Trace] ⏸️ 已停止")
                     elif isinstance(item, Message):
                         current_sequence = item.sequence
                         _print_message_details(item)
@@ -462,10 +465,8 @@ async def main():
                                 if text and not tool_calls:
                                     final_response = text
             except Exception as e:
-                print(f"\n执行出错: {e}")
-                import traceback
-
-                traceback.print_exc()
+                logger.error(f"\n执行出错: {e}")
+                logger.exception("Exception details:")
 
             if paused:
                 if should_exit:
@@ -491,7 +492,7 @@ async def main():
             break
 
     except KeyboardInterrupt:
-        print("\n\n用户中断 (Ctrl+C)")
+        logger.info("\n\n用户中断 (Ctrl+C)")
         if current_trace_id:
             await runner.stop(current_trace_id)
     finally:
@@ -499,39 +500,39 @@ async def main():
             try:
                 html_path = store.base_path / current_trace_id / "messages.html"
                 await trace_to_html(current_trace_id, html_path, base_path=str(store.base_path))
-                print(f"\n✓ Messages 可视化已保存: {html_path}")
+                logger.info(f"\n✓ Messages 可视化已保存: {html_path}")
             except Exception as e:
-                print(f"\n⚠ 生成 HTML 失败: {e}")
+                logger.error(f"\n⚠ 生成 HTML 失败: {e}")
 
     if final_response:
-        print()
-        print("=" * 60)
-        print("Agent 响应:")
-        print("=" * 60)
-        print(final_response)
-        print("=" * 60)
-        print()
+        logger.info("")
+        logger.info("=" * 60)
+        logger.info("Agent 响应:")
+        logger.info("=" * 60)
+        logger.info(final_response)
+        logger.info("=" * 60)
+        logger.info("")
 
         output_file = output_dir / "result.txt"
         with open(output_file, "w", encoding="utf-8") as f:
             f.write(final_response)
 
-        print(f"✓ 结果已保存到: {output_file}")
-        print()
+        logger.info(f"✓ 结果已保存到: {output_file}")
+        logger.info("")
 
     if current_trace_id:
         html_path = store.base_path / current_trace_id / "messages.html"
-        print("=" * 60)
-        print("可视化:")
-        print("=" * 60)
-        print(f"1. 本地 HTML: {html_path}")
-        print()
-        print("2. API Server:")
-        print("   python3 api_server.py")
-        print("   http://localhost:8000/api/traces")
-        print()
-        print(f"3. Trace ID: {current_trace_id}")
-        print("=" * 60)
+        logger.info("=" * 60)
+        logger.info("可视化:")
+        logger.info("=" * 60)
+        logger.info(f"1. 本地 HTML: {html_path}")
+        logger.info("")
+        logger.info("2. API Server:")
+        logger.info("   python3 api_server.py")
+        logger.info("   http://localhost:8000/api/traces")
+        logger.info("")
+        logger.info(f"3. Trace ID: {current_trace_id}")
+        logger.info("=" * 60)
 
 
 if __name__ == "__main__":

+ 1 - 5
examples/create/tool/__init__.py

@@ -4,16 +4,12 @@ Create 示例的自定义工具
 
 from examples.create.tool.topic_search import topic_search
 from examples.create.tool.search_library import (
-    search_library,
-    search_by_element,
     search_point_by_element_from_full_all_levels,
     search_point_by_path_from_full_all_levels,
 )
 
 __all__ = [
     "topic_search",
-    "search_library",
-    "search_by_element",
     "search_point_by_element_from_full_all_levels",
-    "search_point_by_path_from_full_all_levels",
+    "search_point_by_path_from_full_all_levels"
 ]

+ 0 - 258
examples/create/tool/search_library.py

@@ -46,264 +46,6 @@ def _load_graph_full() -> Dict[str, Any]:
     return _graph_full_cache
 
 
-def _search_related_points(query_point: str, top_k: int = 10) -> Dict[str, Any]:
-    """
-    搜索与给定点相关的所有点
-
-    Args:
-        query_point: 查询的点名称
-        top_k: 返回前 K 个关联点(按置信度排序)
-
-    Returns:
-        包含相关点信息的字典
-    """
-    graph = _load_graph()
-
-    if query_point not in graph:
-        return {
-            "found": False,
-            "query": query_point,
-            "message": f"未找到点: {query_point}"
-        }
-
-    point_data = graph[query_point]
-    related_points = []
-
-    # 获取所有边连接的点
-    if "edges" in point_data:
-        for related_point, edge_data in point_data["edges"].items():
-            # 提取置信度用于排序
-            confidence = 0.0
-            if "co_in_post" in edge_data:
-                confidence = edge_data["co_in_post"].get("confidence", 0.0)
-
-            related_info = {
-                "point": related_point,
-                "confidence": confidence,
-                "co_post_count": edge_data.get("co_in_post", {}).get("co_post_count", 0),
-                "post_ids": edge_data.get("co_in_post", {}).get("post_ids", []),
-            }
-
-            # 如果关联点在图中,添加其元数据
-            if related_point in graph:
-                meta = graph[related_point].get("meta", {})
-                related_info["point_type"] = meta.get("point_type")
-                related_info["path"] = meta.get("path")
-                related_info["frequency_in_posts"] = meta.get("frequency_in_posts")
-
-            related_points.append(related_info)
-
-    # 按置信度降序排序,取前 top_k 个
-    related_points.sort(key=lambda x: x["confidence"], reverse=True)
-    related_points = related_points[:top_k]
-
-    return {
-        "found": True,
-        "query": query_point,
-        "meta": point_data.get("meta", {}),
-        "total_related_count": len(point_data.get("edges", {})),
-        "returned_count": len(related_points),
-        "related_points": related_points
-    }
-
-
-def _search_points_by_element(
-    element_value: str,
-    top_k: int = 10
-) -> Dict[str, Any]:
-    """
-    根据元素值在 elements 字段中查找匹配的点
-
-    Args:
-        element_value: 元素值,如 "全景光绘摄影", "奶油风"
-        top_k: 返回前 K 个点(按频率排序)
-
-    Returns:
-        包含匹配点信息的字典
-    """
-    graph = _load_graph()
-    matched_points = []
-
-    # 遍历图中所有点
-    for point_name, point_data in graph.items():
-        meta = point_data.get("meta", {})
-        elements = meta.get("elements", {})
-
-        # 在 elements 字段中查找匹配
-        if element_value in elements:
-            point_info = {
-                "point": point_name,
-                "element_frequency": elements[element_value],
-                "point_type": meta.get("point_type"),
-                "path": meta.get("path"),
-                "frequency_in_posts": meta.get("frequency_in_posts", 0),
-                "edge_count": len(point_data.get("edges", {}))
-            }
-            matched_points.append(point_info)
-
-    if not matched_points:
-        return {
-            "found": False,
-            "element_value": element_value,
-            "message": f"未找到匹配的点: {element_value}"
-        }
-
-    # 按频率降序排序,取前 top_k 个
-    matched_points.sort(key=lambda x: x["frequency_in_posts"], reverse=True)
-    matched_points = matched_points[:top_k]
-
-    return {
-        "found": True,
-        "element_value": element_value,
-        "total_matched_count": len(matched_points),
-        "returned_count": len(matched_points),
-        "matched_points": matched_points
-    }
-
-
-@tool(
-    description="根据关键点名称在图数据库中检索所有关联的点,用于创作参考。返回按置信度排序的前10个关联点。",
-    display={
-        "zh": {
-            "name": "关键点关联检索",
-            "params": {
-                "point_name": "关键点名称",
-                "top_k": "返回数量(默认10)",
-            },
-        },
-    },
-)
-async def search_library(point_name: str, top_k: int = 10) -> ToolResult:
-    """
-    根据关键点名称检索图数据库中的关联点。
-
-    Args:
-        point_name: 关键点名称,如 "关键点_表象>实体>物品>工业医药"
-        top_k: 返回前 K 个关联点,默认 10
-
-    Returns:
-        ToolResult: 关联点数据
-    """
-    if not point_name:
-        return ToolResult(
-            title="关键点检索失败",
-            output="",
-            error="请提供关键点名称",
-        )
-
-    try:
-        result = _search_related_points(point_name, top_k)
-    except FileNotFoundError:
-        return ToolResult(
-            title="关键点检索失败",
-            output="",
-            error=f"图数据文件不存在: {GRAPH_DATA_PATH}",
-        )
-    except Exception as e:
-        return ToolResult(
-            title="关键点检索失败",
-            output="",
-            error=f"检索异常: {str(e)}",
-        )
-
-    if not result["found"]:
-        return ToolResult(
-            title="关键点检索",
-            output=json.dumps(
-                {"message": result["message"], "query": point_name},
-                ensure_ascii=False,
-                indent=2
-            ),
-        )
-
-    # 格式化输出
-    output_data = {
-        "query": result["query"],
-        "meta": result["meta"],
-        "total_related_count": result["total_related_count"],
-        "returned_count": result["returned_count"],
-        "related_points": result["related_points"]
-    }
-
-    output = json.dumps(output_data, ensure_ascii=False, indent=2)
-    return ToolResult(
-        title=f"关键点检索 - {point_name}",
-        output=output,
-        long_term_memory=f"检索到 {result['returned_count']} 个关联点,查询点: {point_name}",
-    )
-
-
-@tool(
-    description="根据元素值在图数据库的 elements 字段中查找匹配的点。返回按频率排序的前10个点。",
-    display={
-        "zh": {
-            "name": "元素关联检索",
-            "params": {
-                "element_value": "元素值",
-                "top_k": "返回数量(默认10)",
-            },
-        },
-    },
-)
-async def search_by_element(element_value: str, top_k: int = 10) -> ToolResult:
-    """
-    根据元素值在 elements 字段中查找图数据库中的点。
-
-    Args:
-        element_value: 元素值,如 "全景光绘摄影", "奶油风"
-        top_k: 返回前 K 个点,默认 10
-
-    Returns:
-        ToolResult: 匹配点数据
-    """
-    if not element_value:
-        return ToolResult(
-            title="元素检索失败",
-            output="",
-            error="请提供元素值",
-        )
-
-    try:
-        result = _search_points_by_element(element_value, top_k)
-    except FileNotFoundError:
-        return ToolResult(
-            title="元素检索失败",
-            output="",
-            error=f"图数据文件不存在: {GRAPH_DATA_PATH}",
-        )
-    except Exception as e:
-        return ToolResult(
-            title="元素检索失败",
-            output="",
-            error=f"检索异常: {str(e)}",
-        )
-
-    if not result["found"]:
-        return ToolResult(
-            title="元素检索",
-            output=json.dumps(
-                {"message": result["message"], "element_value": element_value},
-                ensure_ascii=False,
-                indent=2
-            ),
-        )
-
-    # 格式化输出
-    output_data = {
-        "element_value": result["element_value"],
-        "total_matched_count": result["total_matched_count"],
-        "returned_count": result["returned_count"],
-        "matched_points": result["matched_points"]
-    }
-
-    output = json.dumps(output_data, ensure_ascii=False, indent=2)
-    return ToolResult(
-        title=f"元素检索 - {element_value}",
-        output=output,
-        long_term_memory=f"检索到 {result['returned_count']} 个匹配点,元素值: {element_value}",
-    )
-
-
 def _search_points_by_element_from_full(
     element_value: str,
     element_type: str,