一提到 Palantir,很多人会问:它卖的是大数据平台、知识图谱,还是 AI 看板?
先别急着接受任何一个答案。假设你在凌晨 3 点收到一条安全告警:数据散在七八个系统里,页面都能打开,为什么还是无法做出可靠决策?如果把这些数据搬进图数据库,问题就解决了吗?即使关系找到了,谁有权修改对象、修改怎样回写业务系统、AI 又凭什么知道哪些操作合法?
这篇文章不先给定义,而是沿着这些问题推进。每一节先提出一个必须回答的问题,再用 Foundry / Gotham 的公开文档、工程博客与开源 SDK 检验答案。读完后,你应能自行判断:Palantir Ontology 究竟解决什么、它不解决什么,以及你的业务是否值得采用这套模型。
暂时保留一个待验证的假设:Palantir 的数据本体既不等于 OWL 文件,也不等于一张图数据库;它可能是把对象、关系、受治理动作与权限组织成统一运营接口的一层。下面逐步检验它。
1、为什么统一看板仍不能回答一条凌晨 3 点的告警?
假设你是自来水公司的安全分析员。凌晨 3 点弹出一条告警:
北区水厂余氯掉到危险低值。
传统做法是打开七八套系统:SCADA 看传感器、门禁看谁刷了卡、HR 查承包商、SIEM 看有没有人登 PLC、市民投诉看有没有人喊水有味道、邮箱翻有没有人问过加氯参数、维修工单看有没有人动过设备。
四五个小时对完,你可能还是对不上。麻烦的还在这里:那个凌晨 02:47 刷卡进来的承包商,三周前发过一封问 PLC 配置的邮件------这两件事分别躺在门禁库和邮箱里,中间隔着两套系统、两个部门、两种权限。你大概率发现不了。
如果只是把七个系统的图表拼到一页上,承包商、门禁记录、PLC 登录和余氯传感器仍然是四种彼此独立的记录。你能看见更多页面,却还要自己判断它们是否指向同一个人、同一设施和同一事件。
那么,缺的究竟是第八个看板,还是一套让不同记录指向同一现实对象、并声明对象之间关系的语言?Palantir 的回答是后者:先把数据组织成同一套对象和链接。

一次沿着链接走,就能把人、公司、区域、水厂、登录和传感器串起来。
Gotham 公开材料里,这套对象就这几类:人、组织、地点、文档、事件,以及把它们连起来的关系。Foundry 把同一套想法用到企业运营上,对象从"人 / 事件 / 设施"换成"订单 / 工厂 / 航班",问法没变。
它值钱的点倒不在界面有多炫,而是把问题从"我有哪些表"换成了"这些东西怎么连在一起,我能对它们做什么"。
最危险的线索,往往不是某条记录本身,而是你已经见过、但从未并排放在一起的那几条关系。
2、对象连起来以后,为什么仍不足以支撑决策?
Palantir 有两条产品线,外面常混着讲。底层是同一套方法论,只是对象更偏调查还是更偏运营。
| 产品 | 主要用户 | 本体叫法 | 在干什么 |
|---|---|---|---|
| Gotham | 情报、国防、执法 | Dynamic Ontology | 把人、地点、事件、文档织成一张可调查的图 |
| Foundry + AIP | 企业运营 | Foundry Ontology | 把工厂、订单、航班、客户做成组织的数字孪生 |
官方有一句很关键:
An Ontology is a categorization of the world.
如果本体只是对世界分类,它和一份更好的数据目录有什么根本不同?关键不在于它是否"描述"对象,而在于这份描述能否让人和系统基于同一套对象完成受控决策。
因此,本体是对世界的分类,不是对数据库的分类;但只看到"分类"还不够。2024 年那篇 Connecting AI to Decisions with the Palantir Ontology 把决策拆成三块:
Data 用来做决定的信息,包括人在操作时留下的"决策数据"
Logic 怎么评估一个决定:规则、优化器、模型、人的判断
Action 决定怎么落地:改对象、回写业务系统、留下审计

