Просмотр исходного кода

how agent 人设树条件概率更新

liuzhiheng 2 дней назад
Родитель
Сommit
4b77152433

+ 7 - 4
examples_how/overall_derivation/derivation_main.md

@@ -129,7 +129,7 @@ endif
 共定义以下 **四种** 推导方法,每条推导路径的 `method` 字段必须使用其中之一:
 
 #### 方法一:人设常量
-- **适用场景**:前几轮推导,已推导成功的选题点集合为空或很少,需要广召回可能的输出选题点。
+- **适用场景**:前几轮推导特别是首轮,已推导成功的选题点集合为空或很少,需要广召回可能的输出选题点。
 - **操作方式**:调用工具 `find_tree_constant_nodes(account_name=account_name, post_id=post_id)` 获取人设树的全局常量、局部常量节点;工具返回的每个节点均已附带「帖子选题点匹配」字段,可直接参考哪些节点已匹配到帖子选题点。根据返回的节点名称、概率、常量类型及匹配情况选择候选输出,整理为本推导路径的 `input`/`output`/`reason`。
 - 模拟样例: 以下是使用「人设常量」进行推导所产生的数据解构样例。
     - 单步推导使用的input信息:
@@ -155,7 +155,7 @@ endif
       ```
 
 #### 方法二:账号pattern复用
-- **适用场景**:通过 pattern 数据发现选题点共现关系;首轮或集合为空时也可调用。
+- **适用场景**:通过 pattern 数据发现选题点共现关系;任何轮次都可调用。
 - **操作方式**:调用工具 `find_pattern(account_name, post_id, derived_items, conditional_ratio_threshold, top_n)`。`derived_items` 可为空数组 `[]`(首轮或广召回时);非空时每项建议为 `{"topic":"帖子选题点名称","source_node":"人设树节点名称"}`,不可使用 `name`、`node`、`id` 等其它字段。工具会自动将包含已推导选题点的 pattern 排在前面,且返回的每个 pattern 均已附带「帖子选题点匹配」字段,列出各元素与帖子选题点的匹配情况,可直接参考。根据工具返回的 pattern 名称、条件概率及匹配情况,选取条件概率高的 pattern,将其中尚未推导成功的选题点作为候选输出,整理为本推导路径的 `input`/`output`/`reason`。
 - **优先级**:优先使用条件概率高、pattern 长度(节点数)大的结果;与已推导选题点重合多的 pattern 更优先(工具已自动排序)。
 - 模拟样例: 以下是使用「账号pattern复用」进行推导所产生的数据解构样例。
@@ -182,7 +182,7 @@ endif
     ```
 
 #### 方法三:人设推导
-- **适用场景**:通过人设树条件概率关联推导相关节点;首轮或集合为空时也可调用。
+- **适用场景**:通过人设树条件概率关联推导相关节点;非首轮进行内部推导时可以使用
 - **操作方式**:调用工具 `find_tree_nodes_by_conditional_ratio(account_name, post_id, derived_items, conditional_ratio_threshold, top_n)`。`derived_items` 可为空数组 `[]`(首轮或广召回时);非空时每项建议为 `{"topic":"帖子选题点名称","source_node":"人设树节点名称"}`,不可使用 `name`、`node`、`id` 等其它字段。工具返回的每个节点均已附带「帖子选题点匹配」字段,可直接参考哪些节点已匹配到帖子选题点。根据工具返回的节点名称、条件概率、父节点名称及匹配情况,选取条件概率高的节点作为候选输出,整理为本推导路径的 `input`/`output`/`reason`。推导理由须引用条件概率等数据,不得使用大模型自身世界知识联想。
 - 模拟样例: 以下是使用「人设推导」进行推导所产生的数据解构样例。
     - 单步推导使用的input信息:
@@ -257,7 +257,7 @@ endif
 **执行要点**:
 - **账号 pattern 复用(方法二)在每轮必须使用**,传空 `derived_items`(`[]`)召回所有高支持度 pattern,优先从长 pattern(`l >= 3`)中提取候选点,因为长 pattern 反映更丰富的共现组合
 - 人设常量(方法一)建议在首轮优先使用,一次性召回所有高概率常量节点作为初始候选
-- 人设推导(方法三)作为补充,覆盖 pattern 未能涵盖的维度
+- 人设推导(方法三)作为补充,覆盖 pattern 未能涵盖的维度,但首轮不使用
 - 本阶段每轮输出的候选选题点数量应尽量多,依靠匹配结果过滤后再确认方向
 - 该阶段尽量避免使用 信息搜索(方法四) 方法
 
