news 2026/10/6 7:21:43

DeepSeek RAG环境搭建:避开Embedding与向量库的坑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
DeepSeek RAG环境搭建:避开Embedding与向量库的坑

简介:这份基于DeepSeek搭建RAG系统的实战教程,面向需要落地检索增强生成应用的深度学习开发与运维人员,重点解决模型环境配置繁杂、GPU与容器工具链协调不畅等问题,核心技术栈涵盖CUDA、vLLM与Docker。文档从技术栈概要说起,按Dify服务器(ECS-1)、Rerank/Embedding模型服务器(ECS-2)、DeepSeek模型服务器(ECS-3)三部分展开部署路径,覆盖Ubuntu/CentOS环境配置、Tesla驱动与CUDA版本选择、xinference安装、bge-reranker-large与bge-large-zh-v1.5部署、vLLM安装以及Python相关依赖处理等环节。资源为单个docx文档,约580KB,以图文步骤和命令说明为主,便于对照操作与回溯检查。已有324人学习下载,适合刚接触RAG或需要快速搭建DeepSeek检索增强环境的读者作为入门到实操的参考。

1. DeepSeek RAG 环境搭建,卡人的不是 DeepSeek 而是 Embedding

基于 DeepSeek 搭建 RAG 系统,环境搭建这一步真正卡住人的,往往不是 DeepSeek 本身,而是它没有开放 Embedding 接口。很多人照着“调用 API”的教程走,聊得很顺,一到检索问答就发现文档拼不进去。这篇教程讲的是从一台干净机器开始,把 Python 虚拟环境、文本拆分工具、本地 Embedding 模型、向量库和 DeepSeek 接口一次性装齐,跑通一个能回答私有文档问题的最小 RAG 系统。适合零基础想本地跑知识库的读者,也适合要快速做技术验证的一线开发者。先说预期:按这套走,30 到 60 分钟能把环境搭完,后面每一层我都给了参数和踩坑记录。

2. 先选路线再装包:DeepSeek 访问方式与 RAG 依赖环境

2.1 API 还是本地部署:两条路线怎么选

环境搭建的第一步不是敲命令,而是决定 DeepSeek 以什么形态出现在你的 RAG 系统里。这决定了后续依赖装什么、显存要多大、接口怎么配。

市面上常见的做法是分两条路线。第一条是官方 API 路线,直接调用 DeepSeek 的在线接口,模型是 deepseek-chat 或 deepseek-reasoner,你的机器只需要跑检索和 Embedding,负担很小,普通笔记本就能撑起来。第二条是本地部署路线,用 Ollama 或 vLLM 把开源模型跑在自己机器上,适合隐私敏感或需要离线运行的场景,代价是显存和推理速度。两者对 RAG 框架本身没有区别,因为 DeepSeek 的 API 兼容 OpenAI 协议,本地部署也几乎都暴露成同一套接口。

我给你的建议是:如果是第一次搭,或者只是做技术验证,直接走官方 API。原因很实在——环境搭建的不可控因素已经够多了,别再让大模型推理层添乱。等 RAG 链路跑通、确认检索质量没问题,再考虑把底层模型换成本地部署,这时候改动只是换一个 base_url 和 model 名的事。下面的依赖清单也是按“API + 本地检索”的组合来配的。

2.2 Python 虚拟环境与依赖清单:一把装齐

RAG 环境对 Python 版本有硬性要求,我建议用 3.10 到 3.12 之间的版本,太老或太新都会碰到依赖兼容问题。装包之前先建虚拟环境,别直接装进系统 Python,否则 LangChain、Chroma、SentenceTransformer 这几个库的依赖打架时,你会连项目目录都不敢删。

mkdir -p rag-workspace && cd rag-workspace python -m venv .venv source .venv/bin/activate # Windows 下用 .venv\Scripts\activate pip install --upgrade pip pip install "langchain>=0.3,<0.4" \ "langchain-community>=0.3,<0.4" \ "langchain-openai>=0.3,<0.4" \ "langchain-text-splitters>=0.3,<0.4" \ "chromadb>=0.5,<0.6" \ "faiss-cpu>=1.9,<2.0" \ "sentence-transformers>=3.0,<4.0" \ "pypdf" "python-docx" "openpyxl" \ "python-dotenv"