现在再问一步:如果系统能告诉你"某承包商关联某水厂",它能否安全地批准停机、创建案件或回写 ERP?若不能,图只是可读的事实集合,还不是运营层。
对象和链接是名词,动作是动词,人和 AI 用逻辑把名词和动词拼成句子。社区里有人说得更白:
Ontology 是组织的 API。不要把源系统的表原样 sync 上来。对象和动作必须能支撑真实决策。
所以它既不是数据目录,也不是普通语义层。数据目录告诉你"库里有哪些表",语义层告诉你"字段是什么意思",Palantir 的本体还得接着往下回答:
这个对象对应现实里的哪个人 / 哪座厂 / 哪张订单?
它和别的对象怎么连?
谁能改它?改完会触发什么?
分析员、应用、AI 是不是都在用同一套对象说话?
可以看成三层:
css
应用层 Browser / Graph / Gaia / Workshop / AIP / Object View
本体层 对象 · 属性 · 链接 · 动作 · 函数 · 权限 ← 真正的产品
数据层 dataset、虚拟表、流、文档、模型

中间那一层才是方法的核。上面的页面可以换,下面的数据源也可以换,唯独中间那套世界模型尽量别动。分析员问的是"这个承包商还碰过哪些水厂",不是 JOIN badge_logs ON ...。
Gotham 把这套叫 Dynamic Ontology,动态的意思写在 G-Cloud 服务说明里:领域会变,说明书要能跟着长,结构化数据和非结构化数据都能映射进来。不是把世界写死在一堆业务类里。
3、它是知识本体、关系数据库,还是图数据库?
听到 Ontology,你会不会立刻想到 OWL、RDF、TBox / ABox?如果会,接着追问:Palantir 用户是在编写逻辑公理,还是在定义业务对象、链接和受治理操作?
别被同一个词带偏。知识工程里的 Ontology 常常指 OWL、RDF、TBox / ABox;Palantir 借用了这个词,但产品语言不是那一套。
官方类型参考里写过:Foundry 的数据类型从 RDF、OWL、XSD 里吸收过灵感。但你在平台上写的不是 Turtle 公理,而是这些东西:
| 官方概念 | 是什么 | 类比 |
|---|---|---|
| Object type | 现实里一类实体或事件的 schema | 一张"业务表"的类型 |
| Object | 一个具体的人、厂、订单 | 一行 |
| Object set | 一堆对象,可以按条件动态更新 | 一个过滤结果集 |
| Property | 对象的特征 | 一列 |
| Shared property | 多种对象共用的属性定义 | 可复用字段 |
| Link type | 两种对象之间的关系,两边都能走 | JOIN,但有两边的 API 名 |
| Action type | 一次受控变更,可带副作用 | 受治理的写操作 |
| Function | 对着对象跑的代码逻辑 | 服务端函数 |
| Interface | 多种对象共用的形状 | 多态接口 |
| Role / Marking | 谁能看见、谁能改 | 写进模型的权限 |
这些概念之间怎么关联,画出来是这样:

TBox / ABox 当类比还能用:类型和约束是语法,具体事实是句子。只是别把 OWL 的 subClassOf、minCardinality 直接当成 Palantir 在跑的东西。Palantir 解决"水厂也是一种设施"的官方办法,是 Interface :Facility 规定名字和位置,Airport、Manufacturing Plant 去实现它,再各自加自己的属性。
再追问一个容易混淆的点:RDF/OWL 的有向谓词能不能表达反向关系?当然可以,例如用 inverseOf;差别不在于"能否双向",而在默认产品体验。
Foundry 的 link type 在 API 中原生暴露双端、可遍历的名称:Flight ↔ Aircraft 一边叫 assignedAircraft,另一边叫 flights。代码里 flight.assignedAircraft.get() 和 aircraft.flights.all() 走的是同一条链接的两面。
和常见方案比一下就清楚了:
| SQL Schema | 数据目录 | 向量库 | Palantir 本体 | |
|---|---|---|---|---|
| 描述对象 | 表和列 | 表的注释 | 一段文本的向量 | 现实世界的对象类型 |
| 描述关系 | 外键,要提前写 JOIN | 血缘,偏管道 | 没有一等关系 | 双边可遍历的链接 |
| 约束 | NOT NULL / FK | 很少 | 无 | Value type、动作条件、接口约束 |
| 怎么改世界 | UPDATE,权限在库外 | 不管 | 不管 | Action + 审计 + 回写 |
| AI 怎么用 | 把 DDL 塞进 prompt | 几乎用不上 | 找"长得像"的段落 | 类型化对象和动作,OSDK 生成客户端 |
那么,SQL 能不能存人、厂、事件,也能不能完成多跳 JOIN?当然能。差别不是关系库没有关联能力,而是每次查询都可能要重新处理跨系统的实体含义、JOIN 路径、权限和写入规则。
本体把链接作为一等业务概念:路径沿已经声明、命名和治理的关系走出来;应用与 Agent 面对的是对象 API,而不是每次临时拼出的 SQL。
4、谁定义对象,谁又有权改变它们?
如果对象只对应一行数据,为什么还要专门定义 Action?又为什么把权限、审计和回写放进同一节讨论?先带着这两个问题看下面的对象、链接与动作。
Foundry 里对象不是抽象概念,通常需要映射到 backing datasource。Employee 对象类型可以背靠员工目录 dataset;为便于理解,常可把一条记录视为一个对象,但对象模型并不等于物理表的一一翻版。多对多链接也可以有 backing 表。主键官方要求是 string,而且必须由这个对象自己的属性构成,不能靠"按标题排序的名次"这种会变的东西。
他们开源的 @osdk/maker 把这件事写成了 TypeScript。最小定义大概长这样:
php
import { defineObject, defineLink } from "@osdk/maker";
const person = defineObject({
apiName: "person",
displayName: "Person",
pluralDisplayName: "People",
titlePropertyApiName: "name",
primaryKeyPropertyApiName: "id",
properties: {
id: { type: "string" },
name: { type: "string" },
role: { type: "string" },
},
});
const facility = defineObject({
apiName: "facility",
displayName: "Facility",
titlePropertyApiName: "name",
primaryKeyPropertyApiName: "id",
properties: {
id: { type: "string" },
name: { type: "string" },
status: { type: "string" },
},
});
const event = defineObject({
apiName: "event",
displayName: "Event",
titlePropertyApiName: "description",
primaryKeyPropertyApiName: "id",
properties: {
id: { type: "string" },
description: { type: "string" },
severity: { type: "integer" },
facilityId: { type: "string" },
},
});
// 一边叫 occursAtFacility,另一边叫 events
defineLink({
apiName: "eventOccursAtFacility",
one: {
object: facility,
metadata: { apiName: "events", displayName: "Event" },
},
toMany: {
object: event,
metadata: { apiName: "occursAtFacility", displayName: "Facility" },
},
manyForeignKeyProperty: "facilityId",
});
供水这个域里,对象和链接可以对成:
| 链接 | 两边 | 含义 |
|---|---|---|
eventOccursAtFacility |
Event ↔ Facility | 事件发生在哪 |
eventInvolvesPerson |
Event ↔ Person | 谁卷入了 |
personBelongsToOrg |
Person ↔ Organization | 谁给哪家干活 |
orgOperatesInLocation |
Organization ↔ Location | 公司作业区 |
personConnectedToPerson |
Person ↔ Person | 认识 / 共事 |
facilityHasSensor |
Facility ↔ Sensor | 厂里装了什么表 |
caseLinkedEvent |
RiskCase ↔ Event | 案件的证据链 |

