从零搭建AI工程能力:可复现、可扩展、可观测的落地路径

📅 发布时间:2026/9/30 15:24:57
从零搭建AI工程能力:可复现、可扩展、可观测的落地路径
从零搭建AI工程能力这件事我前前后后折腾过好几轮。最早的时候我也觉得搞AI嘛会调个模型API、能跑通一个demo不就行了结果真到了要把一个模型塞进业务系统里跑起来的时候才发现坑多到离谱——显存不够、推理慢得像蜗牛、换个环境就报错、上线之后监控一片空白。后来我才慢慢意识到AI工程和AI算法完全是两码事算法关心的是模型效果好不好工程关心的是这套东西能不能稳定、高效、低成本地跑在生产环境里。这篇内容就是把我从零搭建AI工程能力这条路上踩过的坑、总结的方法、以及一套可复现的落地路径完整梳理出来适合那些已经会写Python、懂一点深度学习基础但还没真正把AI系统跑进生产环境的同学。不管你是想转行做AI工程还是已经在做但总觉得缺了点什么下面的内容应该都能给你一些参考。1. 先搞清楚AI工程到底在解决什么问题1.1 算法和工程的分界线在哪里很多人一开始会把AI工程理解成把算法工程师写好的模型部署一下这个理解不能说错但太窄了。我自己的体会是算法解决的是这个模型能不能预测准工程解决的是这个预测能力能不能被稳定地、规模化地交付出去。这两件事的思维方式完全不同。举个具体的例子。算法同学在notebook里跑通一个模型用的是固定的数据集、固定的随机种子、固定的环境跑出来准确率95%皆大欢喜。但工程同学要面对的是数据是实时流进来的格式可能随时变模型要在一台没有GPU的机器上跑请求量可能从每秒10个突然涨到每秒1000个服务挂了要能自动恢复模型更新了要能灰度发布。这些在notebook里根本不会遇到。所以AI工程的核心命题其实是三个词可复现、可扩展、可观测。可复现意味着任何人任何时候都能把同样的结果跑出来可扩展意味着流量涨了、数据多了系统还能扛住可观测意味着出了问题你能快速定位是数据的问题、模型的问题还是服务的问题。这三个词听起来简单但每一个背后都是一堆具体的工程决策。1.2 从零开始需要建立的能力地图我梳理了一下一个完整的AI工程能力体系大概包含这么几块你可以对照看看自己缺哪块能力模块核心内容常见工具/技术数据处理数据清洗、特征工程、数据版本管理Pandas, Spark, DVC模型训练分布式训练、超参调优、实验管理PyTorch, MLflow, Optuna模型部署模型转换、推理优化、服务化ONNX, TensorRT, FastAPI服务运维容器化、编排、自动扩缩容Docker, Kubernetes监控告警性能监控、数据漂移检测、日志Prometheus, Grafana, Evidently流水线CI/CD、自动化训练、自动化部署GitHub Actions, Airflow这张表不是让你每个都精通而是让你知道整个链路长什么样。我见过太多人只盯着模型部署这一块结果数据版本对不上、训练环境复现不了、上线后模型效果衰减了也不知道最后整个系统就是个黑盒。1.3 为什么建议从最小可运行闭环开始新手最容易犯的错是一上来就想搭一个完美的AI平台。我当年也是这样花了两周时间研究各种框架结果一行能跑的代码都没写出来。后来我换了个思路先用最简单的技术栈搭一个从数据到模型到服务的最小闭环哪怕它很丑、很慢、很不优雅但它是能跑通的。这个最小闭环大概长这样一个Python脚本读数据、一个简单的模型训练、把模型存成文件、用一个web框架包成API、写个脚本调用测试。就这么点东西可能半天就能搞定。但当你把这个闭环跑通之后你就知道每个环节的输入输出是什么、哪里容易出问题、哪里需要优化。这时候再去引入Docker、Kubernetes、MLflow这些工具你才知道它们到底解决了什么问题而不是为了用而用。我的经验是工具永远是为问题服务的。先有痛点再找工具顺序反了就会陷入学了一堆工具但不知道怎么用的困境。2. 环境与依赖管理别让在我机器上能跑成为噩梦2.1 Python环境隔离的几种方案对比在我机器上能跑这句话大概是工程领域最经典的梗了。AI项目尤其严重因为依赖特别多、版本特别敏感。PyTorch 1.x和2.x的API不兼容CUDA版本和驱动版本要对上numpy版本高了低了都可能出问题。我踩过最离谱的坑是一个项目在本地跑得好好的部署到服务器上因为numpy版本差了一个小版本矩阵运算结果出现了微小的数值差异导致模型输出完全不对。环境隔离的方案主要有这么几种我做个对比方案隔离级别适用场景缺点venvPython包级别本地开发、简单项目不隔离系统库和CUDAconda包系统库级别科学计算、需要特定CUDA体积大、解析慢Docker完整系统级别生产部署、团队协作学习成本、镜像体积虚拟环境容器组合方案复杂项目配置繁琐我现在的习惯是本地开发用conda管理Python环境因为科学计算相关的包它处理得最好生产部署一律用Docker因为只有容器能保证开发环境等于生产环境。中间用一个environment.yml或者requirements.txt把依赖锁死所有版本号都写精确不用这种模糊约束。2.2 依赖锁定为什么requirements.txt不够用很多人以为pip freeze requirements.txt就万事大吉了其实这里面有个大坑pip freeze只会导出你显式安装的包和它们的直接依赖但不会锁定依赖的依赖。也就是说A包依赖B包你锁了A的版本但B的版本没锁下次安装的时候B可能升级了然后就和A不兼容了。更靠谱的做法是用pip-tools或者poetry这类工具做完整的依赖解析和锁定。以pip-tools为例# 在requirements.in里写直接依赖不写版本 # 然后生成锁定的requirements.txt pip-compile requirements.in --output-file requirements.txt # 安装时严格按锁定文件来 pip-sync requirements.txt这样生成的requirements.txt会包含所有传递依赖的精确版本任何人任何时候安装都是一样的结果。对于AI项目我还会额外记录CUDA版本、cuDNN版本、显卡驱动版本因为这些不在Python包管理范围内但同样会影响结果。2.3 容器化把整个运行环境打包带走Docker解决的是环境一致性这个根本问题。但AI项目的Docker镜像有个特殊难点GPU支持。普通的Docker镜像跑不了GPU需要用nvidia-container-toolkit基础镜像也要选对。我常用的一个PyTorch训练镜像的Dockerfile大概长这样FROM nvidia/cuda:12.1.0-cudnn8-runtime-ubuntu22.04 # 装Python和基础工具 RUN apt-get update apt-get install -y \ python3.10 python3-pip git curl \ rm -rf /var/lib/apt/lists/* # 设置工作目录 WORKDIR /app # 先复制依赖文件利用Docker层缓存 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 再复制代码 COPY . . CMD [python, train.py]这里有个关键技巧先复制依赖文件再复制代码。因为Docker是分层构建的只要requirements.txt没变依赖安装这一层就会用缓存构建速度能快好几倍。我见过有人把整个项目一次性COPY进去结果改一行代码就要重新装一遍依赖等得想砸电脑。注意生产环境的镜像尽量用runtime版本而不是devel版本体积能小很多。devel版本包含了编译工具链只有你需要从源码编译CUDA扩展的时候才用得上。3. 数据处理流水线模型效果的上限由数据决定3.1 数据版本管理为什么比代码版本管理更重要代码可以回滚数据回滚起来就麻烦多了。我遇到过好几次这样的情况模型效果突然下降排查了半天代码没改最后发现是上游数据源偷偷改了字段格式或者某天的数据采集出了问题。没有数据版本管理你连上次效果好的时候用的是哪份数据都说不清楚。数据版本管理我推荐两个思路。轻量级的用DVC它把大文件存在对象存储里Git里只存元数据指针用起来和Git很像# 初始化DVC dvc init # 添加数据文件 dvc add data/train.csv # 提交元数据 git add data/train.csv.dvc data/.gitignore git commit -m add training data v1 # 切换数据版本 git checkout commit dvc checkout重量级的就用数据湖方案比如Delta Lake或者Apache Iceberg它们支持时间旅行、schema演进、ACID事务适合数据量大、多人协作的场景。选哪个取决于你的数据规模和团队情况小团队用DVC足够了。3.2 特征工程的工程化从notebook到生产notebook里做特征工程和在生产环境做特征工程最大的区别是一致性。notebook里你可以随手写个df[new_feature] df[a] / df[b]但生产环境里训练时的特征计算逻辑和推理时的特征计算逻辑必须完全一致否则就会出现训练-服务偏差training-serving skew。解决这个问题的标准做法是特征存储Feature Store。它的核心思想是特征的计算逻辑只写一次训练时用批处理方式算历史特征推理时用流式方式算实时特征但用的是同一套代码。Feast是一个比较流行的开源方案from feast import FeatureStore store FeatureStore(repo_path./feature_repo) # 训练时获取历史特征 training_df store.get_historical_features( entity_dfentity_df, features[driver_stats:conv_rate, driver_stats:acc_rate] ).to_df() # 推理时获取在线特征 online_features store.get_online_features( features[driver_stats:conv_rate], entity_rows[{driver_id: 1001}] ).to_dict()如果团队规模不大不一定非要上Feature Store但至少要保证特征计算逻辑封装成独立的函数或类训练和推理都调用同一份代码。我见过最糟糕的情况是训练用SQL算特征、推理用Python重写一遍两边逻辑稍微有点差异模型效果就崩了。3.3 数据质量校验在脏数据进入模型之前拦住它数据质量问题是AI系统最隐蔽的杀手。模型不会报错它只会默默地给出错误的预测。所以必须在数据进入训练或推理之前做校验。校验的内容包括字段是否存在、类型是否正确、取值范围是否合理、分布是否发生漂移。我用得比较多的是Great Expectations和Pandera。Pandera更轻量适合在代码里直接做schema校验import pandera as pa from pandera import Column, DataFrameSchema, Check schema DataFrameSchema({ age: Column(int, Check.in_range(0, 120)), income: Column(float, Check.greater_than(0)), category: Column(str, Check.isin([A, B, C])), }) # 校验数据不符合就抛异常 validated_df schema.validate(raw_df)对于数据漂移检测可以用Evidently这类工具它会对比训练数据和推理数据的分布当漂移超过阈值时告警。这个在生产环境特别重要因为模型效果衰减往往不是模型本身的问题而是输入数据的分布变了。4. 模型训练与实验管理让每一次实验都可追溯4.1 实验追踪别再靠文件名区分模型版本了我早期管理实验的方式极其原始model_v1.pth、model_v2_final.pth、model_v2_final_真的最终版.pth。结果过了一个月我自己都不知道哪个是哪个超参数是什么、用的哪份数据、效果多少全忘了。这种混乱在小规模实验时还能忍一旦实验数量上去了就是灾难。MLflow是我用得最顺手的实验追踪工具它的核心概念很简单每次训练是一个runrun里记录参数、指标、产物。用起来就几行代码import mlflow mlflow.set_experiment(my_experiment) with mlflow.start_run(): # 记录超参数 mlflow.log_params({lr: 0.001, batch_size: 32, epochs: 10}) # 训练循环 for epoch in range(10): train_loss train_one_epoch() val_loss validate() # 记录指标 mlflow.log_metrics({train_loss: train_loss, val_loss: val_loss}, stepepoch) # 记录模型产物 mlflow.pytorch.log_model(model, model)跑完之后打开MLflow的UI所有实验一目了然可以按指标排序、对比不同run的参数、直接下载模型。这个投入产出比极高强烈建议从第一个实验就开始用。4.2 超参数调优网格搜索之外的选择超参数调优如果还用网格搜索那真的是在浪费算力。网格搜索的复杂度是指数级的5个参数各5个候选值就是3125次训练根本跑不起。实际工作中我用得最多的是贝叶斯优化和Hyperband。Optuna是我最推荐的框架它支持多种采样算法而且有个剪枝机制特别实用——如果某个试验在前几个epoch表现明显差于历史最优直接提前终止省下算力import optuna def objective(trial): lr trial.suggest_float(lr, 1e-5, 1e-2, logTrue) batch_size trial.suggest_categorical(batch_size, [16, 32, 64]) dropout trial.suggest_float(dropout, 0.1, 0.5) model build_model(dropout) optimizer torch.optim.Adam(model.parameters(), lrlr) for epoch in range(20): val_loss train_and_validate(model, optimizer, batch_size) # 报告中间结果支持剪枝 trial.report(val_loss, epoch) if trial.should_prune(): raise optuna.TrialPruned() return val_loss study optuna.create_study( directionminimize, pruneroptuna.pruners.MedianPruner() ) study.optimize(objective, n_trials100)实测下来同样的算力预算Optuna找到的最优解通常比网格搜索好一截而且时间省一半以上。4.3 训练的可复现性随机种子只是第一步要让训练结果可复现设置随机种子只是最基础的一步。完整的可复现需要控制这些变量Python的random.seed()NumPy的np.random.seed()PyTorch的torch.manual_seed()和torch.cuda.manual_seed_all()cuDNN的确定性设置torch.backends.cudnn.deterministic True数据加载的shuffle顺序多卡训练的梯度同步顺序但即使这些都设了GPU上的浮点运算仍然可能有微小的非确定性因为CUDA的某些操作比如atomicAdd的执行顺序是不确定的。所以严格意义上的完全可复现在GPU上很难做到工程上追求的是统计意义上的可复现——同样的配置跑多次指标波动在可接受范围内。我的做法是把随机种子、环境版本、数据版本、代码commit hash全部记录到MLflow的run里。这样即使不能100%复现至少能追溯到当时的所有条件。5. 模型部署与推理优化从实验室到生产的关键一跃5.1 模型格式转换为什么不能直接用PyTorch模型部署PyTorch训练出来的.pth文件包含了完整的模型结构和权重但它依赖PyTorch运行时部署起来又重又慢。生产环境通常会把模型转换成更轻量的格式常见的有ONNX和TensorRT。ONNX是一个开放的模型交换格式几乎所有主流框架都支持导出。它的好处是跨平台、跨框架而且有很多推理引擎支持ONNX Runtime、TensorRT、OpenVINO等import torch import torch.onnx # 加载训练好的模型 model MyModel() model.load_state_dict(torch.load(model.pth)) model.eval() # 构造一个示例输入 dummy_input torch.randn(1, 3, 224, 224) # 导出为ONNX torch.onnx.export( model, dummy_input, model.onnx, input_names[input], output_names[output], dynamic_axes{input: {0: batch_size}, output: {0: batch_size}}, opset_version13 )这里有个关键点dynamic_axes参数。如果不设置导出的ONNX模型会固定batch size推理时只能接受那个尺寸的输入。设置成动态之后batch size可以变化灵活性高很多。TensorRT是NVIDIA的推理优化引擎它会对模型做层融合、精度校准、kernel自动调优在NVIDIA GPU上能比原生PyTorch快好几倍。但它的缺点是只支持NVIDIA GPU而且转换过程比较耗时。我的建议是如果部署在GPU上且追求极致性能用TensorRT如果需要跨平台或者部署在CPU上用ONNX Runtime。5.2 推理服务的几种架构模式推理服务的架构选择取决于你的场景。我总结了几种常见模式模式一同步请求-响应。客户端发请求服务端推理完返回结果。适合实时性要求高、请求量不大的场景。用FastAPI就能快速搭起来from fastapi import FastAPI import onnxruntime as ort import numpy as np app FastAPI() session ort.InferenceSession(model.onnx) app.post(/predict) async def predict(data: dict): input_array np.array(data[features], dtypenp.float32) outputs session.run(None, {input: input_array}) return {prediction: outputs[0].tolist()}模式二批处理。请求先攒着攒够一批或者等一小段时间再一起推理。因为GPU的并行能力很强batch size从1加到32推理时间可能只增加一点点但吞吐量提升几十倍。这个模式适合对延迟不那么敏感的场景。模式三异步队列。请求进来先丢到消息队列后台worker慢慢消费。适合推理时间很长比如大模型生成的场景客户端拿到一个任务ID过一会儿再来查结果。模式四流式推理。边生成边返回适合文本生成这类场景。这个模式对服务端的要求最高需要支持Server-Sent Events或者WebSocket。选哪种模式核心看两个指标延迟要求和吞吐量要求。延迟要求高就同步吞吐量要求高就批处理两者都高就得上更复杂的架构。5.3 推理性能优化的几个实用手段推理优化是个深坑我挑几个投入产出比最高的手段说说。量化是最直接的手段。把FP32的权重转成INT8模型体积缩小4倍推理速度提升2-4倍精度损失通常在1%以内。PyTorch支持动态量化和静态量化# 动态量化最简单一行代码 quantized_model torch.quantization.quantize_dynamic( model, {torch.nn.Linear}, dtypetorch.qint8 ) # 静态量化需要校准数据精度更好 model.qconfig torch.quantization.get_default_qconfig(fbgemm) torch.quantization.prepare(model, inplaceTrue) # 用校准数据跑一遍 for data in calibration_loader: model(data) torch.quantization.convert(model, inplaceTrue)算子融合是另一个大杀器。把ConvBNReLU这种连续操作融合成一个算子减少内存访问和kernel启动开销。TensorRT和ONNX Runtime都会自动做这个优化你不需要手动改代码。KV Cache是针对Transformer类模型的优化。自回归生成的时候每次生成一个新token都要重新计算前面所有token的注意力非常浪费。KV Cache把之前算过的Key和Value缓存起来每次只算新token的速度能提升好几倍。这个在HuggingFace的generate方法里默认就开了。批处理调度是服务层面的优化。与其每个请求单独推理不如攒一批一起推。但攒批会增加延迟所以要设一个最大等待时间比如10毫秒超过就立即推理。这个平衡点需要根据实际流量调。6. 监控与运维上线只是开始不是结束6.1 模型监控和普通服务监控的区别普通服务的监控看的是CPU、内存、QPS、延迟、错误率这些指标。AI服务除了这些还要额外监控模型层面的指标预测分布、特征分布、置信度分布。因为模型可能服务本身很健康延迟低、不报错但预测结果已经悄悄变差了。我遇到过最典型的情况一个推荐模型上线三个月后效果明显下降但服务监控一切正常。排查后发现是用户行为模式变了模型训练时用的数据分布和现在的线上数据分布差异很大模型过时了。这种问题只有监控模型层面的指标才能发现。6.2 数据漂移检测的落地方法数据漂移检测的核心是把线上推理时的输入数据分布和训练时的数据分布做对比。如果差异超过阈值就告警。常用的统计指标有PSIPopulation Stability Index衡量两个分布的差异PSI 0.1说明分布稳定0.1-0.25说明有轻微漂移 0.25说明显著漂移。KL散度衡量两个概率分布的差异。KS检验判断两个样本是否来自同一分布。用Evidently可以很方便地做这件事from evidently.report import Report from evidently.metric_preset import DataDriftPreset report Report(metrics[DataDriftPreset()]) report.run(reference_datatrain_df, current_dataprod_df) report.save_html(drift_report.html) # 也可以拿到结构化的结果 result report.as_dict() drift_detected result[metrics][0][result][dataset_drift]我一般会把这个检测做成定时任务每天跑一次结果推到监控面板上。一旦检测到显著漂移就触发模型重训练的流程。6.3 模型回滚与灰度发布模型更新比代码更新风险更高因为模型的行为很难用单元测试覆盖。所以模型上线一定要支持灰度发布和快速回滚。灰度发布的常见做法是按流量比例切分新模型先接1%的流量观察一段时间没问题再逐步加到10%、50%、100%。实现方式可以是在服务层做一个路由根据请求ID的哈希值决定走哪个模型import hashlib def route_model(request_id: str, new_model_ratio: float 0.01): # 根据请求ID的哈希值决定路由 hash_val int(hashlib.md5(request_id.encode()).hexdigest(), 16) if (hash_val % 100) (new_model_ratio * 100): return new_model return old_model回滚就更简单了模型文件都存着把路由切回旧模型就行。关键是要保证旧模型的服务实例还在别一上线就把旧的删了。我一般会保留最近3个版本的模型随时可以切回去。一个血的教训模型上线前一定要做shadow mode也就是新模型接收真实流量但不返回结果只记录预测。对比新老模型的预测差异确认没有异常再正式切流量。这个步骤能拦住大部分低级错误。7. 把整条链路串起来CI/CD与自动化7.1 AI项目的CI/CD和普通项目有什么不同普通项目的CI/CD是代码提交 → 跑测试 → 构建镜像 → 部署。AI项目多了几个环节数据校验 → 模型训练 → 模型评估 → 模型注册 → 部署。而且模型训练本身可能耗时很长不能每次提交都跑全量训练。我的做法是分两条流水线。代码流水线跑得快每次提交都触发只做代码lint、单元测试、镜像构建。模型流水线跑得慢按需触发或者定时触发做数据校验、训练、评估、注册。7.2 用GitHub Actions搭一条模型训练流水线下面是一个简化的模型训练流水线示例用GitHub Actions实现name: Model Training Pipeline on: schedule: - cron: 0 2 * * 0 # 每周日凌晨2点跑一次 workflow_dispatch: # 也支持手动触发 jobs: train: runs-on: [self-hosted, gpu] # 需要GPU的runner steps: - uses: actions/checkoutv3 - name: Setup Python uses: actions/setup-pythonv4 with: python-version: 3.10 - name: Install dependencies run: pip install -r requirements.txt - name: Validate data run: python scripts/validate_data.py - name: Train model run: python scripts/train.py --config configs/prod.yaml - name: Evaluate model run: python scripts/evaluate.py --threshold 0.85 - name: Register model if: success() run: python scripts/register_model.py这里有几个关键点用self-hosted runner是因为训练需要GPUGitHub托管的runner没有GPU评估步骤设了阈值效果不达标就中断流水线不会把差模型推上去模型注册步骤只在前面都成功时才执行。7.3 模型注册与版本管理模型注册表是连接训练和部署的桥梁。每次训练产出的模型都注册进去带上版本号、指标、训练数据版本、代码commit等信息。MLflow Model Registry就是干这个的import mlflow # 注册模型 mlflow.register_model( model_urifruns:/{run_id}/model, namemy_model ) # 把某个版本标记为生产可用 client mlflow.tracking.MlflowClient() client.transition_model_version_stage( namemy_model, version3, stageProduction )部署服务从注册表拉取标记为Production的模型版本这样训练和部署就解耦了。训练团队只管往注册表推模型部署团队只管从注册表拉模型中间通过stage这个状态来协调。8. 一些踩坑之后的真心话8.1 不要过早优化但也不要欠太多技术债我见过两种极端。一种是过度设计一个日请求量几百的小服务非要上Kubernetes加服务网格运维复杂度高得离谱出问题了没人会修。另一种是完全不设计所有东西写在一个脚本里模型文件用文件名区分版本数据直接读本地CSV等到要扩展的时候推倒重来。我的建议是架构的复杂度应该匹配当前的业务规模但要为未来留好扩展点。比如你一开始可以用单机部署但代码里要把模型加载、推理、后处理这些逻辑分层写好将来要拆成微服务的时候直接拆就行。数据存储一开始可以用本地文件但读写接口要封装好将来换成对象存储只改一个配置。8.2 日志和可观测性要从第一天就做这个是我踩过最大的坑。早期项目为了赶进度日志随便打监控也没做。结果上线后模型效果不对排查了整整两天因为根本不知道是数据的问题还是模型的问题还是代码的问题。后来我强制要求任何AI服务上线前必须有三样东西——结构化的日志、关键指标的监控面板、模型输入输出的采样记录。结构化日志意味着不要用print用logging并且输出JSON格式方便后续检索和分析。关键指标包括推理延迟的P50/P95/P99、每秒请求数、错误率、模型置信度分布。输入输出采样记录是为了出问题的时候能复现但要注意脱敏和存储成本。8.3 团队协作接口约定比技术选型更重要AI工程项目通常涉及多个角色数据工程师、算法工程师、后端工程师、运维工程师。我见过太多团队在技术选型上吵得不可开交却忽略了更重要的接口约定。所谓接口约定就是明确每个环节的输入输出格式。数据团队产出的数据长什么样、字段类型是什么、缺失值怎么表示算法团队产出的模型接受什么格式的输入、输出什么格式的结果后端团队怎么调用模型服务、超时时间设多少、错误怎么处理。这些约定如果一开始就定清楚后面能省掉大量的扯皮。我的做法是维护一份INTERFACES.md把每个模块的输入输出、依赖关系、SLA都写清楚。每次有变更先改文档再改代码这样所有人都能对齐。8.4 持续学习这个领域变化太快了AI工程这个领域工具和最佳实践几乎每年都在变。两年前大家还在用Flask部署模型现在FastAPI成了标配一年前大家还在手动管理实验现在MLflow、WandB已经普及。保持学习的方法我觉得有几个关注几个高质量的开源项目看它们怎么做的、定期读一些工程博客、最重要的是动手试。但也不要盲目追新。新技术出来先问自己它解决了什么我现在遇到的问题如果我现在没有这个问题那就先记下来等遇到了再说。我见过太多人追了一堆新工具结果每个都只懂皮毛真正遇到问题的时候还是抓瞎。说到底AI工程的核心能力不是会用多少工具而是理解整个系统的运作原理知道每个环节可能出什么问题以及怎么排查和解决。工具会变但这些底层能力是通用的。把最小闭环跑通把可复现、可扩展、可观测这三个原则刻在脑子里剩下的就是在这个基础上不断迭代和打磨了。