news 2026/10/21 12:58:58

Redis核心知识点详解:从数据结构到高并发缓存实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redis核心知识点详解:从数据结构到高并发缓存实践

1. 为什么我建议你认真学一下Redis

先说结论:Redis几乎是现代后端开发绕不开的一个组件,做Web开发、做接口服务、做数据分析、甚至做AI应用的工程落地,都可能碰到它。如果你面试后端岗位,十次里面有七八次会被问到Redis;如果你接手一个老项目,大概率也会看到Redis的身影。早点把它弄清楚,后面省很多事。

我第一次接触Redis其实是有点抵触的,因为当时觉得“缓存嘛,不就是存个键值对”,没必要专门学。后来真上了场景才发现,这句话就像说“汽车嘛,不就是四个轮子加个沙发”一样,大方向没错,但离真正会开还差得很远。你要往缓存里写什么、什么时候失效、内存不够怎么办、数据崩了会不会丢、多个实例怎么同步,这些才是真正决定系统稳不稳的关键。

Redis本质上是一个开源的、基于内存的键值存储系统。它把数据放在内存里,所以读写速度非常快,单实例QPS轻轻松松能到十万以上,这是传统关系型数据库很难做到的。同时它又不只是简单的get/set,它还提供了丰富的数据结构,比如字符串、哈希、列表、集合、有序集合,还有发布订阅、Lua脚本、事务、持久化、分布式锁等一堆实用功能。

记住一个核心概念:Redis被称为“数据结构服务器”,而不是“缓存的数据库”,因为它的核心卖点就是那五种基本类型和在此基础上衍生出的能力。理解了这个定位,你就知道它为什么能在缓存之外还承担那么多职责。

这篇内容适合谁?已经会写代码但对Redis只有模糊概念的开发者,准备面试需要系统梳理Redis知识点的同学,以及在生产环境里用Redis但经常遇到诡异问题的朋友。我会把安装部署、核心数据类型、典型场景、持久化机制、常见坑全部过一遍,全程用自己的实际经验来讲。

1.1 先弄明白Redis到底解决了什么问题

在讨论命令和配置之前,先把“为什么需要Redis”这件事想明白。日常开发中最典型的问题有三个。

第一个是性能瓶颈。数据库的磁盘IO和行级操作再快,也扛不住高并发下的重复查询。比如一个热门商品详情页,每秒几千人访问,每次都去MySQL里查库存和价格,数据库会被打成热点。Redis把所有高频数据塞到内存里,查询只在内存中完成,速度快了两个数量级。

第二个是数据结构的低效处理。很多业务场景需要临时存储一些结构化的数据,比如一个用户最近浏览过的商品列表、一个直播间的在线观众集合、一个排行榜。用关系型数据库当然也能做,但每条记录都要建表、加索引、写SQL,特别繁琐。Redis的List、Set、ZSet直接对应这些场景,一个命令就能搞定。

第三个是系统组件之间的协作。分布式系统里,多个服务实例需要同步状态,谁在运行、谁持锁、哪个节点离线,这些轻量级协调信息放数据库太重,放本地内存又不对,Redis就成了一个比较稳妥的中间地带。

Redis的定位很清晰:它不是一个万能的数据库,而是高并发场景下的一种加速器和粘合剂。想清楚这一点,你在做技术选型时就不会迷茫。

1.2 什么人应该看这篇内容

如果你正在学后端开发,还没有接触过Redis,这篇可以作为你的第一份入门资料。我会从零开始演示安装,命令一条一条讲,数据结构一个一个拆。

如果你已经用了Redis,但只是简单当缓存用,比如put一个key、get一个value,那我建议你看看后面关于数据结构和场景的章节。Redis至少有五成以上的能力你可能还没用到,而这些能力能让你的代码结构简洁很多。

