Files
2026-moving-helper/docs/design/step-3-ai-search.md
T
tliu93 c42cc2ddb6 docs: add LLM integration design and three-step implementation plan
Add docs/: a bilingual repository brief, plus docs/design/ with the high-level design (Alembic migration foundation, LLM integration, basic AI search) and a self-contained per-step implementation plan (step 1-3).
2026-06-01 13:10:59 +02:00

87 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 步骤 3 · 基础 AI 搜索 / Step 3 · Basic AI Search
> **可独立执行 / Self-contained.** 完整背景见设计文档 [`llm-integration-design.md`](./llm-integration-design.md) §5;跨步骤约定见 [`implementation-plan.md`](./implementation-plan.md)。
> **前置 / Prerequisite** [步骤 2](./step-2-llm-integration.md) 已合入(`app/llm.py::expand_query`、`app_settings` 配置、`ai_search_enabled` 开关均已就绪)。Step 2 merged.
> **产出 / Output** 一个可独立合入的 PR**不改 schema**。
---
## 目标 / Goal
在搜索页提供一个**常驻**的「AI 智能搜索」动作:点击后用查询词扩展增强搜索结果。**不以"零结果"为前提**——即便普通搜索已出结果,用户不满意时也能用。
A **persistent** "AI search" action on the search page that broadens results via query-term expansion. **Not gated on zero results** — usable even when normal results exist.
---
## 必要背景 / Essential Context
- 现有搜索:`app/main.py::_build_search_results(db, query)``Box`/`Item`/`SubItem``name``note` 做大小写不敏感 `LIKE`,返回结果列表;路由 `GET /search`(函数 `search_page`,参数 `q`)渲染 `app/templates/search/index.html`
Existing search: `_build_search_results(db, query)` does case-insensitive `LIKE` over name/note; route `GET /search` renders `search/index.html`.
- 步骤 2 已提供:`app/llm.py::expand_query(cfg, query) -> list[str]`、配置读取 `get_app_settings(db)`、开关 `ai_search_enabled``is_configured(cfg)`
- 本轮检索范围=`name` + `note``image_description` 本轮不存在,属未来图片分析轮次)。
Search scope = `name` + `note` (no `image_description` this round).
### 关键决策 / Key Decisions
- **常驻、不依赖零结果。** 普通 `LIKE` 照常先出结果;AI 动作始终可用(开启且已配置时)。
Persistent and not gated on zero results.
- **流程:** 触发 AI → `expand_query` 得到"原词 + 一批近义/相关词" → 用这组词对 `name`/`note` 做 OR `LIKE` 重搜 → 展示,并用横幅标注「AI 帮你扩展了:…」。**只把查询词发出去**,不外泄物品清单。
Trigger → expand → OR-`LIKE` over the original + expanded terms → render with a banner of the expansion. Only the query leaves.
- **可替换的检索 seam。** 把 AI 检索抽成一个函数(如 `ai_search(db, query) -> (expanded_terms, results)`),本轮内部=查询词扩展 + 本地 `LIKE`;**未来换成向量嵌入 + 相似度时,路由与模板不变**。
Wrap AI retrieval behind a swappable seam so embeddings can replace it later without touching route/template.
- **优雅降级。** AI 关闭/未配置 → 不显示按钮(或提示去 `/settings`);调用失败 → 友好提示 + 回退普通结果。
---
## 任务 / Tasks
- [ ] 实现检索 seam:在 `app/main.py`(或抽一个小搜索模块 `app/search.py`)加 `ai_search(db, query) -> (expanded_terms, results)`
-`expand_query(cfg, query)` 得到扩展词;
- 用「原词 + 扩展词」对 `name`/`note` 做 OR `LIKE`**复用现有 `_build_search_results` 的匹配逻辑**,避免重复实现),去重。
- 注意:现有 `_build_search_results(db, query)` 只接收单个查询词;建议把它泛化为接收一组关键词(对多个词做 OR),让 AI 搜索与普通搜索共用同一套匹配逻辑,避免分叉。
Note: `_build_search_results` currently takes a single query — generalize it to accept multiple keywords so AI and normal search share one matching path.
- [ ] 扩展 `GET /search`:支持 `ai=1` 触发位(如 `GET /search?q=锅&ai=1`),保持单页、可收藏、SSR 友好。
- `ai=1` 且 AI 开启且 `is_configured()` → 走 `ai_search`,把 `expanded_terms` 传给模板做横幅。
- 否则走原有普通搜索。
- [ ] 模板 `app/templates/search/index.html`
- 常驻「AI 智能搜索」按钮,链接到 `?q=<当前词>&ai=1`
- AI 关闭/未配置时隐藏按钮(或显示去 `/settings` 的提示);
- `ai=1` 结果页顶部显示横幅「AI 帮你扩展了:term1、term2…」。
- [ ] 降级:`ai_search` 内部调用失败时捕获,渲染友好提示并回退到普通 `LIKE` 结果。
- [ ] 测试(mock `expand_query`CI 不联网):
- [ ] 扩展词驱动命中:原词 `LIKE` 搜不到、扩展后能搜到。
- [ ] 已有结果时点 AI 仍可用,且结果集被扩大(含原结果)。
- [ ] 按钮可见性随 `ai_search_enabled` + `is_configured()` 门控。
- [ ] 调用失败 → 回退普通结果、页面不报错。
---
## 涉及文件 / Files
`app/main.py`、(可选 `app/search.py`)、`app/templates/search/index.html``tests/`
---
## 验收 / Acceptance
- 搜索页在 AI 开启时**始终**可见「AI 智能搜索」;点击后结果按扩展词扩大,并标注扩展词。
- 未配置/失败时优雅降级,普通搜索完全不受影响。
- 检索逻辑收敛在 `ai_search` seam,未来可整体替换为向量语义搜索而不动路由/模板。
---
## 风险与缓解 / Risks & Mitigations
- **扩展词过多/过散 → 结果噪声大。** 缓解:限制扩展词数量;横幅透明展示扩展词,让用户理解结果来源。
Too many/too-loose terms → cap the expansion count and show it transparently.
- **AI 调用慢/失败拖累搜索页。** 缓解:仅在 `ai=1` 时才调用(普通搜索零开销);设超时;失败回退。
Slow/failed calls → only call on `ai=1`, set a timeout, fall back.
---
## 相关约定 / Conventions(详见 implementation-plan.md
- 不主动 push/commit,除非业主要求。
- CI 不联网(mock `expand_query`)。
- 实现与设计若有偏差 → 回写设计文档 §5 与仓库简报 §15。