news 2026/10/20 8:36:47

Docker基础入门:镜像、容器与Dockerfile实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker基础入门:镜像、容器与Dockerfile实战解析

1. 从“环境地狱”说起:为什么第一课一定是Docker

我第一次接触Docker,是在一个极其狼狈的下午。当时我接到一个任务,要把一套内部系统从老服务器迁移到新环境,依赖里有一个老版本的数据库驱动和一个特定版本的编译工具链。新机器上装了最新版驱动,系统直接起不来,我又不敢乱动生产环境,只能在两台机器之间来回折腾环境变量、动态库冲突,折腾了整整两天。后来一个前辈看着我说:“你用容器把环境一起搬过去不就好了?”那是我第一次听到Docker这个名字。

现在回头看,Docker解决的就是一个非常朴素但极其致命的问题:环境不一致导致的“在我机器上能跑”。你的代码在本机一切正常,交给同事跑就报错,部署到服务器直接崩溃。原因基本都一样——操作系统版本不同、依赖库版本不同、路径配置不同、系统变量不同。Docker的思路很直接:把代码和它运行所需要的一切环境,打包成一个独立的单元,这个单元在任何装了Docker的机器上,表现完全一致。

所以Task 01这个课时,别看它叫“基础知识”,它其实是整个容器学习路线的地基。这节课如果只理解了一个点,那就要理解“镜像”和“容器”这两个词。很多人学了半天Docker,命令背得滚瓜烂熟,但问起“镜像和容器到底啥区别”还是一脸懵,后面排障就容易绕弯子。

这篇内容我会按我自己的学习路径来梳理,把那些文档里讲得不够白话、也不够到位的坑都补上。适合三类人看:刚从学校出来准备进互联网行业的新人、正在做本地开发但经常被环境折腾的开发者、以及刚开始接触CI/CD流程、想搞清楚部署链路里容器到底扮演什么角色的同学。

注意:理解Docker的关键不是背命令,而是理解它“分层打包、一次构建、到处运行”的设计思路。命令只是思路的落地形式。

2. 核心概念先搞明白,再动手指

2.1 镜像、容器与仓库:最容易混淆的三件套

我看过不少新手教程,上来就让人敲 docker pull nginx、docker run nginx,敲完看到一堆输出就觉得学会了。但我建议你先停下来,把三个词的关系理顺。

镜像是一个只读的模板,里面包括了你应用运行需要的操作系统基础层、运行环境、代码文件、依赖库、环境变量配置。你可以把它理解成做蛋糕用的模具——它定义了最终的形态,但本身不变化。

容器是镜像运行起来之后的实例。同一个镜像可以同时跑出多个容器,彼此之间相互独立。还是拿蛋糕举例:同一个模具,倒进去不同的面糊,烤出来的蛋糕可以有不同口味;你甚至可以同时烤两炉,互不干扰。容器就是那个“烤出来的蛋糕”,是一个活生生的、正在运行的进程环境。

仓库用来存放和分发镜像,类似代码里的Git仓库。你可以在本地构建镜像,然后推送到仓库,其他人再拉下来使用。

这里有个最容易被忽略的细节:镜像层是共享的,但容器层是独立的。Docker用分层文件系统来管理镜像,每一层记录一次变更,多个镜像可以共享相同的底层。比如你基于同一个基础镜像构建了三个不同的应用镜像,基础层在本地磁盘上只存一份,不会重复占用三倍空间。而容器在镜像之上加一层可写的容器层,所有运行时的改动,比如写入临时文件、修改配置,都在这一层完成,镜像本身不受影响。

想验证这个特性很简单。你运行一个容器,在里面创建一个文件,退出后用docker commit把这个容器提交成新镜像,再去对比新镜像和旧镜像的大小,你会发现新镜像只多了你修改那一层的体积。这个机制也是后面学习Dockerfile多层构建时必须要理解的底层逻辑。

2.2 为什么Docker能跨机器跑起来

很多人第一次听到Docker时会有一个疑问:难道它不依赖操作系统吗?其实它依赖,只是它把这份依赖一起打包了。

传统部署方式里,你的程序依赖于宿主机的操作系统、系统库、运行时版本。而Docker镜像里自带了一个精简的OS用户态文件系统,比如常见的基于Debian或Alpine的基础镜像,再加上应用运行所需的一切依赖。当容器启动时,它直接使用这个文件系统作为自己的根文件系统,宿主机内核被共享,但用户态的所有内容都是自带的。

