dsivov/investigator
GitHub: dsivov/investigator
一个 OSINT 跨事件分析 pipeline,利用 LLM 和图算法从新闻语料中提取实体与关系,构建评分知识图谱以发现隐藏的跨故事联系。
Stars: 2 | Forks: 0
# Investigator — 发现新闻中隐藏的线索
[](LICENSE)
[](pyproject.toml)
[](ui/)
**Investigator** 是一个 OSINT 分析 pipeline,用于读取关于多个独立事件的新闻文章语料库,并提取出**连接它们的参与者、事件和关系** —— 这是一种跨事件的结构,如果由人工分析师来处理,否则必须手动阅读数百篇文章才能找到。
它将一堆原始素材转化为一个**评分知识图谱**,检测**主题**(反复一起出现的参与者组成的紧密簇)和**桥梁**(在多个事件中出现的参与者),并生成一份分析师级别的报告,其中**每一项陈述都可以追溯到来源 URL**。

一个调查的**概述**:按相关性 × 置信度排名的顶级参与者、语料库覆盖率,以及按证据权重排名的顶级主题 —— 这是 Graph / Key network / TMFG themes / Data / Report / Sources / Claim verdict 标签页中的一个。
## 问题所在
追踪特定地区或主题的调查员通常需要同时处理许多平行的事件。有趣的发现很少存在于单一事件中 —— 而是**出现在两个事件中的参与者**:在制裁新闻中被点名的金融家,同时也出现在另一起航运新闻中;两起互不相关的起诉书中出现的同一个中间人。找到这些联系意味着要在脑海中记住数百篇文章,并注意到那个交叉出现的名字。
Investigator 通过机械化方式执行这种交叉检测。

三次独立的新闻搜索。两个带有绿色边框的节点 —— **HAMAS** 和 **IRAN** —— 是*桥梁*:系统发现其在多个事件中有所交集的参与者。虽然处于不同的事件中,但却是同一个参与者。
## 工作原理

该 pipeline 分为六个阶段运行。前两个是提取;接下来的三个将每篇文章中杂乱的独立事实转化为结构化的网络;最后一个允许置信度计算在网络中传播。
1. **获取。** 为每个查询搜索 Google News 并下载最相关的文章。无法获取正文的文章(付费墙、拦截)将作为**仅包含标题**的记录保留,而不是被丢弃 —— 标题仍然带有实体信号。除了新闻,你还可以启用**额外的搜索源**(Wikipedia、GDELT、OpenSanctions、通用网络搜索 —— 见下文),并引入你**自己的来源** —— 上传 PDF 或粘贴 URL —— 与抓取结果一起分析,或者单独分析(使用 `--no-gnews`),以便对单个案例文件或文档运行相同的图谱机制。
2. **提取。** LLM 阅读每篇文章并提取出**具名参与者**(人物、组织、地点)和**事件**(具体的事故:谁对谁做了什么,何时,何地),以及任何**来源声称的因果关系**。
3. **合并跨文章的证据。** 将同一参与者的变体("Vladimir Putin" / "Putin" / "the Russian president")合并为一个节点,提及该实体的所有文章的集合成为该节点的**证据列表**。关系也以同样的方式合并 —— 三篇断言相同关系的文章合并为一条权重为三的边,并携带三个 URL。
4. **过滤至主干。** 根据有多少独立文章支持这些关系对其进行排名,丢弃单例,但恢复从任何孤立的参与者到调查主体的**最短路径**,以免切掉任何相关内容。
5. **三角化 (TMFG)。** 构建一个弦-平面的**三角化最大过滤图 (Triangulated Maximally Filtered Graph)**。它分解为一棵由 4-clique 组成的树;每个 4-clique 就是一个**主题**。TMFG 添加的但没有被直接证明的边成为系统的**结构假设**,与事实区分开来。
6. **置信度传播。** 在 clique 树上进行一次 junction-tree 的 belief-propagation 过程,根据参与者所处的环境调整其置信度 —— 这是精确的,因为该图是弦图。
对于**跨事件分析**,每个查询都被输入到同一个 pipeline 的同一个会话中,并且每个节点/边都会标记上是由哪个查询产生的。出现在多个查询数据中的参与者即为**桥梁**。
数据流的完整图示见 [`docs/pipeline.md`](docs/pipeline.md)。所有文档均位于 [`docs/`](docs/README.md) 下。
## 你可以审查的主题
*主题*是系统对“哪些参与者属于同一群体?”的回答 —— 一个经常同时出现的由四个参与者组成的紧密群体。主题根据**证据加权分数**进行排名,因此排名最高的主题是得到最好*印证*的跨故事结构,而不仅仅是最密集的结构。(从连通性排名切换到证据排名后,在一个真实的三故事运行中,顶级主题从大致均匀的参与者/事件混合转变为约 90% 以参与者为中心 —— 凸显了调查员想要的关系结构,并将重复的事件标题压至下方。)

