# Acquisition Demo Runtime Boundary

本文整理当前 acquisition demo 在 `acquisition/` 目录以外真实使用的输入、输出、配置和外部接口。调查时间：2026-06-30。

## 当前状态

- 已尝试关闭历史 SubAgent `019f1683-1368-7b20-8d07-8ce7532ab34e`，工具返回 `not found`，当前没有可管理的活跃 SubAgent。
- 当前前端服务入口是 `creation_knowledge.api:app`，本地通常跑在 `http://localhost:8126/app/#/`。
- 当前 demo 主链路不是旧的“找帖子”页面，而是“创作 query 正交 demo”：
  - query 生成：`scripts/build_creation_demo.py`
  - 真实采集：`scripts/run_creation_search.py`
  - AI 补判：`scripts/classify_creation_items.py`
  - API + 静态托管：`creation_knowledge/api.py` + `acquisition/web_api.py`
  - 前端：`acquisition/web/app/src/App.jsx`、`CreationDemo.jsx`、`CreationQueryDetail.jsx`

## 目录外真实依赖

### `core/`

`acquisition` 依赖 `core` 作为共享底座：

- `core/config.py`
  - 读取 `.env` 或系统环境变量。
  - 组装 `Settings`，供搜索、详情、OSS、模型判断、静态目录使用。
- `core/prompts.py`
  - 从项目根 `prompts/<name>.txt` 读取 prompt。
- `core/llm.py`
  - 走 OpenRouter `/chat/completions`，用于旧 query 生成/部分 query 过滤。
- `core/models.py`
  - `Post` / `Card` 数据模型，被 crawler/detail parse 使用。
- `core/embedding.py`
  - 走火山 Ark embedding。当前 acquisition demo 主链路不直接用，旧/解构链路和 scope 工具可能用。
- `core/db.py`
  - PostgreSQL/Greenplum 连接工具。当前 demo 主链路主要用 SQLite；旧/正式入库链路会用。

### `creation_knowledge/`

当前 acquisition demo 借用了 `creation_knowledge` 的服务壳和媒体下载工具：

- `creation_knowledge/api.py`
  - FastAPI app。
  - 挂载 `/app` 到 `acquisition/web/app/dist`。
  - 挂载 `/data` 到 `Settings.data_dir`，默认 `data`。
  - 挂载 `/frames` 到 `Settings.frames_dir`，默认 `runtime/frames`。
  - include `acquisition.web_api.router`。
- `creation_knowledge/integrations/video_extract.py`
  - `acquisition.creation_search` 只复用 `_default_download` 下载图片/媒体。
  - 旧视频解构链路会使用更多 video extract 逻辑。

### `scripts/`

当前 demo 的主要操作入口在 `scripts/`，不在 `acquisition/` 内：

- `scripts/build_creation_demo.py`
  - 读 `scope_trees/trees_index.json`。
  - 调 `acquisition.query_filter.filter_queries`。
  - 写 `data/queries/creation_demo.json`。
- `scripts/run_creation_search.py`
  - 读 `data/queries/creation_demo.json`。
  - 写 `data/app.db` 的 `creation_*` 表。
  - 下载小红书/公众号图片到 `data/media/...`。
  - 抖音视频调用 OSS 上传接口，保存 CDN URL 到 SQLite。
- `scripts/classify_creation_items.py`
  - 从 `data/app.db` 读取未判断/失败的 item。
  - 调 `acquisition.classify` 使用 Qwen / Ark / OpenRouter。
  - 写 `creation_item_classifications`。

旧链路仍存在但不是当前 demo 主路径：

- `scripts/decompose.py`
  - 读 `创作知识提取-skill/extraction/phase1-frame.md`、`phase2-scope.md`。
  - 读 `prompts/gate_admit.txt`、`gate_refute.txt`、`gate_tiebreak.txt` 等。
  - 输出 `outputs/`、`web/frameworks*.json`、`web/payloads*.json` 等旧/后续解构产物。