这就意味着你在本机用的是Ubuntu,服务器是CentOS,只要内核版本满足要求,镜像不需要做任何改动就能正常运行。这种“用户态完全自包含”的设计,是Docker能够实现跨环境一致性的根本原因。

但这里有一个必须提前说清的边界:Docker并不适合做跨内核的虚拟化。比如你在Windows上跑Linux容器,实际上是借助了虚拟化层;在Mac上也是类似。真正生产环境中容器和宿主机是共享同一个内核的,如果你的应用对特定内核模块有依赖,容器没法帮你解决内核问题。理解这一点,后面遇到Hyper-V、WSL2相关的问题就不会懵。

2.3 默认网络模式与端口映射的逻辑

学完镜像和容器,紧接着就需要处理“容器里的服务怎么让外部访问”这个问题。

默认情况下,容器有自己独立的网络命名空间,相当于一个与宿主机隔离的网络环境。你可以把容器想象成一个独立的迷你主机,它有自己内部的IP地址,宿主机上的其他进程默认访问不到它。

想让外部访问容器里的服务,就要做端口映射。命令是:

docker run -d -p 8080:80 nginx

这个命令的意思是:把宿主机的8080端口,映射到容器内部的80端口。外部请求访问宿主机的8080时,Docker会自动把流量转发到容器的80端口。

端口映射的概念学起来不难,实际操作中的坑主要集中在两点。

第一,端口冲突。宿主机上的8080已经被别的进程占用时,启动容器会直接报错,告诉你bind: address already in use。好一点的排查习惯是启动前先用netstat或lsof确认端口空闲,而不是等报错了再手忙脚乱地去找占用的进程。

第二,映射关系搞反。我刚才见过一个同事实习生,配完端口映射后访问不通,排查了半天才发现他把参数写成了 -p 80:8080,意思是把宿主机的80映射到容器的8080,而容器里监听的一直是80端口,那当然不通。写端口映射时记住一个口诀:左边宿主机,右边容器内。

3. 环境准备与镜像拉取的完整实操

3.1 本机安装Docker的三种方式选择

这一节直接进实操。安装Docker的环境不同,选型思路也不同,我做一次完整梳理。

Linux环境(最常见于服务器和开发机)——推荐直接用官方提供的安装脚本或包管理器安装。以Debian/Ubuntu系为例:

sudo apt update sudo apt install -y docker.io sudo systemctl enable docker sudo systemctl start docker

注意版本要确认一下,apt仓库里的docker.io版本可能滞后,如果你需要跑新版特性,建议先添加官方源再安装。生产环境我习惯固定某个已知稳定的版本,避免自动升级引入不兼容问题。

Windows环境——现在主流是Docker Desktop + WSL2。早期我用过Docker Toolbox,那个是基于VirtualBox的方案,性能很差,文件挂载的时区、路径问题也多,现在基本被淘汰了。装上Docker Desktop之后,Settings里确认Use WSL 2 based engine这个选项开启,性能表现会好很多。

macOS环境——直接装Docker Desktop即可。同样的,文件挂载和端口映射都是在它的虚拟机层里做的,初始化之后首次启动镜像拉取可能要一些时间,属于正常现象。

安装完的验证动作是:

docker --version docker info

docker info的输出里可以看到Docker运行模式、存储驱动、镜像数量等关键信息。如果docker info能正常打印信息,说明Docker引擎已经跑起来了。

3.2 拉取镜像时关于镜像源的那点事

国内网络环境下首次拉取镜像经常会遇到超时,这不是你的操作有问题,而是镜像仓库的网络链路问题。Docker默认从Docker Hub拉取镜像,很多情况下需要配置镜像加速器。

配置方法很直接。在Docker配置文件里加上registry-mirrors字段:

{ "registry-mirrors": ["https://your-mirror-url"] }

Linux位置在/etc/docker/daemon.json,Windows和macOS在Docker Desktop的Settings里配置,配置完成之后重启Docker服务生效。

配置好之后,拉一下官方示例镜像:

docker pull hello-world docker run hello-world

你会在控制台看到一段欢迎语。这个镜像极其小,内部就一个打印程序,用来验证你的整套链路是否通畅。我到现在还记得第一次跑通时的感觉——原来一个环境就是这样一个文件系统层面的快照,被快速打包、传输、执行了。