动作类型才是动能层。官方定义:一次 Action 是一组对对象、属性、链接的受控编辑,提交时可以带副作用。Gotham 里分析员在 Browser 里改对象、加笔记、看变更历史,走的也是这条路。Foundry 里更常见的是"改航线""批准索赔""把设备停机",写回 ERP,并留下谁在哪一版数据上做的决定。
缺了动作,本体只是一张静态地图;加上动作,它才变成一套操作系统。
Gotham 工作区把同一份对象资产切成不同看法:Graph 看网络,Gaia 看地理,Browser 看单个对象,Dossier 出报告。Foundry 对应的是 Object Explorer、Object View、Workshop、Quiver。页面不同,对象是同一批。
5、把图存下来以后,谁保证它仍是同一份说明书?
若每个应用各自缓存对象、各自解释权限、各自直接更新底表,前面定义的本体会迅速重新碎裂。那么类型、实例、读路径和受控写入在平台中如何衔接?
说明书不能只躺在文件里。Foundry 官方后端不是一张 Neo4j,而是一组微服务:

各块职责可以对上官方文档:
| 服务 | 干什么 |
|---|---|
| OMS | 对象、链接、动作这些类型的真理源 |
| Object Database | 索引后的对象实例,OSv1 叫 Phonograph,现在主推 OSv2 |
| OSS | 读路径:搜索、过滤、聚合、加载对象集 |
| Funnel | 把 dataset 和 Action 编辑编进对象库,并跟着源数据更新 |
| Actions | 受控写,带权限和动作日志 |
| Functions on Objects | 对着对象跑的业务逻辑 |
OSv2 把索引和查询拆开,方便横着扩。公开文档曾给出单对象类型可达百亿级索引吞吐、一次 Action 默认可改 1 万个对象、Search Around 默认 10 万个对象、单个对象类型最多 2000 个属性等数字;这些配额与限制会随产品版本和部署配置变化,应以当前官方文档为准。Gotham 更早的存储层里,开源过 AtlasDB:在 KV 存储上补事务和索引,给调查型读写用。
所以"本体驱动"四个字,官方落地是:
OMS 里改类型
→ 映射、校验与索引按新 schema 更新
→ 更新完成后,OSS / OSDK / AIP 按新对象和链接说话
→ Action 继续走同一套权限与治理

不是"改完 OWL,再手写一批 Cypher"。最小实现可以先用属性图顶上对象库,但心里要清楚:Palantir 卖的是索引过的对象层,不是通用图查询引擎。
他们自己开源、能对照实现细节的,主要是这些:
| 仓库 | 你能看到什么 |
|---|---|
| palantir/osdk-ts | @osdk/maker 用代码定义对象、接口、链接、动作;生成 TypeScript 客户端 |
| palantir/foundry-platform-python | 平台级 API:管 Ontology 资源本身 |
| palantir/gotham-platform-python | Gotham 应用和数据,Gaia、Target Workbench、地理时间数据 |
| palantir/atlasdb | Gotham 用过的事务型 KV 层 |
官方自己也划了界限:碰对象、链接、动作,用 Ontology SDK;碰平台管理,用 Foundry Platform SDK;碰 Gotham 应用,用 Gotham Platform SDK。OSDK 的口号是:
An SDK of your ontology is an SDK of your business.
最小实现按这个顺序长就行,不必一上来仿整套微服务:
markdown
1. 写下世界里有什么 对象 / 链接 / 动作,哪怕只是一份类型表
2. 把实例编成可查询层 对象库或属性图,主键用字符串
3. 把异构证据对齐到对象 源数据挂 backing,全文检索用同一套对象 ID
4. 写走 Action,读走对象集 不要让应用直接 UPDATE 底表
闭环在不在,比用不用 Neo4j 重要:类型系统变了,走路的人要立刻按新地图走。
| 硬编码规则 | 本体驱动 | |
|---|---|---|
| 新对象类型 | 改代码、改表、发版 | 改 OMS / maker 定义,重新索引 |
| 新关系 | 新 DAO、新接口 | 加一条双边链接 |
| 校验 | 业务里堆 if-else | Value type、动作条件、函数 |
| AI 查询 | 靠模型记忆或猜字段名 | 先读类型,再调 OSDK / Action |
| 关联分析 | 只能走写死的路径 | Search Around / 沿链接展开 |
6、邮件、日志和照片怎样证明自己说的是同一个对象?
如果把所有文件丢进搜索引擎,能找到文本是否就等于完成融合?如果一个名字在门禁、邮件和 HR 系统中指向不同人,本体上的链接又还能相信吗?
情报不来自一个库。真实水厂里,监控转写、维修报告、化验单、人员档案、SCADA 日志、邮件、监管检查、现场照片、门禁、库表导出,分属运营、安保、HR、实验室、IT。
Gotham 的公开说法是:不管格式和体量,先把结构和非结构数据变成对象、属性和关系。搜索是统一入口,外部系统可以联邦进来,分析员可以把外部记录 promote 进来,跟已经在本体里的对象焊在一起。每条数据还拴回原始源,权限可以打到对象的单个属性上,比如一座楼的地址、一辆车的型号。
Foundry 这边更工程:dataset、虚拟表、流先清洗,再在 Ontology Manager 里映射成对象类型,Funnel 负责编进去。对象可以挂多个数据源,OSv2 支持列级 / 属性级权限。
最小实现不必上联邦和 promote,但结构不能省成"扔进一个大盘再搜":