- `scripts/run_search.py`
  - 旧“找帖子”链路，写 `data/search_results.json`、`data/search/...`。

## Prompt 与 Skill

### 当前 demo 直接使用的 prompt

- `acquisition/query_filter.txt`
  - query 机械正交后做 valid/relevant 过滤。
  - `scripts/build_creation_demo.py` 间接调用。
  - 前端 `/api/filter-prompt` 会原样展示。
- `prompts/classify_imgtext.txt`
  - 小红书、微信公众号图文判断“是不是创作知识”。
  - `acquisition.classify.classify_imgtext` 读取。
  - 前端 `/api/judge-prompts` 会展示。
- `prompts/classify_video.txt`
  - 抖音视频判断“是不是创作知识”。
  - `acquisition.classify.classify_video` 读取。
  - 当前列表里的 `x/10创作知识` 暂不把抖音计入分母。

### 旧/解构链路使用的 prompt

- `prompts/extract.txt`
- `prompts/extract_video.txt`
- `prompts/gate_admit.txt`
- `prompts/gate_refute.txt`
- `prompts/gate_tiebreak.txt`
- `prompts/gate_how_*`
- `prompts/gate_why_refute.txt`
- `prompts/normalize_scope.txt`
- `prompts/query_gen.txt`
- `prompts/form_query_gen.txt`

### 创作知识提取 skill

`创作知识提取-skill/` 当前不是 acquisition demo 主链路的直接运行依赖。它仍然是后续“真实解构/组装 payload”的方法论来源：

- `scripts/decompose.py` 直接读取：
  - `创作知识提取-skill/extraction/phase1-frame.md`
  - `创作知识提取-skill/extraction/phase2-scope.md`
- skill 内还包含 schema、taxonomy、lint/ingest/scope-link 工具。

## 数据输入与输出

### Query 输入

- `scope_trees/trees_index.json`
  - `scripts/build_creation_demo.py` 读取。
  - 生成 query 的实质/形式/作用/感受/意图树输入。
- `scope_trees/trees.json`
  - 当前 demo 主路径不直接读。
- `scope_trees/trees_embeddings.npy`
  - 当前 demo 主路径不直接读；scope/embedding 工具可能用。

### Query 输出

- `data/queries/creation_demo.json`
  - 当前前端首页直接 fetch：`/data/queries/creation_demo.json`。
  - `scripts/run_creation_search.py` 默认读取它，作为 430 query 输入。
  - 当前大小约 140KB。

### SQLite

- `data/app.db`
  - 当前 demo 的结构化结果库。
  - SQLite，当前约 52MB。
  - 当前主表：
    - `creation_search_runs`
    - `creation_search_jobs`
    - `creation_search_items`
    - `creation_item_classifications`
  - 旧表目前为空：
    - `queries`
    - `search_results`
    - `post_class`

当前调查时行数：

- `creation_search_runs`: 3
- `creation_search_jobs`: 1302
- `creation_search_items`: 6009
- `creation_item_classifications`: 4290
- `queries`: 0
- `search_results`: 0
- `post_class`: 0

`creation_search_items` 存标题、正文、原帖 URL、本地图片 URL、OSS 视频 CDN URL、raw JSON 等；不是巨大 JSON 文件。

### 媒体输出

- `data/media/xiaohongshu/<query_hash>/<content_id>/image_*.webp|jpg|png`
- `data/media/weixin/<query_hash>/<article_hash>/image_*.webp|jpg|png|gif`
- 抖音视频不落本地，写 OSS CDN URL 到 SQLite `creation_search_items.video_url`。

当前体量：

- `data/media`: 约 5.4GB
- `data/app.db`: 约 52MB
- `data/queries`: 约 140KB
- `data/` 总计：约 5.5GB

### Runtime 输出

- `runtime/logs/...`
  - 全量采集、分类、web 服务日志。
