yangxiaohui 2 semanas atrás
pai
commit
b954477e68
2 arquivos alterados com 122 adições e 133 exclusões
  1. 1 2
      run_step3_from_analysis.py
  2. 121 131
      step3_generate_inspirations.py

+ 1 - 2
run_step3_from_analysis.py

@@ -128,8 +128,7 @@ async def run_step3_for_inspiration(
                 json.dump(output, f, ensure_ascii=False, indent=2)
 
             # 输出预览
-            generated = output.get("生成结果", {})
-            inspirations = generated.get("灵感点列表", [])
+            inspirations = output.get("灵感点列表", [])
             print(f"✓ 生成了 {len(inspirations)} 个灵感点")
             if log_url:
                 print(f"  Trace: {log_url}")

+ 121 - 131
step3_generate_inspirations.py

@@ -21,102 +21,85 @@ MODEL_NAME = "google/gemini-2.5-pro"
 
 
 # ========== System Prompt ==========
+
 GENERATE_INSPIRATIONS_PROMPT = """
 # 任务
-基于给定的人设体系和锚点要素,分析和生成可能的灵感点
+你是一个内容创作者,现在要从一个锚点要素出发,模拟灵感产生的完整思维路径
 
 ## 输入说明
+- **<人设体系></人设体系>**: 完整的人设系统,包含所有可用的节点
+- **<锚点要素></锚点要素>**: 作为起点的人设要素
+- **<要素定义></要素定义>**: 该要素的完整定义
+- **<要素上下文></要素上下文>**: 该要素的上下文信息
 
-- **<人设体系></人设体系>**: 完整的人设系统,用于理解整体风格和定位
-- **<锚点要素></锚点要素>**: 作为锚点的人设要素(一级或二级分类)
-- **<要素定义></要素定义>**: 该要素在人设中的完整定义(如果有)
-- **<要素上下文></要素上下文>**: 该要素的上下文信息(所属视角、一级分类等)
-
-## 分析方法
+## 思维路径规则
 
-### 核心原则:基于人设特征和要素定位发散灵感
+每个灵感的产生都需要完整的思维路径:**[锚点] → [维度] → [节点/联想]**
 
-1. 先理解整个人设体系的风格、调性和定位
-2. 深入理解锚点要素在人设中的含义和作用
-3. 基于人设特征,推理可能触发该要素的灵感来源
+1. **[锚点]**: 必须从给定的锚点要素出发
+2. **[维度]**: 从锚点特征自然产生的思维方向(动态的,根据锚点特点决定)
+   - 例如:跨节点组合、具体场景联想、情感延伸、时间维度、夸张变形等
+3. **[节点/联想]**:
+   - **[节点]**: 人设体系中的其他节点
+   - **[联想]**: 自由联想的具体内容
+   - 可以有多个,用 + 连接
 
-### 分析步骤
+## 示例
 
-1. **理解人设体系**
-   - 分析人设的整体风格和内容定位
-   - 理解灵感点、目的点、关键点的组织方式
-   - 把握人设的表达特色和价值取向
+假设锚点是"宠物迷惑行为":
 
-2. **理解锚点要素**
-   - 结合要素定义,理解该要素的核心含义
-   - 分析该要素在人设体系中的层级位置
-   - 理解该要素代表的内容类型或表达方式
-
-3. **发散灵感思考**
-   - 基于人设整体风格,思考什么样的灵感会触发该要素
-   - 考虑不同的场景、话题、情感、事件等
-   - 确保生成的灵感符合人设的调性和定位
-   - 灵感应该多样化,但都要能映射到该要素
+```
+路径: [锚点]宠物迷惑行为 → [维度]跨节点组合 → [节点]职场疲惫
+灵感点: 猫咪上班后的呆滞眼神
 
-4. **生成灵感点列表**
-   - 每个灵感点应该简洁明确(一句话)
-   - 灵感点之间应有一定的多样性
-   - 灵感点应该能够触发该人设要素
-   - 纯粹基于人设和要素特征推理
+路径: [锚点]宠物迷惑行为 → [维度]具体场景联想 → [联想]盯着空气
+灵感点: 猫咪对着空气打拳
 
----
+路径: [锚点]宠物迷惑行为 → [维度]跨节点组合 → [节点]职场疲惫 + [节点]谐音梗
+灵感点: 猫咪"喵"班摸鱼
+```
 
 ## 输出格式(严格JSON)
 
 ```json
 {
-  "人设理解": {
-    "整体风格": "简要描述人设的整体风格和定位(1-2句话)",
-    "内容调性": "该人设的内容调性和表达特点"
-  },
-  "要素分析": {
-    "核心特征": "结合人设和要素定义,描述该要素的核心特征(1-2句话)",
-    "适用场景": "该要素在这个人设中适用的内容场景"
-  },
   "灵感点列表": [
     {
-      "灵感点": "具体的灵感点描述",
-      "说明": "为什么这个灵感可能触发该要素(结合人设特征说明)"
+      "路径": "[锚点]xxx → [维度]xxx → [节点/联想]xxx",
+      "灵感点": "具体的灵感点描述"
     },
     {
-      "灵感点": "具体的灵感点描述",
-      "说明": "为什么这个灵感可能触发该要素(结合人设特征说明)"
+      "路径": "[锚点]xxx → [维度]xxx → [联想]xxx",
+      "灵感点": "具体的灵感点描述"
     }
   ]
 }
 ```
 
-**输出要求**:
-1. 必须严格按照上述JSON格式输出
-2. 所有字段都必须填写
-3. **人设理解**:体现对整个人设体系的把握
-4. **要素分析**:结合人设和要素定义进行分析
-5. **灵感点列表**:生成 5-10 个灵感点
-6. 每个灵感点包含:
-   - **灵感点**:简洁的灵感描述(一句话)
-   - **说明**:解释为什么这个灵感可能触发该要素,要结合人设特征(1-2句话)
-7. 灵感点应该多样化,覆盖不同角度和场景
-8. 纯粹基于人设和要素特征进行推理,不依赖外部参考
+**要求**:
+1. 生成 8-15 个灵感点
+2. 路径必须严格按照 `[锚点] → [维度] → [节点/联想]` 格式
+3. 维度要多样化,探索不同的思考方向
+4. 每个灵感点简洁明确(一句话)
+5. 灵感点要具体、可执行、符合人设风格
+6. 必须严格按照 JSON 格式输出
 """.strip()
 
 
-def create_generate_agent(model_name: str) -> Agent:
-    """创建灵感生成的 Agent
+def create_agent(model_name: str, prompt: str, name: str) -> Agent:
+    """创建 Agent
 
     Args:
         model_name: 模型名称
+        prompt: System prompt
+        name: Agent 名称
 
     Returns:
         Agent 实例
     """
     agent = Agent(
-        name="Inspiration Generator Expert",
-        instructions=GENERATE_INSPIRATIONS_PROMPT,
+        name=name,
+        instructions=prompt,
         model=get_model(model_name),
         tools=[],
     )
@@ -124,11 +107,12 @@ def create_generate_agent(model_name: str) -> Agent:
     return agent
 
 
-def parse_generate_response(response_content: str) -> dict:
-    """解析生成响应
+def parse_json_response(response_content: str, default_value: dict = None) -> dict:
+    """解析 JSON 响应
 
     Args:
         response_content: Agent 返回的响应内容
+        default_value: 解析失败时的默认返回值
 
     Returns:
         解析后的字典
@@ -149,17 +133,7 @@ def parse_generate_response(response_content: str) -> dict:
         return json.loads(json_text)
     except Exception as e:
         print(f"解析响应失败: {e}")
-        return {
-            "人设理解": {
-                "整体风格": "解析失败",
-                "内容调性": "解析失败"
-            },
-            "要素分析": {
-                "核心特征": "解析失败",
-                "适用场景": "解析失败"
-            },
-            "灵感点列表": []
-        }
+        return default_value if default_value else {}
 
 
 def format_persona_system(persona_data: dict) -> str:
@@ -261,13 +235,62 @@ def find_step1_file(persona_dir: str, inspiration: str, model_name: str) -> str:
     return str(step1_files[0])
 
 
+async def generate_inspirations_with_paths(
+    persona_system_text: str,
+    matched_element: str,
+    element_definition: str,
+    element_context: str
+) -> list:
+    """生成带思维路径的灵感点列表
+
+    Args:
+        persona_system_text: 完整人设系统文本
+        matched_element: 匹配要素
+        element_definition: 要素定义
+        element_context: 要素上下文
+
+    Returns:
+        灵感点列表 [{"路径": "...", "灵感点": "..."}, ...]
+    """
+    task_description = f"""## 本次任务
+
+<人设体系>
+{persona_system_text}
+</人设体系>
+
+<锚点要素>
+{matched_element}
+</锚点要素>
+
+<要素定义>
+{element_definition if element_definition else '无'}
+</要素定义>
+
+<要素上下文>
+{element_context}
+</要素上下文>
+
+请从锚点要素出发,模拟灵感产生的完整思维路径,生成多个灵感点,严格按照 JSON 格式输出。"""
+
+    messages = [{
+        "role": "user",
+        "content": [{"type": "input_text", "text": task_description}]
+    }]
+
+    agent = create_agent(MODEL_NAME, GENERATE_INSPIRATIONS_PROMPT, "Inspiration Path Generator")
+    result = await Runner.run(agent, input=messages)
+
+    parsed = parse_json_response(result.final_output, {"灵感点列表": []})
+    return parsed.get("灵感点列表", [])
+
+
 async def process_step3_generate_inspirations(
     step1_top1: dict,
     persona_data: dict,
     current_time: str = None,
     log_url: str = None
 ) -> dict:
-    """执行灵感生成分析(核心业务逻辑)
+    """执行灵感生成分析(核心业务逻辑 - 单层路径生成
 
     Args:
         step1_top1: step1 的 top1 匹配结果
@@ -291,60 +314,30 @@ async def process_step3_generate_inspirations(
     # 查找要素定义
     element_definition = find_element_definition(persona_data, matched_element)
 
-    print(f"\n开始灵感生成分析")
+    print(f"\n{'=' * 80}")
+    print(f"Step3: 基于锚点生成灵感路径")
+    print(f"{'=' * 80}")
     print(f"锚点要素: {matched_element}")
     print(f"要素定义: {element_definition if element_definition else '(未找到定义)'}")
     print(f"模型: {MODEL_NAME}\n")
 
-    # 构建任务描述(包含完整人设系统、锚点要素、要素定义、要素上下文)
-    task_description = f"""## 本次分析任务
-
-<人设体系>
-{persona_system_text}
-</人设体系>
-
-<锚点要素>
-{matched_element}
-</锚点要素>
-
-<要素定义>
-{element_definition if element_definition else '无'}
-</要素定义>
-
-<要素上下文>
-{element_context}
-</要素上下文>
-
-请基于上述完整的人设体系和锚点要素,深入理解人设的整体风格和该要素的定位,推理并生成可能的灵感点列表,严格按照系统提示中的 JSON 格式输出结果。"""
+    # 生成灵感点(单层,包含完整思维路径)
+    with custom_span(name="生成带路径的灵感点", data={"锚点要素": matched_element}):
+        inspirations = await generate_inspirations_with_paths(
+            persona_system_text, matched_element, element_definition, element_context
+        )
 
-    # 构造消息
-    messages = [{
-        "role": "user",
-        "content": [
-            {
-                "type": "input_text",
-                "text": task_description
-            }
-        ]
-    }]
-
-    # 使用 custom_span 追踪生成过程
-    with custom_span(
-        name=f"Step3: 灵感生成 - {matched_element}",
-        data={
-            "锚点要素": matched_element,
-            "模型": MODEL_NAME,
-            "步骤": "基于要素生成灵感点"
-        }
-    ):
-        # 创建 Agent
-        agent = create_generate_agent(MODEL_NAME)
-
-        # 运行 Agent
-        result = await Runner.run(agent, input=messages)
+    print(f"\n{'=' * 80}")
+    print(f"完成!共生成 {len(inspirations)} 个灵感点")
+    print(f"{'=' * 80}\n")
 
-    # 解析响应
-    parsed_result = parse_generate_response(result.final_output)
+    # 预览前3个
+    if inspirations:
+        print("预览前3个灵感点:")
+        for i, item in enumerate(inspirations[:3], 1):
+            print(f"  {i}. 路径: {item.get('路径', '')}")
+            print(f"     灵感: {item.get('灵感点', '')}")
+        print()
 
     # 构建输出
     return {
@@ -360,7 +353,7 @@ async def process_step3_generate_inspirations(
             "要素上下文": element_context
         },
         "step1_结果": step1_top1,
-        "生成结果": parsed_result
+        "灵感点列表": inspirations
     }
 
 
@@ -461,17 +454,14 @@ async def main(current_time: str, log_url: str, force: bool = False):
     with open(output_file, 'w', encoding='utf-8') as f:
         json.dump(output, f, ensure_ascii=False, indent=2)
 
-    # 输出生成的灵感点预览
-    generated = output.get("生成结果", {})
-    inspirations = generated.get("灵感点列表", [])
-
+    # 输出统计信息
+    stats = output.get("统计", {})
     print(f"\n{'=' * 80}")
-    print(f"生成了 {len(inspirations)} 个灵感点:")
+    print(f"统计信息:")
+    print(f"  外层维度数: {stats.get('外层维度数', 0)}")
+    print(f"  内层维度数: {stats.get('内层维度数', 0)}")
+    print(f"  灵感点总数: {stats.get('灵感点总数', 0)}")
     print(f"{'=' * 80}")
-    for i, item in enumerate(inspirations[:5], 1):
-        print(f"{i}. {item.get('灵感点', '')}")
-    if len(inspirations) > 5:
-        print(f"... 还有 {len(inspirations) - 5} 个")
 
     print(f"\n完成!结果已保存到: {output_file}")
     if log_url: