前言

最近准备投简历,但发现还有一些技术点自己不熟悉。

那么这里就把没有掌握的技术点做个记录和总结。

已掌握(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开源项目

当前:

O1
大模型应用开发缺少的知识点
正常 50%
KR1
总结两个大模型项目的经验,重点是难点、流程
  • 为什么用ES的向量数据库,不用Milvus?
正常 60%
KR2
学习其他向量数据库的用法、特点
Milvus
Chorma 不着急
正常 30%
KR3
Rerank模型了解较少,需要懂理论,会用法
用法
理论
场景
正常 20%
KR-4
VLLM推理的部署
正常 50%
KR-5
LlamaFactory训练
正常 90%
KR-6
学习常见Agent框架用法、场景
  • LangChain
  • llamaindex
  • RAGFlow
正常 60%
KR-7
与知识图谱结合的场景、技术
正常 0%
KR-8
其他能力

Query理解、文档解析、召回、排序、相关性、
引用计算、提示调优、评估迭代。

正常 70%
KR-9
深度使用RAG开源项目

深度使用Dify、FlowRAG等RAG开源项目

正常 70%

一、项目总结

用ES的原因:有些检索需要向量,有些检索需要ES的分词检索。比如事项问答,需要用ES分词检索。而本地风土人情需要用向量数据库检索。

有些功能,比如类案推送、法律法规检索。类案推送中已经让大模型提取出了关键词,那么已经有了这些关键词,可以在ES检索中配置关键词匹配的数量、是否分词等条件,可以更快、更精准的匹配到内容。
法律法规的话,也是同样的已经用正则表达式处理好了法典名称、条目,用ES会更精准。

1.1 项目一 AI辅助办案平台

项目难点分析类案推送系统的设计与优化
在开发类案推送功能时,我们遇到了传统RAG方案的局限性,并最终通过结构化数据方案进行了解决。
最初,我们尝试将”类案推送”设计为传统的RAG(检索增强生成)项目:将案例数据进行向量化处理->存储到向量数据库中->用户输入的案情信息作为检索条件
然而,在测试阶段我们发现这种方法存在问题:检索结果往往相关度不高。后来发现是因为法律案例与普通文本不同,它们具有独特的结构和专业术语,简单的语义相似度无法捕捉案例间的实质联系
解决方案:
经过多次迭代,最终选择用结构化数据+ES检索:

  1. 在数据处理时,对原始数据进行结构化预处理:使用正则表达式,将非结构化案例文本转换为结构化数据,提取出案件的关键组成部分,比如将案件的各类基本信息进行提取。

  2. 在检索时:利用大模型从三个维度对案件进行提取,[争议焦点,核心事实,关键词]

    • 争议焦点(法律争议点锚定)

    • 核心事实(时间-地点-人物-行为四要素)

    • 关键词(罪名+法律要件关键词)

  3. ES进行混合检索:基于这三个维度构建精确的ES查询条件,通过对三个维度进行不同的权重分配去做检索

    混合检索策略:

    must子句保证基础要件匹配

    should子句提升语义相关性

    boost参数动态调整字段权重

  4. 处理长文本:
    很多法律有上千字的详细描述,这对于普通模型来说超出了上下文处理能力。我们采用了两项技术突破:

    • 采用大上下文窗口模型:使用支持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 关键词+语义联合优化 复杂语义与关键词混合查询

image-20250305153139884

2.2 Milvus

四、VLLM推理

GPU环境下安装较为简单,pip安装。

1
2
3
4
5
6
conda create -n myenv python=3.10 -y
conda activate myenv
pip install vllm

# 可设置modelscope的下载模型
export VLLM_USE_MODELSCOPE=True
  1. 使用脚本进行推理

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    from 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}")
  2. 使用OpenAPI接口进行推理
    vllm后可接本地或模型仓库名

    1
    2
    3
    4
    vllm 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-Instruct
    1
    2
    3
    4
    5
    6
    7
    curl 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 应用
  1. Agent

产品描述:

  • 可使用内置工具、自定义工具、编排的工作流。
  • 最多3个工具
  • 支持多工具调用

简单流程:Agent流程分为三步。

  1. 用Query让大模型的Function Call去选择工具和参数。
  2. 调用工具
  3. 大模型再次处理工具返回的结果

image-20250312160544072

稍复杂流程:LLM根据Query循环调用工具

image-20250312162122319

总的来说,支持自定义和工作流,确实也可以实现一些稍微复杂的场景。

但对于用 Dify 平台实现某个具体业务,保持怀疑。需要二次开发或借鉴其思路自己做。

  1. 文本生成应用

专注某类文本生成,利用提示词可作为一个小工具来使用。可以导入excel批量处理。

这个工具在让大模型处理较多数据时,有一些用处。比如让大模型总结100篇科学文章。

