能力边界的误判
两种对称的错误
LLM 应用开发中有两种对称的能力误判:高估 LLM 本身的能力边界,和高估 LLM 框架的抽象能力。前者把模型放在它不适合的位置(事实性查询),后者把框架放在它不适合的位置(业务逻辑的载体)。两者的本质相同——搞错了工具能干什么,系统在工具能力之外的地方就会出问题。
高估模型:把大模型当数据库用
大模型看起来"什么都知道"。你问它某个 API 的参数列表,它能答上来;问它某个历史事件的时间,它能给出日期。这种表象制造了一个诱人的错觉:大模型是一个自然语言接口的知识库。
错觉的根源在于:数据库存储的是数据,查询返回的是精确匹配;LLM 存储的是训练数据的统计压缩,"查询"返回的是条件概率分布上的采样。两者本质不同。
统计压缩带来三个工程后果。训练数据截止日期意味着模型的"知识"定格在某个时间点,且它不会告诉你它不知道——它会以同样自信的语气给出过期信息和当前信息。频率偏差意味着模型对训练数据中频繁出现的信息"记忆"更好,恰好在你最需要准确信息的长尾场景中最不可靠。幻觉是最根本的问题——模型不会说"我不知道",而是生成一个在统计上"看起来像正确答案"的输出,在文本层面和真实信息没有任何可区分的特征。
正确的职责划分
LLM 的正确用法是理解自然语言意图并将其转化为结构化查询——意图解析是它擅长的事。
from pydantic import BaseModel, Field
from typing import Literal
class ProductQuery(BaseModel):
"""LLM 的输出:结构化的查询意图,不是查询结果。"""
product_category: str
attributes: list[str] = Field(
description="用户关心的产品属性,如价格、规格、库存"
)
comparison: bool = Field(
description="用户是否在进行产品对比"
)
time_constraint: Literal["current", "historical"] = "current"
def handle_product_question(user_input: str):
"""正确的职责划分:LLM 解析意图,数据库提供事实。"""
# 第一步:LLM 将自然语言转化为结构化查询意图
query = llm_parse(user_input, output_type=ProductQuery)
# 第二步:用结构化查询去查真正的数据源
results = product_database.query(
category=query.product_category,
attributes=query.attributes,
)
# 第三步(可选):LLM 将结构化结果组织为自然语言回答
response = llm_generate(
system="基于以下产品数据回答用户问题。只使用提供的数据,不要编造信息。",
context=results,
user_query=user_input,
)
return response这个模式的关键在于:LLM 在第一步做意图解析(它擅长的事),事实性信息来自数据库(一个确定性的、可审计的系统),LLM 在第三步做自然语言生成(它擅长的事),但生成的依据是数据库提供的事实,都来自数据库。
务实的分级策略
完全禁止 LLM 回答任何事实性问题在某些场景下不现实。务实的做法是按风险分级处理。
高风险事实:必须外部验证。 涉及法律、医疗、财务、安全的事实性信息,必须来自权威数据源,LLM 只负责意图解析和结果组织。这是不可妥协的底线。具体地:系统架构中应当有一个明确的"事实网关"——任何高风险事实在进入最终输出之前,必须经过外部数据源的验证路径。如果外部数据源不可用,系统就该退到"无法回答",而非让 LLM 自己编一个。
中风险事实:标注来源与时效。 产品信息、技术文档、历史数据——使用 RAG 从可信数据源检索,在输出中标注信息来源和检索时间。让用户知道信息的依据是什么。关键设计要点是:让用户看得到检索结果的时效("根据 2024 年 3 月的文档"),不能让系统默默吞掉。
低风险事实:允许直接回答,但标注免责。 常识性问题、非关键性的背景信息——可以依赖模型的"知识",但系统应明确告知用户这些信息未经实时验证。这是一种坦诚的设计态度:让用户自行决定是否需要交叉验证。
高估框架:抽象泄漏的放大效应
能力误判的另一面是高估 LLM 编排框架的抽象能力。第五章已经从"过度设计"的角度讨论了框架的问题。这里讨论一个不同但相关的维度:即使你选择了一个当前看来合理的框架,过度依赖它仍然会制造严重的技术债务。
所有抽象都会泄漏——这是 Joel Spolsky 二十年前就指出的。但在 LLM 领域,抽象泄漏的后果比传统软件更严重。LLM 框架的抽象建立在一个本身就不确定的系统之上。当框架告诉你"使用 Agent 类来构建一个自主决策的系统"时,它隐藏了大量关于 prompt 工程、错误处理、成本控制的细节。当系统行为不符预期时,你需要同时理解框架的抽象层和 LLM 的概率性行为——两层不确定性的叠加让调试难度不是加法而是乘法。
框架锁定有四个信号:你的业务逻辑无法脱离框架运行;框架升级变成了项目风险;你在写代码绕过框架的限制;调试需要理解框架内部实现。如果你命中了其中两个以上,框架已经从"节省时间的工具"变成了"增加复杂度的负担"。
降低框架锁定的设计原则
在探索阶段的快速原型、标准化需求、以及团队能力约束下,用框架是合理的。但如果决定使用,以下原则可以降低锁定风险。
将框架的使用限制在基础设施层,不要让框架的类型和接口渗透到业务逻辑中。业务逻辑依赖你自己定义的接口,框架是这些接口的一个实现——切换框架时只需替换实现,不需要重写业务逻辑。定期验证:不用这个框架,核心功能照样能实现。不要因为引入了一个框架就把所有功能都交给它——每增加一个依赖框架的功能点,切换成本就增加一分。
把大模型当数据库用和框架锁定,本质上都是对工具能力边界的误判。第一章划定的能力边界,到了实际工程中体现得最直接:正确的做法是让每个工具做它擅长的事。在一个每隔几个月就会出现新范式的领域,搞清楚每个工具能做什么、不能做什么,是基本功。