# AI Use Case Daily Scout — Milestone 1 实录

> 完成日期：2026-02-27
> 状态：✅ 端到端跑通，生成首份 Obsidian 晨报

---

## 一、我们造了什么

**问题**：AI 应用场景内容极度噪声——Chatbot 包装和 Demo 铺天盖地，真正有价值的（结合本地数据、优化工作流的）场景淹没其中，靠人工筛选成本太高。

**方案**：一个每天早上自动运行的"雷达"脚本，全程无人值守：

```
HackerNews ──┐
              ├──► 抓取原始帖子 ──► 三步 LLM 过滤 ──► SQLite 存储 ──► Obsidian 晨报
Reddit     ──┘
```

整个链路不依赖任何 Agent 框架（无 LangChain / CrewAI），只用原始 Claude API 调用 + 标准 Python。

---

## 二、项目结构

```
ai_usecases_explorer/
├── src/ai_usecases_explorer/
│   ├── collectors/
│   │   ├── base.py           # RawItem 数据类 + BaseCollector 抽象基类
│   │   ├── hackernews.py     # HN Algolia API（search_by_date 端点）
│   │   └── reddit.py         # Reddit JSON API（带 403 容错）
│   ├── models/
│   │   └── usecase.py        # Pydantic 数据模型：UseCase、ScenarioType、Novelty
│   ├── processors/
│   │   ├── filter.py         # Step 1：价值过滤器
│   │   ├── classifier.py     # Step 2：场景分类器
│   │   ├── deduplicator.py   # Step 3：新颖性检测
│   │   └── utils.py          # parse_llm_json()：剥离 markdown 代码块
│   ├── storage/
│   │   └── database.py       # SQLite CRUD（save / exists / get_by_scenario）
│   ├── reporters/
│   │   └── obsidian.py       # Markdown 晨报生成器
│   ├── settings.py           # pydantic-settings，读取 .env
│   └── main.py               # Scout 编排器 + CLI 入口
├── tests/                    # 74 个单元测试，全部用 mock，不依赖外网
├── data/usecases.db          # SQLite（.gitignore 忽略）
├── pyproject.toml
├── .env.example
└── Makefile
```

---

## 三、核心设计决策

### 3.1 三步独立 LLM 调用

每条原始帖子经过三次 Claude 调用，每次只做一件事：

```
Step 1 — ValueFilter
  输入: 帖子标题 + 正文（截 3000 字）
  问题: "这是真实的 AI 应用场景吗？"
  输出: {is_real_value, has_local_data, has_workflow_opt, reason}

Step 2 — Classifier（仅对通过 Step 1 的帖子）
  问题: "属于哪个场景类型？用了哪些工具？评分多少？"
  输出: {scenario_type, tools_used, value_score, summary}

Step 3 — Deduplicator（对比同类型已有记录）
  问题: "这是新场景、已知场景的新案例、还是重复内容？"
  输出: {novelty, similar_to_ids, novelty_reason}
```

失败就丢弃，不传播错误。

### 3.2 数据模型

```python
class UseCase(BaseModel):
    id: str                    # sha256(source_url)[:12]
    scenario_type: ScenarioType  # 枚举：本地数据集成 / 代码生成 / 工作流自动化…
    novelty: Novelty           # new / similar / repeat
    value_score: float         # 0.0–1.0，Field(ge=0.0, le=1.0)
    tools_used: list[str]
    has_local_data: bool
    has_workflow_opt: bool
    summary: str               # Claude 生成的中文摘要
    # …完整字段见 models/usecase.py
```

### 3.3 容错：实测踩坑

| 问题 | 根因 | 修复 |
|------|------|------|
| HN 返回 0 条 | Algolia 不支持 `"quoted" OR` 布尔语法 | 改用 `search_by_date` 端点 + 不加引号的 `claude OR mcp OR llm` |
| Reddit 全部 403 | Reddit 已封锁服务器端非浏览器请求 | 每个 subreddit 单独 try/except，失败就 log + 跳过 |
| `JSONDecodeError` | Haiku 会把 JSON 包在 ` ```json ``` ` 里，即使 prompt 说"不要" | `parse_llm_json()` 用正则剥离 markdown 代码块再解析 |

---

## 四、首次运行结果

**2026-02-27 首报**（5 条 HN 帖子，Reddit 全部 403）

```
今日扫描: HN(5) + Reddit(0) → 过滤后: 3 条有价值 → 新场景: 3 个
```

三条全部命中"新场景"，摘录两条：

> **工作流自动化 · BrowserOS**
> 开源隐私优先 AI 浏览器，代理循环在客户端本地运行，支持文件系统访问和 shell 命令执行……

> **工作流自动化 · RowboatX**
> 开源 CLI，创建和运行后台智能体自动化日常任务，通过文件系统管理状态、MCP 服务器集成工具……

晨报写入：`/root/vault/obsidian_vault/obsidian/Documents/obsidian/auto_report/2026-02-27.md`

---

## 五、怎么使用

### 5.1 首次配置

```bash
cd /root/projects/ai_usecases_explorer
cp .env.example .env
# 编辑 .env，填入：
#   ANTHROPIC_API_KEY=sk-ant-...
#   ANTHROPIC_BASE_URL=https://...   （如果用代理）
source venv/bin/activate
pip install -e ".[dev]"
```

