最近在升级我的个人投资研究 Agent 时,我碰到了一个很容易被忽略的问题:
确定性实现,不等于客观判断。
代码当然可以稳定地执行一个正则、关键词表或布尔条件。
但“执行稳定”并不会自动赋予 Runtime 理解开放自然语言的能力。
如果 Runtime 并不知道一句话的真实语义,就不要因为能把它写成 if,假装自己知道。
这篇文章讨论的,就是 Agent 系统里一条很重要的边界:
Runtime 只应该对自己真正知道、能够追溯和复核的事实负责。
前情提要:我们在做什么 Agent
我们做的是一个偏严肃场景的个人投资研究 Agent。
它不是简单把用户问题丢给大模型,也不是让模型自己执行投资操作。
更接近这样的流程:
1用户提出问题 2→ Agent 判断需要什么信息 3→ 按权限读取组合、材料或公开来源 4→ 根据结果继续调查 5→ 形成分析 6→ 系统校验证据、权限和确定性状态 7→ 发布答案 8
例如:
1我的组合风险是不是太集中? 2这两类 ETF 哪个更适合长期配置? 3结合这份材料,重新评估之前的判断。 4
这种系统里,除了 Model,还会有一层 Runtime。
这里的 Runtime 不是语言运行时,而是围绕 Model 的 Host-owned 执行与状态层。
它负责的事情大致包括:
1工具授权 2调用执行 3状态和回执 4来源与 scope 5确定性数值 6持久化 7恢复 8发布 9终态 10
Model 更适合负责:
1理解用户 2决定下一步查什么 3比较信息 4发现矛盾 5形成判断 6组织回答 7
问题就在于:
Runtime 到底应该管到哪里?
先给结论:谁拥有事实,谁才有资格触发硬规则
Runtime 应该负责它能够客观证明的事实。
例如:
1某个工具是否真的调用 2某个来源是否属于当前用户和当前 run 3某个数据是否已经过期 4某个状态绑定是否仍有效 5某个执行回执是否存在 6某个 publication 是否真的提交 7
这些信息来自 Host、持久化状态或明确协议。
它们有一个共同特点:
可以被审计和复核。
但下面这些问题不是一回事:
1这句话是不是“当前事实”? 2这句话是不是个人持仓断言? 3这句话是不是投资建议? 4这句话是否真的被证据支持? 5这句话是否完整回答了用户? 6
这些属于语义判断。
它们不会因为实现语言是 TypeScript,或者判断逻辑写成了正则,就突然变成客观事实。
这就是标题真正想表达的东西:
Runtime 不知道的,不要因为能写一个规则,就假装它知道。
问题通常不是从“大型自然语言分类器”开始的
实际工程里,这类问题往往从一个非常合理的安全需求开始。
例如:
1模型没有读取用户组合 2却生成了一句“你的组合目前没有某类资产” 3
我们当然不希望系统把这种话当成可信的个人状态。
于是一个很自然的想法是:
1如果答案里出现: 2“你的组合” 3“当前持仓” 4“目前没有” 5…… 6就要求 portfolio evidence 7
第一版看起来很合理。
而且 deterministic:
1命中 → reject 2不命中 → pass 3
问题是:
命中的是字符串模式,不是事实身份。
同一句话可能是:
1真实断言 2假设 3引用 4例子 5否定 6转述 7模型错误 8
Runtime 看到的是字符。
它并不知道这句话在当前上下文里究竟扮演什么语义角色。
于是系统开始出现两种错误:
1误拦:只是举例,却被当成真实个人状态 2漏拦:换一种说法,就绕过了关键词 3
然后工程上很容易继续补:
1更多关键词 2更多正则 3更多 reason code 4更多 repair 5更多测试 6
最后,一个最初只是小 helper 的东西,慢慢变成了“安全基础设施”。
这时候真正应该问的,已经不是:
正则覆盖率够不够?
而是:
这个规则到底有没有资格判断这件事?
一个最小例子:执行状态不能从文案里推出来
假设 Model 写了一句:
“已经替你完成了调整。”
Runtime 可以做两种事情。
错误方式:解释文本
1发现“已经完成” 2→ 判断这是执行声明 3→ 检查有没有执行记录 4
这看起来像安全保护。
但问题是:
1“已经完成”可能是引用 2可能是否定句的一部分 3可能是举例 4可能只是文案错误 5
真正的执行状态,其实根本不需要从文字里猜。
Runtime 已经可以知道:
1有没有执行请求 2用户有没有确认 3有没有调用允许的执行工具 4有没有 execution receipt 5账本状态有没有变化 6
所以执行状态应该由这些事实决定:
1有 receipt → executed 2没有 receipt → not executed 3
而不是:
1文案像执行成功 → 猜它执行了 2
如果 Model 文案和真实状态冲突,那是语义质量问题。
可以拒绝、降级或交给评审。
但“执行是否真的发生”,不应该由 prose 决定。
自由文本不能创造权威事实
这条边界可以进一步推广。
自然语言里可能出现:
1“你的组合没有黄金” 2“当前净值是……” 3“我已经帮你调仓” 4
这些句子看起来分别像:
1个人状态 2当前事实 3执行声明 4
但 Runtime 不应该仅凭文本,把它们升级成系统事实。
真正能触发确定性验证的,应该是 Host-owned typed facts,例如:
1状态绑定 2来源引用 3数值句柄 4执行回执 5明确 scope 6
也就是说:
自由文本可以表达内容,但不能创建 authority。
Model 可以提出:
1“我认为这里需要引用当前组合” 2
但是否真的存在当前组合、是否有权限、是否仍有效,必须由 Host 决定。
Model 也可以写出一个金额。
但一个自由形式的金额,不应该自动获得“这是可信当前投资金额”的身份。
真正的权威必须来自系统自己拥有的绑定。
哪些文本检查仍然适合 Runtime
这里不是说 Runtime 完全不能检查文本。
有一类检查是合理的:
1. 机器语法
例如:
1ID 2placeholder 3cursor 4protocol marker 5
2. 明确受保护字面量
例如:
1secret 2credential 3token 4
3. 机械约束
例如:
1长度 2JSON/schema 是否合法 3字段是否存在 4格式是否符合协议 5
这些检查共同特点是:
不需要理解语言的意义。
真正危险的是把下面这些概念也交给字符串规则:
1当前事实 2个人状态 3投资建议 4执行 5完整性 6语义支持 7
这些不是“正则写得够不够好”的问题。
而是所有权就错了。
证据链存在,不等于自然语言一定正确
另一个很容易混淆的地方,是 evidence。
Runtime 可以客观证明:
1某个来源确实被读取 2结果确实进入了下一轮 3最终 publication 确实绑定了这个来源 4scope 和 freshness 检查通过 5
这些都很重要。
但它们并不能单独证明:
1答案正确理解了来源 2答案没有把数字写反 3答案完整回答了问题 4答案没有语义歧义 5
举一个最简单的例子。
来源里写的是:
1A 2
模型回答:
1B 2
即使:
1read 发生了 2citation 也绑定了 3
“B 是否被 A 支持”依然是语义问题。
所以:
provenance 完整,不等于 entailment 成立。
Runtime 可以证明:
“这句话绑定了哪个来源。”
但不能仅凭这一点证明:
“这句话一定正确表达了来源。”
这两个层次最好不要混在一起。
为什么 repair 成功,也不等于规则正确
这是这类 heuristic 最容易制造的错觉。
假设:
1第一轮: 2模型写了一个当前数值 3规则命中 → reject 4 5系统反馈: 6不要输出未经验证的当前事实 7 8第二轮: 9模型把数值删掉,改成泛泛描述 10规则不命中 → pass 11
从测试角度看:
1repair 成功 2
但 underlying facts 并没有变化。
变化的只是:
1wording 2
这可能说明:
1事实真的被修正了 2
也可能只是:
1模型学会绕过 matcher 2
因此至少要把两个概念分开:
1mechanical repair success 2semantic correctness 3
前者 Runtime 可以测。
后者不能从前者推出。
正确的边界不是“全部交给模型”
看到这里,很容易得出另一个极端结论:
那 Runtime 什么都别管,让 Model 自己判断。
也不对。
Runtime 非常适合负责:
1permission 2scope 3freshness 4receipt 5state binding 6numeric binding 7publication 8terminal state 9
因为这些是真实系统状态。
Model 非常适合负责:
1这句话是什么意思 2当前结果说明什么 3还要不要继续查 4两份资料是否矛盾 5怎样回答用户 6
所以真正的目标不是:
1Model 替代 Runtime 2
也不是:
1Runtime 替代 Model 2
而是:
确定性事实交给 Runtime,开放语义交给 Model。
“Runtime 能知道的都不要让 Model 推理”还缺另一半
我们经常会说:
Runtime 能知道的,就不要让大模型推理。
这句话是对的。
例如:
1某个工具是否调用成功 2某个 publication 是否已经提交 3某个数值是否来自可信计算 4
都没必要让 Model 猜。
但这句话只有一半。
另一半同样重要:
Runtime 不知道的,也不要因为能写一个
if,就假装它知道。
两句话合起来才完整:
1Runtime 已知的 2→ 不让 Model 重复维护 3 4Runtime 不知道的 5→ 不让规则冒充理解 6
这也是我们最近越来越认可的分工:
Runtime 维护世界,Model 理解世界。
两个简单案例
案例一:个人持仓
用户的真实组合状态应该来自:
1授权 2scope 3组合数据 4状态绑定 5freshness 6
而不是:
1答案里有没有出现“你的组合” 2
如果没有有效状态绑定,Model 写得再像真实持仓,也不能获得个人状态 authority。
如果状态绑定存在但已经过期,也不能因为文案听起来合理就升级成 current。
案例二:执行结果
执行是否发生应该来自:
1明确请求 2用户确认 3工具调用 4执行回执 5实际状态变化 6
而不是:
1答案里有没有“已完成”“已下单” 2
Model 可以写错。
Runtime 不能因为 Model 写错,就让世界状态跟着变化。
这其实是 Agent 系统最重要的一条原则:
语言描述世界,不等于语言创造世界。
一个实用的 Code Review 清单
以后看到一个新的 deterministic gate,我会优先问下面这些问题:
- 这个 gate 判断的到底是什么?
- 它的 authoritative input 来自哪里?
- 这个输入是 Host-owned fact,还是 Model prose?
- 如果把同一句话换个说法,结果会不会变化?
- 如果会变化,变化的是语义,还是系统事实?
- 自由文本是否能创建个人状态、金额或执行结果?
- evidence chain 证明的是来源追溯,还是语义正确?
- repair 成功以后,事实真的变了吗,还是 wording 变了?
- 没有语义评审时,系统有没有诚实保留“未评估”状态?
- 这个规则是在减少风险,还是把自然语言分类偷偷塞进 Runtime?
如果其中有几项答不上来,就值得重新考虑这条 gate 是否应该存在。
最后
Agent 系统很容易在追求可靠性的过程中,把越来越多判断写成确定性规则。
这本身不是问题。
问题在于:
不是所有能写成代码的判断,都是 Runtime 真正知道的事实。
正则可以稳定。
关键词表可以稳定。
布尔逻辑可以稳定。
但:
稳定执行一个判断,不等于这个判断拥有客观依据。
好的 Runtime 应该很严格。
但严格的前提是:
它只对自己真正拥有的事实负责。
Model 可以理解、推理和表达。
Runtime 可以授权、执行、记录和校验。
语义质量可以由 Model、独立评审或 Human 判断。
但不要让任何一层冒充另一层。
所以最后还是这两句话:
Runtime 已经知道的,不要让 Model 再维护。
Runtime 不知道的,也不要因为能写规则,就假装它知道。
好的 Agent 架构不是把所有复杂度搬进代码。
而是:
把确定性复杂度放进 Runtime,把语义复杂度留给 Model。
《Agent 写正则来实现规则 ≈ 踩坑》 是转载文章,点击查看原文。

