基于LightRAG进行本地RAG部署(包括单卡多卡本地模型部署、调用阿里云或DeepSeekAPI的部署方法、RAG使用方法)
1.简介
RAG(Retrieval-Augmented Generation)是一种结合了检索(Retrieval)和生成(Generation)的自然语言处理模型架构。它旨在解决传统生成模型在面对复杂任务时可能出现的生成内容缺乏准确性和多样性的不足。在RAG模型中,首先会有一个检索模块,它会在一个庞大的外部知识库中检索与输入文本相关的片段或文档。这个知识库可以是预先构建的语料库,也可以是实时从互联网等来源获取的信息。RAG模型通过检索模块引入外部知识,使得生成的内容能够更好地结合实际的背景知识,从而提高生成结果的质量和准确性。例如在回答问题任务中,RAG可以通过检索找到与问题相关的具体信息,从而生成更准确的答案。
在实际应用中,RAG模型虽然表现优异,但由于其检索模块和生成模块的复杂性,可能会导致模型的训练和推理速度较慢,尤其是在处理大规模数据时。
随着研究的深入和技术的发展,人们在RAG的基础上进行了改进和优化,提出了LightRAG模型。LightRAG是对RAG模型的一种轻量化改进,旨在提高模型的效率和可扩展性,同时尽量保持RAG模型的性能优势。LightRAG通过优化检索模块的检索策略和生成模块的架构,减少了模型的计算量和参数规模。例如,它可能会采用更高效的检索算法来快速定位相关知识片段,或者对生成模块的解码器进行简化,减少不必要的计算。通过这些改进,LightRAG能够在保持较好生成质量的同时,显著提高模型的运行效率,使其更适合于实际的工业应用和在线服务场景,例如在需要快速响应的智能客服系统中,LightRAG能够更高效地生成准确的回答,提升用户体验。
在本博客中,我将基于Qwen2.5-3B和DeepSeek-R1-Distill-Qwen-32B(基于deepseek蒸馏的qwen模型),分别演示如何在单卡和多卡上部署LightRAG系统,并演示基于API(阿里云和Deepseek)如何构建LightRAG系统。
基本流程:
- 部署一个大模型(第2章),也可以直接调用云端大模型的API(第4章)
- 部署一个向量模型(第3章),也可以直接调用云端向量模型的API(第4章)
- 本地部署LightRAG(第4章),由LightRAG向大模型和向量模型发送请求,然后把结果返回给用户
显卡占用参考:
- 单卡24G部署可以跑起来7B的模型,但其上下文长度受限,建议使用3B模型或者7B的量化版本
- 8卡4090Ti 可以部署32B的模型,上下文可以拉满(32768),速度也很快。
- 如果需要部署DeepSeek v3 Int4量化版本,预估需要380G显存,8卡A100可高效部署
- 如果大模型是调用API的,本地只部署LightRAG,不会占用太大显存。
API费用参考:一次naive调用大约1w tokens,一次local调用约2w tokens
注意事项:
- RAG对上下文需求非常高,建议优先满足上下文的显存需求(如虽然单卡3090能跑7B模型,但其上下文受限)
- RAG对模型的理解能力要求较高,建议越强的越好。如果模型不够强,可能只能使用基本的naive模式,不过影响不大
阅读注意事项:
- 如果读者打算本地部署大模型,需阅读2-4章全部内容
- 如果读者打算使用API调用大模型,如阿里云百炼、DeepSeek,可以直接阅读第四章,跳过2-3章
LightRAG的github地址:https://github.com/HKUDS/LightRAG
参考博客:https://learnopencv.com/lightrag/#aioseo-legal-document-analysis-with-lightrag
-
-
2.基于vllm部署大模型
参考文档
vllm官方文档:Engine Arguments — vLLM
去年写的部署文章,供读者参考:Vllm进行Qwen2-vl部署(包含单卡多卡部署及爬虫请求)-CSDN博客
-
华为设备部署vllm,使用deepseek,官方文档:Multi-Node (DeepSeek) — vllm-ascend
https://github.com/vllm-project/vllm-ascend/blob/main/README.zh.md
-
环境安装
我使用的是Python3.10的虚拟环境,注意下载好权重,不需要下载github代码。
首先安装torch、transformers等依赖库
pip install torch==2.4.0 torchvision==0.19.0 torchaudio==2.4.0 --index-url https://download.pytorch.org/whl/cu121
pip install transformers -U # 4.50.2
pip install accelerate==0.26.0
接着安装vllm,我这里使用早期版本,读者可以尝试安装最新版本。
pip install vllm==0.6.3
下载权重,这里以Qwen2.5-3B-Instruct和Qwen2.5-7B-Instruct为例:https://huggingface.co/Qwen/Qwen2.5-VL-3B-Instruct
准备就绪后,可使用如下代码查看大模型是否能正常使用:(注意模型权重位置)
from transformers import AutoModelForCausalLM, AutoTokenizermodel_name = "Qwen2.5-3B-Instruct"model = AutoModelForCausalLM.from_pretrained(model_name,torch_dtype="auto",device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(model_name)prompt = "Give me a short introduction to large language model."
messages = [{"role": "system", "content": "You are Qwen, created by Alibaba Cloud. You are a helpful assistant."},{"role": "user", "content": prompt},
]
text = tokenizer.apply_chat_template(messages,tokenize=False,add_generation_prompt=True,
)
model_inputs = tokenizer([text], return_tensors="pt").to(model.device)generated_ids = model.generate(**model_inputs,max_new_tokens=512,
)
generated_ids = [output_ids[len(input_ids):] for input_ids, output_ids in zip(model_inputs.input_ids, generated_ids)
]response = tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
print(response)
如果返回结果,表示安装成功。
-
准备就绪后即可启动vllm
单卡部署
我们可以在命令行输入以下命令
vllm serve Qwen2.5-3B-Instruct --dtype auto --port 8000 --gpu-memory-utilization 0.7 --max_model_len 32768
出现以下界面,说明运行成功:
参数解释:
- Qwen2.5-3B-Instruct:模型权重位置
- dtype:数据类型,一般直接auto就可以了,低版本的显卡可能需要自己设置,如2080要设置为half
- port:端口号
- max_model_len:每次请求最大的token长度,爆显存了就改小,建议至少1w,RAG对长度需求较高
- gpu_memory_utilization:GPU最大利用率,爆显存了就改小,我现在一般设置为0.7-0.8
其他参数的文档:Engine Arguments — vLLM
-
可以使用以下代码检查vllm是否能正常使用:(下面的代码中只需改URL和model即可)
import requests
import json
from PIL import Image
import base64# 1.url
url = 'http://0.0.0.0:8000/v1/chat/completions' # 你的IP# 2.data
data = {"model": "Qwen2.5-3B-Instruct","messages": [{"role": "system", "content": "You are Qwen, created by Alibaba Cloud. You are a helpful assistant."},# 系统命令,一般不要改{"role": "user","content": "什么是大语言模型"}], # 用户命令,一般改这里"temperature": 0.7, "top_p": 0.8, "repetition_penalty": 1.05, "max_tokens": 1024}# 3.将字典转换为 JSON 字符串
json_payload = json.dumps(data)# 4.发送 POST 请求
headers = {'Content-Type': 'application/json'}
response = requests.post(url, data=json_payload, headers=headers)# 5.打印响应内容
# print(response.json().get("choices", [])[0].get("message", []).get("content", [])) # 命令行启动,用这个打印
print(response.json())
-
多卡部署
在命令行中输入:
vllm serve Qwen2.5-32B-Instruct --dtype auto --port 8000 --tensor-parallel-size 4 --pipeline-parallel-size 2 --gpu-memory-utilization 0.7 --max_model_len 32768
参数解释:
- tensor-parallel-size:模型的权重将被分割成n部分分布在GPU上。
- pipeline-parallel-size:设置流水线并行的大小为k,意味着模型的不同层将被分布到k个GPU上。
- 保证n*k=8,正好等于您拥有的GPU数量。
如果需要指定在某些卡上使用,可以使用如下命令:
CUDA_VISIBLE_DEVICES=4,5,6,7 vllm serve DeepSeek-R1-Distill-Qwen-32B --dtype auto --port 8000 --tensor-parallel-size 4 --pipeline-parallel-size 2 --gpu-memory-utilization 0.7 --max_model_len 10000
32B可在4张4090卡上部署,但其上下文受限。
-
-
3.基于Fastchat部署向量模型
环境安装
在RAG领域,向量模型将文本数据(包括用户输入的查询和文档库中的内容)转换为向量形式,这些向量能够捕捉文本的语义信息,使得语义相似的文本在向量空间中距离更近。在检索阶段,向量模型通过计算用户查询向量与文档库中各个文档向量之间的相似度,快速找到与用户查询语义最相关的文档片段,这些向量化的上下文信息帮助生成模型更好地理解用户意图和背景知识,从而生成更准确、更有信息量的回答。
-
这里我们使用Fastchat部署向量模型,首先下载代码和权重:
fastchat:https://github.com/lm-sys/FastChat
向量模型权重:二选一即可,注意不要混用
- 单卡使用bge-large-zh-v1.5 :https://huggingface.co/BAAI/bge-large-zh-v1.5
- 多卡或大显存可以使用更好的bge-m3:https://huggingface.co/BAAI/bge-m3
位置如下:
安装依赖包:
pip3 install "fschat[model_worker,webui]"
pip install pydantic_settings
-
模型部署
将如下脚本,保存为fastchat.sh:
#!/bin/bash# 启动控制器
python -m fastchat.serve.controller --host 0.0.0.0 --port 21003 &# 启动模型
python -m fastchat.serve.model_worker --model-path ./bge-large-zh-v1.5 --model-names gpt-4 --num-gpus 1 --controller-address http://0.0.0.0:21003 &# 启动openai API服务器
python -m fastchat.serve.openai_api_server --host 0.0.0.0 --port 8200 --controller-address http://0.0.0.0:21003
在命令行输入以下命令:
sh fastchat.sh
出现以下界面说明运行成功:
-
-
4.LightRAG部署
环境安装
# Both platforms
pip install -r requirements.txt
pip install nest_asyncio
pip install fastapi
pip install python-multipart
pip install uvicorn
-
接着你要知道模型部署端或LightRAG部署端的IP地址,Linux通过ifconfig查看,如下红框中的就是你的IP地址:(本机使用可以直接0.0.0.0)
-
使用本地模型
examples/lightrag_api_openai_compatible_demo.py
需要设置大约36行处的参数:
LLM_MODEL = "Qwen2.5-3B-Instruct" # 你所使用的模型
EMBEDDING_MODEL = "gpt-4" # 不要改,只是起了一个名字,不影响任何东西
API_KEY = "666" # 本地模型没有 key,随便写一个
BASE_URL = "http://0.0.0.0:8000/v1" # 大模型的URL
EMBEDDING_URL = "http://0.0.0.0:8200/v1" # 向量模型的URL
EMBEDDING_MAX_TOKEN_SIZE = 32768 # 模型最大长度,根据模型和显存来设置
EMBEDDING = 1024 # 向量模型的向量维度,如bge是1024
MAX_ASYNC=10 # 最大并发数,根据显存和需求来设置,(超过了客户端会报错,但服务端还能继续执行,空闲后客户端可继续发请求)
在第94行处,将RAG初始化代码更改为(不做更改也可运行,这里主要是设置了并发数限制):
async def init():embedding_dimension = await get_embedding_dim()embedding_dimension = EMBEDDINGrag = LightRAG(working_dir=WORKING_DIR,llm_model_func=llm_model_func,llm_model_max_async=MAX_ASYNC,max_parallel_insert=10, # 插入新文档时的并发数,根据设备自行设置embedding_func=EmbeddingFunc(embedding_dim=embedding_dimension,max_token_size=EMBEDDING_MAX_TOKEN_SIZE,func=embedding_func,),)await rag.initialize_storages()await initialize_pipeline_status()
然后运行examples/lightrag_api_openai_compatible_demo.py即可
-
使用API调用云端大模型
使用API调用大模型就不用上述步骤,如果你没有设备,且数据不敏感,可以考虑直接调用API,方法如下:
阿里云百炼平台
获取API Key,参考官方文档:https://bailian.console.aliyun.com/?tab=api#/api
选择模型:https://bailian.console.aliyun.com/?tab=model#/model-market
(只需关注其中的文本模型和向量模型即可,在下面的配置中只需要更改LLM_MODEL和EMBEDDING_MODEL即可)
点击API参考,比如我们选择qwen-plus,仿照下图找到模型的名字,把这个改到下面的代码中的LLM_MODEL和EMBEDDING_MODEL即可
-
-
Deepseek
获取API key:DeepSeek
文档:首次调用 API | DeepSeek API Docs
-
使用阿里云,设置大约36行的参数为:
LLM_MODEL = "qwen-plus"
BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1" # 阿里云
API_KEY = "sk-XXXX"
EMBEDDING_MODEL = "text-embedding-v3"
EMBEDDING_URL = BASE_URL
或DeepSeek:
需注意,DeepSeek没有向量模型,需另外找一个,不管本地部署还是云端模型
LLM_MODEL = "deepseek-chat" # deepseek
BASE_URL = "https://api.deepseek.com/v1" # deepseek
API_KEY = "sk-XXXXXXXXXXX" # Deepseek
-
然后运行examples/lightrag_api_openai_compatible_demo.py即可
-
调用方法
首先运行examples/lightrag_api_openai_compatible_demo.py,如果使用本地模型,需先启动vllm,再启动fastchat,最后启动lightrag。
在使用过程中,我们需遵循以下步骤:
- 先使用insert或insert_file插入文档或文本
- 再使用query提问。
-
提问 query
使用如下代码即可,您只需要修改URL为LightRAG的服务器地址,然后修改query和mode即可
- mode包括:naive、local、global、hybrid,
- naive是标准rag
- local是使用图结构增强的RAG,其中图节点是具体的名词,
- global是使用图结构增强的RAG,其中图节点是抽象的名词
- hybrid是混合了local和global的结果
注意:小模型对于后三种模式的理解能力极差,小模型建议只使用naive
import requests
import json
import timestart_time = time.time()# 1.url
url = 'http://0.0.0.0:8020/query' # 你的IP# 2.data
# history [{"role": "user/assistant", "content": "message"}].
data = {"query": "江南大学是211吗?", "mode":"naive"}# 3.将字典转换为 JSON 字符串
json_payload = json.dumps(data)# 4.发送 POST 请求
headers = {'Content-Type': 'application/json'}
response = requests.post(url, data=json_payload, headers=headers)# 5.打印响应内容
print(response.json().get("data", [])) # 用这个打印
# print(response.json())
print(f"耗时{time.time()-start_time}")
结果演示:
是的,江南大学是一所“211工程”重点建设高校。作为中国教育部直属的全国重点大学,江南大学不仅被列入国家“211工程”,还进入了“双一流”建设高校行列,体现了其在全国高等教育体系中的重要地位。### 江南大学的背景
- **“211工程”**:该计划旨在重点支持一批高校发展成为国内高水平大学。江南大学因其在食品科学与工程、轻工技术与工程等领域的突出贡献而入选。
- **“双一流”建设**:江南大学在新一轮国家高等教育发展战略中被列为“世界一流学科建设高校”,进一步巩固了其在国内和国际学术界的影响力。### 学科优势
江南大学尤其以其食品科学与工程学科闻名,该学科在全球范围内具有很高的声誉。根据最新排名,江南大学的食品科学与工程学科连续多年位居世界第一(依据“软科世界一流学科排名”)。### 参考信息
以下是从知识库中提取的相关信息:
- 江南大学入选了国家“211工程”重点建设项目,表明其在全国高校中的重要地位。
- 学校还参与了“985工程优势学科创新平台”建设,并在多个领域取得了显著成就。---### References
1. [KG] 江南大学是“211工程”重点建设高校 (File: library/江南大学.txt)
2. [KG] 江南大学入选“双一流”建设高校 (File: library/江南大学.txt)
{'status': 'success', 'data': '是的,江南大学是一所“211工程”重点建设高校。作为中国教育部直属的全国重点大学,江南大学不仅被列入国家“211工程”,还进入了“双一流”建设高校行列,体现了其在全国高等教育体系中的重要地位。\n\n### 江南大学的背景\n- **“211工程”**:该计划旨在重点支持一批高校发展成为国内高水平大学。江南大学因其在食品科学与工程、轻工技术与工程等领域的突出贡献而入选。\n- **“双一流”建设**:江南大学在新一轮国家高等教育发展战略中被列为“世界一流学科建设高校”,进一步巩固了其在国内和国际学术界的影响力。\n\n### 学科优势\n江南大学尤其以其食品科学与工程学科闻名,该学科在全球范围内具有很高的声誉。根据最新排名,江南大学的食品科学与工程学科连续多年位居世界第一(依据“软科世界一流学科排名”)。\n\n### 参考信息\n以下是从知识库中提取的相关信息:\n- 江南大学入选了国家“211工程”重点建设项目,表明其在全国高校中的重要地位。\n- 学校还参与了“985工程优势学科创新平台”建设,并在多个领域取得了显著成就。\n\n---\n\n### References\n1. [KG] 江南大学是“211工程”重点建设高校 (File: library/江南大学.txt)\n2. [KG] 江南大学入选“双一流”建设高校 (File: library/江南大学.txt)', 'message': None}
耗时0.013264656066894531
-
包含历史记录(即多轮对话)的调用
官方代码支持多轮对话,但其lightrag_api_openai_compatible_demo.py没有写,所以我们需要先修改代码:
首先修改examples/lightrag_api_openai_compatible_demo.py第131行:
class QueryRequest(BaseModel):query: strmode: str = "hybrid"only_need_context: bool = Falsehistory_messages: list = []
修改第151行:
@app.post("/query", response_model=Response)
async def query_endpoint(request: QueryRequest):try:loop = asyncio.get_event_loop()# result = await loop.run_in_executor(# None,# lambda: rag.query(# request.query,# param=QueryParam(# mode=request.mode, only_need_context=request.only_need_context# ),# ),# )history_messages = request.history_messages if request.history_messages else []result = await rag.aquery(request.query,param=QueryParam(mode=request.mode,conversation_history=history_messages),)return Response(status="success", data=result)except Exception as e:raise HTTPException(status_code=500, detail=str(e))
接着我们就可以使用以下代码进行包含历史信息的调用
# 历史记录
start_time = time.time()# 1.url
url = 'http://0.0.0.0:8020/query' # 你的IP# 2.data
data_list = ["介绍一下江南大学?", "该校有什么强势学科吗?", "该学科的历史?"]
history_messages = []
for d in data_list:# history [{"role": "user/assistant", "content": "message"}].data = {"query": d, "mode": "naive", "history_messages": history_messages}# 3.将字典转换为 JSON 字符串json_payload = json.dumps(data)# 4.发送 POST 请求headers = {'Content-Type': 'application/json'}response = requests.post(url, data=json_payload, headers=headers)history_messages.append({"role": "user", "content": d})history_messages.append({"role": "assistant", "content": response.json().get("data", [])})# 5.打印响应内容print(response.json().get("data", [])) # 命令行启动,用这个打印print(response.json())print("-"*50)
print(f"耗时{time.time()-start_time}")
-
insert插入文本
insert可以直接往知识库中插入一段文本:
import requests
import json
from PIL import Image
import base64# 1.url
# url = 'http://0.0.0.0:8020/insert' # 你的IP# 2.data
data = {"text": "湖南大学图书馆特藏分馆它是长沙市近现代保护建筑,也是湖南大学九大“国保建筑”之一,前身可远溯至创建于北宋年间的岳麓书院御书楼,1929年12月学校开始兴建新图书馆,1933年竣工,但1938年毁于日军侵华战火,仅剩下几根残破的石柱,有两根就伫立在湘江边“湖南大学”的石刻旁,湖南大学老图书馆由蔡泽奉教授设计,是湖南大学定名后第一座现代意义的图书馆,亦是当时华中华南最大的图书馆,故宫国宝南迁时曾寄存于此。1947年,湖南大学策划重建老图书馆,由中国近现代建筑师、建筑教育家柳士英先生设计,于1949年竣工,此后,1951年进行了扩建,与原馆完全融为一体,总面积约2400平方米,成为我们今日所见的特藏分馆。被载入长沙市近现代建筑保护名单,1985年,湖南大学新建的总图书馆竣工,老图书馆则作为工商管理学院院楼使用,至2006年恢复作为图书馆的使用功能",}# 3.将字典转换为 JSON 字符串
json_payload = json.dumps(data)# 4.发送 POST 请求
headers = {'Content-Type': 'application/json'}
response = requests.post(url, data=json_payload, headers=headers)# 5.打印响应内容
# print(response.json().get("choices", [])[0].get("message", []).get("content", [])) # 命令行启动,用这个打印
print(response.json())
返回结果为以下时,说明成功:
{'status': 'success', 'data': None, 'message': 'Text inserted successfully'}
insert_file插入文档
txt文档可以直接使用insert_file进行插入,而pdf文档需要借助如pdfplumber或textract进行解析,再插入其中,示例代码如下:只需更改URL和file_path即可
import requests
import pdfplumber
import json
import os
import time# 定义上传文件的接口地址
url = "http://0.0.0.0:8020/"# 定义要上传的文件路径
file_path = "library/江南大学.txt"
# file_path = "library/重庆大学_百度百科.pdf"if file_path.split(".")[-1] == "txt": # 如果是txt文件,则直接上传文件# 打开文件并发送 POST 请求with open(file_path, "rb") as f:files = {"file": (file_path, f)} # "file" 是接口期望的字段名response = requests.post(url+"insert_file", files=files)
elif file_path.split(".")[-1] == "pdf": # 如果是pdf文件,则先提取pdf中的文本,然后上传文件pdf_text = ""with pdfplumber.open(file_path) as pdf:for page in pdf.pages:pdf_text += page.extract_text() + "\n"data = {"text": pdf_text,"file_name": [file_path.split(".")[-2]]}# 3.将字典转换为 JSON 字符串json_payload = json.dumps(data)# 4.发送 POST 请求headers = {'Content-Type': 'application/json'}response = requests.post(url+"insert", data=json_payload, headers=headers)# 打印响应内容
print(response.status_code)
print(response.text)# print(pdf_text)
注意:也可使用lightrag_openai_compatible_demo.py先插入文档内容,插入后再部署RAG
包含文献来源的插入
首先修改examples/lightrag_api_openai_compatible_demo.py第187行代码:(这个修改主要是为了增加文档名字file_name,即RAG中文献来源的)
@app.post("/insert_file", response_model=Response)
async def insert_file(file: UploadFile = File(...)):try:file_content = await file.read()file_name = file.filename# Read file contenttry:content = file_content.decode("utf-8")except UnicodeDecodeError:# If UTF-8 decoding fails, try other encodingscontent = file_content.decode("gbk")# Insert file contentloop = asyncio.get_event_loop()await loop.run_in_executor(None, lambda: rag.insert(content, file_paths=file_name))return Response(status="success",message=f"File content from {file.filename} inserted successfully",)except Exception as e:raise HTTPException(status_code=500, detail=str(e))
如果需要对insert插入文件来源,操作如下:
更改138行:
class InsertRequest(BaseModel):text: strfile_name: str = None
更改178行
@app.post("/insert", response_model=Response)
async def insert_endpoint(request: InsertRequest):try:loop = asyncio.get_event_loop()await loop.run_in_executor(None, lambda: rag.insert(request.text, file_paths=request.file_name))return Response(status="success", message="Text inserted successfully")except Exception as e:raise HTTPException(status_code=500, detail=str(e))
下面的代码只改pdf的部分,因为txt部分上传文档,只需要服务端处理即可。
import requests
import pdfplumber
import json
import os
import time# 定义上传文件的接口地址
url = "http://0.0.0.0:8020/"# 定义要上传的文件路径
file_path = "library/江南大学.txt"
# file_path = "library/重庆大学_百度百科.pdf"if file_path.split(".")[-1] == "txt": # 如果是txt文件,则直接上传文件# 打开文件并发送 POST 请求with open(file_path, "rb") as f:files = {"file": (file_path, f)} # "file" 是接口期望的字段名response = requests.post(url+"insert_file", files=files)
elif file_path.split(".")[-1] == "pdf": # 如果是pdf文件,则先提取pdf中的文本,然后上传文件pdf_text = ""with pdfplumber.open(file_path) as pdf:for page in pdf.pages:pdf_text += page.extract_text() + "\n"data = {"text": pdf_text,"file_name": [file_path.split(".")[-2]]}# 3.将字典转换为 JSON 字符串json_payload = json.dumps(data)# 4.发送 POST 请求headers = {'Content-Type': 'application/json'}response = requests.post(url+"insert", data=json_payload, headers=headers)# 打印响应内容
print(response.status_code)
print(response.text)# print(pdf_text)
经过上述修改后,知识库中就会有文档来源等相关信息,模型也会返回参考文献的名字,帮助用户进一步检索相关文档。如下:
"chunk-d7df3bb3d2949b3cbea9291c6fa24a8f": {"tokens": 300,"content": "部卷动的波浪也像一摞书籍,可谓“书山有路勤为径,学海无涯苦作舟”,体现了江南大学人“笃学尚行、止于至善”的精神。\n校标的标准色名为“江南绿”,象征雨丝浸润下的江南水色。沉稳的基调符合江南大学严谨的、以工科为主体的治学、办学特色。\n校标上的江南大学校名,字体采用毛体“江南大学”(“学”字为简体),英文名字采用“江南”两字音译方案,即定名为“Jiangnan University”。中英文对照融世界性眼光和传统化特色为一体,表达了江南大学立足传统,面向世界,开拓未来的理念,寓意着创建国内外知名的特色鲜明高水平大学的决心。\n校旗\n学校校旗为白色长方形旗帜,中央分别印有江南绿色、规定字体的“江南大学”校名、校名英译全称和校标。\n吉祥物\n学校吉祥物为“太湖神鼋”,源于太湖地区“震泽神鼋”,象征着坚韧执着、勇于拼搏、奋发向上的精神。","chunk_order_index": 4,"full_doc_id": "doc-3cfdc1b74c6aaf7b99bc05b7d806f0a9","file_path": "library/江南大学.txt"},
-
缓存目录
我在lightrag_api_openai_compatible_demo.py中设置了工作目录,如下:
DEFAULT_RAG_DIR = "dickens"# Configure working directory
WORKING_DIR = os.environ.get("RAG_DIR", f"{DEFAULT_RAG_DIR}")
在dickens文件夹下,我们可以看到如下结构:
dickens
--graph_chunk_entity_relation.graphml # 抽取的图结构
--kv_store_doc_status.json # 文档状态
--kv_store_full_docs.json # 完整文档内容
--kv_store_llm_response_cache.json # LLM返回结果的缓存
--kv_store_text_chunks.json # 文档切分结果
--vdb_chunks.json # 向量数据库
--vdb_entities.json # 向量数据库
--vdb_relationships.json # 向量数据库
建议重点关注以下几个:
kv_store_doc_status.json记录了插入文本的状态,其中:
- processed:已处理完
- pending:排队中
- processing:处理中
kv_store_full_docs.json记录了插入文本的完整内容
kv_store_llm_response_cache.json记录了大语言模型的回答的缓存,已有问题直接掉缓存,不需要大模型回答。
-
通用设置
在lightrag/prompt.py下,将部分内容更改为中文:
更改大约第8行处:
PROMPTS["DEFAULT_LANGUAGE"] = "中文"
更改大约194行处:
PROMPTS["fail_response"] = ("对不起,我无法回答这个问题。【知识库中没有相关内容!】"
)
在lightrag/llm/openai.py下大约275行,改为,防止超出长度报错:
response = await openai_async_client.embeddings.create(model=model, input=[i[:500] if len(i) > 500 else i for i in texts], encoding_format="float")
-
交互界面
我使用gradio写了一个交互界面,供大家参考。
import json
import requests
import threading
import gradio as gr# 定义后端 URL
url = 'http://0.0.0.0:8020/query' # 你的IP
# url = 'http://10.7.13.23:8020/query' # 你的IP# 定义查询函数
def query_model(user_input, mode, history_messages):mode_dict = {"标准": "naive","局部": "local","全局": "global","混合": "hybrid"}# 构造请求数据data = {"query": user_input, "mode": mode_dict[mode], "history_messages": history_messages}# 将字典转换为 JSON 字符串json_payload = json.dumps(data)# 发送 POST 请求headers = {'Content-Type': 'application/json'}response = requests.post(url, data=json_payload, headers=headers)# 获取响应内容response_data = response.json().get("data", [])# 更新历史消息history_messages.append({"role": "user", "content": user_input})history_messages.append({"role": "assistant", "content": response_data})# 返回助手的回复和更新后的历史记录return response_data, history_messages# 定义 Gradio 界面
with gr.Blocks() as demo:gr.Markdown("# 模型问答界面")gr.Markdown("在这个界面中,你可以与模型进行交互,并自由切换不同的模式。\n")gr.Markdown("标准模式是标准RAG,能够快速响应问题;局部提取局部(实体级)关键词;全局提取全局(主题级)关键词;混合模式提取局部和全局提示词")chatbot = gr.Chatbot(label="对话记录")history_state = gr.State([]) # 用于存储每个用户的会话历史with gr.Row():user_input = gr.Textbox(label="输入你的问题", placeholder="请输入问题...", scale=4)mode_selector = gr.Dropdown(choices=["标准", "局部", "全局", "混合"],value="标准",label="选择模式",scale=2)submit_button = gr.Button("提交", scale=1)def update_chat(history, user_message, mode, history_state):# 使用多线程处理请求def process_request():nonlocal history, history_stateassistant_response, updated_history = query_model(user_message, mode, history_state)history.append((user_message, assistant_response))history_state = updated_history# 创建并启动线程thread = threading.Thread(target=process_request)thread.start()thread.join() # 等待线程完成(如果需要异步效果,可以去掉这行)return history, history_statesubmit_button.click(fn=update_chat,inputs=[chatbot, user_input, mode_selector, history_state],outputs=[chatbot, history_state])# 启动 Gradio 应用
demo.launch()
-
-
总结
本地部署RAG(Retrieval-Augmented Generation)系统具有诸多显著优势,这些优势主要体现在以下几个方面:
- 从数据安全和隐私保护的角度来看,本地部署能够确保数据在本地环境中进行处理和存储,避免了数据传输到云端或第三方平台可能带来的泄露风险。这对于处理敏感信息或受法律严格监管的数据(如医疗记录、金融数据等)尤为重要。企业或机构可以完全掌控数据的访问和使用权限,从而更好地满足数据合规性要求。
- 在性能优化方面,本地部署可以根据具体的应用场景和硬件环境进行定制化配置。通过优化检索算法和调整模型参数,可以实现更高效的检索和生成性能,减少延迟,提高系统的响应速度。此外,本地部署还可以根据实际需求灵活扩展硬件资源,以应对不同的负载需求,从而更好地满足业务的性能要求。
- 成本控制也是本地部署的一大优势。虽然初期需要投入一定的硬件和软件成本,但长期来看,本地部署可以避免因使用云端服务而产生的持续订阅费用。对于大规模数据处理和高频率的模型调用场景,本地部署的成本效益尤为明显。同时,企业还可以根据实际使用情况合理配置资源,避免资源浪费,进一步降低运营成本。
- 本地部署还提供了更高的灵活性和可定制性。企业可以根据自身的业务需求对RAG系统进行深度定制,包括对检索模块的优化、对生成模型的微调以及对整体架构的调整等。这种灵活性使得系统能够更好地适应特定领域的应用场景,例如在医疗、法律、金融等专业领域,可以根据行业特点和用户需求进行针对性的优化,从而提供更精准、更有价值的服务。
- 此外,本地部署便于进行系统的维护和管理。企业可以自主安排维护时间,快速响应可能出现的技术问题,及时进行系统更新和优化。这种自主性使得企业能够更好地掌控系统的稳定性和可靠性,减少因外部因素导致的系统中断或故障风险。
- 最后,本地部署RAG系统能够更好地支持离线应用。在一些网络条件不稳定或无法联网的环境中,本地部署的系统可以独立运行,不受网络限制。这对于一些需要在特定环境下(如偏远地区、军事设施等)使用RAG技术的应用场景具有重要意义,确保了系统的可用性和可靠性。
综上所述,本地部署RAG系统在数据安全、性能优化、成本控制、灵活性、维护管理以及离线应用支持等方面具有显著的优势,能够为企业和机构提供更加可靠、高效和定制化的解决方案,满足多样化的业务需求。
如果你喜欢我的内容,记得点赞、关注、收藏哦!你的支持是我不断进步的动力,也让我更有信心继续创作。点赞是对我努力的认可,关注是对我持续分享的信任,收藏则是方便你随时回顾。感谢有你,让我们一起成长!🎉💖📚
相关文章:
基于LightRAG进行本地RAG部署(包括单卡多卡本地模型部署、调用阿里云或DeepSeekAPI的部署方法、RAG使用方法)
1.简介 RAG(Retrieval-Augmented Generation)是一种结合了检索(Retrieval)和生成(Generation)的自然语言处理模型架构。它旨在解决传统生成模型在面对复杂任务时可能出现的生成内容缺乏准确性和多样性的不…...
GPIO输出模式
这个 typedef enum 是 STM32 中 GPIO 模式的定义,每一个模式都代表着 GPIO 引脚的不同工作方式。不同的模式会影响引脚的输入或输出状态,以及是否具有其他功能(如外设功能)。接下来,我将详细解释每个模式的作用和如何使…...
Linux,redis数据库安装使用
Redis 非关系型数据库 介绍 安装 主从模式 哨兵模式 集群模式 redis 数据类型/增删改查 redis 持久化 redis 雪崩 击穿 穿透 LAMPredis 数据迁移 git redis 安装部署 1,下载或者上传redis 6.2.14 wget http://download.redis.io/releases/redis-6.2.14.tar.gz …...
3DS 转 STL 全攻略:传统工具与迪威模型网在线转换深度解析
在 3D 建模与 3D 打印的技术领域中,常常会遇到需要将不同格式的文件进行转换的情况。其中,把 3DS 文件转换为 STL 格式是较为常见的操作。3DS 文件作为一种旧版 Autodesk 3D Studio 使用的 3D 图像格式,存储着丰富的信息,包括网格…...
最新Spring Security实战教程(十一)CSRF攻防实战 - 从原理到防护的最佳实践
🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志 🎐 个人CSND主页——Micro麦可乐的博客 🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战 🌺《RabbitMQ》…...
远程医疗系统安全升级:构建抗CC攻击的全方位防护网
随着云计算、大数据和互联网技术的不断发展,远程医疗系统正在逐步走进大众视野,为患者提供便捷高效的医疗服务。然而,远程医疗系统在便利性的背后也面临着严峻的网络安全挑战,其中,CC攻击(Challenge Collap…...
【Java学习笔记】进制与进制转换
进制与进制转换 一、进制介绍 二进制:0、1,满 2 进 1,以 0b 或 0B 开头。 十进制:0-9,满 10 进 1。 八进制:0-7,满 8 进 1,以数字 0 开头表示。 十六进制:0-9 及 A(10…...
《SpringBoot中@Scheduled和Quartz的区别是什么?分布式定时任务框架选型实战》
🌟 大家好,我是摘星! 🌟 今天为大家带来的是Scheduled和Quartz对比分析: 新手常见困惑: 刚学SpringBoot时,我发现用Scheduled写定时任务特别简单。但当我看到同事在项目里用Quartz时&…...
RestSharp和Newtonsoft.Json结合发送和解析http
1.下载RestSharp和Newtonsoft.Json 2编写ApiRequest和ApiResponse和调用工具类HttpRestClient 请求模型 /// <summary>/// 请求模型/// </summary>public class ApiRequest{/// <summary>/// 请求地址/api路由地址/// </summary>public string Route {…...
[图论]Kruskal
Kruskal 本质:贪心,对边进行操作。存储结构:边集数组。适用对象:可为负权图,可求最大生成树。核心思想:最短的边一定在最小生成树(MST)上,对最短的边进行贪心。算法流程:对全体边集…...
腾讯云对象存储以及项目业务头像上传
腾讯云上传步骤: service-vod模块化中 ①、参考文档,引入依赖 ②、配置文件application.properties ③、创建工具类 初始化bean的时候读取配置文件 Component public class ConstantPropertiesUtil implements InitializingBean{Value("${t…...
Windows下导入文件中的环境变量
在Windows批处理脚本(.bat)中,通过文件获取并设置环境变量通常涉及逐行读取文件内容并动态赋值给变量。以下是具体实现方法及示例: 一、从文件读取变量并设置到环境变量 假设有一个配置文件(如env_config.txt…...
【音视频开发】第五章 FFmpeg基础
【音视频开发】第五章 FFmpeg基础 文章目录 【音视频开发】第五章 FFmpeg基础一、播放器框架1.媒体文件读取阶段2.音频处理流程3.视频处理流程 二、常用音视频概念1.常用音视频术语2.复用器3.编解码器 三、FFmpeg 库1.整体结构 四、FFmpeg 常用函数1.libavformat 封装/解封装2.…...
【ESP32|音频】一文读懂WAV音频文件格式【详解】
简介 最近在学习I2S音频相关内容,无可避免会涉及到关于音频格式的内容,所以刚开始接触的时候有点一头雾水,后面了解了下WAV相关内容,大致能够看懂wav音频格式是怎么样的了。本文主要为后面ESP32 I2S音频系列文章做铺垫࿰…...
数据通信学习笔记之OSPF路由汇总
区域间路由汇总 路由汇总又被称为路由聚合,即是将一组前缀相同的路由汇聚成一条路由,从而达到减小路由表规模以及优化设备资源利用率的目的,我们把汇聚之前的这组路由称为精细路由或明细路由,把汇聚之后的这条路由称为汇总路由或…...
【C++】priority_queue的底层封装和实现
目录 前言基本结构如何设置默认大小堆底层实现仿函数的使用向上调整算法向下调整算法其他接口 end 前言 priority_queue的介绍 优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中的元素构造成堆的结构,因此priorit…...
2023年全国青少年信息素养大赛 Python编程挑战赛 小学全年级组 初赛真题答案详细解析
2023信息素养大赛 Python编程挑战赛 选择题(共15题,每题5分,共75分) 1、关于列表的索引,下列说法正确的是 A、列表的索引从0开始 B、列表的索引从1开始 C、列表中可能存在两个元素的索引一致 D、列表中索引的最大…...
十三种通信接口芯片——《器件手册--通信接口芯片》
目录 通信接口芯片 简述 基本功能 常见类型 应用场景 详尽阐述 1 RS485/RS422芯片 1. RS485和RS422标准 2. 芯片功能 3. 典型芯片及特点 4. 应用场景 5. 设计注意事项 6. 选型建议 2 RS232芯片 1. RS232标准 2. 芯片功能 3. 典型芯片及特点 4. 应用场景 5. 设计注意事项 6…...
PyTorch生成式人工智能实战(1)——神经网络与模型训练过程详解
PyTorch生成式人工智能实战(1)——神经网络与模型训练过程详解 0. 前言1. 传统机器学习与人工智能2. 人工神经网络基础2.1 人工神经网络组成2.2 神经网络的训练 3. 前向传播3.1 计算隐藏层值3.2 执行非线性激活3.3 计算输出层值3.4 计算损失值3.5 实现前…...
【软件系统架构】事件驱动架构
一、引言 在当今的软件开发和系统架构领域,事件驱动架构(Event - Driven Architecture,EDA)正逐渐成为构建复杂、分布式和可扩展系统的热门选择。随着信息技术的不断发展,传统的架构模式在应对高并发、实时性要求高、数…...
Doris FE 常见问题与处理指南
在数据仓库领域,Apache Doris 凭借其卓越性能与便捷性被广泛应用。其中,FE(Frontend)作为核心组件,承担着接收查询请求、管理元数据等关键任务。然而,在实际使用中,FE 难免会遭遇各类问题&#…...
Manus AI “算法-数据-工程“三位一体的创新
Manus AI在多语言手写识别领域的技术突破,通过算法创新、数据工程与场景适配的协同作用,解决了传统手写识别的核心痛点。以下是其关键技术路径与创新点的系统性分析: 一、深度学习模型与算法优化 混合神经网络架构Manus AI采用"CNN与LST…...
Flutter Expanded 与 Flexible 详解
目录 1. 引言 2. Expanded 的基本用法 3. Flexible 的基本用法 4. Expanded vs Flexible 的区别 4.1 基础定义 4.2 关键差异 5. Expanded 深度解析 5.1 按比例分配 5.2 强制填充特性 6. Flexible 深度解析 6.1 基础用法:动态收缩 6.2 结合 fit 参数控制…...
乘用车制动系统设计:保障行车安全的核心技术
摘要 随着汽车工业的快速发展,乘用车制动系统的设计至关重要。本文详细阐述了乘用车制动系统的工作原理、组成部分、常见类型,深入分析了制动系统设计过程中的关键要点,包括制动力分配、制动管路设计、制动助力系统选型等。同时,…...
电力行业在保障用电安全方面正积极采用先进的物联网技术
电力行业在保障用电安全方面正积极采用先进的物联网技术 电力行业的物联网安全用电监管装置正发挥着至关重要的作用。 ASCO 电不着安全用电装置凭借其卓越的性能,成为了解决用电安全问题的得力助手。 当电漏电这种危险情况悄然发生时,物联网 ASCO 电不着…...
TDengine 语言连接器(PHP)
简介 PHP 语言广泛用于 Web 开发的开源脚本语言。它语法简单,容易学习,既支持面向过程,也支持面向对象编程。具有跨平台性,能与多种数据库交互,可与 HTML 等前端技术配合,动态生成网页内容。常用于开发各类…...
使用docker该怎么做:从公有仓库拉取镜像并上传到私有仓库
在容器化部署中,将公有镜像仓库(如Docker Hub)的镜像迁移到私有仓库(如Harbor、Nexus)是常见需求。 一、为什么需要将镜像从公有仓库传到私有仓库? 网络连通性:公有仓库依赖公网访问ÿ…...
list的使用
1:list文档 list文档 在之前我们对于链表有过最初始的模拟实现,现在进入C之后,我们可以在STL库中发现到链表这个容器的使用,list的底层也是我们最初实现的双向链表。 2:list的使用 list的接口有很多,我们…...
Redis遇到Hash冲突怎么办
在 Redis 中,哈希冲突通常是指当多个键的哈希值相同或位于相同的哈希槽中时发生冲突。Redis 通过底层的哈希表和一些冲突解决机制(如开放地址法、链表法等)来处理哈希冲突问题。这些通常是透明的,作为开发者,我们无需直…...
OpenCV 图形API(42)颜色空间转换-----将 BGR图像转换为 I420(YUV 4:2:0)格式函数BGR2I420()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 将图像从BGR色彩空间转换为I420色彩空间。 该函数将输入图像从BGR色彩空间转换为I420。R、G和B通道值的传统范围是0到255。 输出图像必须是8位无…...
简述Apache RocketMQ
整体架构分析 基本流程 模块特性 发送消息流程原理分析 同步发送 sync 异步发送 async 直接发送 one-way 主从同步(HA)机制分析 消息投递 持久化机制 RocketMQ的RPC通信 RocketMQ中Remoting通信模块的具体实现 消息的协议涉及与编码解码 消…...
AI融合SEO关键词实战指南
内容概要 随着人工智能技术的迭代升级,SEO关键词策略正经历从人工经验驱动向数据智能驱动的范式转变。本指南聚焦AI技术在搜索引擎优化中的系统性应用,通过构建多层技术框架实现关键词全生命周期管理。核心方法论涵盖语义分析引擎的构建原理、基于NLP的…...
RK3588 实现音视频对讲
RK3588 实现音视频对讲方案 RK3588是瑞芯微推出的一款高性能处理器,非常适合用于音视频对讲系统的开发。以下是基于RK3588实现音视频对讲的方案概述: 硬件架构 核心处理器:RK3588 (4xCortex-A76 4xCortex-A55)视频处理: 内置8…...
OSPF区域间路由计算
ABR:区域边界路由器,连接两个不同区域的设备就称为ABR(不同厂商不同,定义很模糊) ASBR:自治系统边界路由器,引入了外部路由,将不是自治系统外部的不是OSPF路由的条目变成OSPF路由条目…...
NAT、代理服务、内网穿透
NAT、代理服务、内网穿透 1、NAT1.1、NAT过程1.2、NAPT2、内网穿透3、内网打洞3、代理服务器3.1、正向代理3.2、反向代理1、NAT 1.1、NAT过程 之前我们讨论了IPv4协议中IP地址数量不充足的问题。NAT技术是当前解决IP地址不够用的主要手段,是路由器的一个重要功能。 NAT能够将…...
阿尔特拉 EP1C12F324I7N AlteraFPGA Cyclone
EP1C12F324I7N 属于 Altera Cyclone I 系列 FPGA 中的中低密度型号,面向成本敏感、功耗受限的嵌入式与数据通路应用。该器件采用 0.13 μm 全层铜 SRAM 工艺,集成约 12 060 个逻辑单元(LE)、239 616 位片上 RAM、249 路可编…...
解决“驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接“问题
参考链接: https://blog.csdn.net/yyj12138/article/details/123073146...
QtApplets-实现应用程序单例模式,防止重复运行
QtApplets-实现应用程序单例模式,防止重复运行 文章目录 QtApplets-实现应用程序单例模式,防止重复运行摘要引言实现原理核心代码实现头文件定义实现文件 使用方法技术要点解析1. 文件锁机制2. 进程 ID 管理3. Windows 互斥量4. 跨平台兼容 注意事项…...
nodejs使用pkg打包文件
pkg配置 "pkg": {"assets": ["*.html","*.css","*.js"],"mirror": "https://npmmirror.com/mirrors/node-v8-compile-cache/"},"bin": "server.js",嵌入到exe中的资源使用assets打…...
学习笔记十六——Rust Monad从头学
🧠 零基础也能懂的 Rust Monad:逐步拆解 三大定律通俗讲解 实战技巧 📣 第一部分:Monad 是什么? Monad 是一种“包值 链操作 保持结构”的代码模式,用来处理带上下文的值,并方便连续处理。 …...
Idea连接远程云服务器上的MySQL,开放云服务器端口
1.开放云服务器的3306端口 (1)进入到云服务器的控制台 (2)点击使用的云服务器 (3)点击 配置安全组规则 (4)添加规则 (5)开放端口 2.创建可以远程访问…...
云服务器CVM标准型S5实例性能测评——2025腾讯云
腾讯云服务器CVM标准型S5实例具有稳定的计算性能,CPU采用采用 Intel Xeon Cascade Lake 或者 Intel Xeon Cooper Lake 处理器,主频2.5GHz,睿频3.1GHz,CPU内存配置2核2G、2核4G、4核8G、8核16G等配置,公网带宽可选1M、3…...
【Pytorch之一】--torch.stack()方法详解
torch.stack方法详解 pytorch官网注释 Parameters tensors:张量序列,也就是要进行stack操作的对象们,可以有很多个张量。 dim:按照dim的方式对这些张量进行stack操作,也就是你要按照哪种堆叠方式对张量进行堆叠。dim的…...
监控+日志=DevOps 运维的“千里眼”与“顺风耳”
监控+日志=DevOps 运维的“千里眼”与“顺风耳” 在 DevOps 体系中,监控和日志管理是不可或缺的运维基石。有人说,开发只管把代码写好,运维才是真正的“操盘手”,让系统稳定运行、不宕机、不崩溃。而要做到这一点,精准的监控与日志管理 是关键。 试想一下:如果没有监控…...
实战|使用环信Flutter SDK构建鸿蒙HarmonyOS应用及推送配置
本文为大家介绍如何在 Flutter 环境创建 Harmony 项目并集成环信即时通讯IM以及环信 Flutter Harmony 推送配置。 已经基于环信的 Flutter 项目也可以参考本文适配鸿蒙端。 一、开发环境要求 前置条件 1.安装DevEco-Studio 2.安装模拟器 DevEco-Studio 下载与操作指导&…...
构建知识体系
我认为,仅仅建立知识点之间的连接还不足够,还要建立自己的知识体系。 那么什么是知识体系呢? 知识体系,可以理解为立体的知识系统。 立体的知识系统,代表着跨越了多个领域、行业、学科的知识,是多个层面…...
Android Mainline简介
关键要点 Android Mainline 是通过模块化更新 Android 核心组件的框架,可能提高安全性。允许通过 Google Play 系统更新分发模块,无需完整固件更新。能简化厂商工作并减少碎片化,但覆盖范围有限。 什么是 Android Mainline? And…...
2026《数据结构》考研复习笔记二(C++面向对象)
C面向对象 一、类二、继承三、重载运算符和重载函数四、多态代码示例 一、类 1.1类&对象 class classname//class是关键词,classname是类名 { Access specifiers://访问修饰符:private/public/protected Date members/variables;//变量 Member fun…...
【C++】12.list接口介绍
在C标准库中,std::list 是一个基于双向链表实现的顺序容器,它支持高效的插入和删除操作,但无法直接通过下标进行随机访问。以下是关于 std::list 的简单介绍: 核心特性 底层结构 双向链表实现,每个节点包含数据、前驱指…...
决策卫生问题:考公考编考研能补救高考选取职业的错误吗
对于决策者来说,“认识你自己”是一个永恒的主题;警惕认知中的缺陷,比什么都重要。在判断与决策问题上,管理者和专业人士往往都非常自信。人类远远不如我们想象的那么理性,人类的判断也远远不如我们想象的那么完美。在…...