ARTICLE DETAIL

资讯详情

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

以实战论 AI:诚邀一线工程师分享模型调优、工程落地真实案例

以实战论 AI:诚邀一线工程师分享模型调优、工程落地真实案例 聊 AI 的文章太多了但大部分要么停在概念科普层面要么就是我用了某个模型效果很好的体验式分享。真正把模型从 60 分调到 85 分的过程从 demo 到生产踩的那些坑反而很少有人系统性地讲。这篇文章不讲概念只讲实战。模型调优怎么做的、工程上怎么落地的、踩了什么坑、怎么解决的——全是真实经历。如果你也在搞大模型落地希望这些经验能帮你少走点弯路。一、模型调优从 60 分到 85 分的那些事1.1 先搞清楚你的模型为什么只有 60 分很多人拿到一个开源模型跑了几条测试觉得效果不行第一反应是换个更大的模型。但大模型不一定能解决你的问题——很多时候不是模型不够大是你喂给它的东西不对。我见过太多团队模型选型花了两周prompt 调优只花了十分钟。这个优先级完全反了。先看一张调优路径图搞清楚该在哪发力核心原则先调 prompt再调检索最后才考虑微调。微调成本最高、收益最不确定应该是最后的手段。1.2 实战案例运维知识库问答的调优过程我们做了一套运维知识库问答系统用 Qwen2.5-14B RAG第一版的效果大概是检索命中率55%10 个问题里有 4.5 个没检索到正确文档回答准确率60%幻觉率18%这个数据显然上不了线。接下来花了两周时间做调优最终指标检索命中率88%回答准确率85%幻觉率4%下面是每一步具体做了什么。1.3 第一步优化检索命中率 55% → 88%检索是 RAG 的地基检索不对后面模型再强也白搭。我们排查发现命中率低有三个原因原因一向量模型不适合中文运维场景。之前用的是通用的 text2vec对Redis 脑裂连接池打满这种运维术语理解不好。换成了 bge-large-zh-v1.5 后命中率直接涨了 12 个百分点。原因二分块策略有问题。之前按固定 500 字符切把操作步骤切断了。比如一段第一步检查...第二步执行...被切成了两个块检索只命中了第二步模型生成时缺少第一步的上下文。改成按 Markdown 标题 段落分块保留语义完整性。同时设置了 100 字符的重叠窗口防止边界信息丢失。原因三没有 Rerank。向量检索召回的 top-10 里最相关的可能排在第 7、8 位但最终只取 top-3 喂给模型直接把正确答案丢了。加了 bge-reranker 做二次排序后最相关的文档基本都排进了 top-3。python #!/usr/bin/env python3 RAG 检索优化工具包 - 多阶段检索向量召回 → Rerank 精排 → 上下文组装 - 分块策略按 Markdown 结构分块 滑动窗口重叠 import re import json import numpy as np from sentence_transformers import SentenceTransformer, CrossEncoder # 1. 智能分块 class MarkdownChunker: 按 Markdown 标题结构分块保留语义完整性 def __init__(self, max_chunk_size800, overlap100): self.max_chunk_size max_chunk_size self.overlap overlap def chunk(self, text, source): 将文档按标题段落分块 # 按 Markdown 标题切分 sections self._split_by_headers(text) chunks [] for section in sections: title section[title] content section[content].strip() if not content: continue # 如果单个 section 太长再按段落切 if len(content) self.max_chunk_size: paragraphs content.split(\n\n) current_chunk for para in paragraphs: if len(current_chunk) len(para) self.max_chunk_size: if current_chunk: chunks.append({ content: f{title}\n{current_chunk}, source: source, section: title, }) # 重叠窗口保留上一块末尾的内容 overlap_text current_chunk[-self.overlap:] if len(current_chunk) self.overlap else current_chunk overlap_text \n para else: current_chunk \n\n para if current_chunk else para if current_chunk.strip(): chunks.append({ content: f{title}\n{current_chunk}, source: source, section: title, }) else: chunks.append({ content: f{title}\n{content}, source: source, section: title, }) return chunks def _split_by_headers(self, text): 按 # ## ### 标题切分 sections [] current_title current_content for line in text.split(\n): if re.match(r^#{1,4}\s, line): if current_content.strip(): sections.append({title: current_title, content: current_content}) current_title line.strip() current_content else: current_content line \n if current_content.strip(): sections.append({title: current_title, content: current_content}) return sections # 2. 多阶段检索 class HybridRetriever: 向量召回 Rerank 精排 def __init__(self): # 向量模型召回阶段 self.encoder SentenceTransformer(BAAI/bge-large-zh-v1.5) # Rerank 模型精排阶段 self.reranker CrossEncoder(BAAI/bge-reranker-large) self.documents [] self.embeddings None def index(self, chunks): 构建向量索引 self.documents chunks texts [c[content] for c in chunks] self.embeddings self.encoder.encode(texts, normalize_embeddingsTrue) print(f索引完成: {len(chunks)} 个文档块) def retrieve(self, query, top_k3, recall_k20): 两阶段检索 1. 向量召回 top-k*5宽召回 2. Rerank 精排取 top-k精筛选 # 第一阶段向量召回 query_emb self.encoder.encode([query], normalize_embeddingsTrue) scores np.dot(self.embeddings, query_emb.T).flatten() # 宽召回取 recall_k 个候选 candidate_indices np.argsort(scores)[-recall_k:][::-1] candidates [self.documents[i] for i in candidate_indices] # 第二阶段Rerank 精排 pairs [[query, c[content]] for c in candidates] rerank_scores self.reranker.predict(pairs) # 按 rerank 分数排序取 top_k ranked sorted(zip(candidates, rerank_scores), keylambda x: x[1], reverseTrue) results [] for doc, score in ranked[:top_k]: results.append({ **doc, rerank_score: float(score), }) return results # 3. 使用示例 if __name__ __main__: # 模拟知识库文档 docs [ { content: ## Redis 集群脑裂处理 当 Redis 集群出现网络分区时可能出现脑裂问题。 处理步骤 1. 配置 min-slaves-to-write1确保主节点至少有一个从节点确认写入 2. 启用 Sentinel 自动故障转移 3. 检查网络分区恢复后确保旧主节点降级为从节点 4. 验证数据一致性, source: Redis运维手册.md }, { content: ## MySQL 慢查询优化 慢查询排查步骤 1. 开启 slow_query_log 2. 设置 long_query_time1 3. 使用 EXPLAIN 分析执行计划 4. 检查索引覆盖情况 5. 优化 SQL 写法避免 SELECT *, source: MySQL调优指南.md }, ] # 分块 chunker MarkdownChunker(max_chunk_size800, overlap100) all_chunks [] for doc in docs: chunks chunker.chunk(doc[content], sourcedoc[source]) all_chunks.extend(chunks) # 检索 retriever HybridRetriever() retriever.index(all_chunks) # 测试 results retriever.retrieve(Redis 脑裂怎么处理, top_k3) for r in results: print(f来源: {r[source]} | 分数: {r[rerank_score]:.4f}) print(f内容: {r[content][:100]}...) print() 1.4 第二步优化 Prompt准确率 60% → 75%检索优化完之后准确率从 60% 涨到了 75%——因为模型终于能看到正确的上下文了。但还有 25% 的回答不够好这部分靠 prompt 优化来解决。调优前后的 prompt 对比调优前的 prompt 请根据以下参考信息回答问题。 参考信息{context} 问题{question} 回答 问题很明显没有约束输出范围、没有引导推理过程、没有处理信息不足的情况。调优后的 prompt 你是一个专业的运维工程师。请严格按照以下要求回答问题。 ## 参考信息 {context} ## 回答要求 1. 只能基于参考信息回答不得编造参考信息中不存在的内容 2. 如果参考信息不足以回答问题请明确回答当前知识库未覆盖此问题建议查阅以下文档[列出可能相关的文档名] 3. 回答时先给出结论再给出操作步骤 4. 操作步骤必须编号每步不超过两句话 5. 如果涉及风险操作必须标注「⚠️ 风险提示」 ## 示例 问题Redis 内存满了怎么办 回答 Redis 内存满了可以通过以下方式处理 1. 检查内存使用情况执行 INFO memory 查看 used_memory 和 maxmemory 2. 配置淘汰策略设置 maxmemory-policy 为 allkeys-lru ⚠️ 风险提示设置淘汰策略会导致部分 key 被自动删除 3. 扩容如果数据量持续增长考虑增加 Redis 节点 ## 当前问题 {question} 三个关键改进加了 Few-shot 示例让模型知道好回答长什么样加了兜底策略信息不足时明确说不知道而不是编一个加了结构约束先结论后步骤、步骤编号、风险标注光这三个改进准确率就从 75% 涨到了 82%幻觉率从 12% 降到了 6%。1.5 第三步领域微调准确率 82% → 85%最后一步是微调。说实话这步的投入产出比不如前两步高——花了三天准备数据、一天微调、一天评估准确率只涨了 3 个百分点。但这个 3% 恰好是之前怎么调 prompt 都上不去的部分领域术语理解。比如灰度发布蓝绿部署熔断降级这些概念通用模型的理解是大概知道但不够精准。用团队自己的发布流程文档做 SFT 数据让模型学会我们公司说的灰度发布具体是什么流程。python #!/usr/bin/env python3 LoRA 微调数据准备脚本 - 从历史问答数据中构造 SFT 训练集 - 格式化为 Qwen 模型要求的格式 import json import random from pathlib import Path # 微调数据模板 SFT_TEMPLATE { instruction: 你是一个专业的运维工程师请基于团队知识库回答问题。, input_format: 问题{question}\n\n参考信息{context}, output_format: {answer}, } def build_sft_dataset(raw_qa_pairs, output_file): 将原始问答对转换为 SFT 训练数据 raw_qa_pairs 格式 [ { question: 灰度发布怎么做, context: 相关文档片段..., answer: 标准回答... }, ] sft_data [] for pair in raw_qa_pairs: # 构造指令 instruction SFT_TEMPLATE[instruction] # 构造输入 user_input SFT_TEMPLATE[input_format].format( questionpair[question], contextpair[context], ) # 构造输出人工标注的标准答案 output SFT_TEMPLATE[output_format].format( answerpair[answer], ) sft_data.append({ instruction: instruction, input: user_input, output: output, history: [], # 单轮对话 }) # 打乱顺序 random.shuffle(sft_data) # 划分训练集和验证集9:1 split int(len(sft_data) * 0.9) train_data sft_data[:split] val_data sft_data[split:] # 保存 with open(output_file.replace(.json, _train.json), w, encodingutf-8) as f: json.dump(train_data, f, ensure_asciiFalse, indent2) with open(output_file.replace(.json, _val.json), w, encodingutf-8) as f: json.dump(val_data, f, ensure_asciiFalse, indent2) print(fSFT 数据集生成完成:) print(f 训练集: {len(train_data)} 条 → {output_file.replace(.json, _train.json)}) print(f 验证集: {len(val_data)} 条 → {output_file.replace(.json, _val.json)}) # 数据增强从知识库自动生成问答对 def auto_generate_qa(knowledge_docs, llm_client): 用大模型从知识库文档自动生成问答对 generated [] for doc in knowledge_docs: prompt f请根据以下技术文档生成 3 个问答对。 要求 1. 问题应该是运维工程师实际会遇到的问题 2. 答案必须完全基于文档内容不得编造 3. 答案格式先结论后步骤 文档内容 {doc[content]} 输出 JSON 数组格式 [{{question: ..., answer: ...}}, ...] response llm_client.chat.completions.create( modelqwen2.5-14b-instruct, messages[{role: user, content: prompt}], temperature0.5, ) try: qa_pairs json.loads(response.choices[0].message.content) for qa in qa_pairs: generated.append({ question: qa[question], context: doc[content][:500], # 取前500字符作为上下文 answer: qa[answer], source: doc[source], }) except Exception as e: print(f解析失败: {e}) print(f自动生成 {len(generated)} 个问答对) return generated if __name__ __main__: # 模拟人工标注的问答对 manual_qa [ { question: 灰度发布的标准流程是什么, context: 灰度发布分为四个阶段准备阶段、灰度阶段、观察阶段、全量阶段..., answer: 灰度发布标准流程\n1. 准备阶段确认灰度比例通常 5%→20%→50%→100%\n2. 灰度阶段通过流量网关将指定比例流量导入新版本\n3. 观察阶段每级灰度后观察 30 分钟检查错误率和延迟\n4. 全量阶段确认无异常后全量切换, source: 发布流程规范.md, }, ] build_sft_dataset(manual_qa, sft_dataset.json) 微调用 LLaMA-Factory 框架LoRA 方式r8, alpha16只训练了 3 个 epoch在单张 A100 上跑了一个多小时。模型文件只有 80MB推理时挂载到基础模型上即可不影响原始模型的能力。二、工程落地从能跑到能扛2.1 Demo 和生产的差距模型调好了离上线还差十万八千里。Demo 环境你一个人用QPS 不到 1生产环境几十个人同时用QPS 可能冲到 50。Demo 环境挂了你重启就行生产环境挂了有人打电话找你。下面这张图是从 demo 到生产需要补的工程能力2.2 实战生产级 AI 服务架构下面是一个完整的 AI 服务封装包含负载均衡、超时控制、降级策略python #!/usr/bin/env python3 生产级 AI 服务封装 - 多模型实例负载均衡 - 请求超时 重试 降级 - 全链路监控 - 成本控制 import time import json import random import threading from collections import defaultdict from dataclasses import dataclass, field from concurrent.futures import ThreadPoolExecutor, TimeoutError as FutureTimeout from openai import OpenAI # 1. 模型实例池 dataclass class ModelInstance: 单个模型实例 name: str base_url: str model: str client: OpenAI None request_count: int 0 error_count: int 0 avg_latency: float 0 healthy: bool True def __post_init__(self): self.client OpenAI(base_urlself.base_url, api_keyinternal, timeout30) def chat(self, messages, temperature0.3, max_tokens2048): start time.time() try: response self.client.chat.completions.create( modelself.model, messagesmessages, temperaturetemperature, max_tokensmax_tokens, ) latency time.time() - start self.request_count 1 self.avg_latency (self.avg_latency * (self.request_count - 1) latency) / self.request_count return response.choices[0].message.content, latency except Exception as e: self.error_count 1 if self.error_count 10: self.healthy False print(f⚠️ 实例 {self.name} 标记为不健康: {e}) raise class ModelInstancePool: 模型实例池 负载均衡 def __init__(self, instances): self.instances instances self.lock threading.Lock() def get_instance(self, strategyleast_loaded): 选择一个健康的实例 healthy [i for i in self.instances if i.healthy] if not healthy: # 全部不健康尝试恢复 for i in self.instances: i.healthy True i.error_count 0 healthy self.instances print(⚠️ 所有实例不健康尝试全部恢复) if strategy round_robin: return random.choice(healthy) elif strategy least_loaded: return min(healthy, keylambda x: x.request_count) else: return healthy[0] def call_with_failover(self, messages, **kwargs): 带故障转移的调用 max_retries 3 last_error None for attempt in range(max_retries): instance self.get_instance() try: result, latency instance.chat(messages, **kwargs) return result, latency, instance.name except Exception as e: last_error e print(f实例 {instance.name} 调用失败 (attempt {attempt1}): {e}) continue raise last_error # 2. 超时 降级 class AIServiceWithFallback: 带超时和降级的 AI 服务 def __init__(self, instance_pool, timeout_seconds15): self.pool instance_pool self.timeout timeout_seconds self.executor ThreadPoolExecutor(max_workers10) # 降级策略缓存常见问题的标准答案 self.fallback_cache {} # 监控指标 self.metrics { total_requests: 0, success_count: 0, timeout_count: 0, fallback_count: 0, latency_list: [], } def chat(self, messages, question): 带超时和降级的对话 self.metrics[total_requests] 1 start time.time() try: # 提交到线程池设置超时 future self.executor.submit( self.pool.call_with_failover, messages ) result, latency, instance_name future.result(timeoutself.timeout) self.metrics[success_count] 1 self.metrics[latency_list].append(time.time() - start) # 缓存高频问题的答案 if question and self.metrics[total_requests] % 100 0: self._update_fallback_cache(question, result) return { answer: result, latency: latency, instance: instance_name, fallback: False, } except FutureTimeout: self.metrics[timeout_count] 1 print(f⏱️ 请求超时 ({self.timeout}s)尝试降级) return self._fallback(question) except Exception as e: self.metrics[timeout_count] 1 print(f❌ 请求失败: {e}尝试降级) return self._fallback(question) def _fallback(self, question): 降级策略 self.metrics[fallback_count] 1 # 策略1检查缓存 if question in self.fallback_cache: return { answer: self.fallback_cache[question], latency: 0, instance: cache, fallback: True, } # 策略2返回友好提示 建议操作 return { answer: AI 服务当前响应较慢请稍后重试。如紧急问题请联系值班运维。, latency: 0, instance: fallback, fallback: True, } def _update_fallback_cache(self, question, answer): 更新降级缓存只缓存高频问题 if len(answer) 50: # 太短的不缓存 self.fallback_cache[question] answer # 缓存大小限制 if len(self.fallback_cache) 200: # 淘汰最旧的简化版实际用 LRU oldest next(iter(self.fallback_cache)) del self.fallback_cache[oldest] def get_metrics(self): 获取监控指标 m self.metrics.copy() if m[latency_list]: m[avg_latency] sum(m[latency_list]) / len(m[latency_list]) m[p95_latency] sorted(m[latency_list])[int(len(m[latency_list]) * 0.95)] m[p99_latency] sorted(m[latency_list])[int(len(m[latency_list]) * 0.99)] m[success_rate] m[success_count] / max(m[total_requests], 1) m[fallback_rate] m[fallback_count] / max(m[total_requests], 1) return m # 3. 使用示例 if __name__ __main__: # 创建多个模型实例模拟多副本 instances [ ModelInstance(llm-node-1, http://10.10.100.50:8000/v1, qwen2.5-14b-instruct), ModelInstance(llm-node-2, http://10.10.100.51:8000/v1, qwen2.5-14b-instruct), ModelInstance(llm-node-3, http://10.10.100.52:8000/v1, qwen2.5-14b-instruct), ] pool ModelInstancePool(instances) service AIServiceWithFallback(pool, timeout_seconds15) # 模拟并发请求 def make_request(question): messages [ {role: system, content: 你是运维助手}, {role: user, content: question}, ] result service.chat(messages, questionquestion) status ✅ if not result[fallback] else 降级 print(f{status} [{result[instance]}] {result[latency]:.2f}s | {question[:30]}) # 并发测试 questions [ Redis 连接池打满怎么处理, K8s Pod 频繁重启是什么原因, MySQL 慢查询怎么排查, 如何配置 Nginx 负载均衡, Docker 容器无法启动怎么办, ] with ThreadPoolExecutor(max_workers5) as executor: for q in questions: executor.submit(make_request, q) # 打印监控指标 print(\n * 60) print(服务监控指标:) metrics service.get_metrics() for k, v in metrics.items(): if isinstance(v, float): print(f {k}: {v:.2f}) else: print(f {k}: {v}) 2.3 一次完整的请求时序生产环境下一次用户请求从进来到返回经过了这些环节2.4 实际场景一次线上故障复盘上线第二周遇到了一次故障复盘过程很有参考价值。现象下午 2 点开始用户反馈 AI 回答变慢从平均 2 秒涨到 8 秒部分请求直接超时。排查过程根因分析vLLM 默认的 ​​max_num_seqs​​最大并发序列数没有限制下午高峰期并发请求堆积KV Cache 不断膨胀最终把实例 3 的内存撑爆了。OOM 后请求全部涌向实例 1 和 2导致连锁雪崩。修复措施限制 ​​max_num_seqs128​​防止 KV Cache 无限膨胀加了显存使用率告警超过 85% 就通知扩容降级策略生效超时请求返回了缓存答案没有完全白屏这个故障教会我一件事demo 的时候你永远碰不到并发问题但生产环境的第一个 bug 一定是并发问题。三、成本控制别让 AI 变成烧钱机器3.1 成本黑洞在哪AI 服务的成本主要来自三块成本项占比优化空间GPU 推理成本60-70%模型量化、请求批处理、弹性伸缩向量检索成本15-20%索引优化、缓存高频查询工程运维成本10-15%自动化运维、监控告警最大的黑洞是 GPU 推理。一张 A100 每小时成本约 15-20 元云厂商按量计费如果你的服务 24 小时跑着但只有白天有流量那夜间的 GPU 就是纯浪费。3.2 成本优化策略3.3 模型路由简单问题用小模型不是所有问题都需要 14B 模型回答。Redis 怎么重启这种简单问题7B 模型就能搞定没必要走 14B 浪费算力。python #!/usr/bin/env python3 模型路由器 - 根据问题复杂度路由到不同大小的模型 - 简单问题用 7B复杂问题用 14B - 降低平均推理成本 import re from openai import OpenAI # 路由判断模型用小模型做分类成本低 ROUTER_CLIENT OpenAI(base_urlhttp://10.10.100.50:8000/v1, api_keyinternal) # 业务模型池 MODEL_POOL { simple: OpenAI(base_urlhttp://10.10.100.50:8001/v1, api_keyinternal), # 7B complex: OpenAI(base_urlhttp://10.10.100.50:8000/v1, api_keyinternal), # 14B } ROUTER_PROMPT 请判断以下问题的复杂度等级。 复杂度判断标准 - simple: 简单事实查询、单一步骤操作、常见问题如Redis 怎么重启 - complex: 多步骤排查、需要推理分析、跨系统关联如数据库连接池打满同时 Redis 延迟升高怎么排查 问题{question} 只回答 simple 或 complex不要其他内容。 # 高频问题缓存命中缓存不走模型 QUERY_CACHE {} def route_and_answer(question, context): 路由 回答 # 1. 检查缓存 cache_key question.strip().lower() if cache_key in QUERY_CACHE: print(f → 缓存命中) return QUERY_CACHE[cache_key], 0, cache # 2. 路由判断 route_response ROUTER_CLIENT.chat.completions.create( modelqwen2.5-7b-instruct, messages[{role: user, content: ROUTER_PROMPT.format(questionquestion)}], temperature0, max_tokens10, ) complexity route_response.choices[0].message.content.strip().lower() # 3. 路由到对应模型 if simple in complexity: model_key simple model_name qwen2.5-7b-instruct else: model_key complex model_name qwen2.5-14b-instruct print(f → 路由到 {model_name}) # 4. 调用业务模型 messages [ {role: system, content: 你是运维工程师请基于参考信息回答问题。}, {role: user, content: f参考信息{context}\n\n问题{question}}, ] import time start time.time() response MODEL_POOL[model_key].chat.completions.create( modelmodel_name, messagesmessages, temperature0.3, max_tokens2048, ) latency time.time() - start answer response.choices[0].message.content # 5. 缓存高频问题 QUERY_CACHE[cache_key] answer return answer, latency, model_name if __name__ __main__: test_questions [ (Redis 怎么重启, 简单问题 → 应路由到 7B), (数据库连接池打满同时 Redis 延迟升高怎么排查, 复杂问题 → 应路由到 14B), (怎么查看 Nginx 日志, 简单问题 → 应路由到 7B), (K8s 集群中 Pod 反复重启同时服务间调用超时根因可能是什么, 复杂问题 → 应路由到 14B), ] for question, expectation in test_questions: print(f\n问题: {question}) print(f预期: {expectation}) answer, latency, model route_and_answer(question) print(f耗时: {latency:.2f}s | 模型: {model}) print(f回答: {answer[:80]}...) 实际运行下来大约 60% 的问题被路由到了 7B 模型平均推理成本降低了约 40%。缓存命中率在 25% 左右高频问题重复率高进一步降低了成本。四、调优 vs 落地两个阶段的工作对比最后用一张图总结一下模型调优和工程落地这两个阶段的工作重心差异维度调优阶段落地阶段核心目标让模型回答得准让服务跑得稳关键指标准确率、幻觉率、检索命中率P95 延迟、可用性、成本/请求主要工作检索优化、prompt 调优、微调负载均衡、监控告警、降级策略投入产出比前期高每步都有明显提升后期高决定了能不能上线常见坑过早微调、不评估就调忽略并发、无降级策略五、避坑指南血泪经验最后分享几条踩坑总结调优阶段的坑别一上来就微调。先把 prompt 调到极致、把检索优化好这两个做完通常能涨 20-30 分。微调是最后 5 分的事但成本可能是前 25 分的总和。评估集比模型重要。没有 50 条以上的人工标注评估集你根本不知道调优有没有效果。感觉变好了不算数。Rerank 是性价比最高的优化。加一个 reranker 模型命中率涨 10-15 个百分点成本只增加几毫秒延迟。投入产出比极高。落地阶段的坑并发是你第一个会遇到的问题。Demo 的时候永远不会碰到上线第一天一定碰到。提前做好请求队列、超时控制、降级策略。监控不是可选项。没有监控的 AI 服务就像没有仪表盘的汽车——你以为在 60 码跑其实已经 120 了。至少监控请求量、延迟分布、成功率、GPU 利用率。降级策略保命。模型挂了不能让整个系统挂。缓存兜底、友好提示、人工转接总比白屏强。成本要天天看。AI 服务很容易出现某个用户疯狂调用或者某个 bug 导致无限重试的成本事故。设置每日成本上限和异常调用告警。模型调优和工程落地是两件事但很多人只做了第一件就觉得完事了。模型 85 分和系统可用之间还隔着负载均衡、监控告警、降级策略、成本控制这一大堆工程活儿。这不是什么高深的技术的都是脏活累活。但正是这些脏活累活决定了你的 AI 项目是能跑的 demo还是能用的产品。别只盯着模型分数看工程基建一样重要。共勉。
返回列表