用户输入 → 抽取检索字段 → 调用期数 API 返回卡片;字段不足或非目标意图时,引导至「全部」Tab 带关键词搜索。
flowchart TD
A[用户输入 query] --> B{AI智搜 开关开?}
B -->|关| ALL1[全部 Tab 搜索 keyword]
B -->|开| C[Dify 节点:意图 + 抽字段 JSON]
C --> D{intent = course_enroll?}
D -->|否| F[小Q:暂不支持此类智搜]
F --> G[展示标签:去全部看看]
G --> H[点击 → 全部 Tab + keyword]
D -->|是| E{字段是否够查期数?}
E -->|够| I[BFF 调期数 API]
I --> J[SSE 导语 + 期数 cards]
E -->|不够| K[小Q:请补充城市/课名等]
K --> L{仍无法补齐?}
L -->|是| G
L -->|否| I
说明:
course_enroll 是一个大意图,下面再分子类型(查课名 / 查城市期数 / 查导师 / 续聊报读),但出口只有一个:期数卡片。sessionId 多轮时,模型读 history 补全「南宁站还有吗」这类省略句。由产品与研发共同维护字段表。模型从用户输入中填充字段,BFF 据此拼装 HTTP 请求。
| 字段名 | 含义 | 用户可能说法 | 是否必填 | 查期数 API 参数 |
|---|---|---|---|---|
course_id / course_name |
哪门课 | 智慧父母一阶、高EQ领袖营、工作坊 | 与 city / instructor 至少一项 | course_id 或 q=课名 |
city |
哪个城市/站 | 广州、南宁站、深圳 | 同上 | city=广州 |
instructor_name |
哪位导师 | 总导师、6Q张三、授课导师 | 同上 | instructor= |
phase_no |
第几期 | 第533期、533期 | 否 | phase_no=533 |
time_window_days |
时间范围 | 最近、一个月内、近期开课 | 否(默认 30) | start_within_days=30 |
keyword |
原文关键词 | 整句保留 | 是(用于去全部) | 跳转全部 Tab 时用 |
满足任一即可发起期数 API:
course_id 或能匹配到标准课名的 course_namecity + 句子里出现「开课 / 期数 / 课程 / 报读」类动作词instructor_name + 动作词history 里已有 course/city,当前句是「还有吗 / 南宁站 / 报读」等续聊以上都不满足 → 不查 API → 走「去全部看看」。
重要区分:
course_id / city / instructor_id。| 词典类型 | 示例条目 | 用途 |
|---|---|---|
| 课程标准名 + 别名 | 「智慧父母一阶」← 一阶、父母课、WFM L1 | course_name → course_id |
| 城市 / 站点 | 「南宁站」→ city=南宁 | 归一化 city |
| 导师 | 「总导师」→ 业务约定是否指某人或仅标签 | instructor_name |
| 动作触发词(不进库也行,写 Prompt) | 报读、报名、开课、期数、还有名额吗 | 判 intent=course_enroll |
维护方式:后台配置表或 Excel 同步至 Dify 知识库;或由 BFF 先做实体链接再调用 LLM(推荐词典 + 抽槽结合)。
工作流包含两个 LLM 节点:① 意图识别与字段抽取(JSON)② 流式导语(禁止输出具体期号)。
你是 6Q APP 的搜索助手,只做一件事:判断用户是否在问「课程 / 报读 / 期数 / 导师」,并从句子中抽取检索字段。
## 输出要求
- 只输出 JSON,不要其他文字。
- 字段说明见下方 schema。
- 用户句子和 history 里已有的 course/city 要合并;「还有吗」「南宁站」等续聊要继承上文。
- 不要把具体期数、价格、名额写进 JSON(你没有实时数据)。
## 意图
- course_enroll:与报读、课程、期数、导师、开课、报名相关。
- other:商城、音频、视频、文章、盲盒、闲聊,或与课程无关的泛搜。
## 实体归一化(对照知识库/词典)
- 课名:映射到 knowledge 中的标准 course_name;匹配不到则 course_name 填用户原话,course_id 填 null。
- 城市:「南宁站」→ city: "南宁"
- 导师:填 instructor_name;匹配不到填 null。
## 何时标记 ready_for_api
- true:至少能确定 course_name/course_id、或 city+开课意图、或 instructor+开课意图,或 history 已具备可续聊条件。
- false:intent 是 other,或只有「6Q」「课程」等过于模糊的词。
## 输入
session_id: {{session_id}}
query: {{query}}
history: {{history}}
{
"intent": "course_enroll | other",
"ready_for_api": true,
"keyword": "用户原 query,用于跳转全部 Tab",
"slots": {
"course_id": null,
"course_name": "智慧父母一阶",
"city": "广州",
"instructor_name": null,
"phase_no": null,
"time_window_days": 30
},
"missing": [],
"confidence": 0.9
}
missing:列出缺失字段,如 ["city"];APP 可提示补充信息,仍无法补齐则展示「去全部看看」。
根据已返回的 API 摘要写 1~2 句导语。 - 只能使用 API 里的课名、城市、条数。 - 禁止列举具体期号、日期、名额(这些在 cards 里展示)。 - 语气简短,6Q 品牌口吻。
sequenceDiagram
participant APP
participant BFF
participant Dify
participant Dict as 实体词典
participant API as 期数API
APP->>BFF: query + sessionId + history
BFF->>Dify: 节点① 意图+slots
Dify-->>BFF: JSON
alt intent=other 或 ready=false
BFF-->>APP: 小Q文案 + redirect 全部(keyword)
else ready=true
BFF->>Dict: 课名/导师 → id 补全
BFF->>API: GET /sessions?...
API-->>BFF: sessions[]
BFF->>Dify: 节点② 流式导语
BFF-->>APP: SSE text + event:cards
end
GET /api/sessions?course_id=xxx&city=广州&start_within_days=30&status=open GET /api/sessions?instructor=张三&start_within_days=30 GET /api/courses/search?q=智慧父母一阶 → 再查 sessions
| 场景 | AI 表现 | 用户点击标签后 |
|---|---|---|
| intent = other(盲盒、音频、恋爱咨询等) | 小Q:暂不支持此类智能检索 | 全部 Tab,搜索框 = keyword |
| intent = course_enroll 但 ready=false(只说「6Q」「课程」) | 小Q:请说明课名或城市;或去全部看看 | 同上 |
| API 返回 0 条 | 小Q:暂无匹配期数,引导至全部搜索 | 同上 |
// BFF 返回给 APP(非 SSE 或 event:redirect)
{
"tab": "all",
"keyword": "6Q潮玩盲盒",
"message": "小Q暂不支持其他类型的智能检索哦",
"action": { "label": "去全部看看", "type": "open_all_search" }
}
| 用户说法 | 应抽字段 |
|---|---|
| 智慧父母一阶 | course_name |
| 广州最近有哪些课在开课 | city + time_window_days |
| 总导师的课程有哪些 | instructor_name(或业务规则映射) |
| 南宁站还有吗(有 history) | 继承 course + city=南宁 |
| 6Q潮玩盲盒 | intent=other → 全部 |
config/intent-slots-v5.jsonconfig/entity-dictionary.example.jsondocs/dify-prompt-node1-v5.txtAPP 侧需实现:AI 开关、期数卡片展示、小Q 提示及「去全部看看」带 keyword 跳转。