如果你正在准备面试,那这篇内容其实很多考点都覆盖了。缓存穿透、缓存击穿、缓存雪崩、持久化机制、分布式锁、过期策略,这些高频问题我都会聊到,而且是用实际场景来聊,不是死背概念。

好了,废话不多说,直接进入正题。

2. 安装、启动和第一行命令

2.1 安装Redis的几种方式

本地学习的话,我建议直接用Docker跑一个实例,干净、快速、不污染系统环境。装完之后随时可以删了重建,换版本也很方便。

# 拉取镜像并启动一个名为redis-test的容器 docker run --name redis-test -p 6379:6379 -d redis:7

这条命令会拉取最新的Redis 7镜像,把容器内的6379端口映射到本机的6379,这样我们直接用Redis客户端就能连上。

如果你不想用Docker,也可以直接用系统包管理器安装。

# Debian/Ubuntu sudo apt-get install redis-server # CentOS/RHEL sudo yum install redis

安装完成后,启动服务和验证状态:

sudo systemctl start redis-server sudo systemctl status redis-server

还有一种方式是从源码编译,这个一般用于定制化安装或者生产环境自己编译优化。步骤是下载源码包、解压、进入目录执行make和make install。我个人建议新手不要一上来就搞源码编译,除非你已经很清楚自己需要哪些编译选项,否则纯粹是浪费时间。

2.2 连接Redis并执行第一条命令

安装好之后,用Redis自带的命令行客户端连接:

redis-cli # 如果连接成功会看到 127.0.0.1:6379>

如果Redis不是跑在本机,或者改了端口,可以指定地址和端口连接:

redis-cli -h 192.168.1.100 -p 6380

连接成功后,先执行一条最简单的命令试试:

127.0.0.1:6379> SET hello world OK 127.0.0.1:6379> GET hello "world"

SET表示写入一个键值对,GET表示读取。OK和"world"就是Redis给我们的响应。所有功能都逃不开这个套路:发命令、收响应。

如果要查看当前Redis里有多少个键,可以用DBSIZE。如果要清空当前库,可以用FLUSHDB,但慎用,生产环境一旦执行就是灾难。

127.0.0.1:6379> DBSIZE (integer) 1 127.0.0.1:6379> KEYS * 1) "hello"

这里我要多说一句,KEYS *在生产环境千万不要乱用,它会阻塞Redis主线程,数据量大的时候直接卡死。后面我会专门讲这个问题。

2.3 几个实用配置项和密码设置

Redis默认配置可以跑通开发环境,但有几个配置项我建议你一开始就设置好。

首先是绑定地址,默认配置通常只允许本机访问。如果你需要远程连接,需要修改bind配置和protected-mode选项,但我要强调,直接把Redis暴露到公网是非常危险的做法,Redis此前多次因为未授权访问被入侵。千万别图省事不做鉴权。

设置密码很简单,在redis.conf里找到requirepass这一行,改成你要的密码:

requirepass your_strong_password

改完保存并重启Redis,再连接就需要先认证:

redis-cli -a your_strong_password

或者连接后执行AUTH命令:

127.0.0.1:6379> AUTH your_strong_password OK

另外一个很关键的配置是maxmemory,也就是最大内存限制。Redis默认可以用完系统的所有内存,这在生产环境里是个隐患。建议设置一个合理上限,例如:

maxmemory 512mb

当数据量达到上限之后,Redis会根据淘汰策略来清理旧数据,后面我会具体说。

提示:改配置文件之前先备份原文件。我第一次手动把配置改挂的时候花了半小时才找到问题,就是一个空格导致配置项没被识别。

2.4 图形化工具

如果觉得命令行不够直观,可以用一些图形化管理工具。常见的包括Another Redis Desktop Manager、RedisInsight等。安装之后填上主机地址、端口、密码就能连接,可以方便地浏览key、查看value、执行命令。

不过我要提醒一句,不管用什么图形化工具,命令行这个基本功不能丢。因为很多运维场景只有命令行,比如服务器上没有桌面环境,或者容器内连接Redis,你总不能每次都装一个图形工具。

