开篇
经过前面的一些课程,我们手上已经积累了各种LLM的API调用、向量库的建立和使用、embedding算法的意义和基本使用。
这已经为我们具备了开发一个基本的问答类RAG的开发必需要素了。下面我们会来讲一个基本问答类场景的RAG,零售中的“智能导购”场景。
智能导购
大家先不要被这个界面吓到,一旦你理解了原理后开发起来会很快,可能2周里就能开发完了,关键的还是在于原理与基础的夯实。
智能导购基本需求
为什么需要智能导购
试想一下,一般我们用传统类购物APP都是怎么样的搜索你所要的物品的?一般都有一个搜索或者是进入“分类”里不断的展开细分类别最终定位到你想要的商品,对不对?
但这实际是“反人类购物习惯”的。
为什么说这是反人类购物习惯的?购物是一种人类基本物质需求,这个需求很复杂,它可能是为了吃饱饭的刚需、也可能是为了解解嘴馋、甚至有可能为了满足一些小小的虚荣心。
所以当人们是带着一种“需求”来购物时们们有时不一定会带有明确的某个或者某一类商品的需求而来购物。或许他只是在商场逛逛或者是到处看看,看到了某一件东西命中了他心里所正在想的顾客就会付费。
所以现代零售中最有价值挖掘的除了高频的如:吃住拉撒这些刚需外还有一种消费那就叫“激情消费”
激情消费是不带有明确商品目的的,而更多的是一种心情。
试想有顾客如果在饿了吗或者是美团上用带有放大镜的关键字输入部位打入这么一行内容会出现什么:
我脚崴了
你们觉得会搜出什么呢?
这一句话其实就是用户的一种“真正需求”,它不具备确定的商品。
亦或者客户这样问:
下午15:00约了人在办公室喝茶
这要一个传统的互联网数字化的零售购物如何反馈给客户呢?
因此智能导购就是专门用来解决这一类需求的,即挖掘客户的潜在的需求以激起顾客的激情消费。
开发智能导购需要具备什么条件?
- 商品主数据,包括商品的描述、功效、产地、分类、SKUID(商品ID)、适用场景(非必须有最好)、一些这个商品本身所特有的特色描述、价格、库存;
- 每一条商品主数据对应的大张图、小张图(就是预览图和至少3张不同视角或者是场景的小图);
- 一个Embedding库、一个Mongodb、一个LLM API;
开发内容
- 商品主数据假设为Excel,一行一条(一般传统零售的采购部门都用Excel维护-别笑,真的,我见过千家超市连锁的那些龙头都没有API化到2024年年底还是Excel)可以一条条导入Embedding,或者是己有数字化基建的先进的零售商它们的商品都已经在mongodb和关系型db中了;
- 导入Embedding时,我们需要完整保留这一行数据,同时还要把这一行给向量化了;
- 而商品主数据是带着pictureId的,而pictureId所关联的pictureUrl位于Mongodb(商品库)内,而又由于embedding库Qdrant需要的是long型无重复主键,所以我们需要建立起qdrant库中的point id和mongodb中的商品skuid间的mapping关系,即一条数据从qdrant中查出来后可以通过记录中带有的skuId或者我们叫它为productId在mongodb或者是关系DB中定位到唯一的一条商品主数据;
- 相应的增删改查,而且增删改查是要带着qdrant和mongodb联动的否则就会出现搜得出数据结果商品图片或者其它进一步信息显示不出来,亦或者商品搜不出来而实际这个商品存在的问题,因此需要联动两边数据;
- 对话机制,用于搜集商户当前的提问以及上下文历史,这儿就要用上下文对话api接口了;
- 展示,把AI的响应展示成回答告诉用户同时在回答完后把商品相关的图片也给带出来一起显示给到用户看;
根据需求开发系统
有了这些需求后我们就来设计数据流。
系统数据流
商品数据入库(embedding)流程
1. 通过web界面上传Excel
做一个后台管理界面专门用于读取Excel文件。
2. 读取时的解析
在每读到一行时我们如此串联这一行里的数据:
- 商品id(set/get)
- 商品分类(set/get)
- 商品名(set/get)
- 商品描述(set/get)
- 产地(set/get)
- 商品适用场景如不为空(set/get)
- 本商品特殊属性(set/get)
- 商品价格(set/get)
把上面的内容设成一个Java里的Bean,用这个带有set/get的Bean去存一行Excel数据后再把它用ObjectMapper变成一个jsonString。
3. 存储商品数据
第1步:每读1行数据做一次embedding,存成另一个qdrant里需要的point结构,这个point结构需要以下几样东西:
- embedding的值即一个1024位的List<Float>,如果你用的是其它不同的embedding模型千万要注意这个dimension值,我们这用的是前面教程里说的bge embedding large来举例,所以它返回的vector值为1024位;
- 为这一个embedding值使用分布式不重复id产生一个long值记为pointId;
- 把pointId、embedding的值、完整的商品结构通过qdrant的http://localhost:6333/collections/aldi_collection/points {put方式}接口存入qdrant中去;
存储时是这样的body:
{
"points": [
{"id": 1, "vector": [获取到了1024位vector值], "payload": {
"content": {
"商品id":"mongodb里商品的id,如果只有excel也可以用pointId即:10001",
"商品分类":"软饮",
"商品名": "青提藤椒味的王老吉",
"商品描述": "与普通版的王老吉不一样的是,青提藤椒味的王老吉,是一款“无糖气泡凉茶”。",
"商品产地": "广州",
"商品适用场景": "夏天解渴、清凉、降温、解署",
"本商品特殊属性": "让你找到初恋的感觉",
"商品价格": 8.9
},
"productId": "sku101"
}
}
]
}
存储后在qdrant里每一条记录都是这样的:
4. 建立索引
curl --location --request PUT 'http://localhost:6333/collections/test_1/index?wait=true' \
--header 'api-key: 111111' \
--header 'Content-Type: application/json' \
--data-raw '{
"field_name": "content",
"field_schema": {
"type": "text",
"tokenizer": "multilingual",
"min_token_len": 2,
"max_token_len": 20,
"lowercase": true
}
}'
为Qdrant这个库建立一个“支持中文”的全局索引
以上流程为商品入库流程。下面来看会话流程。
会话流程(即用户询问流程)
1. 把用户的会话变成embedding向量;
见上一篇教程《AI Agent开发大全第十二课-向量数据库Qdrant使用全教程》
2.把用户的会话变成的向量去qdrant库中查询Top 10条数据
curl --location --request POST 'http://localhost:6333/collections/test_1/points/search' \
--header 'api-key: 111111' \
--header 'Content-Type: application/json' \
--header 'Host: localhost:6333' \
--header 'Connection: keep-alive' \
--data-raw '{"filter":{},"vector":[-0.002543088747188449,
-0.06530766189098358,
0.05702870339155197,
0.018917983397841454,
0.06251273304224014,
-0.03146464377641678,
-0.010266372002661228,
-0.027892475947737694,
],"with_payload":true,"top":10}'
3. 把每一条通过qdrant返回的数据中的payload和productId通过fastJson取出来
如:
4. 把用户的原始问题+向量搜索结果中的payload里的content一起发给llm
如以下格式示例。
用户的提问:有没有什么饮料可以诠释初恋的味道
实际发送给llm的内容为:
{
"用户当前的提问": "有没有什么饮料可以诠释初恋的味道",
"系统自带商品库": [
{
"productId": "sku101",
"商品内容": payload.content里的内容,
},
{
"productId": "sku102",
"商品内容": payload.content里的内容,
},
{
"productId": "sku103",
"商品内容": payload.content里的内容,
}
]
}
给大厦家一个完整的生产级实例
系统猫娘
作为一品零售导购,你总是联系用户和你提问的上下文积极为用户推荐他心愿中的商品。
systemProducts列表中的商品供你参考,
当找到符合用户的商品时请你重新以一个导购的身份自我组织话术为用户推荐,
推荐商品时有的商品有pictureUrl,有的商品没有pictureUrl这都没有关系。
对于pictureUrl中的内容你只需要原样输出它的值即可。
对于不含pictureUrl的就不用输出pictureUrl的值。如
正确的输出:你的推荐话术。\n http://xxx.xxx.xxx/xxx.jpg。
错误的输出1:你的推荐话术。\n pictureUrl: http://xxx.xxx.xxx/xxx.jpg。
发送给llm时的user这个角色中的内容
{
"用户当前提问": "给我找一下提神的饮料?"
"systemProducts": [
{
"productId": "sku101",
"product_detail": {
"商品id": "10001",
"商品分类": "软饮",
"商品名": "青提藤椒味的王老吉",
"商品描述": "与普通版的王老吉不一样的是,青提藤椒味的王老吉,是一款"无糖气泡凉茶"。",
"商品产地": "广州",
"商品适用场景": "夏天解渴、清凉、降温、解署",
"本商品特殊属性": "让你找到初恋的感觉",
"商品价格": 8.9,
"pictureUrl": "https://xxx.xxx.xxx/xxx.jpg"
}
},
{
"productId": "sku102",
"productDetail": {
"商品id": "10002",
"商品分类": "软饮",
"商品名": "蜜桃乌龙王老吉",
"商品描述": "精选优质乌龙茶,搭配天然蜜桃果汁,清爽不腻口,低糖低卡路里。",
"商品产地": "福建",
"商品适用场景": "下午茶、运动后补充、日常饮用",
"本商品特殊属性": "含茶多酚,助力健康生活",
"pictureUrl": "https://aaa.aaa.bbb/1.jpg"
}
},
{
"productId": "sku103",
"productDetail": {
"商品id": "10003",
"商品分类": "功能饮料",
"商品名": "维生素能量王老吉",
"商品描述": "富含多种维生素和牛磺酸,提供持久能量支持,助力工作学习。",
"商品产地": "上海",
"商品适用场景": "加班、熬夜、运动前",
"本商品特殊属性": "快速补充能量,提神醒脑",
"商品价格": 15.8,
"pictureUrl": "https://abc.def/gh.jpg"
}
},
{
"productId": "sku104",
"productDetail": {
"商品id": "10004",
"商品分类": "果汁",
"商品名": "NFC鲜榨橙汁",
"商品描述": "100%纯鲜榨橙汁,不添加任何防腐剂,保留水果原有营养。",
"商品产地": "四川",
"商品适用场景": "早餐、运动后补充维生素C",
"本商品特殊属性": "富含维生素C,增强免疫力",
"商品价格": 18.9,
"pictureUrl": "https://img2.baidu.com/it/u=2253477487,2124143296&fm=253&fmt=auto&app=138&f=JPEG?w=657&h=1010"
}
},
{
"productId": "sku105",
"productDetail": {
"商品id": "10005",
"商品分类": "茶饮",
"商品名": "玫瑰荔枝红茶",
"商品描述": "精选大马士革玫瑰,搭配清甜荔枝,调和红茶底韵,花香四溢。",
"商品产地": "云南",
"商品适用场景": "下午茶、约会、送礼",
"本商品特殊属性": "花香怡人,浪漫气息",
"商品价格": 16.8
}
},
{
"productId": "sku106",
"productDetail": {
"商品id": "10006",
"商品分类": "功能饮料",
"商品名": "椰子水运动饮料",
"商品描述": "天然椰子水制成,添加电解质,快速补充运动后流失的水分和矿物质。",
"商品产地": "海南",
"商品适用场景": "运动后、炎热天气、补充电解质",
"本商品特殊属性": "天然电解质,快速补水",
"商品价格": 14.9
}
},
{
"productId": "sku107",
"productDetail": {
"商品id": "10007",
"商品分类": "软饮",
"商品名": "薄荷柠檬苏打水",
"商品描述": "清新薄荷配以天然柠檬汁,无糖配方,清爽解暑。",
"商品产地": "浙江",
"商品适用场景": "餐后解腻、夏季解暑、派对调酒",
"本商品特殊属性": "零糖零卡,清新口气",
"商品价格": 9.9
}
},
{
"productId": "sku108",
"productDetail": {
"商品id": "10008",
"商品分类": "茶饮",
"商品名": "抹茶拿铁",
"商品描述": "采用日本进口抹茶粉,搭配优质奶源,醇香浓郁。",
"商品产地": "杭州",
"商品适用场景": "早餐、下午茶、提神",
"本商品特殊属性": "茶香浓郁,奶香四溢",
"商品价格": 22.0
}
},
{
"productId": "sku109",
"productDetail": {
"商品id": "10009",
"商品分类": "果汁",
"商品名": "火龙果火龙果复合果汁",
"商品描述": "红心火龙果搭配苹果汁,营养美味,自然粉红色。",
"商品产地": "海南",
"商品适用场景": "美容养颜、补充维生素、日常饮用",
"本商品特殊属性": "天然粉色,网红饮品",
"商品价格": 19.9
}
},
{
"productId": "sku110",
"productDetail": {
"商品id": "10010",
"商品分类": "功能饮料",
"商品名": "谷物燕麦奶",
"商品描述": "采用优质燕麦与多种谷物,添加钙铁锌等矿物质,营养美味。",
"商品产地": "内蒙古",
"商品适用场景": "早餐、运动后、餐间点心",
"本商品特殊属性": "植物蛋白,营养丰富",
"商品价格": 16.5
}
}
]
}
5. 得到llm的返回
把llm返回时传回来的productId去mongodb找到相应的记录然后带出pictureUrl;
6. 合并回答内容
把llm的回答显示在输出时的上方,输出完回答后把对应的pictureUrl以一行3列的形式显示在文末。
7. 记录对话上下文历史
以上就是一个完整的、基本的商品智能导购的全部过程。
今天我们不讲太多细节代码只是把数据流讲清。
因为,大家可以看到真正了解了原理后开发起来一点不难。
- 上传维护商品商web端开发可能在5天;
- 入库流程开发只需要1天即可;
- 对话流程2-3天开发工作量;
- 再2-3天测试
14天开发时间是差不多的,足以了,特别是那个Android界面,2-3天内即可完成。
好了,结束今天的教程。希望通过今天的教程帮助大家对于一个最最初步的智能体或者说一个最简单的Rag系统的开发有一个初步的认识,后面才可以逐步展开并一步步过渡到大厂级别的AI Agent是怎么开发的的全过程以及相应的代码。