当本体论遇见智能体:软件工程哲学的一次范式转移

序:一个没人注意到的错误
在讨论 Agent 与领域本体的结合时,经常会默认一个前提: 如果系统已经拥有一套清晰的领域本体,那么 Agent 的行为就会更稳定、更符合业务语义。
这个前提看起来是合理的。
领域本体确实可以提供一套结构化描述:实体、关系以及业务约束,都可以通过明确的语义表达出来。从知识建模的角度看,它能够减少歧义,并为系统提供稳定的概念基础。
但在 Agent 系统中,这里存在一个容易被忽略的转换步骤。
本体论的语言,原本用于描述领域结构。 而 Agent 在运行时需要的是一种能够组织行动决策的语言。
如果直接把前者当作后者使用,就会产生一个问题: 描述结构的语义体系,被用来驱动行动。
两种语言的目标不同。
本体论关注的是“世界由什么构成”; 而 Agent 的执行过程需要表达的是“下一步应该做什么”。
当这两种语言被直接合并时,语义层很容易发生失真。系统在逻辑上仍然保持一致,但在具体行为上可能出现偏差。
这篇文章要讨论的,就是这种语义失真产生的原因。
一、本体论的语言是”描述上帝视角”的
先问一个问题:本体论(Ontology)在描述什么?
它在描述世界应该是什么样的。
CBC 范式——Context(上下文)、Behavior(行为)、Constraint(约束)——是这种描述的精华表达。
以电商退款场景为例:
Context:用户购买后 7 日内,商品未被实质使用
Behavior:可发起退款,可申请换货,可要求原路退回
Constraint:退款金额不超过原始订单金额,同一订单仅限一次
注意这套语言的特点:它是全知视角的,静止的,无主体的。
“可发起退款”——谁来发起?什么时机发起?失败了怎么办?CBC 不关心这些。它只是在陈述一个业务事实:在这个上下文下,这个行为是被允许的,这是它的边界。
这种语言非常适合人类理解,因为人类本来就是在”理解世界规则”之后,再决定如何行动的。
但 Agent 不是。
二、Agent 需要的语言,是”触发→执行→反馈”的循环
Agent 在这里充当的是一个执行体,不是一个思考者。
它需要知道的不是”世界是什么样的”,而是:
我是谁?我应该在什么时候做什么?做完了如何知道成功?
这就是 ABC 范式存在的理由:Actor(谁来执行)、Behavior(执行什么)、Condition(什么条件下执行)。
同样的退款场景,ABC 的表达是:
# 定义一个负责处理退款流程的 Agent
Actor: RefundAgent
# Agent 执行的行为:发起退款
Behavior: InitiateRefund(order_id, refund_type)
# 退款触发条件
Condition:
# 购买时间必须在 7 天以内
- days_since_purchase(order_id) <= 7
# 商品状态不能是已使用或损坏
- product_condition NOT IN ["used", "damaged"]
# 该订单此前没有发生过退款
- refund_count(order_id) == 0
你会注意到,这里发生了一件表面上看起来很小、实际上意义深远的事:
“用户购买后 7 日内”变成了 days_since_purchase(order_id) <= 7。
这不是翻译。这是一次语义降维。
原来的表达里,”7 日内”背后是一整套业务语义:消费者权益保护的法律框架、公司的品牌承诺、客服团队的执行文化……这些都隐含在这个短语里,是它的”语义背景”。
到了 ABC,变成了一个布尔判断。背景消失了。
这个消失,就是语义失真的起点。
graph TB
subgraph CBC["CBC 范式(本体论语言)"]
direction TB
C1[Context<br/>上下文]
C2[Behavior<br/>行为描述]
C3[Constraint<br/>约束边界]
C1 --> C2
C2 --> C3
C4["特点:全知视角<br/>静态描述<br/>无执行主体"]
end
subgraph ABC["ABC 范式(执行语言)"]
direction TB
A1[Actor<br/>执行主体]
A2[Behavior<br/>执行动作]
A3[Condition<br/>触发条件]
A1 --> A2
A2 --> A3
A4["特点:第一人称视角<br/>动态执行<br/>明确主体"]
end
CBC -->|语义降维| ABC
ABC -->|损耗| A5["语义失真<br/>背景消失<br/>布尔化判断"]
style C1 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style C2 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style C3 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style C4 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style A1 fill:#e1f5ff,stroke:#0288d1,color:#01579b
style A2 fill:#e1f5ff,stroke:#0288d1,color:#01579b
style A3 fill:#e1f5ff,stroke:#0288d1,color:#01579b
style A4 fill:#e1f5ff,stroke:#0288d1,color:#01579b
style A5 fill:#ffebee,stroke:#d32f2f,color:#b71c1c
三、失真的代价,发生在边缘
大多数情况下,这种失真是无害的。
订单在第 3 天申请退款,条件成立,执行退款,结束。没有问题。
但在边缘场景里,失真的代价就会显现:
场景一:用户在第 6 天 23:58 提交退款申请,系统处理延迟到第 7 天 00:02,条件 days_since_purchase <= 7 此时返回 false,退款被拒绝。
按 ABC,这是正确的。按业务语义,这是荒唐的——因为”7 日内”的真实含义是”给消费者合理的时间窗口”,而不是”精确到秒的计时器”。
场景二:商品有轻微使用痕迹,但用户声称是检查时产生的,并非实质使用。条件 product_condition NOT IN ["used"] 怎么判断?
graph LR
subgraph 场景1["场景一:时间边界"]
direction TB
S1A["用户 23:58 提交申请"]
S1B["系统 00:02 处理"]
S1C["条件判断: 7天2分 > 7天"]
S1D["结果: 拒绝退款<br/>❌ 业务荒唐"]
S1A --> S1B --> S1C --> S1D
end
subgraph 场景2["场景二:模糊语义"]
direction TB
S2A["商品有轻微痕迹"]
S2B["用户声称: 检查所致"]
S2C["条件: NOT IN ['used'<br/>无法判断"]
S2D["结果: 需语义理解<br/>❌ ABC 无法处理"]
S2A --> S2B --> S2C --> S2D
end
R1["CBC 语义: 7日内=合理时间窗口<br/>实质使用=需要场景判断"]
R2["ABC 执行: 精确计时<br/>布尔判断"]
场景1 --> R1
场景2 --> R1
R1 -->|失真| R2
R2 --> 场景1
R2 --> 场景2
style S1A fill:#e1f5ff,stroke:#0288d1,color:#01579b
style S1B fill:#e1f5ff,stroke:#0288d1,color:#01579b
style S1C fill:#fff9c4,stroke:#fbc02d,color:#f57f17
style S1D fill:#ffebee,stroke:#d32f2f,color:#b71c1c
style S2A fill:#e1f5ff,stroke:#0288d1,color:#01579b
style S2B fill:#e1f5ff,stroke:#0288d1,color:#01579b
style S2C fill:#fff9c4,stroke:#fbc02d,color:#f57f17
style S2D fill:#ffebee,stroke:#d32f2f,color:#b71c1c
style R1 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style R2 fill:#e1f5ff,stroke:#0288d1,color:#01579b
ABC 没有答案,因为”实质使用”是一个需要语义理解的概念,不是一个布尔值。
这两个场景,都是因为 CBC 的语义没有被正确地转化进 ABC,导致 Agent 在边缘情况下做出”技术正确、业务错误”的决策。
四、语义编译器:一个被拆解的转化过程
我们现在知道问题了:CBC 和 ABC 之间存在语义损耗,损耗发生在”全知描述”向”执行指令”的转化过程中。
graph LR
subgraph 输入["输入层"]
CBC["CBC 本体定义<br/>Context/Behavior/Constraint<br/>+ 隐性业务语义"]
end
subgraph 处理["语义编译器"]
direction TB
STEP1["第一步: 显性化<br/>Formalization<br/>标注不确定性等级"]
STEP2["第二步: 注入<br/>Injection<br/>生成 SemanticHint"]
STEP3["第三步: 迭代<br/>Evolution<br/>判例法驱动进化"]
STEP1 --> STEP2 --> STEP3
end
subgraph 输出["输出层"]
ABC["ABC 执行指令<br/>Actor/Behavior/Condition<br/>+ 置信度阈值"]
end
subgraph 效果["效果"]
RESULT["语义损耗最小化<br/>边缘场景可控"]
end
CBC --> STEP1
STEP3 --> ABC
ABC --> RESULT
style CBC fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style STEP1 fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
style STEP2 fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
style STEP3 fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
style ABC fill:#e1f5ff,stroke:#0288d1,color:#01579b
style RESULT fill:#e8f5e9,stroke:#388e3c,color:#1b5e20
那么,问题变成:如何构建一个转化机制,让语义损耗最小化?
先澄清一个误解:语义编译器不是一个软件,不是一个服务,也不是一个你可以 npm install 的包。
它是一个转化过程,而这个过程,恰好可以被分解为三个有序的步骤。
第一步:显性化(Formalization)——标注而非消除模糊
CBC 里有大量”人类默认懂”的表达。
“7 日内”——人类知道这是模糊的善意承诺,不是精确计时。
“实质使用”——人类知道这需要结合场景判断,不是布尔值。
“大额订单”——人类知道这是相对概念,依赖品类和客户等级。
显性化的工作,就是把这些隐性共识翻译成可被计算的边界。
但注意:翻译不等于精确化。这一步的产物不是 order_amount > 10000,而是:
Formalized:
large_order:
definition: "单笔金额超过该品类历史均值的 3 倍"
rationale: "非绝对值,避免因品类差异导致的误判"
uncertainty: HIGH # 标记这是一个高不确定性条件
注意 uncertainty 字段。显性化的结果不是消除模糊,而是把模糊标注出来,让后续步骤知道哪里需要特殊处理。
第二步:注入(Injection)——写给 LLM 的”判断上下文”
标注了不确定性之后,语义编译器做的第二件事是:把无法形式化的部分,以自然语言的形式注入到执行指令里。
这就是 SemanticHint (语义提示)字段存在的理由——但它不只是备注,它是给 Agent 的 LLM 推理核心准备的”判断上下文”。
这里有一个微妙但关键的设计决策:
SemanticHint 写给谁看的?
它不是写给执行代码的,是写给 LLM 的。当 Agent 遇到 uncertainty: HIGH 的条件判断时,它不应该直接返回 true/false,而应该把当前场景连同 SemanticHint 一起交给 LLM 推理,让 LLM 给出一个带置信度的判断:
输入:
- 当前条件:product_condition = "有轻微痕迹,用户声称检查所致"
- SemanticHint:product_condition 的判断应考虑正常检查造成的轻微痕迹,
判断标准是"实质性损耗"而非"完好如初"
- 历史参考:同类申请中,87% 的"检查痕迹"描述最终被判定为通过
输出:
- 判断:通过
- 置信度:0.79
- 理由:用户描述与历史通过案例高度吻合,痕迹描述符合正常检查特征
这个输出,才是 Agent 真正拿来决策的东西。0.79 低于置信度阈值 0.85,所以不自动执行,升级人工——但这个升级附带了 LLM 的分析,人工审核员不是从零开始判断,而是在一个有上下文的推荐结果上做确认。
这是语义编译器真正的价值:它没有消灭不确定性,而是把不确定性变成了可管理的、有迹可循的输入。
第三步:迭代(Evolution)——判例法驱动的本体进化
语义编译器不是一次性工作。
每一次 Agent 的执行,都是对编译结果的一次检验。每一次人工介入,都是一次隐性反馈——它在说:”这个场景,当前的 ABC 指令处理得不够好。”
成熟的语义编译器,会把这些反馈结构化地收集回来,形成一个本体进化循环:
graph LR
A[CBC 定义] --> B[语义编译<br/>显性化 + 注入]
B --> C[ABC 执行]
C --> D[边缘案例触发人工介入]
D --> E[人工决策记录为业务判例]
E --> F[判例反哺 CBC 或更新 SemanticHint]
F --> B
style A fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style B fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
style C fill:#e1f5ff,stroke:#0288d1,color:#01579b
style D fill:#fff9c4,stroke:#fbc02d,color:#f57f17
style E fill:#ffebee,stroke:#d32f2f,color:#b71c1c
style F fill:#e8f5e9,stroke:#388e3c,color:#1b5e20
注意这个循环里最重要的一步:人工决策被记录为”业务判例”。
这不是普通的日志,这是法律意义上的”判例法”逻辑——每一次边缘决策,都在扩充本体的”隐性知识库”,让下一次同类场景的 SemanticHint 更丰富、置信度更高、需要人工介入的概率更低。
随着判例积累,语义编译器的产物质量会持续提升。Agent 处理边缘情况的能力不是靠模型升级来的,而是靠业务判例的沉淀来的。这才是企业 AI 系统真正的护城河。
三步之后,语义编译器长什么样
graph TB
subgraph 输入["语义编译器输入"]
I1["CBC 本体定义"]
I2["显性规则"]
I3["隐性背景"]
I4["历史判例"]
end
subgraph 处理["编译处理流程"]
direction TB
P1["识别可形式化条件<br/>→ Condition 列表<br/>→ 标注不确定性等级"]
P2["识别无法形式化部分<br/>→ SemanticHint<br/>→ 嵌入历史判例"]
P3["设定置信度阈值<br/>→ 升级策略"]
end
subgraph 输出["ABC 执行指令"]
O1["Condition"]
O2["SemanticHint"]
O3["置信度阈值"]
O4["升级路径"]
end
subgraph 属性["可审计性"]
A1["业务人员审查 SemanticHint"]
A2["技术人员审查 Condition"]
A3["管理者查看置信度分布"]
end
I1 --> P1
I2 --> P1
I3 --> P2
I4 --> P2
P1 --> P3
P2 --> P3
P3 --> O1
P3 --> O2
P3 --> O3
P3 --> O4
O1 --> A1
O2 --> A1
O1 --> A2
O3 --> A3
style I1 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style I2 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style I3 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style I4 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style P1 fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
style P2 fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
style P3 fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
style O1 fill:#e1f5ff,stroke:#0288d1,color:#01579b
style O2 fill:#e1f5ff,stroke:#0288d1,color:#01579b
style O3 fill:#e1f5ff,stroke:#0288d1,color:#01579b
style O4 fill:#e1f5ff,stroke:#0288d1,color:#01579b
style A1 fill:#e8f5e9,stroke:#388e3c,color:#1b5e20
style A2 fill:#e8f5e9,stroke:#388e3c,color:#1b5e20
style A3 fill:#e8f5e9,stroke:#388e3c,color:#1b5e20
把三步合在一起,语义编译器的完整形态是:
输入:CBC 本体定义(包含显性规则 + 隐性背景 + 历史判例)
处理:
1. 识别所有可形式化的条件 → 生成 Condition 列表,标注不确定性等级
2. 识别所有无法形式化的部分 → 生成 SemanticHint,嵌入历史判例
3. 根据不确定性等级 → 设定置信度阈值和升级策略
输出:ABC 执行指令(Condition + SemanticHint + 置信度阈值 + 升级路径)
它不是一个黑盒,它是一个有明确输入输出、可审计、可迭代的转化机制。
业务人员可以审查它的 SemanticHint 是否准确表达了自己的意图;技术人员可以审查它的 Condition 是否正确形式化了业务规则;管理者可以通过置信度分布和升级频率,判断系统整体的成熟度。
这就是语义编译器凭什么成立的答案:它不是靠魔法,靠的是把”翻译”这件事拆解成可操作、可验证、可进化的三步。
五、这不只是技术问题,这是组织问题
graph TB
subgraph 传统模式["传统软件工程模式"]
direction TB
T1["业务人员"]
T2["需求文档"]
T3["技术人员"]
T4["代码实现"]
T1 --> T2 --> T3 --> T4
T5["特点: 翻译无损<br/>业务不介入执行层"]
end
subgraph 协作模式["Agent 系统协作模式"]
direction TB
B1["业务人员"]
B2["技术人员"]
B3["共同协作"]
B1_1["定义 CBC"]
B1_2["显性规则"]
B1_3["隐性精神"]
B2_1["编译 ABC"]
B2_2["条件形式化"]
B2_3["SemanticHint 提炼"]
B3_1["编译结果共识"]
B3_2["反馈迭代"]
B1 --> B1_1
B1 --> B1_2
B1 --> B1_3
B2 --> B2_3
B2 --> B2_1
B2 --> B2_2
B1 --> B2_3
B1_1 --> B3
B1_2 --> B3
B1_3 --> B3
B2_1 --> B3
B2_2 --> B3
B2_3 --> B3
B3 --> B3_1
B3 --> B3_2
B5["特点: 翻译有损<br/>需要业务人员参与"]
end
RESULT["协作机制处理<br/>'没有写下来的理解'"]
T4 --> RESULT
B3_2 --> RESULT
style T1 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style T2 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style T3 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style T4 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style T5 fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
style B1 fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
style B2 fill:#e1f5ff,stroke:#0288d1,color:#01579b
style B3 fill:#e8f5e9,stroke:#388e3c,color:#1b5e20
style B1_1 fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
style B1_2 fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
style B1_3 fill:#f3e5f5,stroke:#7b1fa2,color:#4a148c
style B2_1 fill:#e1f5ff,stroke:#0288d1,color:#01579b
style B2_2 fill:#e1f5ff,stroke:#0288d1,color:#01579b
style B2_3 fill:#fff59d,stroke:#f57f17,color:#b71c1c
style B3_1 fill:#e8f5e9,stroke:#388e3c,color:#1b5e20
style B3_2 fill:#e8f5e9,stroke:#388e3c,color:#1b5e20
style B5 fill:#e8f5e9,stroke:#388e3c,color:#1b5e20
style RESULT fill:#fff9c4,stroke:#fbc02d,color:#f57f17
到这里,有人可能会问:语义编译器,是一个工具吗?还是一套方法论?
都不完全是。
它首先是一个组织共识的产物。
在传统软件工程里,业务人员提需求,技术人员实现——两者之间的”翻译”由技术人员完成,业务人员不介入执行层。这种分工在确定性系统里是合理的,因为技术翻译不会改变业务结果。
但在 Agent 系统里,翻译是有损的。技术人员在把 CBC 翻译成 ABC 的过程中,必然要做业务判断——而他们往往没有足够的业务上下文来做出正确判断。
真正的语义编译器,需要业务人员和技术人员共同参与:
业务人员负责定义 CBC——包括显性的规则,也包括隐性的”精神”;技术人员负责把 CBC 编译成 ABC——包括条件的形式化,也包括 SemanticHint 的提炼。两者在编译结果上达成共识,并在 Agent 运行后的反馈中持续迭代。
这个协作机制,比任何工具都重要。因为工具处理的是”写下来的规则”,而协作机制处理的是”没有写下来的理解”。
六、范式转移的真正含义
让我们回到最开始那个困境:为什么花了三个月建本体,Agent 还是乱跑?
现在答案很清晰了:因为他们把两件事混淆了。
CBC 是业务世界的宪法,用来定义”什么是对的”。
ABC 是 Agent 世界的法规,用来规定”怎么做才对”。
宪法写得再完美,也不能直接当操作手册用。从宪法到法规,需要一个立法过程——这个过程本身,是专业的、有损的、需要持续维护的。
语义编译器,就是这个立法机制的技术实现。
而从”CBC 直接驱动 Agent”到”CBC 通过语义编译器生成 ABC 再驱动 Agent”的转变,是 Agent 工程走向成熟的必经之路。
这不是一个工具升级,这是一次思维方式的迁移:
从”让 Agent 理解我的业务语言”,到”为 Agent 建造一套它能理解的业务语言”。
后者,才是真正的智能体软件工程。
下一篇,我们聊语义编译器的具体实现路径——包括如何用 LLM 自动化完成部分编译工作,以及如何设计置信度阈值和升级机制。
参考资料:
- CBC-ABC 结构推演