@@ -283,6 +283,9 @@ endif
 - **搜索关键词约束**:只能使用已推导成功的选题点名称或人设树节点名称构造 query,**禁止**使用大模型自行推测或联想出的关键词。**禁止使用账号名称**。
 - **搜索后的跟进**:每次搜索后至少安排 1~2 轮内部方法推导,将搜索发现的新方向优先在 pattern 库中验证,再结合人设树延伸
 
+#### 内部推导结果重合处理
+当某一轮使用了多个内部推导方法推导出了同一个选题点,优先使用 人设常量 和 账号pattern复用 方法作为推导输出结果
+
 #### 内部推导方法阈值动态调整
 内部推导方法二、三的 `conditional_ratio_threshold`(条件概率阈值)、`top_n`(最大返回记录条数)由 agent 动态调整
 - `top_n` 最小设置500,可按 500->1000->2000 间隔动态调整,如果是方法二(账号 pattern 复用),`top_n` 最小设置1000

+ 28 - 15
examples_how/overall_derivation/utils/conditional_ratio_calc.py

@@ -6,6 +6,7 @@
 
 from __future__ import annotations
 
+import itertools
 import json
 from pathlib import Path
 from typing import Any
@@ -101,23 +102,31 @@ def calc_node_conditional_ratio(
         base_dir: 可选,input 根目录;不传则使用相对本文件的 ../input
 
     计算规则:
-        已推导的帖子集合 = 各「推导来源人设树节点」在人设树中的 post_ids 的交集(方法内从树读取)
-        分子 = |已推导的帖子集合 ∩ N 的 post_ids|
-        分母 = |已推导的帖子集合 ∩ P 的 post_ids|
-        条件概率 = 分子/分母,且 ≤1;分母为 0 时返回 1。
+        已推导的帖子集合:从 derived_list 中先取「最多选题点」的交集,再逐步减少到 1 个选题点,
+        对每种选题点子集分别计算条件概率,最后取最大值。
+        对每种情况:已推导的帖子集合 = 该子集中各「推导来源人设树节点」在人设树中的 post_ids 的交集;
+        分子 = |已推导的帖子集合 ∩ N 的 post_ids|,分母 = |已推导的帖子集合 ∩ P 的 post_ids|;
+        条件概率 = 分子/分母,且 ≤1;分母为 0 时该情况跳过。
     """
     index = _build_node_index(account_name, base_dir)
-    derived_post_ids = _derived_post_ids_from_sources(derived_list, index)
     if tree_node_name not in index:
-        return 1.0
+        return 0.0
     n_pids, p_pids = index[tree_node_name]
     set_n = set(n_pids)
     set_p = set(p_pids)
-    den = len(derived_post_ids & set_p)
-    if den == 0:
-        return 0.0
-    num = len(derived_post_ids & set_n)
-    return min(1.0, num / den)
+
+    max_ratio = 0.0
+    # 从「最多选题点」到 1 个选题点:对每种子集大小,取所有组合,分别算条件概率后取最大
+    for k in range(len(derived_list), 0, -1):
+        for combo in itertools.combinations(derived_list, k):
+            derived_post_ids = _derived_post_ids_from_sources(list(combo), index)
+            den = len(derived_post_ids & set_p)
+            if den == 0:
+                continue
+            num = len(derived_post_ids & set_n)
+            ratio = min(1.0, num / den)
+            max_ratio = max(max_ratio, ratio)
+    return max_ratio
 
 
 def _pattern_nodes_and_post_count(pattern: dict[str, Any]) -> tuple[list[str], int, float]:
@@ -197,13 +206,17 @@ def _test_with_user_example() -> None:
     account_name = "家有大志"
     # 已推导列表:(已推导的选题点, 推导来源人设树节点)
     derived_list: list[DerivedItem] = [
-        # ("分享", "分享"),
-        # ("柴犬", "动物角色"),
+        ("分享", "分享"),
+        ("叙事结构", "叙事结构"),
+        ("图片文字", "图片文字"),
+        ("补充说明式", "补充说明式"),
+        ("幽默化标题", "幽默化标题"),
+        ("标题", "标题"),
     ]
 
     # 1)人设树节点「恶作剧」的条件概率
-    r_node = calc_node_conditional_ratio(account_name, derived_list, "恶作剧")
-    print(f"1) 人设树节点「恶作剧」条件概率: {r_node}")
+    r_node = calc_node_conditional_ratio(account_name, derived_list, "柴犬主角")
+    print(f"1) 人设树节点条件概率: {r_node}")
 
     # 2)pattern 分享+动物角色+创意表达 post_count=2 的条件概率
     pattern = {"i": "分享+动物角色+创意表达", "post_count": 2, "s": 0.3}