开篇:如果手里只有锤子,一切看起来都像钉子

这句话在软件工程领域流传了几十年。2025-2026 年的版本变成了:

"如果你的工具链里有 LLM API,一切看起来都该用 AI 解决。"

我看到太多这样的例子:
- 一个简单的字符串匹配任务 → 用了 GPT-4,响应 3 秒,成本 $0.05/次。实际上用正则表达式只要 2ms,零成本
- 一个"如果 A 则 B"的业务规则 → 用了 LLM 做决策。实际上一个 if-else 更可靠
- 一个关键词提取功能 → 用了 Claude API。实际上 TF-IDF 就够用了

这让我想到一个在安全领域已经存在多年的原则:最小权限原则(Principle of Least Privilege)——每个程序只应该拥有完成其任务所必需的最小权限。

同样的逻辑可以应用到 AI 使用上:最小 AI 原则(Principle of Least AI)——每个问题只应该使用解决它所需的最小 AI 能力。

这不是"反 AI"的文章——恰恰相反,我相信 AI 是过去 20 年最重要的技术之一。但正因为重要,才需要更谨慎地使用。


一、什么是"最小 AI 原则"

最小 AI 原则(Principle of Least AI)的核心思想:

面对一个问题时,先用最简单的非 AI 方案。只有当简单方案无法满足需求时,才引入 AI。而当引入 AI 时,选择能满足需求的最低能力层级的模型。

这个概念可以用一个决策树来表达:

问题来了
    ↓
能不用 AI 解决吗?
├── 能 → 用最简单的方式(正则、规则引擎、简单算法)
└── 不能 →
    ├── 轻量 ML 能解决吗?(分类器、TF-IDF、相似度)
    │   ├── 能 → 用小模型 + 嵌入式推理
    │   └── 不能 →
    │       ├── 小型 LLM 能解决吗?(7B-13B 参数)
    │       │   ├── 能 → 用开源小模型
    │       │   └── 不能 →
    │       │       ├── 中型模型能解决吗?(70B 级别)
    │       │       │   ├── 能 → 用中等模型
    │       │       │   └── 不能 →
    │       │       │           └── 用最大型号的模型
    │       │       └── (但这种情况很少见)
    │       └── (这种情况也比很多人想的多)
    └── (比很多人想的少)

这个决策树的核心是:每次引入 AI 都是有一个成本——金钱成本、延迟成本、不可预测性成本。 使用最小 AI 就是在选择一个你愿意为此付出的最小代价。


二、为什么需要这个原则

2.1 成本三角

每个技术方案都有一个"成本三角":

            准确性
              ▲
              │
  速度 ◄──────┼──────► 可预测性
              │
              │
             成本

不同方案在三角上的位置:

方案 准确性 速度 可预测性 成本/次
正则表达式 高(匹配特定模式) <1ms 确定性的 $0.000001
规则引擎 高(已知规则) <5ms 确定性的 $0.000005
小模型(轻量 ML) 中-高 5-50ms 统计性的 $0.0001
小型 LLM(7B-13B) 高(通用) 100-1000ms 概率性的 $0.001-0.005
大型 LLM(70B+) 最高 1-5s 概率性的 $0.01-0.05

正则表达式的准确率和成本远超 LLM——在它适用的场景下。

这不是贬低 LLM。只是说:用高射炮打蚊子不是好策略。 当你面对一个问题时,先问问自己:这个问题的复杂度是否真的需要 LLM 级别的处理能力?

2.2 可预测性成本

一个常被忽视的成本是不可预测性

# 正则表达式版本:确定性的
def extract_email(text: str) -> str:
    import re
    pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
    match = re.search(pattern, text)
    # 永远返回相同的结果,不需要测试覆盖率之外的测试
    return match.group(0) if match else None

# LLM 版本:概率性的
def extract_email_llm(text: str) -> str:
    response = llm.invoke(f"从以下文本中提取邮箱地址:{text}")
    # 每次返回的结果可能不同
    # 需要测试:边界情况、注入攻击、多语言支持
    # 需要监控:响应质量、延迟波动
    # 需要回退:当 LLM 不可用时
    return response.content

正则表达式版本:一行代码,永远返回相同结果。不需要测试 prompt、不需要回退机制、不需要监控输出质量。

LLM 版本:每次调用都可能不同。需要用更复杂的测试、更多的监控、和更多的回退逻辑来处理它的不可预测性。

这个"额外成本"在预估阶段经常被忽略。


三、具体实践

3.1 分类任务:从 LLM 降到规则

# 场景:判断用户消息是不是投诉

