news 2026/10/3 6:02:21

ArxivLoader:学术论文批量下载、解析与RAG语料构建工程实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ArxivLoader:学术论文批量下载、解析与RAG语料构建工程实践

刚接触论文批量加载这个事的时候,我其实挺抗拒用现成工具的。总觉得无非就是拿着requests去 arXiv 抓页面,正则抽一抽 PDF 链接,再自己写个循环下载,一套下来也没多少代码。真做了几次文献综述和 RAG 语料构建之后,才发现问题根本不在"能不能下",而在下载之后那堆破事——文件命名乱成一锅粥、PDF 和元数据对不上号、今天下了明天又要重下、好不容易把全文拼出来又发现双栏排版顺序根本是错的。后来我把这套下载、缓存、解析、元数据管理的逻辑整理成了一个叫 ArxivLoader 的封装层,用到现在半年多,确实省掉了大量重复劳动。

这篇东西不打算写成普通的 API 文档,我是按自己实际项目里怎么用、踩过哪些坑、为什么那样设计的思路来聊。无论你是要做文献综述、追踪领域最新进展,还是要给 RAG 系统或大模型微调积累语料,应该都能从里面找到能直接抄作业的部分。

1. 为什么需要 ArxivLoader:手动下载文献的那堆烂账

先说一个很多人都会低估的问题:手动从 arXiv 下载文献,最耗时间的其实不是下载本身,而是下载完之后的整理。一次调研如果涉及 50 篇论文,你至少得处理这些事:每篇 PDF 的文件名是否包含标题或 ID、对应作者列表放哪了、摘要和全文字段怎么存、哪些论文因为网络抖动没下成功、下一周再跑的时候怎么只增量补新文章。一旦论文数量上百,这些问题会指数级膨胀。

1.1 手动下载的混乱,做过文献综述的都懂

我自己第一次大批量下论文,用的就是当时网上最常见的一套"野路子":requests 请求 arXiv 的搜索页面,正则抓 PDF 链接,再按论文 ID 命名保存。看着挺顺利,实际跑起来全是意外。arXiv 站点的 HTML 结构偶尔微调,正则就失效;某些论文的 PDF 链接藏在 abs 页面里,有的却指向补充材料;更麻烦的是,下载完就只有一堆孤零零的 PDF 文件,标题、作者、摘要这些信息全得靠文件名里那串 ID 关联回去。等真正写综述的时候,你还得把每篇 PDF 打开,手工把核心结论摘出来,再把 BibTeX 条目一条条粘进文献管理器。

如果你的调研是持续性的,比如想追踪某个方向每两周的新论文,那手动方案的体验会更差。你会发现工作流里充满了"重复劳动":同一批论文反复下载,旧版本和新版本搞混,自己改了名的文件再也没法和原始 ID 对应起来。整件事离"高效文档处理"差了十万八千里。

1.2 ArxivLoader 的定位:下载、缓存、结构化一条龙

做 ArxivLoader 的时候,我给它的定位很明确:不要只做一个下载器,而要做成论文数据管道的入口。它内部用arxiv这个 Python 库去和 arXiv API 打交道,但在外面包了四层能力:下载、缓存、解析、元数据管理。下载这层,支持按单篇 ID、搜索关键词和分类号三种方式批量拉取;缓存这层,让重复请求直接走本地文件,不浪费流量和时间;解析层负责把 PDF 变成干净的全文文本,并做区块化;元数据层则把所有标题、作者、摘要、主题分类、BibTeX 统一成结构化 JSON 落地。

这样设计的原因也很实际。一次论文下载,本质上是"获取 PDF + 获取元数据"两个动作的绑定,只做其中一个,后面总得返工。所以我倾向于从一开始就把每个下载动作的返回值定义成统一的记录对象,包含论文 ID、标题、作者、摘要、发布日期、PDF 本地路径、全文文本路径、分块结果路径这些字段。后续不管你是写综述、做向量检索还是喂给模型做微调,都只需要遍历这个目录结构,而不需要再碰原始下载逻辑。

2. 环境准备与初始化:装好依赖只是开始

ArxivLoader 本质上是一个 Python 封装层,底层最关键的两个依赖是arxiv(官方 API 客户端)和PyMuPDF(PDF 文本解析)。装好它们只需要一条命令,但真正影响使用体验的,是环境变量、缓存目录、超时参数这些看起来不起眼的配置。

