supeng 8 часов назад
Родитель
Сommit
753a116831

+ 12 - 6
examples/content_finder/run.py

@@ -135,17 +135,23 @@ class ContentFinderAgent:
         # 构建系统提示
         system_prompt = """你是一个专业的内容寻找助手,擅长根据用户需求在抖音平台上寻找合适的视频内容。
 
+⚠️ 重要提示:当前所有工具返回的都是模拟数据,仅用于测试和演示。
+- 在分析和推荐时,请明确说明这是基于模拟数据的演示
+- 不要给出过于自信的评分和推荐
+- 提醒用户实际使用时需要对接真实API
+
 你的工作流程:
 1. 理解用户需求,提取关键词和目标受众特征
-2. 使用 douyin_search 工具搜索相关内容
-3. 使用画像工具(get_video_audience_profile, get_user_fans_profile)分析内容是否符合目标受众
-4. 对于优质内容,使用 douyin_user_videos 获取作者的其他作品
-5. 综合评估并推荐最合适的内容
+2. 使用 douyin_search 工具搜索相关内容(返回模拟数据)
+3. 使用画像工具分析内容是否符合目标受众(返回模拟数据)
+4. 对于优质内容,使用 douyin_user_videos 获取作者的其他作品(返回模拟数据)
+5. 综合评估并推荐最合适的内容,但要说明这是基于模拟数据的演示
 
 重点关注:
 - 内容是否符合老年人群体的偏好(年龄分布、偏好度)
-- 内容热度(播放量、点赞量、分享量)
-- 互动率(点赞率、分享率)
+- 内容热度(点赞量、评论量、分享量)
+- 互动率(评论率、分享率)
+- 时效性(发布时间)
 - 作者的内容质量和稳定性
 
 请按照 content_finding_strategy 和 content_filtering_strategy 中的策略执行。"""

+ 119 - 50
examples/content_finder/skills/content_filtering_strategy.md

@@ -3,45 +3,76 @@
 ## 目标
 对获取到的视频内容进行多维度筛选,确保内容符合目标受众(主要是老年人群体)的偏好和质量要求。
 
+## 重要说明
+⚠️ **抖音渠道无法获取播放量数据**,筛选策略主要依赖点赞量、评论量、分享量等可获取的指标。
+
 ## 筛选维度
 
 ### 1. 热度指标筛选
-基于视频基础数据进行筛选:
-
-**播放量**
-- 最低门槛:50,000+
-- 优质内容:100,000+
-- 爆款内容:500,000+
 
-**点赞量**
+**点赞量**(主要指标)
 - 最低门槛:2,000+
 - 优质内容:5,000+
 - 爆款内容:20,000+
 
+**评论量**
+- 最低门槛:200+
+- 优质内容:500+
+- 爆款内容:2,000+
+
 **分享量**
+- 最低门槛:100+
+- 优质内容:500+
+- 爆款内容:2,000+
+
+**收藏量**(如果可获取)
 - 最低门槛:500+
 - 优质内容:1,000+
 - 爆款内容:5,000+
 
-### 2. 互动率筛选
-计算并评估内容的互动质量:
+### 2. 互动质量评估
+
+**互动总量** = 点赞量 + 评论量 + 分享量
+- 合格:≥ 2,500
+- 优秀:≥ 6,000
+- 极佳:≥ 22,000
 
-**点赞率** = 点赞量 / 播放量
+**评论/点赞比**(反映内容讨论度)
+- 合格:≥ 8%
+- 优秀:≥ 10%
+- 极佳:≥ 15%
+
+**分享/点赞比**(反映内容传播力)
 - 合格:≥ 3%
 - 优秀:≥ 5%
 - 极佳:≥ 8%
 
-**分享率** = 分享量 / 播放量
-- 合格:≥ 1%
-- 优秀:≥ 2%
-- 极佳:≥ 3%
+**收藏/点赞比**(反映内容价值)
+- 合格:≥ 15%
+- 优秀:≥ 20%
+- 极佳:≥ 30%
+
+### 3. 时效性评估
 
-**评论率** = 评论量 / 播放量
-- 合格:≥ 0.5%
-- 优秀:≥ 1%
-- 极佳:≥ 2%
+**发布时间**(重要指标)
+- 最近7天:新鲜内容,优先推荐
+- 7-30天:较新内容,正常推荐
+- 30-90天:中等时效,需结合热度判断
+- 90天以上:老内容,需要更高的热度指标才推荐
+
+**时效性调整策略**:
+```
+如果发布时间 < 7天:
+  - 点赞量门槛降低30%(1,400+ 即可)
+  - 适合挖掘潜力内容
+
+如果发布时间 > 90天:
+  - 点赞量门槛提高50%(3,000+ 才考虑)
+  - 需要验证内容是否仍有价值
+```
+
+### 4. 观众画像筛选
 