功能本身并不复杂。这里算是提供了一个可视化的操作页面

image-20250312163146931

  1. 工作流

面向自动化和批处理情景,适合高质量翻译、数据分析、内容生成、电子邮件自动化等应用程序。该类型应用无法对生成的结果进行多轮对话交互。

常见的交互路径:给出指令 → 生成内容 → 结束

节点类型丰富,有LLM路由、参数提取等一些好用的功能。

image-20250312170310722

节点内的配置也比较自由,可以添加上下文、System字段、User字段image-20250312170855713

在“探索”中,有挺复杂的工作流,有些RAG编排的思路很不错。但如果在业务中,我还是更倾向于自己写代码实现某个工作流。

  1. Chatflow

常见的交互路径:给出指令 → 生成内容 → 就内容进行多次讨论 → 重新生成结果 → 结束

同工作流,只是

十、RAG 文本切分策略

文本切分的两个基本参数:Chunk Size(块大小)、Overlap(重叠)。

模型选择与Chunk Size

根据Chunk Size的设置,需要考虑EmbeddingMax Token限制、大模型Max sequence length

  1. Chunk Size 不能超过Embedding模型Max Token
  2. 大模型对话时,需考虑 Top k * Chunk Size和大模型的 Max sequence length

Embedding Model 排行榜: https://huggingface.co/spaces/mteb/leaderboard

文本切分策略

  1. CharacterTextSplitter 字符分块
    使用固定长度字符窗口拆分文本(如每512字符)

  2. RecursivelyCharacterTextSplitter 递归分块
    基于字符列表拆分文本。按层次化分隔符(\n\n > \n > , > ? > !)递归拆分至目标长度。

    解释:其中如果每个分割的大小较大,则会递归分割,直到分至目标长度。

  3. Document Specific Splitting
    基于不同的文件类型使用不同的切分方法(如PDF、Python、Markdown)。

  4. Semantic Splitting 语义分块
    基于滑动窗口的语义切分。利用嵌入向量相似性分段。

    • 从前几个句子开始,生成一个嵌入。
    • 移动到下一组句子,并生成另一个嵌入(例如,使用滑动窗口方法)。
    • 比较嵌入以查找重大差异,这表明语义部分之间可能存在“中断点”。

    总结:先用某个方式切分,然后做滑动窗口,比如现在的窗口是1-3块,那么就将1-31-4块计算余旋相似度距离。

    我们会设置一个距离的阀值,如果满足就把4块加入到1-3中,那么现在就是1-4块为一块,继续做滑动窗口。

    如果不满足,就从这里切分,1-3块为一块,下一个窗口是4块,类推用44-5比较…

如果使用LangChain

LangChain 的分割逻辑分为两步:

  1. 按 separator 预分割:先用指定的分隔符(此处是 \n)将文本拆分为多个段落
  2. 合并至 chunk_size:将相邻段落合并,直到字符数不超过 chunk_size,但若某段落本身已超过 chunk_size,则会强制保留完整段落

ps:LangChain提供了两种计数方式:字符切分、Token切分。但根据LangChain的分割逻辑2,某段Chunk Size仍有可能超过设置的长度。

样例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 1. CharacterTextSplitter
document = "COT是一种通过引导大语言模型(LLM)生成逐步推理过程来提升复杂任务解决能力的技术。其核心在于让模型模仿人类分步骤思考的思维链,将问题分解为多个中间推理环节,最终推导出答案。\n\n我是人工智能应用工程师"

from langchain_text_splitters import CharacterTextSplitter
text_splitter = CharacterTextSplitter(
separator="",
chunk_size=20,
chunk_overlap=1,
length_function=len, # 使用内置的 len 函数来计算字符长度
is_separator_regex=False, # 是否使用正则表达式来分割文本
)
texts = text_splitter.split_text(document)
print(texts)

# 可用from_tiktoken_encoder,用token计数
from langchain_text_splitters import CharacterTextSplitter
text_splitter = CharacterTextSplitter.from_tiktoken_encoder(
separator="",
encoding_name="cl100k_base",
chunk_size=20,
chunk_overlap=1,
)
texts = text_splitter.split_text(document)

# 2. RecursivelyCharacterTextSplitter
from langchain_text_splitters import RecursiveCharacterTextSplitter

recursive_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(
chunk_size=20, # token数
separators=["\n\n","\n","。", ","], # 优先级递减
chunk_overlap=0
)
texts = recursive_splitter.split_text(document)
print(texts)

查看Embedding模型MaxToken、统计Chunk的Token数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from sentence_transformers import SentenceTransformer
import matplotlib.pyplot as plt
from transformers import AutoTokenizer
import pandas as pd