2.1 依赖清单与安装命令

我建议你新建一个干净的虚拟环境来跑这些实验,避免污染日常开发环境。Python 版本建议 3.10 及以上,太旧的版本在处理 PDF 文本和异步请求时限制比较多。

python -m venv .arxiv-env source .arxiv-env/bin/activate pip install arxiv pymupdf requests tqdm

值得说明一下,arxiv库本身已经封装好搜索、下载 PDF、获取元数据的能力,为什么还要再包一层?因为官方库是"无状态"的,它不关心你今天下过什么、哪些文件已经存在、论文 A 和论文 B 的全文分块做没做。这些都是我们自己的工程问题。ArxivLoader 要做的,就是在官方库外面建立一套持久化状态,让每次运行都是"接着上次的进度",而不是重新来一遍。

2.2 初始化参数里容易被忽略的目录与超时配置

初始化 ArxivLoader 时,需要指定一个根目录,下面会生成pdfs/、metadata/、fulltext/、chunks/四个子目录。这么做的好处是强制约定目录结构,任何一个脚本都可以根据绝对的路径规则去读数据,而不用在代码里到处传路径参数。

loader = ArxivLoader( root_dir="./arxiv_library", cache_dir="./.arxiv_cache", timeout=60, retries=3, delay=5 )

timeout和retries这两个参数,新手常常会忽略默认值。但真实网络环境下,arXiv 的响应速度并不稳定,尤其是批量下载几十篇 PDF 的时候,单篇超时非常常见。如果不设置重试,一个连接闪断就可能中断整批任务。delay参数则控制在每次请求之间休眠多少秒,目的是把自己伪装成一个"正常读者",不要一口气把服务器请求频率拉满,既保护对方服务,也降低被限流的概率。

缓存目录同样值得细说。ArxivLoader 会把 arXiv API 的元数据 JSON 响应缓存到本地。比如同样一个搜索词,你今天就搜过、明天又搜,如果没有缓存,每次都重新请求 API,既慢又浪费配额。加了缓存后,只要缓存没有过期,ArxivLoader 直接读磁盘返回结果,速度能快一个数量级。过期时间默认设为 24 小时,即一天内的重复搜索不会触发真实 API 请求。

3. 核心用法:按论文ID、关键词、分类号加载与批量下载

ArxivLoader 设计了下加载入口:按单篇 ID 精确加载、按关键词搜索批量收集、按分类号做周期性扫描。每一个入口的返回结果都是同一套记录对象,所以后续处理逻辑完全通用。下面直接上能跑的代码。

3.1 单篇与列表:按 arXiv ID 精确加载

当你看某篇文章引用了另一篇、想快速把被引论文纳入自己的库时,单篇加载是最直接的方式。arXiv 的论文 ID 长得像2401.12345,有些老论文则带中缀,比如cs.CL/0112015这种格式。ArxivLoader 都能正确处理。

paper = loader.load_by_id("2401.12345") print(paper.title) print(paper.entry_id) # http://arxiv.org/abs/2401.12345 print(paper.pdf_path) # ./arxiv_library/pdfs/2401.12345.pdf

如果有多篇要一起加载,直接传列表。ArxivLoader 内部会对列表去重,已经存在本地缓存中的 ID 会被跳过。

papers = loader.load_by_ids([ "2401.12345", "2410.02644", "2306.03082" ], skip_existing=True)

这里有一个实用细节:skip_existing=True时,ArxivLoader 会检查pdfs/目录和元数据缓存中是否已有该论文记录。如果两者都在,就直接从本地返回,不做任何网络请求。配合缓存机制,这相当于天然给了你一个"增量更新"能力——论文库只会越来越多,但不会重复下载同一篇。

3.2 关键词搜索:按主题批量收集

做选题调研时,关键词搜索使用频率最高。它的工作流程分成三步:向 arXiv API 发起搜索请求,拉回最多max_results条结果;对结果做去重和基础过滤;然后开始批量下载 PDF。ArxivLoader 允许你直接传ic或query风格的搜参数,兼容官方 API。

papers = loader.search_and_download( query="large language model reasoning", max_results=50, sort_by="submittedDate", sort_order="descending" )

