record 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. 所有输出不要在通过prompt输出了 应该在每一步返回的结果中,通过代码进行关联
  2. ⏺ 你说得非常对!这是一个架构优化的重要点。
  3. 当前问题
  4. 现状:每一步都通过 prompt 让 LLM 输出完整信息
  5. # Step 5 prompt 中要求 LLM 输出
  6. {
  7. "名称": "实质点名称",
  8. "类型": "元素/概念",
  9. "支撑灵感点得分": 8,
  10. "支撑灵感点依据": "...",
  11. ...
  12. }
  13. 问题:
  14. - ❌ 前面步骤的信息(识别依据、共性分析数据等)需要 LLM 重新输出
  15. - ❌ LLM 可能遗漏或修改前面步骤的数据
  16. - ❌ 数据不一致的风险
  17. - ❌ 浪费 token
  18. ---
  19. 优化方案:代码关联数据
  20. 原则
  21. 每一步只让 LLM 输出该步骤新增的信息,其他信息通过代码合并
  22. 示例
  23. Step 2/3 - 提取
  24. # LLM 只输出
  25. {
  26. "实质点列表": [
  27. {
  28. "名称": "酱料",
  29. "类型": "元素",
  30. "识别依据": "..."
  31. }
  32. ]
  33. }
  34. Step 4 - 共性分析
  35. # LLM 只输出新增的分析数据
  36. llm_result = {
  37. "分析结果": [
  38. {
  39. "名称": "酱料",
  40. "出现段落数": 3,
  41. "段落覆盖率": 0.75,
  42. ...
  43. }
  44. ]
  45. }
  46. # 代码合并:将 Step 2/3 的数据关联进来
  47. analyzed_items = []
  48. for analysis in llm_result["分析结果"]:
  49. # 找到原始实质点
  50. original = find_by_name(all_substantials, analysis["名称"])
  51. # 合并数据
  52. analyzed_items.append({
  53. **original, # 保留原始的 名称、类型、识别依据
  54. **analysis # 添加新的分析数据
  55. })
  56. Step 5 - 评分
  57. # LLM 只输出评分
  58. llm_result = {
  59. "评分结果": [
  60. {
  61. "名称": "酱料",
  62. "支撑灵感点得分": 8,
  63. "支撑灵感点依据": "...",
  64. ...
  65. }
  66. ]
  67. }
  68. # 代码合并
  69. scored_items = []
  70. for score in llm_result["评分结果"]:
  71. # 找到分析数据
  72. analyzed = find_by_name(analyzed_items, score["名称"])
  73. # 合并
  74. scored_items.append({
  75. **analyzed, # 保留前面的所有数据
  76. **score # 添加评分数据
  77. })
  78. Step 7 - 去重
  79. # LLM 只输出去重决策
  80. llm_result = {
  81. "去重决策": [...],
  82. "保留列表": ["酱料", "米饭"] # 只返回名称
  83. }
  84. # 代码执行去重
  85. deduplicated_items = []
  86. for name in llm_result["保留列表"]:
  87. # 找到完整数据
  88. item = find_by_name(filtered_items, name)
  89. deduplicated_items.append(item) # 保留所有历史数据
  90. Step 8 - 整合
  91. # LLM 只输出树状结构(只包含名称和分类)
  92. llm_result = {
  93. "元素列表": [
  94. {
  95. "名称": "调味品",
  96. "描述": "...",
  97. "子项": [
  98. {"名称": "酱料"} # 只有名称
  99. ]
  100. }
  101. ]
  102. }
  103. # 代码填充完整数据
  104. def enrich_tree(node, data_source):
  105. if "子项" in node and node["子项"]:
  106. for child in node["子项"]:
  107. if "名称" in child and "描述" not in child:
  108. # 这是叶子节点,填充完整数据
  109. full_data = find_by_name(data_source, child["名称"])
  110. child.update(full_data)
  111. else:
  112. # 递归处理
  113. enrich_tree(child, data_source)
  114. final_result = llm_result
  115. enrich_tree(final_result, deduplicated_items)
  116. ---
  117. 优势
  118. 1. ✅ 数据一致性:前面步骤的数据不会被 LLM 修改或遗漏
  119. 2. ✅ 节省 token:LLM 只输出新增信息
  120. 3. ✅ 职责清晰:LLM 负责判断,代码负责数据管理
  121. 4. ✅ 减少依赖:后续步骤不需要传入 text_data/images,因为历史数据已包含上下文
  122. ---
  123. 是否要现在重构?
  124. 这是一个较大的架构改动,需要修改所有 8 个步骤。
  125. 建议:
  126. 1. 先确认这个方向是否符合你的需求
  127. 2. 如果确认,我可以逐步重构每个步骤
  128. 你觉得这个方案如何?
  129. > 开始优化吧
  130. ⏺ 好的!我开始优化。让我先创建任务列表,然后逐步重构每个步骤。
  131. ⏺ 现在开始重构 Step 4。让我先读取相关代码:
  132. ⏺ Read(src/components/agents/script_element_extraction_agent.py)
  133. ⎿ Read 160 lines
  134. ⏺ 现在开始重构 Step 4。我将修改为:
  135. 1. LLM 只输出新增的共性分析数据(不包含名称、类型、识别依据)
  136. 2. 代码合并 Step 2/3 的原始数据
  137. ⏺ Update(src/components/agents/script_element_extraction_agent.py)
  138. ⎿ Updated src/components/agents/script_element_extraction_agent.py with 12 additions and 8
  139. removals
  140. 681
  141. 682 对每个实质点进行**共性定量分析**(统计基础数据)。
  142. 683
  143. 684 + **重要**:只输出新增的分析数据,不要重复输出名称、类型、识别依据等已有信息。
  144. 685 +
  145. 686 ## 元素的共性分析(仅针对类型=元素)
  146. 687
  147. 688 1. **出现段落数**:该元素在多少个段落中出现(整数)
  148. ...
  149. 700 3. **核心概念识别**:在每个出现的段落中是主要概念还是辅助概念
  150. 701 - 主要概念:该概念是段落的核心主题
  151. 702 - 辅助概念:该概念是段落的补充说明
  152. 703 - 4. **概念强度**:在每个段落中的重要性权重(0-10分)
  153. 703 + 4. **概念强度详情**:在每个段落中的重要性权重(0-10分)
  154. 704 - 9-10分:段落核心概念,定义段落主题
  155. 705 - 7-8分:段落重要概念,有明显作用
  156. 706 - 5-6分:段落一般概念,有一定作用
  157. ...
  158. 711
  159. 712 - 定量指标必须准确计算
  160. 713 - 所有分析必须有客观依据
  161. 714 + - **只输出名称和对应的分析数据,不要重复已有字段**
  162. 715
  163. 716 # 输出(JSON)
  164. 717
  165. ...
  166. 718 "分析结果": [
  167. 719 {{
  168. 720 "名称": "实质点名称",
  169. 721 - "类型": "元素/概念",
  170. 722 -
  171. 723 - // 元素类型的共性分析
  172. 721 + // 元素类型只输出以下字段
  173. 722 "出现段落数": 3,
  174. 723 "段落覆盖率": 0.75,
  175. 724 "出现频次": 5,
  176. 725 "视觉显著性": 8,
  177. 726 - "视觉显著性依据": "在图片中的位置和显著程度描述",
  178. 727 -
  179. 728 - // 概念类型的共性分析
  180. 726 + "视觉显著性依据": "在图片中的位置和显著程度描述"
  181. 727 + }},
  182. 728 + {{
  183. 729 + "名称": "实质点名称",
  184. 730 + // 概念类型只输出以下字段
  185. 731 "出现段落数": 3,
  186. 732 "段落覆盖率": 0.75,
  187. 733 "核心概念识别": [
  188. ...
  189. 749
  190. 750 **注意**:
  191. 751 - 元素类型的实质点,输出元素相关的共性分析字段
  192. 752 - - 概念类型的实质点,输出概念相关的共性分析字段"""
  193. 752 + - 概念类型的实质点,输出概念相关的共性分析字段
  194. 753 + - 不要输出类型、识别依据等字段,这些会由代码自动合并
  195. 754
  196. 755 # 构建多模态消息
  197. 756 message_content = [{"type": "text", "text": prompt}]
  198. ⏺ 现在添加代码合并逻辑:
  199. ⏺ Update(src/components/agents/script_element_extraction_agent.py)
  200. ⎿ Updated src/components/agents/script_element_extraction_agent.py with 29 additions and 2
  201. removals
  202. 771 ]
  203. 772
  204. 773 # 调用LLM
  205. 774 - result = LLMInvoker.safe_invoke(
  206. 774 + llm_result = LLMInvoker.safe_invoke(
  207. 775 self,
  208. 776 "共性定量分析",
  209. 777 messages,
  210. 778 fallback={"分析结果": []}
  211. 779 )
  212. 780
  213. 781 + # 代码合并:将原始实质点数据与分析数据合并
  214. 782 + analyzed_items = []
  215. 783 + analysis_results = llm_result.get("分析结果", [])
  216. 784 +
  217. 785 + for analysis in analysis_results:
  218. 786 + analysis_name = analysis.get("名称", "")
  219. 787 + # 找到对应的原始实质点
  220. 788 + original = None
  221. 789 + for s in all_substantials:
  222. 790 + if s.get("名称") == analysis_name:
  223. 791 + original = s
  224. 792 + break
  225. 793 +
  226. 794 + if original:
  227. 795 + # 合并数据:原始数据 + 分析数据
  228. 796 + merged_item = {
  229. 797 + **original, # 保留原始的名称、类型、识别依据
  230. 798 + **{k: v for k, v in analysis.items() if k != "名称"} #
  231. + 添加分析数据(排除名称)
  232. 799 + }
  233. 800 + analyzed_items.append(merged_item)
  234. 801 + else:
  235. 802 + logger.warning(f"⚠️ 未找到实质点 '{analysis_name}' 的原始数据")
  236. 803 + # 如果找不到原始数据,仍然保留分析结果
  237. 804 + analyzed_items.append(analysis)
  238. 805 +
  239. 806 + result = {"分析结果": analyzed_items}
  240. 807 +
  241. 808 # 打印结果
  242. 809 import json
  243. 810 - logger.info(f"Step 4
  244. - 结果:\n{json.dumps(result, ensure_ascii=False, indent=2)}")
  245. 810 + logger.info(f"Step 4 合并后
  246. + 结果:\n{json.dumps(result, ensure_ascii=False, indent=2)}")
  247. 811
  248. 812 return result
  249. 813
  250. ⏺ 完成 Step 4!现在继续 Step 5:
  251. ✻ 修改 Step 5… (esc to interrupt · ctrl+t to hide todos · 142s · ↓ 2.9k tokens)
  252. ⎿ ☒ Step 4: 修改为只输出新增的共性分析数据,代码合并 Step 2/3 的原始数据
  253. ☐ Step 5: 修改为只输出评分数据,代码合并 Step 4 的分析数据
  254. ☐ Step 6: 修改筛选逻辑,基于完整数据筛选
  255. ☐ Step 7: 修改为只输出去重决策,代码执行去重并保留完整数据,移除 text_data 参数
  256. ☐ Step 8: 修改为只输出树状结构框架,代码填充完整数据,移除 text_data 参数