p-memory 0.2.3

Embedded memory, knowledge graph, and note storage for Rust and Python
Documentation
# 知识图谱生成


本文件说明**如何从文本生成知识图谱**——也就是「从一篇文档到实体与关系」这一步的标准。它是[数据模型](data-model.md)里实体/关系/事件三张表**上游**的约定。

一句话定位:

> **先定生成标准,再谈落库。图是标准的产物。**

## 1. 这一层管什么、不管什么


图谱在入口就已经定型。如果「从文本抽关系」这一步没有标准,每一步都是自由发挥,落库的东西结构各不一样,后面的清洗怎么补都补不回来。

这一层只定**生成格式**,也就是「一条关系长什么样、方向怎么锁」。它**不定**下面这些:

| 不管 | 归属 |
|---|---|
| 实体消解成谁 | 生成之后的归并步骤(同名返回候选、不自动合并,见 [data-model]data-model.md|
| 关系词/角色词/类型词表 | 数据,放配置或后处理归一,**不进生成语法** |
| 语义类别(这是动作还是身份) | 消费端解释,**生成端不判** |
| 出处怎么定位到切片 | 笔记层的 `notes`/`chunks`,见 [data-model]data-model.md |

**核心原则:生成端只负责把「方向」和「内容」填对,交出一条三元式;语义、类别、解释全在消费端。**

方向不靠 LLM「理解」语义来判,靠**三元式的位次**锁死——主体在前、客体在后,一条三元式只有一个读法。定义一次,方向就是语法的一部分。

## 2. 生成格式:三元式


一条关系输出四行:

```
主体: ...
谓词: ...
客体: ...
出处: ...
```

- `主体`:关系的起点实体。
- `谓词`:关系名(稳定的关系标签)。
- `客体`:关系的落点实体。
- `出处`:来源定位,每条关系各带一条。

一段一条,没有分支。

## 3. 方向:由位次决定


三元式只有一种读法:**主体 → 谓词 → 客体**。方向不靠语义判断,靠位置固定。

```
主体 甲 / 谓词 创造 / 客体 乙   →  甲创造了乙
主体 乙 / 谓词 创造 / 客体 甲   →  乙创造了甲
```

两行的词一样,位次一换,意思就反了——方向完全由谁在主体位决定。

- **有向**关系:主体是施动方,客体是受动方。
- **对称**关系(同事、合作):两端平级,**照写一条即可**,不必反向再写一条;对称性由谓词在消费端标记。

### 语义不标


动作还是身份,**不用标**——LLM 自己分得清「审判」是动作、「师傅」是身份。语法只有一个目标:让 LLM 生成得顺、填得准,所以形状唯一、位置好认、短。

`审判` 和 `父亲` 是同一个形状,方向都不会错。语义类别的维度是为了救方向才存在的;方向被位次锁死后,它就不再需要在生成端出现。

## 4. 样例


```
主体: 甲
谓词: 创造
客体: 乙
出处: docs/characters/lin-zhao/overview

主体: 丙
谓词: 审判
客体: 乙
出处: docs/plot/chapter-5

主体: 丁
谓词: 合作
客体: 戊
出处: notes/interviews/gu-qing
```

## 5. 与落库的衔接


生成端产出的是三元式,落库要把它转成 [data-model](data-model.md) 的结构:

```
文档 →【按标准生成三元式】→【消解成实体 id】→【写 entity / relation 表】→ 图
```

| 三元式 | 落库 |
|---|---|
| 主体 A / 谓词 C / 客体 B | `RelationInput { subject_id: A, predicate: C, object_id: B }` |

`subject_id` / `object_id` 是库分配的实体整数 id,因此落库前必须先完成实体消解;同名实体返回候选、不自动合并。