Skip to content

助手 · 一句话如何变成查真实业务(翻译层 ≠ 查询层 ≠ 知识层) ​

日期: 2026-08-31 | 作者: sunxin(+ Cursor AI) 关联决策: ADR-057 · ADR-047 关联代码: ILlmPort.extractSearchIntent · ActivitySearchIntent · AssistantApplicationService.toCriteria · searchActivitiesAdvanced · VectorKnowledgeRetrievalAdapter 姊妹篇: 意图识别是怎么做到的(Prompt / JSON 细节)· RAG 向量检索新手科普 · Java 编排 vs 模型编排 定位:把「大模型是不是直接查我的库」拆开。读完应能独立画出:人话 → JSON 槽位 → 你原来的 SQL。

TL;DR ​

  • 智能助手没有让大模型连上你的 MySQL。模型不会写 SELECT * FROM activity。
  • 它只做一件 Java 字符串匹配做不好的事:把口语收成固定字段(意图 + 地点 + 时间 + 预算)。
  • 查数的还是你写过的方法,和 App 搜索框最终打到同一类查询。
  • 向量模型是另一条腿:用来在攻略/规则文档里找相似段落,不是用来搜活动表。

1. 你卡住的那句话 ​

「我想去赛里木湖,准备玩 3 天,费用 2000 以内。」

纯 Java / 字符串:识别不到用户想干嘛,也没法稳定变成「标题含赛里木湖、时间窗、价格 ≤ 2000」。 但大模型也不是直接把数据查出来,代码里肯定还有 SQL。这块糊涂。

糊涂的点其实是把三层看成了一层。

用户一句话
    │
    ├─① 翻译层(大模型)→ JSON 槽位     「听懂」
    ├─② 查询层(Java + 原有 SQL)→ 行     「查真数」
    └─③ 知识层(向量检索 + 再生成)→ 引用 「查文档」

① 和 ③ 都用到「模型」,但不是同一个模型、也不是同一件事。② 全程没有「用模型查表」。


2. 为什么纯 Java 字符串做不好 ① ​

同一需求,人会说成完全不同的字:

说法字符串规则容易挂在哪
赛里木湖 / 赛湖 / 赛里木别名表可以补,永远补不完口语
玩 3 天 / 这周末出发待三天 / 7 天内「3 天」是行程长度还是时间窗?要结合整句
2000 以内 / 别超过两千 / 预算两千块单位、中文数字
最近想去那边看看,别太贵「那边」要靠上轮会话,不是本句字面

规则引擎能覆盖演示句,一上真用户就炸。大模型适合的正是这一步:非结构化 → 结构化。

本项目里这一步的契约是 ActivitySearchIntent,大致长这样(真模型走 ILlmPort.extractSearchIntent):

json
{
  "intent": "SEARCH_ACTIVITIES",
  "destinationKeywords": ["赛里木湖"],
  "dateStart": "2026-08-31",
  "dateEnd": "2026-09-03",
  "maxPrice": 2000,
  "days": 3
}

「玩 3 天」有时会被抽成 days(做计划用),有时抽成时间窗。抽错了是意图评测的事(eval-cases.json),不是 SQL 写错。Java 接到 JSON 之后,不再猜这句话的意思。

离线/无 Key 时 MockLlmAdapter 用关键词硬判,那是用代码冒充翻译层,方便测后面的查询层;生产真模型才扛得住口语。


3. 查询层:你熟悉的 Java,一次都没换成模型 ​

AssistantApplicationService.toCriteria 做的就是把 JSON 填进早已存在的搜索条件:

槽位进哪个查询字段
destinationKeywords[0]keyword(活动搜索关键词)
dateStart / dateEndstartTimeFrom / startTimeTo
maxPricemaxCost
city / province城市 / 省

然后调用 searchActivitiesAdvanced——和 App 里筛活动是同一条业务腿,底层还是 JPA/SQL,活动 id、价格、时间都以库为准。模型看不到表,也不许编一条活动。

所以:

没有助手:用户点筛选,你的方法查库。
有助手:用户说话 → 模型填筛选表单 → 还是你的方法查库。

「一个问题写一个方法」并没有消失。消失的是「为每一种口语再写一个 Controller」。方法仍然按结构化条件来,只是表单改由模型填。

退款金额、积分是否到账,同理:将来也是「模型听懂这是查我的订单」→ Java 调既有退款查询 → 把数字说给人听。数字不来自知识库、不来自模型记忆。


4. 向量模型是 ③,不是给活动表用的 ​

Embedding(本项目通义 text-embedding-v4)干的是:把一段文字变成一串数字,意思近的段落数字也近。

用来:用户问「赛里木湖海拔多少 / 注意事项」,在 assistant_kb_doc 切好的段落里找最像的几块,喂给另一个生成模型,要求带「来源:」。找不到或分数太低就拒答。

不用来:扫描 activity 表。活动是结构化库存,用 SQL 的 keyword + 时间 + 价格 更准、可审计。把活动简介灌进向量当搜索引擎,会丢掉价格时间过滤,也更容易搜到过期局。

对照:

找活动(①→②)问攻略/规则(①→③)
模型 1意图模型:吐 JSON同一意图模型:判成 KNOWLEDGE_QA
检索无向量,SQLEmbedding 余弦 + 词面分
模型 2通常不用;Java 拼「找到 N 个」生成模型:只根据片段说话
真相来源活动表你维护的 md/知识库行

「智能」在 ① 和 ③ 的语言能力;业务正确在 ② 和知识库正文。


5. 同一句「赛里木湖」会走哪条腿 ​

用户原话intent之后
想去赛里木湖玩 3 天,2000 以内SEARCH_ACTIVITIEStoCriteria → 查活动
赛里木湖海拔多少 / 怎么去KNOWLEDGE_QA向量检索攻略;成功可挂活动卡(W6)
帮我规划赛里木湖 3 天MAKE_TRAVEL_PLANJava 先查真活动+天气,再让模型排日程(默认关)
我这次报名能退多少现在 OUT_OF_SCOPE将来应是查订单工具,不是攻略 RAG
活动取消怎么退(问政策)现在常被拒;有 kb:policy 后应 KNOWLEDGE_QA只引用条文,不算你的金额

分诊错了(把找活动判成攻略,或反过来),后面再准也是错腿。所以评测有两轨:eval-cases 管意图,rag-cases 管检索。


6. 和企业知识库的关系(电子秤例子只为建立直觉) ​

企业库难,是因为文档类型多、谁能看哪份、PDF/表格怎么切、过期、法务引用。但每一刀仍是这三层:

  1. 听懂员工问的是「查制度」还是「查我的工单」。
  2. 工单/库存/退款走 ERP、电商后台、你们自己的 Java。
  3. 制度/规格书/App 玩法说明走知识库 + 向量。

出海电子秤公司可以按部门切:产品结构文档、芯片规格书、OEM 工艺、App 玩法、平台售后政策——每一刀先 Markdown + 引用 + 拒答,不要第一天就上全公司权限中台。TourMate 助手就是其中一刀:出行活动 + 目的地/规则说明书。细则见 ADR-057。


7. 教学收获 ​

  1. 模型 = 翻译官 +(可选)文书;Java = 仓库管理员。翻译官不能进库房自己点货。
  2. 向量相似 ≠ SQL WHERE。一个比段落意思,一个比列条件。
  3. 「一个问题一个方法」还在,只是方法入口从「筛选表单」变成了「槽位 JSON」。
  4. 觉得助手神奇时,打开审计:先看 intentType,再看是活动 hitCount 还是 rag_top1_source——立刻知道走的是 ② 还是 ③。

Powered by VitePress