TMFG 主干及其作为多边形着色的顶级 4-clique 主题。实线边由来源印证;虚线边是算法添加的结构性**填充** —— 需要验证的假设。桥梁位于多边形相交的地方。
主题并不是一个死胡同式的标签。打开一个主题,它会展开为**绑定其四个成员的关系**,每一条都有其来源。一个来自制裁规避运行的真实例子:
该主题指出了绑定该制裁网络的*机制*(CIPS,中国的人民币支付轨道)—— 而不仅仅是四个同时出现的名字。

一次实时的选举干预运行中的 TMFG-themes 标签页:每个着色的多边形是一个 4-clique 主题,按证据权重在侧边栏中排名。
## Storylines:将图谱视为叙事
主题被刻意划分得很细(每个 4 个参与者)。**Storylines** 是它们之上的粗粒度层:通过在印证加权关系图上运行的 **Louvain 社区发现**算法作为种子,将一项调查分割成其结构上内聚的叙事簇 —— 通常每次运行会有 10–30 个,每个都是分析师一眼就能认出的故事(“FinCEN 规则制定”、“Upbit 黑客攻击”、“Prince Group 制裁”)。

在 **Graph** 标签页上,切换 **Storylines** 以按社区为节点着色,从图例中选择一个(或通过任何节点的 *Storyline* 链接跳转),图谱就会聚焦于它。侧边栏按相关性列出其成员,**Summarize storyline** 会让 LLM 将该簇作为一个故事进行叙述 —— 发生了什么、关键参与者、带有日期的时间线,以及 —— 至关重要的是 —— 该 storyline 是否真的**与调查假设有关**,或者只是无关的噪音。
最后一点是存在这一层的原因:在真实运行上的验证表明,偏题的簇(产品研究语料库中的一个天文学故事)其每个实体的相关性得分为*平均*水平 —— 逐个节点看无法区分 —— 但在*结构上*却完美分离。社区结构能捕捉到基于实体评分无法发现的内容。
## 一个操作示例:伊朗的代理人网络
来自一次运行的三个独立搜索 —— 对哈马斯领导人的以色列打击、美国财政部对真主党金融家的制裁,以及胡塞武装在红海的袭击 —— 融合成了一张图谱:

系统构建的实际合并图谱。每个故事代表一种颜色;两个绿色桥梁(**HAMAS**,**IRAN**)将它们连接起来。粗红色的边是分析中原样保留的**来源声称的因果关系**。
### 调查员能得到什么
对于每个桥梁,调查员都会得到一份可以验证的小档案:在每个故事中提及它的文章、作为证据提取的**实际引述**(附带 URL),以及系统标记它的结构性原因。还有排名靠前的跨故事**线索**:
那是一条有理有据的分析师线索 —— 而不是“Binance 正在帮助胡塞武装”(没有文章这么说),而是“通过 Binance 的伊朗金融渠道与运作胡塞武装的同一个伊朗存在重叠。值得放在一起调查。”

