高校 ICT 产教融合创新大赛 · 赛题九(奇安信)
多源安全情报采集 → 归一化 → LangGraph 多 Agent 富化 → GraphRAG 跨文档问答 → REST / React 控制台
导航:简介 · 架构 · 技术栈 · 快速开始 · 常用命令 · API · 目录结构 · 数据来源 · 质量 · 协作
围绕「AI 安全」主题构建一条可复现的情报流水线,共六层:
| 层 | 名称 | 技术约束 | 职责 |
|---|---|---|---|
| L1 | 采集层 | 纯传统代码,禁止 LLM | 多源采集:NVD / OSV / GHSA / KEV / EPSS / arXiv / OpenAlex / 厂商仓库公告 / 安全博客 RSS |
| L2 | 归一化层 | 纯函数,禁止 LLM | CVE / CVSS / CPE / 时间 / 文本统一,精确 + 近似去重与幂等合并 |
| L3 | 富化层 | LangGraph 多 Agent(7 Agent + 回流条件边) | 五维度富化:受影响资产 / 关联论文 / PoC·EXP / 风险分 / 攻击链(+ 修复建议) |
| L4 | 问答层 | LangGraph 多 Agent | SQL / Cypher / Vector 三路检索 → 证据缺口检测 → 受控外部检索 → 多跳推理 → 强制引用回溯 |
| L5 | 服务层 | FastAPI | REST + 指标/探活 + 问答历史 |
| L6 | 前端 | React 18 + Vite + TypeScript + Tailwind(Nginx 托管) | 总览看板 / 漏洞列表 / 漏洞详情 / 知识图谱 / 智能问答(含历史)/ 数据质量 |
三条贯穿全项目的设计约束:
- 三个冻结契约:
RawItem/UnifiedVuln/EnrichedVuln是全系统唯一的跨层契约,任何变更走 §10.3「只增不改」(新增字段带默认值 +schema_version递增)。 - 供应商无关:LLM 出口唯一收敛在
llm/provider.py;切换模型供应商只改.env(LLM_PROVIDER/LLM_BASE_URL/LLM_MODEL_*),代码零改动。 - 可回溯:结论 → 引用 →
trace_id→ 源原文链接;问答答案强制携带可回溯引用。
完整架构、排期、验收标准与风险应对见 PROJECT_PLAN.md(项目唯一基线)。
┌──────────────────── L1 采集(connectors/,禁 LLM)────────────────────┐
NVD OSV GHSA KEV EPSS arXiv OpenAlex 厂商仓库公告 安全博客 RSS → RawItem
└──────────────────────────────────┬───────────────────────────────────┘
▼
L2 归一化(normalize/,纯函数):CVE/CVSS/CPE/时间/文本 → 去重合并 → UnifiedVuln
▼
L3 富化(enrich/,LangGraph 7 Agent):资产 / 论文 / PoC / 风险分 / 攻击链(+ 修复建议)
│ ── Verifier 置信度闸门 + 回流条件边 ──
EnrichedVuln
┌───────────────┬──────────────────┴──────────────────┬───────────────┐
▼ ▼ ▼ ▼
PostgreSQL Neo4j(图谱) ChromaDB(向量) LLM 缓存
└───────────────┴──────────────────┬──────────────────┴───────────────┘
▼
L4 问答(qa/,LangGraph):Supervisor → Router → SQL/Cypher/Vector → 缺口检测
→ 受控外部检索 → Reasoner → Synthesizer
▼
L5 API(api/,FastAPI) L6 前端(frontend-react/,React)
存储三件套均可降级:PostgreSQL→SQLite、Neo4j→关闭并退化为 PG JSON、ChromaDB→内存 / 哈希嵌入。
| 领域 | 选型 |
|---|---|
| 语言 / 运行时 | Python 3.11(>=3.11,<3.12);前端 Node 18+ |
| 数据模型 / 配置 | Pydantic v2、pydantic-settings(.env)、PyYAML |
| 存储 | SQLAlchemy 2.0 async、Alembic(迁移 0001–0010)、PostgreSQL 16(asyncpg)/ SQLite(aiosqlite 降级)、Neo4j 5、ChromaDB |
| 编排 / LLM | LangGraph、langchain-core、langchain-openai(OpenAI 兼容:DeepSeek 云端 / Ollama 本地) |
| 服务 | FastAPI、uvicorn、sse-starlette、APScheduler |
| 前端 | React 18、Vite 5、TypeScript、TailwindCSS、TanStack Query/Table、ECharts、React Flow(@xyflow/react)、lucide-react |
| 质量 | pytest(+ asyncio / cov / respx)、ruff、mypy、GitHub Actions(CI/CD) |
# 推荐:仓库内本地虚拟环境(.venv/ 已被 .gitignore 排除)
py -3.11 -m venv .venv
.\.venv\Scripts\Activate.ps1# 完整依赖(采集 / 存储 / Agent / 服务)
pip install -e .
# 测试与静态检查
pip install -e ".[dev]"
# 前端(独立 Node 工程)
cd frontend-react; npm install; cd ..copy .env.example .env
# 至少填写:LLM_API_KEY(DeepSeek);建议填写 NVD_API_KEY、GITHUB_TOKEN(GHSA/厂商公告用)密钥安全约定:所有密钥字段为 SecretStr,日志一律走 Settings.masked(),禁止输出明文。
copy .env.example .env # 首次
docker compose up -d --build # pg / neo4j / chroma / api / scheduler / frontend-react 共 6 服务
docker compose ps # 期望全部 (healthy)
docker compose exec api python -m scripts.init_db # 迁移到 head(含 0010 qa_history)
docker compose exec api python -m scripts.seed_sources # 登记采集源访问:API http://localhost:8000/docs | 前端(Nginx)http://localhost:3000
docker compose up -d postgres neo4j chroma # 三件套(或 docker-compose.degraded.yml 只起 PG)
python -m scripts.init_db
python -m scripts.seed_sources
python -m scripts.run_collect --source all --limit 50 --normalize # 采集 + 归一化
python -m scripts.run_enrich --limit 20 # 富化
python -m scripts.load_graph # 图谱入库(Neo4j)
python -m scripts.index_vectors # 向量入库(Chroma)
uvicorn aisec_intel.api.main:app --reload --port 8000 # 后端 API
cd frontend-react; npm run dev # 前端 http://localhost:5173前端本地开发用 Vite dev server(/api → localhost:8000 代理,见 frontend-react/vite.config.ts);容器方式由 Nginx 同源反代 /api → api:8000。
$env:DEGRADED_MODE = "true" # SQLite + 内存 Chroma + 跳过多跳 Reasoner
$env:NEO4J_ENABLED = "false" # 图谱退化为 PG JSON(跳数 ≤2)
python -m scripts.init_db # 建出 data/aisec.db(含全部表)| 命令 | 作用 |
|---|---|
python -m scripts.init_db |
Alembic upgrade head 建表(DATABASE_URL > 降级 SQLite > PG_DSN) |
python -m scripts.seed_sources |
按 configs/sources.yaml 登记采集源到 source 表 |
python -m scripts.run_collect --source all --limit 50 [--normalize] [--since ...] |
采集(可选即归一化);--list-sources 查看已注册源 |
python -m scripts.run_enrich [--limit N] [--only-missing] |
富化指定/缺失条目 |
python -m scripts.load_graph / scripts/clean_graph.py |
Neo4j 图谱装载 / 清理(--max-components-per-vuln 限流) |
python -m scripts.index_vectors |
构建 / 重建 Chroma 向量索引(--rebuild、--dry-run) |
python -m scripts.run_scheduler [--list] |
常驻调度器(pipeline 四层 + 每日 02:00 维护 job),--list 打印计划 |
python -m scripts.retry_failed [--list] [--limit N] [--cve ...] |
失败重试队列(needs_human → 最多 3 次 → permanently_failed) |
python -m scripts.health_check |
中间件 + 数据源 + LLM 全链路探活 |
python -m scripts.qa_ask "问题" |
命令行问答(退出码 0/2/1) |
python -m scripts.smoke_llm |
LLM 连通性冒烟(chat / structured) |
python -m scripts.data_quality |
数据质量报告(字段完整率等) |
python -m scripts.backfill_published_at [--apply] [--null-out] |
发布时间历史回填(默认 dry-run) |
python -m scripts.run_perf_benchmark |
性能基准 |
前缀 /api/v1(Swagger:/docs)。
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /qa/ask |
自然语言问答(Supervisor→Reasoner→Synthesizer),返回带引用的结构化答案 |
| GET | /qa/health |
问答链路探活(配置快照 + 主干节点 + 限流额度) |
| GET | /qa/history |
问答历史列表(session_id / limit / offset) |
| GET | /qa/history/{id} |
问答历史详情(缺失 404) |
| DELETE | /qa/history/{id} |
删除单条问答历史(缺失 404) |
| DELETE | /qa/history?session_id= |
按会话删除;不带参数则清空全部 |
| GET | /vulnerabilities |
漏洞列表(分页 + severity/source/kev/since 筛选) |
| GET | /vulnerabilities/{cve_id} |
漏洞详情(事实层 + 富化层双契约) |
| GET | /stats |
仪表盘统计聚合 |
| GET | /graph · /graph/{cve_id} |
全图概览 · 单漏洞 N 跳子图(React Flow 格式) |
| GET | /data-quality |
数据质量报告 |
| GET | /papers/{paper_id} |
论文详情 |
运维端点(无 /api/v1 前缀):/healthz、/readyz、/metrics。
src/aisec_intel/
├─ models/ # ★接口层:冻结契约 RawItem / UnifiedVuln / EnrichedVuln(+ agent_io / qa_history / paper / external_evidence)
├─ connectors/ # L1 采集(BaseConnector,禁止 LLM):nvd/osv/ghsa/kev/epss/arxiv/openalex/vendor_github/rss_blog
├─ normalize/ # L2 归一化(纯函数,禁止 LLM):cve / cvss / dedupe / pipeline / datetime_utils
├─ enrich/ # L3 富化(LangGraph 7 Agent + 回流条件边)
├─ qa/ # L4 问答(LangGraph:Supervisor → Router → SQL/Cypher/Vector → Reasoner → Synthesizer)
├─ graph/ # 知识图谱抽取与装载(Neo4j)
├─ llm/ # LLM Provider 抽象(唯一模型出口)+ 结构化输出 + 缓存 + 降级
├─ security/ # Prompt 注入防护 + 输入清洗 + 输出二次校验
├─ storage/ # 结构化(PG/SQLite)/ 图谱 / 向量 适配 + repositories
├─ api/ # L5 FastAPI(main / deps / routers / schemas)
├─ services/ # 任务级业务编排(采集 / 富化 / 检索 / 问答历史 / 告警 / 指标 / 质量)
├─ utils/ # 限流 / HTTP / 哈希 / 文本 / 时间工具
├─ config.py # pydantic-settings 全局配置
└─ logging_config.py # 结构化日志 + trace_id
migrations/ # Alembic 迁移(★勿改名为 alembic/:会遮蔽第三方 alembic 包)
configs/ # sources.yaml(采集源开关/限流/调度)、prompts/
scripts/ # 见「常用命令」;init_db / run_collect / run_enrich / load_graph / index_vectors ...
frontend-react/ # L6 前端(唯一前端:React + Vite + TS + Tailwind,Nginx 托管 :3000)
tests/ # unit/(离线单测)+ integration/(真实网络,-m integration)
reports/ # 评测报告、接口冻结记录、答辩材料
文档落点约定:docs/、data/、logs/、*.csv、*.pdf 被 .clineignore 排除,需协作编辑与提交的文档只落在仓库根目录与 reports/。
| 数据源 | 用途 | 许可 / 合规处理 |
|---|---|---|
| NVD / CVE List v5 | 漏洞主数据 | 美国政府公开数据(Public Domain) |
| OSV.dev / GitHub Advisory | 生态包漏洞与修复版本 | 公开数据,仅存元数据 |
| CISA KEV / FIRST EPSS | 被利用情况与利用概率 | 公开数据 |
| arXiv / OpenAlex | AI 安全论文关联 | 只存标题、摘要与元数据,不存全文 PDF |
| 厂商仓库公告 / 安全博客 RSS | 事件背景 | 只存标题、链接与摘要 |
本项目所有结论均可通过 trace_id 回溯到上述来源原文链接。
python -m pytest # 单元/集成单测(默认跳过 -m integration,离线可复现)
python -m pytest -m integration # 真实网络/外部依赖的集成测试
python -m ruff check src tests scripts migrations # 静态检查
python -m mypy src # 类型检查(增量零容忍策略)- 测试规模:约 1096 个用例(默认运行);含
integration共 1117 个。 - 静态检查:
ruff全绿;mypy存量基线见reports/ci_baseline.md。 - CI/CD:
.github/workflows/{ci,cd}.yml(ruff / mypy 增量阻断 / pytest + 覆盖率门禁 / GHCR 镜像推送)。 - 可观测性:结构化 JSON 日志(含
trace_id)、/metrics指标、告警日志(可选 Webhook)、自愈日志。
- 编码规范:
.clinerules/coding-standards.md(分层约束、Pydantic、type hints、BaseConnector)。 - 计划书引用规则:
.clinerules/plan-reference.md(按章节引用,禁止整文件读取)。 - 接口冻结与变更流程:
reports/INTERFACE_FREEZE.md、PROJECT_PLAN.md§10.3(只增不改)。 - 项目基线(唯一):
PROJECT_PLAN.md——架构、排期、验收、风险应对、逐日修订记录(§12)。