一、思维转变:最难的不是技术
转型初期,我以为最大的挑战是学新东西。后来才发现,最难的是忘掉旧思维。
1.1 从确定性到概率性
后端工程师的思维是确定性的:
# 后端思维:100% 确定
def get_user(user_id: int) -> User:
user = db.query(User).filter(id == user_id).first()
if user is None:
raise UserNotFoundError()
return user同样的逻辑,在 AI 世界里是完全不同的:
# AI 思维:概率性结果
def classify_intent(user_message: str) -> str:
response = llm.chat([
{"role": "user", "content": f"分类: {user_message}"}
])
# 同样的输入,可能每次输出不同
# "今天天气怎么样" 可能被分类为:
# - weather (80%)
# - general (15%)
# - schedule (5%)
return parse_intent(response)我的踩坑经历:曾经用传统单元测试的方式测试 Prompt,结果发现同一个测试用例跑 10 次有 3 次失败。一开始以为是 Prompt 问题,花了一周优化 Prompt,后来才发现这在 AI 系统里是正常现象。
正确的做法:
# 测试 AI 输出的分布,而不是单个结果
def test_intent_classification():
"""测试意图分类的稳定性"""
test_cases = [
"今天天气怎么样",
"帮我订一个明天上午的会议",
"查一下我的订单"
]
results = defaultdict(list)
# 每个用例跑 20 次
for _ in range(20):
for case in test_cases:
intent = classify_intent(case)
results[case].append(intent)
# 检查主意图的一致性
for case, intents in results.items():
primary_intent = max(set(intents), key=intents.count)
consistency = intents.count(primary_intent) / len(intents)
# 一致性应该 > 90%,否则需要优化 Prompt
assert consistency > 0.9, f"{case}: 一致性 {consistency} 过低"1.2 从规则驱动到数据驱动
后端系统的逻辑是规则写死的:
# 规则驱动:if-else 逻辑清晰
def calculate_discount(user: User, order: Order) -> float:
if user.is_vip:
if order.amount > 1000:
return 0.2 # VIP + 大额 = 8折
else:
return 0.1 # VIP + 小额 = 9折
else:
if order.amount > 2000:
return 0.05 # 普通 + 大额 = 95折
else:
return 0.0 # 普通 + 小额 = 不打折AI 系统是数据驱动的,规则隐藏在模型参数里:
# 数据驱动:规则从数据中学习
class DiscountAgent:
"""折扣决策 Agent(不是写死的 if-else)"""
def __init__(self, model, discount_history: List[DiscountCase]):
# 通过示例学习折扣策略
self.examples = discount_history
def decide(self, user: User, order: Order) -> DiscountAgentOutput:
prompt = f"""作为折扣决策专家,根据历史案例决定折扣力度。
历史案例:
{self._format_examples()}
当前用户:
- 会员等级: {user.level}
- 购买历史: {len(user.orders)} 单
- 投诉记录: {user.complaint_count} 次
当前订单:
- 金额: {order.amount}
- 商品类别: {order.category}
- 是否促销: {order.is_promotion}
请给出折扣建议,格式:
折扣比例: XX%
理由: XXX
"""
return self.model.generate(prompt)我的踩坑经历:刚开始做 AI 应用时,我本能地想用规则"兜底"——模型输出不可靠,那就加 if-else。结果代码越写越像传统的业务逻辑,AI 变成了"花式 if-else"的装饰器。
正确的做法:承认 AI 的不确定性,用工程手段处理(重试、ensemble、降级),而不是用规则覆盖。
二、技术栈扩展:需要补的课
从后端到 AI 工程师,技术栈扩展比我想象的大得多:
2.1 向量数据库:新的数据存储
向量数据库是 AI 时代的"新数据库",我一开始完全不理解它的价值。
我的踩坑:试图用 MySQL 的全文搜索替代向量检索,结果检索质量差到无法接受。
# ❌ 错误:用 MySQL 全文搜索做语义检索
def search_products_mysql(query: str) -> List[Product]:
# 这种方式只能匹配关键词,无法理解语义
# "想找一台跑机器学习快的电脑" 可能搜不到任何结果
# 因为数据库里没有"机器学习"这个关键词
products = db.query(Product).filter(
Product.name.match(query) |
Product.description.match(query)
).all()
return products
# ✅ 正确:用向量数据库做语义检索
def search_products_vector(query: str) -> List[Product]:
# 1. 把查询转成向量
query_embedding = embedding_model.encode(query)
# 2. 在向量数据库中检索
results = vector_db.search(
collection="products",
query_vector=query_embedding,
top_k=10
)
# 3. 返回相关产品
return [Product.from_vector_result(r) for r in results]2.2 GPU 编程:从零开始
作为后端工程师,我对 GPU 的了解仅限于"玩游戏用的显卡"。转型 AI 后发现,GPU 是 AI 的基础设施。
我的踩坑:第一次部署 vLLM 时,不知道需要 GPU,直接在普通服务器上跑,结果 CPU 推理慢到无法忍受。
# 检查服务器是否有 GPU
nvidia-smi
# 如果没有 GPU,需要使用云服务或更换服务器
# AWS: p3.2xlarge (Tesla V100)
# GCP: a2-highgpu-1g (A100)
# 阿里云: gn6v (V100)2.3 Prompt 工程:新的编程范式
Prompt 工程是 AI 工程师的"新语言",但它跟传统编程完全不同:
# 传统编程:精确的指令
def add(a: int, b: int) -> int:
return a + b
# Prompt 工程:模糊的指导
def classify_with_prompt(text: str) -> str:
prompt = """
请根据用户输入判断意图。
# 注意
- 这只是一个指导,不是硬性规则
- 需要结合上下文理解
- 如果不确定,请返回 "unknown"
"""
# Prompt 的输出取决于模型理解,而不是代码逻辑三、踩坑实录:五个刻骨铭心的教训
踩坑一:用传统 API 思维设计 LLM 接口
问题描述:我把 LLM 当成了普通的 REST API,用传统的接口设计思维来设计 AI 能力。
我的做法:
# 传统 API 思维
class LLMService:
def chat(self, user_input: str) -> str:
"""同步调用,直接返回结果"""
response = openai.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": user_input}]
)
return response.choices[0].message.content
def batch_process(self, inputs: List[str]) -> List[str]:
"""批量处理"""
results = []
for inp in inputs:
# 串行调用,完全忽略 LLM 的特殊性
results.append(self.chat(inp))
return results问题:
超时问题:LLM 响应时间不确定,可能 1 秒也可能 60 秒
成本问题:没有预算控制,大流量直接破产
稳定性问题:API 有失败率,没有降级策略
一致性:同样的输入可能返回不同结果
正确的做法:
# AI-native 接口设计
class LLMService:
def __init__(self, config: LLMConfig):
self.config = config
self.cache = SemanticCache(...) # 语义缓存
self.budget_tracker = BudgetTracker(...)
self.circuit_breaker = CircuitBreaker(...)
async def chat(
self,
user_input: str,
context: Dict = None,
timeout: float = 30.0
) -> LLMResponse:
"""异步调用,带完整错误处理"""
# 1. 检查缓存(70% 请求可以命中)
cached = await self.cache.get(user_input)
if cached:
return LLMResponse(content=cached, source="cache")
# 2. 检查预算
if not self.budget_tracker.check():
return LLMResponse(
content="服务暂时不可用,请稍后重试",
source="budget_limit"
)
# 3. 带超时和重试的调用
try:
response = await asyncio.wait_for(
self._call_llm(user_input, context),
timeout=timeout
)
except asyncio.TimeoutError:
# 超时降级
return self._degrade_response(user_input)
except Exception as e:
# 熔断保护
if self.circuit_breaker.is_open():
return self._fallback_response()
raise
# 4. 更新缓存和预算
await self.cache.set(user_input, response.content)
self.budget_tracker.record(response.usage)
return response
async def batch_chat(
self,
inputs: List[str],
max_concurrency: int = 5
) -> List[LLMResponse]:
"""带并发控制的批量处理"""
semaphore = asyncio.Semaphore(max_concurrency)
async def bounded_call(inp: str) -> LLMResponse:
async with semaphore:
return await self.chat(inp)
# 并发执行,充分利用 API 能力
return await asyncio.gather(*[bounded_call(i) for i in inputs])踩坑二:忽略成本管理
问题描述:作为后端工程师,我对"API 调用成本"完全没有概念。
我的教训:一个周末的自动化测试,烧掉了 2000 美元的 API 费用。
# ❌ 危险的做法:无限调用
def process_all_feedback():
"""处理所有用户反馈"""
feedbacks = get_all_feedbacks() # 假设有 100 万条
results = []
for fb in feedbacks:
# 每条反馈都调用 LLM
# 100万条 × $0.01 = $10,000
result = llm.analyze(fb.content)
results.append(result)
return results
# ✅ 安全的做法:批量 + 预算控制
def process_all_feedback_safe():
"""带预算控制的批处理"""
feedbacks = get_all_feedbacks()
# 分批处理
BATCH_SIZE = 100
DAILY_BUDGET = 100 # 每天最多 $100
total_cost = 0
results = []
for i in range(0, len(feedbacks), BATCH_SIZE):
batch = feedbacks[i:i + BATCH_SIZE]
# 检查预算
batch_cost = estimate_cost(batch)
if total_cost + batch_cost > DAILY_BUDGET:
print(f"预算已达上限,停止处理")
break
# 批量处理(减少 API 调用次数)
batch_result = await llm.batch_analyze(batch)
results.extend(batch_result)
total_cost += batch_result.cost
return results
def estimate_cost(batch: List[Feedback]) -> float:
"""估算成本"""
# 假设平均每个反馈 500 tokens
avg_tokens = 500
input_price = 0.001 # $0.001 / 1K tokens
output_price = 0.003 # $0.003 / 1K tokens
total_input = len(batch) * avg_tokens
total_output = len(batch) * avg_tokens * 0.5 # 输出通常是输入的一半
return (total_input * input_price + total_output * output_price) / 1000成本监控配置:
# config/cost_control.yaml
cost_control:
daily_budget: 100.0 # 每日预算 $100
monthly_budget: 2000.0 # 每月预算 $2000
alert_threshold: 0.8 # 80% 时报警
emergency_stop: 0.95 # 95% 时自动停止
rate_limits:
per_minute: 60 # 每分钟最多 60 次调用
per_hour: 1000 # 每小时最多 1000 次
per_day: 10000 # 每天最多 10000 次
cache:
enabled: true
hit_target: 0.5 # 目标缓存命中率 50%
model_routing:
# 根据任务复杂度选择模型
simple:
- qwen2.5-3b # 简单任务用小模型
complex:
- gpt-4o # 复杂任务用大模型踩坑三:不做评测就上线
问题描述:Prompt 调好了,测试了几个 case 感觉不错,直接上线。结果用户一用,问题百出。
我的教训:用户说 AI "答非所问",我看了日志才发现 AI 把负面反馈识别成了正面。
# ❌ 错误:拍脑袋测试
def test_sentiment():
test_cases = [
"这个产品太棒了", # 正面
"质量太差了", # 负面
]
for case in test_cases:
result = sentiment_analysis(case)
print(f"{case} -> {result}")
# 只测试了 2 个 case,就觉得没问题了
# 实际上漏掉了大量边界情况
# ✅ 正确:系统性评测
class SentimentEvaluator:
"""情感分析评测器"""
def __init__(self):
self.test_suite = self._build_test_suite()
def _build_test_suite(self) -> List[TestCase]:
"""构建测试套件"""
return [
# 明确情感
TestCase("这个产品太棒了", "positive", "明确正面"),
TestCase("质量太差了", "negative", "明确负面"),
TestCase("一般般吧", "neutral", "中性"),
# 讽刺
TestCase("哇,你可真是个好产品啊", "negative", "讽刺"),
TestCase("太棒了,又坏了", "negative", "讽刺"),
# 双重否定
TestCase("不是不好", "positive", "双重否定"),
TestCase("我觉得不差", "positive", "双重否定"),
# 混合情感
TestCase("质量很好但是价格太贵", "mixed", "混合"),
# 边界
TestCase("", "unknown", "空输入"),
TestCase("哈哈哈哈", "positive", "无情感词"),
TestCase("F**k", "negative", "纯脏话"),
# 领域特定
TestCase("等了3天还没到", "negative", "物流投诉"),
TestCase("客服态度恶劣", "negative", "服务投诉"),
]
def evaluate(self, model) -> EvaluationResult:
"""全面评测"""
results = []
for case in self.test_suite:
predicted = model.predict(case.input)
is_correct = predicted == case.expected
results.append({
"input": case.input,
"expected": case.expected,
"predicted": predicted,
"correct": is_correct,
"category": case.category
})
# 分维度统计
by_category = defaultdict(lambda: {"correct": 0, "total": 0})
for r in results:
by_category[r["category"]]["total"] += 1
if r["correct"]:
by_category[r["category"]]["correct"] += 1
category_accuracy = {
cat: data["correct"] / data["total"]
for cat, data in by_category.items()
}
overall = sum(r["correct"] for r in results) / len(results)
return EvaluationResult(
overall_accuracy=overall,
category_accuracy=category_accuracy,
failed_cases=[r for r in results if not r["correct"]],
recommendation=self._get_recommendation(overall, category_accuracy)
)
def _get_recommendation(self, overall, category_accuracy) -> str:
if overall < 0.9:
return "❌ 不建议上线,需要优化"
if category_accuracy.get("讽刺", 0) < 0.8:
return "⚠️ 上线后需重点监控讽刺检测"
return "✅ 可以上线,建议持续监控"踩坑四:Prompt 管理混乱
问题描述:Prompt 散落在代码各处,改一个 Prompt 要找半天,还容易改出问题。
我的教训:改了一个"通用" Prompt,结果影响了 5 个不同功能的输出格式。
# ❌ 混乱的 Prompt 管理
class ChatBot:
def __init__(self):
# Prompt 散落在代码里
pass
def handle_intent_classification(self, text):
prompt = """请分类用户意图:...""" # 这里一个 Prompt
return self.llm.chat(prompt)
def handle_sentiment(self, text):
prompt = """请分析情感:...""" # 另一个 Prompt
return self.llm.chat(prompt)
def handle_entity_extraction(self, text):
prompt = """请提取实体:...""" # 又一个 Prompt
return self.llm.chat(prompt)
# ✅ 集中的 Prompt 管理
# config/prompts.yaml
prompts:
intent_classification:
template: |
分析用户消息的意图,可选类别:
- search: 需要搜索
- order: 需要下单
- query: 需要查询
- complaint: 投诉
- general: 一般对话
用户消息: {input}
只返回一个词。
config:
model: gpt-4o-mini
temperature: 0
max_tokens: 50
examples:
- input: "帮我查一下订单"
output: "query"
- input: "太差了,垃圾产品"
output: "complaint"
sentiment_analysis:
template: |
分析用户反馈的情感倾向:
- positive: 正面
- negative: 负面
- neutral: 中性
用户反馈: {input}
config:
model: gpt-4o-mini
temperature: 0# prompts/manager.py
"""Prompt 管理器"""
from pathlib import Path
import yaml
from typing import Dict, Optional
from dataclasses import dataclass
import hashlib
@dataclass
class PromptConfig:
"""Prompt 配置"""
template: str
config: Dict
examples: list = None
version: str = "1.0.0"
class PromptManager:
"""Prompt 管理器"""
def __init__(self, config_path: str):
self.config_path = Path(config_path)
self.prompts: Dict[str, PromptConfig] = {}
self._load()
# Prompt 版本控制
self.version_history: Dict[str, list] = {}
def _load(self):
"""加载 Prompt 配置"""
with open(self.config_path) as f:
data = yaml.safe_load(f)
for name, config in data.get("prompts", {}).items():
self.prompts[name] = PromptConfig(
template=config["template"],
config=config.get("config", {}),
examples=config.get("examples"),
version=config.get("version", "1.0.0")
)
def render(self, name: str, **kwargs) -> tuple[str, Dict]:
"""渲染 Prompt"""
if name not in self.prompts:
raise ValueError(f"Prompt not found: {name}")
prompt = self.prompts[name]
# 填充变量
rendered = prompt.template.format(**kwargs)
# 添加 few-shot examples
if prompt.examples:
examples_text = "\n".join(
f"示例: {e['input']} -> {e['output']}"
for e in prompt.examples
)
rendered = f"{examples_text}\n\n{rendered}"
return rendered, prompt.config
def update(self, name: str, new_template: str, version: str = None):
"""更新 Prompt(带版本记录)"""
if name not in self.prompts:
raise ValueError(f"Prompt not found: {name}")
old_prompt = self.prompts[name]
# 记录历史
if name not in self.version_history:
self.version_history[name] = []
self.version_history[name].append({
"version": old_prompt.version,
"template": old_prompt.template,
"hash": hashlib.md5(old_prompt.template.encode()).hexdigest()
})
# 更新
self.prompts[name] = PromptConfig(
template=new_template,
config=old_prompt.config,
examples=old_prompt.examples,
version=version or self._increment_version(old_prompt.version)
)
# 保存
self._save()
def _increment_version(self, version: str) -> str:
"""版本号递增"""
parts = version.split(".")
parts[-1] = str(int(parts[-1]) + 1)
return ".".join(parts)
def _save(self):
"""保存配置"""
data = {
"prompts": {
name: {
"template": p.template,
"config": p.config,
"examples": p.examples,
"version": p.version
}
for name, p in self.prompts.items()
}
}
with open(self.config_path, "w") as f:
yaml.dump(data, f, allow_unicode=True)踩坑五:忽视可观测性
问题描述:AI 系统上线后,用户说"不好用",但我看日志完全不知道哪里出了问题。
我的教训:一个复杂的 Agent 工作流,某一步出错了,但日志里只有最终结果,没有中间过程。
# ❌ 缺少可观测性
class Agent:
def run(self, user_input: str):
# 黑盒执行,出问题完全不知道哪一步出错
intent = self.classify_intent(user_input)
entities = self.extract_entities(user_input)
response = self.generate(intent, entities)
return response
# ✅ 完整可观测性
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
class ObservableAgent:
"""可观测的 Agent"""
def __init__(self):
# 设置 tracing
self.tracer = trace.get_tracer(__name__)
# 记录每个步骤的输入输出
self.step_logs: List[StepLog] = []
def run(self, user_input: str):
with self.tracer.start_as_current_span("agent_run") as span:
# 添加上下文
span.set_attribute("user_input.length", len(user_input))
span.set_attribute("user_input.preview", user_input[:100])
try:
# 步骤 1:意图分类
with self.tracer.start_as_current_span("intent_classification"):
span = trace.get_current_span()
span.set_attribute("step", "intent_classification")
intent = self.classify_intent(user_input)
span.set_attribute("intent.result", intent)
span.set_attribute("intent.confidence", intent.get("confidence", 0))
self.step_logs.append(StepLog(
step="intent_classification",
input=user_input,
output=intent,
duration_ms=0, # 计算实际耗时
status="success"
))
# 步骤 2:实体提取
with self.tracer.start_as_current_span("entity_extraction"):
span = trace.get_current_span()
span.set_attribute("step", "entity_extraction")
entities = self.extract_entities(user_input)
span.set_attribute("entities.count", len(entities))
span.set_attribute("entities.types", list(entities.keys()))
self.step_logs.append(StepLog(
step="entity_extraction",
input=user_input,
output=entities,
duration_ms=0,
status="success"
))
# 步骤 3:响应生成
with self.tracer.start_as_current_span("response_generation"):
span = trace.get_current_span()
span.set_attribute("step", "response_generation")
response = self.generate(intent, entities)
span.set_attribute("response.length", len(response))
span.set_attribute("response.tokens_used", response.usage.total_tokens)
self.step_logs.append(StepLog(
step="response_generation",
input={"intent": intent, "entities": entities},
output=response.content,
duration_ms=0,
status="success"
))
span.set_attribute("result.success", True)
return response
except Exception as e:
span.set_attribute("result.success", False)
span.set_attribute("error.type", type(e).__name__)
span.set_attribute("error.message", str(e))
self.step_logs.append(StepLog(
step="unknown",
input=user_input,
output=None,
duration_ms=0,
status="failed",
error=str(e)
))
raise# config/observability.yaml
observability:
tracing:
enabled: true
exporter: jaeger # jaeger / zipkin / otlp
sampling_rate: 1.0 # 全量采样(调试时)
# sampling_rate: 0.1 # 采样 10%(生产时)
metrics:
enabled: true
interval_seconds: 10
custom_metrics:
- name: llm_request_duration
type: histogram
buckets: [0.1, 0.5, 1, 2, 5, 10, 30]
- name: llm_token_usage
type: counter
labels: [model, type]
- name: llm_cache_hit_rate
type: gauge
- name: agent_step_duration
type: histogram
labels: [step_name]
logging:
enabled: true
level: INFO
structured: true # JSON 格式日志
masks: # 敏感字段脱敏
- user_id
- phone
- email
- token四、转型路线图
基于我的踩坑经历,总结一条相对平稳的转型路线:
┌─────────────────────────────────────────────────────────────────┐
│ AI 工程师转型路线图 │
│ │
│ 第一阶段:LLM Ops (1-2个月) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • Prompt 工程基础 │ │
│ │ • API 调用(OpenAI、Claude、本地模型) │ │
│ │ • 基本可观测性(日志、metrics) │ │
│ │ • 语义缓存 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ │
│ 第二阶段:AI Infra (2-3个月) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • vLLM / Ollama 部署 │ │
│ │ • 向量数据库(Milvus / Qdrant) │ │
│ │ • 模型选型与评测 │ │
│ │ • GPU 基础 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ │
│ 第三阶段:Agent 工程化 (2-3个月) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • LangGraph / Agent 框架 │ │
│ │ • RAG 工程化 │ │
│ │ • 工具调用设计 │ │
│ │ • 复杂工作流编排 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ ↓ │
│ 第四阶段:高级能力 (持续学习) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ • 模型微调(LoRA / QLoRA) │ │
│ │ • Agent 内存管理 │ │
│ │ • 多模态应用 │ │
│ │ • AI 安全与合规 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘4.1 每日学习计划
4.2 关键里程碑
第一个可用的 AI 应用(第 1 周):一个简单的 Chatbot
第一个 RAG 应用(第 2 周):文档问答系统
第一个 Agent 应用(第 1 个月):带工具调用的 Agent
第一个生产项目(第 3 个月):完整上线一个 AI 功能
第一个生产系统(第 6 个月):多个 AI 功能的统一平台
五、给后来者的建议
5.1 技术层面
不要忽视基础:Python、API 设计、数据库这些基础能力依然重要
动手最重要:看 10 篇教程不如做 1 个小项目
保持谦逊:AI 发展太快,今天的正确可能明天就过时
关注工程化:模型能力固然重要,但工程能力决定你能不能把它用好
5.2 心态层面
接受不确定性:AI 系统的输出本身就是不确定的,要学会与之共处
拥抱变化:AI 领域的工具和最佳实践还在快速迭代
保持耐心:转型需要时间,不要期望一周就能成为专家
记录成长:写博客、记笔记,这是你回顾和分享的基础
5.3 职业层面
找到自己的定位:不是每个人都要成为 Prompt 工程专家或 AI Infra 专家
与业务结合:纯技术很难体现价值,要找到 AI 与业务的结合点
建立影响力:分享你的经验,这会加速你的成长
持续学习:AI 领域的学习永远不会停止
总结
从后端工程师到 AI 工程师,这一年我踩的坑比过去五年后端生涯加起来都多。但我从不后悔这个选择。
最大的收获:
思维升级:从确定性思维到概率性思维,从规则驱动到数据驱动
技术广度:向量数据库、GPU 编程、Prompt 工程... 技术栈大幅扩展
影响力提升:从"写接口的"到"做 AI 系统的",价值定位完全不同
最痛的教训:
AI 系统不是传统系统的简单升级,需要全新的工程思维
成本控制和可观测性比技术本身更重要
没有评测就没有优化,没有优化就没有改进
如果你也在考虑转型,希望我的经历能给你一些参考。AI 工程化是一条充满挑战但也充满机遇的路,走下去,你会发现一个全新的世界。
相关阅读:
第32篇:AI 工程化的三层架构:模型层 / 平台层 / 应用层
第31篇:vLLM 0.20.0 生产部署实战
第34篇:2026 年 AI 工程化:我们到了哪里,还要走多远
评论区