liuzhiheng 2 месяцев назад
Родитель
Сommit
53aadba3ab

+ 4 - 4
examples_how/overall_derivation/derivation_main.md

@@ -171,8 +171,8 @@ agent(agent_type="derivation_search", task="执行搜索任务,account_name=xx
 **部分推导升级检查**:对于 `partial_derived_set` 中已有的选题点,若本轮出现了更高 `matched_score` 的路径,则更新该选题点的记录(包括分数和对应的推导路径信息)。若更新后 `matched_score >= 0.78`,则将其从 `partial_derived_set` 移入 `derived_success_set`。
 
 **步骤四:写入日志 + 更新集合(每轮必须执行,不可省略)**
-- 将本轮推导路径按**推导日志**格式写入 `output/{account_name}/推导日志/{帖子ID}/{log_id}/{轮次}_推导.json`
-- 将步骤三的匹配判断结果按**评估日志**格式写入 `output/{account_name}/推导日志/{帖子ID}/{log_id}/{轮次}_评估.json`
+- 将本轮推导路径按**推导日志**格式写入 `/Users/liuzhiheng/work/aigc/code/Agent/examples_how/overall_derivation/output/{account_name}/推导日志/{帖子ID}/{log_id}/{轮次}_推导.json`
+- 将步骤三的匹配判断结果按**评估日志**格式写入 `/Users/liuzhiheng/work/aigc/code/Agent/examples_how/overall_derivation/output/{account_name}/推导日志/{帖子ID}/{log_id}/{轮次}_评估.json`
 - 直接调用工具写入文件即可,不需要创建目录
 - 根据匹配结果更新集合:
   - `is_matched=true` 且 `matched_score >= 0.78`:将 `matched_post_point` 加入 `derived_success_set`(完全推导成功)
@@ -556,7 +556,7 @@ agent(agent_type="derivation_search", task="执行搜索任务,account_name=xx
 
 ### 1. 推导日志(每轮一份)
 
-- **路径**: `output/{account_name}/推导日志/{帖子ID}/{log_id}/{轮次}_推导.json`
+- **路径**: `/Users/liuzhiheng/work/aigc/code/Agent/examples_how/overall_derivation/output/{account_name}/推导日志/{帖子ID}/{log_id}/{轮次}_推导.json`
 - **作用**: 记录该轮推导的详细过程,便于追溯与可解释性
 - **格式要求**:
 
@@ -612,7 +612,7 @@ agent(agent_type="derivation_search", task="执行搜索任务,account_name=xx
 
 ### 2. 评估日志(每轮一份)
 
-- **路径**: `output/{account_name}/推导日志/{帖子ID}/{log_id}/{轮次}_评估.json`
+- **路径**: `/Users/liuzhiheng/work/aigc/code/Agent/examples_how/overall_derivation/output/{account_name}/推导日志/{帖子ID}/{log_id}/{轮次}_评估.json`
 - **作用**: 记录该轮各推导输出点的匹配判断结果与推导进度,**内容由主 agent 根据工具返回的匹配数据(或搜索子 agent 返回的匹配结果)直接整理得到**
 - **格式要求**:
 

+ 2 - 2
examples_how/overall_derivation/generate_visualize_data.py

@@ -494,6 +494,6 @@ def main(account_name, post_id, log_id):
 
 if __name__ == "__main__":
     account_name="家有大志"
-    post_id = "68fb6a5c000000000302e5de"
-    log_id="20260312215513"
+    post_id = "69185d49000000000d00f94e"
+    log_id="20260313110749"
     main(account_name, post_id, log_id)

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
examples_how/overall_derivation/input/家有大志/tree/实质_point_tree_how.json


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
examples_how/overall_derivation/input/家有大志/tree/形式_point_tree_how.json


+ 53 - 1
examples_how/overall_derivation/input/家有大志/tree/意图_point_tree_how.json

@@ -1 +1,53 @@
-{"意图":{"t":"root","n":23,"ch":{"产品植入":{"t":"class","w":0.2222,"n":1,"ch":{"产品植入":{"t":"ID","w":0.2222,"n":1,"r":0.0435,"c":true}},"r":0.0435},"分享":{"t":"class","w":1.0,"n":21,"ch":{"分享":{"t":"ID","w":1.0,"n":21,"r":0.913,"c":true}},"r":0.913},"回馈粉丝":{"t":"class","w":0.1163,"n":1,"ch":{"回馈粉丝":{"t":"ID","w":0.1163,"n":1,"r":0.0435,"c":false}},"r":0.0435}}}}
+{
+  "意图": {
+    "_type": "root", 
+    "_post_count": 23, 
+    "children": {
+      "产品植入": {
+        "_type": "class", 
+        "_persona_weight_score": 0.2222, 
+        "_post_count": 1, 
+        "children": {
+          "产品植入": {
+            "_type": "ID", 
+            "_persona_weight_score": 0.2222, 
+            "_post_count": 1, 
+            "_ratio": 0.0435, 
+            "_is_constant": true
+          }
+        }, 
+        "_ratio": 0.0435
+      }, 
+      "分享": {
+        "_type": "class", 
+        "_persona_weight_score": 1.0, 
+        "_post_count": 21, 
+        "children": {
+          "分享": {
+            "_type": "ID", 
+            "_persona_weight_score": 1.0, 
+            "_post_count": 21, 
+            "_ratio": 0.913, 
+            "_is_constant": true
+          }
+        }, 
+        "_ratio": 0.913
+      }, 
+      "回馈粉丝": {
+        "_type": "class", 
+        "_persona_weight_score": 0.1163, 
+        "_post_count": 1, 
+        "children": {
+          "回馈粉丝": {
+            "_type": "ID", 
+            "_persona_weight_score": 0.1163, 
+            "_post_count": 1, 
+            "_ratio": 0.0435, 
+            "_is_constant": false
+          }
+        }, 
+        "_ratio": 0.0435
+      }
+    }
+  }
+}

+ 9 - 6
examples_how/overall_derivation/overall_derivation_agent_run.py

@@ -19,8 +19,9 @@ from pathlib import Path
 # 与 examples/how/run.py 一致:禁止 httpx/urllib 自动检测系统 HTTP 代理
 # os.environ.setdefault("no_proxy", "*")
 
-# 添加项目根目录到 Python 路径
-sys.path.insert(0, str(Path(__file__).parent.parent.parent))
+# 项目根目录(兼容从项目根或脚本目录启动)
+PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
+sys.path.insert(0, str(PROJECT_ROOT))
 
 from dotenv import load_dotenv
 
@@ -322,7 +323,7 @@ async def main(account_name, post_id):
     model_id = model_key
     print(f"   - 模型: {model_id}")
 
-    store = FileSystemTraceStore(base_path=".trace")
+    store = FileSystemTraceStore(base_path=str(PROJECT_ROOT / ".trace"))
     runner = AgentRunner(
         trace_store=store,
         llm_call=create_openrouter_llm_call(model=model_id),
@@ -520,9 +521,11 @@ async def main(account_name, post_id):
         print(final_response)
         print("=" * 60)
         print()
-        output_dir = Path("output")
-        output_dir.mkdir(exist_ok=True)
+        # 以脚本所在目录为基准,兼容从项目根或脚本目录启动
+        script_dir = Path(__file__).resolve().parent
+        output_dir = script_dir / "output"
         output_file = output_dir / account_name / "推导日志" / current_trace_id / log_id / "result.txt"
+        output_file.parent.mkdir(parents=True, exist_ok=True)
         with open(output_file, 'w', encoding='utf-8') as f:
             f.write(final_response)
         print(f"✓ 结果已保存到: {output_file}")
@@ -546,4 +549,4 @@ async def main(account_name, post_id):
 if __name__ == "__main__":
     # anthropic/claude-sonnet-4.6
     # google/gemini-3-flash-preview
-    asyncio.run(main(account_name="家有大志", post_id="68fb6a5c000000000302e5de"))
+    asyncio.run(main(account_name="家有大志", post_id="6921937a000000001b0278d1"))

+ 52 - 0
examples_how/overall_derivation/topic_summary_prompt.md

@@ -0,0 +1,52 @@
+# Role
+社交媒体账号分析专家,擅长从碎片化数据中洞察账号品类、人设总结、创作方向。
+
+# Task
+基于提供的账号内容数据,输出结构化JSON分析报告。
+
+# 输入数据说明
+**选题点聚类树**: 
+选题点是通过对该账号下一批帖子进行深度解构得到的选题关键词,在这些选题点基础上分析得到三个维度的json格式的聚类树。
+聚类树json字段说明如下:
+- `_type` 节点类型,class:分类节点,ID:表示叶子节点,具体的选题点
+- `_post_count` 包含该节点的帖子数量
+- `_persona_weight_score` 节点人设权重
+- `_ratio` 节点出现概率
+- `_is_constant` 是否为常量节点,表示该节点在账号下经常出现
+- `_is_local_constant` 是否为局部常量节点,表示该节点在某个方向经常出现
+- `children` 节点的孩子节点
+
+# 分析维度
+
+## 1. 主要品类
+识别账号所属的核心赛道
+
+**规则**:
+- 禁止使用泛化词汇:"生活"、"Vlog"、"日常"
+- 穿透"教学""种草""分享"等形式外壳,识别真正的流量抓手
+
+## 2. 核心总结
+一句话概括账号定位,需包含:**目标人群 + 内容形式/风格 + 核心价值**
+
+## 3. 创作方向
+识别账号内容创作的几个主要方向
+
+# 输出要求
+仅输出JSON,无任何额外文字:
+```json
+{
+  "主要品类": "单一品类词",
+  "核心总结": "一句话人设描述",
+  "创作方向": [
+    "创作方向1",
+    "创作方向2",
+    "创作方向3"
+  ],
+  "分析过程": "简要说明分析过程"
+}
+```
+
+# 输入数据
+
+## 选题点聚类树
+{topic_point_tree}

+ 8 - 8
examples_how/overall_derivation/tree_data_process.py

@@ -113,11 +113,11 @@ def process_tree_json(
 
 
 def main():
-    parser = argparse.ArgumentParser(description="人设树 JSON 精简")
-    parser.add_argument("--minify", action="store_true", help="单行 JSON,减小体积")
-    parser.add_argument("--round", type=int, default=None, metavar="N", help="数值保留 N 位小数")
-    parser.add_argument("--short-keys", action="store_true", help="使用短键名(读取时需还原)")
-    args = parser.parse_args()
+    # parser = argparse.ArgumentParser(description="人设树 JSON 精简")
+    # parser.add_argument("--minify", action="store_true", help="单行 JSON,减小体积")
+    # parser.add_argument("--round", type=int, default=None, metavar="N", help="数值保留 N 位小数")
+    # parser.add_argument("--short-keys", action="store_true", help="使用短键名(读取时需还原)")
+    # args = parser.parse_args()
 
     INPUT_DIR.mkdir(parents=True, exist_ok=True)
     OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
@@ -127,9 +127,9 @@ def main():
         process_tree_json(
             in_file,
             out_file,
-            minify=args.minify,
-            round_ndigits=args.round,
-            short_keys=args.short_keys,
+            minify=False,
+            round_ndigits=4,
+            short_keys=False,
         )
         size = out_file.stat().st_size
         print(f"已处理: {in_file.name} -> {out_file} ({size:,} B)")

Некоторые файлы не были показаны из-за большого количества измененных файлов