我自己的习惯是:日常排查用命令行,批量查看数据和检查key分布用图形工具。两者互补,效率最高。

3. 五大核心数据结构,一个都不能少

3.1 String:最基础但最容易用错的类型

String是Redis里最简单的类型,也是我们最常用的类型。它不只是存字符串,数字、JSON序列化后的字符串、甚至是二进制数据都可以存。单次存储的最大值是512MB。

常用命令:

SET key value # 写入 GET key # 读取 MSET k1 v1 k2 v2 # 批量写入 MGET k1 k2 # 批量读取 INCR key # 自增1 DECR key # 自减1 EXPIRE key seconds # 设置过期时间 TTL key # 查看剩余存活时间

这里的INCR和DECR用得非常多,比如计数器、库存扣减、访问次数统计,都要靠这种原子自增操作。

String最容易踩的坑是什么?是很多人在存复杂对象时手动做对象的拼串和解析。正确做法是先把对象序列化成JSON,然后用一个key去存,读取后再反序列化。但我见过不少人把JSON展开成多个key来存,比如用户对象的每个字段都单独存一个key,这样不仅代码冗余,还丧失了原子性。

官方文档里专门有提到String的使用场景,包括缓存对象、计数器、分布式会话等。凡是能序列化成字符串的,都可以用String来扛。

3.2 Hash:存对象的正确姿势

Hash类型在Redis里表示一个键对应一个“字段-值”的映射表,听上去很适合存对象,也确实最常用。

HSET user:1001 name "Alice" age 25 HGET user:1001 name HGETALL user:1001 HDEL user:1001 age

实际场景中,用户信息、商品详情、配置项,这类“一条记录有很多字段”的数据都可以用Hash。它可以只读取和更新其中某一个字段,不需要把整个对象序列化出来。这一点比String存JSON更灵活,尤其在只更新一个字段时能省不少流量。

Hash的一个小技巧是配合批量命令:

HMSET user:1002 name "Bob" age 30 email "bob@example.com" HMGET user:1002 name email

要注意的是,Redis 4.0之后HMSET已经被标记为不建议使用的旧命令,功能上和HSET带多组参数是一样的,所以直接用HSET就行。

我见过一个比较典型的误区是,有人用Hash存了上百万个key,每个key的field数量特别多,结果内存占用比预计高很多。这是因为Hash在field数量少的时候有一种内部编码叫ziplist,相对省内存;但一旦field数量超标,就会升级为hashtable编码,内存开销陡增。这也是一个值得留意的点。

3.3 List:消息队列和操作历史

List类型就是一个双向链表,两头都可以push和pop。

LPUSH queue task1 RPUSH queue task2 LPOP queue RPOP queue LRANGE queue 0 -1

List的典型用途有三个。

第一是当作简单的消息队列。生产者LPUSH,消费者RPOP,一进一出就实现了最简单的队列语义。但这只能用来接轻量级的任务,如果想要消息可靠性、ACK机制、重新投递,还是得用专业的消息队列系统。

第二是保存用户的操作历史。比如一个用户最近的浏览记录,每次浏览往List里push一条,再通过LTRIM修剪列表长度,只保留最近20条。

LPUSH user:1001:history article:1001 LTRIM user:1001:history 0 19

第三是取最近N条数据。配合LRANGE可以很方便地分页,比如取最近十条操作:

LRANGE user:1001:history 0 9

我对List的建议是:别在高并发场景下把它当成唯一队列,因为BRPOP、LPUSH这些命令虽然好用,但出错重试、消息丢失这些机制完全要靠业务自己补,成本不低。

3.4 Set:去重是它的看家本领

Set是无序的字符串集合,它最核心的特点就是自动去重,并且支持集合运算。

