☰
AI工程韧性实战:Harness、RAG与CI/CD从原型到生产
2026/10/5 8:46:31 网站建设 项目流程

1. 从原型到生产:AI工程韧性到底在解决什么问题

做过AI项目的人大概都有这种体会:demo跑通那一刻特别兴奋,觉得事情成了一半,结果一上真实流量,各种幺蛾子全来了。模型输出时好时坏,检索结果偶尔驴唇不对马嘴,接口超时、限流、格式解析失败轮番上阵,用户一句“怎么又答错了”就能把整个团队的信心打没。这就是典型的“原型很美好,生产很骨感”。

所谓有韧性的AI工程,说白了就是让系统在真实、嘈杂、不可控的环境里依然能稳定交付可用结果的能力。它跟传统软件工程的“高可用”有交集,但难度更高,因为AI系统里多了一个不确定的组件——大模型本身。传统服务你输入A基本就得到B,而LLM(大语言模型)输入A可能得到B、C、D,甚至一段看起来像模像样但完全错误的胡话。所以韧性工程的核心,不是消灭不确定性,而是把不确定性关进笼子里,让它即使犯错也不至于把整个系统拖垮。

这套东西适合谁看?如果你正在把RAG知识库、AI Agent、LLM应用从个人电脑搬到服务器上,或者已经上线但天天被badcase折磨,那这篇内容就是写给你的。我会围绕**Harness(工程化外壳)、RAG(检索增强生成)、CI/CD(持续集成与持续交付)**这几块,把原型到生产之间那些没人明说但必须踩的坑,一条条摊开讲。

先给个整体判断:一个能扛事的AI系统,通常由四层构成——模型层、编排层(Harness)、知识层(RAG)、交付层(CI/CD)。原型阶段大家往往只关注模型层,觉得换个更强的模型就万事大吉;但真正决定韧性的,是后面三层。模型会换代,但一套好的工程骨架能让你换模型时几乎无痛。下面我按这个思路,从设计到落地逐层拆。

2. 整体架构设计:为什么韧性要靠分层而不是靠单点

2.1 把LLM当成“不可靠的第三方服务”来设计

很多人设计AI系统时,潜意识里把LLM当成一个函数:调用它,拿到结果,完事。这种心智模型是原型思维。生产思维应该反过来——把LLM当成一个随时可能超时、限流、返回垃圾、甚至拒绝服务的第三方API。你想想,如果你对接的是别人家的支付接口,你会怎么做?肯定要加重试、加超时、加降级、加对账。对LLM也该如此。

这个视角一换,很多设计就顺了。比如模型返回的JSON解析失败,你不能直接抛异常让整个请求挂掉,而应该有一个“修复重试”的通道:把错误信息和原始输出一起塞回去,让模型自己修一遍。再比如检索为空,不能硬着头皮让模型瞎编,而应该走“无知识兜底”分支,明确告诉用户“这个问题我暂时没有可靠资料”。这些分支在原型里通常被省略,但它们恰恰是韧性的来源。

2.2 Harness:给模型套上“安全带”的工程外壳

热词里反复出现Harness,很多人第一次听到会懵:它和Agent到底啥区别?我的理解是,Agent关注的是“模型能不能自己规划、调用工具、多步推理”,偏能力;而Harness关注的是“怎么把模型的能力安全、可控、可观测地跑起来”,偏工程。打个比方,Agent是司机,Harness是整辆车——安全带、刹车、仪表盘、行车记录仪,一个都不能少。

一个合格的Harness至少要做四件事:输入输出的结构化校验、调用链路的超时与重试、上下文的裁剪与拼装、全流程的可观测埋点。这四件事听起来朴素,但每一条都能救命。我见过太多项目,模型本身没问题,死在“上下文拼太长把token撑爆”或者“某个工具调用卡死导致整个请求超时”上。Harness的价值就是把这些琐碎的、跨模型的、跟业务无关的脏活统一收口,让上层业务逻辑保持干净。

2.3 RAG不是“检索+拼接”,而是知识供应链

RAG(检索增强生成)被讲烂了,但真正做扎实的没几个。多数教程停留在“把文档切块、向量化、检索top-k、拼进prompt”这个层面,跑个demo没问题,一上生产就露馅。问题出在哪?出在大家把RAG当成一个函数,而不是一条知识供应链。

