丁云鹏 1 день назад
Родитель
Сommit
8c4d1163ad

+ 28 - 15
examples/create/PRD/create_process_v2.md

@@ -3,11 +3,8 @@
 你是一个专业的内容选题推导助手,负责根据人设数据,通过图数据库游走的方式,生成高质量的内容选题。
 
 ## 输入数据
-```
-形式数据: {{形式_point_tree_how}}
-实质数据: {{实质_point_tree_how}}
-意图数据: {{意图_point_tree_how}}
-```
+
+人设名称: {{person_name}}
 
 ## 核心机制说明
 
@@ -46,10 +43,17 @@
 从三个人设树中提取**所有 `_is_constant` 为 true 的常量点**:
 
 **操作指令**:
-1. 遍历形式、实质、意图三棵树
-2. 找到所有 `_type` 为 "ID" 且 `_is_constant` 为 true 的节
+1. 调用工具 `search_person_tree_constants(persona_name)` 获取该人设的所有常量点
+2. 从返回结果中提取形式、实质、意图三个维度的常量
 3. 记录点名称和所属类型
 
+**工具调用格式**:
+```python
+search_person_tree_constants(
+    persona_name="人设名称"  # 人设名称
+)
+```
+
 **输出格式**:
 ```json
 起始点集合 = [
@@ -160,10 +164,10 @@ search_point_by_element_from_full_all_levels(
    search_point_by_path_from_full_all_levels(
        path="关键点_呈现>视觉>创意性"  # 必须是完整格式:点类型_路径
    )
-   # 返回结果包含该点的完整信息,包括 edges 字段
-   # 从 edges 字段中可以获取所有关联点及其置信度
    ```
 