这种压缩使得线索变得可被发现:将抓取的 449 篇文章提炼为 57 个已评分的图谱节点,2 个跨故事桥梁,以及 8 个排名靠前的线索。
## 你可以启用的搜索源
Google News 是默认选项,但每项调查都可以从额外的来源获取数据,这些来源可以在“新建调查”的 **Sources** 步骤中按来源切换(也可以通过 CLI 上的可重复参数 `--source` 实现)。它们获取有关主题的文本,并流经完全相同的 extract → graph pipeline。失败或未配置的来源将被跳过 —— 它永远不会中断运行。
| 来源 | 是否需要 Key | 增加的内容 |
|---|---|---|
| **Wikipedia** | 否 | 关于该主题的百科全书式文章文本(MediaWiki API)。 |
| **GDELT** | 否 | 全球新闻报道,比 Google News 更广泛(免费层级有速率限制)。 |
| **OpenSanctions** | 是 (`INVESTIGATOR_OPENSANCTIONS_KEY`) | 制裁 / PEP / 观察名单条目;在设置前显示为 *needs key*。 |
| **Web search** | 否* | 通用网络结果 —— 如果设置了 `INVESTIGATOR_GOOGLE_API_KEY`+`INVESTIGATOR_GOOGLE_CSE_ID` 则使用 Google Programmable Search,否则使用 DuckDuckGo。 |
## 连点成线:实体间的隐藏关系
整个图谱可能非常密集。当你想问一个集中的问题 —— ***这些*特定的参与者/事件是如何关联的?** —— 可以在 **Data** 标签页中选择任意一组,并按需构建 **Connections** 子图。有三种模式:
- **最短路径** —— 每个选定对之间的单条最短路径,加上它经过的中间(“连接器”)实体。
- **隐藏 (间接)** —— 最有趣的一种。它寻找*不明显的*多跳链(每对最多有 *k* 条不同的最短路径),因此即使**当直接边已经存在时**,通过中介运行的链接也会浮现出来。中介根据**中介中心性**进行排名,最中心的会被标记为**中介** —— 即真正将选定内容绑定在一起的实体。
- **仅限直接连接** —— 仅限选定内容之间直接存在的边。
寻路仅在*关系*边上运行(排除了指向根节点的证据脚手架,因此不会通过中心枢纽伪造连接)。
点击 **Analyse**,连接好的子图 —— 参与者、事件、关系和计算出的路径 —— 将被发送给 LLM,它会就选定实体是*如何*相互连接的写一份简短且基于证据的报告(指出每条链以及每个中介桥接的内容)。
### Key network —— 自动化版本
**Key network** 标签页无需手动选择即可完成此操作:它将隐藏连接算法的种子设定为调查中*最相关*的节点 —— 即**主题成员**(基于证据权重的 TMFG 簇)加上**桥梁**(跨调查参与者)—— 并浮现出将那些原本分离的主题缝合到一个骨架中的**中介** 实体。它是主题视图未显示的结缔组织:在内塔尼亚胡那次运行中,21 个主题节点解析为单个中介,即 **Attorney-General's Office**(总检察长办公室),它将各个簇绑定在一起。只需点击一次 **Analyse**,即可总结整个调查的结构。(质量取决于上游的主题/桥梁 —— 贫乏的运行会产生单薄的骨架。)

一次实时运行的 key-network 骨架:绿色的**关键**节点(主题成员和桥梁),灰色的**连接器**,以及路径经过的带琥珀色圆环的**中介**。
## 事实核查:有多少来源同意
印证 —— 事实核查的核心 —— 在整个 UI 的两个层面中显现出来:
- **声明级别的徽章**,出现在每个参与者和每条证据上(Data 标签页):**weak**(1 个来源)、**moderate**(2 个)、**strong**(3 个以上)—— 取决于有多少*独立*来源证实了**同一声明**。声明按含义进行聚类(意译算作一起),并且几乎相同的**联合发表**副本会合并为一个来源 —— 因此一篇被 20 家媒体转载的通讯社报道*不会*被误认为是 20 次证实。
- **评分中的置信度提升**:被更多独立来源证明的实体会被推离中立位置,因此得到充分印证的参与者的排名会高于单一来源的参与者(单一来源仍然算数,只是权重较低)。

**** 标签页:每个参与者及其每项声明的印证等级、文章计数和相关性评分 —— 还有为按需 Connections 分析提供数据的勾选框。
**Sources** 标签页显示了来源批判的另一半:出版商集中度(语料库中有多少依赖于前 3 大媒体)、每个出版商的声明,以及针对外部公司注册机构(SEC EDGAR + OpenRegistry —— 见下文)的一键**实体富化**。