3.3 常用镜像操作命令清单

说实话,用Docker不需要把命令表全背下来,但基础操作要形成肌肉记忆。这里列一份我在日常开发中出镜率极高的清单,按使用频率排序:

# 搜索镜像 docker search nginx # 拉取镜像,不写tag默认拉latest docker pull nginx:1.25 # 查看所有镜像 docker images # 查看所有运行中的容器 docker ps # 查看所有容器,包括已停止的 docker ps -a # 运行容器并保持前台运行,退出即停止 docker run -it ubuntu bash # 后台运行容器 docker run -d --name my-app nginx # 进入正在运行的容器内部 docker exec -it my-app bash # 停止、启动、重启容器 docker stop my-app docker start my-app docker restart my-app # 删除容器,加-f可以强制删除运行中的容器 docker rm my-app # 删除镜像 docker rmi nginx

这里有两个新手高频踩坑点。

第一,docker run和docker start的区别。run是创建并启动一个新容器;start是启动一个已经存在的、处于停止状态的容器。很多人以为stop之后再run是“继续运行刚才那个容器”,结果发现创建了一个新实例,之前容器里改的文件都不在了。

第二,docker exec进容器后,默认用户可能是root。这方便但不安全,你在容器里改了系统的关键配置,一旦容器被删除,这些改动全部丢失。这也是我强调“容器是临时状态”的原因——真正需要持久化的数据或者配置,用下一节要讲的挂载或者Dockerfile来管理,而不是手动进容器改。

4. Dockerfile:把环境固化到代码里

4.1 一个最小可用的Dockerfile长什么样

上一节讲的命令操作都是“用现成镜像”,真实项目里的镜像通常需要自己定制。Dockerfile就是这个定制过程的蓝图,它用声明式语法描述每一步构建行为。

拿一个最简单的Node.js应用举例。假设项目目录里有一个app.js文件,那么Dockerfile可以这样写:

# 基于官方Node 18镜像,版本不写默认latest FROM node:18-alpine # 设置工作目录,后续命令都在这个目录下执行 WORKDIR /app # 把本地的package.json拷贝到镜像里 COPY package.json ./ # 安装依赖 RUN npm install # 把项目其他文件拷贝进镜像 COPY . . # 容器对外暴露3000端口 EXPOSE 3000 # 容器启动时执行的命令 CMD ["node", "app.js"]

构建并运行:

docker build -t my-node-app . docker run -d -p 3000:3000 my-node-app

访问http://localhost:3000,就能看到你的应用在容器里正常运转。

这个例子麻雀虽小,五脏俱全。FROM、WORKDIR、COPY、RUN、EXPOSE、CMD这六个指令,已经是日常开发中80%的Dockerfile构成。接下来说几个关键点。

4.2 指令的执行逻辑与层缓存机制

构建Dockerfile时,每一行指令都会生成一个新层。比如RUN npm install执行之后,这一层会缓存下来。下次构建如果前面的层没有变化,Docker会直接复用缓存层,只有变化的层及其后续层才会重新执行。

这个机制用得好,构建速度快很多;用不好,会成为日常开发中最烦人的问题。我见过一个项目,把COPY . .写在RUN npm install之前,结果每改一次代码,整个依赖安装步骤都要重新跑一遍,拉一个构建白白多花好几分钟。

要想用好缓存机制,原则很简单:把变化频率低的指令放前面,变化频率高的放后面。先COPY package.json、再RUN npm install、最后COPY . .,就是最常见的缓存友好写法。这样改业务代码不会触发依赖层重新构建。

还有一点,RUN指令里尽量合并执行,减少层级数量。比如:

