Design Doc · Symbol Search

全市场标的
名称模糊搜索

让对话调研与 ⌘K 搜索能查到所有 A 股 / 港股 / 美股——名单外的「没有的」也能模糊搜。混合方案、实时为主 + 日缓存,守住「事实来自数据源、不编、歧义不硬猜」的铁律。

目标 v0.40.0web + web-backend需 ECS rebuild

01背景与问题

现状:名称 → uid 靠一张 ~50 条的内置静态表映射死,表外一律查不到。
  • 后端 investresearch_data/resolve.pyNAME_TO_UID(cn_names 反查 + 精选 A 股 + 别名),前端 web/app.htmlNAME_UID_SEED
  • 表外标的(如「亚信科技」HK:01675)查不到 → 对话调研诚实降级、要求用代码。
  • 诉求:所有美股 / 港股 / A 股名称都能查,没有的也能模糊搜

02数据源现实 · 诚实边界

能做到什么、做不到什么,先说清楚——这是方案的地基。
市场中文名英文/拼音/代码可达源
A 股✅ 全量baostock query_all_stock 全部代码 + 中文名(code_name
港股 / 美股⚠️ 仅精选✅ 全量Yahoo Finance 搜索端点(认英文/拼音/代码,不认中文);中文名无海外可达全量免费源

Yahoo 实测 ?q=asiainfo1675.HK / 600519.SS / NVDA,带交易所 + quoteType,可映射 uid。结论:A 股中文名可全量模糊搜;港/美股英文·拼音·代码可全量搜 + 精选中文名;任意港/美股中文名不保证,代码兜底。

03方案 · 混合、实时为主 + 日缓存

后端 需 ECS rebuild

  1. search.pysearch_symbols(query)[{uid,name,market}]。先查本地精选表(秒回)→ 中文走 A 股名索引 + 精选 cn_names → 拉丁/数字走 Yahoo(EQUITY 过滤、symbol→uid)。best-effort,失败回落本地不抛;依赖注入可离线测。
  2. A 股名日缓存:进程内 TTL(24h) {code_name→uid},baostock query_all_stock 拉一次(复用 baostock provider 登录/前缀映射)。
  3. GET /search?q=&limit=:仿只读端点,进 KNOWN_PATHS
  4. /ask 兜底:实体 resolve_company 未命中 → search_symbols。一条高置信→用之(明示选中名+uid);歧义/空→留 unresolved、列候选

前端 随 CF Pages

  1. onSearchInput:backendOn 时防抖调 /search,与本地 DB.searchIndex 合并去重进下拉;点选→openCompanyByUid(uid,name)。本地即时先出、Yahoo 异步补。
  2. 对话调研零改动:走 /ask,后端加兜底后「没有的也能搜」自动生效;displayName/currentCompany(v0.39.2)已能用后端名。
用户输入本地精选A股名/Yahoouid+名

04铁律与诚实降级

  • 事实来自数据源:名称/代码来自 baostock / Yahoo(同报价),非 LLM 猜;LLM 只在 /ask 做意图路由。
  • 歧义不硬选:多条候选时不静默挑一个,列出 uid + 名让用户确认;空则诚实降级、提示用代码。
  • best-effort 不炸:Yahoo/baostock 超时失败只回本地结果,主流程不受影响。
  • 离线可测http_get / ashare_names 依赖注入,桩 Yahoo JSON + 假 A 股名表全离线。

05验证 & 交付

  • pytest -qtest_search(uid 映射 / 中文命中 / Yahoo 解析 / 网络失败回落)+ test_ask(搜索兜底 / 歧义列候选)+ 全量绿。
  • GET /search?q=asiainfo → 含 HK:01675?q=宁德SZ:300750
  • Playwright:⌘K 输「亚信」「宁德」出候选、点选进对应公司页;对话调研问「亚信科技怎么样」→ 命中 HK:01675
  • ECS rebuild 后:curl "…/search?q=asiainfo"/ask 问「平安银行怎么样」→ baostock 搜到 SZ:000001
交付:单个 feature PR → squash merge → ECS rebuild + 前端 CF Pages → 可选发版 v0.40.0(能力升级,非补丁)。