搜余氯加厂名时,你要同时看到传感器事件、SCADA 日志、门禁和邮件,而且每一份都能指回同一个 Facility、同一个人。搜索负责找证据,链接负责串关系。
文本进搜索,对象进本体,两者用同一套 ID 对齐。融合不是把文件丢进一个大盘,而是让每份证据都能指回某个对象。
再问:找到证据的人是否必然有权看到全部证据?不是。Gotham 和 Foundry 可在本体语义层表达 marking、对象级 / 属性级策略与目的控制,避免把访问控制完全留到查询之后;最终权限仍会与底层数据权限和平台策略共同作用。@osdk/maker 里甚至有专门的 marking 属性类型。最小实现至少先让每份证据带着密级字段,后面才能长成字段级 ACL。
7、沿着关系走得更远,得到的是线索还是结论?
两个人隔着六跳相连,是否就意味着他们有关联?一次异常会波及整张图时,什么权重、时间窗口和证据质量足以支持行动?
图存下来之后,调查要回答两句话:这两个对象中间隔着什么?一个点出事会关系到谁?
Gotham 服务说明里写明的分析能力是:link analysis、地理分析、话单分析、对象分析。工作区里从 Graph 把一簇人拖到 Gaia,再写进 Dossier。Foundry 对应的读能力叫 Search Around:从一批对象出发,沿链接展开。默认上限 10 万个对象,再大要走 Spark 查询层。
官方没有把"带衰减的 BFS 风险传导"写成公开算法。那是把"事件发生之后会关系到谁"收成最小实现时的一种拆法,别当成 Gotham 内部公式。
关联发现的最小核,就是沿着已经声明的链接找路。属性图上可以写成最短路;对象层上就是一层层 Search Around。
scss
# 这是最小复刻,不是 Foundry 的查询语言
MATCH path = allShortestPaths((a)-[*..6]-(b))
WHERE id(a) = $idA AND id(b) = $idB
RETURN path
LIMIT 5
长度 1 是明线,长度大于 1 是暗线。相关度可以先做得很粗,就用 1 / pathLength。边的组合自己会长出语义:
| 类型 | 路径在说什么 |
|---|---|
| 组织链 | 两人没有直接边,但同属一家公司 |
| 人员汇合 | 两人同时出现在同一异常事件 |
| 共享资产 | 两座厂用同一型号 PLC,一个被打,另一个同构 |
| 物质对上 | 两座厂的异常都指向氯 |
| 传感器-人 | 人没有直接连传感器,但通过"事件发生在厂、厂有传感器"连上 |
| 地理三角 | 两座厂在同一作业区,事件在区内成片 |