+   **返回结构**:edges 字段格式为 `{"关联点名称": {"confidence": 置信度, "co_occurrence": 共现次数}}`,已移除 `_post_ids` 字段。
+
 3. **记录新候选点**:
    ```json
    new_candidates = [
@@ -418,10 +422,10 @@ edges_to_explore = []
       - 注意:是"至少一个",不是"恰好一个"
       - 一条路径可以包含多个灵感点、多个目的点、多个关键点
       - 只要三种类型都出现过即可(每种至少1个)
-   ✅ 每条路径中至少包含一个来自"实质"树的
+   ✅ 每条路径中至少包含一个类型是"实质"的灵感
       - 这个实质点可能是起始点(第0轮从实质树提取的常量点)
       - 也可能是游走中关联到的点(路径中任意位置的实质点)
-      - 判断方法:检查路径中的所有点,是否有点来自"实质"树
+      - 判断方法:检查路径中的所有点,是否有类型是"实质"的灵感点
 
    如果必要条件都满足:
      → 终止循环,进入第三阶段
@@ -699,17 +703,26 @@ all_have_substance = all([
 
 ### 工具调用规范
 
-1. **search_point_by_element_from_full_all_levels**(仅第 0 轮使用):
+1. **search_person_tree_constants**(仅第 0 轮步骤 0.2 使用):
+   - 参数:
+     * `persona_name`(人设名称,如"家有大志")
+   - 用途:从人设树中提取所有常量点(_is_constant=true的点)
+   - 返回:包含三个维度(形式、实质、意图)的常量点列表,每个点包含名称、维度、路径、权重、帖子数量
+
+2. **search_point_by_element_from_full_all_levels**(仅第 0 轮步骤 0.3 使用):
    - 参数:
      * `element_value`(元素值,如"创意展示")
      * `element_type`(元素类型:"实质" / "形式" / "意图")
    - 用途:根据元素值和类型在完整图数据库中搜索关联点,返回包含边信息的完整数据
+   - 返回:`matched_points` 列表,每个点包含 `point`, `point_type`, `dimension`, `point_path`, `elements`, `edges` 等字段
+   - edges 格式:`{"关联点名称": {"confidence": 置信度, "co_occurrence": 共现次数}}`,已移除 `_post_ids`
 
-2. **search_point_by_path_from_full_all_levels**(第 1+ 轮使用):
+3. **search_point_by_path_from_full_all_levels**(第 1+ 轮使用):
    - 参数:`path`(完整点路径,如"关键点_呈现>视觉>创意性")
    - 格式要求:必须包含点类型前缀(灵感点_、目的点_、关键点_)
    - 用途:根据点路径获取该点的完整信息,包括 edges(关联点)数据
-   - 返回数据:包含点的元数据、elements、edges 等完整信息
+   - 返回:包含 `path`, `point_type`, `dimension`, `point_path`, `elements`, `edges` 等字段
+   - edges 格式:`{"关联点名称": {"confidence": 置信度, "co_occurrence": 共现次数}}`,已移除 `_post_ids`
    - 使用方式:从返回的 edges 字段中提取关联点列表
 
 ### 状态管理规范
@@ -729,7 +742,7 @@ all_have_substance = all([
 1. **先检查最大轮次**:如果 loop >= 6,强制终止
 2. **再检查必要条件**:三点齐全 + 实质支撑
 3. **避免无限循环**:设置最大轮次限制为 6 轮
-4. **实质点判断**:检查路径中所有点(不限于灵感点),只要包含来自"实质"树的点即可
+4. **实质点判断**:检查路径中灵感点,要包含类型是"实质"的点
 
 ---
 

+ 2 - 1
examples/create/presets.json

@@ -6,7 +6,8 @@
       "core",
       "planning",
       "search_point_by_element_from_full_all_levels",
-      "search_point_by_path_from_full_all_levels"
+      "search_point_by_path_from_full_all_levels",
+      "search_person_tree_constants"
     ],
     "description": "默认 Agent,拥有全部工具权限"
   }

+ 10 - 0
examples/create/run.py

@@ -174,6 +174,16 @@ def _apply_prompt_placeholders(base_dir: Path, prompt: SimplePrompt, persona_dir
         prompt: SimplePrompt 对象
         persona_dir: 人设数据目录名,如 "家有大志"。如果为 None,则不替换树数据
     """
+    # 替换 {{person_name}} 占位符
+    if persona_dir:
+        person_name_placeholder = "{{person_name}}"
+        if "system" in prompt._messages and person_name_placeholder in prompt._messages["system"]:
+            prompt._messages["system"] = prompt._messages["system"].replace(person_name_placeholder, persona_dir)
+            logger.info(f"   - 已替换 {{{{person_name}}}} 为: {persona_dir}")
+        if "user" in prompt._messages and person_name_placeholder in prompt._messages["user"]:
+            prompt._messages["user"] = prompt._messages["user"].replace(person_name_placeholder, persona_dir)
+            logger.info(f"   - 已替换 {{{{person_name}}}} 为: {persona_dir} (user)")
+
     system_md_path = base_dir / "PRD" / "system.md"
     if system_md_path.exists():
         system_content = system_md_path.read_text(encoding="utf-8")

+ 9 - 5
examples/create/skills/search_point_by_element_from_full_all_levels.md

@@ -1,5 +1,5 @@
 ---
-name: element_type_search
+name: search_point_by_element_from_full_all_levels
 description: 根据元素值和类型在完整图数据库中检索点,返回包含边信息的完整数据
 ---
 
@@ -30,14 +30,18 @@ description: 根据元素值和类型在完整图数据库中检索点,返回包
 - `returned_count`: 实际返回的点数量
 - `matched_points`: 匹配点列表,每个包含:
   - `point`: 点的完整名称
-  - `element_frequency`: 该元素在此点中的出现频率
   - `point_type`: 点类型(灵感点/目的点/关键点)
   - `dimension`: 点的维度(实质/形式/意图)
-  - `path`: 点的路径
+  - `point_path`: 点的路径
   - `frequency_in_posts`: 该点在帖子中的总频率
+  - `elements`: 该点包含的所有元素及其频率
   - `edge_count`: 该点的关联边数量
-  - `edges`: 完整的边信息字典
-  - `all_elements`: 该点包含的所有元素
+  - `edges`: 完整的边信息字典,包含:
+    - 关联点名称(key)
+    - 每个关联点的信息(value):
+      - `confidence`: 关联置信度
+      - `co_occurrence`: 共现帖子数量
+    - **注意**: 为优化数据传输,已移除共现帖子ID列表(`_post_ids`字段)
 
 ### 使用示例
 

+ 6 - 5
examples/create/skills/search_point_by_path_from_full_all_levels.md

@@ -1,5 +1,5 @@
 ---
-name: path_search
+name: search_point_by_path_from_full_all_levels
 description: 根据完整路径在图数据库中精确查找点,返回包含边信息的完整数据
 ---
 
@@ -31,10 +31,11 @@ description: 根据完整路径在图数据库中精确查找点,返回包含边
 - `elements`: 该点包含的所有元素及其频率
 - `edge_count`: 该点的关联边数量
 - `edges`: 完整的边信息字典,包含:
-  - 关联点名称
-  - 关联置信度
-  - 共现帖子数量
-  - 共现帖子 ID 列表
+  - 关联点名称(key)
+  - 每个关联点的信息(value):
+    - `confidence`: 关联置信度
+    - `co_occurrence`: 共现帖子数量
+  - **注意**: 为优化数据传输,已移除共现帖子ID列表(`_post_ids`字段)
 
 ### 使用示例
 

+ 6 - 2
examples/create/tool/__init__.py

@@ -5,11 +5,15 @@ Create 示例的自定义工具
 from examples.create.tool.topic_search import topic_search
 from examples.create.tool.search_library import (
     search_point_by_element_from_full_all_levels,
-    search_point_by_path_from_full_all_levels,
+    search_point_by_path_from_full_all_levels
+)
+from examples.create.tool.search_person_tree import (
+    search_person_tree_constants
 )
 
 __all__ = [
     "topic_search",
     "search_point_by_element_from_full_all_levels",
-    "search_point_by_path_from_full_all_levels"
+    "search_point_by_path_from_full_all_levels",
+    "search_person_tree_constants"
 ]

+ 32 - 9
examples/create/tool/search_library.py

@@ -46,6 +46,23 @@ def _load_graph_full() -> Dict[str, Any]:
     return _graph_full_cache
 
 
+def _remove_post_ids_from_edges(edges: Dict[str, Any]) -> Dict[str, Any]:
+    """移除 edges 中的 _post_ids 字段"""
+    if not edges:
+        return edges
+
+    cleaned_edges = {}
+    for edge_name, edge_data in edges.items():
+        if isinstance(edge_data, dict):
+            # 移除 _post_ids 字段
+            cleaned_data = {k: v for k, v in edge_data.items() if k != "_post_ids"}
+            cleaned_edges[edge_name] = cleaned_data
+        else:
+            cleaned_edges[edge_name] = edge_data
+
+    return cleaned_edges
+
+
 def _search_points_by_element_from_full(
     element_value: str,
     element_type: str,
@@ -60,7 +77,7 @@ def _search_points_by_element_from_full(
         top_k: 返回前 K 个点(按频率排序)
 
     Returns:
-        包含匹配点完整信息的字典(包括 edges)
+        包含匹配点完整信息的字典(包括 edges,已移除 _post_ids
     """
     graph = _load_graph_full()
     matched_points = []
@@ -73,16 +90,19 @@ def _search_points_by_element_from_full(
 
         # 检查:元素值在 elements 中 AND dimension 匹配 element_type
         if element_value in elements and dimension == element_type:
+            # 移除 edges 中的 _post_ids
+            cleaned_edges = _remove_post_ids_from_edges(point_data.get("edges", {}))
+
+            # 返回结构与 search_point_by_path_from_full_all_levels 保持一致
             point_info = {
                 "point": point_name,
-                "element_frequency": elements[element_value],
                 "point_type": meta.get("point_type"),
                 "dimension": dimension,
-                "path": meta.get("path"),
+                "point_path": meta.get("path"),
                 "frequency_in_posts": meta.get("frequency_in_posts", 0),
-                "edge_count": len(point_data.get("edges", {})),
-                "edges": point_data.get("edges", {}),
-                "all_elements": elements
+                "elements": elements,
+                "edge_count": len(cleaned_edges),
+                "edges": cleaned_edges
             }
             matched_points.append(point_info)
 
@@ -116,7 +136,7 @@ def _search_point_by_path_from_full(path: str) -> Dict[str, Any]:
         path: 点的完整路径,如 "关键点_形式_架构>逻辑>逻辑架构>组织逻辑>框架规划>结构设计"
 
     Returns:
-        包含该点完整信息的字典(包括 edges)
+        包含该点完整信息的字典(包括 edges,已移除 _post_ids
     """
     graph = _load_graph_full()
 
@@ -130,6 +150,9 @@ def _search_point_by_path_from_full(path: str) -> Dict[str, Any]:
     point_data = graph[path]
     meta = point_data.get("meta", {})
 
+    # 移除 edges 中的 _post_ids
+    cleaned_edges = _remove_post_ids_from_edges(point_data.get("edges", {}))
+
     return {
         "found": True,
         "path": path,
@@ -138,8 +161,8 @@ def _search_point_by_path_from_full(path: str) -> Dict[str, Any]:
         "point_path": meta.get("path"),
         "frequency_in_posts": meta.get("frequency_in_posts"),
         "elements": meta.get("elements", {}),
-        "edge_count": len(point_data.get("edges", {})),
-        "edges": point_data.get("edges", {})
+        "edge_count": len(cleaned_edges),
+        "edges": cleaned_edges
     }