RUN apt-get update && \ apt-get install -y curl vim && \ rm -rf /var/lib/apt/lists/*

为什么要合并?每多一层,镜像体积就多一分冗余,仓库存储和拉取速度都会受影响。上面的rm -rf清理是为了防止缓存文件留在镜像里,一句话:层数越少、镜像越瘦,构建和分发越快。

4.3 环境变量与动态参数传递

容器里配置环境变量有两个地方。

第一是写在Dockerfile里:

ENV NODE_ENV=production ENV APP_PORT=3000

第二是在运行容器时通过-e参数临时覆盖:

docker run -d -p 3000:3000 -e NODE_ENV=development my-node-app

这个优先级关系要清楚:运行时的-e参数会覆盖Dockerfile里的ENV。

我建议把容易变化的配置,比如数据库地址、外部服务密钥等,放到运行时通过-e传递,或者用后面会提到的env_file文件管理。这样可以避免把敏感信息写死在镜像里。把密钥写进镜像这个问题,对新手来说几乎人人踩坑,有人把密钥写进Dockerfile,后来镜像推到公共仓库,等于把密钥公开了。血的教训。

4.4 .dockerignore不能省

和.gitignore类似,Docker构建时会把构建上下文整个打包发送给Docker守护进程。如果你的项目里有一堆node_modules、.git目录、日志文件、临时文件,这些也会被一并打包进构建上下文,导致构建速度慢、镜像体积大。

解决办法是在项目根目录建一个.dockerignore文件:

node_modules .git *.log .tmp Dockerfile .dockerignore

这里面有个特别容易被忽略的坑:被.dockerignore排除的文件,即使Dockerfile里写了COPY也拷贝不进去。如果你发现容器里缺少某个文件,第一件事去看这个文件是不是命中了ignore规则。我为了这个问题排查过一个多小时,最后发现就是.dockerignore里误写了一个目录名匹配规则,把整个src目录都干掉了。

5. 数据管理与持久化的正确姿势

5.1 容器里文件为什么不能直接存

容器被删除后,容器层里所有的文件改动都会消失。这条规则对很多新人来说违背直觉——明明在容器里创建了文件,看起来还在,为什么换个容器就没了?

原因在于容器层是临时的、生命周期与容器绑定的。你手动创建的配置文件、日志、上传的文件,如果不做持久化,全部随容器销毁而消失。

真实项目中需要持久化的数据主要是三类:应用产生的用户数据、日志输出、需要预先放入的配置文件。这三类都用挂载来解决。

5.2 挂载的三种方式对比

第一种:绑定挂载(Bind Mount)。把宿主机的一个目录/文件直接挂载到容器内路径。

docker run -d -p 3000:3000 \ -v /host/app-data:/container/app-data \ my-node-app

这种方式好处是宿主机直接能改数据,适合开发调试时改配置即时生效。坏处是宿主机与容器的耦合变强了,迁移不太方便。

第二种:数据卷(Volume)。Docker自己管理的一块存储区域,宿主机上的具体位置对用户透明。

docker run -d -v app-data:/var/lib/data my-node-app

数据卷不依赖宿主机特定路径,跨机器迁移方便,是生产环境里持久化数据的首选。它由Docker引擎接管,通过docker volume ls可以查看和管理。

第三种:tmpfs挂载。数据写入内存中,容器停止后数据即消失。适合放临时文件、不重要的缓存。

三者的选择逻辑不复杂:重要的、需要备份的数据用卷;开发期需要和宿主机互通的配置用绑定挂载;临时性数据用tmpfs。

5.3 数据卷操作速查

# 创建卷 docker volume create my-data # 查看所有卷 docker volume ls # 查看卷详情 docker volume inspect my-data # 删除未使用的卷 docker volume prune

我踩过的一个很实际的坑:运行容器时没写卷挂载,后来想给这个容器加数据卷,发现容器一旦创建就不能再挂载了。正确做法是删除容器,用新的命令重建。容器可以删,卷可以保留,只要卷名不变,数据就不会丢。

docker rm my-container docker run -d --name my-container -v my-data:/var/lib/data my-node-app

整个过程看起来是“重建”,但数据安然无恙。这也是容器理念里一个微妙的点——容器本身是瞬态的,数据才是需要长期关心的东西。

6. 网络模式与容器间通信

6.1 四类网络模式怎么选

Docker的默认网络是一个特殊的虚拟网桥。除了默认网络,还支持以下几种模式:

网络模式说明适用场景
bridge默认模式,容器通过虚拟网桥与宿主机通信单机多容器部署
host容器直接使用宿主机网络栈,无端口映射对网络性能要求高的场景
none容器有独立网络栈,但不配置网络安全隔离需求
container容器共享另一个容器的网络命名空间特殊调试需求

日常开发里bridge绝对够用。它内部有一个内置DNS,同一自定义bridge网络下的容器可以直接用容器名互相访问,不需要查IP。

6.2 容器间通过容器名互通的配置方法

最直接的方式是创建一个自定义网络:

docker network create my-net docker run -d --name app-a --network my-net my-node-app docker run -d --name app-b --network my-net my-other-app

之后在app-b容器里,可以直接通过app-a这个名字访问app-a容器的IP。这个“服务发现”能力是bridge网络自带的,不需要你手动维护IP映射表。

很多初学者搞不懂为什么不能直接用localhost访问另一个容器。本质是每个容器有独立的网络命名空间,localhost指向的是容器自己。如果用的是默认bridge网络,还只能通过IP访问,而IP每次重建容器都可能变。因此我在项目里总是建议从第一步就建一个自定义网络,让服务通过容器名称互相调用,后续哪怕容器重建,调用关系始终不变。

6.3 外网访问容器的开放策略

容器对外提供服务,除了端口映射,还要考虑安全。最简单的原则是:只映射必要的端口,不要图省事把几千个端口全部暴露。

实际操作中,我见到过有人为省事写了-p 1-65535:1-65535,这种做法风险极高,几乎等于把所有容器服务直接暴露到网络上,完全放弃了访问控制。正确做法是明确映射应用实际使用的端口,并尽可能在防火墙层面再加一层限制。

如果需要限制访问来源,比如只允许内网访问某个管理接口,可以考虑在映射时绑定到宿主机特定IP地址:

docker run -d -p 127.0.0.1:8080:80 nginx

这个配置只有通过宿主机本机访问8080才能转发到容器,外部网络访问不到。做开发调试的时候极为实用。

7. 常见问题排查与实用技巧

7.1 容器启动失败怎么查

容器一启动就退出,是最常见的故障。先别急着搜错误码,按顺序排查。

首先用docker ps -a确认容器状态,找到退出的容器ID。

然后查看容器日志:

docker logs <container-id>

日志里可以看到应用启动时的报错信息。如果日志空白,多半是命令配置问题,比如Dockerfile里的CMD写错了,进程一启动就异常退出。这时候用docker inspect查看容器的启动配置:

docker inspect <container-id>

重点看Mounts、NetworkSettings、State这几个字段,能确认挂载是否生效、端口映射是否正确、容器退出码是什么。

容器的退出码很有参考价值。0表示正常退出,通常是因为后台进程自己结束了,比如前台进程的命令在容器里没有保持为守护状态;非0则往往表示应用自身报错。很多新手喜欢在前台执行方式里不加-d运行一个Web服务,发现一关终端容器就停了,这就是没有理解前台进程和后台进程的关系。

7.2 端口占用与映射常见报错

端口占用时启动容器会报这样一个错误:bind: address already in use。

排查思路:

# 查看端口被哪个进程占用(Linux/macOS) lsof -i :8080 # 或者使用netstat netstat -tulpn | grep 8080 # 停掉占用端口的进程,或者换一个映射端口

如果确认宿主机端口没被占用,但还是报错,考虑是不是Docker服务本身没起来。运行systemctl status docker(Linux)或检查Docker Desktop是否正在运行。

7.3 镜像体积过大的减肥思路

镜像体积直接影响拉取速度和存储占用,优化空间很大。编排思路是从依赖源到最终产物逐层瘦身。

优先换更小的基础镜像。Alpine系的镜像普遍在几十MB级,比标准镜像小一个数量级。但要注意Alpine用的是musl libc,某些二进制程序可能会有兼容性问题,需要实测确认。

其次是精简构建产物。避免把不需要的文件COPY进去,多依赖.dockerignore。构建阶段临时下载的编译器、构建工具,如果最终镜像用不到,可以用多阶段构建来丢弃。

多阶段构建我简单说一下思路。第一阶段用一个完整的基础环境编译你的代码,生成可执行文件或静态产物;第二阶段用一个小体积的运行时镜像,只把第一阶段的产物拷贝进来。这样最终镜像里不包含编译工具链,体积能大幅压缩。示例:

# 第一阶段:编译构建 FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build # 第二阶段:运行环境 FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]

这类写法在构建Java、Go、Node应用时特别常见,建议尽早掌握。

注意:多阶段构建的中间阶段不会进入最终镜像,也不占用最终存储,所以可以大胆使用,不影响产物。

8. 这套基础课的扩展方向

学完本课时,你手上的工具箱已经有:镜像管理、容器生命周期、Dockerfile构建、数据持久化、网络通信和基础排障能力。这些能力单看可能觉得只是一些命令,但放到一个真实场景里就能组成完整的开发链路。

用Docker跑通本地开发环境,只是最表层的收益。再往下走,和docker compose结合,把数据库、缓存、应用多个服务一键编排,本地开发体验会再上一个台阶。之后是CI/CD流水线里把镜像构建、推送、部署串起来,到那一步,Docker基础知识的价值会迅速放大——因为流水线上每一环都是对一个镜像的构建和消费。

我个人建议的进阶路线是:先熟练写出当前项目的Dockerfile,把构建时间优化到可接受范围;然后折腾docker compose,把一个前后端分离项目跑起来;再尝试给项目接入镜像仓库,至少完成一次镜像推送和拉取。这三步走完,你的Docker基础就不再是“学过”,而是“能干活”。

9. 关于学习Docker的两句实话

很多人学Docker时容易走入一个误区:对着命令大全一遍遍抄写,试图把所有选项背下来。我的建议是反过来,拿一个真实的项目,先写出第一版能跑的Dockerfile,再去迭代优化。这个过程中踩到的每一个坑,都会比背十遍命令记得更牢。

还有一句实话是,不要被“容器是虚拟机”这种类比带偏。容器和虚拟机在隔离级别、资源占用、启动速度上差异很大,但在学习初期,把它理解成“一个轻量级的、自带环境的独立运行空间”就够了。等你真正需要理解Cgroups、Namespaces这些底层机制的时候,你已经能在实际项目中体会到它们的意义了,那时候再深入才是顺理成章的。

我在实际教学和带新人的过程中发现,第一课最需要的其实不是知识量,而是一次成功的正反馈——亲手把一个应用容器化跑起来。如果你读到这里,建议立刻打开终端,拉一个nginx镜像,写一个最简单的Dockerfile,把这个流程完整地走一遍。把基础动作变成肌肉记忆之后,后头的容器编排、服务治理、云原生架构,都会顺很多。

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

大模型竞争格局深度拆解:从技术路线到商业选型指南

全球大模型竞争走到今天&#xff0c;单纯拼参数已经没什么新鲜感了。打开任何一份榜单&#xff0c;前排选手的评分差距往往就在一两个点之间&#xff0c;真正拉开身位的是更底层的选择&#xff1a;走哪条技术路线、服务哪类用户、靠什么撑起长期成本。这一轮格局分析&#xff0…

作者头像 李华
网站建设 2026/10/20 8:36:37

2026全球大模型竞争地图:从参数竞赛到系统能力重构

大模型这个赛道&#xff0c;已经很难用一两句话概括了。我长期在AI应用一线折腾&#xff0c;眼看着它从“拼名字、拼参数”一路卷到“拼成本、拼落地”。如果以2026年10月6日作为一个观察基准点&#xff0c;重新画一张全球大模型竞争地图&#xff0c;会发现格局已经和我两年前认…

作者头像 李华
网站建设 2026/10/20 8:35:48

FFmpeg Win64共享库版指南:从DLL配置到转码实战

简介&#xff1a;FFmpeg是一套功能强大的开源音视频处理框架&#xff0c;支持编码、解码、转码、封装格式处理及流媒体传输&#xff0c;几乎兼容所有主流音视频格式。该压缩包为FFmpeg最新开发分支在64位Windows系统下的GPL共享库版本&#xff0c;适用于需要集成音视频能力进行…

作者头像 李华
网站建设 2026/10/20 8:35:37

RAG预处理核心:TextLoader与递归字符文本分割器实战

做RAG项目&#xff0c;很多人一上来就调embedding、换向量库、研究重排序&#xff0c;结果效果就是上不去。我见过太多团队把检索结果的锅甩给模型&#xff0c;最后定位到源头&#xff0c;发现是文档在进入向量库之前就已经被切碎了。这次要聊的&#xff0c;正是RAG开发里最基础…

作者头像 李华
网站建设 2026/10/20 8:35:15

SQL分桶统计缺失补0:从LeetCode 1435到业务报表

刷题平台数据库题库里有一道编号 1435 的题&#xff0c;翻译过来叫“制作会话柱状图”。我第一眼看到这题觉得是送分题&#xff1a;把 session 的时长按分钟分个组&#xff0c;count 一下不就完事了&#xff1f;结果第一次提交就被几个测试用例教育了——当某个时间桶里压根没有…

作者头像 李华