# What解构业务技术设计文档 v2.0

> **文档目标**: 为开发者提供清晰、可执行的技术实现指导
>
> **设计原则**: 每个决策都有明确的PRD依据和技术理由

---

## 目录
1. [PRD目标解析](#1-prd目标解析)
2. [功能需求拆解](#2-功能需求拆解)
3. [工作流 vs 组件职责划分](#3-工作流-vs-组件职责划分)
4. [工作流设计](#4-工作流设计)
5. [组件设计](#5-组件设计)
6. [数据结构设计](#6-数据结构设计)
7. [实现路线图](#7-实现路线图)

---

## 1. PRD目标解析

### 1.1 核心目标是什么？

**PRD原文** (1. 需求目标):
> 针对给定的小红书多模态内容（图文、视频、音频），从消费者视角进行充分必要的What要素逆向解构，通过层级化递归深入分析，识别和提取内容中所有构成成分"what"。

**核心目标拆解**:

| 维度 | 具体含义 | PRD依据 |
|------|---------|---------|
| **输入对象** | 小红书多模态内容（图+文+视频+音频） | 2.1.1节 |
| **视角** | 从消费者视角分析 | 1. 需求目标 |
| **方法** | 层级化递归深入分析 | 1. 需求目标、2.2.3节 |
| **产出** | What要素树（JSON结构） | 2.2.1节、2.2.2节 |
| **价值** | 通过聚合分析提取爆款特征和趋势 | 1. 需求目标（核心价值） |

**目标提炼**:
> **构建一个递归解构系统，将多模态帖子内容自上而下、从整体到局部地拆解为树状的"What元素"结构，每个元素包含动态描述维度（由知识库提供），并关联原始素材。**

### 1.2 关键约束条件

**PRD依据** (2.2.3节、4节):

1. **递归深度**: 最多10层
2. **停止条件**:
   - 已是不可再分的最小单元
   - 达到10层深度
3. **解构原则**:
   - 由宏观到微观、由整体到局部
   - 子节点不重不漏（充分必要）
4. **知识驱动**: 描述维度、分割判断都由知识库动态提供
5. **客观性**: 严格基于帖子内容，禁止臆测

---

## 2. 功能需求拆解

### 2.1 核心功能清单

基于PRD 3.1节"总体解构流程"和3.3节"对单一节点的递归解构"，提炼出以下核心功能：

| 功能ID | 功能名称 | 功能描述 | PRD依据 | 实现方式 |
|--------|---------|---------|---------|---------|
| **F1** | 帖子初理解 | 分析帖子整体，提取品类、主题、关键词 | 3.1节步骤1 | Agent组件 |
| **F2** | 知识需求生成 | 根据品类/主题/关键词生成解构所需的query | 3.2节 | 工作流逻辑 |
| **F3** | 知识检索 | 调用知识库获取描述维度、工具推荐、分割判断 | 3.2节、3.3.2节 | Tool组件 |
| **F4** | 评论理解 | 分析评论，提取消费者关注的亮点 | 3.1节步骤4 | Agent组件 |
| **F5** | 图片递归解构 | 递归解构图片元素，直到不可再分 | 3.1节步骤6-7、3.3节 | Agent组件 |
| **F6** | 图片分割 | 将图片分割为多个独立的视觉元素 | 3.3.1节、3.5节 | Tool组件 |
| **F7** | 文本递归解构 | 递归解构文本元素（标题/正文/标签） | 3.1节步骤8-11、3.3节 | Agent组件 |
| **F8** | 文本切分 | 根据知识库指导切分文本 | 3.5节 | Function组件 |
| **F9** | 帖子整体解构 | 从点线面体维度总结帖子 | 3.1节步骤13、3.2节 | Agent组件 |
| **F10** | 结果汇总 | 将所有解构结果组装为树状JSON | 2.2.2节 | Function组件 |

### 2.2 功能依赖关系

```
F1(帖子初理解)
  ↓
F2(知识需求生成) → F3(知识检索)
  ↓
F4(评论理解)
  ↓
[F5(图片递归解构) + F6(图片分割)] 并行 [F7(文本递归解构) + F8(文本切分)]
  ↓
F9(帖子整体解构)
  ↓
F10(结果汇总)
```

**关键观察**:
- F5和F7内部都会多次调用F3(知识检索)
- F6和F8是F5、F7的支撑工具
- F2是一个轻量级逻辑，不需要独立组件

---

## 3. 工作流 vs 组件职责划分

### 3.1 划分原则

**CLAUDE.md原则**:
> - **工作流**：负责编排组件执行顺序和流程逻辑
> - **组件**：实现具体业务功能

### 3.2 职责划分表

| 功能 | 实现方式 | 决策依据 |
|------|---------|---------|
| **F1 帖子初理解** | **Agent组件** | 需要多模态理解+语义推理（不确定性任务） |
| **F2 知识需求生成** | **工作流逻辑** | 简单的字符串拼接，不需要独立组件 |
| **F3 知识检索** | **Tool组件** | 需要被Agent调用 + 确定性API调用 |
| **F4 评论理解** | **Agent组件** | 需要情感分析+语义理解（不确定性任务） |
| **F5 图片递归解构** | **Agent组件** | 需要LLM视觉理解+ReAct模式调用工具 |
| **F6 图片分割** | **Tool组件** | 需要被Agent调用 + 确定性模型调用 |
| **F7 文本递归解构** | **Agent组件** | 需要LLM语义理解+ReAct模式调用工具 |
| **F8 文本切分** | **Function组件** | 确定性字符串处理 + 工作流直接调用 |
| **F9 帖子整体解构** | **Agent组件** | 需要综合分析+抽象提炼（不确定性任务） |
| **F10 结果汇总** | **Function组件** | 确定性数据结构转换 + 工作流直接调用 |
| **递归控制** | **工作流逻辑** | 编排递归流程，管理状态和深度 |
| **并行执行** | **工作流逻辑** | 编排图片和文本并行解构 |

**总结**:
- **1个主工作流**: WhatDeconstructionWorkflow
- **5个Agent组件**: F1, F4, F5, F7, F9
- **2个Tool组件**: F3, F6
- **2个Function组件**: F8, F10

---

## 4. 工作流设计

### 4.1 工作流核心职责

**WhatDeconstructionWorkflow** 的核心职责：

1. **编排执行顺序**: 按PRD 3.1节流程图编排各组件
2. **管理状态传递**: 维护 WhatDeconstructionState，在各节点间传递数据
3. **控制递归深度**: 确保不超过10层
4. **并行执行控制**: 图片和文本解构并行执行
5. **知识query生成**: 根据中间结果动态生成知识库query

### 4.2 工作流流程图

**PRD依据**: 3.1节"总体解构流程"

```mermaid
graph TD
    START([开始]) --> N1[节点1: 帖子初理解<br/>PostUnderstandingAgent]
    N1 --> N2[节点2: 评论理解<br/>CommentAnalysisAgent]
    N2 --> PARALLEL{并行分支}

    PARALLEL --> N3[节点3: 图片递归解构<br/>RecursiveImageDeconstructionAgent]
    PARALLEL --> N4[节点4: 文本递归解构<br/>RecursiveTextDeconstructionAgent]

    N3 --> N5[节点5: 帖子整体解构<br/>PostSummaryDeconstructionAgent]
    N4 --> N5

    N5 --> N6[节点6: 结果汇总<br/>ResultAggregationFunction]
    N6 --> END([结束])

    style N3 fill:#e1f5ff
    style N4 fill:#e1f5ff
    style PARALLEL fill:#fff3cd
```

**流程说明**:

| 节点 | 输入 | 输出 | PRD依据 |
|------|------|------|---------|
| N1 | 帖子多模态内容 | category, theme, keywords | 3.1节步骤1 |
| N2 | 评论列表 | consumer_highlights | 3.1节步骤4 |
| N3 | images列表 | image_deconstruction_results | 3.1节步骤6-7 |
| N4 | text对象 | text_deconstruction_results | 3.1节步骤8-11 |
| N5 | 所有子元素解构结果 | post_summary | 3.1节步骤13 |
| N6 | 所有解构结果 | final_result (JSON树) | 2.2.2节 |

### 4.3 工作流核心代码框架

```python
from langgraph.graph import StateGraph, END
from typing import TypedDict, List, Dict, Any

# 1. 定义状态
class WhatDeconstructionState(TypedDict):
    """工作流状态定义"""
    # 输入
    images: List[str]
    text: Dict[str, Any]  # {title, body, hashtags}
    comments: List[Dict[str, str]]

    # 中间状态
    category: str
    theme: str
    keywords: List[str]
    consumer_highlights: List[Dict]

    # 解构结果
    image_deconstruction_results: List[Dict]
    text_deconstruction_results: List[Dict]
    post_summary: Dict[str, Any]

    # 最终输出
    final_result: Dict[str, Any]

# 2. 工作流类
class WhatDeconstructionWorkflow:
    """What解构主工作流"""

    def __init__(self, llm, knowledge_retrieval_tool, image_segment_tool):
        # 初始化所有组件
        self.post_understanding_agent = PostUnderstandingAgent(llm)
        self.comment_analysis_agent = CommentAnalysisAgent(llm)
        self.image_agent = RecursiveImageDeconstructionAgent(
            llm, knowledge_retrieval_tool, image_segment_tool, max_depth=10
        )
        self.text_agent = RecursiveTextDeconstructionAgent(
            llm, knowledge_retrieval_tool, max_depth=10
        )
        self.summary_agent = PostSummaryDeconstructionAgent(llm, knowledge_retrieval_tool)
        self.aggregation_func = ResultAggregationFunction()

        # 构建图
        self.graph = self._build_graph()

    def _build_graph(self) -> StateGraph:
        """构建LangGraph工作流"""
        workflow = StateGraph(WhatDeconstructionState)

        # 添加节点
        workflow.add_node("post_understanding", self._node_post_understanding)
        workflow.add_node("comment_analysis", self._node_comment_analysis)
        workflow.add_node("image_deconstruction", self._node_image_deconstruction)
        workflow.add_node("text_deconstruction", self._node_text_deconstruction)
        workflow.add_node("post_summary", self._node_post_summary)
        workflow.add_node("result_aggregation", self._node_result_aggregation)

        # 定义边（流程）
        workflow.set_entry_point("post_understanding")
        workflow.add_edge("post_understanding", "comment_analysis")

        # 并行分支：评论理解后，图片和文本并行解构
        workflow.add_edge("comment_analysis", "image_deconstruction")
        workflow.add_edge("comment_analysis", "text_deconstruction")

        # 汇聚：图片和文本都完成后，执行帖子整体解构
        workflow.add_edge("image_deconstruction", "post_summary")
        workflow.add_edge("text_deconstruction", "post_summary")

        workflow.add_edge("post_summary", "result_aggregation")
        workflow.add_edge("result_aggregation", END)

        return workflow.compile()

    # 3. 节点实现
    async def _node_post_understanding(self, state: WhatDeconstructionState):
        """节点1: 帖子初理解"""
        result = await self.post_understanding_agent.ainvoke({
            "images": state["images"],
            "text": state["text"]
        })
        return {
            "category": result["category"],
            "theme": result["theme"],
            "keywords": result["keywords"]
        }

    async def _node_comment_analysis(self, state: WhatDeconstructionState):
        """节点2: 评论理解"""
        result = await self.comment_analysis_agent.ainvoke({
            "comments": state["comments"],
            "post_content": state["text"]
        })
        return {"consumer_highlights": result["highlights"]}

    async def _node_image_deconstruction(self, state: WhatDeconstructionState):
        """节点3: 图片递归解构（处理所有图片）"""
        results = []
        for idx, image_path in enumerate(state["images"]):
            result = await self.image_agent.ainvoke({
                "image_path": image_path,
                "node_id": f"img_{idx+1}",
                "depth": 0,
                "category": state["category"],
                "theme": state["theme"]
            })
            results.append(result)
        return {"image_deconstruction_results": results}

    async def _node_text_deconstruction(self, state: WhatDeconstructionState):
        """节点4: 文本递归解构（标题+正文+标签）"""
        results = []
        text_data = state["text"]

        # 解构标题
        if text_data.get("title"):
            title_result = await self.text_agent.ainvoke({
                "text": text_data["title"],
                "text_type": "title",
                "node_id": "title",
                "depth": 0
            })
            results.append(title_result)

        # 解构正文
        if text_data.get("body"):
            body_result = await self.text_agent.ainvoke({
                "text": text_data["body"],
                "text_type": "body",
                "node_id": "body",
                "depth": 0
            })
            results.append(body_result)

        # 解构话题标签
        if text_data.get("hashtags"):
            hashtags_result = await self.text_agent.ainvoke({
                "text": " ".join(text_data["hashtags"]),
                "text_type": "hashtags",
                "node_id": "hashtags",
                "depth": 0
            })
            results.append(hashtags_result)

        return {"text_deconstruction_results": results}

    async def _node_post_summary(self, state: WhatDeconstructionState):
        """节点5: 帖子整体解构"""
        result = await self.summary_agent.ainvoke({
            "category": state["category"],
            "theme": state["theme"],
            "keywords": state["keywords"],
            "image_results": state["image_deconstruction_results"],
            "text_results": state["text_deconstruction_results"],
            "consumer_highlights": state["consumer_highlights"]
        })
        return {"post_summary": result["summary"]}

    async def _node_result_aggregation(self, state: WhatDeconstructionState):
        """节点6: 结果汇总"""
        final_result = self.aggregation_func.invoke({
            "post_summary": state["post_summary"],
            "image_results": state["image_deconstruction_results"],
            "text_results": state["text_deconstruction_results"]
        })
        return {"final_result": final_result}

    # 4. 入口方法
    async def ainvoke(self, input_data: Dict) -> Dict:
        """执行工作流"""
        initial_state = WhatDeconstructionState(
            images=input_data["multimedia_content"]["images"],
            text=input_data["multimedia_content"]["text"],
            comments=input_data["comments"]
        )
        result = await self.graph.ainvoke(initial_state)
        return result["final_result"]
```

**关键设计点**:

1. **并行执行**: `image_deconstruction` 和 `text_deconstruction` 从 `comment_analysis` 同时出发
2. **状态传递**: 通过 `WhatDeconstructionState` 在节点间传递数据
3. **递归封装**: 图片/文本的递归逻辑封装在各自的Agent内部
4. **知识库调用**: 在Agent内部调用 KnowledgeRetrievalTool

---

## 5. 组件设计

### 5.1 Agent组件总览

**CLAUDE.md原则**:
> **Agent组件特征**: 不确定性任务 + LLM智能能力 + 推理/多模态理解/语义分析

| Agent | 任务类型 | LLM能力需求 | PRD依据 |
|-------|---------|------------|---------|
| PostUnderstandingAgent | 多模态理解 | 图文融合理解 | 3.1节步骤1 |
| CommentAnalysisAgent | 语义理解 | 情感分析、关键点提取 | 3.1节步骤4、2.1.4节 |
| RecursiveImageDeconstructionAgent | 视觉理解+推理 | 图片理解、分割判断 | 3.3节、3.3.1节 |
| RecursiveTextDeconstructionAgent | 语义理解+推理 | 文本分析、切分判断 | 3.3节 |
| PostSummaryDeconstructionAgent | 综合分析 | 抽象提炼、多维度总结 | 3.2节 |

---

### 5.2 Agent组件详细设计

#### 5.2.1 PostUnderstandingAgent（帖子初理解）

**组件类型**: Agent (继承 BaseLLMAgent)

**选择依据**:
- **PRD依据**: 3.1节步骤1 "帖子初理解，输出品类、主题、关键词"
- **CLAUDE.md依据**: 需要多模态理解（图+文），属于不确定性任务

**核心职责**:
1. 综合分析图片和文本内容
2. 推理提取品类（如"时尚美妆"、"美食"等）
3. 总结主题（如"夏日穿搭"）
4. 提取关键词（如"OOTD"、"小白裙"）

**关键点**:

| 关键点 | 实现方式 | 依据 |
|--------|---------|------|
| **多模态输入** | 将图片和文本一起输入给LLM | LLM具备多模态理解能力 |
| **结构化输出** | 使用JSON格式约束LLM输出 | 需要提取固定字段 |
| **品类识别准确性** | 在prompt中提供常见品类列表 | 提升品类识别准确性 |

**代码框架**:

```python
from agents.base import BaseLLMAgent
from typing import List, Dict, Any

class PostUnderstandingAgent(BaseLLMAgent):
    """帖子初理解Agent

    PRD依据: 3.1节步骤1
    功能: 分析帖子多模态内容，提取品类、主题、关键词
    """

    async def ainvoke(self, state: Dict[str, Any]) -> Dict[str, Any]:
        """
        执行帖子理解

        Args:
            state: {
                "images": List[str],  # 图片路径列表
                "text": {             # 文本内容
                    "title": str,
                    "body": str,
                    "hashtags": List[str]
                }
            }

        Returns:
            {
                "category": str,      # 品类
                "theme": str,         # 主题
                "keywords": List[str] # 关键词
            }
        """
        # 1. 构建多模态prompt
        prompt = self._build_prompt(state["images"], state["text"])

        # 2. 调用LLM
        response = await self.llm.ainvoke(prompt)

        # 3. 解析结果
        result = self._parse_response(response)

        return result

    def _build_prompt(self, images: List[str], text: Dict) -> str:
        """构建prompt

        关键点:
        - 多模态输入（图片+文本）
        - 明确要求输出JSON格式
        - 提供品类参考列表
        """
        return f"""
你是一个小红书内容分析专家。请分析以下帖子的多模态内容，提取品类、主题和关键词。

【文本内容】
标题: {text.get('title', '')}
正文: {text.get('body', '')}
话题标签: {', '.join(text.get('hashtags', []))}

【图片】
{self._format_images(images)}

【常见品类参考】
时尚美妆、美食、旅游、家居、母婴、运动健身、数码科技等

请以JSON格式输出:
{{
    "category": "品类",
    "theme": "主题",
    "keywords": ["关键词1", "关键词2", ...]
}}
"""

    def _parse_response(self, response: str) -> Dict:
        """解析LLM响应，提取JSON"""
        import json
        # 提取JSON部分
        json_str = self._extract_json(response)
        return json.loads(json_str)
```

---

#### 5.2.2 CommentAnalysisAgent（评论理解）

**组件类型**: Agent (继承 BaseLLMAgent)

**选择依据**:
- **PRD依据**: 2.1.4节 "评论信息用于提取内容消费者关注的亮点"
- **CLAUDE.md依据**: 需要情感分析和语义理解，属于不确定性任务

**核心职责**:
1. 分析评论区文字内容
2. 识别消费者关注的亮点（对应帖子的哪些元素）
3. 提取高频关注点和情绪共鸣点

**关键点**:

| 关键点 | 实现方式 | 依据 |
|--------|---------|------|
| **亮点映射** | 将评论中的关注点映射到帖子具体元素 | PRD 2.1.4节要求 |
| **情感分析** | 识别评论的情感倾向（共鸣、兴趣、疑问等） | 理解消费者反应 |
| **高频提取** | 聚合多条评论的共同关注点 | 识别关键吸引点 |

**代码框架**:

```python
class CommentAnalysisAgent(BaseLLMAgent):
    """评论理解Agent

    PRD依据: 2.1.4节
    功能: 分析评论，提取消费者关注的亮点
    """

    async def ainvoke(self, state: Dict[str, Any]) -> Dict[str, Any]:
        """
        执行评论分析

        Args:
            state: {
                "comments": List[Dict],  # [{user, content}, ...]
                "post_content": Dict     # 帖子内容（用于映射）
            }

        Returns:
            {
                "highlights": List[Dict]  # 消费者关注的亮点列表
                # [
                #   {
                #     "element": "封面图中的小白裙",
                #     "reason": "多条评论询问购买链接",
                #     "emotion": "兴趣、购买意愿"
                #   },
                #   ...
                # ]
            }
        """
        prompt = self._build_prompt(state["comments"], state["post_content"])
        response = await self.llm.ainvoke(prompt)
        return {"highlights": self._parse_highlights(response)}

    def _build_prompt(self, comments: List[Dict], post_content: Dict) -> str:
        """构建prompt

        关键点:
        - 提供帖子内容作为参考（用于映射）
        - 要求识别具体元素
        - 要求分析情感和关注原因
        """
        comments_text = "\n".join([
            f"- {c['content']}" for c in comments
        ])

        return f"""
你是一个内容分析专家。请分析评论区内容，提取消费者关注的亮点。

【帖子内容】
标题: {post_content.get('title', '')}
正文: {post_content.get('body', '')}

【评论区】
{comments_text}

请分析:
1. 评论中提到了帖子的哪些具体元素（封面、图片、标题、正文中的哪部分）
2. 消费者对这些元素的关注原因（为什么吸引他们）
3. 评论的情感倾向（共鸣、兴趣、疑问、赞美等）

以JSON格式输出亮点列表:
{{
    "highlights": [
        {{
            "element": "具体元素描述",
            "reason": "关注原因",
            "emotion": "情感倾向"
        }},
        ...
    ]
}}
"""
```

---

#### 5.2.3 RecursiveImageDeconstructionAgent（图片递归解构）

**组件类型**: Agent (继承 BaseReactAgent)

**选择依据**:
- **PRD依据**: 3.3节 "对单一节点的递归解构"、3.3.1节 "判断图片元素是否要继续分割拆解"
- **CLAUDE.md依据**: 需要LLM视觉理解 + 动态调用工具（ReAct模式）

**核心职责**:
1. 粗理解图片，生成what字段
2. 调用知识库获取描述维度
3. 细致理解图片，填充描述值
4. 判断是否需要分割（调用知识库）
5. 如需分割，调用图片分割工具
6. 递归处理子元素（最多10层）

**关键点**:

| 关键点 | 实现方式 | PRD依据 |
|--------|---------|---------|
| **ReAct模式** | 思考→行动→观察循环 | 需要多次调用工具 |
| **递归控制** | 深度参数 + 停止条件判断 | 2.2.3节（最多10层） |
| **知识驱动** | 描述维度和分割判断都由知识库提供 | 3.3.2节 |
| **分割优先判断** | 优先判断是否为多子图拼接 | 3.3.1节 |
| **what字段生成** | 对图片的文本描述 | 2.2.2节 |
| **判断不依赖分割** | 判断是否拆解基于完整原图+文字描述，不依赖分割结果 | PRD 3.3.1节原则 |

**递归流程图**:

```mermaid
graph TD
    START([接收图片节点]) --> DEPTH{检查深度<br/>是否≥10层?}
    DEPTH -->|是| STOP([返回结果<br/>不再递归])
    DEPTH -->|否| ROUGH[粗理解图片<br/>基于完整原图+节点描述<br/>生成what字段]

    ROUGH --> QUERY1[生成query:<br/>获取描述维度]
    QUERY1 --> KB1[调用知识库]
    KB1 --> DETAIL[细致理解图片<br/>基于完整原图+节点描述+维度<br/>填充描述维度值]

    DETAIL --> QUERY2[生成query:<br/>是否需要分割?]
    QUERY2 --> KB2[调用知识库<br/>基于完整原图+what+描述]
    KB2 --> DECISION{知识库判断:<br/>是否分割?}

    DECISION -->|否| STOP
    DECISION -->|是| IDENTIFY[识别子元素<br/>基于完整原图<br/>生成子元素描述]
    IDENTIFY --> SEGMENT[调用图片分割工具<br/>传入完整原图<br/>获得子图片列表]

    SEGMENT --> RECURSE[遍历子图片<br/>递归调用自身<br/>传递完整原图]
    RECURSE --> STOP

    style ROUGH fill:#e1f5ff
    style DETAIL fill:#e1f5ff
    style KB1 fill:#fff3cd
    style KB2 fill:#fff3cd
    style SEGMENT fill:#d4edda
```

**代码框架**:

```python
from agents.base import BaseReactAgent
from tools.base import BaseTool
from typing import List, Dict, Any

class RecursiveImageDeconstructionAgent(BaseReactAgent):
    """图片递归解构Agent

    PRD依据: 3.3节、3.3.1节
    功能: 递归解构图片元素，最多10层
    """

    def __init__(
        self,
        llm,
        knowledge_retrieval_tool: BaseTool,
        image_segment_tool: BaseTool,
        max_depth: int = 10
    ):
        super().__init__(llm, tools=[knowledge_retrieval_tool, image_segment_tool])
        self.knowledge_tool = knowledge_retrieval_tool
        self.segment_tool = image_segment_tool
        self.max_depth = max_depth

    async def ainvoke(self, state: Dict[str, Any]) -> Dict[str, Any]:
        """
        递归解构图片

        Args:
            state: {
                "original_image_path": str,  # **完整原图路径**（PRD 3.3.1：始终传递未分割的完整图）
                "current_image_path": str,   # 当前节点对应的图片路径（首次调用时=original_image_path）
                "node_description": str,     # 当前节点的文字描述（首次为空，递归时为子元素描述）
                "node_id": str,              # 节点ID（如"1", "1_1"）
                "depth": int,                # 当前递归深度
                "category": str,             # 帖子品类（用于生成query）
                "theme": str                 # 帖子主题（用于生成query）
            }

        Returns:
            {
                "id": str,
                "what": str,
                "description": Dict,
                "children": List[Dict],  # 子元素（递归结构）
                "importance_weight": float
            }
        """
        # 步骤1: 检查递归深度（PRD 2.2.3节）
        if state["depth"] >= self.max_depth:
            return self._build_leaf_node(state)

        # 步骤2: 粗理解当前节点，生成what字段（PRD 3.3节流程步骤B0）
        # **关键**: 基于完整原图 + 节点描述进行理解（PRD 3.3.1原则）
        what_value = await self._rough_understanding(
            original_image=state["original_image_path"],
            current_image=state["current_image_path"],
            node_description=state.get("node_description", "")
        )

        # 步骤3: 调用知识库获取描述维度（PRD 3.3.2节）
        description_query = self._generate_description_query(what_value)
        description_dimensions = await self.knowledge_tool.ainvoke({
            "query": description_query,
            "query_type": "description"
        })

        # 步骤4: 根据描述维度细致理解当前节点（PRD 3.3节流程步骤C）
        # **关键**: 基于完整原图 + 节点描述 + 描述维度进行理解（PRD 3.3.1原则）
        description_values = await self._detailed_understanding(
            original_image=state["original_image_path"],
            current_image=state["current_image_path"],
            node_description=state.get("node_description", ""),
            description_dimensions=description_dimensions
        )

        # 步骤5: 判断是否需要分割（PRD 3.3节流程步骤D0）
        # **关键**: 判断分割的输入是完整原图 + what + 描述，不依赖分割结果（PRD 3.3.1原则）
        split_query = self._generate_split_query(what_value, description_values)
        split_decision = await self.knowledge_tool.ainvoke({
            "query": split_query,
            "query_type": "split_decision"
        })

        # 构建当前节点结果
        result = {
            "id": state["node_id"],
            "what": what_value,
            "description": description_values,
            "children": [],
            "importance_weight": 0.5  # TODO: 计算权重逻辑
        }

        # 步骤6: 如需分割，执行分割并递归（PRD 3.3节流程步骤E1-E2）
        if split_decision.get("should_split", False):
            # 识别子元素（基于完整原图 + 当前节点描述）
            sub_elements = await self._identify_sub_elements(
                original_image=state["original_image_path"],
                current_node_what=what_value,
                current_node_description=state.get("node_description", "")
            )

            # 调用分割工具（输入：完整原图 + 子元素描述列表）
            sub_images = await self.segment_tool.ainvoke({
                "image_path": state["original_image_path"],  # **传入完整原图**
                "elements_description": sub_elements
            })

            # 递归处理每个子元素
            children = []
            for idx, (sub_img_path, sub_element_desc) in enumerate(zip(sub_images, sub_elements)):
                child_state = {
                    "original_image_path": state["original_image_path"],  # **传递完整原图**
                    "current_image_path": sub_img_path,  # 分割后的子图片
                    "node_description": sub_element_desc,  # 子元素的文字描述
                    "node_id": f"{state['node_id']}_{idx+1}",
                    "depth": state["depth"] + 1,
                    "category": state["category"],
                    "theme": state["theme"]
                }
                child_result = await self.ainvoke(child_state)
                children.append(child_result)

            result["children"] = children

        return result

    async def _rough_understanding(
        self,
        original_image: str,
        current_image: str,
        node_description: str
    ) -> str:
        """粗理解当前节点，生成what字段

        PRD依据: 3.3节步骤B0, 3.3.1节原则
        关键点: 基于完整原图 + 节点描述进行理解

        Args:
            original_image: 完整原图路径（提供上下文）
            current_image: 当前节点对应的图片路径
            node_description: 当前节点的文字描述（首次为空，递归时为子元素描述）
        """
        # 构建prompt：如果有节点描述，说明是递归调用，需要结合原图理解特定部分
        if node_description:
            prompt = f"""
请基于完整原图的上下文，描述指定的视觉元素。

【完整原图】: {original_image}
【当前关注的元素描述】: {node_description}
【当前元素图片】: {current_image}

请用一句话描述这个视觉元素的核心内容。
要求: 简洁准确，聚焦于该元素本身。
"""
        else:
            # 首次调用，直接理解整图
            prompt = f"""
请用一句话描述这张图片的核心内容和视觉元素。
要求: 简洁准确，涵盖主要视觉要素。

图片: {original_image}
"""
        response = await self.llm.ainvoke(prompt)
        return response.strip()

    def _generate_description_query(self, what_value: str) -> str:
        """生成描述维度query

        PRD依据: 3.3.2节、2.2.2节
        Query句式: PRD 3.3.2节定义
        """
        return f'刻画描述"{what_value}"核心特征的角度和维度有哪些？请尽可能不重不漏列举全。'

    def _generate_split_query(self, what_value: str, description: Dict) -> str:
        """生成分割判断query

        PRD依据: 3.3节步骤D0
        """
        return f'该节点"{what_value}"是否需要继续拆解分割？'

    async def _detailed_understanding(
        self,
        original_image: str,
        current_image: str,
        node_description: str,
        dimensions: Dict
    ) -> Dict:
        """根据描述维度细致理解当前节点

        PRD依据: 3.3节步骤C, 3.3.1节原则
        关键点: 基于完整原图 + 节点描述 + 描述维度进行理解

        Args:
            original_image: 完整原图路径（提供上下文）
            current_image: 当前节点对应的图片路径
            node_description: 当前节点的文字描述
            dimensions: 知识库返回的描述维度
        """
        # 构建prompt：结合原图上下文和节点描述
        if node_description:
            prompt = f"""
请基于完整原图的上下文，分析指定视觉元素的特征。

【完整原图】: {original_image}
【当前关注的元素描述】: {node_description}
【当前元素图片】: {current_image}

请从以下维度分析这个视觉元素:
{self._format_dimensions(dimensions)}

以JSON格式输出各维度的值。
"""
        else:
            # 首次调用，分析整图
            prompt = f"""
请从以下维度分析图片:
{self._format_dimensions(dimensions)}

图片: {original_image}

以JSON格式输出各维度的值。
"""
        response = await self.llm.ainvoke(prompt)
        return self._parse_description(response)

    async def _identify_sub_elements(
        self,
        original_image: str,
        current_node_what: str,
        current_node_description: str
    ) -> List[str]:
        """识别当前节点中的子元素

        PRD依据: 3.3.1节
        关键点: 基于完整原图 + 当前节点描述识别子元素（不依赖分割结果）

        Args:
            original_image: 完整原图路径（提供上下文）
            current_node_what: 当前节点的what字段值
            current_node_description: 当前节点的文字描述
        """
        # 构建prompt：基于原图和当前节点描述识别子元素
        if current_node_description:
            prompt = f"""
请基于完整原图的上下文，识别指定视觉元素中包含的子元素。

【完整原图】: {original_image}
【当前关注的元素】: {current_node_what}
【当前元素的详细描述】: {current_node_description}

判断步骤:
1. 该元素是否为多张子图拼接？（如4宫格、9宫格）
2. 如果不是，该元素包含哪些独立的视觉对象？（如人物、商品、背景元素）

请列出所有子元素的文字描述，每个元素一行。
"""
        else:
            # 首次调用，分析整图
            prompt = f"""
分析图片"{current_node_what}"，识别其中包含的子视觉元素。

【图片】: {original_image}

判断步骤:
1. 是否为多张子图拼接？（如4宫格、9宫格）
2. 如果不是，包含哪些独立的视觉对象？（如人物、商品、背景元素）

请列出所有子元素的文字描述，每个元素一行。
"""
        response = await self.llm.ainvoke(prompt)
        return [line.strip() for line in response.strip().split('\n') if line.strip()]
```

---

#### 5.2.4 RecursiveTextDeconstructionAgent（文本递归解构）

**组件类型**: Agent (继承 BaseReactAgent)

**选择依据**:
- **PRD依据**: 3.3节 "对单一节点的递归解构"
- **CLAUDE.md依据**: 需要LLM语义理解 + 动态调用工具

**核心职责**:
1. 提取文本原文作为what字段（不可改写）
2. 调用知识库获取描述维度
3. 分析文本，填充描述值
4. 判断是否需要切分
5. 如需切分，调用文本切分函数
6. 递归处理子文本

**关键点**:

| 关键点 | 实现方式 | PRD依据 |
|--------|---------|---------|
| **what字段是原文** | 直接使用文本原文，不可总结改写 | 2.2.2节 |
| **充分必要原则** | 子文本合并后必须等于父文本 | 3.4节 |
| **递归控制** | 深度限制 + 最小语义单元判断 | 2.2.3节 |

**代码框架**:

```python
class RecursiveTextDeconstructionAgent(BaseReactAgent):
    """文本递归解构Agent

    PRD依据: 3.3节
    功能: 递归解构文本元素（标题/正文/标签）
    """

    def __init__(
        self,
        llm,
        knowledge_retrieval_tool: BaseTool,
        max_depth: int = 10
    ):
        super().__init__(llm, tools=[knowledge_retrieval_tool])
        self.knowledge_tool = knowledge_retrieval_tool
        self.max_depth = max_depth

    async def ainvoke(self, state: Dict[str, Any]) -> Dict[str, Any]:
        """
        递归解构文本

        Args:
            state: {
                "text": str,          # 当前文本内容
                "text_type": str,     # 文本类型（title/body/hashtags）
                "node_id": str,       # 节点ID
                "depth": int          # 当前递归深度
            }

        Returns:
            {
                "id": str,
                "what": str,          # 文本原文
                "description": Dict,
                "children": List[Dict]
            }
        """
        # 步骤1: 检查递归深度
        if state["depth"] >= self.max_depth:
            return self._build_leaf_node(state)

        # 步骤2: what字段直接使用原文（PRD 2.2.2节）
        what_value = state["text"]

        # 步骤3: 调用知识库获取描述维度
        description_query = self._generate_description_query(
            what_value,
            state["text_type"]
        )
        description_dimensions = await self.knowledge_tool.ainvoke({
            "query": description_query,
            "query_type": "description"
        })

        # 步骤4: 根据描述维度分析文本
        description_values = await self._analyze_text(
            what_value,
            description_dimensions,
            state["text_type"]
        )

        # 步骤5: 判断是否需要切分
        split_query = self._generate_split_query(what_value)
        split_decision = await self.knowledge_tool.ainvoke({
            "query": split_query,
            "query_type": "split_decision"
        })

        result = {
            "id": state["node_id"],
            "what": what_value,  # 原文，不可改写
            "description": description_values,
            "children": []
        }

        # 步骤6: 如需切分，执行切分并递归
        if split_decision.get("should_split", False):
            # 获取切分规则
            split_rules = split_decision.get("split_rules", {})

            # 执行文本切分（调用Function组件）
            sub_texts = self._split_text(what_value, split_rules)

            # 递归处理子文本
            children = []
            for idx, sub_text in enumerate(sub_texts):
                child_state = {
                    "text": sub_text,
                    "text_type": state["text_type"],
                    "node_id": f"{state['node_id']}_{idx+1}",
                    "depth": state["depth"] + 1
                }
                child_result = await self.ainvoke(child_state)
                children.append(child_result)

            result["children"] = children

        return result

    def _split_text(self, text: str, split_rules: Dict) -> List[str]:
        """切分文本

        PRD依据: 3.5节
        关键点: 保证子文本合并后等于父文本（充分必要）
        """
        strategy = split_rules.get("strategy", "sentence")

        if strategy == "sentence":
            # 按句子切分
            import re
            sentences = re.split(r'[。！？\n]', text)
            return [s.strip() for s in sentences if s.strip()]
        elif strategy == "paragraph":
            # 按段落切分
            paragraphs = text.split('\n\n')
            return [p.strip() for p in paragraphs if p.strip()]
        else:
            return [text]
```

---

#### 5.2.5 PostSummaryDeconstructionAgent（帖子整体解构）

**组件类型**: Agent (继承 BaseLLMAgent)

**选择依据**:
- **PRD依据**: 3.2节 "帖子整体解构环节"
- **CLAUDE.md依据**: 需要综合分析和抽象提炼能力

**核心职责**:
1. 调用知识库获取总结维度
2. 综合所有子元素解构结果
3. 从点线面体维度总结帖子

**关键点**:

| 关键点 | 实现方式 | PRD依据 |
|--------|---------|---------|
| **动态总结维度** | 由知识库根据品类/主题/关键词提供 | 2.2.2节、3.2节 |
| **综合分析** | 整合图片、文本、评论的解构结果 | 3.1节步骤13 |
| **维度数量** | 不少于3个维度 | 2.2.2节 |

**代码框架**:

```python
class PostSummaryDeconstructionAgent(BaseLLMAgent):
    """帖子整体解构Agent

    PRD依据: 3.2节
    功能: 从点线面体维度总结帖子
    """

    def __init__(self, llm, knowledge_retrieval_tool: BaseTool):
        super().__init__(llm)
        self.knowledge_tool = knowledge_retrieval_tool

    async def ainvoke(self, state: Dict[str, Any]) -> Dict[str, Any]:
        """
        执行帖子整体解构

        Args:
            state: {
                "category": str,
                "theme": str,
                "keywords": List[str],
                "image_results": List[Dict],
                "text_results": List[Dict],
                "consumer_highlights": List[Dict]
            }

        Returns:
            {
                "summary": Dict  # 动态维度的总结
            }
        """
        # 步骤1: 生成总结维度query（PRD 3.2节）
        summary_query = self._generate_summary_query(
            state["category"],
            state["theme"],
            state["keywords"]
        )

        # 步骤2: 调用知识库获取总结维度
        summary_dimensions = await self.knowledge_tool.ainvoke({
            "query": summary_query,
            "query_type": "description"
        })

        # 步骤3: 根据总结维度分析帖子
        prompt = self._build_summary_prompt(
            summary_dimensions,
            state["image_results"],
            state["text_results"],
            state["consumer_highlights"]
        )

        response = await self.llm.ainvoke(prompt)
        summary = self._parse_summary(response)

        return {"summary": summary}

    def _generate_summary_query(
        self,
        category: str,
        theme: str,
        keywords: List[str]
    ) -> str:
        """生成总结维度query

        PRD依据: 3.2节
        Query句式: PRD 3.2节定义
        """
        keywords_str = ', '.join(keywords)
        return f'对于一篇主题为"{theme}"，品类为"{category}"，关键词包含"{keywords_str}"的多模态社交媒体帖子，从内容创作者视角进行What要素的初步识别和分类，需要使用哪些通用工具？'
```

---

### 5.3 Tool组件详细设计

**CLAUDE.md原则**:
> **Tool组件特征**: 确定性任务 + 可被Agent调用

#### 5.3.1 KnowledgeRetrievalTool（知识检索工具）

**组件类型**: Tool (继承 BaseTool)

**选择依据**:
- **PRD依据**: 3.2节、3.3.2节 "对单一节点解构如何获取知识"
- **CLAUDE.md依据**: 确定性API调用 + 需要被Agent调用

**核心职责**:
1. 接收query和query类型
2. 调用外部知识库API
3. 根据query类型解析返回结果

**关键点**:

| 关键点 | 实现方式 | PRD依据 |
|--------|---------|---------|
| **支持多种query类型** | description/tool/split_decision | 3.3.2节 |
| **降级策略** | 知识库不可用时使用LLM默认知识 | 容错处理 |
| **结果格式化** | 转换为Agent可用的结构化数据 | 提升可用性 |

**代码框架**:

```python
from tools.base import BaseTool
from typing import Dict, Any

class KnowledgeRetrievalTool(BaseTool):
    """知识检索工具

    PRD依据: 3.2节、3.3.2节
    功能: 根据query检索解构所需的知识
    """

    name: str = "knowledge_retrieval"
    description: str = "根据query检索What解构所需的知识（描述维度、工具推荐、分割判断等）"

    def __init__(self, knowledge_base_url: str, fallback_llm=None):
        super().__init__()
        self.knowledge_base_url = knowledge_base_url
        self.fallback_llm = fallback_llm  # 降级LLM

    async def _arun(
        self,
        query: str,
        query_type: str = "description"
    ) -> Dict[str, Any]:
        """
        调用知识库检索

        Args:
            query: 查询语句（PRD 3.3.2节定义的句式）
            query_type: 查询类型
                - description: 获取描述维度
                - tool: 获取工具推荐
                - split_decision: 获取分割判断

        Returns:
            根据query_type返回不同格式的结果
        """
        try:
            # 调用知识库API
            response = await self._call_knowledge_base(query)

            # 根据query类型解析结果
            if query_type == "description":
                return self._parse_description_dimensions(response)
            elif query_type == "tool":
                return self._parse_tool_recommendations(response)
            elif query_type == "split_decision":
                return self._parse_split_decision(response)

            return response

        except Exception as e:
            # 降级策略: 使用LLM默认知识
            if self.fallback_llm:
                return await self._fallback_with_llm(query, query_type)
            raise e

    def _parse_description_dimensions(self, response) -> Dict[str, Any]:
        """解析描述维度

        返回格式:
        {
            "dimensions": ["维度1", "维度2", "维度3", ...],
            "count": 3
        }
        """
        dimensions = response.get("dimensions", [])
        return {
            "dimensions": dimensions,
            "count": len(dimensions)
        }

    def _parse_split_decision(self, response) -> Dict[str, Any]:
        """解析分割判断

        返回格式:
        {
            "should_split": True/False,
            "split_rules": {  # 如果should_split=True
                "strategy": "sentence/paragraph/grid",
                "params": {...}
            }
        }
        """
        return {
            "should_split": response.get("should_split", False),
            "split_rules": response.get("split_rules", {})
        }
```

**复用决策**:
- **现有组件**: `tools/knowledge_retrieval_tools.py`
- **决策**: **复用并修改**
- **修改点**: 增强支持多种query_type，增加降级策略

---

#### 5.3.2 ImageSegmentTool（图片分割工具）

**组件类型**: Tool (继承 BaseTool)

**选择依据**:
- **PRD依据**: 3.3.1节 "判断图片元素是否要继续分割拆解"、3.5节
- **CLAUDE.md依据**: 确定性模型调用 + 需要被Agent调用

**核心职责**:
1. 接收图片路径和子元素描述
2. 调用分割模型（SAM/GroundingDINO）
3. 保存分割后的子图片
4. 返回子图片路径列表

**关键点**:

| 关键点 | 实现方式 | PRD依据 |
|--------|---------|---------|
| **支持多种分割模式** | grid（子图拼接）/ object（视觉元素） | 3.3.1节 |
| **分割质量验证** | 验证mask是否覆盖元素 | 保证准确性 |
| **文件管理** | 统一命名规范和存储路径 | 2.1.1节 |

**代码框架**:

```python
from tools.base import BaseTool
from typing import List

class ImageSegmentTool(BaseTool):
    """图片分割工具

    PRD依据: 3.3.1节、3.5节
    功能: 根据文字描述将图片分割为多个独立的视觉元素
    """

    name: str = "image_segment"
    description: str = "根据文字描述将图片分割为多个独立的视觉元素"

    def __init__(self, segment_model, output_dir: str):
        super().__init__()
        self.segment_model = segment_model
        self.output_dir = output_dir

    async def _arun(
        self,
        image_path: str,
        elements_description: List[str],
        segment_type: str = "object"
    ) -> List[str]:
        """
        分割图片

        Args:
            image_path: 原始图片路径
            elements_description: 子元素文字描述列表
            segment_type: 分割类型
                - object: 视觉元素分割（抠图）
                - grid: 子图拼接拆解（简单切割）

        Returns:
            分割后的子图片路径列表
        """
        # 1. 加载图片
        image = self._load_image(image_path)

        # 2. 根据分割类型选择策略
        if segment_type == "grid":
            # 拼接图拆解（简单切割）
            sub_images = self._grid_split(image, len(elements_description))
        else:
            # 视觉元素分割（调用分割模型）
            sub_images = await self._segment_objects(image, elements_description)

        # 3. 保存子图片
        saved_paths = []
        for idx, sub_img in enumerate(sub_images):
            save_path = f"{self.output_dir}/{self._generate_filename(image_path, idx)}"
            self._save_image(sub_img, save_path)
            saved_paths.append(save_path)

        return saved_paths

    def _grid_split(self, image, num_elements: int):
        """拼接图拆解

        PRD依据: 3.3.1节（优先判断是否为多子图拼接）
        支持: 2x2, 3x3, 1xN等常见拼接模式
        """
        # TODO: 根据num_elements推测拼接模式
        pass

    async def _segment_objects(self, image, descriptions: List[str]):
        """视觉元素分割

        调用SAM/GroundingDINO等模型
        """
        masks = await self.segment_model.segment(image, descriptions)
        return self._extract_objects(image, masks)
```

**复用决策**:
- **现有组件**: `tools/segment_tools.py`
- **决策**: **直接复用**
- **理由**: 已实现图片分割功能，完全符合PRD需求

---

### 5.4 Function组件详细设计

**CLAUDE.md原则**:
> **Function组件特征**: 确定性任务 + 不需要被Agent调用

#### 5.4.1 TextSplitFunction（文本切分函数）

**组件类型**: Function (继承 BaseFunction)

**选择依据**:
- **PRD依据**: 3.5节 "文本切分工具"
- **CLAUDE.md依据**: 确定性字符串处理 + 工作流直接调用

**核心职责**:
1. 接收文本和切分规则
2. 按规则切分文本
3. 保证不重不漏（子文本合并=父文本）

**关键点**:

| 关键点 | 实现方式 | PRD依据 |
|--------|---------|---------|
| **充分必要原则** | 验证子文本合并后等于父文本 | 3.4节 |
| **多种切分策略** | sentence/paragraph/semantic | 3.5节 |
| **保留原文** | 不修改文本内容 | 2.2.2节 |

**代码框架**:

```python
from functions.base import BaseFunction
from typing import List, Dict

class TextSplitFunction(BaseFunction):
    """文本切分函数

    PRD依据: 3.5节
    功能: 根据切分规则切分文本
    """

    def invoke(self, text: str, split_rules: Dict) -> List[str]:
        """
        切分文本

        Args:
            text: 待切分文本
            split_rules: 切分规则
                {
                    "strategy": "sentence/paragraph/semantic",
                    "params": {...}
                }

        Returns:
            切分后的子文本列表
        """
        strategy = split_rules.get("strategy", "sentence")

        if strategy == "sentence":
            sub_texts = self._split_by_sentence(text)
        elif strategy == "paragraph":
            sub_texts = self._split_by_paragraph(text)
        elif strategy == "semantic":
            sub_texts = self._split_by_semantic(text, split_rules.get("params"))
        else:
            sub_texts = [text]

        # 验证充分必要原则（PRD 3.4节）
        self._validate_completeness(text, sub_texts)

        return sub_texts

    def _split_by_sentence(self, text: str) -> List[str]:
        """按句子切分"""
        import re
        sentences = re.split(r'[。！？\n]', text)
        return [s.strip() for s in sentences if s.strip()]

    def _validate_completeness(self, parent_text: str, child_texts: List[str]):
        """验证子文本合并后是否等于父文本

        PRD依据: 3.4节 "充分必要原则"
        """
        merged = ''.join(child_texts)
        if merged.replace(' ', '') != parent_text.replace(' ', ''):
            raise ValueError("子文本合并后不等于父文本，违反充分必要原则")
```

**复用决策**:
- **现有组件**: 无
- **决策**: **完全新增**
- **理由**: 项目中不存在文本切分功能

---

#### 5.4.2 ResultAggregationFunction（结果汇总函数）

**组件类型**: Function (继承 BaseFunction)

**选择依据**:
- **PRD依据**: 2.2.2节 "输出格式定义"
- **CLAUDE.md依据**: 确定性数据结构转换

**核心职责**:
1. 接收所有解构结果
2. 组装为树状JSON结构
3. 生成节点ID
4. 验证JSON格式

**关键点**:

| 关键点 | 实现方式 | PRD依据 |
|--------|---------|---------|
| **递归构建树** | 递归函数处理children | 2.2.2节 |
| **ID生成规则** | "1", "1_1", "1_1_2"格式 | 2.2.2节 |
| **格式验证** | 验证所有必需字段存在 | 2.2.2节 |

**代码框架**:

```python
from functions.base import BaseFunction
from typing import Dict, List

class ResultAggregationFunction(BaseFunction):
    """结果汇总函数

    PRD依据: 2.2.2节
    功能: 将所有解构结果组装为树状JSON
    """

    def invoke(self, state: Dict) -> Dict:
        """
        汇总所有解构结果

        Args:
            state: {
                "post_summary": Dict,
                "image_results": List[Dict],
                "text_results": List[Dict]
            }

        Returns:
            最终的树状JSON结构（PRD 2.2.2节格式）
        """
        # 1. 提取各部分结果
        post_summary = state["post_summary"]
        image_results = state["image_results"]
        text_results = state["text_results"]

        # 2. 构建元素列表
        elements = []

        # 添加图片元素
        for idx, img_result in enumerate(image_results):
            element = self._build_element_tree(
                id=str(idx + 1),
                result=img_result
            )
            elements.append(element)

        # 添加文本元素
        text_id_start = len(image_results) + 1
        for idx, text_result in enumerate(text_results):
            element = self._build_element_tree(
                id=str(text_id_start + idx),
                result=text_result
            )
            elements.append(element)

        # 3. 组装最终JSON
        final_result = {
            "帖子总结": post_summary,
            "帖子包含元素": elements
        }

        # 4. 验证格式
        self._validate_result(final_result)

        return final_result

    def _build_element_tree(self, id: str, result: Dict) -> Dict:
        """递归构建元素树

        PRD依据: 2.2.2节
        """
        element = {
            "id": id,
            "what": result["what"],
            "描述": result["description"],
            "子节点元素关系": result.get("relationships", []),
            "元素重要性权重": result.get("importance_weight", 0.5),
            "子节点元素": []
        }

        # 递归处理children
        if "children" in result and result["children"]:
            for idx, child in enumerate(result["children"]):
                child_element = self._build_element_tree(
                    id=f"{id}_{idx+1}",
                    result=child
                )
                element["子节点元素"].append(child_element)

        return element

    def _validate_result(self, result: Dict):
        """验证JSON格式

        PRD依据: 2.2.2节
        检查: 必需字段、维度数量≥3等
        """
        # 验证帖子总结
        assert "帖子总结" in result, "缺少'帖子总结'字段"
        assert len(result["帖子总结"]) >= 3, "帖子总结维度不足3个"

        # 验证帖子包含元素
        assert "帖子包含元素" in result, "缺少'帖子包含元素'字段"

        # 递归验证每个元素节点
        for element in result["帖子包含元素"]:
            self._validate_element(element)

    def _validate_element(self, element: Dict):
        """递归验证元素节点"""
        required_fields = ["id", "what", "描述", "子节点元素关系", "元素重要性权重", "子节点元素"]
        for field in required_fields:
            assert field in element, f"元素节点缺少'{field}'字段"

        # 验证描述维度数量
        assert len(element["描述"]) >= 3, f"元素{element['id']}的描述维度不足3个"

        # 递归验证子节点
        for child in element["子节点元素"]:
            self._validate_element(child)
```

**复用决策**:
- **现有组件**: `functions/result_aggregation.py`
- **决策**: **复用并修改**
- **理由**: 可复用结果聚合逻辑，需新增树状结构构建

---

## 6. 数据结构设计

### 6.1 WhatDeconstructionState（工作流状态）

**PRD依据**: 2.1节（输入）、2.2节（输出）

```python
from typing import TypedDict, List, Dict, Any, Optional

class WhatDeconstructionState(TypedDict):
    """What解构工作流状态

    PRD依据: 2.1节、2.2节
    """

    # ========== 输入数据（PRD 2.1节） ==========
    images: List[str]                      # 图片路径列表（1-9张）
    text: Dict[str, Any]                   # {title, body, hashtags}
    comments: List[Dict[str, str]]         # [{user, content}, ...]
    creator_info: Optional[Dict]           # 创作者信息（可选）

    # ========== 中间状态 ==========
    category: str                          # 品类（F1输出）
    theme: str                             # 主题（F1输出）
    keywords: List[str]                    # 关键词（F1输出）
    consumer_highlights: List[Dict]        # 消费者亮点（F4输出）

    # ========== 解构结果 ==========
    image_deconstruction_results: List[Dict]   # 图片解构结果（F5输出）
    text_deconstruction_results: List[Dict]    # 文本解构结果（F7输出）
    post_summary: Dict[str, Any]               # 帖子总结（F9输出）

    # ========== 最终输出（PRD 2.2.2节） ==========
    final_result: Dict[str, Any]           # 树状JSON结果
```

### 6.2 ElementNode（元素节点结构）

**PRD依据**: 2.2.2节 "输出格式定义"

```python
class ElementNode(TypedDict):
    """元素节点结构（递归树的节点）

    PRD依据: 2.2.2节
    """

    id: str                          # 节点ID（如"1", "1_1", "1_2_3"）
    what: str                        # 元素概述（文本原文 or 图片描述）
    描述: Dict[str, Any]             # 动态描述维度（≥3个）
    子节点元素关系: List[str]        # 子节点之间的关系描述
    元素重要性权重: float            # 0-1之间
    子节点元素: List['ElementNode']  # 递归的子节点列表
```

### 6.3 FinalOutput（最终输出结构）

**PRD依据**: 2.2.2节

```python
class FinalOutput(TypedDict):
    """最终输出的JSON结构

    PRD依据: 2.2.2节
    """

    帖子总结: Dict[str, Any]         # 动态总结维度（≥3个）
    帖子包含元素: List[ElementNode]  # 元素树的根节点列表
```

---

## 7. 实现路线图

### Phase 1: 基础框架搭建

**目标**: 建立工作流骨架和基础组件

| 任务 | 组件 | 优先级 | 依赖 |
|------|------|--------|------|
| 1.1 定义数据结构 | WhatDeconstructionState | P0 | 无 |
| 1.2 实现PostUnderstandingAgent | Agent | P0 | 1.1 |
| 1.3 修改KnowledgeRetrievalTool | Tool | P0 | 无 |
| 1.4 搭建工作流骨架 | Workflow | P0 | 1.1, 1.2, 1.3 |
| 1.5 端到端测试（简化版） | - | P0 | 1.4 |

**验收标准**:
- 工作流能够运行
- PostUnderstandingAgent能够输出品类/主题/关键词
- 知识库工具能够返回模拟数据

### Phase 2: 核心解构能力

**目标**: 实现图片和文本的递归解构

| 任务 | 组件 | 优先级 | 依赖 |
|------|------|--------|------|
| 2.1 实现RecursiveImageDeconstructionAgent | Agent | P0 | Phase 1 |
| 2.2 复用ImageSegmentTool | Tool | P0 | 2.1 |
| 2.3 实现RecursiveTextDeconstructionAgent | Agent | P0 | Phase 1 |
| 2.4 实现TextSplitFunction | Function | P0 | 2.3 |
| 2.5 集成测试（单个图片+单个文本） | - | P0 | 2.1-2.4 |

**验收标准**:
- 能够递归解构单张图片（至少2层）
- 能够递归解构单段文本（至少2层）
- 递归深度控制生效（不超过10层）

### Phase 3: 增强功能

**目标**: 完成评论理解、帖子总结、结果汇总

| 任务 | 组件 | 优先级 | 依赖 |
|------|------|--------|------|
| 3.1 实现CommentAnalysisAgent | Agent | P1 | Phase 2 |
| 3.2 实现PostSummaryDeconstructionAgent | Agent | P1 | Phase 2 |
| 3.3 修改ResultAggregationFunction | Function | P0 | Phase 2 |
| 3.4 完整端到端测试 | - | P0 | 3.1-3.3 |

**验收标准**:
- 能够分析评论并提取亮点
- 能够生成帖子整体总结
- 能够输出符合PRD 2.2.2节格式的完整JSON

### Phase 4: 完善优化

**目标**: 优化性能、容错、测试覆盖

| 任务 | 优先级 |
|------|--------|
| 4.1 递归深度优化（提前停止） | P2 |
| 4.2 错误处理和降级策略 | P1 |
| 4.3 并行执行优化 | P2 |
| 4.4 单元测试覆盖 | P1 |
| 4.5 性能基准测试 | P2 |

**验收标准**:
- 单元测试覆盖率 > 80%
- 错误情况下有合理降级
- 性能满足预期（待定义）

---

## 8. 决策依据总结表

### 8.1 工作流设计决策

| 决策点 | 选择 | PRD依据 | CLAUDE.md依据 | 技术理由 |
|--------|------|---------|---------------|---------|
| 工作流框架 | LangGraph | - | 要求使用LangGraph | 支持状态管理、节点编排 |
| 并行执行 | 图片和文本并行 | 3.1节流程图 | 工作流负责编排 | 两者无依赖，可并行提升效率 |
| 递归深度 | 最多10层 | 2.2.3节 | - | 防止无限递归，控制成本 |
| 知识query生成 | 工作流逻辑 | 3.2节 | 轻量级逻辑不需组件 | 简单字符串拼接 |

### 8.2 组件类型选择决策

| 组件 | 类型 | PRD依据 | CLAUDE.md依据 | 选择理由 |
|------|------|---------|---------------|---------|
| PostUnderstandingAgent | Agent | 3.1步骤1 | 多模态理解（不确定性） | 需要LLM理解图文 |
| CommentAnalysisAgent | Agent | 2.1.4节 | 语义理解（不确定性） | 需要LLM情感分析 |
| RecursiveImageDeconstructionAgent | Agent (ReAct) | 3.3节 | 视觉理解+工具调用 | 需要多次调用知识库和分割工具 |
| RecursiveTextDeconstructionAgent | Agent (ReAct) | 3.3节 | 语义理解+工具调用 | 需要多次调用知识库 |
| PostSummaryDeconstructionAgent | Agent | 3.2节 | 综合分析（不确定性） | 需要LLM抽象提炼 |
| KnowledgeRetrievalTool | Tool | 3.3.2节 | Agent需调用 | 确定性API调用 |
| ImageSegmentTool | Tool | 3.3.1节 | Agent需调用 | 确定性模型调用 |
| TextSplitFunction | Function | 3.5节 | 确定性+工作流调用 | 简单字符串处理 |
| ResultAggregationFunction | Function | 2.2.2节 | 确定性+工作流调用 | 数据结构转换 |

### 8.3 复用决策

| 组件 | 决策 | 理由 | 修改点 |
|------|------|------|--------|
| knowledge_retrieval_tools.py | 复用并修改 | 已有基础查询功能 | 增强query类型支持、降级策略 |
| segment_tools.py | 直接复用 | 功能完全匹配 | 无 |
| result_aggregation.py | 复用并修改 | 可复用聚合逻辑 | 新增树状结构构建 |
| TextSplitFunction | 完全新增 | 项目中无此功能 | - |
| 所有Agent | 完全新增 | PRD业务逻辑全新 | - |

---

## 附录: Query模板速查表

**PRD依据**: 3.2节、3.3.2节

| Query类型 | 句式模板 | 使用场景 |
|-----------|---------|---------|
| 帖子整体总结维度 | 对于一篇主题为"{主题}"，品类为"{品类}"，关键词包含"{关键词}"的多模态社交媒体帖子，从内容创作者视角进行What要素的初步识别和分类，需要使用哪些通用工具？ | PostSummaryDeconstructionAgent |
| 元素描述维度 | 刻画描述"{元素的what字段值}"核心特征的角度和维度有哪些？请尽可能不重不漏列举全。 | 所有递归解构Agent |
| 分割判断 | 该节点"{元素的what字段值}"是否需要继续拆解分割？ | 所有递归解构Agent |
| 图片整体分割工具 | 对一张描述为"{图片描述}"的图片，从内容创作者视角进行视觉元素分割，需要使用哪些图片分割/抠图工具？ | RecursiveImageDeconstructionAgent |
| 文本段落分割工具 | 对一段描述为"{文本摘要}"的文本段落，从内容创作者视角进行结构化分割拆解，需要使用什么文本切分工具或文本结构化大模型？ | RecursiveTextDeconstructionAgent |

---

**文档版本**: v2.0
**最后更新**: 2025-10-21
**适用PRD版本**: v1.3