这段代码的意思是说:抓取最近提交的 50 篇关于大模型推理的论文,并下载 PDF。排序方式选submittedDate很有用,它能让每次搜索都优先看到最新 submission,适合做持续追踪。下载完成后,papers里每个元素都带pdf_path和metadata字段,你可以直接把元数据存成一份 JSON 清单,后续二次检索非常方便。

这里我建议你在真实项目里不要一次搜索就把范围铺得太大。比如large language model reasoning这个查询词可能一年内有几千篇论文,max_results=50只是一个起点。更合理的做法是先搜一个较宽泛的词,快速浏览标题和摘要,再筛出值得精读的子集,用load_by_id二次加载。搜索下载适合圈定候选,精读加载适合锁定目标,两个入口配合使用,效率是最高的。

3.3 分类批量扫描与增量更新

除了关键词,还有一种检索维度是论文分类号,比如cs.CL是计算语言学、cs.LG是机器学习、physics.data-an是数据统计物理。如果你在研究某个固定领域,按分类周期性地扫描新论文,是一个非常高效的追踪办法。

loader.scan_category( category="cs.CL", start_date="2025-01-01", end_date="2025-03-31", max_results=200 )

scan_category内部会按日期范围拉取该分类下提交的所有论文元数据,并与已有的arxiv_library做比对,自动跳过已经下载过的条目。这意味着你可以把这条命令挂到每周的定时任务里,每周跑一次,就能拿到"本周这个分类下面的新增论文",而且完全不会重复下载。

不过要注意,arXiv 的分类体系和会议投稿不完全一致。有些论文会挂在多个分类下,比如既标cs.CL又标cs.AI,如果你同时对两个分类做扫描,就会遇到重复条目。ArxivLoader 默认以论文 ID 为唯一键去重,所以不影响最终结果,但在统计论文数量时你需要意识到有重复标记的情况。

4. 文档处理的基本盘:从 PDF 到可检索文本

下载 PDF 只是第一步。对做文本分析、RAG、机器翻译、摘要生成的场景来说,PDF 本质上是一个"不可直接使用"的格式。你需要把每篇论文的正文抽出来,清洗干净,再按语义切分。这个阶段做得不好,后面所有工作都会受影响。

4.1 全文字符串提取与分块

ArxivLoader 的process_pdf方法封装了 PyMuPDF 的提取逻辑,并额外处理了页眉页脚、参考文献列表和版面分割。调用方式非常简单:

paper = loader.process_pdf(paper) print(paper.fulltext[:500])

底层它做的事情比较细:把 PDF 的每一页渲染成text dict对象,通过坐标区域判断哪些属于正文、哪些属于页眉页脚;再过滤掉常见的 "arXiv:2401.12345v1" 这类水印;最后把每一页的文本按顺序拼成完整的fulltext字符串,保存到fulltext/<paper_id>.txt中。

分块环节,我采用的是按段落加上滑动窗口的混合策略。具体逻辑是:先用空行把全文拆成自然段落,然后以 512 个字符为窗口、128 个字符为重叠,生成若干 chunk。这样做的好处是既保留段落结构,又不会让超出上下文长度的长文本损失语义完整性。每个 chunk 都会记录它来自哪篇论文、属于第几页、在全文中的偏移量。这些信息对后续构建 RAG 系统时的引用溯源非常关键。

4.2 双栏PDF的读取顺序问题

双栏问题是 PDF 文本提取里最经典的坑。如果直接用 PyMuPDF 的get_text("text")提取双栏论文,读出来的结果往往是一行来自左栏、下一行来自右栏,语义完全被打乱。比如摘要的左半部分读完了,紧接着是右半部分的第一行,然后又是左半部分的下一行。人眼看到的是两块栏并行,机器拿到的却是两条线绞在一起。

ArxivLoader 中解决办法不复杂,但非常有效:拿到 PDF 每页的文本块信息后,先根据块坐标的x0值判断该块属于左栏还是右栏。如果页面上存在两个明显分布的 x 坐标簇,就从左到右分别提取两个栏的文本块,再把两栏文本按"左栏整体在前、右栏整体在后"的顺序拼接。如果页面上只有一个 x 坐标簇,就按正常的段落顺序读取。

