♥复试第十五天
项目:RAG
一种将信息检索系统与大语言模型的生成能力相结合的技术框架。
基础流程:索引、检索和生成。
索引:目的是把杂乱的非结构化文档,处理成计算机便于快速查找的格式。有基于关键词的索引和基于语义的索引。
检索:不同的索引结构对应不同的检索方式?》《 mmmmmmmmmmm,可以根据关键词和根据语义进行检索。
2. 两种索引和检索的方式:
基于关键词匹配(无法理解语义)和基于语义向量化(可以理解语义)
文本预加载->文本分割(固定长度分割,引入一定的重叠区域)
#建立document对象
for response_ref in response_refs:
if len(response_ref) > 0:
documents.append(Document(text=response_ref))
#文本分割
node_parser = SentenceSplitter(chunk_size=self.chunk_size, chunk_overlap=self.chunk_overlap) #SentenceSplitter 的作用:是一个文本分割器,负责把长文本切成适合检索的小块。
nodes = node_parser.get_nodes_from_documents(documents)
2.1基于关键词
最常用的算法:BM25,求每一个文件(D)和关键词(Q)之间的相关性。
利用技术:倒排索引(记录每个词出现在每个文档里的频率),词频饱和机制(防止无意义的词重复导致文件得分高),长度归一化机制(避免文章长度太长导致的得分高)
bm25_retriever = BM25Retriever.from_defaults(
nodes=nodes,
similarity_top_k=similarity_top_k
)
2.2基于词块向量的索引和检索(🐖:将文本转换成高维向量,语义相近的向量在向量空间里距离较近,可以找到意思最相关的文本)
步骤:nodes->embedding(存储在字典里,根据HNSW 构建索引结构)->retrieve(利用余弦相似度找到最相近的向量)->选择top-k输出
embedding模型的训练:1.预训练 2. 模型微调
模型微调:指句子提取向量进行对比学习训练,目的是让语义相近的向量挨的更近。
微调的方法:将句子映射到向量,计算不同向量间相似度,用softmax转变成概率分布,构建Infonce损失函数,行损失和列损失,最终损失是两者的平均值。
# 相似度矩阵 S (3x3)
h1+ h2+ h3+
h1 [ sim11 sim12 sim13 ]
h2 [ sim21 sim22 sim23 ]
h3 [ sim31 sim32 sim33 ]
# 行方向:对每行做 softmax
行1: softmax([sim11, sim12, sim13]) → 希望 sim11 最大
行2: softmax([sim21, sim22, sim23]) → 希望 sim22 最大
行3: softmax([sim31, sim32, sim33]) → 希望 sim33 最大
# 列方向:对每列做 softmax
列1: softmax([sim11, sim21, sim31]) → 希望 sim11 最大
列2: softmax([sim12, sim22, sim32]) → 希望 sim22 最大
列3: softmax([sim13, sim23, sim33]) → 希望 sim33 最大
检索过程:
#构建embedding模型
embedding_model = HuggingFaceEmbedding(
model_name=embedding_model_path,
device=device
)
#构建向量索引
index = VectorStoreIndex(nodes, embed_model=self.embedding_model)
#构建索引器
vector_retriever = index.as_retriever(similarity_top_k=self.top_k)
#执行索引
vector_results = vector_retriever.retrieve(query)
2.3.去重合并
将bm25生成的vector生成的结果进行合并和去重。
3.生成
检索阶段完成,已经得到query相关的参考文献,进入生成阶段,即利用大语言模型LLM结合参考文献生成最终答案。包含两个重要部分:prompt和LLM推理
C笔试2024年真题
二:编程题
#include <stdio.h>
#include <math.h>
int main() {
int num[8] = { 0 };
int n, count = 0;
scanf("%d", &n);
int i = 0;
int data = 0;
while ((n /10) != 0) {
num[i] =n%10;
n = n / 10;
i++;
count++;
}
num[i] = n;
count++;
for (int m = 0; m < count; m++) {
if (num[m] % 2 != 0) {
printf("%d", num[m]);
}
}
return 0;
}
2. 编写程序,输入的字符串中只包含字母和*,将字符串中除了首位部
int earase_L(char str[]) {
int left = 0;
int i = 0;
while (str[i] != '\0') {
if (str[i] <= 'Z' && str[i]>='A') left++;
else {
if (left > 0) {
str[i] = 0;
}
}
i++;
}
return 0;
}
int earase_R(char str[]) {
int right = 0;
int i = strlen(str);
for(i;i>0;i--){
if (str[i] < 'Z' && str[i]>'A') right++;
else {
if (right > 0) {
str[i] = 0;
}
}
}
return 0;
}
int main() {
char str[20];
char strl[20];
char strr[20];
gets(str);
int len = strlen(str);
strcpy(strl, str);
strcpy(strr, str);
earase_L(strl);
earase_R(strr);
int i;
for ( i = 0; i < len; i++) {
if (strl[i] != '0') printf("%c",strl[i]);
}
int j = len-1;
while (strr[j] == '*') {
printf("%c",strr[j]);
j--;
}
return 0;
}
3.编写程序,将一个单链表(不带头结点)进行冒泡排序
typedef struct node {
int data;
struct node* next;
}Linklist;
int Len(Linklist *list) {
Linklist* p=list;
int count = 0;
while (p != NULL) {
p = p->next;
count++;
}
return count;
}
int Swap(Linklist* p, Linklist* q) {
int tempt = 0;
tempt = p->data;
p->data = q->data;
q->data = tempt;
return 0;
}
void Sort(Linklist* list) {
Linklist* p=list;
Linklist* q = p->next;
int len = Len(list);
for (int i = 0; i < len-1; i++) {
for (int j = 0; j < len - i - 1; j++) {
if ((p->data) >(q->data)) {
Swap(p, q);
}
p = p->next;
q = q->next;
}
p = list;
q = p->next;
}
}
一:简答题:
1. 请简述数组和结构体的区别及联系
2.解释下面四条语句考察运算符优先级:
()【】. -> 后置++,后置--(优先级最高)
从内到外,从右到左,优先级高的先运算。
int *p[4]; #大小为4的指针型数组,指针指向int型元素
int (*p)[4]; #一个指针指向大小为4的Int型数组
int *p(); #函数返回类型是Int型指针,可以是一个数组或者一个链表
int (*p)(); #p是一个指针,指向返回值是Int型的函数,即函数指针
3.static作用
全局变量和普通的全局变量有什么区别?static 局部变量和普通的局部变量有什么区别?
4. 下面程序的功能是将字符串 src 逆序输出,请找出下面的错误。
#include<string.h> #缺少include<stdlib.h>
void main(){
char *src = "hello,world";
char *dest, *d, *s;
int len,i;
len = strlen(src);
dest = (char *)malloc(len); #改:dest=(char*)malloc((len+1)*sizeof(char));
s=&src[len]; #改:s=&src[len-1]
d=dest;
while(len--!=0) {
d++=s--; #改:*d++=*s--
}
printf("%s",dest);
}
各种头文件的作用:
<stdio.h> <string.h> <math.h> <stdlib.h.>
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)