-### 3. 观众画像筛选
 使用 `get_video_audience_profile` 获取画像数据:
 
 **年龄分布(老年人群体)**
@@ -56,9 +87,10 @@
 - 60岁以上偏好度:≥ 1.3
 
 **城市等级分布**
-- 二线及以下城市占比:≥ 50%(老年人群体在低线城市占比更高)
+- 二线及以下城市占比:≥ 50%
+
+### 5. 粉丝画像筛选
 
-### 4. 粉丝画像筛选
 使用 `get_user_fans_profile` 获取作者粉丝画像:
 
 **粉丝量**
@@ -67,7 +99,7 @@
 - 头部作者:200,000+
 
 **粉丝年龄分布**
-- 41岁以上占比:≥ 40%(说明作者擅长老年人内容)
+- 41岁以上占比:≥ 40%
 - 51岁以上占比:≥ 15%
 
 **粉丝偏好度**
@@ -77,9 +109,10 @@
 ## 筛选流程
 
 ### 第一轮:基础筛选
-1. 检查播放量、点赞量、分享量是否达到最低门槛
-2. 计算点赞率、分享率、评论率
-3. 过滤掉不符合基础标准的内容
+1. 检查点赞量、评论量、分享量是否达到最低门槛
+2. 检查发布时间,根据时效性调整门槛
+3. 计算互动总量和互动比例
+4. 过滤掉不符合基础标准的内容
 
 ### 第二轮:画像筛选
 1. 对通过基础筛选的内容获取观众画像
@@ -98,10 +131,11 @@
 为每个视频计算综合得分(满分100分):
 
 ```
-综合得分 = 热度得分(40分) + 互动率得分(30分) + 画像匹配度(30分)
+综合得分 = 热度得分(30分) + 互动质量得分(25分) + 时效性得分(15分) + 画像匹配度(30分)
 
-热度得分 = (播放量得分 + 点赞量得分 + 分享量得分) / 3
-互动率得分 = (点赞率得分 + 分享率得分 + 评论率得分) / 3
+热度得分 = (点赞量得分 + 评论量得分 + 分享量得分) / 3
+互动质量得分 = (互动总量得分 + 评论/点赞比得分 + 分享/点赞比得分) / 3
+时效性得分 = 根据发布时间计算(7天内满分,90天以上0分)
 画像匹配度 = (年龄匹配度 + 偏好度匹配度 + 城市等级匹配度) / 3
 ```
 
@@ -115,28 +149,34 @@
 
 ```
 # 第一轮:基础筛选
-视频A: 播放150k, 点赞8k, 分享500
-- 点赞率: 5.3% ✓
-- 分享率: 0.33% ✗
-结果: 不通过(分享率过低)
-
-视频B: 播放280k, 点赞15k, 分享1.2k
-- 点赞率: 5.4% ✓
-- 分享率: 0.43% ✗
-结果: 不通过(分享率过低)
-
-视频C: 播放95k, 点赞5.2k, 分享350
-- 点赞率: 5.5% ✓
-- 分享率: 0.37% ✗
-结果: 不通过(分享率过低)
-
-# 第二轮:画像筛选(假设视频通过第一轮)
-获取观众画像:
+视频A: 点赞8k, 评论1.2k, 分享500, 发布3天前
+- 互动总量: 9,700 ✓
+- 评论/点赞比: 15% ✓
+- 分享/点赞比: 6.25% ✓
+- 时效性: 新鲜内容 ✓
+结果: 通过(优先推荐)
+
+视频B: 点赞15k, 评论2.3k, 分享1.2k, 发布120天前
+- 互动总量: 18,500 ✓
+- 评论/点赞比: 15.3% ✓
+- 分享/点赞比: 8% ✓
+- 时效性: 老内容,但热度高 ✓
+结果: 通过
+
+视频C: 点赞2.5k, 评论300, 分享150, 发布150天前
+- 互动总量: 2,950 ✓
+- 评论/点赞比: 12% ✓
+- 分享/点赞比: 6% ✓
+- 时效性: 老内容且热度一般 ✗
+结果: 不通过(时效性差)
+
+# 第二轮:画像筛选
+获取视频A观众画像:
 - 41-50岁: 20.8% (偏好度1.25) ✓
 - 51-60岁: 10.5% (偏好度1.45) ✓
 - 60岁以上: 2.7% (偏好度1.65) ✓
 - 41岁以上总占比: 34% ✗
-结果: 勉强通过(接近35%门槛)
+结果: 勉强通过
 
 # 第三轮:作者筛选
 获取作者粉丝画像:
@@ -146,9 +186,38 @@
 结果: 通过,该作者擅长老年人内容
 ```
 
