关系提取规则
本文只用虚构例子(合成数据生成器
alertalgo/synth.py 的环境)。中债只写汇总数字。界面示意画的是页面内容区,实际页面左侧还有约 220px 的导航栏。第一稿(单独一套全局关系提取规则、预填六条纵向关系、关系类型表、保存时作废)被用户否定:告警推出的关系本来就少、也不一定准,主战场是以后的 CMDB,不宜做复杂。第一稿见 git 历史(meta
842e29c)。1. 已定的决定(用户 2026-10-11)
| # | 决定 |
|---|---|
| R1 | 代码里不预置任何关系逻辑。现在代码按字段建的「对象 → 主机 / 业务系统 / 监控系统 / 站点」(中债库 B 上 5649 条)去掉,这几个值改作对象自己的属性,取自全局提取规则 |
| R2 | 模板与关系提取规则是 1:N:一条告警可以提取多条关系,每条关系各写起点、关系、终点的取法 |
| R3 | 起点不缺省为对象,也不限定是对象;没有全局关系规则,只在解析规则(模板)上写 |
| R4 | 关系是自由文本,可以是固定值,不限定在某张表里 |
| R5 | 终点不限定是对象,数据结构上不做约束;治理智能体的 SOP 里推荐起点、终点优先从对象里选 |
| R6 | 起点类型、终点类型可选,内容是自由文本;SOP 里推荐优先用对象类型表的类型 |
| R7 | (用户让按 R1–R6 判断)解析规则原来的 relations 段换成本文的关系提取列表;classify.call_fail(是否调用失败)一并去掉:关系既然是自由文本,代码里就不该有「调用失败」这类专门判断 |
| R8 | (第 9 节问题 1、4 的答复)对象不带「所在主机、所属系统、监控系统、站点」四个属性,先不显示;业务系统、监控系统、站点不再单独建对象。R1 里「改作对象属性」一句作废 |
| R9 | (问题 2)对象抽屉里,起点或终点文本与对象的键或某个标识相同(不分大小写)的关系都显示 |
| R10 | (问题 3)五段文本都相同才算同一条关系 |
| R11 | 对象类型就取 objectType 字段:配了规则且取到值就显示该值,否则是「未知」。objectType 的取法以后由治理智能体建议、确认后生效;告警本身有表示对象类型的列时,用户直接在全局提取规则里配。代码里「对象等于主机就记主机,否则记其他」的判断去掉,解析规则里单独的 classify.object_type 也去掉(模板里改对象类型就写字段规则 objectType) |
| R12 | (按 R8 推出,用户可否决)主机也不单独建对象:对象只来自 objectId 字段,标识只记对象标识本身;告警对象页去掉「显示辅助对象」开关 |
| R13 | (用户 2026-10-11 调整 R8)主机、系统、站点、监控系统都不作对象的属性。但主机和系统单独存:全局提取规则(及模板规则)里 host 和 system(业务系统)两个字段取到的值,按库去重存进数据库;界面上放在「告警对象」下,和「对象」子页签并列,加「主机」「系统」两个子页签显示对应的表格。站点、监控系统、app(应用)不存。(用户原话是 host 和 app,随后更正为 system,即业务系统) |
2. 一条关系提取规则
写在解析规则里,和字段提取规则放在一起,每个模板零到多条:
"relations": [
{"name": "网关报告调用清算服务失败",
"start": {"from": "host"},
"relation": {"const": "调用失败"},
"end": {"lookup": "code_system", "key": {"from": "content", "regex": "errorCode=(\\S+)"}},
"start_type": {"const": "主机"},
"end_type": {"const": "业务系统"}},
{"name": "网关调用支付接口超时",
"start": {"from": "host"},
"relation": {"const": "调用超时"},
"end": {"from": "content", "regex": "url=https?://([^/:]+)"}}
]
| 项 | 必填 | 写法 |
|---|---|---|
name | 否 | 给人看的一句话 |
start 起点 | 是 | 字段规则的六种写法之一(from、from+regex+format、const、first_of、lookup、map),from 先找原始列、再找标准字段 |
relation 关系 | 是 | 同上,多数写 const |
end 终点 | 是 | 同上 |
start_type、end_type | 否 | 同上,多数写 const |
每条告警逐条规则取值:起点、关系、终点三个都取到值,就记一条关系;缺一个,这条规则对这条告警不产出。取到的值只去掉首尾空白,原样保存。
代码不做的事:不补起点,不校验关系的写法,不把终点解析成对象,不按 IP 规划换 IP,不判断调用失败。要用语义约定(如错误码指向哪个系统),在规则里用 lookup 写明,如上例的终点。
3. 产出怎么存
- 一条关系 = 五段文本:起点类型、起点、关系、终点类型、终点。五段都相同的算同一条,累计证据数、首次与最近出现、按小时的条数。
- 来源记产出它的解析规则版本。规则被撤销、被新版本取代后,没有其他来源的关系标「作废」。这和现在的来源表机制相同,只是关系不再挂对象 ID。
- 没有已确认解析规则的模板不产出关系。静态阶段没有关系,「告警对象 › 关系」在治理阶段之前是空的。
- 对象抽屉里显示起点或终点文本与这个对象的键或某个标识相同(不分大小写)的关系,页面上写明「按文本相同关联」。这一步只做显示,不写库。
4. 去掉的东西
| 去掉 | 现在在哪 | 之后 |
|---|---|---|
| 按字段建的纵向关系(运行在、承载于、端接于、属于、被监控于、位于) | kb alert/compute.py graph() | 不建(R8、R12)。对象列表去掉「所在主机」「所属系统」两列和按系统、监控系统的筛选;主机、业务系统、监控系统、站点都不再单独建对象。主机与系统改为两张去重表(R13) |
classify.call_fail、通用目标抽取与目标解析 | 算法包 classify.py、targets.py | 删掉。解析规则旧的 relations 段(type、object、object_kind、role)不再认,换成第 2 节的写法 |
| 未解析目标 | 表 tb_sem_alert_unresolved_target 与查询、忽略接口 | 删表、删接口(界面入口 2.2.0 已去掉)。终点不要求是对象,就没有「解析不到」这回事 |
| 分析结果包里建在目标解析上的输出 | refs.csv;objects.csv、hosts.csv 的 ref_in_*;systems.csv 的 ref_out、ref_in_systems;call_fail、call_fail_alerts、targets 列 | refs.csv 换成 relations.csv(模板、五段文本、条数、首次、最近、样例告警);alerts.csv、templates.csv 的 targets 列换成 relations;其余列删掉 |
synonym 约定 | 只给 2.2.0 去掉的调用失败词用 | 没有地方用了,治理阶段定去留 |
5. 界面
图 1 解析规则抽屉 › 规则与预览:关系提取
字段表下面 · 模板 L-GWSET(虚构)
关系提取 新增一条
一个模板可以写多条。起点、关系、终点三个都取到值才记一条关系;类型可不填。每项可选「从原始列取」「固定值」或写复杂写法(JSON)。
| 名称 | 起点 | 关系 | 终点 | 起点类型 | 终点类型 | |
|---|---|---|---|---|---|---|
| 网关报告调用清算服务失败 | 从原始列取 host | 固定值 调用失败 | 复杂写法 lookup code_system … | 固定值 主机 | 固定值 业务系统 | 删除 |
预览 · 样本逐条
| 告警 | 拼出的关系 |
|---|---|
| A00031 | (主机)gw-app-02 —调用失败→ (业务系统)清算系统 |
| A00035 | (主机)gw-app-02 —调用失败→ (业务系统)清算系统 |
| A00040 | 终点没取到,不产出 |
图 1a 告警对象的子页签
告警对象 · 子页签依次是 对象 / 主机 / 系统 / 关系(R13)
主机
| 主机 | 告警数 | 首次出现 | 最近出现 |
|---|---|---|---|
| pay-app-01 | 24 | … | … |
| gw-app-02 | 35 | … | … |
值取自全局提取规则(或模板规则)的 host 字段,按库去重;「系统」页同样取 system(业务系统)字段。只做列表,不和对象、关系关联。列是建议,实施时可按数据调整。
图 2 告警对象 › 关系
只有解析规则提出来的关系;关系是自由文本
| 起点 | 关系 | 终点 | 状态 | 来源 | 证据数 | 最近出现 |
|---|---|---|---|---|---|---|
| gw-app-02 主机 | 调用失败 | 清算系统 业务系统 | 生效 | 解析规则 L-GWSET 第 3 版 | 10 | … |
| gw-app-02 主机 | 调用超时 | 10.0.1.21 | 生效 | 解析规则 L-GWPAY 第 1 版 | 25 | … |
筛选:关系(文本)、起点或终点包含、状态、来源模板。
图 3 告警对象 › 对象
R8 定为先不显示四个属性,本图作废;对象类型取 objectType 字段,取不到记「未知」(R11)
| 对象键 | 类型 | 主机 | 业务系统 | 监控系统 | 站点 | 告警数 |
|---|---|---|---|---|---|---|
| pay-app-01/server1 | 其他 | pay-app-01 (4) | 支付系统 (4) | 应用监控 (4) | A站 (4) | 4 |
6. 对治理智能体 SOP 的要求(第 2 期)
- 按模板推断关系提取规则,一个模板可以提多条,随解析规则一起提交、确认。
- 起点、终点优先从对象里选:对象标识、主机、IP 这类已有字段;从内容里取时说明取的是什么。
- 起点类型、终点类型优先用对象类型表(主机、数据库实例、中间件实例、容器、网络设备、线路、应用实例、业务系统、监控系统、站点)。
- 关系的说法在 SOP 里给推荐词(如「调用失败」「调用超时」「探测」),代码不校验。
7. 影响面与实施步骤
| 步 | 仓库 | 改动 | 验证 |
|---|---|---|---|
| 1 | aimp-kb 算法包 | 解析规则的 relations 按第 2 节取值;删 call_fail、targets.py 的抽取与解析;结果包改第 4 节的列;升 2.3.0 | 合成数据的三处调用失败与一处探测改写成新规则;单测 |
| 2 | aimp-kb 表与接口 | 迁移 0093:关系表改为五段文本(去掉对象外键),按小时统计挂到所有关系;删未解析目标表;新建主机、系统两张去重表(R13,值、条数、首次、最近);纵向关系、主机、业务系统、监控系统、站点对象删掉;对象列表、筛选、对象详情、快照、导出改读新结构 | sqlite 与 PostgreSQL 回归;迁移前按惯例拍快照 |
| 3 | aimp-platform | 抽屉里的关系提取列表与试算展示;告警对象的对象、主机、系统、关系四个子页(主机、系统是新加的,R13);对象抽屉的「按文本相同关联」 | 单测;库 B 截图 |
| 4 | 本机数据 | 库 B 重建:关系 0、对象只来自 objectId、主机与系统两张表有数;端到端用例按新页面改 | 模板号与离线比 0 不同,清单不变 |
| 5 | aimp-meta | 设计文档 3.3、3.4、4.4、4.7 节,数据标准第 5、7 节,两份界面稿,交接文首,静态内置规则盘点第 2.4、2.5 条 | — |
8. 已知限制
- 一条规则对一条告警只取一个值,正则取第一个匹配。一条告警里列了不定个数的目标(如「调用 A、B、C 失败」)时,只能按位置写几条规则,取不全。
- 关系、类型都是自由文本。同一种关系换了说法就是两种关系,靠 SOP 和人确认时统一。
9. 要你确认的
对象属性(R1):主机、业务系统、监控系统、站点四个属性……用户:去掉,先不显示(R8)。对象抽屉里按文本相同关联关系用户:同意(R9)。同一条关系的判定用户:同意(R10)。业务系统、监控系统、站点不再单独建对象用户:不需要显示(R8)。另定了对象类型取objectType字段(R11)。
确认后按第 7 节分步实施,每步验证后在本地 main 提交。
10. 实施交接(2026-10-11,新会话从这里开始)
开工时:R1–R13 已定,kb 5f47506(算法包 2.2.0)、平台 ca10ee6a。本机库 B 是 2.2.0 重建的,ID 在 daily_task/rca/中债/v2/results/state.json。
10.0 进度(本地 main,未推送)
| 步 | 状态 | 提交 | 验证 |
|---|---|---|---|
| 1 算法包 2.3.0 | 已完成 | kb 362de86 | kb 全量 631 通过,PostgreSQL 回归 56 通过;系统 python3 3.9 跑通合成数据 |
| 2 表与接口(迁移 0093) | 已完成,本机库已迁到 0093(迁移前快照 .runtime/backups/kb-20261011T101418Z) | kb 67da949 | kb 全量 637 通过,PostgreSQL 回归 62 通过(含新的 test_sem_relations.py) |
| 2a 关系列表按模板号筛 | 已完成(第 3 步要用) | kb a0d3182 | kb semantic 162 通过 |
| 3 平台 | 已完成 | 平台 a1cd0c40、eda1f562(关系提取列表收窄宽度) | 平台 semantic 单测 64 通过;库 B 截图在本机 daily_task/rca/中债/v2/results/shots-2.3.0/ |
| 4 库 B 重建 | 已完成(删库 B 前快照 .runtime/backups/kb-20261011T103556Z,2.2.0 的输出归档在 v2/results/relation-2.2.0/) | meta 5574f99(端到端用例与夹具) | 模板 539、变体 1997、样本 3955 不变;对象 1522(原 2941,少的是辅助对象)、标识只剩对象标识、关系 0、主机 1319、系统 187;模板号与离线比 0/28618 不同,清单 539/0/0,A10 0 处问题;端到端 2 通过。数字在本机 trial-results.md 5.5 节 |
| 5 文档同步 | 已完成:设计 3.3、3.4、4.1、4.4、4.7、7.7 节,数据标准 3.1、3.3、5.1、6、7.2–7.4 节,两份界面稿文首,交接文首,静态内置规则盘点 2.3–2.5 条与第 4 节 | meta 8794bea | — |
| 收尾(审查后补) | 分析结果包的语义切片补用例;kb-instance.sh migrate 有本机覆盖文件时一并挂载(原来只用镜像里的旧 alembic);运行态文档的 kb 版本;设计 6.5 节预览例子 | kb 2f9376e,meta 987f2df | 切片用例 sqlite、PostgreSQL 都通过;alembic heads 经挂载读到 0093 |
10.1 开工前查到的改动点
| 处 | 现状 |
|---|---|
算法包 classify.py | call_fail、targets、_rule_targets(旧 relations 写法);a.object_type 取 classify.object_type |
算法包 aggregate.py | 对象类型 a.object_type or ("主机" if host_level else "其他")(第 152 行);_refs、_silent_target、ref_in_*、call_fail_alerts 建在 targets.py 的 Resolver 上 |
算法包 render.py、records.py、synth.py | 结果包列(refs.csv 等)、Alert 的 call_fail/targets/object_type;合成数据 5 个模板用旧 relations(含一处 probes,旧代码从没执行过它),测试真值 top_host_by_ref_in、silent_referenced_system 依赖目标解析 |
kb alert/compute.py graph() | 建主机对象、业务系统 / 监控系统 / 站点对象、六类纵向关系、调用失败关系、hostname/ip 标识 |
kb models.py | Relation 有 src_object_id/dst_object_id 外键和 (library_id, rel_type, src, dst) 唯一约束;RelationHourly 只记 reported_call_failure(alert/statistics.py 第 82 行);Unresolved 表待删。五段文本做唯一键时用哈希列,PostgreSQL 的 btree 装不下五段长文本 |
| kb 其余 | 按文件统计的引用数:query_api.py 24、alert/sources.py 13、reviews.py 11(第 36–40 行校验 classify.object_type,第 163 行约定影响按调用失败关系算)、queries.py 10(第 209–213 行对象的 hosts/systems 列)、snapshot.py 9、manage_api.py 7(decide_relation,治理智能体提的 depends_on)、analyze.py 4、settings.py、merges.py、export_api.py、alert/config.py 各 2,ui_api.py、template_settings.py、review_api.py、predicates.py、imports.py、alert/ingest.py 各 1。用 grep -rn "relations\b\|object_type\|is_alert_object\|src_object_id\|dst_object_id\|Unresolved" 复查 |
| kb 查询 | query_api.py 第 54 行按 classify.object_type 筛模板;第 136–139 行按 belongs_to/observed_by 筛对象;第 166–170 行关系列表按方向筛 |
| 平台 | RuleDrawer.jsx 的「对象类型」下拉(写 classify.object_type,字段表里已有 objectType 一行,去掉下拉);Rules.jsx「横向关系」列;Objects.jsx 对象列表的「所在主机」「所属系统」、所属系统与监控系统搜索、「显示辅助对象」开关,关系页的方向与来源筛选;ObjectDrawer.jsx 关系页;reviewModel.js、DecisionDrawer.jsx(对象关系待确认) |
10.2 本机操作
- kb 单测:
cd aimp-kb/backend && .venv/bin/python -m pytest -q tests/ -k sem -p no:cacheprovider;PostgreSQL 回归只跑tests/test_sem_postgres.py,带SEM_TEST_DATABASE_URL(取.runtime/kb.env的DATABASE_URL)。改完 kb 要./aimp.sh restart kb。 - 迁移前拍快照:
AIMP_RUNTIME_DIR=/home/eoi/gitlab/aimp-meta/.runtime scripts/kb-instance.sh snapshot。 - 平台:
packages/ui下npx vitest run src/views/semantic、npx prettier --write、npm run build(约 70 s)。 - 库 B 重建:按 SQL 删掉库 B 在 20 张
tb_sem_*表里的行和.runtime/storage/semantic/<库 ID>,旧输出移到results/下的归档目录,再在daily_task/rca/中债/v2下执行ODC_PASSWORD=… node trial.mjs build、node trial.mjs worklist、python3 kb_compare.py、uv run --project …/aimp-kb/backend python a10_check.py。上一次的做法记在模板生成方案第 11.1 节。 - 截图:临时写
tests/e2e/zz-tmp-*.spec.ts(loginOdc,默认窗口登录后再setViewportSize),AIMP_E2E_BASE_URL=http://192.168.31.220:18180,用完删掉。
10.3 规矩
- 不调外部模型,不开子 Agent;每完成一块验证后在本地 main 提交,历史一条线,不推送,提交信息不带品牌词和署名行。
- 中债数据只放
daily_task/rca/中债/,仓库里(含测试数据)只写汇总数字和虚构例子。 - 动数据库前拍快照;方案和交接都没写的取舍:与目标无关的实现细节按推荐直接做(用户 2026-10-11),影响目标的先问用户。
- 当前只做静态处理,不应有需要确认的内容。
10.4 实施中定下的细节(用户 2026-10-11:与目标无关的实现细节按推荐直接做)
- 第 1、2 步的边界:第 1 步除算法包外,kb 只做解耦(入库不再产出调用失败关系与未解析目标、去掉
known_identifiers与跨分组引用重算),表结构留给第 2 步。 - 结果包:
relations.csv一行一条关系(五段相同算一条),列为relation_key、五段、alerts、first、last、templates(模板键:条数)、first_alert、last_alert;alerts.csv的relations列是关系键列表,templates.csv的是「关系键:条数」前 5 个。 - 关系表列名用
start_value、end_value(end是 PostgreSQL 保留字),按五段的 sha256(rel_hash)去重;状态只有生效、作废。 - 关系的证据数 = 当前代次按小时统计之和(统计 2026-10-11 起不再按 34 天清理),和对象告警数同口径;统计只在摄入时写,所以确认规则之后,这条规则的关系从下一次摄入起计数(首次、最近出现在确认时就有)。
- 主机、系统(R13):两张去重表各配一张按小时统计表;值取规则取到的
host字段和别名归一后的system字段,超过 512 字截断。和对象一样按来源生效或作废:确认的模板规则不再取到某个值时,它从列表消失(不必等重新摄入)。 - 去掉的接口:未解析目标的三个、建议关系的确认(
decide_relation,没有代码产出建议关系)、待办计数里的dependencies、对象详情的neighbors、对象 DTO 的hosts/systems、分组列表按objectType与未解析目标的筛选。classify.object_type保存时不再校验也不读(平台第 3 步前还会发)。 - 新接口:
GET /libraries/{lid}/alert/hosts、/alert/systems(q、分页,按告警数倒序);关系列表参数relation(等于)、q(起点或终点包含)、status、groupId(来源模板)。试算samples[]每行加relations(五段)与relationRules(index、name、values、missing)。 - 迁移:
kb-instance.sh migrate用的是镜像里的 alembic(只到 0087),本机要带源码挂载的覆盖文件执行:podman-compose -f deploy/kb/compose.yaml -f .runtime/kb-compose.local.yaml run --rm --no-deps backend alembic upgrade head(先停 kb、拍快照)。 - 主机、系统和对象一样按来源生效或作废(算法包不管,kb 的
graph()产出host、system两类来源),所以确认 I-ORD 这类改主机取法的规则后,旧值马上从列表消失。 - 端到端夹具
tests/fixtures/semantic/library.json是合成数据语义库的旧副本,N-LOSS、L-GWSET 两条关系改成新写法(旧写法导入时 kb 拒收);其余不动。 - 库 B 第四次重建删表时是 23 张
tb_sem_*加库表,按外键顺序删:来源、样本、各统计表、标识,再对象、关系、主机、系统、规则、合并、变体,把分组的parent_id置空后删分组,最后约定、谓词、任务、上传、主题、库。