| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- """
- Post Summary Deconstruction Agent.
- 帖子整体解构Agent:解构帖子整体的各种描述维度。
- """
- from typing import Dict, Any, List
- import json
- from src.components.agents.base import BaseLLMAgent
- from src.states.what_deconstruction_state import WhatDeconstructionState
- from src.utils.logger import get_logger
- logger = get_logger(__name__)
- class PostSummaryDeconstructionAgent(BaseLLMAgent):
- """帖子整体解构Agent
- 根据 PRD 1.4 - 2.2.2.2 帖子整体节点要求:
- **核心功能**:
- 1. 综合所有子元素的解构结果(图片、文本)
- 2. 从多个描述维度解构帖子整体
- 3. 帖子总体的各种描述、总结、归纳等维度或角度,每一个维度都是一个字段项
- **必须满足的约束条件**:
- 1. 维度名称和数量根据每篇帖子动态变化
- 2. **一定要包含本帖子最关键/最吸引内容消费者的亮点维度**
- - 包括但不限于:内容亮点、情绪共鸣点、创作手法等维度
- 3. **描述维度的数量不得少于3个**
- - 要尽可能多而全的覆盖这个帖子的所有可描述角度
- 4. 包括但不限于:品类、主题、脚本等维度
- 5. 描述维度应根据帖子的品类、主题、关键词等信息来向知识库动态请求询问
- """
- def __init__(
- self,
- name: str = "post_summary_deconstruction_agent",
- description: str = "解构帖子整体的各种描述维度",
- model_provider: str = "google_genai",
- temperature: float = 0.1,
- max_tokens: int = 10240
- ):
- system_prompt = """你是一个专业的内容分析专家。你的任务是从多个维度解构帖子整体。
- 根据 PRD 1.4 - 2.2.2.2 帖子整体节点要求:
- **核心任务**:
- 1. 综合分析所有子元素(图片、文本)的解构结果
- 2. 从多个描述维度解构帖子整体
- 3. 帖子总体的各种描述、总结、归纳等维度或角度,每一个维度都是一个字段项
- **必须满足的约束条件**:
- 1. ✅ 维度名称和数量根据每篇帖子动态变化
- 2. ✅ **一定要包含本帖子最关键/最吸引内容消费者的亮点维度**
- - 包括但不限于:内容亮点、情绪共鸣点、创作手法等维度
- 3. ✅ **描述维度的数量不得少于3个**
- - 要尽可能多而全的覆盖这个帖子的所有可描述角度
- 4. ✅ 包括但不限于:品类、主题、脚本等维度
- 5. ✅ 描述维度应根据帖子的品类、主题、关键词等信息来向知识库动态请求询问
- - Query句式(参见 PRD 1.4 - 3.2):
- 对于一篇主题为"{帖子主题}",品类为"{帖子品类}",关键词包含"{帖子关键词列表}"的多模态社交媒体帖子,
- 从内容创作者视角进行What要素的初步识别和分类,需要使用哪些通用工具?
- **输出格式必须是JSON**:
- {
- "品类": "值",
- "主题": "值",
- "脚本": "值",
- "内容亮点": "值", # 必须包含
- "情绪共鸣点": "值", # 必须包含
- "创作手法": "值", # 必须包含
- "整体风格": "值",
- "视觉呈现": "值",
- "内容价值": "值",
- "目标受众": "值",
- ... # 其他动态维度(根据帖子特点)
- }
- **输出要求**:
- 1. ✅ 客观准确,严格基于实际解构结果,禁止主观臆测、凭空假设、虚构数据
- 2. ✅ 维度名称和数量根据帖子内容动态确定
- 3. ✅ 突出核心特征和亮点
- 4. ✅ **最少包含3个描述维度**
- 5. ✅ 必须包含"内容亮点"、"情绪共鸣点"、"创作手法"等吸引消费者的亮点维度
- """
- super().__init__(
- name=name,
- description=description,
- model_provider=model_provider,
- system_prompt=system_prompt,
- temperature=temperature,
- max_tokens=max_tokens
- )
- def _build_messages(self, state: WhatDeconstructionState) -> List[Dict[str, Any]]:
- """构建消息
- 包含所有子元素解构结果、消费者亮点、总结维度
- """
- messages = [
- {"role": "system", "content": self.system_prompt}
- ]
- # 构建用户消息
- user_prompt = "# 帖子解构结果\n\n"
- # 添加帖子基本信息
- category = state.get("category", "未知")
- theme = state.get("theme", "未知")
- keywords = state.get("keywords", [])
- user_prompt += f"**品类**:{category}\n"
- user_prompt += f"**主题**:{theme}\n"
- user_prompt += f"**关键词**:{', '.join(keywords)}\n\n"
- # 添加图片解构结果
- image_results = state.get("image_deconstruction_results", [])
- if image_results:
- user_prompt += "## 图片元素解构\n\n"
- for idx, img_result in enumerate(image_results, 1):
- what = img_result.get("what", "")
- desc = img_result.get("description", img_result.get("描述", {}))
- user_prompt += f"### 图片 {idx}\n"
- user_prompt += f"**What**: {what}\n"
- user_prompt += f"**描述**: {json.dumps(desc, ensure_ascii=False, indent=2)}\n\n"
- # 添加文本解构结果
- text_results = state.get("text_deconstruction_results", [])
- if text_results:
- user_prompt += "## 文本元素解构\n\n"
- for idx, text_result in enumerate(text_results, 1):
- what = text_result.get("what", "")
- desc = text_result.get("description", text_result.get("描述", {}))
- user_prompt += f"### 文本元素 {idx}\n"
- user_prompt += f"**What**: {what}...\n" # 限制长度
- user_prompt += f"**描述**: {json.dumps(desc, ensure_ascii=False, indent=2)}\n\n"
- # 添加消费者亮点
- consumer_highlights = state.get("consumer_highlights", [])
- if consumer_highlights:
- user_prompt += "## 消费者关注的亮点\n\n"
- for idx, highlight in enumerate(consumer_highlights, 1):
- element = highlight.get("element", "")
- highlight_desc = highlight.get("highlight", "")
- emotion = highlight.get("emotion", "")
- user_prompt += f"{idx}. **{element}**: {highlight_desc} ({emotion})\n"
- user_prompt += "\n"
- # 添加总结维度要求
- # 根据 PRD 1.4 - 2.2.2.2:
- # - 描述维度有哪些、有多少个,需要根据本帖子的品类、主题、关键词等信息来向知识库动态请求询问
- # - Query句式:参见3.2 环节中对query的定义
- # 这里使用默认维度作为示例(实际应从知识库获取)
- summary_dimensions = state.get("summary_dimensions", [
- "品类",
- "主题",
- "脚本",
- "内容亮点",
- "情绪共鸣点",
- "创作手法",
- "整体风格",
- "视觉呈现",
- "内容价值",
- "目标受众"
- ])
- user_prompt += "## 解构维度\n\n"
- user_prompt += "请根据以下维度进行帖子整体解构(至少包含3个维度):\n"
- for dim in summary_dimensions:
- user_prompt += f"- {dim}\n"
- user_prompt += "\n请严格按照JSON格式输出,字段名为上述维度名。至少包含3个描述维度。"
- messages.append({"role": "user", "content": user_prompt})
- return messages
- def _update_state(self, state: WhatDeconstructionState, response: Any) -> Dict[str, Any]:
- """更新状态
- 解析LLM返回的JSON,更新帖子整体
- """
- try:
- # 提取响应内容
- if hasattr(response, 'content'):
- content = response.content
- else:
- content = str(response)
- # 尝试提取JSON
- content = content.strip()
- if "```json" in content:
- content = content.split("```json")[1].split("```")[0].strip()
- elif "```" in content:
- content = content.split("```")[1].split("```")[0].strip()
- # 解析JSON
- result = json.loads(content)
- # 返回更新后的字段
- return {
- "post_overall": result # 更新为 post_overall
- }
- except Exception as e:
- logger.error(f"解析帖子整体响应失败: {e},原始内容: {response}")
- # 返回默认值
- return {
- "post_overall": {
- "错误": f"解析失败: {str(e)}"
- }
- }
|