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

5.7 KiB
Raw Blame History

步骤 3 · 基础 AI 搜索 / Step 3 · Basic AI Search

可独立执行 / Self-contained. 完整背景见设计文档 llm-integration-design.md §5;跨步骤约定见 implementation-plan.md前置 / Prerequisite 步骤 2 已合入(app/llm.py::expand_queryapp_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/SubItemnamenote 做大小写不敏感 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_enabledis_configured(cfg)
  • 本轮检索范围=name + noteimage_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_queryCI 不联网):
    • 扩展词驱动命中:原词 LIKE 搜不到、扩展后能搜到。
    • 已有结果时点 AI 仍可用,且结果集被扩大(含原结果)。
    • 按钮可见性随 ai_search_enabled + is_configured() 门控。
    • 调用失败 → 回退普通结果、页面不报错。

涉及文件 / Files

app/main.py、(可选 app/search.py)、app/templates/search/index.htmltests/


验收 / 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。