# ❌ 过度 AI:
def is_complaint_llm(message: str) -> bool:
    """用 LLM 判断是否为投诉"""
    prompt = f"判断以下用户消息是否为投诉(是/否):{message}"
    response = llm.invoke(prompt)
    return "是" in response.content
    # 成本:~$0.02/次
    # 延迟:~1.5s
    # 可靠度:~95%(还会因为 prompt 微调而波动)

# ✅ 最小 AI:
def is_complaint_keyword(message: str) -> bool:
    """用关键词规则判断是否为投诉"""
    COMPLAINT_KEYWORDS = [
        "投诉", "差评", "退款", "赔偿",
        "太差了", "无法接受", "强烈不满",
        "complaint", "refund", "terrible",
    ]
    message_lower = message.lower()
    return any(kw in message_lower for kw in COMPLAINT_KEYWORDS)
    # 成本:几乎为零
    # 延迟:<1ms
    # 可靠度:对于已知模式 ~100%
    # 可以独立测试,不依赖外部 API

# 折中方案:先快速通道,再 LLM 兜底
def is_complaint_hybrid(message: str) -> tuple[bool, str]:
    """
    混合方案:
    1. 关键词快速通道(覆盖 ~70% 的投诉)
    2. 未命中关键词的再用 LLM 判断
    """
    # 快速通道
    if is_complaint_keyword(message):
        return True, "keyword_match"

    # 如果业务要求高覆盖,再引入 LLM
    # 但这里只对"疑似投诉"做 LLM 判断
    # 而不是所有消息
    SUSPICIOUS_PATTERNS = ["退", "赔", "差", "慢", "错"]
    if any(p in message for p in SUSPICIOUS_PATTERNS):
        result = llm.invoke(f"判断是否为投诉(只回答是/否):{message}")
        return "是" in result.content, "llm_fallback"

    return False, "no_match"

3.2 文档分类:从 LLM 降到小模型

# 场景:对用户反馈进行主题分类(5 个类别)

# ❌ 过度 AI:
def classify_with_llm(text: str) -> str:
    """用 LLM 做 5 分类"""
    categories = ["性能", "功能", "界面", "价格", "其他"]
    prompt = f"将以下用户反馈分类到:{', '.join(categories)}\n反馈: {text}\n类别:"
    response = llm.invoke(prompt)
    return response.content.strip()
    # 成本:~$0.01/次
    # 处理 10000 条/天 = $100/天

# ✅ 最小 AI:
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
import joblib

class TextClassifier:
    """
    轻量级文本分类器
    用于替代 LLM 的多分类任务
    """

    def __init__(self):
        self.vectorizer = TfidfVectorizer(max_features=5000)
        self.classifier = MultinomialNB()
        self.is_trained = False

    def train(self, texts: list[str], labels: list[str]):
        """用带标注的数据训练"""
        X = self.vectorizer.fit_transform(texts)
        self.classifier.fit(X, labels)
        self.is_trained = True

    def predict(self, text: str) -> str:
        """预测分类"""
        if not self.is_trained:
            return "模型未训练"

        X = self.vectorizer.transform([text])
        return self.classifier.predict(X)[0]

    def predict_with_confidence(self, text: str) -> tuple[str, float]:
        """预测分类并返回置信度"""
        if not self.is_trained:
            return "模型未训练", 0.0

        X = self.vectorizer.transform([text])
        probs = self.classifier.predict_proba(X)[0]
        max_prob = max(probs)
        prediction = self.classifier.predict(X)[0]
        return prediction, max_prob


# 使用方式
classifier = TextClassifier()

# 用 1000 条历史标注数据训练
classifier.train(
    texts=["页面加载太慢了", "功能很好用", "按钮太小"],
    labels=["性能", "功能", "界面"]
)

# 预测
category, confidence = classifier.predict_with_confidence("网站打不开")
if confidence > 0.7:
    print(f"分类: {category} (置信度: {confidence:.2%})")
else:
    # 低置信度时再用 LLM
    print(f"低置信度 ({confidence:.2%}),改用 LLM 兜底")
    category = classify_with_llm("网站打不开")

训练好之后,这个分类器的推理成本趋近于零,而且可以在本地运行,不依赖外部 API。

3.3 代码审查:从 LLM 降到 lint

# 场景:检测代码中的常见问题

# ❌ 用 LLM 做代码审查
def review_code_llm(code: str) -> list[str]:
    """让 AI 审查代码"""
    response = llm.invoke(f"请检查以下代码的问题:{code}")
    return parse_issues(response.content)
    # 延迟:3-5 秒
    # 成本:$0.05-0.10/次
    # 不稳定:每次可能发现不同的问题