Embedding_model = 'BAAI/bge-large-zh-v1.5'
print(SentenceTransformer(Embedding_model).max_seq_length)

print(f"文本长度 {len(texts[1])}")

tokenizer = AutoTokenizer.from_pretrained(Embedding_model)
print(f"Token数 {len(tokenizer.encode(texts[1]))}")

# 展示该chunk文本中使用 Embedding_model 的Token数
def plot_chunk(chunks, embedding_model):
tokenizer = AutoTokenizer.from_pretrained(embedding_model)
length = [len(tokenizer.encode(chunk)) for chunk in chunks]
fig = pd.Series(length).hist()
plt.show()

plot_chunk(texts, Embedding_model)

语义切分

递归语义切分

直接语义切分有几个问题:每块长度不平均,单块太长会出现超出Max Token的风险。

一轮切分后,根据每块的长度判断是否需要再次切分。

ps:块数和字符数没有正比关系。比如第一块有3个,第二块有4个,但第一块仍有可能比第4块长很多。

image-20250311095728968

RAG优化:

  1. 预检索阶段:这个阶段的核心是“打好基础”,主要是对数据进行整理和预处理,比如建立索引、优化查询方式,让后续的检索更高效。
  2. 检索阶段:这个阶段的重点是“精准搜索”,通过改进嵌入模型(embedding model)和利用元数据过滤,让向量搜索的结果更准确、更相关。
  3. 后检索阶段:这个阶段的任务是“去粗取精”,从检索到的文档中剔除无关信息,压缩提示内容,再把干净、简洁的上下文交给大模型(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 流程

  1. 生成初始草稿
    • 使用 GPT-3.5-turbo 生成一个初始的草稿答案(draft)。
    • 草稿答案是基于用户输入的问题生成的,可能包含一些错误或不完整的信息。
  2. 分割草稿
    • 将草稿答案分割成多个段落(draft_paragraphs),每个段落包含一个完整的思路。
    • 分割的目的是为了逐段修正和优化答案。
  3. 逐段修正答案
    • 对每个段落,生成一个检索查询(query),用于从网络中检索相关信息。
    • 根据检索到的内容,修正当前段落的答案。
    • 重复这一过程,直到所有段落都修正完毕。
  4. 结构化输出
    • 最后,为修正后的答案添加标题和副标题,使其更具结构性。
  5. 返回结果
    • 返回初始草稿和修正后的最终答案。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
## 示例流程
假设用户输入的问题是:“介绍爱因斯坦的生平和成就。”
### 生成初始草稿:
GPT-3.5-turbo 生成一个初始答案,可能包含一些不准确的信息。
### 分割草稿:
将初始答案分割成多个段落,例如:
段落1:爱因斯坦的早期生活。
段落2:爱因斯坦的科学成就。
段落3:爱因斯坦的晚年生活。
### 逐段修正:
对每个段落生成检索查询,例如:
查询1:“爱因斯坦的早期生活”。
查询2:“爱因斯坦的科学成就”。
查询3:“爱因斯坦的晚年生活”。
根据检索结果修正每个段落的内容。
### 结构化输出:
为修正后的答案添加标题和副标题,例如:
标题:爱因斯坦的生平和成就
副标题1:早期生活
副标题2:科学成就
副标题3:晚年生活
### 返回结果:
返回初始草稿和修正后的最终答案。

## 提示词
prompt1 = """
尝试用逐步的思考来回答这个问题\指令,并使答案更具结构化。
使用 `\n\n` 来将答案分成几个段落。
直接响应指令。除非被要求,否则不要在答案中添加额外的解释或介绍。
"""

prompt2 = """
我想验证给定问题的内容准确性,特别是最后几句话。
请用相应的问题总结内容。
这个总结将被用作必应搜索引擎的查询。
查询应该简短,但需要足够具体,以确保必应能够找到相关知识或页面。
您还可以使用搜索语法,使查询足够简短和清晰,以便搜索引擎能够找到相关的语言数据。
尽量使查询与内容中的最后几句话尽可能相关。
**重要**
直接输出查询。除非被要求,否则不要在答案中添加额外的解释或介绍。
"""

prompt3 = """
我想根据在维基百科页面上学到的相关文本来修订答案。
你需要检查答案是否正确。
如果你在答案中发现了错误,请修订答案使其更好。
如果你发现有些必要的细节被忽略了,请根据相关文本添加这些细节,以使答案更加可信。
如果你发现答案是正确的且不需要添加更多细节,请直接输出原始答案。
**重要**
尽量保持修订后答案的结构(多个段落及其子标题),使其更具结构性以便理解。
`\n\n` 字符分隔段落。
直接输出修订后的答案。除非被要求,否则在修订后的答案中不要添加额外的解释或声明。
"""




总访问
发表了 19 篇文章 🔸 总计 43.8k 字