[{"data":1,"prerenderedAt":1608},["ShallowReactive",2],{"post-\u002Fposts\u002Fdatabase-ai-week4":3,"all-posts-nav":1324},{"id":4,"title":5,"body":6,"categories":1304,"date":1306,"description":1307,"draft":1308,"extension":1309,"hidden":1308,"meta":1310,"navigation":1311,"path":1312,"published":1308,"seo":1313,"stem":1314,"tags":1315,"__hash__":1323},"posts\u002Fposts\u002Fdatabase-ai-week4.md","Week 4：数据库速成——从 Storage、Index、Query Optimization 到 Vector DB 与 RAG",{"type":7,"value":8,"toc":1270},"minimark",[9,18,21,28,33,36,47,50,56,59,90,93,97,100,211,214,218,221,224,227,247,250,254,257,260,266,269,272,278,281,284,288,291,294,300,303,320,323,340,343,347,350,356,359,362,382,385,396,400,403,420,423,429,432,435,449,452,458,461,467,470,474,477,480,486,489,506,509,512,516,519,525,528,531,534,594,597,601,607,610,616,619,645,648,652,655,658,664,667,672,678,681,685,691,694,697,720,723,727,730,736,739,745,748,751,755,758,861,864,878,881,885,888,891,911,914,918,921,927,930,936,939,945,948,951,974,978,981,987,990,994,997,1001,1004,1008,1011,1015,1018,1022,1025,1029,1032,1102,1105,1109,1112,1135,1138,1167,1171,1174,1221,1225,1228,1260,1264,1267],[10,11,12,13,17],"p",{},"Week 1 我们理解了 Autograd，Week 2 理解了 GPU 推理加速，Week 3 理解了分布式系统。Week 4 要补的是数据库，但目标不是成为数据库内核工程师，而是学会用数据库视角理解 AI 系统里的 ",[14,15,16],"strong",{},"Vector DB、RAG pipeline、LLM memory 和 retrieval latency","。",[10,19,20],{},"只看 CMU 15-445 中和 AI 最相关的四块：Storage & Buffer Pool、Index（B+ Tree \u002F LSM）、Query Optimization、Caching。你会发现，很多所谓“AI memory 系统”的核心问题，本质仍然是数据库老问题：数据怎么存、索引怎么建、查询怎么优化、缓存怎么命中。",[10,22,23],{},[24,25],"img",{"alt":26,"src":27},"Storage buffer cache","\u002Fimages\u002Fposts\u002Fdatabase-ai\u002Fstorage-buffer-cache.svg",[29,30,32],"h2",{"id":31},"_1-为什么-ai-系统要学数据库","1. 为什么 AI 系统要学数据库",[10,34,35],{},"一个 RAG 系统看起来像是 LLM 应用：",[37,38,44],"pre",{"className":39,"code":41,"language":42,"meta":43},[40],"language-text","用户问题 -> embedding -> 向量检索 -> rerank -> 拼 prompt -> LLM 回答\n","text","",[45,46,41],"code",{"__ignoreMap":43},[10,48,49],{},"但如果拆到底，它其实是一条数据库查询链路：",[37,51,54],{"className":52,"code":53,"language":42,"meta":43},[40],"query\n  -> query embedding\n  -> index lookup\n  -> metadata filter\n  -> top-k candidate\n  -> rerank\n  -> fetch document chunks\n  -> cache result\n",[45,55,53],{"__ignoreMap":43},[10,57,58],{},"这条链路里每一步都像数据库：",[60,61,62,66,69,72,75,78,81,84,87],"ul",{},[63,64,65],"li",{},"文档 chunk 是 record；",[63,67,68],{},"embedding 是向量字段；",[63,70,71],{},"metadata 是标量字段；",[63,73,74],{},"vector index 是特殊索引；",[63,76,77],{},"top-k retrieval 是近似查询；",[63,79,80],{},"rerank 是二阶段排序；",[63,82,83],{},"prompt context 是查询结果；",[63,85,86],{},"memory 是不断更新的知识表；",[63,88,89],{},"cache 命中率决定尾延迟。",[10,91,92],{},"所以理解数据库不是为了写 SQL，而是为了知道 retrieval 为什么慢、Vector DB 为什么这么设计、LLM memory 为什么难做。",[29,94,96],{"id":95},"_2-数据库视角下的-ai-数据","2. 数据库视角下的 AI 数据",[10,98,99],{},"AI 应用里常见数据可以分成几类：",[101,102,103,119],"table",{},[104,105,106],"thead",{},[107,108,109,113,116],"tr",{},[110,111,112],"th",{},"数据",[110,114,115],{},"数据库类比",[110,117,118],{},"例子",[120,121,122,134,145,156,167,178,189,200],"tbody",{},[107,123,124,128,131],{},[125,126,127],"td",{},"原始文档",[125,129,130],{},"heap file \u002F object storage",[125,132,133],{},"PDF、网页、Markdown",[107,135,136,139,142],{},[125,137,138],{},"文本块",[125,140,141],{},"record \u002F row",[125,143,144],{},"chunk text",[107,146,147,150,153],{},[125,148,149],{},"embedding",[125,151,152],{},"vector column",[125,154,155],{},"768\u002F1024\u002F1536 维向量",[107,157,158,161,164],{},[125,159,160],{},"metadata",[125,162,163],{},"scalar columns",[125,165,166],{},"source、time、author、tag",[107,168,169,172,175],{},[125,170,171],{},"索引",[125,173,174],{},"access path",[125,176,177],{},"B+Tree、HNSW、IVF、LSM",[107,179,180,183,186],{},[125,181,182],{},"对话记忆",[125,184,185],{},"mutable state",[125,187,188],{},"user profile、session memory",[107,190,191,194,197],{},[125,192,193],{},"检索缓存",[125,195,196],{},"result cache",[125,198,199],{},"query -> top-k chunks",[107,201,202,205,208],{},[125,203,204],{},"embedding 缓存",[125,206,207],{},"computed feature cache",[125,209,210],{},"text -> vector",[10,212,213],{},"当你说“让 LLM 有长期记忆”，工程上往往意味着：设计一张或多张表，存储内容、时间、来源、embedding、重要性分数、过期策略，然后提供低延迟检索和更新。",[29,215,217],{"id":216},"_3-storage数据到底怎么放","3. Storage：数据到底怎么放",[10,219,220],{},"数据库首先要解决 storage。数据不是抽象地“存在库里”，而是以 page、file、segment、SSTable、object 等形式落在磁盘或对象存储中。",[10,222,223],{},"传统数据库常见单位是 page，例如 4KB、8KB、16KB。Buffer pool 以 page 为单位把磁盘数据加载到内存。",[10,225,226],{},"AI 系统里也有类似问题：",[60,228,229,232,235,238,241,244],{},[63,230,231],{},"文档原文放对象存储还是数据库；",[63,233,234],{},"chunk text 和 embedding 放一起还是分开；",[63,236,237],{},"metadata 和 vector index 是否共存；",[63,239,240],{},"大 embedding 是否压缩；",[63,242,243],{},"冷数据是否下沉到便宜存储；",[63,245,246],{},"热门 chunk 是否常驻内存。",[10,248,249],{},"如果数据布局不合理，即使模型很强，检索也会慢。",[29,251,253],{"id":252},"_4-row-store-与-column-store","4. Row Store 与 Column Store",[10,255,256],{},"数据库常见两种布局：row store 和 column store。",[10,258,259],{},"Row store 把一行的数据放在一起：",[37,261,264],{"className":262,"code":263,"language":42,"meta":43},[40],"[id, text, embedding, source, timestamp]\n[id, text, embedding, source, timestamp]\n",[45,265,263],{"__ignoreMap":43},[10,267,268],{},"适合按主键取完整记录，例如取某个 chunk 的 text、metadata 和向量。",[10,270,271],{},"Column store 把同一列连续存放：",[37,273,276],{"className":274,"code":275,"language":42,"meta":43},[40],"id column\ntext column\nembedding column\nsource column\ntimestamp column\n",[45,277,275],{"__ignoreMap":43},[10,279,280],{},"适合分析查询和扫描某些列，例如只扫描 timestamp 或 source。",[10,282,283],{},"Vector DB 里经常混合使用：向量索引用特殊结构保存，metadata 用标量索引保存，chunk 原文可能放在独立 doc store 中。查询时先通过向量索引拿到 candidate id，再回表读取文本和 metadata。",[29,285,287],{"id":286},"_5-buffer-pool为什么缓存-page-很重要","5. Buffer Pool：为什么缓存 page 很重要",[10,289,290],{},"Buffer pool 是数据库在内存中管理磁盘 page 的组件。它解决的问题是：内存放不下所有数据，但频繁访问磁盘太慢，所以要把热 page 缓存在内存里。",[10,292,293],{},"基本流程：",[37,295,298],{"className":296,"code":297,"language":42,"meta":43},[40],"query needs page P\n  -> check buffer pool\n  -> hit: return memory page\n  -> miss: read page from disk\n  -> maybe evict another page\n",[45,299,297],{"__ignoreMap":43},[10,301,302],{},"几个关键概念：",[60,304,305,308,311,314,317],{},[63,306,307],{},"page table：记录 page id 到 frame 的映射；",[63,309,310],{},"frame：内存中的 page slot；",[63,312,313],{},"pin count：防止正在使用的 page 被淘汰；",[63,315,316],{},"dirty bit：page 是否被修改过，淘汰前是否要写回；",[63,318,319],{},"replacement policy：淘汰谁，例如 LRU、Clock、LRU-K。",[10,321,322],{},"对应到 RAG：",[60,324,325,328,331,334,337],{},[63,326,327],{},"热门文档 chunk 应该更容易留在 cache；",[63,329,330],{},"热门 query 的 top-k 结果可以缓存；",[63,332,333],{},"embedding 计算结果可以缓存；",[63,335,336],{},"rerank 结果可以缓存；",[63,338,339],{},"长尾冷数据可以接受更高延迟。",[10,341,342],{},"Buffer pool 思想告诉我们：性能不是只靠索引，缓存命中率同样关键。",[29,344,346],{"id":345},"_6-index索引是为了减少扫描","6. Index：索引是为了减少扫描",[10,348,349],{},"没有索引时，查询只能全表扫描：",[37,351,354],{"className":352,"code":353,"language":42,"meta":43},[40],"for row in table:\n    if row.source == \"paper\":\n        return row\n",[45,355,353],{"__ignoreMap":43},[10,357,358],{},"数据小的时候没问题，数据大了就不可接受。索引的作用是提供 access path，让查询直接跳到可能相关的数据。",[10,360,361],{},"AI 系统里至少有两类查询：",[363,364,365,379],"ol",{},[63,366,367,368,371,372,371,375,378],{},"标量查询：",[45,369,370],{},"source = paper","、",[45,373,374],{},"timestamp > 2025",[45,376,377],{},"user_id = 123","；",[63,380,381],{},"向量查询：找 embedding 距离 query embedding 最近的 top-k。",[10,383,384],{},"因此 Vector DB 通常需要同时支持：",[60,386,387,390,393],{},[63,388,389],{},"标量索引：B+ Tree、Hash、Bitmap；",[63,391,392],{},"向量索引：HNSW、IVF、PQ、DiskANN；",[63,394,395],{},"混合查询：vector search + metadata filter。",[29,397,399],{"id":398},"_7-b-tree最经典的范围查询索引","7. B+ Tree：最经典的范围查询索引",[10,401,402],{},"B+ Tree 是数据库里最常见的索引结构之一。它的特点是：",[60,404,405,408,411,414,417],{},[63,406,407],{},"多叉树，高度低；",[63,409,410],{},"内部节点只存 key 和指针；",[63,412,413],{},"叶子节点存 key 和 record pointer；",[63,415,416],{},"叶子节点之间有链表，方便范围扫描；",[63,418,419],{},"适合磁盘和 page 访问模型。",[10,421,422],{},"结构大概是：",[37,424,427],{"className":425,"code":426,"language":42,"meta":43},[40],"          [30 | 60]\n        \u002F    |     \\\n   [1..29] [30..59] [60..99]\n",[45,428,426],{"__ignoreMap":43},[10,430,431],{},"为什么不用普通二叉树？因为磁盘 I\u002FO 很贵，B+ Tree 一个节点可以放很多 key，对应一个 page。这样树高度很低，几次 page read 就能找到数据。",[10,433,434],{},"B+ Tree 适合：",[60,436,437,440,443,446],{},[63,438,439],{},"主键查询；",[63,441,442],{},"范围查询；",[63,444,445],{},"排序扫描；",[63,447,448],{},"metadata filter，例如 timestamp、doc_id、user_id。",[10,450,451],{},"在 RAG 中，B+ Tree 可以用来做标量过滤：",[37,453,456],{"className":454,"code":455,"language":42,"meta":43},[40],"先过滤 user_id = 123 and timestamp > 2025\n再在过滤后的文档集合里做向量检索\n",[45,457,455],{"__ignoreMap":43},[10,459,460],{},"或者反过来：",[37,462,465],{"className":463,"code":464,"language":42,"meta":43},[40],"先 ANN 召回 top-1000\n再用 metadata filter 过滤\n",[45,466,464],{"__ignoreMap":43},[10,468,469],{},"哪个更好，就是 query optimization 的问题。",[29,471,473],{"id":472},"_8-lsm-tree写优化索引","8. LSM Tree：写优化索引",[10,475,476],{},"LSM Tree 常见于 RocksDB、LevelDB、Cassandra 等系统。它适合写多读也多的场景。",[10,478,479],{},"核心思想：先写内存，再批量刷盘，磁盘上以有序文件保存。",[37,481,484],{"className":482,"code":483,"language":42,"meta":43},[40],"write -> WAL\n      -> MemTable\n      -> flush to SSTable\n      -> compaction\n",[45,485,483],{"__ignoreMap":43},[10,487,488],{},"关键组件：",[60,490,491,494,497,500,503],{},[63,492,493],{},"WAL：write-ahead log，防止内存数据丢失；",[63,495,496],{},"MemTable：内存中的有序结构；",[63,498,499],{},"SSTable：磁盘上的不可变有序文件；",[63,501,502],{},"Compaction：合并多个 SSTable，清理旧版本和删除标记；",[63,504,505],{},"Bloom Filter：快速判断某个 key 是否可能存在。",[10,507,508],{},"LSM 的优点是写入吞吐高，因为随机写变成顺序写。缺点是读可能需要查多个层级，compaction 也会带来后台开销。",[10,510,511],{},"对应 AI memory：如果你的记忆系统频繁写入新事实、新对话、新工具结果，LSM 思想就很重要。很多向量库或嵌入式存储底层会用 LSM KV 来保存 metadata 或对象。",[29,513,515],{"id":514},"_9-向量索引为什么不是简单-b-tree","9. 向量索引：为什么不是简单 B+ Tree",[10,517,518],{},"Embedding 是高维向量，例如 768 维或 1536 维。我们关心的是相似度：",[37,520,523],{"className":521,"code":522,"language":42,"meta":43},[40],"cosine similarity(query_vector, doc_vector)\n",[45,524,522],{"__ignoreMap":43},[10,526,527],{},"高维空间里，B+ Tree 这类一维有序索引不适合直接做 nearest neighbor。向量检索通常用 ANN：Approximate Nearest Neighbor。",[10,529,530],{},"ANN 的核心取舍是：牺牲一点召回精度，换取大幅查询速度提升。",[10,532,533],{},"常见向量索引：",[101,535,536,548],{},[104,537,538],{},[107,539,540,542,545],{},[110,541,171],{},[110,543,544],{},"思想",[110,546,547],{},"特点",[120,549,550,561,572,583],{},[107,551,552,555,558],{},[125,553,554],{},"HNSW",[125,556,557],{},"小世界图，沿图贪心搜索",[125,559,560],{},"召回高、内存占用大",[107,562,563,566,569],{},[125,564,565],{},"IVF",[125,567,568],{},"聚类分桶，先找近的 bucket",[125,570,571],{},"速度快，依赖聚类质量",[107,573,574,577,580],{},[125,575,576],{},"PQ",[125,578,579],{},"向量量化压缩",[125,581,582],{},"省内存，可能损失精度",[107,584,585,588,591],{},[125,586,587],{},"DiskANN",[125,589,590],{},"面向磁盘\u002FSSD 的图索引",[125,592,593],{},"大规模低成本存储",[10,595,596],{},"Vector DB 的核心不是“存向量”，而是在延迟、召回率、内存占用、更新成本之间做取舍。",[29,598,600],{"id":599},"_10-rag-pipeline数据库视角","10. RAG Pipeline：数据库视角",[10,602,603],{},[24,604],{"alt":605,"src":606},"RAG vector database pipeline","\u002Fimages\u002Fposts\u002Fdatabase-ai\u002Frag-vector-db.svg",[10,608,609],{},"一个典型 RAG pipeline：",[37,611,614],{"className":612,"code":613,"language":42,"meta":43},[40],"离线：\ndocuments\n  -> parse\n  -> chunk\n  -> embedding\n  -> build vector index\n  -> store metadata and text\n\n在线：\nquery\n  -> query embedding\n  -> ANN search\n  -> metadata filter\n  -> rerank\n  -> fetch top-k chunks\n  -> build prompt\n  -> LLM answer\n",[45,615,613],{"__ignoreMap":43},[10,617,618],{},"从数据库视角看：",[60,620,621,624,627,630,633,636,639,642],{},[63,622,623],{},"parse\u002Fchunk 是 ETL；",[63,625,626],{},"embedding 是特征生成；",[63,628,629],{},"vector index 是 access method；",[63,631,632],{},"metadata filter 是 predicate；",[63,634,635],{},"rerank 是二阶段 query processing；",[63,637,638],{},"top-k 是排序和截断；",[63,640,641],{},"prompt assembly 是结果 materialization；",[63,643,644],{},"query cache 是 result cache。",[10,646,647],{},"所以 RAG 优化不能只调 prompt。很多时候更该问：chunk 是否合理、索引参数是否合理、metadata filter 顺序是否合理、cache 是否命中、rerank 是否太慢。",[29,649,651],{"id":650},"_11-query-optimization为什么执行顺序很重要","11. Query Optimization：为什么执行顺序很重要",[10,653,654],{},"同一个查询有多种执行计划。数据库优化器要选择成本最低的计划。",[10,656,657],{},"比如用户问：",[37,659,662],{"className":660,"code":661,"language":42,"meta":43},[40],"只在 2024 年后的论文里，找和 diffusion acceleration 相关的段落\n",[45,663,661],{"__ignoreMap":43},[10,665,666],{},"可能有两种计划：",[668,669,671],"h3",{"id":670},"plan-a先向量检索再过滤","Plan A：先向量检索，再过滤",[37,673,676],{"className":674,"code":675,"language":42,"meta":43},[40],"ANN search top-1000\n  -> filter year >= 2024\n  -> rerank top-50\n",[45,677,675],{"__ignoreMap":43},[10,679,680],{},"如果过滤条件不严格，这个计划很好。",[668,682,684],{"id":683},"plan-b先-metadata-filter再向量检索","Plan B：先 metadata filter，再向量检索",[37,686,689],{"className":687,"code":688,"language":42,"meta":43},[40],"filter year >= 2024\n  -> ANN search within filtered subset\n  -> rerank top-50\n",[45,690,688],{"__ignoreMap":43},[10,692,693],{},"如果过滤条件很严格，这个计划可能更好。",[10,695,696],{},"优化器要估算：",[60,698,699,702,705,708,711,714,717],{},[63,700,701],{},"过滤条件选择率；",[63,703,704],{},"ANN search 成本；",[63,706,707],{},"rerank 成本；",[63,709,710],{},"回表读取成本；",[63,712,713],{},"cache 命中率；",[63,715,716],{},"top-k 大小；",[63,718,719],{},"网络开销。",[10,721,722],{},"这就是为什么一些 Vector DB 提供 hybrid search 和 filter pushdown。它们本质上是在做查询优化。",[29,724,726],{"id":725},"_12-cost-model数据库如何估算成本","12. Cost Model：数据库如何估算成本",[10,728,729],{},"数据库优化器会用 cost model 比较执行计划。简化看：",[37,731,734],{"className":732,"code":733,"language":42,"meta":43},[40],"cost = I\u002FO cost + CPU cost + network cost + memory cost\n",[45,735,733],{"__ignoreMap":43},[10,737,738],{},"RAG 里可以类似估算：",[37,740,743],{"className":741,"code":742,"language":42,"meta":43},[40],"retrieval latency = embedding latency\n                  + ANN search latency\n                  + metadata filter latency\n                  + fetch chunk latency\n                  + rerank latency\n                  + network latency\n",[45,744,742],{"__ignoreMap":43},[10,746,747],{},"如果 rerank 模型很大，rerank 可能成为瓶颈。如果 chunk 存在远程对象存储，fetch chunk 可能成为瓶颈。如果 query embedding 没缓存，embedding API 延迟也可能主导整体体验。",[10,749,750],{},"优化前一定要测量，不要凭感觉。",[29,752,754],{"id":753},"_13-caching缓存什么最划算","13. Caching：缓存什么最划算",[10,756,757],{},"AI 系统里缓存非常重要。常见缓存层：",[101,759,760,776],{},[104,761,762],{},[107,763,764,767,770,773],{},[110,765,766],{},"缓存",[110,768,769],{},"Key",[110,771,772],{},"Value",[110,774,775],{},"适用场景",[120,777,778,792,806,819,833,847],{},[107,779,780,783,786,789],{},[125,781,782],{},"Embedding cache",[125,784,785],{},"text hash",[125,787,788],{},"vector",[125,790,791],{},"重复文本、重复 query",[107,793,794,797,800,803],{},[125,795,796],{},"Retrieval cache",[125,798,799],{},"query hash",[125,801,802],{},"top-k ids",[125,804,805],{},"热门问题",[107,807,808,811,814,816],{},[125,809,810],{},"Chunk cache",[125,812,813],{},"chunk id",[125,815,42],{},[125,817,818],{},"热门文档",[107,820,821,824,827,830],{},[125,822,823],{},"Rerank cache",[125,825,826],{},"query + candidate ids",[125,828,829],{},"rerank scores",[125,831,832],{},"重复检索结果",[107,834,835,838,841,844],{},[125,836,837],{},"Prompt cache",[125,839,840],{},"prefix tokens",[125,842,843],{},"KV cache \u002F token states",[125,845,846],{},"长系统提示、固定上下文",[107,848,849,852,855,858],{},[125,850,851],{},"Answer cache",[125,853,854],{},"normalized query",[125,856,857],{},"final answer",[125,859,860],{},"FAQ 类场景",[10,862,863],{},"缓存要考虑四个问题：",[363,865,866,869,872,875],{},[63,867,868],{},"命中率高不高；",[63,870,871],{},"value 计算成本贵不贵；",[63,873,874],{},"value 会不会过期；",[63,876,877],{},"缓存错误会不会影响正确性。",[10,879,880],{},"比如 embedding cache 通常很安全，因为同一文本的 embedding 稳定。answer cache 风险更高，因为答案可能依赖时间、权限、上下文。",[29,882,884],{"id":883},"_14-cache-invalidation缓存失效比缓存更难","14. Cache Invalidation：缓存失效比缓存更难",[10,886,887],{},"缓存最大的问题是失效。文档更新后，旧的 embedding、旧的 retrieval result、旧的 answer 都可能过期。",[10,889,890],{},"常见策略：",[60,892,893,896,899,902,905,908],{},[63,894,895],{},"TTL：过一段时间自动失效；",[63,897,898],{},"version：文档版本变化后 cache key 变化；",[63,900,901],{},"explicit invalidation：更新文档时主动删缓存；",[63,903,904],{},"write-through：写入时同步更新缓存；",[63,906,907],{},"lazy refresh：读到旧缓存时异步刷新；",[63,909,910],{},"namespace：按用户、项目、知识库隔离缓存。",[10,912,913],{},"RAG 系统尤其要注意权限。如果 retrieval cache 没有把 user_id、tenant_id、permission version 放进 cache key，可能出现越权召回。",[29,915,917],{"id":916},"_15-llm-memory长期记忆是数据库问题","15. LLM Memory：长期记忆是数据库问题",[10,919,920],{},"LLM memory 常被包装得很神秘，但工程上通常是：",[37,922,925],{"className":923,"code":924,"language":42,"meta":43},[40],"memory item = {\n  id,\n  user_id,\n  content,\n  embedding,\n  importance,\n  timestamp,\n  source,\n  access_count,\n  expires_at\n}\n",[45,926,924],{"__ignoreMap":43},[10,928,929],{},"写入 memory：",[37,931,934],{"className":932,"code":933,"language":42,"meta":43},[40],"conversation\u002Ftool result\n  -> extract facts\n  -> score importance\n  -> deduplicate\n  -> embed\n  -> upsert memory store\n",[45,935,933],{"__ignoreMap":43},[10,937,938],{},"读取 memory：",[37,940,943],{"className":941,"code":942,"language":42,"meta":43},[40],"current query\n  -> embed query\n  -> retrieve relevant memories\n  -> filter by user\u002Fsession\u002Fpermission\n  -> rerank by relevance + recency + importance\n  -> inject into prompt\n",[45,944,942],{"__ignoreMap":43},[10,946,947],{},"这就是一个带向量索引、标量过滤、更新策略、缓存策略的数据库系统。",[10,949,950],{},"LLM memory 难点：",[60,952,953,956,959,962,965,968,971],{},[63,954,955],{},"什么时候写入；",[63,957,958],{},"写入什么粒度；",[63,960,961],{},"如何去重和合并；",[63,963,964],{},"如何处理过期记忆；",[63,966,967],{},"如何避免错误记忆污染；",[63,969,970],{},"如何控制检索延迟；",[63,972,973],{},"如何保证用户隔离和隐私。",[29,975,977],{"id":976},"_16-retrieval-latency慢在哪里","16. Retrieval Latency：慢在哪里",[10,979,980],{},"一次 RAG 检索可能慢在很多地方：",[37,982,985],{"className":983,"code":984,"language":42,"meta":43},[40],"query normalization\n  -> embedding API\n  -> vector DB network call\n  -> ANN index search\n  -> metadata filtering\n  -> fetch full chunk text\n  -> rerank model\n  -> prompt assembly\n",[45,986,984],{"__ignoreMap":43},[10,988,989],{},"优化要先定位瓶颈。",[668,991,993],{"id":992},"_161-embedding-慢","16.1 Embedding 慢",[10,995,996],{},"优化：embedding cache、批量 embedding、本地 embedding 模型、更小模型、异步预计算。",[668,998,1000],{"id":999},"_162-ann-search-慢","16.2 ANN search 慢",[10,1002,1003],{},"优化：调 HNSW ef_search、IVF nprobe、减少搜索范围、增加内存、使用量化、冷热分层。",[668,1005,1007],{"id":1006},"_163-metadata-filter-慢","16.3 Metadata filter 慢",[10,1009,1010],{},"优化：建立标量索引、filter pushdown、先过滤再向量搜、权限 bitmap。",[668,1012,1014],{"id":1013},"_164-fetch-chunk-慢","16.4 Fetch chunk 慢",[10,1016,1017],{},"优化：chunk cache、把 hot text 放近、减少回表、列裁剪、压缩。",[668,1019,1021],{"id":1020},"_165-rerank-慢","16.5 Rerank 慢",[10,1023,1024],{},"优化：减少候选数、batch rerank、小模型 rerank、只对高价值 query rerank、缓存 rerank 分数。",[29,1026,1028],{"id":1027},"_17-b-treelsmvector-index-怎么选","17. B+ Tree、LSM、Vector Index 怎么选",[10,1030,1031],{},"一个 AI memory \u002F RAG 系统里通常不是只用一种索引。",[101,1033,1034,1044],{},[104,1035,1036],{},[107,1037,1038,1041],{},[110,1039,1040],{},"查询需求",[110,1042,1043],{},"合适结构",[120,1045,1046,1054,1062,1070,1078,1086,1094],{},[107,1047,1048,1051],{},[125,1049,1050],{},"按 id 查 chunk",[125,1052,1053],{},"Hash \u002F B+ Tree",[107,1055,1056,1059],{},[125,1057,1058],{},"按时间范围查",[125,1060,1061],{},"B+ Tree",[107,1063,1064,1067],{},[125,1065,1066],{},"按用户过滤",[125,1068,1069],{},"Hash \u002F B+ Tree \u002F Bitmap",[107,1071,1072,1075],{},[125,1073,1074],{},"高频写入 memory",[125,1076,1077],{},"LSM KV",[107,1079,1080,1083],{},[125,1081,1082],{},"向量相似度 top-k",[125,1084,1085],{},"HNSW \u002F IVF \u002F PQ \u002F DiskANN",[107,1087,1088,1091],{},[125,1089,1090],{},"大规模冷数据",[125,1092,1093],{},"DiskANN \u002F object store + metadata index",[107,1095,1096,1099],{},[125,1097,1098],{},"混合检索",[125,1100,1101],{},"Vector index + scalar index + optimizer",[10,1103,1104],{},"真正的系统通常是组合拳：LSM 存 metadata，object store 存原文，HNSW 存热向量，DiskANN 存冷向量，Redis 缓存热门结果。",[29,1106,1108],{"id":1107},"_18-vector-db-不是魔法","18. Vector DB 不是魔法",[10,1110,1111],{},"Vector DB 一般包括：",[60,1113,1114,1117,1120,1123,1126,1129,1132],{},[63,1115,1116],{},"storage layer：保存向量、metadata、文档引用；",[63,1118,1119],{},"index layer：HNSW、IVF、PQ 等；",[63,1121,1122],{},"query layer：top-k、filter、hybrid search；",[63,1124,1125],{},"update layer：insert、delete、compaction、rebuild；",[63,1127,1128],{},"cache layer：热向量、热结果、热文档；",[63,1130,1131],{},"distributed layer：sharding、replication、load balancing；",[63,1133,1134],{},"consistency layer：写入可见性、快照、版本控制。",[10,1136,1137],{},"所以评价一个 Vector DB，要看：",[60,1139,1140,1143,1146,1149,1152,1155,1158,1161,1164],{},[63,1141,1142],{},"recall-latency 曲线；",[63,1144,1145],{},"写入和删除成本；",[63,1147,1148],{},"metadata filter 能力；",[63,1150,1151],{},"是否支持多租户隔离；",[63,1153,1154],{},"索引重建成本；",[63,1156,1157],{},"热更新是否影响查询；",[63,1159,1160],{},"内存占用；",[63,1162,1163],{},"tail latency；",[63,1165,1166],{},"运维复杂度。",[29,1168,1170],{"id":1169},"_19-rag-优化-checklist","19. RAG 优化 Checklist",[10,1172,1173],{},"做 RAG 系统时，可以按数据库思路检查：",[363,1175,1176,1179,1182,1185,1188,1191,1194,1197,1200,1203,1206,1209,1212,1215,1218],{},[63,1177,1178],{},"Chunk 粒度是否适合查询；",[63,1180,1181],{},"Embedding 模型是否和领域匹配；",[63,1183,1184],{},"向量索引参数是否测过 recall-latency；",[63,1186,1187],{},"Metadata filter 是否有索引；",[63,1189,1190],{},"Filter 是先做还是后做；",[63,1192,1193],{},"Top-k 候选数是否合理；",[63,1195,1196],{},"Rerank 是否成为瓶颈；",[63,1198,1199],{},"Chunk text 是否频繁回表；",[63,1201,1202],{},"Embedding \u002F retrieval \u002F rerank 是否有缓存；",[63,1204,1205],{},"Cache key 是否包含用户权限和版本；",[63,1207,1208],{},"文档更新后索引和缓存如何失效；",[63,1210,1211],{},"P95\u002FP99 latency 慢在哪里；",[63,1213,1214],{},"召回错误是 chunk 问题、embedding 问题还是 index 问题；",[63,1216,1217],{},"是否需要冷热分层；",[63,1219,1220],{},"是否需要分片和副本。",[29,1222,1224],{"id":1223},"_20-week-4-学完应该掌握什么","20. Week 4 学完应该掌握什么",[10,1226,1227],{},"这一周不要求你能实现数据库内核，但要能讲清楚：",[60,1229,1230,1233,1236,1239,1242,1245,1248,1251,1254,1257],{},[63,1231,1232],{},"Storage 为什么决定数据读取路径；",[63,1234,1235],{},"Buffer pool 为什么能显著影响性能；",[63,1237,1238],{},"B+ Tree 为什么适合范围查询和 metadata filter；",[63,1240,1241],{},"LSM Tree 为什么适合高写入场景；",[63,1243,1244],{},"向量索引为什么要做 ANN，而不是简单排序全量向量；",[63,1246,1247],{},"Query optimizer 为什么要选择执行计划；",[63,1249,1250],{},"RAG pipeline 为什么是一条数据库查询链路；",[63,1252,1253],{},"Caching 应该缓存 embedding、retrieval、chunk、rerank 还是 answer；",[63,1255,1256],{},"LLM memory 为什么本质是带向量检索的数据库状态；",[63,1258,1259],{},"Retrieval latency 应该如何拆解和定位。",[29,1261,1263],{"id":1262},"_21-最后总结","21. 最后总结",[10,1265,1266],{},"数据库不是 AI 系统的外围组件，而是 RAG、Vector DB、LLM memory 的底层骨架。Storage 决定数据怎么放，Buffer Pool 决定热数据怎么留在内存，Index 决定如何避免全量扫描，Query Optimization 决定执行顺序，Caching 决定尾延迟。",[10,1268,1269],{},"当你用这套视角看 RAG，就不会只停留在“换 embedding 模型”或“调 prompt”。你会开始系统性地问：数据布局对吗，索引选型对吗，filter 顺序对吗，缓存 key 对吗，P99 慢在哪里。这才是把 AI 应用做成可靠系统的关键。",{"title":43,"searchDepth":1271,"depth":1272,"links":1273},2,3,[1274,1275,1276,1277,1278,1279,1280,1281,1282,1283,1284,1288,1289,1290,1291,1292,1299,1300,1301,1302,1303],{"id":31,"depth":1271,"text":32},{"id":95,"depth":1271,"text":96},{"id":216,"depth":1271,"text":217},{"id":252,"depth":1271,"text":253},{"id":286,"depth":1271,"text":287},{"id":345,"depth":1271,"text":346},{"id":398,"depth":1271,"text":399},{"id":472,"depth":1271,"text":473},{"id":514,"depth":1271,"text":515},{"id":599,"depth":1271,"text":600},{"id":650,"depth":1271,"text":651,"children":1285},[1286,1287],{"id":670,"depth":1272,"text":671},{"id":683,"depth":1272,"text":684},{"id":725,"depth":1271,"text":726},{"id":753,"depth":1271,"text":754},{"id":883,"depth":1271,"text":884},{"id":916,"depth":1271,"text":917},{"id":976,"depth":1271,"text":977,"children":1293},[1294,1295,1296,1297,1298],{"id":992,"depth":1272,"text":993},{"id":999,"depth":1272,"text":1000},{"id":1006,"depth":1272,"text":1007},{"id":1013,"depth":1272,"text":1014},{"id":1020,"depth":1272,"text":1021},{"id":1027,"depth":1271,"text":1028},{"id":1107,"depth":1271,"text":1108},{"id":1169,"depth":1271,"text":1170},{"id":1223,"depth":1271,"text":1224},{"id":1262,"depth":1271,"text":1263},[1305],"技术","2026-05-05 12:00:00","Week 1 我们理解了 Autograd，Week 2 理解了 GPU 推理加速，Week 3 理解了分布式系统。Week 4 要补的是数据库，但目标不是成为数据库内核工程师，而是学会用数据库视角理解 AI 系统里的 Vector DB、RAG pipeline、LLM memory 和 retrieval latency。",false,"md",{},true,"\u002Fposts\u002Fdatabase-ai-week4",{"title":5,"description":1307},"posts\u002Fdatabase-ai-week4",[1316,1317,1318,1319,1320,1321,1322],"数据库","CMU 15-445","Vector DB","RAG","LLM Memory","Query Optimization","Caching","BnwoQ5VZVBohDfjxKxl_TfolPUb45pp7kKkv0X_LpQ8",[1325,1337,1350,1357,1370,1380,1390,1401,1412,1421,1431,1443,1456,1468,1477,1487,1491,1502,1512,1520,1531,1538,1544,1550,1559,1569,1577,1583,1591,1599],{"slug":1326,"path":1327,"title":1328,"date":1329,"tags":1330,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1336},"multimodal-rag-from-scratch","\u002Fposts\u002Fmultimodal-rag-from-scratch","从零实现多模态 RAG：BM25、Dense 检索、RRF 融合、MMR 重排全部手写","2026-06-30 18:00:00",[1319,1331,1332,1333,1334,1098,1335],"多模态","AI Infra","BM25","向量检索","实习求职",9,{"slug":1338,"path":1339,"title":1340,"date":1341,"tags":1342,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1349},"mini-llm-engine-deep-dive","\u002Fposts\u002Fmini-llm-engine-deep-dive","讲透 mini-llm-engine：从显存碎片到六大推理优化","2026-06-30 14:00:00",[1343,1332,1344,1345,1346,1347,1348,1335],"LLM","vLLM","PagedAttention","KV Cache","推理优化","投机解码",11,{"slug":1351,"path":1352,"title":1353,"date":1354,"tags":1355,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1356},"mini-llm-engine-from-scratch","\u002Fposts\u002Fmini-llm-engine-from-scratch","从零实现 LLM 推理引擎：深挖 vLLM 的六大核心优化","2026-06-30 10:00:00",[1343,1332,1344,1345,1347,1348,1335],10,{"slug":1358,"path":1359,"title":1360,"date":1361,"tags":1362,"description":1368,"draft":1308,"hidden":1308,"published":1311,"readingTime":1369},"bytedance-recommendation-architecture-intern-interview","\u002Fposts\u002Fbytedance-recommendation-architecture-intern-interview","字节推荐架构实习生 Data 面试准备：推荐系统、实时特征与高并发八股","2026-06-09",[1363,1364,1365,1366,1367],"面试","推荐系统","后端架构","实时计算","字节跳动","面向字节跳动推荐架构团队实习岗位的八股准备清单，覆盖推荐系统链路、实时数据、特征服务、高并发后端、分布式系统与项目包装。",18,{"slug":1371,"path":1372,"title":1373,"date":1361,"tags":1374,"description":1378,"draft":1308,"hidden":1308,"published":1311,"readingTime":1379},"high-concurrency-rate-limiting-algorithms","\u002Fposts\u002Fhigh-concurrency-rate-limiting-algorithms","高并发限流算法：固定窗口、滑动窗口、漏桶与令牌桶",[1375,1376,1365,1377,1363],"高并发","限流","系统设计","面试和工程都常见的限流算法总结，讲清楚固定窗口、滑动窗口、漏桶、令牌桶、并发数限制以及分布式限流如何落地。",12,{"slug":1381,"path":1382,"title":1383,"date":1361,"tags":1384,"description":1388,"draft":1308,"hidden":1308,"published":1311,"readingTime":1389},"kafka-producer-broker-consumer","\u002Fposts\u002Fkafka-producer-broker-consumer","Kafka 入门：生产者、Broker、消费者和“消费”到底是什么意思",[1385,1386,1387,1363,1364],"Kafka","消息队列","后端","用推荐系统里的用户行为日志为例，讲清楚 Kafka 的作用、Producer、Broker、Consumer、Topic、Partition、Offset 和消费语义。",8,{"slug":1391,"path":1392,"title":1393,"date":1361,"tags":1394,"description":1399,"draft":1308,"hidden":1308,"published":1311,"readingTime":1400},"leetcode-lru-merge-k-reverse-list","\u002Fposts\u002Fleetcode-lru-merge-k-reverse-list","链表与缓存高频题：LRU Cache、合并 K 个有序链表、反转链表",[1395,1396,1397,1398,1363],"算法","链表","LRU","LeetCode","面试高频算法题速记，整理 LRU Cache、合并 K 个有序链表、反转链表的核心思路、复杂度和 C++ 代码。",6,{"slug":1402,"path":1403,"title":1404,"date":1405,"tags":1406,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1411},"meddococr-interpreter-source-analysis","\u002Fposts\u002Fmeddococr-interpreter-source-analysis","MedDocOCR-Interpreter 源码导读：医疗文档 OCR、结构化抽取与报告解读原型","2026-05-22 10:30:00",[1407,1331,1408,1319,1409,1410],"OCR","医疗 AI","Python","源码分析",16,{"slug":1413,"path":1414,"title":1415,"date":1416,"tags":1417,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1356},"cet6-writing-model-essays","\u002Fposts\u002Fcet6-writing-model-essays","六级写作范文背诵包：10 个高频话题","2026-05-20 09:00:00",[1418,1419,1420],"English","CET6","Writing",{"slug":1422,"path":1423,"title":1424,"date":1425,"tags":1426,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1430},"claude-code-context-management","\u002Fposts\u002Fclaude-code-context-management","Claude Code 上下文管理机制：从 Microcompact 到 Auto Compact","2026-05-19 10:00:00",[1427,1428,1343,1332,1429],"Claude Code","Agent","上下文工程",27,{"slug":1432,"path":1433,"title":1434,"date":1435,"tags":1436,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1442},"nanotron-llm-pretraining-framework-analysis","\u002Fposts\u002Fnanotron-llm-pretraining-framework-analysis","Nanotron 项目详解：Hugging Face 的大模型预训练框架怎么做分布式训练","2026-05-10 12:10:00",[1343,1437,1438,1439,1440,1332,1441],"大模型训练","分布式训练","Nanotron","Hugging Face","PyTorch",19,{"slug":1444,"path":1445,"title":1446,"date":1447,"tags":1448,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1455},"gofoundry-go-backend-foundation-framework","\u002Fposts\u002Fgofoundry-go-backend-foundation-framework","GoFoundry 项目详解：基于 Go 的后端基础框架套件设计","2026-05-10 11:20:00",[1449,1450,1451,1452,1453,1386,1454],"Go","后端框架","ORM","分布式缓存","分布式锁","项目架构",25,{"slug":1457,"path":1458,"title":1459,"date":1460,"tags":1461,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1430},"cloudvault-go-cloud-storage-system","\u002Fposts\u002Fcloudvault-go-cloud-storage-system","CloudVault 项目详解：基于 Go 的云端存储与网盘系统架构设计","2026-05-10 10:30:00",[1449,1462,1463,1464,1454,1465,1466,1467],"云存储","网盘系统","分布式系统","Redis","RabbitMQ","Elasticsearch",{"slug":1469,"path":1470,"title":1471,"date":1472,"tags":1473,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1476},"openclaw-source-code-analysis","\u002Fposts\u002Fopenclaw-source-code-analysis","OpenClaw 源码导读：个人 AI 助手的网关、通道、插件与运行时架构","2026-05-08 16:30:00",[1474,1428,1332,1475,1410],"OpenClaw","TypeScript",20,{"slug":1478,"path":1479,"title":1480,"date":1481,"tags":1482,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1356},"flow-matching-generative-models","\u002Fposts\u002Fflow-matching-generative-models","Flow Matching：从噪声到数据的连续流生成模型","2026-05-07 00:00:00",[1483,1484,1485,1486],"生成模型","Diffusion","Flow Matching","深度学习",{"slug":1488,"path":1312,"title":5,"date":1306,"tags":1489,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1490},"database-ai-week4",[1316,1317,1318,1319,1320,1321,1322],15,{"slug":1492,"path":1493,"title":1494,"date":1495,"tags":1496,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1411},"distributed-systems-week3","\u002Fposts\u002Fdistributed-systems-week3","Week 3：分布式系统速成——MapReduce、Raft、容错与 Distributed KV Store","2026-05-05 11:00:00",[1464,1497,1498,1499,1500,1501,1428],"MIT 6.824","MapReduce","Raft","KV Store","Ray",{"slug":1503,"path":1504,"title":1505,"date":1506,"tags":1507,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1490},"gpu-inference-acceleration-week2","\u002Fposts\u002Fgpu-inference-acceleration-week2","Week 2：GPU 与推理加速——从 Kernel、算子融合到 LLM Serving","2026-05-05 10:00:00",[1486,1508,1509,1343,1510,1344,1511],"GPU","推理加速","CMU 10-414","TensorRT",{"slug":1513,"path":1514,"title":1515,"date":1516,"tags":1517,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1369},"dl-framework-autograd-mini","\u002Fposts\u002Fdl-framework-autograd-mini","Week 1：DL 框架与 Autograd——从计算图、反向传播到 Mini Autograd 实现","2026-05-05 09:00:00",[1486,1518,1441,1510,1519],"Autograd","Mini Framework",{"slug":1521,"path":1522,"title":1523,"date":1524,"tags":1525,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1379},"lock-free-concurrency-notes","\u002Fposts\u002Flock-free-concurrency-notes","无锁并发入门：从 CAS 到 Atomic Ring Buffer","2026-04-25",[1526,1527,1528,1529,1530],"C++","并发","无锁编程","性能优化","量化开发",{"slug":1532,"path":1533,"title":1534,"date":1535,"tags":1536,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1537},"agent-memory","\u002Fposts\u002Fagent-memory","Agent 对话记忆化：从原理到实现","2026-04-24",[1343,1428,1319,1363],5,{"slug":1539,"path":1540,"title":1541,"date":1535,"tags":1542,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1400},"llm-context-compression","\u002Fposts\u002Fllm-context-compression","LLM 上下文五层压缩机制详解",[1343,1428,1543,1363],"上下文压缩",{"slug":1545,"path":1546,"title":1547,"date":1548,"tags":1549,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1336},"cpp-concurrency-basics","\u002Fposts\u002Fcpp-concurrency-basics","C++ 并发编程入门：从数据竞争到线程池","2026-04-15",[1526,1527,1363,1530],{"slug":1551,"path":1552,"title":1553,"date":1554,"tags":1555,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1558},"travel-in-shenzhen","\u002Fposts\u002Ftravel-in-shenzhen","XCPC 深圳游记","2026-04-13",[1556,1526,1557],"XCPC","比赛",1,{"slug":1560,"path":1561,"title":1562,"date":1563,"tags":1564,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1568},"backend-stack-deep-dive","\u002Fposts\u002Fbackend-stack-deep-dive","后端五件套：FastAPI \u002F Node.js \u002F SQLAlchemy async \u002F PostgreSQL \u002F Docker 面试速通","2026-04-07",[1387,1565,1566,1567,1363],"FastAPI","PostgreSQL","Docker",7,{"slug":1570,"path":1571,"title":1572,"date":1573,"tags":1574,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1400},"deepscientist-tech-stack","\u002Fposts\u002Fdeepscientist-tech-stack","DeepScientist 技术栈全解析：一个 AI 科研平台的架构设计","2026-04-06",[1575,1565,1576,1566,1363],"全栈","Next.js",{"slug":1578,"path":1579,"title":1580,"date":1573,"tags":1581,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1389},"minicode-source-analysis","\u002Fposts\u002Fminicode-source-analysis","MiniCode 源码解析：用 5000 行 TypeScript 实现一个 AI 编程助手",[1475,1582,1343,1410,1363],"CLI",{"slug":1584,"path":1585,"title":1586,"date":1573,"tags":1587,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1537},"nova-theme-implementation","\u002Fposts\u002Fnova-theme-implementation","我是怎么从零实现 Nova 主题的",[1588,1589,1590],"Hexo","前端","开源",{"slug":1592,"path":1593,"title":1594,"date":1595,"tags":1596,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1271},"git-cheatsheet","\u002Fposts\u002Fgit-cheatsheet","Git 常用操作备忘","2026-04-05 14:00:00",[1597,1598],"Git","工具",{"slug":1600,"path":1601,"title":1602,"date":1603,"tags":1604,"description":43,"draft":1308,"hidden":1308,"published":1311,"readingTime":1272},"github-actions-intro","\u002Fposts\u002Fgithub-actions-intro","GitHub Actions 入门：自动化你的工作流","2026-04-04 09:00:00",[1605,1606,1607],"GitHub Actions","CI\u002FCD","自动化",1782796011453]