SADD tags:article:1 "java" "redis" SADD tags:article:2 "java" "mysql" SMEMBERS tags:article:1 SINTER tags:article:1 tags:article:2 # 交集 SUNION tags:article:1 tags:article:2 # 并集 SDIFF tags:article:1 tags:article:2 # 差集

Set的应用场景很多。

一是活动去重。用户每参加一个抽奖活动,把他的ID加到一个Set里,天然防止重复参与和重复中奖。

二是标签系统。一篇文章有多少个标签,往Set里加就行了,统计标签数量就是SCARD。

三是共同好友。两个Set做交集,瞬间算出共同关注了哪些人。

还有一个很有趣的玩法是随机抽取,SPOP可以从集合里随机弹出元素,适合做抽奖类功能:

SPOP lottery:100

3.5 ZSet:排序由你来定

ZSet,也叫有序集合。它在Set的基础上给每个元素加了一个分数,Redis按照分数从小到大自动排序。这是我认为Redis中最值得深入理解的一个类型。

ZADD leaderboard 100 "player1" ZADD leaderboard 90 "player2" ZRANGE leaderboard 0 -1 ZREVRANGE leaderboard 0 -1 ZSCORE leaderboard player1 ZINCRBY leaderboard 10 player1

ZSet的典型场景非常多。

排行榜是最经典的场景。实时更新积分,用ZINCRBY给某个用户加分,排行榜自然就排出来了:

ZINCRBY user:score:2024 10 "user_id_123" ZREVRANGE user:score:2024 0 9 WITHSCORES

延迟队列也可以用它实现。把任务的到期时间戳作为score,轮询ZRANGEBYSCORE把score小于当前时间戳的任务取出来执行。

限流也能借助它。滑动窗口限流的一种实现就是,把每次请求的时间戳加到ZSet里,统计一段时间内的请求数,超过阈值就拒绝。

ZREMRANGEBYSCORE rate:api:1 0 (now - window) ZCARD rate:api:1

ZSet的内存占用比前几种类型要大,因为它除了存数据本身,还要维护一套跳跃表结构用于排序。如果数据量极大,要考虑内存成本。

注意:ZSet的score是双精度浮点数,如果数值精度要求特别高,比如需要精确到分甚至更小,建议用整数保存最小单位,不要存小数。

4. 持久化机制:崩溃了数据还在吗

4.1 RDB快照

Redis的所有数据都在内存里,如果进程退出或机器断电,内存数据就没了。为了应对这种情况,Redis提供了两种持久化机制,第一种是RDB。

RDB会根据配置生成一个二进制的快照文件,把某个时间点的数据完整保存到磁盘。默认的规则一般是:

save 900 1 save 300 10 save 60 10000

含义是:900秒内有1次写操作就生成快照,300秒内有10次写操作就生成,60秒内有10000次写操作就生成。

RDB的优点是可以快速加载恢复数据,文件紧凑、适合备份。缺点是快照之间的数据如果丢失,就只能恢复到最近一次快照的时间点,中间的数据会丢。

我自己在实操中会周期性手动执行BGSAVE,生成备份文件,再把文件同步到异地存储。这样即使整个服务器挂掉,也能从备份恢复。

4.2 AOF日志

AOF(Append Only File)把每次写操作以日志形式追加到文件中。开启方式是:

appendonly yes appendfsync everysec

appendfsync有三个选项:always表示每个命令都同步刷盘,最安全但性能最差;everysec表示每秒刷一次,性能和安全性平衡;no表示由操作系统决定何时刷盘,性能最好但可能丢更多数据。

实际生产环境我建议选择everysec,这也是Redis官方推荐的折中选择。崩溃时最多丢1秒的数据,大部分业务都能接受。

AOF文件会不断增加,Redis会用后台进程来重写AOF文件,去掉其中的冗余命令,保持文件精简。相关的配置项是:

auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb

4.3 官方推荐:混合持久化

Redis 4.0之后支持混合持久化。开启方式:

aof-use-rdb-preamble yes

混合持久化的思路是,AOF文件的前半部分是RDB格式的快照,后半部分是增量命令日志。这样重启时加载速度比纯AOF快,又比纯RDB丢失的数据更少。

如果业务对数据完整性要求比较高的场景,建议把持久化策略设置为混合模式。对于允许丢失少量数据的纯缓存场景,甚至可以全关持久化,换来最高的性能。

5. 缓存三大难题,你必须能讲清楚

5.1 缓存穿透

缓存穿透指的是查询一个数据库中不存在的数据,缓存里自然也不存在,于是每次请求都直接打到数据库上。如果这是恶意攻击,大量不存在的ID进来,数据库压力会瞬间飙升。

解决办法有几种。

第一种是缓存空值。当数据库查不到结果时,也把这个key写入缓存,值设为一个特殊标识,过期时间设短一点,比如1分钟。这样短时间内同样的请求就不会直接打穿到数据库。

第二种是使用布隆过滤器。把所有可能存在的ID提前写入布隆过滤器,查询之前先判断ID是否可能存在,如果过滤器判断不存在,直接返回,不再查数据库。

我在项目里经常组合使用这两种方式,小规模场景用空值缓存就够,大规模场景再考虑布隆过滤器。

5.2 缓存击穿

缓存击穿指某个热点key在失效的瞬间,大量并发请求同时打到数据库,导致数据库瞬间压力过大。

互斥锁是比较常见的方式。在缓存失效后,先让一个线程去数据库加载数据并重建缓存,其他线程等待重建完成后再从缓存读取。

# 伪代码,用setnx实现互斥锁 is_mutex_ok = redis.set("lock:hot_key", "1", nx=True, ex=10) if is_mutex_ok: value = db.query() redis.set("hot_key", value, ex=60) redis.delete("lock:hot_key") else: time.sleep(0.05) value = redis.get("hot_key")

逻辑过期也是一种思路,不直接把缓存key设过期,而是存一个逻辑过期时间,在读取时判断逻辑时间是否过期。如果过期了,先返回旧数据,再异步去刷新缓存。

5.3 缓存雪崩

缓存雪崩指大量key同时失效,或者缓存服务整体宕机,导致所有请求全部打到数据库。前者可以通过过期时间加随机值来规避,例如:

expire_time = base_expire_time + random.randint(0, 60)

这样每个key的过期时间都不同,不会在同一时刻集体失效。

后者则需要通过高可用方案来解决,包括Redis主从架构、哨兵模式、甚至集群模式。这些内容比较深,新手可以先了解概念,知道有这么回事,等真正需要时再深入研究。

6. 常见问题和排查技巧

6.1 KEYS命令把Redis卡死了

这个坑我见过太多次了。生产环境里有人执行KEYS *去查匹配的key,数据量几百万时,主线程直接被阻塞,所有请求都变得很慢甚至超时。

正确做法是使用SCAN命令进行渐进式遍历:

SCAN 0 MATCH user:* COUNT 100

SCAN是一次一次迭代返回,不会阻塞主线程,虽然速度比KEYS慢,但不会拖垮服务。

如果只是想知道key的个数,DBSIZE就够用,不要用KEYS去数。

6.2 Redis内存满了怎么办

当达到maxmemory设置的限额之后,Redis会根据maxmemory-policy来淘汰key。常见策略有:

  • noeviction:不淘汰,写入直接报错
  • allkeys-lru:从所有key里淘汰最近最少使用的
  • volatile-lru:从设置了过期时间的key里淘汰最近最少使用的
  • allkeys-random:随机淘汰所有key
  • volatile-ttl:从设置了过期时间的key里淘汰即将过期的

缓存场景一般用allkeys-lru,会话场景可以用volatile-lru,带有持久性的数据不能轻易淘汰,需要从架构上避免放入同一实例。