- `runtime/frames`
  - 旧/视频帧链路使用；FastAPI 会挂载为 `/frames`。

## `.env` 配置

配置读取优先级是：真实环境变量 > `CK_ENV_FILE` 指定文件 > 默认 `.env` > 代码默认值。

当前 demo 主链路实际会读取这些 key：

### 基础

- `CK_ENV_FILE`
- `CK_DATA_DIR`
- `CK_FRAMES_DIR`
- `CK_MAX_CARDS`

### Aiddit 爬虫接口（小红书 / 微信公众号等）

- `AIDDIT_CRAWLER_BASE_URL`
- `AIDDIT_CRAWLER_TIMEOUT_SECONDS`

### 票圈 TV 抖音独立后端

- `PIAOQUANTV_DOUYIN_BASE_URL`
- `PIAOQUANTV_DOUYIN_ACCOUNT_ID`
- `PIAOQUANTV_DOUYIN_COOKIE_BATCH`
- `CK_DOUYIN_RATIO`

### OSS 转存

- `CRAWLER_OSS_UPLOAD_URL`
- `CRAWLER_OSS_UPLOAD_TIMEOUT_SECONDS`

### OpenRouter / Gemini

- `OPENROUTER_BASE_URL`
- `OPENROUTER_API_KEY`
- `OPENROUTER_MODEL`
- `OPENROUTER_TIMEOUT_SECONDS`

### 阿里云百炼 / Qwen

- `ALIYUN_BAILIAN_API_KEY`
- `ALIYUN_BAILIAN_BASE_URL`
- `ALIYUN_BAILIAN_MODEL`

### Ark / 豆包 / 火山

- `ARK_API_KEY`
- `ARK_CHAT_URL`
- `ARK_CHAT_MODEL`
- `ARK_EMBEDDING_EP`
- `ARK_EMBEDDING_URL`
- `ARK_EMBEDDING_DIM`

### 分类限流

- `CLASSIFY_PROVIDER`
- `CLASSIFY_MODEL`
- `CLASSIFY_PROVIDER_MIN_INTERVAL_SECONDS`
- `CLASSIFY_QWEN_MIN_INTERVAL_SECONDS`
- `CLASSIFY_ARK_MIN_INTERVAL_SECONDS`
- `CLASSIFY_429_BACKOFF_SECONDS`
- `CLASSIFY_QWEN_429_BACKOFF_SECONDS`
- `CLASSIFY_ARK_429_BACKOFF_SECONDS`

### Query 过滤

- `QUERY_FILTER_PROVIDER`

### PG / 后续正式入库

当前 acquisition demo 主要用 SQLite，但 `Settings` 仍要求/读取 PG 配置：

- `OPEN_AIGC_PG_HOST`
- `OPEN_AIGC_PG_PORT`
- `OPEN_AIGC_PG_USER`
- `OPEN_AIGC_PG_PASSWORD`
- `OPEN_AIGC_PG_DB_NAME`
- `CK_PG_SCHEMA`

## 外部接口

### 小红书

- 搜索：`POST {AIDDIT_CRAWLER_BASE_URL}/crawler/xiao_hong_shu/keyword`
- 详情：`POST {AIDDIT_CRAWLER_BASE_URL}/crawler/xiao_hong_shu/detail`

当前 demo：

- 搜索前 10 条。
- 逐条拉详情。
- 下载图文图片到本地 `data/media/xiaohongshu/...`。

### 微信公众号

- 搜索：`POST {AIDDIT_CRAWLER_BASE_URL}/crawler/wei_xin/keyword`
- 详情：`POST {AIDDIT_CRAWLER_BASE_URL}/crawler/wei_xin/detail`

当前 demo：

- 搜索前 10 条。
- 逐条拉详情。
- 下载图文图片到本地 `data/media/weixin/...`。

### 抖音

- 搜索：`POST {PIAOQUANTV_DOUYIN_BASE_URL}/crawler/dou_yin/keyword`
- 详情：`POST {PIAOQUANTV_DOUYIN_BASE_URL}/crawler/dou_yin/detail`