text_dict = page.get_text("dict") left_blocks = [b for b in text_dict["blocks"] if b["bbox"][0] < mid_x] right_blocks = [b for b in text_dict["blocks"] if b["bbox"][0] >= mid_x] page_text = "".join([b["text"] for b in sorted(left_blocks, key=by_y)]) page_text += "".join([b["text"] for b in sorted(right_blocks, key=by_y)])

这段逻辑看起来简单,但解决的是"全文抽取后被下游语义模型误解"的根本问题。如果你是自己手写 PDF 解析脚本,我强烈建议把双栏检测这一步加上。

4.3 元数据清洗与统一命名规范

ArxivLoader 在处理完 PDF 文本后,还会顺带把元数据清洗成统一格式。原始 arXiv API 返回的authors是一个Person对象列表,直接序列化会变成一串冗长的嵌套结构。ArxivLoader 会把它转成["FirstName LastName", ...]这种纯字符串列表。摘要和标题则做两件事:去掉多余换行符和奇怪的 Unicode 字符,保留数学公式部分的原始文本(比如$...$包裹的 LaTeX 内容)。

命名规范也很重要。每一篇论文的 PDF 文件名统一为<arxiv_id>.pdf,元数据统一为<arxiv_id>.json,全文文本统一为<arxiv_id>.txt。这样做的好处是当你同时打开pdfs/和metadata/目录时,一眼就能对上号。我之前用过"标题+作者"的命名方案,看起来直观,但实际使用中全是坑:标题里的斜杠、冒号等特殊字符会让文件路径失效,作者名重复率高,同名不同文的概率也不小。最后我全部换回了 ID 命名,一劳永逸。

5. 接上大模型/RAG:让论文库变成可用问答的知识库

有了干净的全文和 chunk 后,最自然的下一步就是把这批论文接进 RAG 工作流,做论文问答、综述辅助或研究趋势分析。这部分的重点不是"调用大模型 API",而是如何组织索引和检索,让回答有据可依。

5.1 分块策略与 embedding 选型

前面提到 ArxivLoader 生成 chunk 时用的是"段落 + 滑动窗口"策略。为什么不用固定长度?学术论文的段落差异极大,方法描述可能一整页才是一个完整逻辑,实验部分又往往是碎片化的。固定 512 字符切下去,很可能会把两句本来紧密耦合的句子生硬切断。而基于段落切,至少能保证 chunk 内部语义在"段落级"是连贯的。

Embedding 模型的选择上,我的经验是先在"召回质量"上做平衡。通用领域可以用text-embedding-3-small或bge-large-zh-v1.5,而在论文这种长文本场景里,我更建议用BAAI/bge-m3,它对多语言和学术文本的鲁棒性都比我试过的几个通用模型好。向量维度也不用太高,很多场景下 768 维都能满足需求,关键在于检索阶段是否做了 embedding 与 query 的语义匹配,而不是盲目堆维度。

5.2 检索增强问答的流程编排

构建 RAG 问答时,接口设计思路是这样的:用户提出问题后,先对 query 做 embedding,然后从向量库中检索 top-k 个 chunk(k 一般取 8 到 12),再把这 12 个 chunk 连同提问一起拼进 prompt,发送给大模型生成答案。因为它严格限定了检索范围,回答时就能给出明确的引用来源。

results = index.search("什么是思维链提示") for r in results: print(r.paper_id, r.page_number, r.text[:100]) answer = llm.generate_answer( question="什么是思维链提示", context=[r.text for r in results] )

这里有一个我认为非常重要的流程设计:回答和引用必须同时输出。也就是说,大模型不能只输出答案字符串,还要输出它引用了哪些 chunk 的编号,否则你很难排查它哪句是根据文献说的、哪句是模型自己脑补的。ArxivLoader 在前面的分块阶段给每个 chunk 打了论文 ID、页码、偏移量标签,这一步正好派上用场。用户点开回答里的引用标记,就能直接跳到对应 PDF 的对应页面去验证。这个体验,比那种"看起来有道理但找不到出处"的问答强太多。

5.3 从引用到 BibTeX 导出

文献管理还有一个经常被忽略的痛点:综述论文或者项目报告里需要引用这些文献时,BibTeX 条目从哪来?ArxivLoader 在下载元数据时就把生成 BibTeX 所需的所有字段存好了,包括title、author、journal(arXiv 预印本标注为arXiv)、year、eprint、archivePrefix等。你只需要一个导出函数,把所有已下载论文的 BibTeX 拼成一个.bib文件。