+## 筛选策略建议
+
+### 1. 优先新鲜内容
+- 7天内的内容优先推荐
+- 可以挖掘潜力内容
+- 适当降低热度门槛
+
+### 2. 重视互动质量
+- 评论/点赞比反映讨论度
+- 分享/点赞比反映传播力
+- 比绝对数值更能反映内容质量
+
+### 3. 结合画像数据
+- 画像数据可以精准定位受众
+- 通过年龄分布和偏好度判断匹配度
+- 作者粉丝画像比单个视频更可靠
+
+### 4. 关注作者稳定性
+- 通过作者的多个作品判断质量
+- 优先选择有多个优质作品的作者
+- 粉丝画像符合目标受众的作者
+
+### 5. 灵活调整门槛
+- 根据实际数据分布调整标准
+- 可以通过 A/B 测试优化门槛值
+- 定期根据效果调整策略
+
 ## 注意事项
-- 筛选条件可根据实际情况灵活调整
-- 不要过度依赖单一指标
-- 画像数据可能存在误差,需结合多个维度判断
+- ⚠️ 无法获取播放量,评估标准有一定局限性
+- ⚠️ 时效性很重要,优先推荐新鲜内容
+- 建议结合多个维度综合判断
+- 画像数据可能存在误差,需结合实际效果验证
 - 对于新发布的内容,可适当放宽热度要求
-- 关注内容质量,不要只看数据
+- 关注内容质量,数据只是参考
+- 定期根据实际效果调整筛选策略

+ 201 - 16
examples/content_finder/skills/content_finding_strategy.md

@@ -3,6 +3,10 @@
 ## 目标
 根据用户输入的需求,智能解析关键词并通过抖音搜索获取相关视频内容。对于符合条件的内容,进一步获取作者的其他作品进行深度挖掘。
 
+## 重要说明
+⚠️ **抖音渠道无法获取播放量数据**,筛选时主要依赖点赞量、评论量、分享量等可获取的指标。
+⚠️ **优先推荐新鲜内容**,时效性是重要的筛选维度。
+
 ## 策略流程
 
 ### 1. 需求解析
@@ -14,40 +18,221 @@
 ### 2. 初步搜索
 使用 `douyin_search` 工具进行关键词搜索:
 - 使用提取的核心关键词
