1、前言
代码全部开源,GitHub地址为: github.com/aehyok/go-o…
前端完全也能搭建, 前端完全也能搭建, 前端完全也能搭建, 本文中我使用的是后端语言golang,来调用的所有外部接口,但它们均是restful api,所以如果你使用的是其他语言,那么是完全可以替换的,包括nodejs或者直接使用前端请求都是可以实现我的功能的。后面有机会会使用vue3来添加一个页面,现在主要通过postman或者apifox来调试接口,主要为了验证逻辑想法。
接下来首先来看看embeddings到底是什么吧
1.1、 官网的介绍是这样的
可以被应用于以下几种情况
- 搜索(根据查询字符串的相关性对结果进行排名)
- 聚类(根据相似性对文本字符串进行分组)
- 推荐(具有相关文本字符串的项目被推荐)
- 异常检测(识别关联度小的异常值)
- 多样性测量(对相似性分布进行分析)
- 分类(文本串按其最相似的标签进行分类)
本文将主要学习第一种情况:搜索,根据相关性进行排名。也可以理解成搜索完一定会有结果,但是相关性有可能很低,有可能需要用户加以甄别。出来的信息可能不是用户需要的答案。
1.2、 而chatgpt是这样跟我说的
1.3、最后我的一句话理解便是:它可以将文本转换为固定长度的连续向量。
比如我下面使用的
text-embedding-ada-002
模型输出的向量维度便是1536,这个在官网是有描述的,大家可以认真看看), 同时它是可以将任意的文本转换为向量。
那么接下来我会根据我的思路把我整个的搭建流程和调试思路都展现出来,方便自己后面进行复习查阅,也方便可能需要的你。
2、架构流程图介绍
从上图可以比较清晰明了的知道大致要干什么了
- 准备测试数据:测试数据可能很多一个很大的数组,慢慢通过调用ChatGPT接口进行转换数据,然后将转换后的向量数据存储到qdrant云数据库中,相当于本地数据了。
- 根据查询返回结果:首先还是将要查询的字符串调用ChatGPT接口转换为向量数据,然后再将向量数据与向量数据库中的进行匹配相似度,匹配结束可以再通过GPT-3.5或者GPT-4的模型接口进行进一步的优化数据处理。
接下来就根据如下步骤一步步进行搭建
- Qdrant云数据库的搭建
- 准备测试数据并写入云数据库
- 进行查询并返回结果
3、Qdrant云数据库的搭建
3.1、初识Qdrant
说白一点就是为了存储我自己的测试数据,不过它的重点是存储向量数据。
来到github上看了一下:github.com/qdrant/qdra… , 有点牛逼 而且是Rust写的。那就来试试玩玩呗。
3.2、创建云数据库
通过github可以直接到云官网: Vector Search Database | Qdrant Cloud
可以看到能免费创建一个免费套餐,拿来做个测试还是非常方便的。
针对图示的配置,可以永久免费使用,所以基本的测试是没问题了,可以好好的愉快玩耍。
找到左侧菜单Clusters
然后右侧点击 Create
,输入一个cluster
名称(是不是可以翻译为集群名称??)。创建后等待一会儿在进行初始化。
点击上面的api-key
或者左侧 Access
都可以创建访问云数据库的链接和api-key。
记得复制好哟,这个跟ChatGPT生成的API-Key一样,只能看到一次,所以要保存好。
3.3、通过curl 接口访问
Swagger UI (qdrant.tech) 这个就是官方提供给我们的Swagger。可视化 RESTful Web Api
我是通过这个主要看接口以及接口参数,主要还是通过postman或者apifox等工具来测试接口,swagger这里好像没有配置api-key的地方?
ok可以看到我之前创建的 collect
还在,其实这个时候本来是要创建一个collect
集合(在关系型数据库中可以叫做table表)。
4、写入测试数据
4.1、准备测试数据
注意:以上数据来源于ChatGPT,仅供参考和测试使用
然而我想要的数据结构是json数组的,那么继续使用ChatGPT进行装逼
可以发现准备这一组测试数据,有一点不费吹灰之力的感觉,真是太爽了。
这里就是准备的json数组,总共13条简单的记录而已,主要是为了看一下效果
[ { "title": "感冒", "text": "感冒是一种由病毒引起的呼吸道感染。典型症状包括喉咙痛、流鼻涕、咳嗽、打喷嚏、头痛和发热。" }, { "title": "流感", "text": "流感(Influenza)是一种由流感病毒引起的呼吸道感染。症状与感冒相似,但通常更严重,包括高热、寒战、喉咙痛、咳嗽、鼻塞、肌肉痛和乏力。" }, { "title": "肠胃炎", "text": "肠胃炎是胃和肠道的炎症,通常由病毒、细菌或寄生虫感染引起。症状包括腹泻、呕吐、腹痛、恶心、发热和脱水。" }, { "title": "常见皮肤病", "text": "如湿疹、皮炎、脓疱疮、疱疹等。症状可能包括红肿、瘙痒、干燥、脱皮和疼痛。" }, { "title": "头痛", "text": "头痛有许多原因,如压力、紧张、缺水、缺乏睡眠等。头痛可能表现为钝痛、搏动痛、集中在头的某个部位等。" }, { "title": "过敏", "text": "过敏是免疫系统对外来物质(过敏原)的异常反应。症状包括打喷嚏、流鼻涕、鼻塞、喉咙痛、眼睛痒、红肿和喘息。" }, { "title": "高血压", "text": "高血压是血压持续升高的病状。许多高血压患者没有明显症状,但可能会引发头痛、眩晕、心悸和呼吸困难。" }, { "title": "糖尿病", "text": "糖尿病是一种由于胰岛素分泌不足或细胞对胰岛素反应不良导致的血糖水平过高的疾病。症状包括频繁的小便、口渴、饥饿、疲劳、视力模糊、感染和伤口愈合缓慢。" }, { "title": "哮喘", "text": "哮喘是一种慢性呼吸道炎症疾病,表现为气道对刺激物的过度反应。症状包括喘息、呼吸困难、胸闷和咳嗽。" }, { "title": "背痛", "text": "背痛可能是由于肌肉拉伤、韧带损伤、关节炎、椎间盘问题等原因引起的。症状包括持续或间歇性的背部疼痛、僵硬和肌肉痉挛。" }, { "title": "关节炎", "text": "关节炎是关节炎症的一个通用术语,可能是由于多种原因引起的,如磨损性关节炎、类风湿性关节炎等。症状包括关节疼痛、肿胀、僵硬和活动受限。" }, { "title": "痔疮", "text": "痔疮是肛门或直肠血管的炎症或肿胀。症状包括肛门疼痛、瘙痒、肿胀、出血和可能的肛门突出物。" }, { "title": "眼疾", "text": "如干眼症、结膜炎和近视等。症状可能包括眼睛干燥、瘙痒、红肿、分泌物和视力模糊。" }]
4.2、go代码将测试数据转换为向量数据
这里暂时就要用到ChatGPT的接口了
看官网接口请求主要就两个参数,一个就是model
选择模型,我这里使用的是text-embedding-ada-002
,另外一个input
就是我们要转换的数据字符串了,好了直接上代码看看
func GetEmbeddings(ctx *gin.Context) dto.ResponseResult {
// 配置日志
data, _ := ctx.GetRawData()
var parameters map[string]interface{}
// 包装成json 数据
_ = json.Unmarshal(data, ¶meters)
input := parameters["input"].(string)
// n := m["n"].(int)
// size := m["size"].(string)
var response = GetEmbeddingApi(input)
var obj map[string]interface{}
if err := json.Unmarshal(response, &obj); err != nil {
panic(err)
}
fmt.Println("Body:", obj)
return dto.SetResponseData(obj)
}
func GetEmbeddingApi(input string) []byte {
// 定义请求参数
embeddingModel := EmbeddingModel{
Model: "text-embedding-ada-002",
Input: input,
}
// 定义请求地址
url := utils.OpenAIUrl + `/v1/embeddings`
// 将请求参数转换为json格式
bytes, err := json.Marshal(embeddingModel)
if err != nil {
fmt.Println("Error:", err)
// return dto.SetResponseFailure("调用openai发生错误")
}
// 定义请求
req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)
req.SetRequestURI(url)
req.Header.SetMethod("POST")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+utils.OpenAIAuthToken)
req.SetBody(bytes)
// 定义响应
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)
if err := fasthttp.Do(req, resp); err != nil {
fmt.Println("Error:", err)
// return dto.SetResponseFailure("调用openai发生错误")
}
fmt.Println("Status:", resp.StatusCode())
return resp.Body()
}
我在代码里添加了详细的注释,对照代码看一下应该还是比较好理解的。
这里其实就是通过go语言调用restful 接口
https://api.openai.com/v1/embeddings
请求,因为下面查询的时候还需要将查询字符串转换为向量数据,所以我单独进行了封装可以在两个地方调用
4.3、循环上述方法将预准备的json测试数据全部转换为向量数据
// 解析请求参数
var jsonData []map[string]string
if err := c.Bind(&jsonData); err != nil {
return dto.SetResponseFailure("error")
}
if len(jsonData) == 0 {
return dto.SetResponseFailure("json is empty")
}
// 数据向量化
points := make([]Point, 0)
for _, v := range jsonData {
// 获取文本内容
input := v["text"]
// 获取文本内容的向量
response := GetEmbeddingApi(input)
fmt.Println(response, "response----response")
var embeddingResponse EmbeddingResponse
json.Unmarshal(response, &embeddingResponse)
points = append(points, Point{
ID: uuid.New().String(),
Payload: v,
Vector: embeddingResponse.Data[0].Embedding,
})
}
4.4、将上面准备好的向量数据数组全部写入向量数据库
现在向量数据通过ChatGPT接口转换好了,现在就需要将向量数据写入到Qdrant云数据库中。 下面主要是调用了CreatePoints方法,同样可以看看
pr := PointRequest{
Points: points,
}
//存储
err := CreatePoints(utils.QdrantCollectName, pr)
if err != nil {
// common.Logger.Error(err.Error())
// c.JSON(http.StatusOK, common.Error(err.Error()))
// return
return dto.SetResponseFailure("数据上传发生错误")
}
// c.JSON(http.StatusOK, common.Success(nil))
return dto.SetResponseSuccess("数据上传成功")
其实相对来说我前面也写过的,就是来调用Restful api写入到云数据库。
func CreatePoints(collectionName string, pointRequest PointRequest) (err error) {
response := &CommonResponse{}
var reqBytes []byte
reqBytes, err = json.Marshal(pointRequest)
if err != nil {
return
}
body, err := middleware.Send(http.MethodPut, collectionApi+"/"+collectionName+pointsApi+"?wait=true", reqBytes)
if err != nil {
return
}
err = json.Unmarshal(body, &response)
if err != nil {
return
}
if response.Result == nil {
return errors.New(response.Status.(map[string]interface{})["error"].(string))
}
return
}
这里其实就是通过go语言调用restful 接口
https://ui.qdrant.tech/#/points/upsert_points
(点击查看具体的接口详情) 请求
现在测试数据有了,向量数据库也有了,上一小节将测试数据转换为了向量数据,这里上面刚刚又写好了向量数据写入云数据库的接口。那么写入数据的基本完成了。
通过运行接口来调试一下吧
5、开始查询数据
准备好查询数据,先通过##3.2
将字符串转换为向量数据(也就是为什么进行封装上面的方法的原因),然后通过向量数据去查询云数据库,去查询相似度了
5.1、将查询字符串转换为向量数据
那么这里就先准备一下查询云数据库的接口
var message ChatMeMessage
if err := c.Bind(&message); err != nil {
// c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
// return
}
response := GetEmbeddingApi(message.Text)
json.Unmarshal(response, &response)
fmt.Println(response, "response----response")
var embeddingResponse EmbeddingResponse
json.Unmarshal(response, &embeddingResponse)
这里其实就是通过go语言调用restful 接口
https://api.openai.com/v1/embeddings
请求
这里注意一下,我理解的正常的话只要云数据库有数据,就会返回数据的,无非相似度低一些而已。
5.2、根据向量来查询匹配相关性高的前三条记录
准备查询参数数据,然后到Qdrant云数据库进行查询
params := make(map[string]interface{})
params["exact"] = false
params["hnsw_ef"] = 128
sr := PointSearchRequest{
Params: params,
Vector: embeddingResponse.Data[0].Embedding,
Limit: 3,
WithPayload: true,
}
//查询相似的
res, err := SearchPoints(utils.QdrantCollectName, sr)
if err != nil {
// common.Logger.Error(err.Error())
// c.JSON(http.StatusOK, common.Error(err.Error()))
// return
}
这里其实就是通过go语言调用restful接口
https://ui.qdrant.tech/#/points/search_points
(点击查看具体的接口详情) 请求
5.3、通过chatGPT对查询的相关性数据进行优化
其实上面查询出来数据列出来就完事了,但是我上面也说了相关性的问题,那么这里我们可以通过ChatGPT对于查询返回的数据加工一下。
//组装本地数据
localData := ""
for i, v := range res {
re := v.Payload.(map[string]interface{})
localData += "\n"
localData += strconv.Itoa(i + 1)
localData += "."
localData += re["title"].(string)
localData += ":"
localData += re["text"].(string)
}
messages := make([]ChatCompletionMessage, 0)
q := "使用以下段落来回答问题,如果段落内容与\"" + message.Text + "\"不相关就通过查询返回信息。"
q += localData
system := ChatCompletionMessage{
Role: "system",
Content: "你是一个医院问诊客服机器人",
}
user := ChatCompletionMessage{
Role: "user",
Content: q,
}
messages = append(messages, system)
messages = append(messages, user)
var chatResponse = GetChatCompletionsApi(messages)
var obj map[string]interface{}
if err := json.Unmarshal(chatResponse, &obj); err != nil {
panic(err)
}
fmt.Println("Body:", obj)
// 最后我通过一个方法进行统一返回参数处理
return dto.SetResponseData(obj)
5.4、调试效果
这是我通过GPT-3.5模型的接口调试其返回结果并不是非常理想。但是如果通过GPT-4.0就完全可以达到我想要的结果了
当然了我这里演示的数据较少,仅用作演示效果,但是这种简单的问答模式加上最后GPT来润色优化有点好用了。而且还可以进行优化,比如问的问题是本地没有的,通过GPT回答后,可以进行操作,将当前问答回写到本地云数据库,这样下次再有类似的问答,就可以直接使用本地的数据了,这里仅仅提供一点点的我思考的逻辑,不一定是对的。
6、总结
这个对于我来说,理解起来还是蛮费劲的,主要是一开始没有抓到重点,其实现在把思路捋顺了,从应用的层面来看也就那么回事,当然了目前我的理解还是比较浅显的,有待机会进一步深入摸索,大数据训练模型。是不是可以考虑训练一个自己的AI虚拟人。当然还有另外一个Fine-Tunes 跟Embedding有没有关系,我得继续研究研究了,感觉上还是非常好玩的。
再次声明本文所有代码都已上传github github.com/aehyok/go-o…
如何零基础入门 / 学习AI大模型?
大模型时代,火爆出圈的LLM大模型让程序员们开始重新评估自己的本领。 “AI会取代那些行业?
”“谁的饭碗又将不保了?
”等问题热议不断。
不如成为「掌握AI工具的技术人」
,毕竟AI时代,谁先尝试,谁就能占得先机!
想正式转到一些新兴的 AI 行业,不仅需要系统的学习AI大模型。同时也要跟已有的技能结合,辅助编程提效,或上手实操应用,增加自己的职场竞争力。
但是LLM相关的内容很多,现在网上的老课程老教材关于LLM又太少。所以现在小白入门就只能靠自学,学习成本和门槛很高
那么我作为一名热心肠的互联网老兵,我意识到有很多经验和知识值得分享给大家,希望可以帮助到更多学习大模型的人!至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费
】
👉 福利来袭
优快云大礼包:《2025最全AI大模型学习资源包》免费分享,安全可点 👈
全套AGI大模型学习大纲+路线
AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!
640套AI大模型报告合集
这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。
👉学会后的收获:👈
• 基于大模型全栈工程实现(前端、后端、产品经理、设计、数据分析等),通过这门课可获得不同能力;
• 能够利用大模型解决相关实际项目需求: 大数据时代,越来越多的企业和机构需要处理海量数据,利用大模型技术可以更好地处理这些数据,提高数据分析和决策的准确性。因此,掌握大模型应用开发技能,可以让程序员更好地应对实际项目需求;
• 基于大模型和企业数据AI应用开发,实现大模型理论、掌握GPU算力、硬件、LangChain开发框架和项目实战技能, 学会Fine-tuning垂直训练大模型(数据准备、数据蒸馏、大模型部署)一站式掌握;
• 能够完成时下热门大模型垂直领域模型训练能力,提高程序员的编码能力: 大模型应用开发需要掌握机器学习算法、深度学习框架等技术,这些技术的掌握可以提高程序员的编码能力和分析能力,让程序员更加熟练地编写高质量的代码。
👉 福利来袭
优快云大礼包:《2025最全AI大模型学习资源包》免费分享,安全可点 👈
这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费
】
作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。