loader.export_bibtex("./papers.bib")

这个文件可以直接丢进 Overleaf 或 Zotero 里,省掉了手动维护引用库的环节。我自己的论文笔记仓库里,每次运行完批量加载后,都会自动重新导出一次.bib,确保论文库和引用文件始终同步。从长期看,这是一个投入产出比非常高的自动化步骤。

6. 踩坑记录:我用了半年 ArxivLoader 后总结的实践经验

工具做得再顺手,真上量之后总会暴露一堆边界问题。这段我把自己踩过的坑、处理方式和排查链路都写下来,希望帮你少走弯路。

6.1 论文版本更新,旧缓存没失效

这是最容易踩的坑。ArxivLoader 的缓存机制是按论文 ID 判断"这篇我下过了",但 arXiv 上的论文会不定期更新版本:作者修了 bug、补了实验,或者改了结论。如果 PDF 文件和元数据缓存都以"论文 ID 已存在"为理由跳过,你就会永远错过新版内容。

后来我在缓存里额外加了version字段,每次元数据请求时都对比 arXiv API 返回的version列表长度和本地记录的长度。一旦发现版本数增加,就重新下载 PDF、重新生成全文和 chunk,并保留旧版本在archive/目录里,不直接覆盖。这样既不会重复下载没更新过的论文,也不会漏掉有实质修改的新版内容。

6.2 网络超时被当成下载失败反复重试

另一个常见的坑是网络抖动。我在开发前期遇到过一种情况:某个论文 PDF 其实已经下载成功了,但因为 TCP 连接在下载完成的前一刻断开,导致本地只留了一个 0 字节的空文件。ArxivLoader 检查文件存在时发现它"存在",所以不会重新下载,但全文解析时却拿不到内容,非常隐蔽。

排查链路是这样的:先看pdfs/目录里的文件大小分布,发现大量不符合预期的 0 字节文件;然后定位到下载函数里没有做"下载结果完整性校验",只用"文件是否存在"判断成败;最后修复方案是,下载完成后必须校验文件大小,低于 500KB 的 PDF 会被视为异常,强制删除并重新下载。别看 500KB 这个阈值拍脑袋定的,但对绝大多数论文 PDF 来说,这个大小很合理。你也可以根据自己要下载的论文类型调高或调低。

6.3 ARXIV API 搜索结果的 limit 与游标

arxiv官方库的搜索结果默认限制一次返回 10 条,即使你传了max_results=100,底层也有可能只取到部分数据。要拿到完整结果,必须处理分页游标。这个坑很隐蔽,因为小规模测试时没差别,等你要抓取某个分类下 2000 篇论文时才会发现数量不对。

我的做法是:写一个专门的分页封装,循环请求直到收到的条数达到目标值。每页拉取page_size条,记录当前游标,下一页从游标继续。同时设置一个最大页数上限,防止某个异常查询词导致无限循环。补上这段逻辑后,我再也没有遇到过"论文数量不明不白少了"的问题。

6.4 双栏论文的图片说明与表格顺序

文本抽取时,双栏顺序解决得很顺利,但有一个漏网之鱼:人物图片下方的说明文字和跨栏表格。说明文字经常位于图片内部,PyMuPDF 的dict模式下会返回一个单独的 text block,位置坐标不在左栏也不在右栏,而会出现在页面的中间区域。如果不特殊处理,这段说明文字会被漏掉或者顺序错乱。

后来我在双栏拼接逻辑里增加了一个中间栏检测:如果文本块的 x 轴坐标覆盖了整个页面宽度的 60% 以上,就把它视为"跨栏块"或"图注块",先提取出来,再嵌入到对应位置。提取跨栏文本之后,再按照"左栏正文 -> 中间栏图注 -> 右栏正文"的顺序拼接。这个微调对论文的自然语言理解影响很大,毕竟有些关键的方法说明恰恰藏在图注里。

6.5 大规模下载前的“预检”有多重要

最后分享一个流程上的建议:在执行几百篇批量下载之前,先拿 3-5 篇做全链路预检。检查项包括:PDF 能否正常打开、全文提取是否有异常、chunk 数量是否合理、BibTeX 格式是否合法。我最初为了省时间跳过预检,结果一次抓了 400 篇,最后人工检查时发现将近 30 篇 PDF 因为加密或扫描版无法解析文本,白花了很多下载流量和时间。