我在实际项目里看到过一个有意思的教训:有的人把maxmemory设得很小,比如64MB,然后正常业务一跑就报OOM错误。排查了很久才发现是测试环境的配置没更新,所以每次调配置都要确认真正生效。

6.3 Big Key问题

一个key的value特别大,比如几兆甚至几十兆,这就是Big Key。它会带来几个问题:读取该key时耗时高、网络流量大、删除或序列化时阻塞主线程。

排查Big Key可以用:

redis-cli --bigkeys

它会扫描整个实例并给出最大的几个key。但是要注意,线上实例要谨慎使用,因为扫描也可能带来压力,建议在低峰期执行。

解决办法是拆分大key,或者根据业务场景合理设计数据结构。例如一个List存了十几万条消息,可以考虑按时间或类型拆成多个key。

6.4 过期删除策略

Redis删除过期key的方式有两种:惰性删除和定时删除结合使用。惰性删除指访问key时发现已过期就当场删除;定期删除指每隔一段时间抽取一批设置了过期时间的key,把其中过期的删掉。

这也是面试常考的点。理解它的意义在于:过期key不一定被立即删除,如果一个key过期了但没被访问,它可能还会占据内存。所以如果对内存特别敏感,不能只依赖过期机制,还要配合主动淘汰策略。

6.5 连接数打满

出现连接数打满时,一般先检查是不是有连接泄漏。很多语言客户端如果使用不当,连接池没有被正确归还,就会出现连接持续增长直到占满。

排查步骤一般是:

# 查看当前连接数 INFO clients # 查看最大连接数配置 CONFIG GET maxclients

代码层面要检查连接池的配置和使用方式,比如Java的Lettuce、Python的redis-py、Go的go-redis,都必须确保用完即归还连接。

我见到过一些团队为了省事用单例客户端但关闭了连接池复用,结果每个请求创建一个新连接,高并发下一分钟内就会打满。

7. 场景实战:一个完整的小案例

7.1 需求描述

我拿一个常见的电商场景来串一遍:用户查看商品详情,详情数据中有商品基本信息、库存、评论数、评分。这个接口会被频繁访问,数据库压力很大。我们要用Redis做缓存来扛住高并发读取。

7.2 方案设计

商品基本信息用Hash存,字段包括名称、价格、库存、评论数、评分。库存用String存一个数字,方便直接用DECR来做扣减。评论数可以用String类型配合INCR来累加。商品详情页的完整对象用String存一份JSON,加速读取。

缓存更新采用Cache Aside模式:读的时候先读缓存,缓存没有就查数据库,然后回填缓存;写的时候先更新数据库,再删除缓存。

7.3 伪代码演示

import redis import json r = redis.Redis(host="localhost", port=6379, db=0) def get_product_detail(product_id): cache_key = f"product:detail:{product_id}" data = r.get(cache_key) if data is not None: return json.loads(data) # 缓存未命中,查询数据库 product = query_db(product_id) if product is None: return None # 回填缓存,设置过期时间加随机值 expire = 300 + (product_id % 60) r.set(cache_key, json.dumps(product), ex=expire) return product

扣减库存:

def reduce_stock(product_id): key = f"product:stock:{product_id}" remaining = r.decr(key) if remaining < 0: # 超卖风险,需要回滚或标记异常 r.incr(key) return False return True

注意这里的超卖检查不是完整的解决方案,真实场景有很多并发控制细节。但我用这个例子想说明的是:Redis的一些原子操作确实能够直接简化业务逻辑,不用引入分布式锁也能做到一些基础的并发控制。

7.4 这个案例说明了什么

这个案例把所有核心内容串起来了:String存JSON做整体读取,Hash做结构化存储,INCR/DECR做计数和扣减,过期时间防脏数据留存。理解了这些,你至少能解决大多数日常开发问题了。

8. 实操中的个人小结