# ✅ 先用 lint 覆盖基础问题
def review_code_lint(code: str) -> list[str]:
    """先用静态分析工具覆盖基础问题"""
    import subprocess
    result = subprocess.run(
        ["pylint", "--from-stdin", "temp.py"],
        input=code,
        capture_output=True,
        text=True,
    )
    issues = parse_pylint_output(result.stdout)

    # 只有 lint 无法覆盖的才用 AI
    if has_complex_logic(code):
        ai_issues = review_code_llm(code)
        issues.extend(ai_issues)

    return issues

先 lint,再 LLM。Lint 能在毫秒级别覆盖 80% 常见问题。只在需要分析复杂业务逻辑时才引入 LLM。


四、一个真实的优化案例

4.1 优化前后对比

某电商平台的内容审核系统:

优化前(全部消息走 LLM 审核):
- 日均处理量:500,000 条
- LLM 成本:$0.03/次 × 500,000 = $15,000/天
- 平均延迟:2.3 秒
- 准确率:94%

优化后(三级审核体系):
- 第一级(关键词过滤):60% 的消息直接通过或拒绝,零成本
- 第二级(小模型分类):30% 的消息用小模型处理
- 第三级(LLM):只剩 10% 的模糊消息走 LLM
- 总成本:$1,500/天(降低了 90%)
- 平均延迟:0.3 秒
- 准确率:维持 94%(没有下降)
class TieredContentModeration:
    """
    三级内容审核体系

    实现最小 AI 原则:
    - 第一级:规则引擎(零 AI)
    - 第二级:小模型分类(轻量 ML)
    - 第三级:LLM(最低优先级)
    """

    def __init__(self, llm_model):
        self.llm = llm_model
        self.keyword_filter = KeywordFilter()     # 规则引擎
        self.classifier = FastTextClassifier()     # 小模型
        self.stats = {"tier1": 0, "tier2": 0, "tier3": 0}

    def moderate(self, content: str) -> tuple[str, float]:
        """
        三级审核

        返回:
        - decision: "allow" | "reject" | "review"
        - confidence: 0-1
        """

        # 第一级:关键词快速通道(零 AI,<1ms)
        keyword_result = self.keyword_filter.check(content)
        if keyword_result["certain"]:
            self.stats["tier1"] += 1
            return keyword_result["decision"], 1.0

        # 第二级:小模型分类(轻量 ML,5ms)
        prediction, confidence = self.classifier.predict_with_confidence(content)
        if confidence > 0.9:
            self.stats["tier2"] += 1
            return prediction, confidence

        # 第三级:LLM 兜底(高成本,2-3s)
        self.stats["tier3"] += 1
        result = self.llm.moderate(content)
        return result["decision"], result["confidence"]

五、什么时候应该用 AI

最小 AI 原则不是说"不要用 AI"。是说"在你需要的时候用,不需要的时候别用"。

5.1 适合 AI 的场景

✅ 真正适合用 AI 的场景:
- 自然语言理解(意图识别、情感分析)
- 内容生成(草稿、摘要、翻译)
- 模糊匹配(拼写纠正、语义搜索)
- 复杂决策辅助(需要综合大量上下文判断)
- 异常情况处理(规则引擎覆盖不到的场景)

❌ 不适合 AI 的场景:
- 确定性操作("如果 A 则 B"的逻辑)
- 精确匹配(邮箱格式验证、手机号校验)
- 高频低价值操作(每一次用户点击都调用一次 LLM)
- 可预测的数据处理(排序、过滤、聚合)

5.2 选择模型的决策框架

当你确定需要 AI 时,选择最小的合适模型:

def select_model(task_description: str, 
                 requirements: dict) -> str:
    """
    根据任务需求选择最小合适的模型

    参数:
        task_description: 任务描述
        requirements: {
            "max_latency_ms": int,   # 最大可接受延迟(毫秒)
            "max_cost_per_call": float,  # 单次调用最大成本
            "need_reasoning": bool,   # 是否需要推理能力
            "need_long_context": bool, # 是否需要长上下文
            "accuracy_minimum": float, # 最低准确率要求
        }
    """

    # 第一问:需要 LLM 吗?
    if not requirements.get("need_reasoning"):
        return "no_llm_needed"

    # 第二问:小模型是否够用?
    if requirements.get("accuracy_minimum", 0.9) <= 0.85:
        # 如果准确率要求不高
        return "7b_model"

    # 第三问:延迟和成本约束
    max_latency = requirements.get("max_latency_ms", 1000)
    if max_latency < 200:  # 200ms 以内
        return "7b_model_quantized"  # 量化的小模型,最快
    elif max_latency < 500:
        return "13b_model"
    else:
        # 延迟要求宽松
        if requirements.get("need_long_context"):
            return "large_model_with_long_context"
        return "70b_model"

    # 默认回退
    return "medium_model"