### 5.2 日常运行

```bash
# 试跑：不写数据库，只打印结果
make dry-run
# 等价于：
python -m ai_usecases_explorer.main --dry-run

# 正式运行：写入 SQLite + 生成 Obsidian 报告
make run
# 等价于：
python -m ai_usecases_explorer.main

# 指定日期（补跑历史）
python -m ai_usecases_explorer.main --date 2026-02-26
```

### 5.3 设置每日定时运行

```bash
crontab -e
# 加入以下行（每天早 7:00 运行，日志写 /var/log/）：
0 7 * * * /root/projects/ai_usecases_explorer/venv/bin/python -m ai_usecases_explorer.main >> /var/log/ai_usecases_scout.log 2>&1
```

### 5.4 查看报告

报告位置：`/root/vault/obsidian_vault/obsidian/Documents/obsidian/auto_report/YYYY-MM-DD.md`

在 Obsidian 中打开 `auto_report/` 文件夹即可按日期浏览。

### 5.5 可调参数（.env）

| 变量 | 默认值 | 说明 |
|------|--------|------|
| `ANTHROPIC_API_KEY` | 必填 | Claude API Key |
| `ANTHROPIC_BASE_URL` | （空）| 代理地址，如 `https://anyrouter.top` |
| `CLAUDE_MODEL` | `claude-haiku-4-5-20251001` | 改成 sonnet 质量更高但更贵 |
| `HN_MIN_POINTS` | `10` | HN 帖子最低分数门槛 |
| `REDDIT_MIN_SCORE` | `20` | Reddit 帖子最低分数门槛 |
| `DB_PATH` | `data/usecases.db` | SQLite 文件位置 |
| `OBSIDIAN_REPORT_DIR` | `/root/vault/obsidian_vault/obsidian/Documents/obsidian/auto_report` | 晨报输出目录 |

---

## 六、怎么测试

### 6.1 全量单元测试

```bash
source venv/bin/activate
pytest tests/ -v
# 预期：74 passed
```

所有测试都用 mock，不发真实网络请求，不需要 API Key，1 秒内跑完。

### 6.2 分模块测试

```bash
pytest tests/test_models.py -v      # Pydantic 模型（18 个）
pytest tests/test_storage.py -v     # SQLite CRUD（15 个）
pytest tests/test_collectors.py -v  # HN + Reddit 抓取（12 个）
pytest tests/test_processors.py -v  # LLM 三步流水线（11 个）
pytest tests/test_reporters.py -v   # Markdown 报告生成（12 个）
pytest tests/test_main.py -v        # 编排器集成（6 个）
```

### 6.3 关键 mock 模式

LLM 调用通过 patch `_call_llm` 方法来 mock，例如：

```python
with patch("ai_usecases_explorer.processors.filter.ValueFilter._call_llm",
           return_value={"is_real_value": True, "reason": "uses local data",
                         "has_local_data": True, "has_workflow_opt": False}):
    result = ValueFilter(client=MagicMock()).run(item)
assert result["is_real_value"] is True
```

HTTP 请求用 `pytest-httpx` mock：

```python
def test_filters_by_min_points(self, httpx_mock: HTTPXMock) -> None:
    httpx_mock.add_response(json=HN_RESPONSE)
    items = HackerNewsCollector(min_points=10).fetch()
    assert len(items) == 1  # 只有 45 分那条通过，3 分那条被过滤
```

### 6.4 代码质量检查

```bash
ruff check src/ tests/   # 风格 + 类型 lint（0 错误）
```

---

## 七、已知限制与 Phase 2 计划

### 当前限制

- **Reddit 被封**：Reddit 在 2023 年 API 收费政策后，公共 JSON 端点已对服务器 IP 全面封锁。目前 4 个 subreddit 均返回 403，只能跳过。
- **HN 数据量偏少**：`search_by_date` 按关键词匹配，单日通常 20-50 条。可以降低 `HN_MIN_POINTS` 或扩展关键词。
- **Haiku 的 JSON 不稳定**：即使 prompt 要求"不加 markdown 代码块"，Haiku 仍会偶尔包裹。已通过 `parse_llm_json()` 容错。

### Phase 2 候选项

| 优先级 | 方向 | 说明 |
|--------|------|------|
| 高 | Reddit OAuth API | 用官方 OAuth 流程替换公共 JSON |
| 高 | 扩大 HN 关键词 | 加入 `cursor / copilot / vibe coding` 等词 |
| 中 | GitHub Trending | 抓取 AI 相关仓库 README |
| 低 | Twitter/X | 待 API 方案确定 |
| 低 | 相似度去重优化 | 目前 deduplicator 依赖 LLM 判断，可引入向量相似度 |

---

## 八、技术栈一览

| 层次 | 技术 |
|------|------|
| 语言 | Python 3.11 |
| 数据模型 | Pydantic v2（`StrEnum`、`Field(ge/le)` 约束） |
| 配置 | pydantic-settings（读 `.env`） |
| HTTP 客户端 | httpx（同步） |
| LLM 调用 | Anthropic Python SDK（直接调用，无框架） |
| 存储 | SQLite（标准库 `sqlite3`） |
| 终端输出 | Rich（进度条 + 彩色日志） |
| 测试 | pytest + pytest-httpx（HTTP mock） |
| Lint | ruff |
