Gallind/OSINT-Military-Bases-Analyzer

GitHub: Gallind/OSINT-Military-Bases-Analyzer

一个基于LangGraph多智能体协作的军事基地卫星图像OSINT分析流水线,通过八个视觉LLM分析师、指挥官和战略家三级架构实现自动化威胁评估与跨基地模式识别,并以实时交互地图呈现结果。

Stars: 0 | Forks: 0

# OSINT 军事基地分析器 一个多智能体 OSINT 流水线,用于获取军事基地的卫星图像,对每个基地运行 **8 个视觉 LLM 分析师**,通过 **指挥官** 智能体综合他们的发现,通过 **战略家** 智能体生成跨基地模式,并在实时 **Streamlit + Folium** 仪表板中将所有内容可视化。 为 *From Idea to App*(赖希曼大学,第 4 学期,作业 2)构建。 ## 目录 - [功能介绍](#what-it-does) - [架构](#architecture) - [技术栈](#tech-stack) - [项目布局](#project-layout) - [设置](#setup) - [运行流水线](#running-the-pipeline) - [运行仪表板](#running-the-dashboard) - [配置](#configuration) - [输出 schema (`data.json`)](#output-schema-datajson) - [测试](#tests) - [注意事项](#gotchas) ## 功能介绍 给定一个包含军事基地的 CSV 文件,流水线将执行以下操作: 1. **获取图像**:从 Google Maps Static API(主要)和 Sentinel Hub(Sentinel-2 真彩色,深度视图)获取每个基地的图像。 2. **运行 8 个分析师智能体**:在 LangGraph 循环中运行。每个分析师检查当前画面,提取发现及其置信度,并选择一个动作(`zoom-in`、`zoom-out`、`move-left`、`move-right` 或 `finish`)。系统会据此重新获取下一帧画面。 3. **调用指挥官智能体**:将 8 份分析师报告整合为一份 `threat_assessment`(HIGH / MEDIUM / LOW / UNKNOWN),包括高共识发现(3 名以上分析师同意,平均置信度 ≥ 7)、有争议的发现以及建议的后续行动。 4. **调用战略家智能体**:在运行结束时调用,以揭示跨基地模式、优先基地及整体评估。 5. **持久化所有数据**:将所有数据保存到 `data.json`(原子写入,仅追加的运行历史记录)并在仪表板中呈现。 仪表板将分析器作为子进程启动,在运行期间每 2 秒轮询一次 `data.json`,并包含一个“Ask AI”选项卡,该选项卡以图像和报告作为上下文,回答关于所选基地的自由格式问题。 ## 架构 ``` military_bases.csv │ ▼ ┌───────────────────────────────────────┐ │ base_analyzer.py │ │ (orchestrator: per-base loop, run │ │ versioning, commander, strategist) │ └───────────────────────────────────────┘ │ ▼ ┌───────────────────────────────────────┐ │ pipeline.py │ │ LangGraph StateGraph │ │ │ │ fetch_image ──► run_analyst ──► │ │ ▲ │ │ │ │ ▼ │ │ └──── decide_next ──► END │ └───────────────────────────────────────┘ │ │ ┌───────────┘ └──────────────┐ ▼ ▼ ┌──────────────┐ ┌──────────────┐ │ imagery.py │ │ llm_client.py│ │ │ │ │ │ Google Maps │ │ gemini / │ │ Sentinel Hub │ │ openai / │ │ Moondream │ │ qwen factory │ └──────────────┘ └──────────────┘ │ ▼ ┌────────────────┐ │ storage.py │ │ atomic JSON │ │ run versioning │ └────────────────┘ │ ▼ data.json │ ▼ ┌────────────────┐ │ app.py │ │ Streamlit + │ │ Folium map + │ │ Ask AI tab │ └────────────────┘ ``` 每个分析师的写入都是通过 `graph.stream()`(而不是 `.invoke()`)进行流式传输的,以便仪表板可以实时看到每个分析师的进度。 ## 技术栈 | 层级 | 库 / 服务 | 备注 | | --- | --- | --- | | 图像 — 主要 | Google Maps Static API | REST → JPEG;需要 `GOOGLE_MAPS_KEY` | | 图像 — 深度视图 | `sentinelhub-py` 3.11.5 | 通过 Copernicus Data Space 获取 Sentinel-2 L2A | | 图像 — 描述生成 | Moondream 3 cloud (`moondream`) | 可选的快速预传递;需要 `MOONDREAM_API_KEY` | | 分析师 LLM | `google.genai` (Gemini) | 使用 `response_schema` 进行结构化输出的 `gemini-3.1-pro-preview` | | 指挥官 / 战略家 | `openai` SDK | 通过 `beta.chat.completions.parse` 调用 `gpt-5.5` | | 免费视觉替代方案 | OpenRouter (`qwen3-vl-32b`) | 通过 `PROVIDER="qwen"` 直接替换 | | 多智能体循环 | `langgraph` 1.1.10 | StateGraph;流式传输 | | 仪表板 | `streamlit` 1.57 + `streamlit-folium` | 使用 Folium MarkerCluster 处理重叠的基地 | | 验证 | `pydantic` 2.x | 原生结构化输出(无 `instructor` —— 参见注意事项) | ## 项目布局 ``` . ├── base_analyzer.py # main orchestrator — entry point ├── pipeline.py # LangGraph nodes + commander/strategist callers ├── llm_client.py # provider factory: gemini | openai | qwen ├── imagery.py # Google Maps, Sentinel Hub, Moondream fetchers ├── storage.py # atomic data.json reads/writes + run versioning ├── models.py # AnalystReport, CommanderReport, StrategistReport ├── app.py # Streamlit dashboard ├── tests/ # 13 unit tests (models, storage, consensus) ├── military_bases.csv # input dataset ├── data.json # output (gitignored, append-only run history) ├── screenshots/ # JPEGs per base (gitignored) ├── requirements.txt ├── .env.example # template — copy to .env and fill in keys └── CLAUDE.md # project instructions for Claude Code ``` ## 设置 ``` # 克隆并进入项目 cd OSINT-Military-Bases-Analyzer # 创建 virtualenv(推荐 Python 3.12+) python3 -m venv .venv source .venv/bin/activate # 安装依赖 pip install -r requirements.txt # 配置 secrets cp .env.example .env # 然后编辑 .env 并填入你的 API keys(见下文) ``` ### 必需的环境变量 ``` GOOGLE_MAPS_KEY= # required — primary imagery GEMINI_API_KEY= # required — analyst + commander vision LLM OPENAI_API_KEY= # required — commander + strategist (gpt-5.5) OPENROUTER_API_KEY= # optional — only if PROVIDER="qwen" MOONDREAM_API_KEY= # optional — caption pre-pass SENTINELHUB_CLIENT_ID2= # optional — deep Sentinel-2 imagery SENTINELHUB_CLIENT_SECRET2= # optional — paired with the above ``` ## 运行流水线 ``` # 完整运行(使用 base_analyzer.py 中的 ROWS_TO_PROCESS) .venv/bin/python base_analyzer.py # 全新运行 — 先清除之前的输出 rm data.json && .venv/bin/python base_analyzer.py ``` 流水线在单次运行中是**幂等的**:最新运行中标记为 `status="complete"` 的基地将被跳过,因此您可以安全地中断并重新运行。 ## 运行仪表板 ``` .venv/bin/streamlit run app.py # → 打开 http://localhost:8501 ``` 功能: - **Folium 地图**:每个基地一个标记,缩小视图时自动聚合(`disableClusteringAtZoom=8`),因此同处一地的基地(例如 0.17° 内的四个埃及 SA-2 阵地)仍可单独选择。 - **运行选择器**:浏览 `data.json` 中的历史运行。运行进行时锁定为最新一次运行。 - **详情面板**:屏幕截图、所有 8 份分析师报告、指挥官摘要、威胁级别。 - **Ask AI 选项卡**:关于所选基地的自由格式问答(使用 Gemini,将图像和报告作为上下文注入)。 - **实时轮询**:在分析器子进程存活期间,执行 2 秒间隔的 `st.rerun()` 循环。 您也可以直接从仪表板的“Run analysis”按钮启动分析器。 ## 配置 `base_analyzer.py` 的顶部: ``` ROWS_TO_PROCESS = 20 # 1 for testing, full CSV otherwise NUM_ANALYSTS = 8 PROVIDER = "gemini" # "gemini" | "openai" | "qwen" ANALYST_MODEL = "gemini-3.1-pro-preview" COMMANDER_PROVIDER = "openai" COMMANDER_MODEL = "gpt-5.5" STRATEGIST_PROVIDER = "openai" STRATEGIST_MODEL = "gpt-5.5" DEFAULT_ZOOM = 17 ZOOM_DELTA = 1 LAT_LNG_DELTA = 0.01 ``` 调整 `ROWS_TO_PROCESS` 以控制单次运行中处理多少行 CSV 数据。 ## 输出 schema (`data.json`) ``` { "runs": [ { "run_id": "2026-05-09T13:10:42", "started_at": "...", "completed_at": "...", "strategist": { "cross_base_patterns": ["..."], "priority_bases": [147, 1059], "overall_assessment": "..." }, "bases": [ { "id": 147, "country": "Egypt", "latitude": 23.954, "longitude": 32.995, "status": "complete", // "pending" | "in_progress" | "complete" "moondream_caption": "...", "screenshots": ["screenshots/147/static_z17.jpg", "screenshots/147/sentinel.jpg"], "analysts": [ /* 8 × AnalystReport */ ], "commander": { /* CommanderReport */ } } ] } ] } ``` 运行记录是**追加的,永远不会被覆盖**。仪表板默认读取 `runs[-1]`。 ### Pydantic 模型 (`models.py`) ``` class AnalystReport(BaseModel): findings: list[str] finding_confidences: list[int] # same length as findings confidence: int # overall 1–10 analysis: str things_to_continue_analyzing: list[str] action: Literal["zoom-in", "zoom-out", "move-left", "move-right", "finish"] status: Literal["done", "failed"] = "done" error: str | None = None class CommanderReport(BaseModel): summary: str threat_assessment: Literal["HIGH", "MEDIUM", "LOW", "UNKNOWN"] high_consensus_findings: list[str] # 3+ analysts agree, avg conf ≥ 7 contested_findings: list[str] recommended_next_actions: list[str] class StrategistReport(BaseModel): cross_base_patterns: list[str] priority_bases: list[int] overall_assessment: str ``` ## 测试 ``` .venv/bin/python -m pytest tests/ -v # 13/13 通过 ``` - `tests/test_models.py` —— Pydantic 模型验证(4 个测试) - `tests/test_storage.py` —— 原子化 JSON 读写,运行版本控制(6 个测试) - `tests/test_consensus.py` —— 指挥官共识评分(3 个测试) ## 注意事项 在修改任何内容之前,值得了解的一些棘手问题。 ### LLM 客户端 - **`instructor` 在此环境中已损坏** —— 由于 `mistralai` 版本冲突导致导入失败。请改用原生结构化输出 API(`google.genai` 的 `response_schema` 和 `openai` 的 `beta.chat.completions.parse`)。 - **Gemini**:从 `google.genai` 导入,而不是已弃用的 `google.generativeai`。 - **`gemini-3.1-flash-image-preview`** 是一个*图像生成*模型。对于视觉*分析*,请使用 `gemini-3.1-pro-preview`。 - **OpenAI**:指挥官/战略家只使用 `gpt-5.x` 模型 —— 绝不要使用 `gpt-4.x`。 ### Sentinel Hub (Copernicus Data Space) - 使用 `SENTINELHUB_CLIENT_ID2` 和 `SENTINELHUB_CLIENT_SECRET2` —— 原始的(`CLIENT_ID` / `CLIENT_SECRET`)对 CDSE 无效。 - 必须设置全部三个 `SHConfig` URL 字段:`sh_auth_base_url`、`sh_token_url`、`sh_base_url`。 - 仅设置 `config.sh_base_url` **不能**覆盖请求 URL。您还必须重新定义数据集合: cdse_s2 = DataCollection.SENTINEL2_L2A.define_from( "SENTINEL2_L2A_CDSE", service_url="https://sh.dataspace.copernicus.eu", ) ### Streamlit 仪表板 - `DATA_PATH` 必须是绝对路径:`Path(__file__).parent / "data.json"`。 - “Run analysis”按钮必须使用绝对 Python 路径**以及**显式的 `cwd` 来启动分析器: subprocess.Popen( [str(PROJECT_ROOT / ".venv/bin/python"), "base_analyzer.py"], cwd=str(PROJECT_ROOT), ) - Folium 地图使用 `MarkerCluster(disableClusteringAtZoom=8)`,这样四个埃及 SA-2 阵地(在约 0.17° 范围内)就不会在视觉上合并。 ### `data.json` 版本控制 运行记录是追加的。不要原地替换 `runs[-1]` —— `start_run()` 会使用 CSV 派生的 `latitude`/`longitude` 字段创建一个新条目,并且每个基地的跳过逻辑依赖于该最新运行中的 `status`。
标签:Black Hat, DLL 劫持, ESC4, Folium, GIS, Google Maps API, Kubernetes, LangGraph, LLM, Multi-Agent, OSINT, PyRIT, Sentinel Hub, Streamlit, Unmanaged PE, Vision-LLM, 人工智能, 军事侦察, 军事基地, 卫星图像分析, 地理信息系统, 多智能体系统, 大语言模型, 威胁评估, 实时仪表盘, 情报分析, 数据聚合, 用户模式Hook绕过, 网络诊断, 自动化情报管线, 视觉大模型, 访问控制, 逆向工具, 遥感分析