"会关系到谁"的最小算法,是带边权的 BFS。边权写在链接类型上:现场卷入热,文档里提到凉。衰减可以先取 0.6,低于阈值就剪掉。这是模拟冲击波,别当成 Palantir 论文里现成的公式。
scss
propagatedRisk(n) = parentRisk × 边权 w_r × 衰减^深度
检测也可以先挂规则:同一设施短时间多条高严重度事件、物理和网络告警碰头、夜间未授权访问。规则打已知套路,模型补未知异常。官方平台里这块会变成 Action、函数和 AIP 工作流,最小实现先别训分类器。
8、最小实现
如果只写几十行图遍历代码,是否就实现了 Palantir Ontology?显然没有;但它能否帮助我们验证"类型、链接、路径和传导"这组最小思想?
把产品外壳剥掉,这套方法论的最小内核可以先收成:类型、链接、路径、传导。下面这段不依赖 Foundry,能把"找暗线 / 看冲击波"跑通。
但先限定它的含义:这不是 Palantir 源码,也不复刻对象存储、对象集查询、权限、审计、事务、Action 语义或实体对齐;它只用来检验"显式类型与关系能够支持路径分析"的方法核。
css
from collections import defaultdict, deque
# 类型表:世界上有什么,以及链接的传导权重
NODE_TYPES = {"Person", "Facility", "Event", "Organization"}
EDGE_WEIGHT = {
"OCCURS_AT": 0.95,
"INVOLVES_PERSON": 0.90,
"BELONGS_TO": 0.75,
"CONNECTED_TO": 0.80,
"OPERATES_IN": 0.70,
}
nodes = {
"PER-023": ("Person", "Dmitri"),
"PER-067": ("Person", "Carlos"),
"ORG-01": ("Organization", "AquaServ"),
"FAC-01": ("Facility", "北区水厂"),
"FAC-02": ("Facility", "南区泵站"),
"EVT-01": ("Event", "PLC 登录"),
"EVT-02": ("Event", "余氯骤降"),
"EVT-03": ("Event", "南区夜间门禁"),
}
edges = [ ("EVT-01", "OCCURS_AT", "FAC-01"), ("EVT-01", "INVOLVES_PERSON", "PER-023"), ("EVT-02", "OCCURS_AT", "FAC-01"), ("EVT-03", "OCCURS_AT", "FAC-02"), ("EVT-03", "INVOLVES_PERSON", "PER-067"), ("PER-023", "BELONGS_TO", "ORG-01"), ("PER-067", "BELONGS_TO", "ORG-01"), ("PER-023", "CONNECTED_TO", "PER-067"),]
graph = defaultdict(list)
for src, rel, dst in edges:
graph[src].append((rel, dst))
graph[dst].append((rel, src)) # 链接按双边走
def hidden_paths(src, dst, max_depth=6):
q = deque([(src, [src])])
seen = {src}
found = []
while q:
node, path = q.popleft()
if node == dst and len(path) > 2:
found.append(path)
continue
if len(path) > max_depth:
continue
for _, nxt in graph[node]:
if nxt in path:
continue
if nxt not in seen or nxt == dst:
seen.add(nxt)
q.append((nxt, path + [nxt]))
return found
def propagate(source, source_risk=9.0, decay=0.6, floor=0.1, max_depth=5):
risk = {source: source_risk}
q = deque([(source, source_risk, 0)])
while q:
node, parent_risk, depth = q.popleft()
if depth >= max_depth:
continue
for rel, nxt in graph[node]:
if nxt in risk:
continue
w = EDGE_WEIGHT.get(rel, 0.5)
nxt_risk = parent_risk * w * (decay ** (depth + 1))
if nxt_risk < floor:
continue
risk[nxt] = round(nxt_risk, 2)
q.append((nxt, nxt_risk, depth + 1))
return risk
print("Dmitri → 南区泵站 的暗线:")
for path in hidden_paths("PER-023", "FAC-02"):
print(" " + " → ".join(nodes[n][1] for n in path))
print("余氯事件的冲击波:")
for nid, score in sorted(propagate("EVT-02").items(), key=lambda x: -x[1]):
print(f" {nodes[nid][1]:8s} {score}")
跑完你会看到:Dmitri 和南区泵站没有直连,但能走出 Dmitri → Carlos → 南区夜间门禁 → 南区泵站。余氯事件的分数先关系到北区水厂(5.13),再传到同厂的 PLC 登录和 Dmitri;再往外很快掉到阈值以下。暗线负责"找得到",传导负责"够不够"。
再往上加,按官方顺序长,别按"先上图数据库"长:
类型表 + 内存图 + 最短路 + 传导
→ 对象 / 链接 / 动作写成 maker 那样的定义
→ 实例编进可查询层,主键用字符串
→ 全文索引用同一套对象 ID
→ 读走对象集,写走 Action
→ 函数和 marking 进模型
→ Agent 只碰类型化对象和动作

