同一批向量换个距离度量,第一名就换了
版权与内容来源声明
本文为原创整理。文中涉及官方文档、开源仓库、论文与公开报道的内容,均在附表 A 中标注来源;引用官方原文保持原样,不作改写。文中命令、版本号与界面截图以本文成文时的实测/核验结果为准,标注「待验证」的部分请以你本地环境实际输出为判断依据。本文不推荐任何不合规的软件获取方式,也不对任何收益结果作承诺。转载请注明出处。
一、先把同一批向量喂进去,看第一名怎么换
同一批 200 条向量、同一批 20 条查询,只把排序函数从余弦换成内积,20 条查询里有 16 条的第一名换了人;换成 L2 之后,19 条的第一名换了人。
这批向量里没有加任何随机噪声:种子固定,重跑一遍每个小数点都一样。差别全部来自一处刻意的设置——每条向量的方向随机,长度却从 0.23 拉到 4.48。这就是「写入侧没有归一化」在数值上的样子:向量长短不齐,方向和长度一起进了索引。
1.1 造数据只做了一件事:把模长拉开
200 条,12 维。每一维取标准正态,缩到单位长度,再乘一个 0.22 到 4.48 之间的随机倍数。20 条查询用同样的造法,因为查询和文档通常出自同一个编码器,模长分布本来就同源。
维度固定 12,是有意的:维度只改变数值大小,不改变排序机制,让它变成第二个变量反而看不清归因。
1.2 三列名次摆在一起,问题就露出来了
🧪 实测环境:Python 3.13.12 / macOS / 仅标准库。脚本:
work/exp1027/e05_metric.py
"""e05_metric.py —— 同一批向量换度量,top-1 换不换人(未归一化,固定种子)。"""importmath,random random.seed(20261027)N,D,QN=200,12,20defrv():# 随机方向 × 0.22~4.48 倍模长d=[random.gauss(0,1)for_inrange(D)]s=math.exp(random.uniform(-1.5,1.5))return[x*s/math.sqrt(sum(y*yforyind))forxind]dot=lambdaa,b:sum(x*yforx,yinzip(a,b))nrm=lambdaa:math.sqrt(dot(a,a))cos=lambdaa,b:dot(a,b)/(nrm(a)*nrm(b))l2=lambdaa,b:math.sqrt(sum((x-y)**2forx,yinzip(a,b)))top=lambdaf,q,hi:sorted(range(N),key=lambdai:f(q,V[i]),reverse=hi)[:5]V,QS,F=[rv()for_inrange(N)],[rv()for_inrange(QN)],(dot,cos,l2)R=[(top(dot,q,1),top(cos,q,1),top(l2,q,0))forqinQS]ln=[nrm(v)forvinV]print("=== e05_metric · %d 条 %d 维向量,未归一化 ==="%(N,D))print("模长 min %.2f / max %.2f / mean %.2f,极差÷均值 = %.2f"%(min(ln),max(ln),sum(ln)/N,(max(ln)-min(ln))/(sum(ln)/N)))print("查询 %d 条,下表是第 1 条的 top-5(格子里是 id 与它在该度量下的值):"%QN)print("名次 内积(越大越好) 余弦(越大越好) L2(越小越好)")forrinrange(5):print("#%-2d "%(r+1)+" ".join("id=%-3d %8.4f"%(R[0][j][r],F[j](QS[0],V[R[0][j][r]]))forjinrange(3)))agree=lambdaa,b:sum(t[a][0]==t[b][0]fortinR)ovl=lambdaa,b:sum(len(set(t[a])&set(t[b]))fortinR)/QNprint("")fora,b,nmin((0,1,"内积 vs 余弦"),(0,2,"内积 vs L2 "),(1,2,"余弦 vs L2 ")):print("%s:20 条查询里 top-1 一致 %2d 条,top-5 平均交集 %.1f/5"%(nm,agree(a,b),ovl(a,b)))原样贴出来的输出:
=== e05_metric · 200 条 12 维向量,未归一化 === 模长 min 0.23 / max 4.48 / mean 1.29,极差÷均值 = 3.29 查询 20 条,下表是第 1 条的 top-5(格子里是 id 与它在该度量下的值): 名次 内积(越大越好) 余弦(越大越好) L2(越小越好) #1 id=28 1.4249 id=27 0.7746 id=102 0.5165 #2 id=27 0.8488 id=102 0.6141 id=184 0.5263 #3 id=40 0.8484 id=28 0.5711 id=129 0.5309 #4 id=135 0.7623 id=1 0.5652 id=29 0.5336 #5 id=176 0.7179 id=81 0.4957 id=111 0.5425 内积 vs 余弦:20 条查询里 top-1 一致 4 条,top-5 平均交集 1.4/5 内积 vs L2 :20 条查询里 top-1 一致 1 条,top-5 平均交集 0.6/5 余弦 vs L2 :20 条查询里 top-1 一致 13 条,top-5 平均交集 2.6/5第 1 条查询的三列,一眼能看出它们答的不是同一个问题:
- 内积第一名
id=28,分数 1.4249,它的余弦只有 0.5711,按余弦排第 3; - 余弦第一名
id=27,余弦 0.7746,按内积排第 2; - L2 第一名
id=102,距离 0.5165,它在内积榜上连前 5 都没进。
把前两名拎出来对一下:id=28与id=27的内积分数比是 1.4249 ÷ 0.8488 = 1.68,余弦比是 0.5711 ÷ 0.7746 = 0.74,两个比值一除,模长比 2.28。它坐在内积榜第一,靠的是「长」,不是「像」。
20 条查询的统计更直白:内积与余弦只有 4 条 top-1 一致,top-5 平均重叠 1.4 条;内积与 L2 更差,1 条一致、0.6 条重叠;余弦与 L2 好一些,13 条一致、2.6 条重叠。同一份数据、同一个查询集,换一个排序函数就是三份结果。
二、这段代码里其实只有两件事:归一化 与 度量
三十行上下的代码,真正决定结果的只有两个开关:写进来的向量有没有归一化、排序时用哪个公式,其余都是造数据和打印。
2.1 第一个开关:模长有没有进计算
三个分值函数一行一个,差别全在模长怎么处理:
dot直接乘,模长原封不动乘进分数;cos除以两个模长的乘积,模长被剥掉;l2先减再平方,|a|²那一项留在了结果里。
同样是「算像不像」,一个把长度算进去,一个把长度除掉,一个把长度平方后加进去。名次不一样,是应该的。
2.2 第二个开关:谁越大越好
top(dot, q, 1)和top(l2, q, 0)只差一个reverse。内积和余弦越大越好,L2 越小越好——听着像常识,换库时却是最常踩的一条:不同实现把「相似度」返回成正数还是负数并不统一,pgvector 的<#>返回的是负内积,原句留在第五章。
2.3 三种口径钉死在一张表里
| 度量 | 排序用的量 | 方向 | 模长怎么进结果 | 归一化后它等于谁 |
|---|---|---|---|---|
| 内积(IP / Dot) | q·a | 越大越好 | 乘|a| | 余弦 |
| 余弦(COSINE) | q·a / (‖q‖‖a‖) | 越大越好 | 被除掉 | 内积 |
| 欧氏(L2 / Euclid) | ‖q − a‖ | 越小越好 | |a|²留在平方里 | 余弦的严格递减函数 |
表下口径:q 是查询,a 是候选;「归一化后」指 ‖q‖ = ‖a‖ = 1;「严格递减函数」在第三章推。三行的方向只是本文排行榜的约定,各库的返回值口径以自己那份文档为准。
表里第三行是全文的转折点:在归一化的世界里,L2 和余弦不是两种度量,是同一个量的两种刻度。
三、机制:内积把模长算了进去,余弦把它剥掉
内积的第一名可能是「最长的那个」,不是「最像的那个」,因为模长是乘在分数上的,不是加在旁边的。
3.1 一个除法就能把名次翻过来
把内积拆开:q·a = ‖q‖·‖a‖·cos(q,a)。查询对所有候选是同一个,‖q‖ 是常数,所以内积排序等价于按‖a‖·cos排。
两条候选 a、b,余弦更偏好 b(cos_b > cos_a)。内积要翻过来,只需要 ‖a‖·cos_a > ‖b‖·cos_b,也就是:
‖a‖ / ‖b‖ > cos_b / cos_a
回到实跑数字。id=28与id=27的余弦比是 0.7746 ÷ 0.5711 = 1.36,而它们的模长比 2.28 > 1.36,所以内积把id=28顶到了第一。
这个式子还能解释一个更难受的现象:余弦榜的第 3 名与第 4 名,余弦是 0.5711 和 0.5652,比值只有 1.01——模长差 1%,这两名就换位。只要写入侧不是严格单位长度,top-k 内部那些挨得很近的名次就随时会被扰动;挨得越近,需要翻盘所需的模长差越小。
反过来说,内积并不「更差」:当模长本身就带信息时(推荐里的热度、文档里的篇幅),把长度算进分数才是你想要的排序。错的从来不是某个度量,是「索引按 A 建、查询按 B 算」。
3.2 L2 为什么会挑中「近但短」的那条
把 L2 也拆开:‖q − a‖² = ‖q‖² + ‖a‖² − 2q·a。‖q‖² 对每个候选都一样,剩下两项里‖a‖²随候选变化,−2q·a才是相似度。两条路一起走,L2 会系统性地偏向模长小的候选。
本文第 1 条查询里,L2 的第一名id=102距离 0.5165,换成余弦只排第 2,内积榜上根本没有它。三张榜各挑出一个不同的「最近」,原因就在这一个平方项上。
3.3 归一化后一定一致:那是单调变换,不是巧合
设 ‖q‖ = ‖a‖ = 1,上面那个展开立刻塌成:
‖q − a‖² = 1 + 1 − 2·q·a = 2 − 2·cos(q,a)
这是一个关于 cos 的仿射函数,斜率 −2,严格递减。严格递减函数保序:cos 越大,L2² 越小,于是「按 cos 降序」与「按 L2 升序」排出来的顺序逐条相同。同时 ‖a‖ = 1 时 q·a 就等于 cos,内积也退化成同一个量。
三张榜合一不是这批数据碰巧,是代数结果:只要真的归一化了就一定一致,跟数据分布、维度、查询条数都无关。
faiss 的官方 wiki 把这个关系直接写成了式子:「the distances are related by |x − y|² = 2 − 2 × ⟨x, y⟩ for normalized vectors」。注意它报的是平方距离,第四章那个恒等式校验正好对上。
四、归一化前后:三张榜合并成一张
把同一批向量和查询都缩到单位长度之后,三种度量的 top-1 在 20 条查询上全部一致,top-5 交集从 1.4 / 0.6 / 2.6 一起变成 5.0。
4.1 只多一步 unit,其余全不动
第二个脚本与第一个脚本的造数据方式逐行相同,种子也相同,多出来的只有一行:把每条向量、每条查询都除以自己的模长。末尾再补一行恒等式校验,专门验 3.3 那个式子。
🧪 实测环境:Python 3.13.12 / macOS / 仅标准库。脚本:
work/exp1027/e05_norm.py
"""e05_norm.py —— 归一化前后对照:三种度量会不会合并成一条名次。"""importmath,random random.seed(20261027)# 与 e05_metric.py 同一种子N,D,QN=200,12,20defrv():d=[random.gauss(0,1)for_inrange(D)]s=math.exp(random.uniform(-1.5,1.5))return[x*s/math.sqrt(sum(y*yforyind))forxind]dot=lambdaa,b:sum(x*yforx,yinzip(a,b))cos=lambdaa,b:dot(a,b)/(math.sqrt(dot(a,a))*math.sqrt(dot(b,b)))l2=lambdaa,b:math.sqrt(sum((x-y)**2forx,yinzip(a,b)))nz=lambdaa:[x/math.sqrt(dot(a,a))forxina]run=lambdaV,QS:[tuple(sorted(range(N),key=lambdai:f(q,V[i]),reverse=hi)[:5]forf,hiin((dot,1),(cos,1),(l2,0)))forqinQS]V0,QS0=[rv()for_inrange(N)],[rv()for_inrange(QN)]V1,QS1=[nz(v)forvinV0],[nz(q)forqinQS0]A,B=run(V0,QS0),run(V1,QS1)agree=lambdaR,a,b:sum(t[a][0]==t[b][0]fortinR)ovl=lambdaR,a,b:sum(len(set(t[a])&set(t[b]))fortinR)/QN n0,n1=[math.sqrt(dot(v,v))forvinV0],[math.sqrt(dot(v,v))forvinV1]print("=== e05_norm · 归一化前后对照(%d 条 %d 维 / %d 条查询 / 同一种子)==="%(N,D,QN))print("模长:未归一化 %.3f~%.3f(均值 %.3f)→ 归一化后 %.2f~%.2f"%(min(n0),max(n0),sum(n0)/N,min(n1),max(n1)))print("%-13s %8s %8s %10s %10s"%("度量对","top1未归","top1归一","交集未归","交集归一"))fora,b,nmin((0,1,"内积 vs 余弦"),(0,2,"内积 vs L2"),(1,2,"余弦 vs L2")):print("%-15s %6d %8d %10.1f %10.1f"%(nm,agree(A,a,b),agree(B,a,b),ovl(A,a,b),ovl(B,a,b)))print("(top-1 一致满分 %d 条,交集满分 5.0)"%QN)dev=max(abs(l2(q,v)**2-(2-2*cos(q,v)))forqinQS1forvinV1)print("恒等式校验:归一化后 max |L2² − (2 − 2cos)| = %.1e(%d 对样本)"%(dev,N*QN))=== e05_norm · 归一化前后对照(200 条 12 维 / 20 条查询 / 同一种子)=== 模长:未归一化 0.226~4.477(均值 1.292)→ 归一化后 1.00~1.00 度量对 top1未归 top1归一 交集未归 交集归一 内积 vs 余弦 4 20 1.4 5.0 内积 vs L2 1 20 0.6 5.0 余弦 vs L2 13 20 2.6 5.0 (top-1 一致满分 20 条,交集满分 5.0) 恒等式校验:归一化后 max |L2² − (2 − 2cos)| = 1.3e-15(4000 对样本)4.2 三件事从这张表里直接读出来
- 未归一化那三行,与第一章的统计完全一致(4 / 1 / 13,1.4 / 0.6 / 2.6)。两个脚本各自独立生成数据、同一种子,数字对得上,说明差别来自度量,不来自抽样。
- 归一化后三行全是满分:top-1 一致 20 条,top-5 交集 5.0。之前那 16 条、19 条、7 条「换人」全部消失。
- 恒等式校验 1.3e-15:4000 对样本上,L2² 与 2 − 2cos 的最大偏差是 1.3 乘 10 的负 15 次方,属于双精度浮点的舍入量级。这不是近似关系,是恒等。
一句限定:这是 200 条 12 维的合成数据,用来暴露机制,不用来代表某个真实编码器的模长分布。真实模型上「差多少会翻名次」要看它自己的范数分布,但翻名次的条件(3.1 那个不等式)不会变。
五、四家官方文档对一遍:三条能对上,一条对不上
Qdrant、Milvus、faiss 三家的正文都把「归一化后内积等于余弦」写明白了;对不上的是 pgvector 那份 README——我原以为它会写「用内积建索引必须先归一化」,截至 2026-10-27 逐段核过,这句话不在里面。
5.1 Qdrant 与 Milvus:都把等价关系写在正文里
Qdrant 官方文档《Collections》页的 Distance metrics 一节,原文是:
For search efficiency, Cosine similarity is implemented as dot-product over normalized vectors. Vectors are automatically normalized during upload
这句讲的是它自己怎么实现 Cosine:上传时自动归一化。别把这句推广成「所有库用余弦都会替你归一化」,它只是 Qdrant 这一页在 2026-10-27 的表述。
Milvus 官方文档《Similarity Metrics》页对 IP 的说明是:
If you apply the IP distance metric to normalized embeddings, the result will be equivalent to calculating the cosine similarity between the embeddings.
同页 FAQ 又补了两句,原文照抄:
After normalization, inner product equals cosine similarity.
This occurs if you have not normalized the vectors when using inner product as the distance metric.
后一句是在回答「为什么内积搜索的第一名不是查询向量本身」,答案就是没归一化。3.1 那个不等式说的正是这件事。
5.2 pgvector:三个运算符,外加一个方向陷阱
pgvector 的 README 给的运算符是:
<->- L2 distance<#>- (negative) inner product<=>- cosine distance
紧接着还有一句,值得逐字看:
Note:
<#>returns the negative inner product since Postgres only supportsASCorder index scans on operators
翻成人话:索引只能升序扫,所以它把内积取负,让「越大越好」变成「越小越好」。把<#>的返回值直接当相似度排序,方向是反的,分数越负反而越像。换库踩这个坑,症状通常不是「结果略差」,而是「结果像随机的」。
至于「内积建索引要不要先归一化」:我逐段核过这份 README,没有这句话。它只要求给每种距离函数各建一个对应的 ops 索引(vector_ip_ops、vector_cosine_ops);唯一提到归一化的地方在 Performance → Exact Search 一节:「If vectors are normalized to length 1 (like OpenAI embeddings), use inner product for best performance.」——那是性能建议,不是索引的前置条件。
5.3 faiss:等价式写成公式,但报的是平方距离
faiss 官方 wiki《MetricType and distances》里两句关键原文:
This is not by itself cosine similarity, unless the vectors are normalized (lie on the surface of a unit hypersphere; see cosine similarity below).
Note that this is equivalent to using an index with
METRIC_L2, except that the distances are related by |x − y|² = 2 − 2 × ⟨x, y⟩ for normalized vectors.
同一页还有一句实操上很要命的:
Faiss reports squared Euclidean (L2) distance, avoiding the square root. This is still monotonic as the Euclidean distance, but if exact distances are needed, an additional square root of the result is needed.
名次不受开不开方影响(单调),但按距离阈值过滤时,阈值口径会差一个平方。Milvus 那边也一样,原文是「Milvus only caculates the value before applying square root when Euclidean distance is chosen as the distance metric.」——caculates是原文拼写,照抄不改。
这份资料是什么:把 Qdrant / Milvus / pgvector / faiss 四份距离度量文档的关键原句摘成对照表,加上本文两个实验脚本的注释版。第五章那几条原文,在表里能一条条对着看,放在资料包里,扫码即可获取:
六、什么时候该停手:对齐写入侧,别在查询侧补救
度量混用是写入侧的口径问题,不是查询侧的参数问题;三种度量选哪个都能用,前提是全链路一个口径,并且离线评测与线上召回走同一个函数。
6.1 两个预警指标,先算再看
第一个:模长极差 ÷ 均值。本文这组数据是 (4.477 − 0.226) ÷ 1.292 = 3.29,对应的结果是 top-1 只有 4/20 一致。这个比值不用跑检索就能算,入库前扫一遍向量范数即可。我按这组数据定的线是0.1:超过就停下来查,因为 top-k 内部的余弦差常常只有 0.01 量级(本文第 3、4 名只差 0.0059),模长差 1% 就够翻名次。
第二个:同一批查询、只换度量的 top-k 交集。5 个里掉到 4 个以下(也就是换了 2 个以上),就不用再讨论「是不是模型不行」,直接怀疑口径。本文未归一化时是 1.4/5,属于彻底不在一个世界里。
这两条线是我按本文这组合成数据定的,不是行业标准;换到你自己的数据上,线要按自己的余弦间距重定。
6.2 三个动作,有先后
写入侧归一化,一次做干净。入库前统一 unit,或者明确交给索引侧做并写进文档——最怕的是两边都以为对方做了。
索引侧的 metric 跟着写入口径走。换库时先核三件事:metric 名字对不对、返回值的正负号、报的是距离还是平方距离。pgvector 的<#>与 faiss 的平方 L2 都落在这三件事里。
离线评测用线上同一个函数。自己手写一份余弦去评离线、线上用的是库里的实现,两边差一点点就足够让 top-10 对不上,然后你会去怪召回,其实只是口径。
| 现象 | 最可能的原因 | 先查什么 | 动作 |
|---|---|---|---|
| 内积榜第一是长文本,余弦榜不是 | 写入侧没归一化 | 向量范数的极差 ÷ 均值 | 入库前统一 unit |
| 换库后结果像随机的 | 返回值方向反了 | 用的是<#>还是<=> | 乘 −1 或换运算符 |
| 按距离阈值过滤,效果骤降 | 拿到的是平方距离 | 结果有没有开根号 | 阈值改成平方 |
| 离线评测与线上 top-10 对不上 | 两边排序函数不同 | 是不是同一个库函数 | 统一成一个 |
| top-1 隔几天换一次 | top-k 内部余弦太接近,被模长扰动 | 第 1 与第 5 名的余弦差 | 对齐模长后重排 |
表下口径:五行都是本文两个实验里出现过的机制,按「现象 → 原因 → 检查点 → 动作」排,不按严重程度排。「阈值改成平方」指用 L2 平方做过滤时,阈值要换成距离的平方,否则等于把半径放大了。
6.3 别在查询侧补救
一个很容易想到的补法:查询时把查询向量归一化,问题就解决了。解决不了。归一化查询只让余弦变正确;L2 里的‖a‖²还在,内积里的‖a‖也还在——3.1 和 3.2 两个式子里的‖a‖一项都没被消掉。要修的是库里的向量,不是查询。
停手条件:模长极差 ÷ 均值 < 0.01、换度量的 top-5 交集满 5/5、离线与线上同一个函数,三条同时成立,这件事就不用再管。反过来,只要有一条不成立,先别急着调 top-k 或者换模型,回写入侧看一遍。
这份资料是什么:一张「度量混用」自查清单,把模长预警线、top-k 交集、平方距离阈值、负内积方向四件事写成可以逐项打勾的检查表,配合本文的判据直接照着走,放在资料包里,扫码即可获取:
附表 A:本文引用事实与出处对照表
| 事实 | 出处 | 本文位置 |
|---|---|---|
| 「For search efficiency, Cosine similarity is implemented as dot-product over normalized vectors. Vectors are automatically normalized during upload」 | Qdrant 官方文档《Collections》Distance metrics 一节;https://qdrant.tech/documentation/concepts/collections/ ;2026-10-27 核 | 第 5.1 节 |
| 「If you apply the IP distance metric to normalized embeddings, the result will be equivalent to calculating the cosine similarity between the embeddings.」 | Milvus 官方文档《Similarity Metrics》;https://milvus.io/docs/metric.md ;2026-10-27 核 | 第 5.1 节 |
| 「After normalization, inner product equals cosine similarity.」「This occurs if you have not normalized the vectors when using inner product as the distance metric.」 | 同上页 FAQ;2026-10-27 核 | 第 5.1 节 |
| 「Milvus only caculates the value before applying square root when Euclidean distance is chosen as the distance metric.」(原文拼写如此) | 同上页 Euclidean distance (L2) 一节;2026-10-27 核 | 第 5.3 节 |
「<->- L2 distance」「<#>- (negative) inner product」「<=>- cosine distance」,以及「Note:<#>returns the negative inner product since Postgres only supportsASCorder index scans on operators」 | pgvector 官方 README;https://github.com/pgvector/pgvector ;2026-10-27 核 | 第 5.2 节 |
该 README 无「用内积建索引必须先归一化」的表述;索引只要求按距离函数建对应 ops(vector_ip_ops/vector_cosine_ops),归一化建议仅出现在 Performance → Exact Search:「If vectors are normalized to length 1 (like OpenAI embeddings), use inner product for best performance.」 | 同上 README,逐段核对后的结论;2026-10-27 核 | 第 5.2 节 |
| 「This is not by itself cosine similarity, unless the vectors are normalized…」「the distances are related by |x − y|² = 2 − 2 × ⟨x, y⟩ for normalized vectors」「Faiss reports squared Euclidean (L2) distance, avoiding the square root.」 | faiss 官方 wiki《MetricType and distances》;https://github.com/facebookresearch/faiss/wiki/MetricType-and-distances ;2026-10-27 核 | 第 5.3 节 |
| 未归一化时三种度量的 top-1 与 top-5 交集(4 / 1 / 13 条,1.4 / 0.6 / 2.6);归一化后 20 / 20 / 20 条与 5.0;L2² = 2 − 2cos 最大偏差 1.3e-15 | 本文实测,脚本work/exp1027/e05_metric.py、work/exp1027/e05_norm.py | 第 1.2 节、第四章 |
表下口径:官方原文按页面原样抄录,未改标点、大小写与拼写;实测数字由两个脚本各跑一次得出,输出逐字粘贴;核验日期 2026-10-27。
写在最后:这篇用到的资料
写这篇文章时,把相关的官方文档和源码又翻了一遍,顺手也整理了几份配套的东西:
- 大模型学习路线图:从零基础到能自己动手做 Agent,按阶段说明每一步该学什么、哪些可以先跳过
- 《LangChain + LangGraph + MCP 智能体开发实战》视频课:7 个模块,从私有化部署、Embedding+RAG 到 MCP+Agent 全流程
- AI 大模型知识库(在线可查):Agent Skills 从入门到落地、Claude Skills 完全指南等专题,按目录浏览即可
- 640 套 AI 大模型行业报告 + 经典 PDF 书籍:看行业落地案例和别人怎么做的时候用得上
- 大模型零基础到精通教学视频:跟着敲一遍,比只读文档快得多
资料是我自己整理的,放在下面这个码上,扫码即可获取:
添加时备注「AI」,优先通过。
资料按「先路线、再动手、最后查漏」的顺序整理好了,建议先看学习路线那一份,照着它挑一条适合自己当前基础的路径再往下看。