-- 设置合理的筛选条件(播放量、点赞数
+- 设置合理的筛选条件(只能使用点赞数筛选
 - 获取初步结果集
 
+**搜索参数建议**:
+```python
+douyin_search(
+    keywords="孩子军抗日",
+    min_likes=2000,      # 最低点赞数
+    max_results=20       # 返回数量
+)
+```
+
 ### 3. 内容筛选
 对搜索结果进行初步筛选:
-- 检查视频热度指标(播放量、点赞量、分享量)
-- 计算互动率(点赞率、分享率)
-- 识别高质量内容
+
+**可用指标**:
+- ✅ 点赞量
+- ✅ 评论量
+- ✅ 分享量
+- ✅ 收藏量(如果可获取)
+- ✅ 发布时间(时效性)
+
+**筛选标准**:
+- 点赞量:≥ 2,000
+- 评论量:≥ 200
+- 分享量:≥ 100
+- 互动总量:≥ 2,500
+- 评论/点赞比:≥ 8%
+- 分享/点赞比:≥ 3%
+
+**时效性筛选**:
+```
+发布时间 < 7天:
+  - 优先推荐
+  - 点赞量门槛降低30%(1,400+ 即可)
+
+发布时间 7-30天:
+  - 正常推荐
+  - 使用标准门槛
+
+发布时间 30-90天:
+  - 需结合热度判断
+  - 热度高才推荐
+
+发布时间 > 90天:
+  - 谨慎推荐
+  - 点赞量门槛提高50%(3,000+ 才考虑)
+```
 
 ### 4. 深度挖掘
 对于符合条件的优质内容:
 - 记录作者ID
 - 使用 `douyin_user_videos` 获取该作者的其他作品
 - 对作者作品进行二次筛选
+- 识别作者的内容风格和质量稳定性
+
+**深度挖掘策略**:
+```python
+# 对于点赞量 > 5000 的优质内容
+if video['like_count'] > 5000:
+    # 获取作者的其他作品
+    author_videos = douyin_user_videos(
+        author_id=video['author_id'],
+        max_results=10
+    )
+    # 筛选作者的优质作品(考虑时效性)
+    quality_videos = [
+        v for v in author_videos
+        if v['like_count'] > 2000
+        and days_since_publish(v) < 90  # 90天内的内容
+    ]
+```
 
-### 5. 画像验证(可选)
-如果需要精准定位目标受众:
-- 使用 `get_video_audience_profile` 获取视频观众画像
+### 5. 画像验证
+使用画像数据精准定位目标受众:
+
+**视频观众画像**:
+- 使用 `get_video_audience_profile` 获取点赞观众画像
+- 检查年龄分布(41岁以上占比 ≥ 35%)
+- 检查年龄偏好度(41-50岁 ≥ 1.1,51-60岁 ≥ 1.2)
+- 检查城市等级分布(二线及以下 ≥ 50%)
+
+**作者粉丝画像**:
 - 使用 `get_user_fans_profile` 获取作者粉丝画像
-- 验证是否符合目标受众特征
+- 检查粉丝量(≥ 10,000)
+- 检查粉丝年龄分布(41岁以上 ≥ 40%)
+- 检查粉丝偏好度(51-60岁 ≥ 1.3)
 
 ## 使用示例
 
 **用户需求**: "孩子军抗日,让人感动。找这样的视频。"
 
 **执行步骤**:
-1. 解析关键词:抗日、孩子军、感人
-2. 搜索:`douyin_search(keywords="孩子军抗日", min_views=50000, min_likes=2000)`
-3. 筛选:选择点赞率 > 5%、分享率 > 2% 的视频
-4. 深度挖掘:对优质内容作者调用 `douyin_user_videos`
-5. 画像验证:检查观众年龄分布是否符合老年人群体
+
+1. **解析关键词**:
+   - 核心关键词:抗日、孩子军
+   - 情感倾向:感人
+   - 目标受众:老年人
+
+2. **初步搜索**:
+   ```python
+   douyin_search(
+       keywords="孩子军抗日",
+       min_likes=2000,
+       max_results=20
+   )
+   ```
+
+3. **内容筛选**(考虑时效性):
+   ```
+   视频A: 点赞8k, 评论1.2k, 分享500, 发布3天前
+   - 互动总量: 9,700 ✓
+   - 评论/点赞比: 15% ✓
+   - 分享/点赞比: 6.25% ✓
+   - 时效性: 新鲜内容 ✓✓
+   结果: 通过(优先推荐)
+
+   视频B: 点赞15k, 评论2.3k, 分享1.2k, 发布120天前
+   - 互动总量: 18,500 ✓
+   - 评论/点赞比: 15.3% ✓
+   - 分享/点赞比: 8% ✓
+   - 时效性: 老内容,但热度高 ✓
+   结果: 通过
+
+   视频C: 点赞2.5k, 评论300, 分享150, 发布150天前
+   - 互动总量: 2,950 ✓
+   - 评论/点赞比: 12% ✓
+   - 分享/点赞比: 6% ✓
+   - 时效性: 老内容且热度一般 ✗
+   结果: 不通过
+   ```
+
+4. **深度挖掘**:
+   ```python
+   # 对视频A的作者进行深度挖掘
+   author_videos = douyin_user_videos(
+       author_id="user_001",
+       max_results=10
+   )
+   # 筛选30天内的优质作品
+   recent_quality = [
+       v for v in author_videos
+       if v['like_count'] > 2000
+       and days_since_publish(v) < 30
+   ]
+   # 发现该作者有3个近期优质作品
+   ```
+
+5. **画像验证**:
+   ```python
+   # 获取视频A的观众画像
+   profile = get_video_audience_profile(video_id="video_001")
+   # 检查:41岁以上占比 38% ✓
+
+   # 获取作者粉丝画像
+   fans_profile = get_user_fans_profile(author_id="user_001")
+   # 检查:粉丝量 125k ✓,41岁以上占比 43.2% ✓
+   ```
+
+## 筛选优先级
+
+建议按以下优先级筛选:
+
+1. **时效性**(新增,权重高)
+   - 7天内的内容优先
+   - 门槛:发布时间越近越好
+
+2. **点赞量**
+   - 最直接的热度指标
+   - 门槛:≥ 2,000(新内容可降低30%)
+
+3. **互动总量**
+   - 综合反映内容受欢迎程度
+   - 门槛:≥ 2,500
+
+4. **互动比例**
+   - 评论/点赞比 ≥ 8%
+   - 分享/点赞比 ≥ 3%
+
+5. **画像匹配度**
+   - 年龄分布符合老年人群体
+   - 偏好度 ≥ 1.1
+
+6. **作者质量**
+   - 粉丝量 ≥ 10,000
+   - 有多个近期优质作品
 
 ## 注意事项
+
+### 关于时效性
+- ⚠️ **优先推荐新鲜内容**(7天内)
+- ⚠️ 老内容(90天以上)需要更高的热度才推荐
+- ⚠️ 时效性可以弥补热度不足
+
+### 关于数据限制
+- ⚠️ 无法获取播放量,不要使用 `min_views` 参数
+- ⚠️ 评估标准需要调整,主要依赖点赞量和互动比例
+- ⚠️ 画像数据可以弥补播放量缺失
+
+### 关键词策略
 - 关键词要准确,避免过于宽泛
-- 筛选条件要合理,不要过于严格导致结果过少
-- 深度挖掘时注意作者内容的一致性
-- 画像数据仅作为参考,不要完全依赖
+- 可以尝试多个关键词组合
+- 根据搜索结果调整关键词
+
+### 筛选策略
+- 不要过于严格,避免结果过少
+- 结合多个维度综合判断
+- 时效性和热度需要平衡
+
+### 深度挖掘
+- 注意作者内容的一致性
+- 优先选择有多个近期优质作品的作者
+- 关注作者的粉丝画像
+
+### 灵活调整
+- 根据实际数据分布调整门槛
+- 定期根据效果优化策略
+- 可以通过 A/B 测试验证效果

+ 62 - 19
examples/content_finder/tools/douyin_search.py

@@ -3,6 +3,7 @@
 """
 
 from typing import List, Dict, Any, Optional
+from datetime import datetime, timedelta
 from agent.tools import tool, ToolResult, ToolContext
 
 
@@ -10,51 +11,63 @@ from agent.tools import tool, ToolResult, ToolContext
 async def douyin_search(
     keywords: str,
     max_results: int = 20,
-    min_views: Optional[int] = None,
     min_likes: Optional[int] = None,
     ctx: Optional[ToolContext] = None,
 ) -> ToolResult:
     """
     通过关键词搜索抖音视频内容
 
+    ⚠️ 注意:当前返回的是模拟数据,仅用于测试和演示
+    实际使用时需要对接真实的抖音API
+
     Args:
         keywords: 搜索关键词
         max_results: 最大结果数,默认20
-        min_views: 最小播放量筛选
         min_likes: 最小点赞数筛选
         ctx: 工具上下文
 
     Returns:
-        ToolResult: 包含搜索到的视频列表
+        ToolResult: 包含搜索到的视频列表(模拟数据)
     """
     # TODO: 实际实现需要调用抖音API或爬虫服务
     # 这里返回模拟数据
 
-    results = await _mock_douyin_search(keywords, max_results, min_views, min_likes)
+    results = await _mock_douyin_search(keywords, max_results, min_likes)
 
-    summary = f"搜索关键词「{keywords}」,找到 {len(results)} 条视频"
-    if min_views:
-        summary += f"(播放量 ≥ {min_views})"
+    summary = f"⚠️ [模拟数据] 搜索关键词「{keywords}」,找到 {len(results)} 条视频"
     if min_likes:
         summary += f"(点赞数 ≥ {min_likes})"
+    summary += "\n\n⚠️ 注意:以下是模拟数据,仅用于测试。实际使用需对接真实抖音API。"
 
     # 构建详细输出
     output_lines = [summary, ""]
     for i, item in enumerate(results[:5], 1):  # 只显示前5条
+        days_ago = item.get('days_since_publish', 0)
+        time_desc = f"{days_ago}天前" if days_ago > 0 else "今天"
+
         output_lines.append(f"{i}. {item['title']}")
         output_lines.append(f"   作者: {item['author_name']} (ID: {item['author_id']})")
-        output_lines.append(f"   数据: 播放 {item['play_count']:,} | 点赞 {item['like_count']:,} | 分享 {item['share_count']:,}")
+        output_lines.append(f"   发布: {time_desc}")
+        output_lines.append(f"   数据: 点赞 {item['like_count']:,} | 评论 {item['comment_count']:,} | 分享 {item['share_count']:,}")
+
+        # 计算互动比例
+        like_count = item['like_count']
+        comment_ratio = (item['comment_count'] / like_count * 100) if like_count > 0 else 0
+        share_ratio = (item['share_count'] / like_count * 100) if like_count > 0 else 0
+        output_lines.append(f"   互动: 评论率 {comment_ratio:.1f}% | 分享率 {share_ratio:.1f}%")
         output_lines.append("")
 
     if len(results) > 5:
         output_lines.append(f"... 还有 {len(results) - 5} 条结果")
 
     return ToolResult(
-        title=f"抖音搜索: {keywords}",
+        title=f"[模拟数据] 抖音搜索: {keywords}",
         output="\n".join(output_lines),
         metadata={
             "total": len(results),
             "items": results,
+            "is_mock_data": True,
+            "warning": "这是模拟数据,实际使用需对接真实API",
         },
     )
 
@@ -62,23 +75,25 @@ async def douyin_search(
 async def _mock_douyin_search(
     keywords: str,
     max_results: int,
-    min_views: Optional[int],
     min_likes: Optional[int],
 ) -> List[Dict[str, Any]]:
     """模拟抖音搜索(实际应调用真实API)"""
 
-    # 模拟数据
+    now = datetime.now()
+
+    # 模拟数据(包含不同时效性的内容)
     mock_data = [
         {
             "video_id": "7234567890123456789",
             "title": f"感人至深!{keywords}相关视频1",
             "author_id": "user_001",
             "author_name": "感动中国",
-            "play_count": 150000,
             "like_count": 8000,
             "comment_count": 1200,
             "share_count": 500,
-            "create_time": "2024-03-01 10:00:00",
+            "collect_count": 1500,
+            "create_time": (now - timedelta(days=3)).strftime("%Y-%m-%d %H:%M:%S"),
+            "days_since_publish": 3,
             "video_url": "https://www.douyin.com/video/7234567890123456789",
             "cover_url": "https://example.com/cover1.jpg",
         },
@@ -87,11 +102,12 @@ async def _mock_douyin_search(
             "title": f"{keywords}经典片段合集",
             "author_id": "user_002",
             "author_name": "历史回忆",
-            "play_count": 280000,
             "like_count": 15000,
             "comment_count": 2300,
             "share_count": 1200,
-            "create_time": "2024-03-02 14:30:00",
+            "collect_count": 3000,
+            "create_time": (now - timedelta(days=15)).strftime("%Y-%m-%d %H:%M:%S"),
+            "days_since_publish": 15,
             "video_url": "https://www.douyin.com/video/7234567890123456790",
             "cover_url": "https://example.com/cover2.jpg",
         },
@@ -100,21 +116,48 @@ async def _mock_douyin_search(
             "title": f"真实{keywords}故事",
             "author_id": "user_001",
             "author_name": "感动中国",
-            "play_count": 95000,
             "like_count": 5200,
             "comment_count": 800,
             "share_count": 350,
-            "create_time": "2024-03-03 09:15:00",
+            "collect_count": 1000,
+            "create_time": (now - timedelta(days=45)).strftime("%Y-%m-%d %H:%M:%S"),
+            "days_since_publish": 45,
             "video_url": "https://www.douyin.com/video/7234567890123456791",
             "cover_url": "https://example.com/cover3.jpg",
         },
+        {
+            "video_id": "7234567890123456792",
+            "title": f"最新{keywords}短片",
+            "author_id": "user_003",
+            "author_name": "时代记忆",
+            "like_count": 3500,
+            "comment_count": 450,
+            "share_count": 200,
+            "collect_count": 800,
+            "create_time": (now - timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S"),
+            "days_since_publish": 1,
+            "video_url": "https://www.douyin.com/video/7234567890123456792",
+            "cover_url": "https://example.com/cover4.jpg",
+        },
+        {
+            "video_id": "7234567890123456793",
+            "title": f"{keywords}珍贵影像",
+            "author_id": "user_002",
+            "author_name": "历史回忆",
+            "like_count": 2800,
+            "comment_count": 350,
+            "share_count": 150,
+            "collect_count": 600,
+            "create_time": (now - timedelta(days=120)).strftime("%Y-%m-%d %H:%M:%S"),
+            "days_since_publish": 120,
+            "video_url": "https://www.douyin.com/video/7234567890123456793",
+            "cover_url": "https://example.com/cover5.jpg",
+        },
     ]
 
     # 应用筛选条件
     filtered = []
     for item in mock_data:
-        if min_views and item["play_count"] < min_views:
-            continue
         if min_likes and item["like_count"] < min_likes:
             continue
         filtered.append(item)

+ 94 - 19
examples/content_finder/tools/douyin_user_videos.py

@@ -3,6 +3,7 @@
 """
 
 from typing import List, Dict, Any, Optional
+from datetime import datetime, timedelta
 from agent.tools import tool, ToolResult, ToolContext
 
 
@@ -15,13 +16,16 @@ async def douyin_user_videos(
     """
     根据抖音用户ID获取该用户的作品列表
 
+    ⚠️ 注意:当前返回的是模拟数据,仅用于测试和演示
+    实际使用时需要对接真实的抖音API
+
     Args:
         author_id: 抖音用户ID
         max_results: 最大返回数量,默认20
         ctx: 工具上下文
 
     Returns:
-        ToolResult: 包含用户作品列表
+        ToolResult: 包含用户作品列表(模拟数据)
     """
     # TODO: 实际实现需要调用抖音API或爬虫服务
     # 这里返回模拟数据
@@ -30,33 +34,52 @@ async def douyin_user_videos(
 
     if not results:
         return ToolResult(
-            title=f"用户作品: {author_id}",
-            output=f"未找到用户 {author_id} 的作品",
-            metadata={"total": 0, "items": []},
+            title=f"[模拟数据] 用户作品: {author_id}",
+            output=f"⚠️ 未找到用户 {author_id} 的作品(模拟数据)",
+            metadata={"total": 0, "items": [], "is_mock_data": True},
         )
 
     author_name = results[0]["author_name"]
-    summary = f"用户「{author_name}」(ID: {author_id}) 共有 {len(results)} 个作品"
+    summary = f"⚠️ [模拟数据] 用户「{author_name}」(ID: {author_id}) 共有 {len(results)} 个作品"
+
+    # 统计时效性
+    recent_count = sum(1 for v in results if v.get('days_since_publish', 999) < 30)
+    if recent_count > 0:
+        summary += f",其中 {recent_count} 个是近30天内发布"
+
+    summary += "\n\n⚠️ 注意:以下是模拟数据,仅用于测试。实际使用需对接真实抖音API。"
 
     # 构建详细输出
     output_lines = [summary, ""]
     for i, item in enumerate(results[:5], 1):  # 只显示前5条
+        days_ago = item.get('days_since_publish', 0)
+        time_desc = f"{days_ago}天前" if days_ago > 0 else "今天"
+
         output_lines.append(f"{i}. {item['title']}")
-        output_lines.append(f"   发布: {item['create_time']}")
-        output_lines.append(f"   数据: 播放 {item['play_count']:,} | 点赞 {item['like_count']:,} | 分享 {item['share_count']:,}")
+        output_lines.append(f"   发布: {time_desc}")
+        output_lines.append(f"   数据: 点赞 {item['like_count']:,} | 评论 {item['comment_count']:,} | 分享 {item['share_count']:,}")
+
+        # 计算互动比例
+        like_count = item['like_count']
+        comment_ratio = (item['comment_count'] / like_count * 100) if like_count > 0 else 0
+        share_ratio = (item['share_count'] / like_count * 100) if like_count > 0 else 0
+        output_lines.append(f"   互动: 评论率 {comment_ratio:.1f}% | 分享率 {share_ratio:.1f}%")
         output_lines.append("")
 
     if len(results) > 5:
         output_lines.append(f"... 还有 {len(results) - 5} 个作品")
 
     return ToolResult(
-        title=f"用户作品: {author_name}",
+        title=f"[模拟数据] 用户作品: {author_name}",
         output="\n".join(output_lines),
         metadata={
             "author_id": author_id,
             "author_name": author_name,
             "total": len(results),
+            "recent_count": recent_count,
             "items": results,
+            "is_mock_data": True,
+            "warning": "这是模拟数据,实际使用需对接真实API",
         },
     )
 
@@ -67,7 +90,9 @@ async def _mock_user_videos(
 ) -> List[Dict[str, Any]]:
     """模拟获取用户作品(实际应调用真实API)"""
 
-    # 模拟不同用户的数据
+    now = datetime.now()
+
+    # 模拟不同用户的数据(包含时效性信息)
     user_data = {
         "user_001": {
             "author_name": "感动中国",
@@ -75,29 +100,42 @@ async def _mock_user_videos(
                 {
                     "video_id": "7234567890123456789",
                     "title": "感人至深!孩子军抗日故事",
-                    "play_count": 150000,
                     "like_count": 8000,
                     "comment_count": 1200,
                     "share_count": 500,
-                    "create_time": "2024-03-01 10:00:00",
+                    "collect_count": 1500,
+                    "create_time": (now - timedelta(days=3)).strftime("%Y-%m-%d %H:%M:%S"),
+                    "days_since_publish": 3,
                 },
                 {
                     "video_id": "7234567890123456791",
                     "title": "真实抗战故事",
-                    "play_count": 95000,
                     "like_count": 5200,
                     "comment_count": 800,
                     "share_count": 350,
-                    "create_time": "2024-03-03 09:15:00",
+                    "collect_count": 1000,
+                    "create_time": (now - timedelta(days=45)).strftime("%Y-%m-%d %H:%M:%S"),
+                    "days_since_publish": 45,
                 },
                 {
                     "video_id": "7234567890123456792",
                     "title": "历史不能忘记",
-                    "play_count": 120000,
                     "like_count": 6500,
                     "comment_count": 950,
                     "share_count": 420,
-                    "create_time": "2024-03-05 15:20:00",
+                    "collect_count": 1200,
+                    "create_time": (now - timedelta(days=20)).strftime("%Y-%m-%d %H:%M:%S"),
+                    "days_since_publish": 20,
+                },
+                {
+                    "video_id": "7234567890123456794",
+                    "title": "铭记历史,珍爱和平",
+                    "like_count": 4200,
+                    "comment_count": 600,
+                    "share_count": 280,
+                    "collect_count": 800,
+                    "create_time": (now - timedelta(days=8)).strftime("%Y-%m-%d %H:%M:%S"),
+                    "days_since_publish": 8,
                 },
             ],
         },
@@ -107,20 +145,57 @@ async def _mock_user_videos(
                 {
                     "video_id": "7234567890123456790",
                     "title": "抗日经典片段合集",
-                    "play_count": 280000,
                     "like_count": 15000,
                     "comment_count": 2300,
                     "share_count": 1200,
-                    "create_time": "2024-03-02 14:30:00",
+                    "collect_count": 3000,
+                    "create_time": (now - timedelta(days=15)).strftime("%Y-%m-%d %H:%M:%S"),
+                    "days_since_publish": 15,
                 },
                 {
                     "video_id": "7234567890123456793",
                     "title": "那些年的英雄",
-                    "play_count": 180000,
                     "like_count": 9500,
                     "comment_count": 1500,
                     "share_count": 800,
-                    "create_time": "2024-03-04 11:00:00",
+                    "collect_count": 2000,
+                    "create_time": (now - timedelta(days=25)).strftime("%Y-%m-%d %H:%M:%S"),
+                    "days_since_publish": 25,
+                },
+                {
+                    "video_id": "7234567890123456795",
+                    "title": "珍贵历史影像资料",
+                    "like_count": 12000,
+                    "comment_count": 1800,
+                    "share_count": 950,
+                    "collect_count": 2500,
+                    "create_time": (now - timedelta(days=5)).strftime("%Y-%m-%d %H:%M:%S"),
+                    "days_since_publish": 5,
+                },
+            ],
+        },
+        "user_003": {
+            "author_name": "时代记忆",
+            "videos": [
+                {
+                    "video_id": "7234567890123456796",
+                    "title": "最新抗战短片",
+                    "like_count": 3500,
+                    "comment_count": 450,
+                    "share_count": 200,
+                    "collect_count": 800,
+                    "create_time": (now - timedelta(days=1)).strftime("%Y-%m-%d %H:%M:%S"),
+                    "days_since_publish": 1,
+                },
+                {
+                    "video_id": "7234567890123456797",
+                    "title": "感动瞬间合集",
+                    "like_count": 5800,
+                    "comment_count": 720,
+                    "share_count": 380,
+                    "collect_count": 1100,
+                    "create_time": (now - timedelta(days=12)).strftime("%Y-%m-%d %H:%M:%S"),
+                    "days_since_publish": 12,
                 },
             ],
         },

+ 18 - 8
examples/content_finder/tools/hotspot_profile.py

@@ -14,6 +14,9 @@ async def get_video_audience_profile(
     """
     获取抖音视频的点赞观众画像数据
 
+    ⚠️ 注意:当前返回的是模拟数据,仅用于测试和演示
+    实际使用时需要对接真实的热点宝API
+
     包括:
     - 观众地域分布(占比&偏好度)
     - 观众城市等级(占比&偏好度)
@@ -25,7 +28,7 @@ async def get_video_audience_profile(
         ctx: 工具上下文
 
     Returns:
-        ToolResult: 包含观众画像数据
+        ToolResult: 包含观众画像数据(模拟数据)
     """
     # TODO: 实际实现需要调用热点宝API
     # 这里返回模拟数据
@@ -34,7 +37,9 @@ async def get_video_audience_profile(
 
     # 构建输出
     output_lines = [
-        f"视频 {video_id} 的点赞观众画像:",
+        f"⚠️ [模拟数据] 视频 {video_id} 的点赞观众画像:",
+        "",
+        "⚠️ 注意:以下是模拟数据,仅用于测试。实际使用需对接真实热点宝API。",
         "",
         "【年龄分布】",
     ]
@@ -64,9 +69,9 @@ async def get_video_audience_profile(
         output_lines.append(f"  {i}. {region}: {data['percentage']:.1f}% (偏好度: {data['preference']:.2f})")
 
     return ToolResult(
-        title=f"视频观众画像: {video_id}",
+        title=f"[模拟数据] 视频观众画像: {video_id}",
         output="\n".join(output_lines),
-        metadata=profile,
+        metadata={**profile, "is_mock_data": True, "warning": "这是模拟数据,实际使用需对接真实API"},
     )
 
 
@@ -78,6 +83,9 @@ async def get_user_fans_profile(
     """
     获取抖音用户的粉丝画像数据
 
+    ⚠️ 注意:当前返回的是模拟数据,仅用于测试和演示
+    实际使用时需要对接真实的热点宝API
+
     包括:
     - 粉丝地域分布(占比&偏好度)
     - 粉丝城市等级(占比&偏好度)
@@ -89,7 +97,7 @@ async def get_user_fans_profile(
         ctx: 工具上下文
 
     Returns:
-        ToolResult: 包含粉丝画像数据
+        ToolResult: 包含粉丝画像数据(模拟数据)
     """
     # TODO: 实际实现需要调用热点宝API
     # 这里返回模拟数据
@@ -98,7 +106,9 @@ async def get_user_fans_profile(
 
     # 构建输出
     output_lines = [
-        f"用户 {author_id} 的粉丝画像:",
+        f"⚠️ [模拟数据] 用户 {author_id} 的粉丝画像:",
+        "",
+        "⚠️ 注意:以下是模拟数据,仅用于测试。实际使用需对接真实热点宝API。",
         "",
         f"粉丝总数: {profile['total_fans']:,}",
         "",
@@ -130,9 +140,9 @@ async def get_user_fans_profile(
         output_lines.append(f"  {i}. {region}: {data['percentage']:.1f}% (偏好度: {data['preference']:.2f})")
 
     return ToolResult(
-        title=f"用户粉丝画像: {author_id}",
+        title=f"[模拟数据] 用户粉丝画像: {author_id}",
         output="\n".join(output_lines),
-        metadata=profile,
+        metadata={**profile, "is_mock_data": True, "warning": "这是模拟数据,实际使用需对接真实API"},
     )