|
|
@@ -0,0 +1,818 @@
|
|
|
+# find_agent 工具能力与接口 PRD
|
|
|
+
|
|
|
+> 文档版本:v1.0
|
|
|
+> 代码基线:2026-08-03
|
|
|
+> 文档性质:As-Is 工具产品说明与接口契约
|
|
|
+> 适用对象:产品、算法、Agent Prompt、后端、测试与运维人员
|
|
|
+
|
|
|
+## 1. 文档目标
|
|
|
+
|
|
|
+本文说明“寻找视频 Agent”`find_agent` 当前真实可调用的工具,包括:
|
|
|
+
|
|
|
+- 工具清单、定位和推荐调用阶段;
|
|
|
+- 每个工具对模型暴露的参数 Schema;
|
|
|
+- 参数的业务含义、默认值、枚举、数量限制和组合规则;
|
|
|
+- 成功、部分成功和失败时的返回结构;
|
|
|
+- 搜索、详情、画像、候选更新和运行结束之间的数据衔接;
|
|
|
+- 当前接口限制、风险和验收口径。
|
|
|
+
|
|
|
+本文以运行时 `create_find_agent().tools` 生成的 Schema 和当前实现代码为准,不把仅为旧调用方
|
|
|
+保留、但未注册给 Agent 的函数算作可用工具。
|
|
|
+
|
|
|
+## 2. 产品定位
|
|
|
+
|
|
|
+`find_agent` 面向一条已经分级并完成视频点位拓展的需求,使用多个抖音数据来源完成:
|
|
|
+
|
|
|
+1. 搜索候选视频;
|
|
|
+2. 保存每次搜索及其候选;
|
|
|
+3. 拉取视频详情和受众画像;
|
|
|
+4. 判断相关性 `R`、老年受众倾向 `E`、分享价值 `S` 和综合价值 `V`;
|
|
|
+5. 将候选放入 `primary` 或 `rejected`;
|
|
|
+6. 完成运行并输出 `goal_met`、`partial` 或 `no_match`。
|
|
|
+
|
|
|
+工具服务于模型的 ReAct 决策,但搜索记录、证据、候选门禁和最终运行结果均由代码持久化,
|
|
|
+不能只依赖模型最终文本。
|
|
|
+
|
|
|
+## 3. 工具总览
|
|
|
+
|
|
|
+Agent 初始化后共有 13 个可调用工具:1 个框架内置工具和 12 个 `find_agent` 专属工具。
|
|
|
+
|
|
|
+| # | 工具 | 类型 | 主要用途 | 是否写库 |
|
|
|
+|---:|---|---|---|---:|
|
|
|
+| 1 | `load_skill` | 框架内置 | 按名称加载 Skill 指令 | 否 |
|
|
|
+| 2 | `batch_search_and_record` | 批量搜索 | 一次提交最多 6 个关键词任务,每项最多 2 页 | 是 |
|
|
|
+| 3 | `douyin_search` | 关键词搜索 | 使用内部搜索源获取一页视频 | 是 |
|
|
|
+| 4 | `douyin_search_tikhub` | 关键词搜索 | 使用 TikHub 获取一页视频和完整分页状态 | 是 |
|
|
|
+| 5 | `douyin_user_videos` | 作者扩展 | 按作者 `sec_uid` 获取一页最热或最新作品 | 是 |
|
|
|
+| 6 | `douyin_detail` | 详情证据 | 批量获取视频详情;新模式自动保存证据并重算门禁 | 新模式是 |
|
|
|
+| 7 | `get_content_fans_portrait` | 单条画像 | 获取视频点赞用户画像 | 否 |
|
|
|
+| 8 | `get_account_fans_portrait` | 单条画像 | 获取作者粉丝画像 | 否 |
|
|
|
+| 9 | `batch_fetch_portraits` | 批量画像 | 批量获取视频/作者画像;新模式自动保存并重算门禁 | 新模式是 |
|
|
|
+| 10 | `normalize_age_portraits` | 证据处理 | 将两侧年龄桶标准化为统一证据 | 否 |
|
|
|
+| 11 | `batch_update_video_discovery_candidates` | 候选决策 | 按 `candidate_id` 更新评分、理由和最终分池 | 是 |
|
|
|
+| 12 | `update_video_discovery_run_status` | 运行控制 | 更新运行状态、意图摘要和停止原因 | 是 |
|
|
|
+| 13 | `query_video_discovery_state` | 状态查询 | 读取运行、搜索轨迹和候选快照 | 否 |
|
|
|
+
|
|
|
+以下文件存在,但当前没有注册给 `find_agent`:
|
|
|
+
|
|
|
+- `create_video_discovery_run`:运行由调度器在模型循环前预创建;
|
|
|
+- `qwen_video_analyze`:当前不开放视频理解;
|
|
|
+- `batch_save_video_candidate_evaluations`、`audit_video_discovery_run` 等旧接口:不在实际工具表中。
|
|
|
+
|
|
|
+## 4. 推荐调用链
|
|
|
+
|
|
|
+```mermaid
|
|
|
+flowchart LR
|
|
|
+ A["调度器预创建 run_id"] --> B["批量或单页搜索"]
|
|
|
+ B --> C["返回 search_id 和 candidate_id"]
|
|
|
+ C --> D["douyin_detail 拉详情"]
|
|
|
+ D --> E["batch_fetch_portraits 拉双侧画像"]
|
|
|
+ E --> F["候选 R/E/S/V 判断"]
|
|
|
+ F --> G["batch_update... 写入分池"]
|
|
|
+ G --> H["query... 核对最终状态"]
|
|
|
+ H --> I["update... status=finished"]
|
|
|
+ I --> J["输出业务结果"]
|
|
|
+```
|
|
|
+
|
|
|
+推荐优先使用带 `run_id + candidate_ids` 的详情和批量画像新模式。该模式由工具从数据库读取
|
|
|
+`aweme_id` 和作者 ID,自动保存原始证据、刷新候选字段并重算门禁,减少模型搬运大 JSON 的错误。
|
|
|
+
|
|
|
+## 5. 全局接口约定
|
|
|
+
|
|
|
+### 5.1 返回值类型
|
|
|
+
|
|
|
+所有工具在 Python 层都返回 `str`。除 `load_skill` 成功时返回 Skill 上下文文本外,其余工具
|
|
|
+返回值均为 JSON 字符串,调用方必须先解析 JSON,不能把它当成已经反序列化的对象。
|
|
|
+
|
|
|
+通用成功字段通常包括:
|
|
|
+
|
|
|
+| 字段 | 类型 | 含义 |
|
|
|
+|---|---|---|
|
|
|
+| `title` | string | 结果标题,主要用于日志和模型阅读 |
|
|
|
+| `output` | string | 人类可读摘要,不是最终业务事实的唯一来源 |
|
|
|
+
|
|
|
+通用错误字段:
|
|
|
+
|
|
|
+| 字段 | 类型 | 含义 |
|
|
|
+|---|---|---|
|
|
|
+| `error` | string | 参数、上游接口、网络或数据库错误文本 |
|
|
|
+| `input_error` | boolean,可选 | `true` 表示调用参数错误;缺失不代表成功 |
|
|
|
+| `title` | string,可选 | 错误场景标题 |
|
|
|
+| `errors` | array,可选 | 批量调用中的逐项错误 |
|
|
|
+
|
|
|
+框架通过返回内容中是否存在错误字段识别工具错误,但不会自动重试、回滚整条 Agent 运行或切换
|
|
|
+备用工具。模型必须读取返回结果后决定下一步。
|
|
|
+
|
|
|
+### 5.2 核心 ID
|
|
|
+
|
|
|
+| ID | 来源 | 用途 | 约束 |
|
|
|
+|---|---|---|---|
|
|
|
+| `run_id` | 调度器预创建 | 贯穿一次需求的视频发现过程 | 所有写库工具必须复用同一个值 |
|
|
|
+| `search_id` | 搜索工具返回 | 标识一页搜索记录 | 翻页/标签/作者扩展可作为 `parent_search_id` |
|
|
|
+| `candidate_id` | 搜索工具返回 | 标识一次搜索命中的候选记录 | 详情、画像、评分和分池更新的首选主键 |
|
|
|
+| `aweme_id` / `content_id` | 抖音内容 | 标识视频本身 | 同一视频被多个搜索命中时可对应多个 `candidate_id` |
|
|
|
+| `author.sec_uid` / `account_id` | 搜索或详情结果 | 标识抖音作者 | 作者画像及作者作品扩展使用完整 `sec_uid` |
|
|
|
+
|
|
|
+### 5.3 当前 Schema 能力边界
|
|
|
+
|
|
|
+工具框架可从 Python 类型注解生成顶层 JSON Schema,但当前不生成枚举、取值范围、字符串格式,
|
|
|
+也不展开 `list[dict]` 内部对象字段。因此模型可见 Schema 中:
|
|
|
+
|
|
|
+- `searches` 和 `items` 只显示为“对象数组”;
|
|
|
+- `source_type`、`status`、排序方式等只显示为普通字符串;
|
|
|
+- 单批上限、字段组合关系只存在于工具描述和运行时代码校验中。
|
|
|
+
|
|
|
+本文后续表格补齐这些语义约束,但它们尚未全部成为可被模型供应方提前校验的 JSON Schema。
|
|
|
+
|
|
|
+## 6. 搜索类工具
|
|
|
+
|
|
|
+### 6.1 `batch_search_and_record`
|
|
|
+
|
|
|
+#### 功能
|
|
|
+
|
|
|
+顺序执行多个关键词搜索任务。每完成一页立即新增搜索记录,并为该页每条有效结果新增候选。
|
|
|
+适合启动阶段一次性提交 2~3 个语义不同的根搜索,也可用于受控翻页。
|
|
|
+
|
|
|
+#### 顶层参数
|
|
|
+
|
|
|
+| 参数 | 类型 | 必填 | 默认 | 说明 |
|
|
|
+|---|---|---:|---|---|
|
|
|
+| `run_id` | string | 是 | - | 预创建的运行 ID,不能为空 |
|
|
|
+| `searches` | array<object> | 是 | - | 搜索任务数组,必须非空,最多 6 项 |
|
|
|
+
|
|
|
+#### `searches[]` 对象
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 默认/取值 | 说明 |
|
|
|
+|---|---|---:|---|---|
|
|
|
+| `keyword` | string | 是 | - | 实际搜索词,不能为空 |
|
|
|
+| `query_reason` | string | 是 | - | 为什么执行该搜索,不能为空 |
|
|
|
+| `source_type` | string | 是 | `demand` / `seed` / `point` / `tag` / `pagination` / `mixed` | 搜索来源类型 |
|
|
|
+| `provider` | string | 否 | `internal_keyword` | 可选 `internal_keyword`、`tikhub` |
|
|
|
+| `max_pages` | integer | 否 | `1` | 自动限制到 `1~2`;超范围不会报错而会被截断 |
|
|
|
+| `cursor` | string 或 integer | 否 | 内部源为 `"0"`,TikHub 为 `0` | 起始游标 |
|
|
|
+| `search_id` | string | 否 | `""` | TikHub 翻页状态,不是数据库 `search_id` |
|
|
|
+| `backtrace` | string | 否 | `""` | TikHub 翻页回溯状态 |
|
|
|
+| `source_value` | string | 否 | `null` | 来源值,如点位文本、标签词 |
|
|
|
+| `parent_search_id` | integer | 否 | `null` | 父搜索页的数据库 ID |
|
|
|
+| `content_type` | string | 否 | `视频` | 传给底层搜索源 |
|
|
|
+| `sort_type` | string | 否 | `综合排序` | 传给底层搜索源 |
|
|
|
+| `publish_time` | string | 否 | `不限` | 发布时间筛选 |
|
|
|
+| `filter_duration` | string | 否 | `不限` | 仅 TikHub 使用 |
|
|
|
+| `min_duration_seconds` | integer | 否 | `30` | 实际最小值固定不低于 30 秒 |
|
|
|
+
|
|
|
+#### 返回结果
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `title` | string | 固定为“批量搜索并自动落库” |
|
|
|
+| `run_id` | string | 本次运行 ID |
|
|
|
+| `task_count` | integer | 通过顶层校验并进入结果的任务数;不一定等于输入项数 |
|
|
|
+| `saved_page_count` | integer | 已成功持久化的搜索页数 |
|
|
|
+| `new_candidate_count` | integer | 所有成功页新增候选总数 |
|
|
|
+| `error_count` | integer | 任务校验或分页执行错误数 |
|
|
|
+| `errors` | array<string> | 带任务下标、关键词和页码的错误摘要 |
|
|
|
+| `tasks` | array<object> | 各搜索任务的执行结果 |
|
|
|
+| `tasks[].index` | integer | 原始输入数组下标 |
|
|
|
+| `tasks[].keyword` | string | 搜索词 |
|
|
|
+| `tasks[].provider` | string | 实际搜索源 |
|
|
|
+| `tasks[].pages` | array<object> | 各页结果 |
|
|
|
+| `pages[].page_no` | integer | 页码 |
|
|
|
+| `pages[].results_count` | integer | 该页结果数 |
|
|
|
+| `pages[].has_more` | boolean | 是否还有下一页 |
|
|
|
+| `pages[].next_cursor` | string 或 integer | 下一页游标 |
|
|
|
+| `pages[].search_id` | integer | 数据库搜索记录 ID |
|
|
|
+| `pages[].new_candidate_count` | integer | 该页新增候选数 |
|
|
|
+| `pages[].candidates` | array<object> | 该页候选摘要,结构见 6.5 |
|
|
|
+| `pages[].persisted` | boolean | 是否成功落库 |
|
|
|
+| `pages[].error` | string/null | 该页错误 |
|
|
|
+| `output` | string | 批量结果摘要 |
|
|
|
+| `error` | string,可选 | 所有页均未成功保存时出现 |
|
|
|
+
|
|
|
+执行是串行的,不并发。单个任务某页报错后停止该任务后续翻页,但会继续处理后面的任务;因此
|
|
|
+返回结果可能是部分成功。
|
|
|
+
|
|
|
+### 6.2 `douyin_search`
|
|
|
+
|
|
|
+#### 功能
|
|
|
+
|
|
|
+通过内部关键词搜索源获取一页抖音视频,并自动保存搜索页、原始搜索证据和候选记录。
|
|
|
+
|
|
|
+#### 参数
|
|
|
+
|
|
|
+| 参数 | 类型 | 必填 | 默认 | 说明 |
|
|
|
+|---|---|---:|---|---|
|
|
|
+| `run_id` | string | 是 | - | 运行 ID |
|
|
|
+| `keyword` | string | 是 | - | 搜索词 |
|
|
|
+| `query_reason` | string | 是 | - | 搜索原因 |
|
|
|
+| `source_type` | string | 是 | - | 可选 `demand/seed/point/tag/author/pagination/mixed` |
|
|
|
+| `source_value` | string/null | 否 | `null` | 来源原值 |
|
|
|
+| `parent_search_id` | integer/null | 否 | `null` | 父搜索记录 ID |
|
|
|
+| `page_no` | integer | 否 | `1` | 小于 1 时按 1 保存;大于 1 自动改为 `pagination` |
|
|
|
+| `content_type` | string | 否 | `视频` | 上游支持 `视频/图文` |
|
|
|
+| `sort_type` | string | 否 | `综合排序` | 上游支持 `综合排序/最新发布/最多点赞` |
|
|
|
+| `publish_time` | string | 否 | `不限` | 上游支持 `不限/一天内/一周内/半年内` |
|
|
|
+| `cursor` | string | 否 | `"0"` | 翻页游标 |
|
|
|
+| `account_id` | string | 否 | `771431222` | 内部搜索接口账号 ID |
|
|
|
+| `min_duration_seconds` | integer | 否 | `30` | 客户端短视频过滤阈值,实际不低于 30 秒 |
|
|
|
+| `timeout` | number/null | 否 | `null` | 请求超时;`null` 时底层默认 60 秒 |
|
|
|
+
|
|
|
+#### 返回结果
|
|
|
+
|
|
|
+成功后返回“搜索页公共结构”,见 6.5。内部源特有或常用字段还包括:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `title` | string | `抖音搜索: {keyword}` |
|
|
|
+| `output` | string | 含标题、作者、点赞、评论、分享的文本摘要 |
|
|
|
+| `filtered_count` | integer | 因时长不足被过滤的数量 |
|
|
|
+| `duration_ms` | integer | 上游调用耗时 |
|
|
|
+
|
|
|
+### 6.3 `douyin_search_tikhub`
|
|
|
+
|
|
|
+#### 功能
|
|
|
+
|
|
|
+使用 TikHub 独立搜索源获取一页抖音视频,提供收藏、播放、话题以及完整分页状态,并自动落库。
|
|
|
+
|
|
|
+#### 参数
|
|
|
+
|
|
|
+| 参数 | 类型 | 必填 | 默认 | 说明 |
|
|
|
+|---|---|---:|---|---|
|
|
|
+| `run_id` | string | 是 | - | 运行 ID |
|
|
|
+| `keyword` | string | 是 | - | 搜索词,不能为空 |
|
|
|
+| `query_reason` | string | 是 | - | 搜索原因 |
|
|
|
+| `source_type` | string | 是 | - | 可选值同单页内部搜索 |
|
|
|
+| `source_value` | string/null | 否 | `null` | 来源原值 |
|
|
|
+| `parent_search_id` | integer/null | 否 | `null` | 父搜索记录 ID |
|
|
|
+| `page_no` | integer | 否 | `1` | 大于 1 自动记录为 `pagination` |
|
|
|
+| `content_type` | string | 否 | `视频` | `不限/视频/图片/图文/文章`,也兼容 `0/1/2/3` |
|
|
|
+| `sort_type` | string | 否 | `综合排序` | `综合排序/最多点赞/最新发布`,也兼容 `0/1/2` |
|
|
|
+| `publish_time` | string | 否 | `不限` | `不限/一天内/一周内/半年内`,也兼容 `0/1/7/180` |
|
|
|
+| `cursor` | integer | 否 | `0` | 首次为 0;翻页原样使用上次 `next_cursor` |
|
|
|
+| `filter_duration` | string | 否 | `不限` | `不限/一分钟内/1-5分钟/5分钟以上`,兼容供应商代码 |
|
|
|
+| `search_id` | string | 否 | `""` | 供应商分页状态;翻页必须原样回传 |
|
|
|
+| `backtrace` | string | 否 | `""` | 供应商回溯状态;翻页必须原样回传 |
|
|
|
+| `min_duration_seconds` | integer | 否 | `30` | 客户端二次过滤,实际不低于 30 秒 |
|
|
|
+| `timeout` | number/null | 否 | `null` | `null` 时默认 60 秒 |
|
|
|
+
|
|
|
+#### 返回结果
|
|
|
+
|
|
|
+除 6.5 的搜索页公共结构外,还返回:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `provider` | string | `tikhub` |
|
|
|
+| `request_params` | object | 传给 TikHub 的规范化请求参数 |
|
|
|
+| `filtered_count` | integer | 被时长过滤的数量 |
|
|
|
+| `provider_search_id` | string,可选 | 供应商返回的分页 `search_id`;避免与数据库 `search_id` 混淆 |
|
|
|
+| `backtrace` | string | 下一页回传值 |
|
|
|
+| `duration_ms` | integer | 上游调用耗时 |
|
|
|
+
|
|
|
+分页时必须同时复用上一页的 `next_cursor`、`provider_search_id` 和 `backtrace`。数据库
|
|
|
+`search_id` 只能用于父子搜索关系,不能作为 TikHub 的供应商分页参数。
|
|
|
+
|
|
|
+### 6.4 `douyin_user_videos`
|
|
|
+
|
|
|
+#### 功能
|
|
|
+
|
|
|
+按作者完整 `sec_uid` 获取一页最热或最新作品,适合从高潜作者扩展更多候选;结果自动落库。
|
|
|
+
|
|
|
+#### 参数
|
|
|
+
|
|
|
+| 参数 | 类型 | 必填 | 默认 | 说明 |
|
|
|
+|---|---|---:|---|---|
|
|
|
+| `run_id` | string | 是 | - | 运行 ID |
|
|
|
+| `account_id` | string | 是 | - | 作者 `sec_uid` |
|
|
|
+| `query_reason` | string | 是 | - | 作者扩展原因 |
|
|
|
+| `source_value` | string/null | 否 | `null` | 缺省时使用 `account_id` |
|
|
|
+| `parent_search_id` | integer/null | 否 | `null` | 触发作者扩展的父搜索页 ID |
|
|
|
+| `page_no` | integer | 否 | `1` | 页码 |
|
|
|
+| `sort_type` | string | 否 | `最热` | 仅支持 `最热`、`最新` |
|
|
|
+| `cursor` | string | 否 | `""` | 作者作品分页游标 |
|
|
|
+| `min_duration_seconds` | integer | 否 | `30` | 实际不低于 30 秒 |
|
|
|
+| `timeout` | number/null | 否 | `null` | `null` 时默认 60 秒 |
|
|
|
+
|
|
|
+#### 返回结果
|
|
|
+
|
|
|
+使用 6.5 的搜索页公共结构,并保留:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `account_id` | string | 作者 `sec_uid` |
|
|
|
+| `sort_type` | string | 实际排序方式 |
|
|
|
+| `filtered_count` | integer | 被时长过滤的数量 |
|
|
|
+| `duration_ms` | integer | 上游调用耗时 |
|
|
|
+
|
|
|
+持久化返回前会移除原始 `user_videos` 和 `search_results` 大数组,只保留数据库生成的候选摘要。
|
|
|
+
|
|
|
+### 6.5 搜索页公共返回结构
|
|
|
+
|
|
|
+三个单页搜索工具成功持久化后共同返回:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `run_id` | string | 运行 ID |
|
|
|
+| `search_id` | integer | 数据库搜索页 ID |
|
|
|
+| `keyword` | string | 本页搜索词;作者作品为 `author:{account_id}` |
|
|
|
+| `query_reason` | string | 搜索原因 |
|
|
|
+| `source_type` | string | 实际保存的来源类型 |
|
|
|
+| `source_value` | string/null | 来源值 |
|
|
|
+| `parent_search_id` | integer/null | 父搜索页 ID |
|
|
|
+| `provider` | string | `internal_keyword` / `tikhub` / `internal_blogger` |
|
|
|
+| `provider_state` | object | 保存的供应商分页状态 |
|
|
|
+| `content_type` | string | 内容类型 |
|
|
|
+| `sort_type` | string | 排序方式 |
|
|
|
+| `publish_time` | string | 发布时间筛选 |
|
|
|
+| `cursor` | string | 本页请求游标 |
|
|
|
+| `page_no` | integer | 规范化页码 |
|
|
|
+| `results_count` | integer | 上游本页结果数 |
|
|
|
+| `new_candidate_count` | integer | 本页实际新增候选数 |
|
|
|
+| `has_more` | boolean | 是否有下一页 |
|
|
|
+| `next_cursor` | string 或 integer/null | 下一页游标 |
|
|
|
+| `status` | string | `success` 或 `failed` |
|
|
|
+| `error_message` | string/null | 持久化的搜索错误 |
|
|
|
+| `raw_evidence_id` | integer/null | 原始搜索证据 ID |
|
|
|
+| `candidates` | array<object> | 本页新建候选摘要 |
|
|
|
+| `persisted` | boolean | 成功落库时为 `true` |
|
|
|
+
|
|
|
+`candidates[]` 摘要字段:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `candidate_id` | integer | 后续详情、画像和更新使用的数据库 ID |
|
|
|
+| `search_id` | integer | 所属搜索页 |
|
|
|
+| `aweme_id` | string | 抖音视频 ID |
|
|
|
+| `title` | string/null | 标题或描述 |
|
|
|
+| `author_name` | string/null | 作者名 |
|
|
|
+| `author_sec_uid` | string/null | 作者完整 `sec_uid` |
|
|
|
+| `publish_at` | string/null | 发布时间 |
|
|
|
+| `duration_seconds` | number/null | 视频时长,秒 |
|
|
|
+| `share_count` | integer/null | 分享数 |
|
|
|
+| `gate_status` | string | 初始通常为 `pending` |
|
|
|
+
|
|
|
+相同 `aweme_id` 被不同搜索命中会创建不同 `candidate_id`,不会按视频 ID 合并覆盖。
|
|
|
+
|
|
|
+## 7. 详情工具
|
|
|
+
|
|
|
+### 7.1 `douyin_detail`
|
|
|
+
|
|
|
+#### 功能
|
|
|
+
|
|
|
+批量获取视频详情、真实播放链接、作者、互动、话题和时间信息。单次最多处理 8 个去重后的视频。
|
|
|
+
|
|
|
+#### 参数
|
|
|
+
|
|
|
+| 参数 | 类型 | 必填 | 默认 | 说明 |
|
|
|
+|---|---|---:|---|---|
|
|
|
+| `content_ids` | array<string>/null | 否 | `null` | 旧模式视频 ID 列表;新流程不推荐 |
|
|
|
+| `timeout` | number/null | 否 | `null` | 单请求超时,`null` 时默认 60 秒 |
|
|
|
+| `run_id` | string/null | 条件必填 | `null` | 使用 `candidate_ids` 时必填 |
|
|
|
+| `candidate_ids` | array<integer>/null | 条件必填 | `null` | 新模式候选 ID,必须属于同一 `run_id` |
|
|
|
+
|
|
|
+组合规则:
|
|
|
+
|
|
|
+- 有 `candidate_ids` 时忽略 `content_ids`,从数据库读取 `aweme_id`;
|
|
|
+- `candidate_ids` 模式缺少 `run_id` 返回 `input_error=true`;
|
|
|
+- ID 不存在或不属于本次运行时整次输入失败;
|
|
|
+- 去重后为空会报错;超过 8 条会报错;
|
|
|
+- 新模式会追加保存每条成功或失败的原始证据,并重算对应候选门禁。
|
|
|
+
|
|
|
+#### 新模式返回结果
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `title` | string | 成功数/请求数摘要 |
|
|
|
+| `output` | string | 详情与失败项文本摘要 |
|
|
|
+| `results_count` | integer | 请求视频数 |
|
|
|
+| `success_count` | integer | 成功详情数 |
|
|
|
+| `failed_count` | integer | 失败数 |
|
|
|
+| `errors` | array<object> | `content_id`、`error`;错误文本最多保留 500 字符 |
|
|
|
+| `duration_ms` | integer | 整批耗时 |
|
|
|
+| `candidates` | array<object> | 刷新后的候选门禁摘要 |
|
|
|
+| `candidates[].candidate_id` | integer | 候选 ID |
|
|
|
+| `candidates[].aweme_id` | string | 视频 ID |
|
|
|
+| `candidates[].gate_status` | string | `pending/pass/fail` |
|
|
|
+| `candidates[].failed_reason_codes` | array<string> | 未通过门禁原因 |
|
|
|
+| `candidates[].evidence_version` | integer | 当前证据版本 |
|
|
|
+
|
|
|
+#### 旧模式额外返回
|
|
|
+
|
|
|
+旧模式不自动关联候选,返回 `details` 数组;单条成功时额外返回 `detail`。每条详情常用字段包括:
|
|
|
+
|
|
|
+- `content_id`、`channel_content_id`、`content_link`;
|
|
|
+- `title`、`body_text`、`content_type`、`topic_list`;
|
|
|
+- `video_url`、`video_duration`、`duration_seconds`、`cover_url`;
|
|
|
+- `channel_account_id`、`channel_account_name`、`channel_account_avatar`;
|
|
|
+- `play_count/view_count`、`like_count`、`comment_count`、`collect_count`、`share_count`;
|
|
|
+- `publish_at` 及源数据中的创建、发布、修改时间;
|
|
|
+- `image_url_list`、`video_url_list`、`multi_bitrate`、`bgm_data`、`is_original`。
|
|
|
+
|
|
|
+## 8. 画像与标准化工具
|
|
|
+
|
|
|
+### 8.1 `get_content_fans_portrait`
|
|
|
+
|
|
|
+获取单个视频的点赞用户画像。`content_id` 必须为 15~25 位纯数字 `aweme_id`。
|
|
|
+
|
|
|
+### 8.2 `get_account_fans_portrait`
|
|
|
+
|
|
|
+获取单个作者的粉丝画像。`account_id` 必须是完整 `sec_uid`,并以 `MS4wLjABAAAA` 开头。
|
|
|
+
|
|
|
+### 8.3 两个单条画像工具的公共参数
|
|
|
+
|
|
|
+| 参数 | 类型 | 必填 | 默认 | 说明 |
|
|
|
+|---|---|---:|---|---|
|
|
|
+| `content_id` / `account_id` | string | 是 | - | 内容或作者 ID |
|
|
|
+| `need_province` | boolean | 否 | `false` | 是否返回省份分布 |
|
|
|
+| `need_city` | boolean | 否 | `false` | 是否返回城市分布 |
|
|
|
+| `need_city_level` | boolean | 否 | `false` | 是否返回城市等级 |
|
|
|
+| `need_gender` | boolean | 否 | `false` | 是否返回性别分布 |
|
|
|
+| `need_age` | boolean | 否 | `true` | 是否返回年龄分布 |
|
|
|
+| `need_phone_brand` | boolean | 否 | `false` | 是否返回手机品牌 |
|
|
|
+| `need_phone_price` | boolean | 否 | `false` | 是否返回手机价格 |
|
|
|
+| `timeout` | number/null | 否 | `null` | `null` 时默认 60 秒 |
|
|
|
+
|
|
|
+### 8.4 两个单条画像工具的公共返回
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `title` | string | 内容或账号画像标题 |
|
|
|
+| `output` | string | 各画像维度的人类可读摘要;省份和城市只展示 TOP5 |
|
|
|
+| `has_portrait` | boolean | 是否存在任一非空画像维度 |
|
|
|
+| `portrait_data` | object | 画像维度对象;常见维度为年龄、性别、地域等 |
|
|
|
+| `raw_data` | object | 上游原始完整响应 |
|
|
|
+| `duration_ms` | integer | 调用耗时 |
|
|
|
+
|
|
|
+单条工具不自动写入候选证据。需要持久化时应优先使用 `batch_fetch_portraits` 新模式。
|
|
|
+
|
|
|
+### 8.5 `batch_fetch_portraits`
|
|
|
+
|
|
|
+#### 功能
|
|
|
+
|
|
|
+按输入顺序逐条获取内容点赞画像;`fetch_account_portrait=true` 时同时获取作者粉丝画像,
|
|
|
+否则仅在内容画像缺失且允许兜底时请求作者画像。单次最多 8 项。
|
|
|
+
|
|
|
+#### 参数
|
|
|
+
|
|
|
+| 参数 | 类型 | 必填 | 默认 | 说明 |
|
|
|
+|---|---|---:|---|---|
|
|
|
+| `candidates_json` | string | 否 | `""` | 旧模式 JSON 数组字符串 |
|
|
|
+| `fetch_account_portrait` | boolean | 否 | `false` | 是否始终同时取作者画像;老年受众判断建议为 `true` |
|
|
|
+| `need_province` | boolean | 否 | `false` | 同单条画像 |
|
|
|
+| `need_city` | boolean | 否 | `false` | 同单条画像 |
|
|
|
+| `need_city_level` | boolean | 否 | `false` | 同单条画像 |
|
|
|
+| `need_gender` | boolean | 否 | `false` | 同单条画像 |
|
|
|
+| `need_age` | boolean | 否 | `true` | 同单条画像 |
|
|
|
+| `need_phone_brand` | boolean | 否 | `false` | 同单条画像 |
|
|
|
+| `need_phone_price` | boolean | 否 | `false` | 同单条画像 |
|
|
|
+| `timeout` | number/null | 否 | `null` | `null` 时默认 60 秒 |
|
|
|
+| `run_id` | string/null | 条件必填 | `null` | 使用 `candidate_ids` 时必填 |
|
|
|
+| `candidate_ids` | array<integer>/null | 条件必填 | `null` | 新模式候选 ID,最多 8 条 |
|
|
|
+
|
|
|
+旧模式 `candidates_json` 每项:
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 默认 | 说明 |
|
|
|
+|---|---|---:|---|---|
|
|
|
+| `aweme_id` | string | 是 | - | 视频 ID;也兼容字段名 `content_id` |
|
|
|
+| `author_sec_uid` | string | 否 | - | 作者 ID;也兼容字段名 `account_id` |
|
|
|
+| `try_account_fallback` | boolean | 否 | `true` | 内容画像缺失时是否尝试作者画像 |
|
|
|
+
|
|
|
+#### 新模式返回
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `title` | string | 批量完成标题 |
|
|
|
+| `output` | string | 各候选画像获取摘要 |
|
|
|
+| `count` | integer | 处理项数 |
|
|
|
+| `duration_ms` | integer | 整批耗时 |
|
|
|
+| `candidates` | array<object> | 刷新后的候选门禁摘要 |
|
|
|
+| `candidates[].candidate_id` | integer | 候选 ID |
|
|
|
+| `candidates[].aweme_id` | string | 视频 ID |
|
|
|
+| `candidates[].gate_status` | string | `pending/pass/fail` |
|
|
|
+| `candidates[].failed_reason_codes` | array<string> | 门禁失败原因 |
|
|
|
+| `candidates[].evidence_version` | integer | 证据版本 |
|
|
|
+
|
|
|
+#### 旧模式返回
|
|
|
+
|
|
|
+旧模式返回 `results`,每项包含:
|
|
|
+
|
|
|
+- `aweme_id`、`author_sec_uid`、`try_account_fallback`、`fetch_account_portrait`;
|
|
|
+- `content`:`ok/error/has_portrait/portrait_data/output`;
|
|
|
+- `account`:`attempted/error/skipped_reason/has_portrait/portrait_data/output`;
|
|
|
+- `age_normalization`:两侧年龄标准化结果;
|
|
|
+- `error`:条目级错误。
|
|
|
+
|
|
|
+批量画像允许逐项失败,不会因为一条上游失败而丢弃整批结果。
|
|
|
+
|
|
|
+### 8.6 `normalize_age_portraits`
|
|
|
+
|
|
|
+#### 参数
|
|
|
+
|
|
|
+| 参数 | 类型 | 必填 | 默认 | 说明 |
|
|
|
+|---|---|---:|---|---|
|
|
|
+| `content_portrait` | object | 是 | - | 视频 `portrait_data` 或其中的年龄字典 |
|
|
|
+| `account_portrait` | object/null | 否 | `null` | 作者 `portrait_data` 或其中的年龄字典 |
|
|
|
+
|
|
|
+#### 返回结果
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `title` | string | “年龄画像标准化” |
|
|
|
+| `content` | object | 视频侧标准化结果 |
|
|
|
+| `account` | object | 作者侧标准化结果 |
|
|
|
+| `consistency` | string | `aligned/conflict/content_only/account_only/missing` |
|
|
|
+| `elder_score_cap` | number | 当前证据条件下建议的 E 分数上限 |
|
|
|
+| `output` | string | 两侧强度、一致性与上限摘要 |
|
|
|
+
|
|
|
+`content`、`account` 公共字段:
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `has_age_portrait` | boolean | 是否识别到年龄维度 |
|
|
|
+| `older_ratio` | number | 50+ 桶占比,范围 0~1 |
|
|
|
+| `older_tgi` | number/null | 50+ 桶按占比加权 TGI |
|
|
|
+| `mature_ratio` | number | 40~50 等成熟代理桶占比 |
|
|
|
+| `strength` | string | `strong/moderate/weak/missing` |
|
|
|
+| `buckets` | array<object> | 原桶的 `label/kind/ratio/tgi` |
|
|
|
+
|
|
|
+当前 `elder_score_cap` 规则:
|
|
|
+
|
|
|
+| 证据情况 | 上限 |
|
|
|
+|---|---:|
|
|
|
+| 内容与作者两侧都有画像 | `1.0` |
|
|
|
+| 仅内容侧 | `1.0` |
|
|
|
+| 仅作者侧且强证据 | `0.85` |
|
|
|
+| 仅作者侧且非强证据 | `0.75` |
|
|
|
+| 两侧均缺失 | `0.50` |
|
|
|
+
|
|
|
+此上限是返回给模型的决策建议,候选更新工具不会硬校验 `elder_score <= elder_score_cap`。
|
|
|
+
|
|
|
+## 9. 候选更新工具
|
|
|
+
|
|
|
+### 9.1 `batch_update_video_discovery_candidates`
|
|
|
+
|
|
|
+#### 功能
|
|
|
+
|
|
|
+严格按 `candidate_id` 批量更新候选详情、画像证据、R/E/S/V 评分、理由和分池。该工具只更新
|
|
|
+候选,不新增候选、不修改搜索记录,也不结束运行。
|
|
|
+
|
|
|
+#### 顶层参数
|
|
|
+
|
|
|
+| 参数 | 类型 | 必填 | 说明 |
|
|
|
+|---|---|---:|---|
|
|
|
+| `run_id` | string | 是 | 运行 ID |
|
|
|
+| `items` | array<object> | 是 | 非空候选更新数组 |
|
|
|
+
|
|
|
+#### `items[]` 字段
|
|
|
+
|
|
|
+| 字段 | 类型 | 必填 | 说明 |
|
|
|
+|---|---|---:|---|
|
|
|
+| `candidate_id` | integer | 是 | 必须大于 0、存在且属于 `run_id` |
|
|
|
+| `decision_bucket` | string | 是 | 仅 `primary` 或 `rejected` |
|
|
|
+| `title` | string | 否 | 标题,最多 512 字符 |
|
|
|
+| `content_link` | string | 否 | 内容链接,最多 1024 字符 |
|
|
|
+| `author_name` | string | 否 | 作者名,最多 256 字符 |
|
|
|
+| `author_sec_uid` | string | 否 | 作者 ID,最多 256 字符 |
|
|
|
+| `tags` | array/string | 否 | 标签;与已有标签合并 |
|
|
|
+| `publish_at` | string/number | 否 | ISO 时间、日期或秒/毫秒时间戳 |
|
|
|
+| `duration_seconds` | number | 否 | 秒;也兼容 `video_duration` |
|
|
|
+| `play_count` | integer | 否 | 播放数,负值归零 |
|
|
|
+| `like_count` | integer | 否 | 点赞数,负值归零 |
|
|
|
+| `comment_count` | integer | 否 | 评论数,负值归零 |
|
|
|
+| `collect_count` | integer | 否 | 收藏数,负值归零 |
|
|
|
+| `share_count` | integer | 否 | 分享数,负值归零 |
|
|
|
+| `content_age_evidence` | object | 否 | 视频侧原始/结构化年龄证据 |
|
|
|
+| `account_age_evidence` | object | 否 | 作者侧原始/结构化年龄证据 |
|
|
|
+| `age_normalization` | object | 否 | 标准化结果;兼容包在 `result` 等字段内 |
|
|
|
+| `content_50_plus_ratio` | number | 否 | 视频侧 50+ 占比,必须在 0~1 |
|
|
|
+| `content_50_plus_tgi` | number | 否 | 视频侧 50+ TGI |
|
|
|
+| `account_50_plus_ratio` | number | 否 | 作者侧 50+ 占比,必须在 0~1 |
|
|
|
+| `account_50_plus_tgi` | number | 否 | 作者侧 50+ TGI |
|
|
|
+| `temporal_type` | string | 否 | 建议 `evergreen/event/seasonal/festival/daypart` |
|
|
|
+| `temporal_status` | string | 否 | 显式 `fail/unknown` 会参与时间门禁;其他值由规则重算 |
|
|
|
+| `temporal_evidence` | object | 否 | 时效判断证据 |
|
|
|
+| `reject_reason_code` | string | 否 | 拒绝原因码,最多 64 字符 |
|
|
|
+| `relevance_score` | number | 否 | `R`,保存 6 位小数 |
|
|
|
+| `elder_score` | number | 否 | `E`,保存 6 位小数 |
|
|
|
+| `share_score` | number | 否 | `S`,保存 6 位小数 |
|
|
|
+| `value_score` | number | 否 | `V`,保存 2 位小数 |
|
|
|
+| `decision_reason` | string | 否 | 最终判断理由 |
|
|
|
+
|
|
|
+#### 校验和重分类
|
|
|
+
|
|
|
+- 任一 `items[]` 不是对象、缺少有效 `candidate_id` 或分池非法,整批在写库前失败;
|
|
|
+- 不存在或不属于本次运行的 `candidate_id` 会使数据库更新失败;
|
|
|
+- `content/account_50_plus_ratio` 被硬校验为 0~1;
|
|
|
+- R/E/S/V 当前只做数字转换和精度处理,不硬校验 0~1,也不自动计算 `V`;
|
|
|
+- 请求 `primary` 但证据未齐时保存为 `pending_evaluation`;
|
|
|
+- 请求 `primary` 但 P0 门禁失败时自动保存为 `rejected`;
|
|
|
+- 请求 `rejected` 时即使门禁通过也仍保存为 `rejected`。
|
|
|
+
|
|
|
+默认 P0 规则快照包含:时效有效、时长至少 30 秒、分享至少 1000、视频或作者任一侧 50+ 占比
|
|
|
+至少 20%。部分缺失项可由代码中的高质量信号补偿;运行使用预创建时保存的规则快照,环境变量
|
|
|
+可修改阈值。
|
|
|
+
|
|
|
+#### 返回结果
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `title` | string | “候选已更新” |
|
|
|
+| `run_id` | string | 运行 ID |
|
|
|
+| `updated_count` | integer | 成功更新候选数 |
|
|
|
+| `reclassified_count` | integer | 门禁导致分池变化的数量 |
|
|
|
+| `reclassified` | array<object> | `candidate_id/requested_bucket/saved_bucket/failed_reason_codes` |
|
|
|
+| `candidates` | array<object> | 更新后候选摘要 |
|
|
|
+| `candidates[].candidate_id` | integer | 候选 ID |
|
|
|
+| `candidates[].aweme_id` | string | 视频 ID |
|
|
|
+| `candidates[].decision_bucket` | string | 实际保存的分池 |
|
|
|
+| `candidates[].gate_status` | string | `pending/pass/fail` |
|
|
|
+| `candidates[].failed_reason_codes` | array<string> | 门禁失败码 |
|
|
|
+| `candidates[].pending_reason_codes` | array<string> | 尚缺证据的原因码 |
|
|
|
+| `candidates[].evidence_version` | integer | 候选证据版本 |
|
|
|
+| `candidates[].gate_evidence_version` | integer/null | 门禁使用的证据版本 |
|
|
|
+| `candidates[].latest_gate_evaluation_id` | integer/null | 最近门禁评估记录 ID |
|
|
|
+| `output` | string | 更新与重分类摘要 |
|
|
|
+
|
|
|
+## 10. 运行控制与查询工具
|
|
|
+
|
|
|
+### 10.1 `update_video_discovery_run_status`
|
|
|
+
|
|
|
+#### 参数
|
|
|
+
|
|
|
+| 参数 | 类型 | 必填 | 默认 | 说明 |
|
|
|
+|---|---|---:|---|---|
|
|
|
+| `run_id` | string | 是 | - | 运行 ID |
|
|
|
+| `status` | string | 是 | - | 仅 `running/finished/failed` |
|
|
|
+| `intent_summary` | string/null | 否 | `null` | Agent 对需求真实意图的总结 |
|
|
|
+| `stop_reason` | string/null | 否 | `null` | 停止搜索或失败原因 |
|
|
|
+
|
|
|
+#### 行为
|
|
|
+
|
|
|
+- `finished`:把所有剩余 `pending_evaluation/unreviewed` 候选归档为 `rejected`,刷新计数并计算业务结果;
|
|
|
+- `failed`:设置 `outcome_status=failed`;
|
|
|
+- `running`:只更新运行状态及可选说明,不清空既有搜索和候选。
|
|
|
+
|
|
|
+业务结果:有效且按 `aweme_id` 去重的 `primary` 至少 5 条为 `goal_met`,1~4 条为 `partial`,
|
|
|
+0 条为 `no_match`。
|
|
|
+
|
|
|
+#### 返回结果
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `title` | string | 状态更新标题 |
|
|
|
+| `run` | object | 完整运行摘要,见 10.3 |
|
|
|
+| `output` | string | `run_id/status/primary_count` 摘要 |
|
|
|
+
|
|
|
+### 10.2 `query_video_discovery_state`
|
|
|
+
|
|
|
+#### 参数
|
|
|
+
|
|
|
+| 参数 | 类型 | 必填 | 默认 | 说明 |
|
|
|
+|---|---|---:|---|---|
|
|
|
+| `run_id` | string | 是 | - | 运行 ID |
|
|
|
+| `include_rejected` | boolean | 否 | `true` | 是否包含 `rejected`;为 false 时仍包含 `primary` 和待评估候选 |
|
|
|
+| `limit` | integer | 否 | `100` | 候选返回上限,代码约束为 `1~500` |
|
|
|
+
|
|
|
+#### 返回结果
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `title` | string | 查询标题 |
|
|
|
+| `run` | object | 运行摘要 |
|
|
|
+| `searches` | array<object> | 所有搜索页,结构见 10.4 |
|
|
|
+| `candidates` | array<object> | 候选详情,结构见 10.5 |
|
|
|
+| `output` | string | 搜索页数和主推荐数摘要 |
|
|
|
+
|
|
|
+### 10.3 `run` 对象
|
|
|
+
|
|
|
+| 字段 | 类型 | 说明 |
|
|
|
+|---|---|---|
|
|
|
+| `run_id` | string | 运行 ID |
|
|
|
+| `biz_dt` | string/null | 业务日期 |
|
|
|
+| `demand_grade_id` | integer/null | 需求分级记录 ID |
|
|
|
+| `demand_word` | string | 需求词 |
|
|
|
+| `seed_video_id` | string/null | 兼容旧流程的主参考视频 ID |
|
|
|
+| `seed_video_title` | string/null | 兼容旧流程的主参考视频标题 |
|
|
|
+| `intent_summary` | string/null | 意图总结 |
|
|
|
+| `status` | string | `running/finished/failed` |
|
|
|
+| `search_count` | integer | 已保存搜索页数 |
|
|
|
+| `primary_count` | integer | 当前 primary 记录数 |
|
|
|
+| `valid_primary_count` | integer | 门禁通过且按视频去重后的 primary 数 |
|
|
|
+| `outcome_status` | string/null | `goal_met/partial/no_match/failed` |
|
|
|
+| `attempt_count` | integer | 执行次数 |
|
|
|
+| `stop_reason` | string/null | 停止或失败原因 |
|
|
|
+| `rule_version` | string | P0 规则版本 |
|
|
|
+| `rule_config` | object | 本次运行冻结的门禁配置和评估时间 |
|
|
|
+
|
|
|
+### 10.4 `searches[]` 对象
|
|
|
+
|
|
|
+字段与 6.5 搜索页公共结构一致,但不含 `run_id`、`candidates` 和 `persisted`。查询态包含:
|
|
|
+`search_id`、关键词与原因、来源和父子关系、供应商及分页状态、筛选参数、结果数、候选数、
|
|
|
+`has_more/next_cursor`、执行状态、错误信息和原始证据 ID。
|
|
|
+
|
|
|
+### 10.5 `candidates[]` 完整对象
|
|
|
+
|
|
|
+| 字段组 | 字段 |
|
|
|
+|---|---|
|
|
|
+| 标识与来源 | `candidate_id`、`search_id`、`aweme_id`、`source_keywords`、`source_search_ids` |
|
|
|
+| 内容与作者 | `title`、`content_link`、`author_name`、`author_sec_uid`、`tags`、`publish_at`、`duration_seconds` |
|
|
|
+| 互动数据 | `play_count`、`like_count`、`comment_count`、`collect_count`、`share_count` |
|
|
|
+| 模型评分 | `relevance_score`、`elder_score`、`share_score`、`value_score`、`decision_reason` |
|
|
|
+| 分池 | `decision_bucket`、`reject_reason_code` |
|
|
|
+| 年龄证据 | `content_age_evidence`、`account_age_evidence`、`age_normalization`、两侧 `50_plus_ratio/tgi` |
|
|
|
+| 画像状态 | `content_portrait_status`、`account_portrait_status`、`portrait_conflict` |
|
|
|
+| 时效门禁 | `temporal_type`、`temporal_status`、`temporal_evidence` |
|
|
|
+| 门禁结果 | `gate_status`、`gate_results`、`rule_version` |
|
|
|
+| 证据引用 | 四类 `latest_*_evidence_id`、三类 `*_fetch_status` |
|
|
|
+| 版本审计 | `evidence_version`、`gate_evidence_version`、`latest_gate_evaluation_id`、`gate_evaluated_at` |
|
|
|
+
|
|
|
+数据库旧值 `unreviewed` 在返回时统一映射为 `pending_evaluation`。
|
|
|
+
|
|
|
+## 11. 内置工具 `load_skill`
|
|
|
+
|
|
|
+### 参数
|
|
|
+
|
|
|
+| 参数 | 类型 | 必填 | 说明 |
|
|
|
+|---|---|---:|---|
|
|
|
+| `name` | string | 是 | Skill 名称 |
|
|
|
+
|
|
|
+### 返回
|
|
|
+
|
|
|
+- 找到 Skill:返回包含 Skill 名称、说明和完整指令的上下文文本;
|
|
|
+- 未找到:返回 JSON 字符串 `{"error": "Skill '...' not found. Available: ..."}`。
|
|
|
+
|
|
|
+当前 `find_agent` 没有预加载 Skill,项目 `skills/` 下也没有可发现的 `SKILL.md`,因此正常视频
|
|
|
+发现流程不依赖此工具。
|
|
|
+
|
|
|
+## 12. 非功能要求
|
|
|
+
|
|
|
+### 12.1 性能与限流
|
|
|
+
|
|
|
+- 内部关键词搜索:进程内相邻请求至少间隔约 10.1 秒;
|
|
|
+- 作者作品:进程内相邻请求至少间隔约 10.1 秒;
|
|
|
+- 视频详情:进程内逐条请求至少间隔约 10.1 秒;
|
|
|
+- TikHub 搜索:进程内相邻请求至少间隔 1 秒;
|
|
|
+- 批量搜索和批量画像均按顺序执行,不承诺并发;
|
|
|
+- 单次 Agent 运行默认总超时 600 秒,工具自身默认上游超时通常为 60 秒。
|
|
|
+
|
|
|
+### 12.2 可追溯性
|
|
|
+
|
|
|
+- 每次搜索页都新增记录,不覆盖同参数历史页;
|
|
|
+- 搜索、详情和批量画像新模式保存原始证据;
|
|
|
+- 候选门禁记录证据版本和最近评估 ID;
|
|
|
+- 运行完成后以数据库 `outcome_status` 和 `valid_primary_count` 为准,不能仅看最终文案。
|
|
|
+
|
|
|
+### 12.3 数据安全与体积
|
|
|
+
|
|
|
+- 单条画像工具返回 `raw_data`,可能体积较大;Agent 主流程应优先使用新模式批量画像的候选摘要;
|
|
|
+- 搜索落库返回会移除原始响应和统一搜索结果大数组,但原始响应已保存到证据表;
|
|
|
+- 错误文本可能包含上游响应内容,展示到前台前应做长度控制和敏感信息过滤。
|
|
|
+
|
|
|
+## 13. 已知问题与产品改进项
|
|
|
+
|
|
|
+| 优先级 | 问题 | 影响 | 建议 |
|
|
|
+|---|---|---|---|
|
|
|
+| P0 | `list[dict]` 内部结构未进入 JSON Schema | 模型容易漏填 `keyword/query_reason/candidate_id/decision_bucket` | 使用 Pydantic 模型或 TypedDict 生成嵌套 Schema |
|
|
|
+| P0 | 多数枚举和范围未进入 JSON Schema | 非法 `source_type/status/sort_type` 只能运行时发现 | 为参数增加 enum、minimum、maximum |
|
|
|
+| P1 | 所有工具都返回字符串化 JSON | 调用方易发生二次解析遗漏 | 在框架层明确结构化工具结果协议 |
|
|
|
+| P1 | 搜索工具的数据库 `search_id` 与 TikHub `search_id` 同名 | 翻页时容易传错 ID | 对外统一命名为 `db_search_id/provider_search_id` |
|
|
|
+| P1 | R/E/S/V 不做范围与公式校验 | 可保存越界分数或错误 V | 强制 0~1 并由代码计算 V |
|
|
|
+| P1 | `elder_score_cap` 只提示、不执行 | 模型可能给出高于证据上限的 E | 更新候选时加入硬校验或自动截断 |
|
|
|
+| P1 | 单条画像工具不写证据 | 使用旧模式会出现结果存在但不可追溯 | Prompt 和调用层只开放批量新模式,或给单条工具增加候选模式 |
|
|
|
+| P2 | 批量搜索只返回部分 TikHub 分页字段 | 外部调用方难以手动接管中途分页 | 在 `pages[]` 明确返回 `provider_search_id/backtrace` |
|
|
|
+| P2 | 错误结构不完全统一 | 调用方需兼容 `error/errors/error_message` | 定义统一 `ok/code/error/data` 包装 |
|
|
|
+
|
|
|
+其中年龄上限应以本文件记录的当前代码值为准:仅作者强证据 `0.85`、仅作者非强证据 `0.75`、
|
|
|
+两侧缺失 `0.50`。旧文档中的 `0.65/0.35` 已不符合当前实现。
|
|
|
+
|
|
|
+## 14. 验收标准
|
|
|
+
|
|
|
+### 14.1 文档验收
|
|
|
+
|
|
|
+- 工具数量与 `create_find_agent().tools.list_tools()` 一致;
|
|
|
+- 每个工具的顶层必填项、类型和默认值与运行时 Schema 一致;
|
|
|
+- 搜索任务、候选更新项等嵌套字段与运行时代码校验一致;
|
|
|
+- 返回字段可在对应实现或 Service 序列化函数中逐项定位;
|
|
|
+- 明确区分数据库 ID、平台 ID 和供应商分页 ID。
|
|
|
+
|
|
|
+### 14.2 调用验收
|
|
|
+
|
|
|
+- 搜索成功后必须得到 `search_id` 和至少零个 `candidate_id`,且 `persisted=true`;
|
|
|
+- 详情/画像新模式必须使用同一 `run_id` 下的 `candidate_ids`;
|
|
|
+- 候选更新后必须读取实际 `decision_bucket` 和 `gate_status`,不能假设请求分池等于保存分池;
|
|
|
+- 结束前必须调用状态查询核对搜索数、候选分池和门禁;
|
|
|
+- 正常业务结束必须调用 `status=finished`,并以返回的 `outcome_status` 为最终结果;
|
|
|
+- 任一返回含 `error` 时都必须显式处理,不得视为成功继续。
|
|
|
+
|
|
|
+## 15. 代码依据
|
|
|
+
|
|
|
+| 范围 | 代码位置 |
|
|
|
+|---|---|
|
|
|
+| Agent 注册工具 | `agents/find_agent/tools/__init__.py` |
|
|
|
+| 运行时 Tool Schema | `supply_agent/tools/base.py` |
|
|
|
+| 内置 `load_skill` | `supply_agent/agent/core.py` |
|
|
|
+| 搜索工具 | `agents/find_agent/tools/` 与 `agents/find_agent/support/douyin_*.py` |
|
|
|
+| 搜索持久化 | `agents/find_agent/support/search_persistence.py` |
|
|
|
+| 详情与画像 | `agents/find_agent/support/douyin_detail.py`、`portrait.py`、`age_portrait.py` |
|
|
|
+| 候选与运行工具 | `agents/find_agent/support/video_discovery.py` |
|
|
|
+| 返回对象序列化 | `supply_infra/services/video_discovery_service.py` |
|
|
|
+| P0 门禁 | `supply_infra/video_discovery_gates.py` |
|
|
|
+
|