现在我的标准流程是:先load_by_ids下载 3 篇预检,确认无误后,再跑真正的批量化任务。批跑完成后,用一段校验脚本遍历fulltext/下的所有 txt 文件,把文件大小为 0 或文本行数少于 50 行的条目挑出来重新处理。这个步骤看起来简单,但能帮你提前发现绝大多数异常场景。

结尾:一个小技巧

ArxivLoader 这套东西本质上没有高深的技术,核心就是下载、缓存、解析、索引四个环节的工程化。我在实际使用中还有一个很小但很顺手的技巧:把所有加载记录写进一个index.sqlite数据库文件,而不是只依赖 JSON 文件目录。这样当你需要回答"过去三个月我下载了哪些论文属于 cs.CL 分类"或者"哪些论文的摘要里同时提到了 reinforcement learning 和 reasoning"这类交叉查询时,直接用 SQL 就能过滤,比遍历目录高效得多。

如果你也想把这套流程用起来,建议先别急着把功能铺满,就从最核心的"按关键词搜索 + 下载 PDF + 提取全文"这三步开始,跑通一次之后再加缓存、加增量、接 RAG。等论文库积累到一定规模,你会发现自己做综述、做调研、做问答,都轻松了很多。

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

superpowers:为AI编码助手打造按需加载的技能库

1. 先搞清楚 superpowers 是什么1.1 AI 编程助手为什么需要“技能”你有没有遇到过这种情况&#xff1a;同一个 AI 编码助手&#xff0c;在干净的“hello world”项目里表现得像个天才&#xff0c;一旦扔进一个带历史包袱的企业级 Java 工程&#xff0c;就开始一本正经地胡说八…

作者头像 李华
网站建设 2026/10/3 6:01:49

RAG检索效果差?从Markdown到JSON,格式选型让准确率大幅提升

1. 从一次检索翻车说起&#xff1a;Markdown在RAG里的隐性坑先讲个我实际项目里遇到的事。今年上半年给一家企业做内部知识库问答系统&#xff0c;技术栈是当时主流的FastAPI LangChain RAG pgvector那一套。语料是几十份产品文档&#xff0c;原始格式是Markdown&#xff0c…

作者头像 李华
网站建设 2026/10/3 6:00:52

Paperclip 实战:Node.js 与 React 驱动 AI Agent 的会话锁与通信优化

1. 从“paperclip”这个名字说起&#xff1a;它到底想解决什么问题第一次看到“paperclip”这个项目名&#xff0c;我脑子里蹦出来的画面是那个经典的办公小物件——回形针。它不起眼&#xff0c;但几乎每个人的桌上都有一两个&#xff0c;用来把散落的纸张别在一起。放到技术语…

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

C++配合libxlsxwriter向Excel批量插入图片的实践与踩坑

做报表自动化久了&#xff0c;你会发现一个很尴尬的中间地带&#xff1a;数据、公式、格式都好说&#xff0c;文本一填、样式一刷就完事&#xff1b;一旦需求里出现“把现场照片塞进Excel对应行”&#xff0c;常规套路基本全哑火。我最近在手写一个设备点检报告生成工具&#x…

作者头像 李华
网站建设 2026/10/3 6:00:17

基于Dify和RAG构建智能复盘助手,自动化项目复盘实践

项目概述与核心思路1.1 “hindsight”到底是个什么东西先说结论&#xff1a;hindsight 不是一个模型、不是一套算法&#xff0c;而是一个基于 Dify 平台搭建的“智能复盘助手”原型项目。它的名字取自英文“事后聪明”——我们常说“回头看&#xff0c;一切都清晰”&#xff0c…

作者头像 李华
网站建设 2026/10/3 6:00:17

从零开始AI工程化:数据、训练、部署、监控全链路实战

2022年我给自己定了一个目标&#xff1a;搞一个叫ai-engineering-from-scratch的长期项目&#xff0c;从零开始把 AI 应用真正做出来&#xff0c;而不是一直停留在"看论文、刷榜单、跑通别人代码"的阶段。两年前我还是一个只会调库的脚本小子&#xff0c;看着 Huggin…

作者头像 李华