当前 demo：

- 请求体带 `account_id` 和 `cookie_batch`。
- 搜索前 10 条。
- 逐条拉详情。
- 第一个 `video_url` 调 OSS 转存。
- 本地不保存抖音视频文件。

### OSS 转存

- `POST {CRAWLER_OSS_UPLOAD_URL}`
- 当前默认：`http://crawler-upload-v2.aiddit.com/crawler/oss/upload_stream`
- 请求体：
  - `src_url`
  - `src_type`: `image` 或 `video`
- 返回 `oss_object.cdn_url`。

当前 demo 只强制用于抖音视频。文档 `docs/oss-media-transfer.md` 记录过：小红书图片、公众号图片、抖音视频都实测可转存；文字正文不能直接用该接口存，需要另做 JSON/HTML/Markdown 文件上传接口。

### 多模态模型

- OpenRouter：`{OPENROUTER_BASE_URL}/chat/completions`
- Qwen/DashScope：`{ALIYUN_BAILIAN_BASE_URL}/chat/completions`
- Ark/豆包：默认 `https://ark.cn-beijing.volces.com/api/v3/chat/completions`

当前 demo 判断逻辑：

- `classify_imgtext`: 标题 + 正文前 1500 字 + 本地图片 base64 data URL。
- `classify_video`: HTTP(S) CDN video URL 直接传模型；本地 mp4 是兼容 fallback。
- Qwen / Ark / OpenRouter 按 provider 选择和可用密钥兜底。
- provider 级 limiter 和 429 backoff 在单进程内生效。

## 前端依赖

前端不是独立后端，它由 FastAPI 静态托管：

- 构建源：`acquisition/web/app`
- 构建产物：`acquisition/web/app/dist`
- 入口：`/app`
- 路由：
  - `#/`：Query Demo
  - `#/query/<encoded-query>`：单 query 详情

前端直接请求：

- `/data/queries/creation_demo.json`
- `/api/creation-search/summary`
- `/api/creation-search/query?query=...`
- `/api/filter-prompt`
- `/api/judge-prompts`
- `/data/media/...`

## 正式开发迁移建议

如果另起正式目录，不建议把当前 5.5GB `data/` 直接复制为默认输入输出。建议拆成四类可配置路径：

1. `QUERY_SOURCE_PATH`
   - 当前对应 `data/queries/creation_demo.json`。
   - 正式版可以换成数据库表、对象存储 JSON、或正式 query 生成服务。

2. `RESULT_DB_PATH`
   - 当前固定在 `acquisition.store.DB_PATH = data/app.db`。
   - 正式版应改成 env 可配置，例如 `CK_SQLITE_PATH` 或直接切 PG。

3. `MEDIA_ROOT`
   - 当前由 `CK_DATA_DIR` 控制，默认 `data`。
   - 当前媒体实际写死在 `ROOT / data / media/...` 的代码也需要改成使用 `settings.data_dir`，否则迁目录会漏。

4. `PROMPT_ROOT`
   - 当前 `core/prompts.py` 固定读项目根 `prompts/`。
   - 正式版建议显式配置 prompt 目录或把 prompt 版本入库。

优先改造点：

- `acquisition.store.DB_PATH` 改成可配置，不再硬绑定 `data/app.db`。
- `acquisition.creation_search._process_xhs/_process_weixin` 的本地媒体目录改成 `settings.data_dir`。
- `load_creation_queries` 默认路径改为参数/环境配置。
- `core.prompts.PROMPTS_DIR` 改成可配置，或在启动时固定 prompt snapshot。
- 把 crawler/OSS/model provider 封装成正式 adapter，避免 `.env` key 分散。
- 将旧链路 `scripts/run_search.py`、旧表 `queries/search_results/post_class` 与当前 `creation_*` demo 数据模型分离归档。