六、我的观点:AI 应该是一种能力,不是一种默认

写这篇文章的目的不是批评"多用 AI"——我自己每天都在用 AI 写代码、调试、写作。

但我担心一件事:当 AI 成为所有问题的默认方案时,解决问题的能力反而会下降。

原因很简单:如果你每次遇到问题都习惯性地问 AI,你慢慢就会失去"自己先试试"的习惯。而"自己先试试"恰恰是培养解决问题能力的方式。

最小 AI 原则不是在技术上限制你,是在习惯上给你一个缓冲。它想让你在调用 AI 之前先问自己:"这个问题真的需要 AI 吗?有没有更简单的方式?"

如果答案是"真的需要",那就放心地用。但如果答案是"好像用正则也能行"——那先试试正则。


结尾

最小 AI 原则可以用三句话总结:

  1. 先用最简单的方案——正则、规则引擎、小模型。如果三行代码能解决,不要调 API
  2. 引入 AI 要有明确的边界——清晰的输入输出定义,明确的失败处理
  3. AI 应该是最后的选择,而不是默认的选项——让简单方案覆盖 80% 的场景,AI 处理剩下 20%

从下个任务开始,试试先问自己:"不用 AI 能解决吗?" 如果答案是"能",先尝试不用 AI 的方式。你可能会发现,很多时候你的直觉比想象中更够用。


文章由文字工作者编写。最小 AI 原则的提出受最小权限原则的启发。成本数据基于 2026 年中公开 API 价格估算。

七、最小 AI 原则在团队中的实践

7.1 团队规范示例

如果你想让团队也遵循这个原则,可以考虑建立一个简单的决策流程:

团队规范:AI 使用决策流程

1. 写代码前先问:这个问题能不用 AI 解决吗?
   -   写标准的 if-else / 正则 / 算法
   - 不能  进入步骤 2

2. 如果用 AI:能满足需求的最小模型是什么?
   - 规则引擎 / 简单算法  不要用任何模型
   - 文本分类 / 关键词匹配  小模型 / TF-IDF
   - 简单文本生成  7B-13B 模型
   - 复杂推理  70B+ 模型

3. 每次代码审查时增加一个检查项:
   - "这个 LLM 调用是否可以用非 AI 方案替代?"
   - 如果回答不了,说明可能用过度了

4. 每个 sprint 审查 AI 使用情况:
   - 统计 LLM API 调用次数和成本
   - 找出可以优化掉的"过度 AI"调用
   - 目标:每条 LLM 调用都有明确的必要性

7.2 代码审查中的检查清单

在 Code Review 时,增加几个针对 AI 使用的检查项:

# CODE REVIEW CHECKLIST - AI USAGE
# 
# 看到 LLM 调用时,问以下问题:
#
# [ ] 这个调用可以用 if-else / 规则引擎替代吗?
# [ ] 这个调用可以用小模型(<7B)替代吗?
# [ ] 如果 LLM 超时或返回空值,有回退方案吗?
# [ ] 调用结果有校验逻辑吗(不是直接信任 LLM 输出)?
# [ ] 有没有缓存?相同输入是否反复调用?
# [ ] 是否记录了调用的性能和成本?
#
# 如果有超过 2 项回答"否",需要重新讨论设计。

这个检查清单帮我避免了几次"过度 AI 设计"——最有意思的一次,我要用 LLM 做"中文数字转阿拉伯数字"("一万二千三百四十五" → "12345"),结果 review 之后改成了 30 行的纯 Python 函数。更快、更便宜、更可靠。


结尾

最小 AI 原则可以用三句话总结:

  1. 先用最简单的方案——正则、规则引擎、小模型。如果三行代码能解决,不要调 API
  2. 引入 AI 要有明确的边界——清晰的输入输出定义,明确的失败处理
  3. AI 应该是最后的选择,而不是默认的选项——让简单方案覆盖 80% 的场景,AI 处理剩下 20%

从下个任务开始,试试先问自己:"不用 AI 能解决吗?" 如果答案是"能",先尝试不用 AI 的方式。你可能会发现,很多时候你的直觉比想象中更够用。


文章由文字工作者编写。最小 AI 原则的提出受最小权限原则的启发。成本数据基于 2026 年中公开 API 价格估算。