前言
最近准备投简历,但发现还有一些技术点自己不熟悉。
那么这里就把没有掌握的技术点做个记录和总结。
已掌握(2025.3.5):
- 基础:Python、Django、Flask等
- 大模型运用方式方法,有自己的一些技巧
- RAG概念、Agent概念、智能体概念
- 了解大模型在一些方面的强项和弱项
- 熟练使用cursor等AI编程工具,突破技术瓶颈
- 实操过大模型训练、微调方法,知道何时需要上微调
- 熟悉Linux操作,熟练掌握大模型、小模型部署流程
- 大模型如何利用结构化、非结构化数据
未掌握(2025.3.5):
- 之前做的两个大模型项目的难点、流程,没有总结。面试时会有风险。️
- 热门向量数据库用法、特点。只熟悉ES的向量数据库用法,不会Milvus。
- 召回优化、多路?
- Rerank模型了解较少,需要懂理论,会用法。
- VLLM推理
- LlamaFactory训练
- Agent框架不熟悉
- RAG、智能体、Agent 的场景用法没有统一的思路,要总结
- 和知识图谱结合
- 没有深度使用Dify、FlowRAG等RAG开源项目
当前:
- 为什么用ES的向量数据库,不用Milvus?
- LangChain
- llamaindex
- RAGFlow
Query理解、文档解析、召回、排序、相关性、
引用计算、提示调优、评估迭代。
深度使用Dify、FlowRAG等RAG开源项目
一、项目总结
用ES的原因:有些检索需要向量,有些检索需要ES的分词检索。比如事项问答,需要用ES分词检索。而本地风土人情需要用向量数据库检索。
有些功能,比如类案推送、法律法规检索。类案推送中已经让大模型提取出了关键词,那么已经有了这些关键词,可以在ES检索中配置关键词匹配的数量、是否分词等条件,可以更快、更精准的匹配到内容。
法律法规的话,也是同样的已经用正则表达式处理好了法典名称、条目,用ES会更精准。
1.1 项目一 AI辅助办案平台
项目难点分析:类案推送系统的设计与优化
在开发类案推送功能时,我们遇到了传统RAG方案的局限性,并最终通过结构化数据方案进行了解决。
最初,我们尝试将”类案推送”设计为传统的RAG(检索增强生成)项目:将案例数据进行向量化处理->存储到向量数据库中->用户输入的案情信息作为检索条件
然而,在测试阶段我们发现这种方法存在问题:检索结果往往相关度不高。后来发现是因为法律案例与普通文本不同,它们具有独特的结构和专业术语,简单的语义相似度无法捕捉案例间的实质联系。
解决方案:
经过多次迭代,最终选择用结构化数据+ES检索:
在数据处理时,对原始数据进行结构化预处理:使用正则表达式,将非结构化案例文本转换为结构化数据,提取出案件的关键组成部分,比如将案件的各类基本信息进行提取。
在检索时:利用大模型从三个维度对案件进行提取,[争议焦点,核心事实,关键词]
争议焦点(法律争议点锚定)
核心事实(时间-地点-人物-行为四要素)
关键词(罪名+法律要件关键词)
ES进行混合检索:基于这三个维度构建精确的ES查询条件,通过对三个维度进行不同的权重分配去做检索
混合检索策略:
must子句保证基础要件匹配
should子句提升语义相关性
boost参数动态调整字段权重
处理长文本:
很多法律有上千字的详细描述,这对于普通模型来说超出了上下文处理能力。我们采用了两项技术突破:- 采用大上下文窗口模型:使用支持128K上下文窗口的大语言模型,确保能够处理完整案例
- 设计Prompt:精心设计了比较两个案例相似点和差异点的专业Prompt,引导模型关注法律要素而非表面文字
- 其他的优化思路
先对长案例进行分段总结,获取核心要点后再进行对比,分段总结时可以并行处理,提高效率。
功能
- 类案推送:根据案情信息,提取[争议焦点,核心事实,关键词],
总体流程
类案推送
数据建模
法律法规
文书生成
1.2 项目二 政务问答助手
二、向量数据库
2.1 向量数据库对比
Metadata filter:支持对元数据进行过滤。元数据是附加在向量上的一些信息,键值对的形式。
BM25(Best Matching 25):是一种用于信息检索的排序算法,文档长度归一化和词频饱和机制,更精准地评估文档与搜索查询的相关性。
- 文档长度归一化
- 作用:避免长文档因包含更多词汇而获得不合理的高分。
- 机制:根据文档长度动态调整词频权重,短文档中匹配关键词的得分更高。
示例:搜索“人工智能”,一篇100字的短文比1000字的长文更易因关键词集中而排名靠前。
- 词频饱和(Term Frequency Saturation)
- 作用:限制高频词对得分的过度影响。
- 机制:使用对数函数对词频进行压缩,使词频达到一定阈值后重要性增幅趋缓。
示例:某文档中“算法”出现100次,BM25会将其重要性压缩至接近出现10次时的水平。
- 稀疏嵌入表示
- 文档长度归一化
Sparse(稀疏检索)
Hybrid(混合检索)
方法 | 核心逻辑 | 优势场景 | |
---|---|---|---|
BM25 | 关键词统计匹配 | 短文本、精确关键词搜索 | |
Sparse | 高维稀疏向量(词频驱动) | 可解释性要求高的结构化检索 | |
Hybrid | 关键词+语义联合优化 | 复杂语义与关键词混合查询 |
2.2 Milvus
四、VLLM推理
GPU环境下安装较为简单,pip安装。
1 | conda create -n myenv python=3.10 -y |
使用脚本进行推理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20from vllm import LLM, SamplingParams
prompts = [
"Hello, my name is",
"The president of the United States is",
"The capital of France is",
"The future of AI is",
]
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
llm = LLM(model="/mnt/workspace/.cache/modelscope/models/Qwen/Qwen2.5-1.5B-Instruct")
outputs = llm.generate(prompts, sampling_params)
# Print the outputs.
# 打印输出
for output in outputs:
prompt = output.prompt
generated_text = output.outputs[0].text
print(f"Prompt: {prompt!r}, Generated text: {generated_text!r}")使用OpenAPI接口进行推理
vllm后可接本地或模型仓库名1
2
3
4vllm serve /mnt/workspace/.cache/modelscope/models/Qwen/Qwen2.5-1.5B-Instruct
或
vllm serve /mnt/workspace/.cache/modelscope/models/Qwen/Qwen2.5-1.5B-Instruct \
--served-model-name Qwen2.5-1.5B-Instruct1
2
3
4
5
6
7curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen2.5-1.5B-Instruct",
"prompt": "法国的首都是",
"max_tokens": 50
}'
五、LlamaFactory训练
总结到了这里
九、开源平台技术洞察
1. Dify 技术洞察
1.1 知识库
导入方式
- 本地文件,单文件15M限制
- 其他:Notion、Firecrawl、Jina Reader。后者是在线爬虫平台,可将html等页面数据转为规范等MD等格式,便于大模型读取。
分段模式
- 通用模式:按照自定义的规则将内容拆分为独立的分段。可用正则表达式。
- 父子模式:如一篇文章是父,其句子为子。
- 父为较大的文本单位(如段落),用于提供信息
- 子为较小的文本单位(如句子),用于精确检索
索引模式
索引方法:
高质量:即用Embedding模型将分段文本转为向量。Q&A:对分段文本进行总结,生成Q&A 匹配对,Dify采用的是「Q to Q」(问题匹配问题)策略。
当用户提问时,系统会找出与之最相似的问题,然后返回对应的分段作为答案。
问题生成的逻辑:
Step 1:了解并总结这段文本的主要内容。
Step 2:这段文本提到了哪些关键信息或概念。
Step 3:可分解或结合多个信息与概念。
Step 4:将这些关键信息与概念生成 20 个问题与答案。
经济:每个区块内使用 10 个关键词进行检索,使用倒排索引。
检索方式:
- 高质量:向量检索、全文检索与混合检索设置。混合检索中可以设置两种检索方式的结果权重。
总的来说,效果可能不能保证的好。一些分段策略、索引策略,感觉也一般。尤其QA模式,感觉有很大的问题,有的文件直接没有生成或者生成的效果一般。用他的切分策略,比较固定,可能不如自己去做切分的处理,再导入。
1.2 应用
- Agent
产品描述:
- 可使用内置工具、自定义工具、编排的工作流。
- 最多3个工具
- 支持多工具调用
简单流程:Agent流程分为三步。
- 用Query让大模型的Function Call去选择工具和参数。
- 调用工具
- 大模型再次处理工具返回的结果
稍复杂流程:LLM根据Query循环调用工具
总的来说,支持自定义和工作流,确实也可以实现一些稍微复杂的场景。
但对于用 Dify 平台实现某个具体业务,保持怀疑。需要二次开发或借鉴其思路自己做。
- 文本生成应用
专注某类文本生成,利用提示词可作为一个小工具来使用。可以导入excel批量处理。
这个工具在让大模型处理较多数据时,有一些用处。比如让大模型总结100篇科学文章。
功能本身并不复杂。这里算是提供了一个可视化的操作页面
- 工作流
面向自动化和批处理情景,适合高质量翻译、数据分析、内容生成、电子邮件自动化等应用程序。该类型应用无法对生成的结果进行多轮对话交互。
常见的交互路径:给出指令 → 生成内容 → 结束
节点类型丰富,有LLM路由、参数提取等一些好用的功能。
节点内的配置也比较自由,可以添加上下文、System字段、User字段
在“探索”中,有挺复杂的工作流,有些RAG编排的思路很不错。但如果在业务中,我还是更倾向于自己写代码实现某个工作流。
- Chatflow
常见的交互路径:给出指令 → 生成内容 → 就内容进行多次讨论 → 重新生成结果 → 结束
同工作流,只是
十、RAG 文本切分策略
文本切分的两个基本参数:Chunk Size(块大小)、Overlap(重叠)。
模型选择与Chunk Size
根据Chunk Size
的设置,需要考虑Embedding
的Max Token
限制、大模型Max sequence length
。
Chunk Size
不能超过Embedding
模型Max Token
- 大模型对话时,需考虑
Top k * Chunk Size
和大模型的Max sequence length
。
Embedding Model 排行榜: https://huggingface.co/spaces/mteb/leaderboard
文本切分策略
CharacterTextSplitter 字符分块
使用固定长度字符窗口拆分文本(如每512字符)RecursivelyCharacterTextSplitter 递归分块
基于字符列表拆分文本。按层次化分隔符(\n\n > \n > , > ? > !)递归拆分至目标长度。解释:其中如果每个分割的大小较大,则会递归分割,直到分至目标长度。
Document Specific Splitting
基于不同的文件类型使用不同的切分方法(如PDF、Python、Markdown)。Semantic Splitting 语义分块
基于滑动窗口的语义切分。利用嵌入向量相似性分段。- 从前几个句子开始,生成一个嵌入。
- 移动到下一组句子,并生成另一个嵌入(例如,使用滑动窗口方法)。
- 比较嵌入以查找重大差异,这表明语义部分之间可能存在“中断点”。
总结:先用某个方式切分,然后做滑动窗口,比如现在的窗口是
1-3
块,那么就将1-3
和1-4
块计算余旋相似度距离。我们会设置一个距离的阀值,如果满足就把
4
块加入到1-3
中,那么现在就是1-4
块为一块,继续做滑动窗口。如果不满足,就从这里切分,
1-3
块为一块,下一个窗口是4
块,类推用4
和4-5
比较…
如果使用LangChain
LangChain 的分割逻辑分为两步:
- 按 separator 预分割:先用指定的分隔符(此处是 \n)将文本拆分为多个段落
- 合并至 chunk_size:将相邻段落合并,直到字符数不超过 chunk_size,但若某段落本身已超过 chunk_size,则会强制保留完整段落
ps:LangChain提供了两种计数方式:字符切分、Token切分。但根据LangChain的分割逻辑2,某段Chunk Size仍有可能超过设置的长度。
样例代码
1 | # 1. CharacterTextSplitter |
查看Embedding模型MaxToken、统计Chunk的Token数量
1 | from sentence_transformers import SentenceTransformer |
语义切分
递归语义切分
直接语义切分有几个问题:每块长度不平均,单块太长会出现超出Max Token的风险。
一轮切分后,根据每块的长度判断是否需要再次切分。
ps:块数和字符数没有正比关系。比如第一块有3个,第二块有4个,但第一块仍有可能比第4块长很多。
RAG优化:
- 预检索阶段:这个阶段的核心是“打好基础”,主要是对数据进行整理和预处理,比如建立索引、优化查询方式,让后续的检索更高效。
- 检索阶段:这个阶段的重点是“精准搜索”,通过改进嵌入模型(embedding model)和利用元数据过滤,让向量搜索的结果更准确、更相关。
- 后检索阶段:这个阶段的任务是“去粗取精”,从检索到的文档中剔除无关信息,压缩提示内容,再把干净、简洁的上下文交给大模型(LLM),让它生成高质量的答案。
1. 预检索阶段
数据清洗、删掉那些无关紧要的细节。
给数据加点标签(元数据),检索的时候有效过滤。
父子:用一小段文本来计算嵌入,在元数据里保留更宽的上下文窗口。小块的文本能提高检索的准确性,而更大的上下文则能给LLM(大语言模型)提供更多的背景信息。
用整篇文本来计算嵌入,可能会引入太多噪音,或者文本里可能包含多个主题,这样一来嵌入的整体语义表示就会变差。
查询优化
- 查询路由:数据检索可从向量库、数据库、网络等途径获取数据。 所以,在检索前、使用提示词之前,用LLM针对Query做判断。相当于编程的 if 语句
- 查询重写:重新组织问题的表述,来更好地匹配我们索引里的信息。
- 释义:把用户的查询换个说法,但意思不变
- 同义词替换:把一些不太常用的词换成更常见的同义词,这样搜索范围就更广了
- 子查询:如果查询比较长,我们可以把它拆成几个更短、更聚焦的小查询。
- 假设文档嵌入(HyDE):LLM对用户问题做一个假设性回答,这个回答会和原始查询一起,输入到检索阶段。
- 查询扩展:通过添加一些相关的术语或概念,来丰富问题的维度
- 转结构化:把非结构化的查询“翻译”成结构化的查询,LLM 从Query中识别出关键的实体、事件和关系。作为元数据的过滤条件。
⚠️ 需要注意的是,数据索引和查询优化的预检索技术,都高度依赖于数据的类型、结构和来源。所以,跟其他数据处理流程一样,没有一种方法是万能的。每个用例都有它的特殊性和潜在的坑。优化预检索 RAG 层是一个实验性很强的工作。因此,多尝试几种方法(比如上面提到的这些),反复试验,找到最适合的方案,才是关键。
2. 检索阶段
1. 混合搜索
结合向量搜索和关键字搜索的混合方法。
- 关键字搜索擅长找到包含特定关键词的文档。如果你的任务需要高精度,并且检索结果必须包含精确的关键词匹配,那么这种方法非常有用。
- 向量搜索虽然功能强大,但在精确匹配上可能稍显不足,不过它更擅长捕捉语义上的相似性。
通过把这两种方法结合起来,可以同时利用关键词匹配和语义相似性的优势。
会用一个参数(比如叫 alpha)来控制两者的权重。
具体来说,算法会分别进行两种独立的搜索,然后将结果标准化并合并。
2. 过滤向量搜索
利用元数据索引来筛选出符合特定关键词的文档。
它和混合搜索的区别在于,只需要用向量索引检索一次数据,然后在向量搜索之前或之后,通过过滤步骤来缩小搜索范围。
3. 后检索阶段
检索后优化主要是对已经检索到的数据进行处理,减少一些数据对 LLM 的干扰。如上下文窗口有限或数据有噪声,
RAT
来源:https://www.cnblogs.com/quincyqiang/p/18652768
检索增强思维 (RAT) 是一种简单但有效的提示方法,它将思路链 (CoT) 提示与检索增强生成 (RAG) 相结合,以处理长窗口推理和生成问题。
RAT 流程
- 生成初始草稿:
- 使用 GPT-3.5-turbo 生成一个初始的草稿答案(
draft
)。 - 草稿答案是基于用户输入的问题生成的,可能包含一些错误或不完整的信息。
- 使用 GPT-3.5-turbo 生成一个初始的草稿答案(
- 分割草稿:
- 将草稿答案分割成多个段落(
draft_paragraphs
),每个段落包含一个完整的思路。 - 分割的目的是为了逐段修正和优化答案。
- 将草稿答案分割成多个段落(
- 逐段修正答案:
- 对每个段落,生成一个检索查询(
query
),用于从网络中检索相关信息。 - 根据检索到的内容,修正当前段落的答案。
- 重复这一过程,直到所有段落都修正完毕。
- 对每个段落,生成一个检索查询(
- 结构化输出:
- 最后,为修正后的答案添加标题和副标题,使其更具结构性。
- 返回结果:
- 返回初始草稿和修正后的最终答案。
1 | ## 示例流程 |