认清现实吧,LLM就是个"超级赌场",而我们需要的是一套"紧箍咒"
📌 摘要:LLM本质上是一个无状态的"条件概率文本生成器",它没有记忆、没有意识、不会创新,且天生存在弱指令遵守和幻觉两大致命弱点。不加约束地使用LLM就像让一个"天才但散漫的实习生"独立负责生产任务,注定会出问题。本文提出"Harness(约束框架)"的概念------通过记忆系统、系统调用门、校验Agent、知识图谱和Batch Agent等工程手段,给LLM装上"规则引擎",让它从"不可靠的赌场"变成"可信赖的生产力工具"。核心观点:别神化AI,要工程化AI。
🔍 SEO关键词:LLM本质、条件概率文本生成器、LLM幻觉、弱指令遵守、Harness约束框架、Agent工程化、LLM无状态、知识图谱、AI系统设计、LLM生产部署
之前我的系列文章一直在聊"流马怎么设计"、"用了什么技术"、"能带来什么收益"。但今天我想退一步,聊聊一个更根本的问题:
LLM到底是什么?它擅长什么?不擅长什么?为什么我们需要一套"Harness"来约束它?
这些问题的答案,决定了我们到底应该把AI当成"神"来崇拜,还是当成"工具"来调教。
一、LLM的本质:一个没有状态的"条件概率文本生成器"
如果你用过LLM的API,你会发现一个"反直觉"的事实:LLM本身没有任何记忆。 它不知道上一轮对话说了什么,不知道你是谁,甚至不知道自己在哪。
每一次你调用它,你发给它的消息长这样:
diff
系统提示词(Agent.md、Skills、Rules、Specs、Powers...)
+ 对话历史(如果有的话)
+ 当前用户的输入
LLM拿到这一大坨文本,开始工作。它的工作原理非常"简单粗暴":
- 根据你给的输入条件,计算下一个词的概率分布。
- 从这个概率分布中,选出第一个词。
- 把选出的第一个词拼到输入后面,重新计算第二个词的概率分布。
- 再选第二个词。
- 递归执行,直到生成完整的回答。
这就是全部。没有思考,没有意识,没有状态。
你可能会问:"那它怎么记住对话上下文?"答案是:它不记,是你每次都把历史对话重新塞给它。 LLM本身是无状态的------每次请求都是一次全新的计算,它的"记忆"完全依赖于你每次喂进去的上下文。
这也解释了为什么你可以随时切换模型(从GPT-4换到Claude,或者换到Qwen),只要上下文一致,任务可以无缝继续。因为LLM只是一个"接收文本、返回文本"的函数,它的内部状态不影响外部任务的一致性。状态由外部系统(就是我们一直在做的Harness)维护,LLM只负责"给定输入,生成输出"。
至于温度(Temperature)、Top-K、Top-P这些参数,它们属于后处理工程 ,不影响LLM的本质。温度高,LLM选词的随机性大,输出看起来更"有创意";温度低,LLM更倾向于选概率最高的词,输出更"保守"。但无论怎么调,它都是在已有的概率分布上做文章。它不会"顿悟",不会"灵光一闪",不会创造出训练数据中从未出现过的真正新概念。
二、LLM的致命弱点:弱指令遵守 + 幻觉
因为LLM的本质是"条件概率",所以它有两个无法根治的毛病。
第一个毛病:弱指令遵守。
你告诉它"必须用JSON格式输出",它答应了。但输出的时候,可能多打了一个逗号,少加了一个引号。为什么?因为它在生成每个词的时候,只是在考虑"下一个词是什么概率最高",而不是"我有没有严格遵守某个规则"。
你把一堆规则写在System Prompt里------它都会"看",但会不会遵守?看运气。看概率。看它训练数据里类似的规则被遵守的频率。
这就是"弱指令遵守":它能理解你的指令,但它无法保证每次都不犯低级错误。 因为它不是一个"函数",不会"编译"------它只是一个"文本生成器"。
第二个毛病:幻觉。
这也是条件概率的必然结果。当LLM遇到一个它"不太确定"的问题时,它不会说"我不知道"。它会基于训练数据中见过的类似模式,"编"一个听起来合理的答案。这个答案可能格式完全正确、语气非常自信,但内容完全错误。
幻觉不是bug,是feature。 LLM的设计目标就是"生成",不是"验证"。验证需要外部世界的信息------一个它没有的"现实锚点"。
三、既然创新不行,守成也不行,那LLM不是"鸡肋"了吗?
读到这,你可能觉得:创新任务不适合LLM,因为它只会根据先验出结果。非创新任务也不适合,因为它总会犯错。那LLM不就是个鸡肋吗?
对,如果不加任何约束,它就是鸡肋。 写个周报还行,写生产代码?你敢直接部署它生成的代码不经人工审查吗?我猜你不敢。
但这不是LLM的错,这是我们用法的错。 我们把一个天生"无状态、弱约束、会幻觉"的文本生成器,当成一个"全知全能的智能体"来用。出了问题,我们骂它"不靠谱",但其实是我们自己没给它搭好台子。
这就是Harness存在的意义。Harness不是给LLM锦上添花,而是给LLM雪中送炭。
四、Harness怎么做:给"赌场"装上"规则引擎"
LLM是一个"超级赌场"------它每次生成一个词,都是在赌概率。而Harness,就是给这个赌场装上规则引擎、审计系统和质量门禁。
在我的流马(Gliding Horse)里,Harness是这样调教LLM的:
1. 用记忆系统弥补LLM的"无状态"
LLM自己没记忆,但流马有四层记忆(L0-L3)。对话历史不用全塞进上下文,而是存摘要和IRI。LLM需要细节时,沿着IRI去图数据库里查。状态由Harness维护,LLM只是一个"查询引擎"。
2. 用系统调用门弥补LLM的"弱指令遵守"
你写Prompt说"不要删文件"?LLM可能还是会删。但流马在代码层拦截:PA想写文件?白名单里没有,直接拒绝。DA想调用危险API?Ed25519签名对不上,直接拒绝。软约束在Prompt里,硬约束在代码里。Harness替LLM兜底。
3. 用CA检查Agent和阶段门禁弥补LLM的"幻觉"
LLM生成了一份PRD,说"功能模块已完整"。CA Agent会自动检查:真的完整吗?缺少参与者定义?打回重做。这个检查不是LLM的"自我反省",而是独立于LLM之外的校验Agent在把关。
4. 用知识图谱弥补LLM的"没有现实锚点"
LLM说"上次我们讨论过JWT密钥长度是256位"。真的吗?流马自动查知识图谱里的历史决策节点,验证事实。如果LLM在胡编,知识图谱会"打脸"。
5. 用Batch Agent让系统"自我优化"
技能图谱用久了会乱,知识碎片会散,失败模式会堆积。流马的后台整理Agent自动做技能合并、实体解析、失败模式挖掘。**系统越用越聪明,不是因为LLM变强了,而是因为Harness在持续优化。 系统越用越聪明,不是因为LLM变强了,而是因为Harness在持续优化。
下面是流马(Gliding Horse)中Harness的整体系统架构图,直观展示各组件如何协同工作:
架构说明:用户请求先进入Harness层,由Harness统一调度LLM、管理记忆、执行安全检查、验证事实,并定期自我优化。LLM仅作为"查询引擎"被调用,不直接接触存储或执行危险操作。
**
五、总结:别把LLM当神,把它当"天才实习生"
LLM是一个天才但散漫的实习生。它学富五车(训练数据量大),反应极快(推理速度快),但:
- 不记事儿(无状态)
- 不守规矩(弱指令遵守)
- 爱胡扯(幻觉)
- 没有创新(基于先验)
- 不懂验证(只会生成)
如果你直接让它独立负责生产任务,它一定会闯祸。 但如果你给它配上一套完善的工程体系------记忆系统帮它记事儿,校验系统帮它把关,门禁系统帮它守住底线,知识系统帮它验证事实------它就能从一个"散漫的天才"变成"可信赖的生产力"。
这就是Harness的价值:不是让LLM变得更强,而是让LLM变得靠谱。
流马不是在做"更强的AI",而是在做"让AI可以放心用"的工程基座。
六、最后说句心里话
AI圈现在有两个极端:一派把LLM当成"通向AGI的神谕",一派把LLM当成"只会写周报的玩具"。
我的立场在中间:LLM是伟大的发明,但它只是一个"零件"。 它需要操作系统、需要文件系统、需要权限管理、需要质量保障------就像CPU很强大,但没有主板、内存、操作系统,它就是个发热的硅片。
LLM是天才,Harness是纪律。天才需要纪律,才能创造价值。
我这套系统叫 Gliding Horse(流马) ,所有代码都在 GitHub 上:github.com/doiito/glid...
*系列第15篇了。写了这么多,其实核心思想只有一个:别神化AI,工程化AI。如果你也在做Agent系统,希望这个系列能让你少踩一些坑。
七、实战:用Harness约束LLM的Python示例
前面我们聊了Harness的理念------给LLM装上"规则引擎"。下面用一个完整的Python示例,展示如何通过一个简单的Harness类来包装LLM调用,实现记忆缓存 、输出格式校验 和内容安全检查。
7.1 核心Harness类
python
import json
import re
import hashlib
from typing import Any, Callable, Optional
class Harness:
"""
Harness 类:给 LLM 调用套上"紧箍咒"
对应文章中的 Harness 理念:
- 记忆缓存 → 避免重复调用,节省成本
- 格式校验 → 确保 LLM 输出符合预期结构
- 安全检查 → 过滤敏感/违规内容
"""
def __init__(self, llm_func: Callable[[str], str]):
# llm_func:实际的 LLM 调用函数(如 OpenAI API 封装)
self.llm_func = llm_func
# 记忆缓存:存储已处理过的 prompt 及其结果
self._cache: dict[str, str] = {}
# 关键词黑名单:内容安全检查用
self._blocklist: set[str] = set()
# ---------- 记忆缓存 ----------
def _cache_key(self, prompt: str) -> str:
"""生成缓存键,对应文章"缓存机制""""
return hashlib.sha256(prompt.encode()).hexdigest()
def _check_cache(self, prompt: str) -> Optional[str]:
"""命中缓存直接返回,对应文章"减少重复调用""""
key = self._cache_key(prompt)
return self._cache.get(key)
def _update_cache(self, prompt: str, response: str):
"""更新缓存"""
key = self._cache_key(prompt)
self._cache[key] = response
# ---------- 格式校验 ----------
def _validate_json(self, text: str) -> dict:
"""
校验 LLM 输出是否为合法 JSON
对应文章"输出格式约束"------LLM 可能输出非结构化文本
"""
try:
return json.loads(text)
except json.JSONDecodeError as e:
raise ValueError(f"输出格式校验失败:不是合法 JSON({e})")
# ---------- 安全检查 ----------
def add_blocklist(self, keywords: list[str]):
"""添加关键词黑名单,对应文章"内容安全过滤""""
self._blocklist.update(k.lower() for k in keywords)
def _safety_check(self, text: str) -> bool:
"""
检查输出是否包含黑名单关键词
对应文章"安全护栏"------防止 LLM 生成违规内容
"""
lower_text = text.lower()
for keyword in self._blocklist:
if keyword in lower_text:
return False # 未通过安全检查
return True
# ---------- 主调用入口 ----------
def invoke(self, prompt: str, require_json: bool = False) -> Any:
"""
带 Harness 约束的 LLM 调用
参数:
prompt: 输入提示词
require_json: 是否要求输出为 JSON 格式
返回:
校验通过后的 LLM 输出
对应文章"Harness 工作流":
1. 查缓存 → 2. 调用 LLM → 3. 格式校验 → 4. 安全检查 → 5. 更新缓存
"""
# 步骤1:查缓存
cached = self._check_cache(prompt)
if cached is not None:
print("[Harness] 命中缓存,跳过 LLM 调用")
return cached
# 步骤2:调用 LLM
print("[Harness] 调用 LLM...")
raw_response = self.llm_func(prompt)
# 步骤3:格式校验
if require_json:
raw_response = self._validate_json(raw_response)
# 步骤4:安全检查
response_str = json.dumps(raw_response, ensure_ascii=False) if isinstance(raw_response, dict) else str(raw_response)
if not self._safety_check(response_str):
raise RuntimeError("内容安全检查未通过:输出包含敏感关键词")
# 步骤5:更新缓存
self._update_cache(prompt, response_str)
return raw_response
7.2 使用示例
python
# 模拟一个 LLM 调用函数(实际使用时替换为 OpenAI / 本地模型 API)
def mock_llm(prompt: str) -> str:
"""模拟 LLM 返回 JSON 格式的天气信息"""
return json.dumps({
"city": "北京",
"temperature": 22,
"condition": "晴",
"advice": "适合户外活动"
})
# 创建 Harness 实例
harness = Harness(llm_func=mock_llm)
# 添加安全关键词过滤
harness.add_blocklist(["暴力", "色情", "赌博"])
# 调用 LLM,要求 JSON 输出
try:
result = harness.invoke(
prompt="北京今天天气怎么样?",
require_json=True
)
print(f"✅ 校验通过,结果:{result}")
# 输出:{'city': '北京', 'temperature': 22, 'condition': '晴', 'advice': '适合户外活动'}
# 第二次调用相同 prompt → 命中缓存
result2 = harness.invoke(prompt="北京今天天气怎么样?", require_json=True)
print(f"✅ 缓存命中,结果:{result2}")
except ValueError as e:
print(f"❌ 格式校验失败:{e}")
except RuntimeError as e:
print(f"❌ 安全检查失败:{e}")
7.3 扩展思路
这个Harness类只是一个起点,你可以根据实际需求扩展:
| 功能 | 对应文章理念 | 实现方式 |
|---|---|---|
| 重试机制 | 容错性 | 校验失败时自动重试 LLM,最多 N 次 |
| Token 预算控制 | 成本约束 | 在调用前预估 token,超限则截断 prompt |
| 输出长度限制 | 质量保障 | 校验响应字符数,超限则截断或重试 |
| 多轮对话记忆 | 状态管理 | 用列表维护对话历史,每次调用自动拼接上下文 |
| 结构化输出 Schema | 格式约束 | 用 Pydantic 定义输出模型,校验时自动转换 |
核心思想:LLM 是"天才实习生",Harness 是"纪律"。没有纪律的天才只会制造混乱,有了纪律的天才才能创造价值。