## 基于声明的调查:从声明到 ICD-203 裁决
你可以不输入搜索查询,而是交给系统一个**声明**(“华为向伊朗提供用于镇压抗议活动的监控技术”),然后得到一个带有支持*和*反对证据的**置信度裁决**。有两种深度:
- **快速核查**(*Verify a claim* 页面,约 30 秒)。声明被标准化为一个可检验的断言,扩展为**平衡的支持和驳斥搜索**,并且每个检索到的片段都会进行立场分类。结果是一个 ICD-203 裁决(*Almost Certainly … Almost Certainly Not*),并附带支持/驳斥的证据卡片、实际运行的查询(对抗性透明度),以及**来源数量调节** —— 如果证据基础薄弱,会将裁决拉向中间,并标记为线索而非结论。
- **全面声明调查**(从快速核查中点击一次即可,或者在新建调查向导中以声明为种子启动)。该声明的支持/驳斥搜索将成为调查的**事件线程** —— 因此图谱在设计上就是基于双方证据构建的 —— 而标准化的断言则成为相关性假设。**对抗性扇出**是可配置的(彻底的运行设置为 3+3 个线程,快速的为 1+1,或者单个中性线程),每个线程的深度调节也是如此;每个线程的成本大约相当于一次单查询运行。在向导中,可以在启动前完全编辑计划好的线程,并且可以在保留这些线程的同时关闭声明模式。
当一项声明调查完成时,**Claim verdict** 标签页会根据存储的声明对*深层*图谱证据(而不是重新搜索)进行立场分类,并将其聚合为同样的 ICD-203 裁决 —— 在一次验证运行中,它凭借包括原始 FinCEN / Federal Register 文件在内的 11 个独立来源达到了 **Almost Certainly** 的级别,并具有真实的 22 支持 / 1 驳斥 / 37 中立的立场划分,而不是一种橡皮图章式的批准。该标签页也适用于任何旧的调查:输入一个声明,它就会根据该图谱的证据进行评估。
## 跨调查的累积知识图谱(可选)
启用分析引擎(`--analytic_engine_enabled`)后,每个已完成调查的图谱都会累积到**一个持久化知识图谱**中(代码内使用 LightRAG,无需单独的服务器),存储在代码树之外的 `~/.local/share/investigator/kg` 目录中(可通过 `INVESTIGATOR_KG_STORE` 覆盖)。后续调查可以利用早期调查发现的内容。
- **跨调查标准化。** 一个保守的层可以防止同一个现实世界实体在不同运行中碎片化 —— 它仅自动合并安全的名称变体(精确匹配 + 格式差异),并将模糊匹配路由到审查日志中,而不是冒着错误且永久性合并的风险。
- **不会丢失任何内容。** LightRAG 的图谱只保留固定的 schema,因此一个辅助的**结构化存储**会保留我们构建的所有属性 —— 信念分数、证据(包括置信度 + 来源 URL)、标签、主题、每条边的关系类型/上下文、假设标记,以及每个条目是由哪些调查证明的 —— 全部以相同的规范名称作为键,并跨运行合并。
- **从 UI 查询。** **Knowledge Base** 标签页可以跨所有调查中看到的*所有*内容提出问题:它返回结构化的实体和关系(以实体为锚点的*混合*检索)加上可选的 LLM 合成答案,并且每个实体都可以展开以显示其信念分数、印证证据、来源链接以及它出现在哪些调查中。
- **预填充。** 当一项新调查开始时,它会以 KG 已经知道的关于其主题的内容进行预填充,并与新发现一起展示。
### 常驻监控器
建立在累积 KG 之上,**Monitor** 标签页将 Investigator 从请求驱动转变为一种*常驻监视*:一个计划任务会为观察列表抓取最新新闻,仅保留涉及 KG 已知实体的事件,并将**影响**传播到相连的节点(在每个触及的实体周围进行小规模的局部 TMFG + 信念传播)—— 从而生成一份按日期排序、排名靠前的*你的图谱中发生了什么变动*的摘要。对 KG 只读。详见 [`docs/monitoring.md`](docs/monitoring.md)。
## 这不是什么
- **不是因果引擎。** 它揭示的是共现性和来源证明的关系。因果关系仅在来源文章本身断言时才会出现。
- **并不全面。** 图谱的质量仅取决于新闻语料库的质量。
- **不是最终答案。** 跨事件的线索只是一个开始阅读的地方 —— 系统提供给你 URL,正是因为依然需要有人去阅读它们。
## 架构
三个进程:
```
┌────────────────────┐ spawns ┌──────────────────────┐ HTTP POST ┌─────────────────────┐
│ Frontend (Svelte) │ /api proxy │ UI backend (Flask) │ ───────────▶ │ Pipeline engine │
│ Vite dev :5180 │ ──────────▶ │ ui/server │ │ python -m investigator │
│ graph / themes / │ │ :5050 REST + SSE │ ◀─────────── │ :5003 │
│ data / report UI │ ◀────────── │ job queue + reports │ graph JSON │ NER · graph · TMFG │
└────────────────────┘ └──────────────────────┘ │ · belief propagation│
└─────────────────────┘
```
- **Pipeline 引擎** (`python -m investigator`, 端口 **5003**) —— 核心:实体 + 事件提取 (dspy + GPT-4.1),证据整合,图谱构建,印证过滤器,TMFG 三角化,以及 junction-tree 信念传播。
- **UI 后端** (`ui/server.py`, 端口 **5050**) —— REST + SSE API(见 [`docs/ui-api.md`](docs/ui-api.md))。将调查作为子进程运行,这些子进程向引擎发送 POST 请求,流式传输进度,生成客户报告,并提供适配 Cytoscape 的图谱/主题数据。
- **前端** (`ui/`, Svelte 5 + Vite, 端口 **5180**) —— 调查员 UI:新建调查向导(领域感知的查询优化 + 可否决的审查步骤,可选将**声明种子**转化为可编辑的支持/驳斥线程,以及用于添加你自己的 PDF/URL 的 Sources 步骤),实时进度,Graph / Key-network / TMFG-themes / Data / Report / Sources / **Claim-verdict** 标签页,**Storylines**(带有每个社区 LLM 叙述的 Louvain 社区),按需 **Connections** 分析(选择实体 → 隐藏关系子图 + LLM 摘要),自动的 **Key network**(带有中介的主题+桥梁骨架),每个参与者/证据的**印证**徽章,**Verify a claim** 快速检查,**Knowledge Base** 标签页(查询累积的跨调查 KG),**Monitor** 标签页(常驻监视摘要),以及用于连接数据提供商的 **Settings** 页面。
## 运行方式
最快的方法是使用 Docker;手动安装在其下方。无论哪种方式,你都需要一个 **OpenAI API key**。
### 使用 Docker 快速开始
在一个容器中运行所有三个服务(引擎、UI 后端、前端)。
```
cp .env.example .env # then edit .env and set OPENAI_API_KEY
docker compose up --build # reads OPENAI_API_KEY from your shell or .env
```
或者不使用 compose:
```
docker build -t investigator .
docker run --rm -p 5003:5003 -p 5050:5050 -p 5180:5180 \
-e OPENAI_API_KEY=sk-... -v investigator-data:/data investigator
```
然后打开 **http://localhost:5180**。持久会话状态和累积知识图谱保存在 `investigator-data` 数据卷中。
### 手动设置
**前置条件:** Python **3.12**(3.11+ 也可),**Node.js 18+**,以及一个 **OpenAI API key**。
**1. 安装。** 虚拟环境可以将繁重的 ML 技术栈隔离开来;`pip install -e .` 会从 `pyproject.toml` 中拉取完整的 pipeline(依赖项的唯一事实来源):
```
python -m venv .venv && source .venv/bin/activate
pip install -e .
```
**2. 密钥。** 复制模板并填入你的 key(真正的 `.env` 已被 git-ignore):
```
cp .env.example .env
# 编辑 .env 并设置 OPENAI_API_KEY
```
**3. 启动 pipeline 引擎(端口 5003):**
```
INVESTIGATOR_TMFG=1 INVESTIGATOR_VIZ=1 INVESTIGATOR_DISABLE_CACHE=1 \
PYTHONPATH=src:. python -m investigator
```
`INVESTIGATOR_TMFG=1` 启用主题/网络分析阶段。添加 `--analytic_engine_enabled`(或设置 `ANALYTIC_ENGINE_ENABLED=1`)可将已完成的调查累积到持久化知识图谱中(以便 **Knowledge Base** 标签页有数据)。如果 Knowledge Base 停止接收新的调查,这个开关是首先要检查的 —— 没有它引擎也能正常运行,而且不会警告你。
**4. 启动 UI 后端(端口 5050):**
```
PYTHONPATH=.:src python ui/server.py --port 5050
```
它会自动发现 `news_investigations/cross_event/` 下过去的调查工件。添加 `--host 0.0.0.0` 以便从局域网 (LAN) 内的另一台机器访问它(Vite 开发服务器已经绑定了所有网络接口)。
**5. 启动前端(端口 5180):**
```
cd ui && npm install && npm run dev # http://localhost:5180, proxies /api -> :5050
```
打开 **http://localhost:5180**。
### 有用的环境变量
| 变量 | 效果 |
|---|---|
| `OPENAI_API_KEY` | LLM 访问权限(引擎,以及 UI 的查询优化 endpoint)。 |
| `ANALYTIC_ENGINE_ENABLED=1` | 将已完成的调查累积到持久化 KG 中(与 `--analytic_engine_enabled` 相同)。 |
| `INVESTIGATOR_TMFG=1` | 启用 TMFG 主题 + 信念传播(主题标签页必需)。 |
| `INVESTIGATOR_DISABLE_CACHE=1` | 禁用 LLM 响应缓存。 |
| `INVESTIGATOR_TMFG_UNIFORM_WEIGHTS=1` | 恢复旧的仅基于拓扑的主题加权(默认是感知证据的)。 |
| `INVESTIGATOR_UI_MAX_CONCURRENT` | UI 后端同时运行的最大并发调查数(默认为 1)。 |
| `INVESTIGATOR_CORRO_GAIN` / `INVESTIGATOR_CORRO_CAP` | 多来源印证的置信度提升(默认增益 0.35,上限 8)。 |
| `INVESTIGATOR_CLAIM_SIM` / `INVESTIGATOR_SYNDICATION_SIM` | 用于事实核查徽章的声明聚类 / 联合发表阈值(默认 0.78 / 0.97)。 |
| `INVESTIGATOR_KG_LLM_MODEL` | 用于累积 KG 层的 OpenAI 模型(默认 `gpt-4.1-mini`)。 |
| `INVESTIGATOR_KG_STORE` | 累积 KG 存储目录(默认 `~/.local/share/investigator/kg`)。 |
| `INVESTIGATOR_OPENSANCTIONS_KEY` | 启用 OpenSanctions 搜索源的 API key。 |
| `INVESTIGATOR_GOOGLE_API_KEY` / `INVESTIGATOR_GOOGLE_CSE_ID` | 用于网络搜索源的 Google Programmable Search(否则使用 DuckDuckGo)。 |
## 从 CLI 运行调查(无 UI)
```
PYTHONPATH=.:src python research/cross_event_investigation.py \
--domain sanctions_evasion --period 30d \
--event "russia_oil:Russia oil sanctions evasion dark fleet 2026" \
--event "china_yuan:China yuan settlement Russia trade sanctions 2026" \
--event "iran_drone:Iran Russia military cooperation drone supply 2026"
```
使用可重复的 `--source` 添加额外的搜索源(例如 `--source wikipedia --source gdelt --source websearch`)。
然后将工件转换为客户报告:
```
python research/build_customer_report.py news_investigations/cross_event/.json
```
### 分析你自己的文档
将 PDF 或 URL 作为额外来源添加,可选择是否获取新闻。使用 `--no-gnews` 时,pipeline 仅根据你提供的内容运行 —— 例如 `criminal_investigation` 领域下的单个案例文件:
```
PYTHONPATH=.:src python research/cross_event_investigation.py \
--domain criminal_investigation --no-gnews \
--event "case:GBH stabbing investigation" \
--extra-pdf /path/to/report.pdf --extra-url https://example.com/filing
```
## 实体富化(可选)
运行后,`research/enrichment.py` 可以将外部记录附加到图谱中的顶级公司(`ORG`)实体上 —— 写入到 `.enriched.json` 中,并在客户报告的每个实体下作为 **External records** 显示。
这是可选项,并且与引擎解耦(它会进行网络调用)。
```
PYTHONPATH=.:src python research/enrichment.py [--top-n 12]
```
两个免费提供商:
- **SEC EDGAR** —— 开箱即用,无需 key。美国上市公司的身份信息 + 最近的备案文件。
- **OpenRegistry** —— 30 个国家级公司注册机构(受益所有人、高管、股东)。免费层级,而且至关重要的是**无需账户且无需 API key**:认证使用带有 Dynamic Client Registration 的 OAuth 2.1。只需授权**一次**:
PYTHONPATH=.:src python research/enrichment.py --openregistry-login
这会在你的浏览器中打开 OpenRegistry 的授权页面 —— 你只需点击 **Authorize**(*没有*用户名/密码;可选择输入电子邮件以将免费限制从 20 提高到 30 rpm)。令牌(包括刷新令牌)存储在 `~/.config/investigator/openregistry_oauth.json` 中,此后会**自动刷新**,所以你只需执行一次此操作。在无头服务器上,可以在带有浏览器的机器上运行登录并复制该文件过去(或者将 `INVESTIGATOR_OAUTH_DIR` 指向它)。
你也可以在应用中**不使用 CLI** 执行此操作:**Settings → OpenRegistry → Connect**,它会运行同样的一次性浏览器授权,并显示实时连接状态。*提示:*在 **Firefox** 中执行 **Authorise** 步骤 —— Chrome/Edge/Brave 会阻止提供商重定向回 `localhost`,因此在那里无法完成登录(Settings 页面也提供了粘贴回调 URL 的后备)。
使用 `--no-edgar` / `--no-openregistry` 禁用提供商。注意:富化会将提取的实体*名称*发送给这些外部服务。你也可以**从应用中**运行富化 —— **Sources** 标签页有一个 *Enrich* 按钮,它会运行相同的查询并列出每个实体的外部记录。
## 仓库结构
```
src/investigator/ Pipeline engine: NER, graph build, dedup/merge,
corroboration filter, TMFG, junction-tree BP.
graph/connector.py Connections subgraph (shortest-path / hidden / brokers)
graph/corroboration.py Claim-level multi-source corroboration (fact-check badges)
analytics/ Cumulative KG: in-code LightRAG merge, cross-
investigation canonicalization, structured_store
(preserves all node/edge props), retrieval
monitor/ Standing watch: watchlist intake, KG intersect,
impact propagation, ranked digests
research/
cross_event_investigation.py CLI driver for a multi-query run
claim_verify.py Claim → assertion + adversarial search plan +
stance classification + ICD-203 verdict
search_sources.py Wikipedia / GDELT / OpenSanctions / web providers
enhanced_retrieval.py Query-expansion + rerank + entity-deepening
build_customer_report.py Analyst-grade markdown report generator
build_graph_prototype.py Cytoscape graph-payload (incl. Louvain
storyline layer) + standalone prototype
build_tmfg_prototype.py TMFG-themes payload + standalone prototype
build_full_ui_prototype.py Single-file six-tab UI prototype
build_blog_post.py Generates the illustrated blog post
domain_presets.py Per-domain relevance hypotheses
ui/ Svelte 5 + Vite frontend (the investigator UI)
server.py UI backend (REST + SSE) — see docs/ui-api.md
docs/ All project documentation (see docs/README.md)
architecture.md System overview · components · data stores
pipeline.md Graph-creation pipeline (per-investigation)
knowledge-base.md Cumulative KG · temporal layer · retrieval
analysis.md Themes · bridges · belief propagation
sources.md Search sources + enrichment
operations.md Running, env vars, OOM/memory notes
data-model.md Node/edge schema + structured sidecar
ui-api.md REST + SSE contract
roadmap.md Productization roadmap
monitoring.md Standing monitor (watchlist · impact digests)
reviews/ Design reviews
images/ README figures
screenshots/ UI screenshots used in this README
news_investigations/ Run artifacts + job state (git-ignored)
```
## 方法论说明
- 报告中的**置信度语言**遵循 ICD 203 分析标准(Almost Certain / Highly Likely / Likely / …)。
- **主题**根据证据加权分数进行排名(经过证明的参与者间联系和跨运行印证比偶然的共现更有分量)。
- **不包含闭源情报、人工情报,也不包含**新闻聚合器返回的发布者页面之外的**开放网络爬取**。
这是研究级别的软件。示例中的数字是来自特定运行的准确计数;由于 LLM 的非确定性和新闻语料库的漂移,在不同的运行中对相同的查询可能会产生不同的结果。
标签:C2, DLL 劫持, ESC4, OSINT, Python, SBOM分析, Svelte, 代码示例, 大语言模型, 情报分析, 数据分析, 无后门, 网络诊断