写了这么多,最后分享一点我自己的体会。学Redis不是背命令,而是理解数据结构与场景的匹配关系。很多年前我学的时候,上来就背了一大堆命令,但遇到实际问题还是懵。后来我换了个思路,先想清楚业务里有哪些数据结构,再考虑Redis里的哪种类型能落地,这样学习的效率高了很多。

另一个体会是,虽然Redis易上手,但生产环境里想用好它,必须提前把监控和告警做好。至少要知道内存使用率、连接数、命中率这几个指标,不要等到服务出了问题才去想对策。

还有一个小建议,所有的配置变更都要先在测试环境验证,并且确认重启后的加载结果。别问我为什么这么强调,问就是经历过多台实例配置不一致的惨痛教训。

对于扩展学习的方向,建议下一步去研究发布订阅、Lua脚本、分布式锁、Redis Cluster。掌握了这篇基础内容之后,这些东西的理解也会顺畅很多。

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

Aruba DHCP Option 43/60/138/150 配置实战与排障指南

1. 项目概述&#xff1a;为什么DHCP Option配置在Aruba网络中不是“配完就完事”的小事Aruba DHCP Option上线配置&#xff0c;这个标题乍看是网络工程师日常操作里再普通不过的一环——不就是给DHCP服务器加几条Option字段嘛&#xff1f;但如果你真这么想&#xff0c;等设备上…

作者头像 李华
网站建设 2026/10/21 12:58:08

JavaEE网上考试系统设计:Servlet+JSP+JDBC三层架构大作业资源解析

简介&#xff1a;这是一套面向软件工程专业课程设计的JavaEE网上考试系统完整项目&#xff0c;涵盖源代码、设计报告与使用说明&#xff0c;适合正在完成大作业、需要参考成熟考试系统设计与实现思路的学生。压缩包共包含74个文件&#xff0c;其中16个Java文件负责后台核心逻辑…

作者头像 李华
网站建设 2026/10/21 12:57:03

五种AI编程范式:Vibe、Plan、Glue、Spec与Smell的工程化实践

过去这半年&#xff0c;我身边的开发者几乎没人不在用AI编程。天天用&#xff0c;也天天在争论&#xff1a;到底应该怎么用&#xff1f;有人说直接聊就行&#xff0c;要啥给啥&#xff1b;有人说必须先写好规划再动手&#xff0c;不然AI多改几次就失控&#xff1b;还有人觉得AI…

作者头像 李华
网站建设 2026/10/21 12:56:32

PyTorch多分类实战:从Logits理解、损失设计到部署鲁棒性

1. 多分类不是“多选一”&#xff0c;而是让模型学会“打分排序” 刚接触PyTorch做分类任务的新手&#xff0c;常把“多分类”简单理解成“从N个类别里挑一个最像的”。这种直觉在二分类里勉强能用&#xff0c;但一旦落到真实项目——比如识别100种工业零件、区分50类医学影像、…

作者头像 李华
网站建设 2026/10/21 12:55:06

从零构建AI Agent:最小骨架、工具调用与学习路线

“从零构建 Agent&#xff0c;应该按什么顺序学习&#xff1f;”这是后台被问得最多的问题之一&#xff0c;我今天直接聊这个话题。很多人学 Agent 的方式是&#xff1a;先看一堆概念、再收藏一堆框架文档、最后跟着某篇教程敲一遍&#xff0c;然后就没有然后了。为什么&#x…

作者头像 李华
网站建设 2026/10/21 12:54:52

图片视频去水印全攻略:从裁剪覆盖到内容识别与动态追踪

直接分享点体会。做内容这行&#xff0c;几乎每天都会碰到带水印的素材——自己拍的视频要加字幕条、截图里混进角落的Logo、从旧设备导出的照片压着拍摄时间戳。不是要去偷别人的作品&#xff0c;而是处理自己手里这些改造起来费劲的东西。这篇教程我想把“图片去水印”和“视…

作者头像 李华