ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从零搭建AI工程能力:分层设计与模型调用健壮性实战

从零搭建AI工程能力:分层设计与模型调用健壮性实战 1. 从零搭建AI工程能力为什么我劝你别一上来就调包这两年“AI工程”这个词被说得太多了多到有点变味。打开任何一个技术社区满屏都是“三行代码调用大模型”“十分钟搭建RAG”“零基础转行AI工程师”。我身边不少做后端、做前端、甚至做测试的朋友都来问我是不是真的这么简单我的回答一直是同一句——调包谁都会但把AI能力做成一个能上线、能扛量、能排障的工程系统是另一回事。ai-engineering-from-scratch这个标题我理解的核心不是“教你用某个框架”而是“从零开始把AI工程当成一门正经工程学科来搭”。它要解决的是这样一个问题当你手里有一个模型、一个API、一堆数据怎么把它们组装成一个稳定、可观测、可迭代的产品级系统。这件事适合谁适合那些已经会写代码、但对AI系统落地没有完整认知的开发者也适合已经在做AI应用、但总觉得自己是在“拼凑”而不是“设计”的工程师。我自己踩过的坑很典型早期做第一个AI问答服务时我直接在一个Flask接口里塞了模型调用、提示词拼接、结果解析跑通那一刻特别爽。结果上线第三天接口超时率飙到30%日志里全是看不懂的报错用户投诉答非所问我连问题出在哪一层都定位不了。那次之后我才明白AI工程和传统后端最大的区别在于它的不确定性来自模型本身而工程的价值就是把这部分不确定性关进笼子里。这篇内容我就按“从零搭建”的思路把整套AI工程能力拆开讲清楚包括整体设计、核心细节、实操过程和排障经验尽量让你看完能直接抄作业。2. 整体设计与思路拆解AI工程到底该分几层2.1 为什么不能把AI应用写成一个函数很多人对AI应用的想象是输入问题调用模型返回答案。这个模型在Demo阶段没问题但一旦要面对真实用户就会暴露三个致命问题。第一模型调用是慢且不稳定的外部依赖它可能超时、可能限流、可能返回格式错乱你不能让它直接决定整个请求的生死。第二提示词是核心资产但极易腐化今天改一个字明天效果就变如果没有版本管理你根本不知道哪次改动导致了效果回退。第三效果无法用传统单元测试衡量一个接口返回200不代表答案是对的你需要一套评估机制。所以从零搭建AI工程第一步不是选框架而是分层。我习惯把它分成五层接入层、编排层、模型层、数据层、观测层。接入层负责请求校验、鉴权、限流编排层负责提示词组装、多步推理、工具调用模型层负责具体模型的路由、重试、降级数据层负责向量检索、缓存、历史记录观测层负责日志、指标、追踪和效果评估。这个分层不是照搬教科书而是我在实际排障时倒逼出来的——只有分层清晰出问题时你才能快速判断是“模型抽风”还是“编排逻辑写错了”。2.2 技术选型的取舍逻辑选型这块我不喜欢给死答案因为不同团队规模差别太大。但有几个原则是通用的。编排层优先用代码而不是可视化拖拽原因很简单可视化流程在复杂分支和版本对比时会变成灾难而代码可以进Git、可以Code Review、可以写测试。模型层一定要做抽象不要让你的业务代码直接依赖某一家厂商的SDK否则换模型时你会想哭。我通常会在模型层定义一个统一接口把不同厂商的调用差异封装在适配器里。向量库的选择要看数据量级。几万条数据用本地文件加内存索引完全够用几十万到百万级可以考虑轻量级向量库再往上才需要分布式方案。我见过太多团队一上来就上重型向量数据库结果数据才几千条运维成本比收益还高。缓存策略是AI工程里被严重低估的一环相同或相似的问题占比往往很高一层语义缓存能省下大量模型调用成本还能显著降低响应延迟。2.3 从零搭建的推荐路径如果你真的是从零开始我建议按这个顺序推进不要跳步。第一步先用最朴素的方式跑通“输入到输出”的闭环哪怕就是几十行代码目的是建立体感。第二步把模型调用抽出来做成独立模块加上超时、重试、降级。第三步引入提示词模板管理把提示词从代码里剥离出来。第四步加上日志和基础指标让你能看见系统在发生什么。第五步引入评估集每次改动前后跑一遍用数据说话。第六步再做缓存、检索、多模型路由这些进阶能力。这个顺序背后的逻辑是先保证能看见再保证能控制最后才追求能优化。很多团队反着来一上来就搞多智能体、搞复杂RAG结果系统像个黑盒出了问题只能靠猜。我个人的经验是一个AI工程系统的成熟度不取决于它用了多炫的技术而取决于它在出问题时你能不能五分钟内定位到根因。3. 核心细节解析与实操要点把不确定性关进笼子3.1 模型调用层的健壮性设计模型调用是整条链路里最不可控的一环所以这里的工程细节最多。首先是超时设置我一般会把超时分成两段连接超时和读取超时。连接超时设短一点比如3到5秒因为连不上就是连不上等再久也没用读取超时根据任务复杂度设简单问答15到30秒复杂推理可以放到60秒甚至更长。这里有个坑很多HTTP客户端默认没有读取超时模型卡住时你的线程会被一直占着并发一上来直接雪崩。其次是重试策略。不是所有错误都值得重试。网络抖动、限流这类瞬时错误可以重试但参数错误、内容审核拒绝这类确定性错误重试多少次都一样。我通常用指数退避加重试上限比如最多重试2次间隔1秒、2秒。重试时要注意幂等性尤其是涉及计费的调用别因为重试把账单翻倍。第三是降级方案。当主模型不可用时你要有备选。备选可以是更小的模型、可以是缓存里的历史答案、也可以是一句友好的兜底话术。降级的关键是提前设计好触发条件比如连续失败3次、或者错误率超过阈值就自动切换而不是等用户投诉了才手动处理。# 模型调用适配器的简化示意 class ModelAdapter: def __init__(self, primary, fallback, timeout30, max_retries2): self.primary primary self.fallback fallback self.timeout timeout self.max_retries max_retries def call(self, prompt, **kwargs): for attempt in range(self.max_retries 1): try: return self.primary.invoke(prompt, timeoutself.timeout, **kwargs) except TransientError as e: if attempt self.max_retries: break time.sleep(2 ** attempt) except PermanentError: break # 主模型彻底失败走降级 return self.fallback.invoke(prompt, timeoutself.timeout, **kwargs)注意降级返回的内容一定要打上标记方便后续在日志和评估里区分否则你会把降级答案当成正常答案去分析得出错误结论。3.2 提示词工程的管理与版本化提示词是AI应用里最像“代码”又最不像“代码”的东西。它影响效果但它不是逻辑改起来没有编译报错所以特别容易失控。我的做法是把提示词当成配置文件来管理每个提示词有唯一ID、有版本号、有变更记录。提示词模板里用占位符表示变量运行时填充而不是在代码里做字符串拼接。提示词版本化还有一个好处可以做A/B测试。同一批请求一半走v1提示词一半走v2对比效果指标。没有版本化你连对比的基准都没有。我见过团队改提示词全靠“感觉这次更好”结果上线后效果反而下降回头想找回旧版本发现已经被覆盖了只能凭记忆重写。另外提示词里要明确输出格式约束。如果你期望模型返回JSON就在提示词里写清楚字段名、类型、是否必填并且给出示例。即便如此也要在代码里做解析容错因为模型偶尔还是会多输出一段解释文字。解析失败时不要直接抛异常给用户而是尝试提取JSON片段或者触发一次“格式修复”的重新调用。3.3 数据层缓存与检索的配合缓存这块我想重点讲语义缓存。传统缓存用精确的key匹配但用户问“怎么重置密码”和“密码忘了怎么办”是两个key实际是同一个意图。语义缓存的做法是把用户问题向量化在缓存库里找相似度超过阈值的历史问题命中就直接返回历史答案。阈值一般设在0.9以上比较稳妥太低会返回不相关答案太高又命中不了。检索增强这块核心是分块策略。文档不能整篇塞进向量库要切成合适大小的块。块太大检索出来的内容冗余浪费上下文窗口块太小语义不完整检索质量下降。我一般按语义边界切比如按段落、按标题层级块大小控制在200到500字之间块之间保留一定重叠避免关键信息被切断。检索时还有个细节召回数量不是越多越好。召回10条和召回3条效果可能差不多但成本和延迟差很多。我通常先召回一个较大的候选集比如20条然后用重排序模型或者简单的相似度阈值筛到3到5条再送给模型。这个“粗排加精排”的思路和传统搜索系统是一致的。4. 实操过程与核心环节实现从空目录到可运行系统4.1 项目骨架搭建与依赖管理我习惯从一个干净的空目录开始先把项目骨架立起来。目录结构大致是这样app/放接入层代码orchestration/放编排逻辑models/放模型适配器data/放数据访问和缓存observability/放日志和指标prompts/放提示词模板evals/放评估集和评估脚本。这个结构不是强制的但它的好处是每个目录对应一个关注点新人进来能快速理解系统边界。依赖管理上我强烈建议用虚拟环境加锁定文件。AI项目的依赖往往又大又杂不同版本的SDK行为可能不一样锁定版本能避免“在我机器上能跑”的经典问题。配置文件用环境变量注入不要把API密钥硬编码在代码里这是基本的安全底线。# 初始化项目骨架 mkdir ai-engineering-from-scratch cd ai-engineering-from-scratch python -m venv .venv source .venv/bin/activate pip install fastapi uvicorn httpx pydantic pip freeze requirements.txt4.2 最小闭环一个能跑的问答接口骨架搭好后先实现最小闭环。接入层用FastAPI起一个接口接收问题调用编排层返回答案。编排层这时候可以很简单就是拼一个提示词调用模型解析结果。这个阶段的目标不是完美而是让整条链路通起来这样你才能开始观察和迭代。from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class Query(BaseModel): question: str app.post(/ask) async def ask(query: Query): prompt build_prompt(query.question) answer model_adapter.call(prompt) return {answer: answer}跑通之后立刻加上日志。日志里要记录请求ID、用户问题、使用的提示词版本、模型名称、耗时、token消耗、返回结果。这些字段看起来多但排障时每一个都可能救命。我吃过亏早期没记录提示词版本效果回退时完全不知道是哪次改动导致的只能一个个翻Git提交。4.3 加上超时、重试与降级最小闭环跑通后马上补健壮性。把模型调用换成前面说的适配器模式加上超时和重试。这里有个实操细节超时时间要分层设置。接入层对外的超时要大于模型层的超时比如接入层设60秒模型层设30秒这样模型层超时后还有时间走降级而不是整个请求直接被接入层掐断。降级方案我一般准备两级第一级是切换到备用模型第二级是返回缓存答案或兜底话术。触发条件用滑动窗口统计比如最近1分钟错误率超过20%就触发降级恢复后自动切回。这个逻辑要写成独立模块不要散落在业务代码里。4.4 引入评估集与回归测试这是从零搭建AI工程里最容易被跳过、但最重要的一步。你需要准备一个评估集里面是若干条“问题加标准答案”或者“问题加评分标准”。每次改动提示词、换模型、调参数都跑一遍评估集对比指标。指标可以是准确率、相关性、格式合规率甚至可以用另一个模型来打分。评估集不用一开始就很大20到50条高质量样本就能发现大部分问题。关键是持续维护把线上发现的bad case补充进去让评估集越来越贴近真实场景。我现在的习惯是每次线上出现严重bad case第一件事就是把它加进评估集然后修复再跑回归确保不会再次出现。评估维度衡量方式目标参考值答案相关性人工或模型打分4分以上5分制格式合规率解析成功比例99%以上平均延迟端到端耗时3秒以内降级触发率降级请求占比1%以下4.5 观测层让系统变得可看见观测层包括日志、指标、追踪三块。日志记录离散事件指标记录聚合趋势追踪记录单次请求的完整链路。AI工程里追踪特别重要因为一次请求可能经过提示词组装、检索、模型调用、结果解析多个环节没有追踪你根本不知道时间花在哪。我一般用请求ID把整条链路串起来每个环节记录开始和结束时间。指标方面重点看几个请求量、错误率、延迟分位数P50、P95、P99、token消耗、缓存命中率、降级触发率。这些指标配上告警能让你在用户投诉之前发现问题。P99延迟尤其值得关注因为AI调用的长尾效应很明显平均值好看不代表体验好。5. 常见问题与排查技巧实录那些文档里不会写的事5.1 模型返回格式错乱的排查思路这是最高频的问题。你明明在提示词里要求返回JSON模型却给你返回一段带解释的文字。排查时先看提示词是否足够明确有没有给示例。如果提示词没问题那就是模型的随机性导致的需要在代码里做容错解析。我的做法是先用正则提取JSON片段提取失败再触发一次“只返回JSON”的修复调用修复调用还失败才走兜底。还有一个隐蔽原因温度参数设太高。温度越高输出越随机格式越容易跑偏。对于需要严格格式的任务温度设0到0.3比较稳妥。这个参数很多人不注意但它对稳定性的影响非常大。5.2 响应慢的定位方法响应慢要先分段定位。看追踪数据是检索慢、模型调用慢、还是解析慢。模型调用慢又分两种情况首token慢和整体生成慢。首token慢通常是网络或模型排队问题整体生成慢通常是输出太长。对应的优化手段不同前者考虑换区域或换模型后者考虑限制输出长度或流式返回。流式返回是改善体验的利器。用户不用等完整答案生成完而是边生成边显示感知延迟大幅降低。但流式也有代价错误处理更复杂因为可能已经输出一半了才发现出错。我的经验是流式适合对话类场景不适合需要严格格式校验的场景。5.3 效果回退的应急处理效果回退最让人头疼因为它不像接口报错那么明显。用户可能只是觉得“答案变差了”但说不清哪里差。这时候评估集就派上用场了。先跑评估集确认是否真的回退再看最近有哪些变更提示词改了没、模型换了没、参数调了没、检索策略变了没。应急处理的第一步是回滚到上一个已知good版本先止血。然后离线复现问题定位根因。我建议每次上线都保留上一个版本的提示词和配置回滚时能一键切换。这个习惯救过我很多次尤其是节假日前的紧急上线。常见问题可能原因排查动作解决方向格式错乱提示词不明确、温度过高检查提示词和温度参数加示例、降温度、加解析容错响应慢检索慢、模型排队、输出长看追踪分段耗时优化检索、换模型、流式返回效果回退提示词变更、模型变更跑评估集、对比版本回滚、离线复现、定位根因成本飙升缓存失效、重试过多、输出长看token消耗和缓存命中率修缓存、限重试、限输出长度5.4 成本控制的几个实操技巧成本控制不是等账单来了才做而是设计阶段就要考虑。第一缓存能省的钱远超你想象尤其是FAQ类场景命中率能到50%以上。第二限制输出长度很多任务不需要长篇大论设个上限能省不少token。第三小模型能做的事不要用大模型比如意图分类、格式修复这类任务小模型完全够用。第四批量处理如果场景允许把多个请求合并成一次调用能摊薄开销。提示成本监控要按维度拆开看比如按接口、按用户、按模型。只看总账单你永远不知道钱花在哪拆开看才能发现异常。6. 我个人的几点实操体会从零搭建AI工程这件事我最大的体会是它考验的不是你对某个模型的了解而是你对工程本质的理解。模型会换、框架会变、提示词技巧会过时但分层、抽象、可观测、可回滚这些工程原则是稳定的。我见过太多人把精力花在追新模型上却连基本的超时和重试都没做系统一上量就崩。另一个体会是评估集的价值怎么强调都不为过。没有评估集你的所有优化都是盲人摸象。我现在的习惯是任何AI项目启动的第一周就要把评估集的框架搭起来哪怕只有十条样本。它逼着你把“效果好”这个模糊概念变成可衡量的指标这是从玩具走向产品的分水岭。最后分享一个小技巧把每次线上bad case都当成礼物。用户帮你发现了评估集没覆盖的场景这是最真实的反馈。我有个习惯每周花半小时翻一遍线上bad case挑出典型的补进评估集。坚持几个月后你会发现系统的稳定性有质的提升因为你在用真实世界的边界不断打磨它。这个内容后续还可以往多模型路由、智能体编排、成本自动优化这些方向扩展但前提是基础工程能力已经扎实否则上层建筑都是空中楼阁。
返回列表