垂直AI(Vertical AI)这个词,现在几乎成了创投圈和技术圈共同追逐的方向:医疗、法律、金融、工业制造,似乎每个细分领域都在用大模型重新包装一套软件。但如果你真把这些系统放到生产环境里跑上一周,大概率会遇到一个很劝退的场景:同一份合同,同一个模型,同样的提示词,上午审查出三条风险,下午就变成了另外三条。这不是玄学,也不是偶发bug——因为LLM本质上是一个概率系统,它每一次回答,都相当于掷了一次骰子。
所以在我看来,当前这轮垂直AI泡沫,最危险的并不是融资估值,而是我们悄悄把LLM当作了一个100%确定性的数据库来用。模型越强大,这种“确定性幻觉”越容易被放大。这篇文章想聊清楚三件事:第一,LLM的随机性到底从哪里来,是不是把temperature调成0就万事大吉;第二,垂直AI应用应该怎么围绕这种随机性做架构设计;第三,怎么评估一个垂直AI系统到底能不能上线。如果你是AI应用开发者、技术负责人,或者正准备投身某个垂直领域做AI产品,这篇内容可以给你一个比较冷静的参考。
1. 这篇文章真正要解决的问题
先从身边最常见的现象说起。做AI产品的人,大多经历过“同一个问题,模型答得不一样”。产品经理把它当成bug提给算法同学,算法同学看了一眼采样参数说,这是正常的,大模型本来就有随机性。然后产品经理陷入困惑:如果它每次答案都不一样,我怎么敢拿给客户用?
这种困惑,在垂直AI里会被放大一百倍。
垂直AI的目标不是做一个通用聊天机器人,而是在特定行业里完成特定任务。合同审核、法律检索、医疗分诊、数据分析、代码审查,这些都是“任务”,不是“闲聊”。任务型系统天然要求稳定、可复现、低风险。但LLM的文本生成过程,恰恰是一个采样过程。这就形成一个结构性冲突:业务要确定性,模型给概率。
更麻烦的是,现在很多垂直AI创业公司的demo演示非常顺畅。演示时,demo只跑一遍;客户验收时,可能要跑一千遍。只要有一遍输出离谱,整套系统的信任就没了。这也是我判断“垂直AI泡沫”到来的技术依据:泡沫不在模型能力层,而在确定性预期层。整个行业对LLM随机性的正视程度,远低于它进入生产环境的速度。
这篇文章不是劝退,也不是让你不用LLM。相反,我认为垂直AI依然是未来,但前提是,工程上必须把LLM重新定义为“一个概率函数”,然后用校验、重试、评估、人工兜底这些传统软件手段,把它封装成一个确定性的服务。下面先解决第一个问题:LLM到底是怎么掷骰子的。
2. LLM是怎么“掷骰子”的:概率分布与采样
2.1 从Logits到概率
要理解随机性,得先看大模型生成文本时的内部过程。简单说,模型在预测下一个词时,会先给一批候选token打一个原始分,这个分数称为logits。这些分数没有归一化,需要通过Softmax函数变成概率。概率越高,代表模型认为这个词越可能出现在当前位置。
但真正生成的时候,模型并不是永远选择概率最高的那个词。它通常会根据这个概率分布去采样。也就是说,某个词哪怕概率只有15%,也有一定机会被选中。这就像掷骰子,只不过每个面被抽中的权重不同。
下面用一个极简的Python示例来模拟这个过程:
# 模拟LLM的token概率采样 import math import random # 假设模型给出的原始分数(logits) logits = { "继续": 3.2, "终止": 1.5, "暂停": 1.8, } def softmax_with_temperature(logits, temperature): exp_vals = {k: math.exp(v / temperature) for k, v in logits.items()} total = sum(exp_vals.values()) return {k: v / total for k, v in exp_vals.items()} probs = softmax_with_temperature(logits, temperature=0.7) print("采样概率:", probs) # 按概率采样一次 choice = random.choices(list(probs.keys()), weights=list(probs.values()))[0] print("本次采样结果:", choice)这里的关键是temperature参数。temperature越低,Softmax分布越尖锐,高概率词被选中的可能性越大;temperature越高,分布越平滑,低概率词被选中的可能性也越大。所以,当你在生产环境里把temperature调得很高,同一个问题得到完全不同的回答,是完全正常的。
2.2 采样带来的不确定性
真实场景里,一个LLM生成几百个token,每一步都这样采样,所以组合出来的回答自然五花八门。即便把temperature调成0,很多模型会采用贪心解码,看起来稳定,但这里有两个容易忽略的坑。
第一,不少云API在服务端仍然存在随机性,seed参数只能降低变化,不能保证不同请求在分布式环境下完全复现。第二,模型版本更新、推理框架不同、部署环境不同,都可能改变输出。所以,temperature=0和seed只是控制随机性的手段,并不能像数据库事务一样提供强一致性保证。
核心结论是:LLM不是纯函数,同一个输入可能对应多个输出。这个特性不是bug,而是模型设计的一部分。垂直AI工程要解决的问题,不是消灭随机性,而是管理随机性。
3. 垂直AI应用的典型场景与不确定性风险
理解随机性之后,我们看几个垂直场景。先看内容生成类:营销文案、招聘JD、行业摘要。这类任务对随机性容忍度较高,只要风格一致、事实正确,每次换一种说法反而可能是优点。
再看规则类任务:合同审查、法律问答、金融风控报告、医疗预问诊。这类任务输出直接影响决策,随机性可能是致命的。最后是代码和数据类:自动生成SQL、生成代码、测试用例。这类任务看起来“能运行就行”,但LLM生成的逻辑可能在不同批次里产生不同实现,如果没有测试覆盖,隐患非常大。
| 场景 | 随机性影响 | 可接受程度 | 工程对策 |
|---|---|---|---|
| 营销文案生成 | 同一产品介绍每次不同 | 高,反而需要多样性 | temperature设0.7~1.0,人工挑选 |
| 合同风险审查 | 高风险条款漏检 | 低,必须稳定 | 结构化输出+校验+人工复核 |
| 客服自动问答 | 相似问题不同回复 | 中,需要兜底话术 | RAG+会话状态+降级到FAQ |
| 医疗预问诊 | 症状理解偏差 | 低,不能直接诊断 | 限定角色+规则流程,结果仅参考 |
| 代码生成 | 逻辑非确定性实现 | 中,依赖测试 | 单测覆盖+静态检查+代码评审 |
| 数据分析问答 | 生成的SQL结果不同 | 低,需要准确 | 限定表结构+SQL验证+人工确认 |
这里特别想提醒一个现象,我把它称为“Demo陷阱”。很多垂直AI演示都只准备了三五个暖场案例,而这些案例往往都被精心调过提示词。一旦上线,真实输入比demo复杂得多,模型就会在概率空间里“自由发挥”。所以,评估一个垂直AI应用,第一件事不是看它聪明不聪明,而是看它稳不稳。
4. 控制随机性的基础:采样参数与结构化输出
4.1 采样参数
先从最直接的手段讲起:采样参数。这是每个AI应用开发者都应该掌握的旋钮。
temperature:采样温度。范围一般0到2,越低越保守。top_p:核采样概率。控制候选token的累计概率范围,越小越保守。max_tokens:限制生成长度,避免输出被截断。stop:停止词,让输出更收敛。seed:随机数种子,尽量复现结果,但不要完全依赖。response_format/json_schema:结构化输出,这是当前最实用的稳定性手段。
如果你的业务并不需要创意发挥,那么默认建议把temperature调低,尤其是合同审查、医疗问答、数据查询这类任务。很多团队把temperature默认值留在0.7甚至更高,等于主动给生产环境埋雷。
4.2 结构化输出与固定随机种子
下面是一个使用OpenAI兼容API的示例。代码里同时启用了temperature=0和seed=42,并强制返回JSON格式,这样业务系统可以直接解析结果。
# 文件路径:llm_stable_call.py # 需要先安装 openai 库:pip install openai from openai import OpenAI client = OpenAI(api_key="your-api-key") resp = client.chat.completions.create( model="gpt-4o-mini", temperature=0, seed=42, response_format={"type": "json_object"}, messages=[ { "role": "system", "content": ( "你是合同风险审查助手。只输出JSON,不要额外说明。" "JSON格式:{\"risks\":[{\"description\":\"风险描述\", \"level\":\"high|medium|low\"}]}" ) }, { "role": "user", "content": "请审查这份合同是否存在风险:甲方应在合同签订后10日内向乙方支付全部款项,逾期视为违约。" } ] ) content = resp.choices[0].message.content print(content)这段代码里,response_format={"type": "json_object"}会让模型尽量输出JSON,极大降低了解析失败的概率。temperature=0和seed用来减缓随机性。但注意,就算你把这套代码重复执行几十次,仍然可能看到风险描述的措辞有差异,只是整体结构会稳定很多。
如果你需要在本地达到更强的可复现性,可以考虑本地部署开源模型,并固定随机种子。即便如此,模型版本、推理框架(vLLM、llama.cpp等)的不同也会影响输出。所以,生产环境一定要把模型版本和推理框架版本一起锁定。
目前主流的LLM应用开发框架,比如LangChain、Spring AI,也都在做同一件事:把模型输出变成可消费的业务数据。它们提供的结构化输出能力,本质上就是用来对冲LLM随机性的。
5. 从“一次调用”到“可验证流程”:稳定输出的工程链路
把采样参数调好,只解决了第一层问题。真正的生产系统,需要把LLM调用包在一条可验证、可重试、可兜底的流程里。核心思想是:LLM是生成器,不是真理机。业务系统要建立防线,防止错误输出直接落到用户头上。
5.1 验证、重试、兜底的最小流程
下面是一个较为完整的示例函数。它的职责是:调用LLM审查合同风险,解析JSON,做业务校验,失败重试,最后兜底。
# 文件路径:llm_verified_flow.py import json from openai import OpenAI client = OpenAI(api_key="your-api-key") def extract_contract_risks(contract_text: str, max_retries: int = 2): system_prompt = ( "你是合同风险审查助手。" "只输出JSON,不要输出其他内容。" "JSON格式:{\"risks\":[{\"description\":\"风险描述\", \"level\":\"high|medium|low\"}]}" ) messages = [ {"role": "system", "content": system_prompt}, {"role": "user", "content": contract_text} ] for attempt in range(1, max_retries + 1): try: resp = client.chat.completions.create( model="gpt-4o-mini", temperature=0.1, response_format={"type": "json_object"}, messages=messages, ) data = json.loads(resp.choices[0].message.content) # 业务校验 risks = data.get("risks", []) if not isinstance(risks, list): raise ValueError("risks must be a list") for r in risks: if "description" not in r or r.get("level") not in ("high", "medium", "low"): raise ValueError("risk item schema invalid") return data except Exception as exc: print(f"第 {attempt} 次尝试失败: {exc}") # 兜底:返回安全默认值,而不是直接抛异常 return {"risks": [], "warning": "llm_output_invalid"} if __name__ == "__main__": result = extract_contract_risks("甲方应在合同签订后10日内向乙方支付全部款项,逾期视为违约。") print(result)这段代码看起来简单,但已经是生产级的最小骨架。有三个关键点需要展开。
第一,校验必须紧跟解析。不要相信模型输出的JSON一定符合业务schema,尤其要注意字段是否存在、枚举值是否合法。第二,重试不是无限重试。网络抖动或偶发格式错误可以重试,但如果模型始终产生非法输出,就要快速失败,进入兜底。第三,兜底不能是简单的空值,而是业务系统能安全处理的默认结果,同时要记录日志和告警,方便后续定位。
5.2 更进一步:RAG与Agent
如果场景更严肃,比如医疗、金融,还可以在验证重试之上加一层多模型投票:多个模型或多次采样,比对结果,如果分歧超过阈值,就转人工队列。这种思路本质上还是在对冲不确定性。
RAG和Agent架构也能降低随机性带来的风险。RAG把事实检索从参数记忆里分离出来,让模型基于给定文档回答,会显著减少“胡编”,但不会完全消除随机性。Agent则把一次大调用拆成多步小调用,每步之间用代码检查中间结果,等于在每个决策点都加校验器。
这里要提醒架构团队:不要把Agent做成“prompt里塞一百条规则”的巨无霸。步骤越多,随机性叠加越明显。要尽量让每一步输出可验证,把不确定的地方交给流程引擎或人工来处理。
6. 怎么科学评估垂直AI系统的稳定性
很多团队评估LLM,就是拿几个case试试,然后拍脑袋说“效果不错”。这在垂直AI里远远不够。我们需要一套可重复的评估流程。
6.1 建立Golden Set
第一步,建立golden set,也就是一批有标准答案的问题样本。根据业务场景不同,每个样本带上输入和期望输出类型。注意,不一定要有逐字的标准答案,但要有可判定的标准,比如“风险等级是否合理”“输出是否包含某个关键点”。
6.2 多次运行与指标
第二步,多次运行。由于有随机性,每个样本至少要跑3到5次,收集结果。第三步,统计指标。常见的有格式合法率、字段填充率、语义相似度、人工通过率。对于分类或提取任务,可以算准确率和召回率。
下面是一个简化的评估脚本,用来演示“重复运行并观察稳定性”的流程:
# 文件路径:eval_stability.py # 演示版:真实场景中把 llm_call 替换为你的模型服务 import random def llm_call(prompt, seed): # 这里用随机结果模拟LLM输出,用于演示评估流程 candidates = [ "合同缺少违约金条款", "合同缺少保密期限", "付款期限过短" ] return random.choice(candidates) golden_set = [ {"id": "case_001", "prompt": "审查这份合同风险", "expected": "至少包含付款期限或违约金"}, {"id": "case_002", "prompt": "审查这份合同风险", "expected": "至少包含保密条款"}, ] repeat_k = 5 results = [] for case in golden_set: for seed in range(repeat_k): output = llm_call(case["prompt"], seed) results.append({"case_id": case["id"], "output": output, "seed": seed}) for case_id in ["case_001", "case_002"]: outputs = [r["output"] for r in results if r["case_id"] == case_id] unique_ratio = len(set(outputs)) / len(outputs) print(f"{case_id}: 共 {len(outputs)} 次,输出种类 {len(set(outputs))},随机度 {unique_ratio:.2f}")真实场景中,你需要把llm_call替换为真实模型服务,并且要对输出做归一化和语义比对。比如,两个完全不同的文案可能表达同一个意思,这时候不能简单用字符串相等来判断是否一致。
6.3 让评估进入CI/CD
这个环节直接决定垂直AI系统的生死。很多项目上线前只测了10个case,上线后用户数据一进来,问题立刻暴露。比较务实的做法是把评估集做成一个自动化任务,每次修改prompt、换模型、更新RAG知识库之后,都自动跑一遍,输出对比报告。
被业内反复讨论的“AI工程师”,本质上就是能把这套评估闭环跑起来的人。不要把评估当成上线前的一次性动作,而要当成持续回归的工程能力。
7. 常见问题与排查方法
在垂直AI落地过程中,下面几个问题出现频率很高,这里列一个排查清单。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 相同提示词结果不同 | 采样温度偏高;seed未生效;服务端多机部署 | 检查请求参数,重复调用20次统计输出分布 | 调低temperature;约定seed;固定模型版本;必要时本地部署 |
| 输出JSON解析失败 | 模型未遵守格式;输出被max_tokens截断 | 打印原始返回,检查error和finish_reason | 使用response_format;增大max_tokens;增加解析兜底与重试 |
| 偶尔输出明显错误信息 | 模型幻觉;缺少检索上下文 | 对照输入检查prompt;看是否缺少RAG | 补充RAG;增加事实校验;高风险场景人工复核 |
| 业务指标不稳定,时好时坏 | 测试集过小;只测试了单次输出 | 检查评估集规模和重复次数 | 建立golden set,多次运行取平均 |
| 模型更新后行为变化 | 云厂商对模型升级;prompt对模型版本敏感 | 对比回归测试结果 | 锁定模型版本快照,升级前走评估流水线 |
| Agent任务中途失败 | 子任务输出校验失败;上下文过长 | 查看每一步的日志和token消耗 | 增加中间结果校验;分步重试;拆分任务 |
排查时有一个基本原则:先看原始返回内容,不要只看最终渲染结果。很多问题在请求日志里就能看到原因,比如截断、字段缺少、模型返回了空数组等。把这些日志结构化,后面会省很多时间。
8. 最佳实践与工程建议:在泡沫里做“确定性优先”的垂直AI
如果你准备做一个垂直AI产品,这里有七条比较务实的建议。
第一,先想清楚这个问题是否必须要用LLM。很多垂直领域的自动化,用规则、正则、统计分类器就能解决,而且稳定、可解释。让LLM做它擅长的事,而不是让它做所有事。
第二,给LLM定义契约。包括输入输出schema、错误码、超时和默认行为。不要允许自由文本满天飞,更不要在业务核心链路里直接拼接模型返回的原始字符串。
第三,把“低随机性”当作默认配置。除非业务需要多样性,否则优先使用temperature=0、结构化输出、多轮校验。创意的优先级要排在稳定性之后。
第四,建立评估和观测体系。除了CPU、内存这些常规指标,还要记录prompt、输出、耗时、token用量、用户反馈。每次迭代都跑回归测试。
第五,设计降级链路。规则系统、兜底文案、人工工单,任何一个环节都能在模型异常时接管。千万不要让用户直接面对模型出错时的“白屏”。
第六,重视安全与合规。LLM输出不能直接用于医疗、法律、金融等高影响决策,需要人工审核时不要省。数据要按最小权限访问,敏感数据建议脱敏后再调用外部API。涉及生产环境变更,先备份、再灰度、后回滚。这些不是形式主义,而是在不确定性之上做兜底。
第七,团队心智同步。要让产品、销售、客户都理解“AI不是100%准确”,在服务协议和产品说明里明确人工复核边界。很多项目最后不是死在模型效果上,而是死在预期管理上。
如果你要做垂直AI产品,我建议从“最好的模型+最稳的工程”切换到“足够好的模型+最强的校验”。很多时候,稳定性和可维护性比单次效果更重要。在泡沫期,能够稳定交付比什么都值钱。
9. 总结与后续学习方向
回到标题:为什么是垂直AI泡沫?不是因为LLM不强大,而是因为我们在忘记一个事实——LLM会掷骰子。模型能力越强,人们越容易相信它的输出是确定答案;工程链路越简陋,这种错误信任爆雷的概率就越高。真正能穿越周期的垂直AI公司,不是把模型调得多聪明,而是把随机输出管理得多稳定。
如果你正在做这类项目,下一步可以按这个顺序实践:先把一个业务场景跑通,记录它最不稳定的输出;然后加上结构化输出和校验重试;再建一个20条样本的评估集,重复跑几次看稳定率;最后把评估接入CI,让每次prompt或模型更新都留下可对比的记录。做完这四步,你对“LLM随机性”的理解会比大多数只在demo上见过AI的人深得多。
后续值得深入的方向包括:RAG与知识库增强、Agent可观测性、多模型路由、特定业务的局部微调、评估框架的二次开发。这些内容都可以在真实项目里继续验证。如果你在生产中遇到过最离谱的LLM输出,欢迎在评论区写出来,那会是最好的反面教材。