供应链意味着每个环节都可能出问题:文档解析可能丢格式,切块可能切断语义,向量化可能语义漂移,检索可能召回无关内容,重排可能把对的排后面,拼接可能超出上下文。韧性RAG要求你对每个环节都有监控和兜底。比如检索回来的内容相关性低于阈值时,宁可不拼,也不要污染模型的判断。再比如知识库里既有结构化数据又有非结构化文本,你得想清楚什么场景查哪种,而不是一股脑全塞进向量库。

2.4 CI/CD:让AI系统的每次变更都可回滚

传统CI/CD管的是代码,AI系统的CI/CD还得管提示词、知识库、模型版本、评测集。这四样东西任何一个变了,系统行为都可能变。我踩过最深的坑是:改了一句提示词,线上准确率掉了十几个点,但因为没做提示词版本管理,回滚都无从下手。

所以AI的CI/CD要额外做三件事:提示词和配置的版本化、离线评测集的自动化回归、灰度发布与快速回滚。每次改动先跑评测集,指标不达标直接卡住;达标了先放小流量,观察真实badcase;出问题一键回滚到上一个稳定版本。这套机制建起来之后,你才敢频繁迭代,否则每次上线都像赌博。

3. 核心细节拆解:Harness、RAG、CI/CD各自的实操要点

3.1 Harness工程化的四个关键动作

第一个动作是结构化输出校验。让模型返回JSON是常见需求,但模型经常给你返回带markdown代码块的JSON、带解释文字的JSON、甚至字段名拼错的JSON。我的做法是:先用正则把可能的JSON块抠出来,再用宽松解析器尝试解析,失败则触发一次“修复调用”,把错误和原文一起给模型让它重写。实测下来,这一套能把解析失败率从百分之十几压到百分之一以内。

第二个动作是超时与重试的精细化。不要用一个全局超时糊弄所有调用。检索、模型生成、工具调用,各自的合理耗时完全不同。检索通常几百毫秒,模型生成可能几秒到几十秒,工具调用看具体工具。给每类调用单独设超时,并且重试要区分错误类型:网络抖动可以重试,参数错误重试也没用,限流则要退避重试。我一般用指数退避加随机抖动,避免重试风暴把下游打挂。

第三个动作是上下文预算管理。模型的上下文窗口是有限资源,你得像个会计一样精打细算。系统提示词占多少、历史对话占多少、检索内容占多少、留给输出的空间有多少,都要提前分配。我的经验是给检索内容设一个硬上限,超出就按相关性截断,绝不因为“舍不得”而把上下文撑爆。撑爆的后果往往是模型直接报错,或者更糟——它开始忽略中间的内容。

第四个动作是全链路埋点。每次请求的输入、检索到的文档ID、拼装的prompt、模型的原始输出、解析后的结果、耗时、token消耗,全部记下来。这些数据平时看着冗余,出问题时就是救命稻草。我排查过一个“模型偶尔答非所问”的问题,最后就是靠埋点发现是某类问题的检索结果被重排模型错误地压到了最后。

3.2 RAG韧性的三个易被忽视的环节

文档解析与切块。这是最脏最累但最影响效果的环节。PDF里的表格、扫描件的OCR、网页的正文提取,每一个都是坑。切块更不能无脑按字数切,那样会把一个完整语义单元拦腰截断。我通常按标题层级切,再对超长段落做语义切分,同时保留一定的重叠窗口,让上下文不至于断裂。切块大小没有万能值,中文场景我一般从500字左右起步,根据评测结果微调。

检索策略的组合。纯向量检索擅长语义相似,但对精确匹配(比如产品型号、专有名词)很弱;关键词检索(BM25)擅长精确匹配,但不懂语义。生产环境我基本都用混合检索:两路召回后做融合排序。融合可以用简单的加权,也可以用RRF(倒数排名融合)。实测混合检索比单路向量检索的召回质量高出一截,尤其是用户query里带具体名词的时候。

重排与阈值。召回阶段宁滥勿缺,重排阶段再精挑细选。重排模型(cross-encoder类)比向量相似度准得多,但慢,所以只对top-N做。重排之后一定要设相关性阈值,低于阈值的直接丢弃。这一步是防止“检索到无关内容反而误导模型”的关键。很多RAG答非所问,根因就是检索回来的东西本身就不相关,模型被带偏了。

3.3 CI/CD在AI项目里的特殊改造

评测集是命根子。没有评测集,你的CI/CD就是空转。评测集要覆盖典型问题、边界问题、对抗性问题,并且要持续补充线上badcase。我习惯把评测集分成“冒烟集”(几十条,每次提交都跑)和“全量集”(几百上千条,发版前跑)。冒烟集要快,几分钟出结果;全量集可以慢,但要全面。