每加一层,问自己一句:它是在读同一份说明书,还是又写回了硬编码?
9、如果模型会写 SQL 或 Cypher,为什么还要先读本体?
模型能生成查询,并不等于它知道字段是否存在、关系是否允许遍历、操作是否获批。怎样让 Agent 在业务世界中"会说话",但不擅自编造或越权行动?
AIP 架在本体上面,方法核就一句:模型不是世界本身,本体才是。模型是翻译层。

和常见"让模型写 Cypher / SQL"不一样。Palantir 的走法是给模型类型化的对象和动作 :AIP Logic 的输入输出可以是 Ontology 对象,编辑必须走 Action,权限和人走同一套。OSDK 从 OMS 生成客户端,字段名、描述直接出现在编辑器里,模型不太有机会发明 INVOLVES_EVENT 这种不存在的边。
最小实现如果还没有代码生成,退一步也行:先把对象类型、链接方向、动作名单塞进上下文,只许用清单里的名字。温度压低,写操作扫掉,失败就把报错喂回去。这一步模仿的是 OSDK 的约束,跟 Gotham 的查询语言不是一回事。
调查 Agent 的工具也可以按官方能力来对齐:
sql
读 OMS / 类型表 世界上有什么
查对象集 / 搜对象 OSS 在干的事
沿链接展开 Search Around
搜对齐后的文档 统一搜索
提交 Action 立案、升级、回写
打开一个案件,循环大概是:先看类型,把案件挂着的事件、人、厂拉出来,接着问两个人认不认识,再去文档里找旁证。同一份对象,军事情报、公共安全、工艺运维看到的侧重点可以不同,地图必须是同一张。
本体是说明书,SDK 是翻译,对象层是事实源。Agent 不靠记忆编字段名,它先把类型系统读一遍。
这也解释了为什么"本体驱动的 AI"和普通 RAG 不是一回事:RAG 是找回一段像的文本,本体 Agent 是在类型化对象上走路,必要时提交一个受治理的动作。你加一种 suppliesChemicalsTo,下次调查会自动把它算进去,不用重训。
数据不出网也是这套方法的一部分。本体上挂的是人、设施、案件,查询本身就是情报。AIP 可以跑在客户私网里,模型可替换。最小实现用本地模型,倒不是本地一定更聪明,是说明书和事实源都不能离开这张网。
10、什么业务值得上本体,什么业务不值得?
如果所有数据问题都用本体解决,是否只是把复杂性换了一个名字?先换领域,再用同一组问题检验。
骨架不绑水。对象、链接、动作换一套,问法还是那三个。
| 领域 | 对象 | 关键链接 | 图在找什么 |
|---|---|---|---|
| 反欺诈 | 账户、设备、地址、交易 | 转到、共用设备、同住址 | 环、身份重叠 |
| 内部威胁 | 员工、系统、下载、外联 | 访问、导出、对外联系 | 越权链、泄密路径 |
| 供应链 | 供应商、零件、认证、物流 | 供货、认证、承运 | 假件链、单点依赖 |
| 反恐 | 人、地点、通信、资金 | 旅行、通话、转账 | 小组网络、行程汇合 |
| 医疗骗保 | 医生、病人、处方、索赔 | 开方、转诊、申赔 | 空壳诊所、处方作坊 |
官方设计原则里有几条很实用,比"先画企业级数字孪生"靠谱:
- 先写用户要做的决定。句子里的名词是对象,动词是动作。如果只是分析、从不改世界,数据可以先留在 dataset 里。
- 先做一个工作流端到端,包含 Action 和回写,再做第二个。
- 用业务语言。没法念成人话的类型名,多半不是好本体。
- 不要
Message_v2这种版本化类型名。成熟度用 Experimental / Active / Deprecated 标。 - 属性能放在父对象上就别在子对象上重复。
- 主键必须是字符串,且只由这个对象自己的属性构成。
判断一个领域值不值得上本体,就看你是不是经常问:
这两个看起来无关的东西,中间隔着几跳?
一个点出事,会关系到哪些点?
证据散落在邮件、日志、工单里,怎么指回同一批对象?
改完之后,谁批准、回写到哪、下次还能不能复盘?
如果日常查询都是"按主键查一行、按时间出报表",那上本体是杀鸡用牛刀;反过来,如果日常查询是"关联、传导、跨源对上、还要落地成动作",关系库会先把你逼疯。
11、在采纳前,你能回答这些问题吗?
到这里可以回看开头的假设:对象、链接、动作和权限可以把"看数据"推进到"做决策",但这不保证模型正确、更不保证组织能长期维护它。真要落地,先不要问"能不能画出图",而要回答下面五个反问。
(1)本体谁来维护?领域专家懂世界,工程师懂图。Palantir 把这件事做成了 Ontology Manager,类型还有负责人、健康检查、成熟度。自己做的时候,说明书很容易变成一份没人更新的文件,或者重新缩回代码里的硬编码。
(2)类型稳定性和业务变化怎么平衡?加链接容易,改链接语义很难。CONNECTED_TO 今天是同事,明天混进了亲属和微信好友,传导权重还用同一套吗?官方建议别做版本化类型名,迁移要一次做完,说起来容易。
(3)暗线太多怎么办?6 跳在小图上好玩,Search Around 到 10 万对象也只是上限。相关度只用 1/length 太糙,还得叠时间、频率、边的可信度。
(4)非结构化抽取往往是最难的一公里。真文档要上 OCR、NER、指代消解、实体对齐。本体再漂亮,对象对不上,图就是一张错图。Gotham 能联邦和 promote,脏活并没有消失,只是被收进管道里。
(5)动能层怎么做才不危险?模型能读对象是一回事,模型能提交 Action 是另一回事。Foundry 把变更关进动作类型、函数和权限,还能先 stage 成 scenario 再提交。这层比调查层难很多。
这些问题没有标准答案。我自己的倾向比较保守:先把 20 个对象类型和几十条链接写对,把两三个最痛的源融进来,让人能沿着链接走通一条暗线,最后再补一个真正会改世界的 Action。等说明书真的被分析员天天用,再谈 Agent 自动立案。
反正,别一上来就画一张"企业级数字孪生"的大图。
参考
(1)palantir.com/docs/foundr... (Foundry Ontology 官方概述)
(2)palantir.com/docs/foundr... (对象、属性、链接、动作、函数、接口)
(3)palantir.com/docs/foundr... (OMS / OSS / Funnel / Actions / OSv2)
(4)palantir.com/docs/foundr... (Ontology SDK)
(5)blog.palantir.com/connecting-... (决策中心:数据、逻辑、动作)
(6)blog.palantir.com/building-wi... (OSDK 是业务的 SDK)
(7)github.com/palantir/os... (@osdk/maker,用代码定义本体)
(8)github.com/palantir/fo... (Foundry 平台 SDK)
(9)github.com/palantir/go... (Gotham 平台 SDK)
(10)github.com/palantir/at... (Gotham 用过的事务型 KV 层)
(11)community.palantir.com/t/ontology-... (本体设计原则)
(12)assets.applytosupply.digitalmarketplace.service.gov.uk/g-cloud-14/... (Gotham G-Cloud 服务说明:Dynamic Ontology、Graph、Gaia、Browser)