type
Post
status
Published
date
Sep 23, 2024
slug
summary
以图片检索为例子,介绍qanything的检索逻辑(问答逻辑)
tags
category
技术分享
icon
password
前言:
在 Qanything 2.0源码解析系列4: 图片解析逻辑 文章中,介绍了针对一张图片内容是如何处理最后embedding并存入milvus中的。
本文介绍Qanything的问答接口,以图片为例,详细阐述一下Qanything的检索逻辑。
RAG问答其实还是涉及到蛮多流程的,主要包含一下内容
1. 检索 (retrieve)
2. 重排 (reranker)图片的话内容较少,其实这一步就不需要了。
3. 大模型问答 (llm answer)
📝 前情提要

对这样一张图片:
产生了两个父doc,并存入了mysql数据库中,两个父doc如下:
产生了4个子doc,并存入了向量数据库中。4个doc如下:
query的问题如下:
🐵 问答接口
local_doc_chat方法定义在handler文件下
常用请求参数如下:
🤗 检索逻辑
- 从mysql File表中查询到这些kb_id对应的status为green的file_id,为green表示该文件的解析逻辑正确处理,doc也都存入了milvus库中。如果有效文件的长度<1,说明没有知识库,设置kb_ids为空,相当于进入和大模型的纯聊天模式了。
源码在handler.py的第718行。
- 核心方法是 handler.py第736行(非流式)的这个方法:
- 使用bce-embedding对query:【自如的转租政策是什么?】进行embedding。使用milvus的search方法从库中搜索前top-k个向量,默认topk=30,所以上面存储的4个doc都会被检索出来。
- 子doc的处理
- docs根据page_content内容去重,这里就两个,没有重复的。
- 组装prompt, prompt定义在model_config.py文件中
- 处理source_documents,得到source_documents、retrieval_documents。
- 将e步骤得到的source_documents和d步骤的模版拼起来。
- 将f步骤的prompt提问大模型得到结果。
这个方法内部执行了很多模块,大体如下:
将子doc的doc_id放入ids列表中,4个子doc得到两个doc_id,然后从mysql Documents表中根据doc_id得到父doc的内容。两个doc_id对应两个父doc。这一步根据4个子doc得到了两个父doc。
1)替换掉{{system}}和{{instructions}}
c步骤得到的两个父doc称之为source_documents。
1) 处理source_documents:
prompt的默认长度是4096,这里计算一下两个source_documents的token长度+prompt模版的长度+如果有历史问答加上历史+额外的符号的。
如果超过了4096,就会有source_documents被丢弃,从相似度最高的开始遍历,丢弃相似度低的。因为是图片内容,包含的文字有限。这里source_documents只有两个,都加上也不会超过4096,返回的retrieval_documents和source_documents是一样的,limited_token_nums=3061。
2)聚合文档, 处理retrieval_documents,1)步骤的内部方法
retrieval_documents包含两个文档,这两个文档的file_id是一样的,都是一张图片的,根据前面的介绍已知哈。第一个文档是相似度最高的,aggregate_documents这个方法的逻辑是返回相似度最高的这个doc_id对应的file_id的完整文档,会从数据库中查的。也就是说对于两张图片或者pdf之类的,会返回第一个完整文档,超过4096了会截取。逻辑会比较复杂一点,但是对于图片来说,理解起来就很简单了,返回的new_docs就是两个retrieval_documents拼接在一起的doc,也就是整个ocr内容作为一个整体的doc。然后将source_documents赋值new_docs。
3)根据2)知道,方法1)得到的source_documents是整个图片内容是一个整体的doc, retrieval_documents是两个doc。
得到的prompt如下:
将answer_result做一些处理,就可以返回给用户【自如的转租政策是什么?】的回答了。
📎 总结
图片的问答逻辑相比pdf、doc还是简单很多的,没有太多复杂的逻辑,基本上就是拿到整个ocr的识别结果喂给大模型去处理。

思考:
一般而言,知识库中很少是以很多张图片组成的。图片文档更合理的逻辑是:用户上传了一张图片或两张图片,然后针对这一两张图片问个问题,相当于是图片理解类任务。比如一张机构和用户的聊天记录,让大模型根据这个图片写一段营销话术。
因此我认为完全不需要图片ocr完了之后还要split父doc,还要split子doc,还要存向量数据库。因为最终检索出来的内容还是整个ocr识别的结果。不如用户上传一张图片之后直接对其进行ocr存mysql数据库,然后根据用户问题,从数据库拿到ocr结果组装prompt提问大模型。当然Qanything提供了一套更通用的方法。如果你的业务本身就是说图解画类型的,完全可以采用ocr+大模型的方式,省去了embedding和retriever的流程,整体的速度也会快很多。
📎 参考文章
- Qanything源码
有问题,欢迎您在底部评论区留言,一起交流~