这里每个包都不是随手装的。langchain 是 RAG 编排框架,langchain-openai 是 DeepSeek 接口的接入层,因为 DeepSeek 兼容 OpenAI 协议,直接用这个包就能调;langchain-text-splitters 在 0.3 版本被独立拆出来了,不装会报缺失;chromadb 负责向量存储,faiss-cpu 是备选的向量检索库;sentence-transformers 用来跑本地 Embedding 模型;pypdf、python-docx、openpyxl 分别处理 PDF、Word 和 Excel 三种最常见的知识库文件格式。最后那个 python-dotenv 是给 API Key 用的,不建议把 Key 写死在代码里。

装完验证一下环境是否完整,跑一个最简导入:

python -c "from langchain_openai import ChatOpenAI; from langchain_community.vectorstores import Chroma; from sentence_transformers import SentenceTransformer; print('ok')"

这条命令能一次确认三个核心组件都可用。如果报错,优先看是什么包导入失败,再针对那个包单独重装,不要一上来就全部卸载重来。

2.3 配置 DeepSeek 接口:Key、base_url 与 .env

环境装完,先把 DeepSeek 接口配好,这样后面每一步调试都能确认“大模型侧是通的”。在 rag-workspace 下创建一个 .env 文件,内容如下:

DEEPSEEK_API_KEY=sk-你的密钥 DEEPSEEK_BASE_URL=https://api.deepseek.com DEEPSEEK_MODEL=deepseek-chat

注意 base_url 不要随手加 /v1 后缀。DeepSeek 官方文档给的地址是 https://api.deepseek.com,加了 /v1 在部分 SDK 版本里也能通,但没必要给自己留一个可以避免的不确定因素。model 建议先用 deepseek-chat,它是通用对话模型,RAG 问答场景足够;deepseek-reasoner 是推理模型,回答更慢,适合后面做复杂问题进阶时再换。

写一段代码验证接口连通性,顺便把读取 .env 的习惯建立起来:

import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI load_dotenv() llm = ChatOpenAI( model=os.getenv("DEEPSEEK_MODEL", "deepseek-chat"), api_key=os.getenv("DEEPSEEK_API_KEY"), base_url=os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com"), temperature=0.3, ) resp = llm.invoke("用一句话说明什么是 RAG") print(resp.content)

这里重点说明两个参数。temperature 我习惯设 0.3,RAG 场景要求回答紧贴知识库内容,温度太高容易让模型自由发挥,编出知识库里没有的东西;base_url 是这次环境搭建里最容易翻车的点,后面避坑章节会专门展开。把能跑通这一小段作为环境搭建的第一里程碑,比直接冲 RAG 全链路稳妥得多。

3. 给 RAG 配好“检索引擎”:Embedding 模型与向量库的选型落地

3.1 为什么必须自备 Embedding:DeepSeek 不提供文本向量接口

做 RAG 环境搭建时,很多人会默认“DeepSeek 既然是大模型,向量化肯定也一并搞定”。这是最大的误解。DeepSeek 官方 API 目前不提供 Embedding 接口,你没法把一段文本丢给 DeepSeek 换回一串向量。这个缺口必须用本地 Embedding 模型补上。

RAG 的检索链路本质上是“文本向量化 + 相似度计算”。知识库里的文档先被切块,每一块转换成向量存进向量库;用户提问时,问题也被转成向量,到向量库里找最相似的几个片段,拿这些片段当上下文交给大模型。换句话说,Embedding 模型决定了“什么内容算相似”,大模型只负责“基于相似内容组织回答”。Embedding 这层选不好,RAG 的瓶颈会直接卡在召回上,上下文拼错,后面大模型再强也白搭。

选择 Embedding 模型时,中文场景我第一推荐是 BAAI/bge-m3。它的优势有三个:中文效果稳定、支持最长 8192 token 的输入、输出 1024 维向量,在检索精度和资源消耗之间比较均衡。如果机器配置较差,可以退一步用 bge-small-zh-v1.5,速度快很多,精度损失在可接受范围内。千万不要用 word2vec 或者 TF-IDF 来做 RAG 检索,那两种方法处理不了语义匹配,换个说法问同一个问题就查不到。

3.2 用 bge-m3 提供本地向量能力:加载与调用

bge-m3 的加载方式有两种。走 Hugging Face 的缓存路径,第一次需要下载模型文件;走 ModelScope(魔搭)的路径则适合国内网络环境。我先给 Hugging Face 的标准做法,后面避坑章节会讲国内下载的替换方案。

from sentence_transformers import SentenceTransformer import torch model_name = "BAAI/bge-m3" device = "cuda" if torch.cuda.is_available() else "cpu" model = SentenceTransformer(model_name, device=device) texts = [ "环境搭建需要哪些组件", "RAG 的瓶颈通常在检索召回而不是生成", ] embeddings = model.encode(texts, normalize_embeddings=True) print(embeddings.shape)

这段代码里有几个参数是必须注意的。第一,device 的判断要放在加载模型之前,bge-m3 在 CPU 上也能跑,但第一次加载和推理会明显偏慢;有 NVIDIA 显卡就优先走 cuda。第二,encode 时 normalize_embeddings=True 必须开,这决定了向量是否归一化,后面向量库做内积计算时,归一化过的向量等价于余弦相似度,否则检索结果会和预期差很远。第三,bge-m3 默认输出 1024 维向量,打印 shape 是 (2, 1024) 就说明模型加载成功。

如果你走 ModelScope 下载,代码要稍作调整,先下载再指定本地路径加载:

from modelscope import snapshot_download model_dir = snapshot_download("BAAI/bge-m3", local_dir="./models/bge-m3") model = SentenceTransformer("./models/bge-m3", device=device)

ModelScope 在国内访问稳定,第一次下载时优先考虑这条路。下载完成后,以后启动项目直接指定本地路径,不再触发网络请求,离线也能跑。这个细节很重要,因为 Embedding 模型加载失败是 RAG 环境搭建里最高频的卡点之一。

3.3 向量库选型:Chroma 起步,FAISS 提速

向量库是 RAG 环境的存储层,负责存放文档向量并提供相似度检索。选型不需要纠结太久,我直接给你一个判断框架:个人项目和技术验证用 Chroma,数据量大、要上生产再考虑 Qdrant 或 Milvus。

向量库启动方式适合阶段持久化形式
Chroma进程内运行,零部署个人项目、原型验证本地目录文件
FAISSPython 库直接调用单机百万级向量以内需自行管理索引文件
QdrantDocker 容器生产级、需要 HTTP 服务磁盘映射
MilvusDocker Compose 集群企业级、亿级向量分布式存储

我个人的偏好是:刚开始一律 Chroma,没有之一。它不需要单独起服务,代码里指定一个目录就能持久化,重启不丢数据,对“把 RAG 跑起来”这个目标来说性价比最高。FAISS 更适合批量检索、对速度和内存占用敏感的场景,但它没有开箱即用的持久化方案,索引文件要自己存自己读,入门阶段容易搞乱。

Chroma 的持久化初始化方式如下:

import chromadb client = chromadb.PersistentClient(path="./chroma_db") collection = client.get_or_create_collection( name="knowledge_base", metadata={"hnsw:space": "ip"}, ) print(collection.count())

这里两个参数要解释。PersistentClient 的 path 是向量数据落盘目录,我习惯放在项目根目录下的 chroma_db 文件夹里,这样备份整个项目时向量库也跟着走。collection 的 metadata 里 hnsw:space 设成 ip(内积空间),配合前面 bge-m3 做过的向量归一化,检索时算的就是余弦相似度,这是官方推荐的中文检索组合。count() 返回 0 说明 collection 建好了,可以开始灌数据。

如果你的知识库文档量级在一万份以内,Chromapath 完全够用;等涨上去再迁 Qdrant,迁移逻辑在后面章节的代码里本来就是抽象出来的,改动成本不大。不要在环境搭建阶段就上一套分布式向量库,那是把复杂度提前预支给自己。

4. 跑通最小 RAG 闭环:DeepSeek API + 本地知识库的完整链路

4.1 RAG 链路拆解与目录规划

环境搭好、Embedding 就绪,接下来把整个 RAG 链路串起来。完整的 RAG 系统包含五个环节:加载文档、切分文本、向量化入库、检索命中、拼接上下文交给大模型问答。前三个属于离线流程,后两个属于在线流程。环境搭建阶段要做的是让这五个环节能在一台机器上顺序跑通,不需要一开始就追求工程化,先把链路走通,再谈优化.

我习惯按下面的目录结构组织一个最小项目,方便区分数据和代码:

rag-workspace/ ├── .env ├── docs/ # 原始知识库文档,放 PDF / TXT / Word ├── data/chroma_db/ # Chroma 持久化目录 ├── models/bge-m3/ # 本地 Embedding 模型 └── src/ ├── ingest.py # 离线:加载、拆分、入库 └── query.py # 在线:检索 + 问答

docs 目录放你的知识库原始文件,建议先放一两份真实的业务文档测试,别用网上的通用文本——检索效果好不好,只有用自己领域的内容才能看出来。ingest.py 跑一次,把文档内容变成向量存进 chroma_db;query.py 负责接收问题、查库、调 DeepSeek。两个脚本一个数据目录,这是最小但五脏俱全的形态。

4.2 文档加载与拆分:先解决文本入口

文档加载是环境搭建里最容易被低估的一步。很多项目搭完环境、入库跑通,一查检索结果全是乱序,问题就出在拆分参数上。我先给加载和拆分的完整代码:

from pathlib import Path from langchain_community.document_loaders import PyPDFLoader, TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter docs_dir = Path("docs") raw_docs = [] for path in docs_dir.iterdir(): if path.suffix.lower() == ".txt": raw_docs.extend(TextLoader(str(path)).load()) elif path.suffix.lower() == ".pdf": raw_docs.extend(PyPDFLoader(str(path)).load()) print(f"加载了 {len(raw_docs)} 份文档") splitter = RecursiveCharacterTextSplitter( chunk_size=800, chunk_overlap=120, separators=["\n\n", "\n", "。", "!", "?", " ", ""], keep_separator=True, ) chunks = splitter.split_documents(raw_docs) print(f"拆分出 {len(chunks)} 个片段")

这段代码解决了“文本入口”问题,我逐个参数说明。chunk_size=800 表示每个片段最多 800 字符,这是中文 RAG 的常用起步值,既能保住语义完整,又不会让上下文太长;chunk_overlap=120 让相邻片段有 120 字符重叠,防止答案正好被切在片段边界上;separators 里的顺序很关键,从“段落换行”到“句号”再到“空格”,递归拆分时会按这个优先级寻找断开点,中文文本里把“。”放在“\n”之后,能有效避免把一句话腰斩。keep_separator=True 保留分隔符在片段末尾,对后续检索拼接有好处。

顺带解决一个很多人纠结的问题:知识库能不能存图片?文本 RAG 链路接不了图片本身,PDF 里的插图如果不做 OCR 转文本,检索时只会跳过。环境搭建阶段先规划好:图片类知识要么先转成文本描述,要么等后续接入多模态管线,这不是当前这套环境能覆盖的范围。

4.3 检索与问答:把命中片段交给 DeepSeek

文档入库后,查询脚本要做三件事:给问题向量化、到向量库取 Top-K 片段、把片段拼进 Prompt 交给 DeepSeek。先说入库代码,这是 ingest.py 的后半段:

from langchain_core.embeddings import Embeddings from langchain_community.vectorstores import Chroma class BgeM3Embeddings(Embeddings): def __init__(self, model): self._model = model def embed_documents(self, texts): return self._model.encode(texts, normalize_embeddings=True).tolist() def embed_query(self, text): return self._model.encode([text], normalize_embeddings=True).tolist()[0] embedder = BgeM3Embeddings(model) vectorstore = Chroma.from_documents( documents=chunks, embedding=embedder, persist_directory="./data/chroma_db", )

为什么需要这个 BgeM3Embeddings 包装类?因为 LangChain 的 Chroma 接口要求 Embedding 对象实现 embed_documents 和 embed_query 两个方法,而 sentence-transformers 的 SentenceTransformer 本身不兼容这个协议,所以必须包一层。注意 embed_query 和 embed_documents 的处理路径略有不同:查询向量只需要对单条文本编码,返回一维向量;文档向量则按批量编码。代码里 normalize_embeddings=True 保持和前面一致,保证向量空间相同。

查询端代码同样简洁:

import os from dotenv import load_dotenv from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate load_dotenv() retriever = vectorstore.as_retriever(search_kwargs={"k": 4}) llm = ChatOpenAI( model=os.getenv("DEEPSEEK_MODEL", "deepseek-chat"), api_key=os.getenv("DEEPSEEK_API_KEY"), base_url=os.getenv("DEEPSEEK_BASE_URL", "https://api.deepseek.com"), temperature=0.3, ) prompt = ChatPromptTemplate.from_template( "请根据以下知识库片段回答问题。如果片段中没有答案,就明确说不知道。\n" "片段如下:\n{context}\n\n问题:{question}" ) def answer(question: str): hits = retriever.invoke(question) context = "\n\n".join([hit.page_content for hit in hits]) chain = prompt | llm return chain.invoke({"context": context, "question": question}).content

search_kwargs={"k": 4} 表示每次检索取 4 个片段,这是环境验证阶段的合理值。片段太少容易漏答案,太多会把无关内容塞给模型,还浪费 token。Prompt 里那句“没有答案就明确说不知道”必须加,它能抑制大模型在信息不足时自由发挥,这是 RAG 问答和普通聊天最重要的区别。跑一遍 answer("你的知识库里某份文档的核心结论是什么"),如果能引用到对应片段并给出符合文档原意的回答,说明环境搭建已经完整走通。

5. 环境搭建避坑清单:5 个高频翻车现场与排查方法

5.1 langchain 版本冲突导致 import 崩溃

现象是 pip install 一切顺利,但一 import langchain 就抛 AttributeError 或者 pydantic 相关的报错,错误栈往往指向 langchain_core 内部。原因是 LangChain 0.3 要求 pydantic 2.x,而某些第三方包或者旧缓存会把 pydantic 锁在 1.x,两个版本共存时直接炸掉。解决方法是先看错误栈最后一行,确认是哪个包冲突,然后执行 pip install -U "pydantic>=2.0" "langchain>=0.3,<0.4" 强制对齐版本。如果还不行,直接把虚拟环境删了重建,重新按第 2 章的依赖清单装,别在原环境里硬修。这个坑几乎每个新项目都会遇到一次,不值得花太多时间。

5.2 没写 base_url,请求默认打到了 OpenAI

现象是调用 DeepSeek 时返回 401 unauthorized,或者明确提示 model 不存在。原因是 ChatOpenAI 这个类默认 base_url 指向 OpenAI 的地址,你如果忘了传 base_url 参数,SDK 会把 deepseek-chat 当成 OpenAI 的模型名去请求,自然被拒。解决方法是每次初始化时显式传 base_url=os.getenv("DEEPSEEK_BASE_URL"),不要依赖默认值。我踩过一次之后养成了习惯:所有兼容 OpenAI 协议的国产模型,base_url 一律写进 .env,代码里显式读取。这个坑不会报错提示你“地址错了”,它只会给你一个让人摸不着头脑的 401。

5.3 Embedding 模型下载卡死

现象是第一次执行 SentenceTransformer("BAAI/bge-m3") 时进度条永远停在某个百分比,或者直接报连接超时。原因是模型权重托管在 Hugging Face,国内直连不稳定。解决方法是优先切换到 ModelScope 下载,按第 3 章的 snapshot_download 方式拉取到本地目录,然后直接用 SentenceTransformer("./models/bge-m3") 加载本地路径。如果必须走 Hugging Face,可以设置环境变量 HF_ENDPOINT 指向国内可访问的镜像站,但镜像的可用性会变化,ModelScope 更稳定。记住一点:模型下载成功后,加载路径就固定用本地目录,别再依赖在线缓存。

5.4 入库“成功”但检索永远为空

现象是 Chroma 的 add 没有报错,count() 也显示有数据,但检索时 hits 为空或者返回完全不相关的内容。原因有两类:一类是 encode 时忘了 normalize_embeddings=True,向量没有归一化,而 collection 的 hnsw:space 设的是 ip,相似度计算全乱;另一类是混合用了两套 Embedding 模型,入库时用一个模型,检索时换了另一个,两个模型的向量空间根本不兼容。解决方法是先确认代码里所有 encode 调用都带 normalize_embeddings=True,再确认入库和查询用的是同一个模型实例或同一路径。排查时可以随手打印一条检索回来的片段原文,比对是否和文档内容沾边,别只看有没有返回结果。

5.5 上下文超长,DeepSeek 返回空响应

现象是检索正常、拼接正常,但调用 DeepSeek 时返回空字符串或者报输入超限。原因是 k 值太大、chunk_size 又设得高,拼出来的 context 超出了模型上下文窗口,或者正好顶到边界被截断。解决方法是先打印 len(context) 看实际 token 规模,把 k 从 4 降到 3,或者把 chunk_size 从 800 调到 500。我见过最极端的案例是 k=10、chunk_size=1200,拼出来的上下文快两万字符,模型直接罢工。RAG 不是给模型喂越多越好,控制在刚好能覆盖答案的范围内才是正解。

6. 验证 RAG 检索效果,并把 DeepSeek 换成本地推理

先做效果验证再做部署升级,这个顺序别颠倒。最快的验证方法是拿知识库里一段原话去提问,打印检索命中的片段原文,看它是否真的包含答案内容:

hits = retriever.invoke("你的测试问题") for idx, hit in enumerate(hits): print(idx, hit.page_content[:80])

如果命中的片段和问题语义对得上,再进行第二步:同一个问题,分别用不带上下文的直答和带上下文的 RAG 回答做对比。直答版本经常会给一个“看起来合理但细节错误”的答案,RAG 版本必须能引用到知识库里的具体表述。第三步是调参验证,chunk_size 分别试 400、800、1200,k 试 3 和 5,记录哪组参数下答案最稳定。调参时只动一个变量,别同时改两处。

验证通过后,如果你有足够显存想换成完全本地部署,两条路都行。Ollama 适合快速替换,一条命令拉模型再起服务:

ollama pull deepseek-r1:7b ollama serve

然后把 ChatOpenAI 的 base_url 换成 http://localhost:11434/v1,model 换成 deepseek-r1:7b,其余代码不用动。要更高吞吐就上 vLLM:

vllm serve deepseek-ai/DeepSeek-R1-Distill-Qwen-7B --host 0.0.0.0 --port 8000

同样只改 base_url 和 model,RAG 链路完全复用。本地部署 7B 级模型建议至少 16GB 显存,显卡不够就别硬上,API 路线在验证阶段其实更划算。

我现在的习惯是每次新项目都把 chunk_size=800、k=4、temperature=0.3 当作基线跑一遍,再按验证结果调整。这套环境搭建流程我重复过很多次,最深的教训是:一切异常先查 Embedding,再查向量库,最后才查大模型接口——绝大多数翻车都发生在检索侧。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/6 7:20:29

XC7A100TFGG484 FPGA DDR3硬件设计实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 7:20:27

SFP+接口深度解析:从引脚定义到10G网络硬件设计实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 7:20:14

电荷泵升压电路原理、五种拓扑对比与选型维修指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 7:19:34

DDR4内存SPD自定义与稳定性验证:从参数填写到压测排查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 7:19:34

ThinkPad T470p电源适配器功率不足?静电释放与排查全指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 7:18:13

ESP32-P4+ESP32-C5双芯驱动带屏智能家居网关:架构设计与实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华