提示词也要进版本库。提示词不是代码,但它比代码还敏感。把提示词当配置文件管理,每次改动走PR流程,记录改动原因和预期效果。上线后如果指标异常,能立刻定位到是哪次提示词改动引入的。

灰度与回滚。新版本先放5%流量,观察核心指标(准确率、拒答率、平均耗时、token成本)有没有异常。异常就回滚,正常再逐步放量。回滚要能做到分钟级,所以模型版本、提示词版本、知识库版本都要能独立切换。这一点在原型阶段没人管,但生产阶段是刚需。

4. 实操落地:从零搭一套可复现的韧性骨架

4.1 环境与依赖准备

假设你用的是Python技术栈,核心依赖大概这几类:模型调用客户端(各家SDK或统一封装)、向量库客户端、Web框架(FastAPI比较顺手)、任务队列(可选,用于异步)、监控(日志+指标)。我建议一开始就把配置抽出来,用环境变量或配置文件管理模型地址、密钥、超时参数、阈值参数,别硬编码在代码里。

# 示例:用环境变量管理关键配置 export LLM_BASE_URL="http://your-llm-endpoint/v1" export LLM_API_KEY="your-key" export LLM_TIMEOUT_SECONDS=30 export RETRIEVAL_TOP_K=8 export RERANK_TOP_N=4 export RELEVANCE_THRESHOLD=0.35

这些参数后面都会在评测中反复调整,抽出来改起来才不痛苦。

4.2 Harness核心代码骨架

下面是一个简化但可用的Harness骨架,重点看它的分层和兜底逻辑。

import json import re import time from typing import Any class LLMHarness: def __init__(self, client, max_retries=2, timeout=30): self.client = client self.max_retries = max_retries self.timeout = timeout def call_with_repair(self, messages, schema_hint=None): raw = self._call_with_retry(messages) parsed = self._try_parse(raw) if parsed is not None: return parsed # 解析失败,触发修复调用 repair_messages = messages + [ {"role": "assistant", "content": raw}, {"role": "user", "content": f"上面的输出无法解析为JSON。请只输出合法JSON,不要任何解释。参考结构:{schema_hint}"} ] raw2 = self._call_with_retry(repair_messages) return self._try_parse(raw2) def _call_with_retry(self, messages): last_err = None for attempt in range(self.max_retries + 1): try: return self.client.chat(messages, timeout=self.timeout) except RateLimitError as e: last_err = e time.sleep((2 ** attempt) + random.random()) except TimeoutError as e: last_err = e time.sleep(1) raise last_err def _try_parse(self, text): if not text: return None # 先尝试直接解析 try: return json.loads(text) except json.JSONDecodeError: pass # 再尝试抠出代码块里的JSON match = re.search(r"```(?:json)?\s*(\{.*?\})\s*```", text, re.DOTALL) if match: try: return json.loads(match.group(1)) except json.JSONDecodeError: return None return None

这段代码的价值不在多复杂,而在于它把“重试、退避、修复、解析”这几件事收口了。上层业务只管调用call_with_repair,不用关心模型抽风。

4.3 RAG检索链路的关键参数与计算

检索链路我一般拆成四步:query改写、混合召回、重排、阈值过滤。每一步都有参数要调。

query改写是为了解决用户口语化、指代不明的问题。比如用户问“它多少钱”,得先结合历史对话把“它”补全成具体产品名。这一步可以用小模型做,成本低。

混合召回里,向量召回和关键词召回各取top-K,K一般设10到20。融合用RRF,公式是score = Σ 1/(k + rank),k通常取60。RRF的好处是不用调权重,对两路召回的分数尺度不敏感。

重排对融合后的top-N做,N一般取召回总数的一半左右。重排模型输出相关性分数,然后按阈值过滤。阈值怎么定?我的方法是拿评测集跑一遍,画出准确率和召回率随阈值变化的曲线,选一个准确率可接受、召回率不太低的点。中文场景我实测0.3到0.4之间比较常见,但一定要用自己的数据校准。

上下文拼装时,给检索内容设token上限。假设模型上下文窗口是8k,系统提示词占500,历史对话占1000,输出预留1500,那检索内容最多6000token。按中文大概1.5字/token估算,就是9000字左右。超出就按重排分数从高到低截断。

4.4 CI/CD流水线的具体配置

以常见的GitLab CI为例,一个AI项目的流水线大概长这样:

stages: - lint - smoke_test - full_eval - deploy_staging - canary smoke_test: stage: smoke_test script: - python run_eval.py --suite smoke --threshold 0.85 only: - merge_requests full_eval: stage: full_eval script: - python run_eval.py --suite full --threshold 0.80 only: - main canary: stage: canary script: - python deploy.py --env prod --traffic 5 - python monitor.py --duration 600 --alert-on "accuracy<0.75" when: manual

关键点是:冒烟集卡MR,全量集卡主干,灰度手动触发且带监控。评测脚本要能输出结构化结果,方便对比历史版本。我一般会把每次评测的指标存进数据库,画成趋势图,这样能一眼看出某次改动是不是引入了退化。

5. 常见问题与排查技巧实录

5.1 模型输出不稳定,同一问题答案忽好忽坏

这是最高频的问题。排查顺序我一般是:先看温度参数是不是设太高(生产环境建议0到0.3),再看检索结果是不是每次不一样(向量库更新、重排随机性),最后看prompt里有没有引入随机因素。如果都正常,那可能是模型本身在长上下文下注意力漂移,这时候要么缩短上下文,要么换更稳的模型。

5.2 RAG答非所问,检索内容明明相关

这种情况八成是重排或阈值出了问题。先检查重排后的top内容是不是真的相关,如果重排把对的排后面了,可能是重排模型和你的领域不匹配,考虑换模型或加领域微调。如果重排没问题但模型还是答偏,那可能是prompt里检索内容和问题的关联没讲清楚,试试在检索内容前加一句“以下资料与问题相关,请优先依据资料回答”。

5.3 接口超时频繁,用户等待体验差

先区分是模型慢还是检索慢。埋点数据一看便知。模型慢的话,考虑流式输出,让用户先看到部分结果;检索慢的话,看是不是向量库索引没建好,或者重排模型太大。实在慢,可以上异步:先返回“正在思考”,后台跑完再推送。但异步会复杂化架构,非必要不上。

5.4 评测指标好看,线上效果差

这是典型的评测集和真实分布不一致。评测集往往是你自己精心构造的,而线上用户的问题千奇百怪。解决办法是持续把线上badcase回流到评测集,让评测集越来越接近真实分布。另外,评测指标要选对,别只看准确率,拒答率、平均耗时、token成本都要看。

5.5 常见问题速查表

现象可能原因排查动作解决方向
输出解析失败模型不守格式看原始输出加修复调用、收紧schema提示
答非所问检索污染看检索内容加重排阈值、改prompt
超时频繁模型或检索慢看埋点耗时流式、异步、换小模型
指标虚高评测集偏差对比线上分布回流badcase、扩充评测集
上线后退化配置漂移对比版本版本化管理、灰度回滚

5.6 几条踩坑换来的经验

第一,别迷信更大的模型。很多问题换模型解决不了,是工程问题。我见过团队花大价钱换模型,结果badcase还是那些,因为根因在检索和prompt。

第二,埋点要早做。等项目出问题再补埋点,你会发现自己连复现都做不到。埋点成本很低,收益极高。

第三,评测集要当资产养。它不是一次性的,是持续投入的。一个高质量的评测集,比多招一个人还值钱。

第四,回滚能力比发布能力更重要。能快速回滚,你才敢快速迭代。回滚做不好,团队会越来越保守,迭代速度越来越慢。

第五,成本要监控。token消耗、向量库查询、重排调用,都是钱。上线前算好单次请求成本,上线后盯着趋势,别等账单来了才傻眼。

6. 关于韧性工程的一点个人体会

做AI工程这几年,我最大的感受是:原型拼的是想象力,生产拼的是克制力。原型阶段你可以天马行空,什么新模型新框架都往上堆;生产阶段你得做减法,把不确定的东西一个个收口,把能兜底的地方都兜住。Harness、RAG、CI/CD这三样,本质上都是在给系统加“确定性”——Harness让调用确定,RAG让知识确定,CI/CD让变更确定。确定性越多,系统越有韧性。

还有一点,韧性不是一次建成的,是迭代出来的。别指望第一版就完美,先跑起来,用埋点看问题,用评测集量化改进,用灰度控制风险。每次线上出问题,都是一次让系统更韧的机会。把badcase当燃料,系统才会越跑越稳。

最后分享一个我常用的小技巧:给每个请求生成一个trace_id,从入口一直透传到模型调用和检索,所有日志都带上这个id。出问题时,一个id就能把整条链路串起来,排查效率能提升好几倍。这个习惯我从传统后端带过来,在AI系统里同样好使。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询