ScenarioEngine 是一个面向生产环境的场景编排与仿真平台,覆盖场景创建、仿真回放、运行期控制、知识检索,以及 AI 辅助的兵棋推演工作流。
本仓库围绕清晰的职责边界组织:
- 后端是运行期事实源(source of truth),负责持久化仿真运行、快照、事件、AI 动作和知识库状态。
- 前端是功能完备的操作员控制台,负责镜像后端状态,并通过认证 API 与实时通道发送指令。
- 运行时支持本地模式与容器化模式,并对安全、可观测性和自动化 AI 能力保留显式约束。
推荐阅读顺序:
ScenarioEngine 提供一个浏览器化的环境,用于:
- 场景创建与编辑
- 仿真运行的启动、单步、暂停、恢复、分支与对比
- 持久化快照与事件以支持回放
- 面向领域知识库的混合检索
- 生成带证据支撑(grounded)的 AI 问答
- 在护栏与审批门约束下编排 AI 驱动的兵棋动作
- 为操作员暴露作战图层(operational overlay)与运行期可观测性
- 将仿真权威(authority)保留在服务端,使客户端无法直接篡改状态。
- 提供统一的 AI 辅助动作工作流层,而不是把 LLM 调用散落到 UI 代码各处。
- 通过逐 tick 快照与事件历史保证可回放性。
- 通过 RBAC、CSRF、Cookie 认证与显式安全默认值支撑运维使用。
- 让知识检索与 AI 提示词可检视、可审计、可测试。
- 场景 CRUD、导入、导出、补丁(patch)、克隆、版本回滚
- 仿真运行的生命周期管理
- 快照与事件回放
- SSE 与 WebSocket 实时更新
- AI 模型 / provider 配置与提示词模板管理
- 知识文档导入与向量化检索
- 兵棋动作的生成、审批、执行与重试
- 按阵营(per-side)的 AI agent 循环,默认保守的 dry-run
- 作战图层与地图配置管理
- 面向分析员、设计师与操作员的内部仿真工具
- 受控环境中的 AI 辅助决策支持
- 基于场景的分析与回放工作流
- 面向领域文档的 RAG 问答
- 带安全门的多智能体 / 自主策略实验原型
- 后端权威的仿真生命周期,由进程内
SimSession持有运行态 - 显式的运行流(run-stream)broker 抽象,含内存实现与 Redis 实现
- 稳定的提示词整形与压缩,用于 token 预算控制
- 领域专属的 AI 动作流:检索、校验、审批、执行、重试
- 本地开发使用 SQLite WAL 调优,部署环境支持 Postgres
- FastAPI 中间件提供请求 ID、CORS 与一致的错误信封
| 层 | 技术 | 说明 |
|---|---|---|
| 前端框架 | React 18 + TypeScript + Vite | UI 代码在 client/src,由 Vite 构建。 |
| UI 体系 | MUI v7 + Emotion | 用于操作员控制台与各类对话框。 |
| 地图栈 | OpenLayers | 主要的地图渲染与图层管理。 |
| 国际化 | react-i18next + locale JSON |
内置中文与英文语言包。 |
| 认证 UI | @auth0/auth0-react + 本地认证界面 |
支持本地化认证流程与后端会话认证。 |
| 后端框架 | FastAPI + Uvicorn | API 入口 backend/app/main.py。 |
| ORM | SQLAlchemy 2.x | 声明式模型在 backend/app/models。 |
| 迁移 | Alembic | 迁移脚本在 backend/alembic。 |
| 校验 | Pydantic v2 + pydantic-settings |
用于 API 契约与配置。 |
| 数据库(默认) | SQLite + WAL | 默认/最小后端(DATABASE_TYPE=sqlite),零外部依赖。 |
| 数据库(规模化,可选) | PostgreSQL 16 | 预留口子(DATABASE_TYPE=postgres),用于 Compose 拓扑。 |
| 向量库 | sqlite-vec(默认)或 Qdrant |
由 VECTOR_BACKEND 选择;默认本地 sqlite-vec,Qdrant 可选。 |
| 对象存储(可选) | MinIO | 用于 Compose 拓扑;最小本地运行不需要。 |
| 运行流 / 缓存(可选) | Redis | 预留口子(RUN_STREAM_BACKEND=redis);默认内存、单进程。 |
| AI SDK / LLM 层 | 基于 httpx 的自研 OpenAI 兼容适配器 |
不使用独立 SDK 封装;provider 在内部统一归一化。 |
| AI providers | OpenAI 兼容 provider、Qwen、DeepSeek、Gemini、Ollama | provider 注册表抽象在编排器之后。 |
| 测试框架(前端) | Vitest + Testing Library + JSDOM | 前端与治理测试在 client/src。 |
| 测试框架(后端) | Pytest | 后端测试在 backend/tests。 |
| Lint / 格式化 | ESLint、Prettier、Black、Ruff | JS/TS 与 Python 风格检查分离。 |
| 构建工具 | Vite、TypeScript 项目引用、setuptools、Alembic | 前后端独立构建。 |
| 部署 | Docker Compose | 规范的多服务拓扑在 deployments/docker-compose.yml。 |
说明:
- 代码库中没有 GraphQL 服务。
- 代码库中没有 MCP 工具服务。
- 没有 Kafka / RabbitMQ 这类消息 broker;Redis 是唯一类队列的运行期依赖。
设计取向——默认最小实现。 当前默认跑最轻的可用栈,便于快速看到真实效果:SQLite(无需独立 DB 服务)、内存运行流、本地向量索引。PostgreSQL、Redis、MinIO、Qdrant 是预留的规模化口子——代码里已留好开关(
DATABASE_TYPE、RUN_STREAM_BACKEND、VECTOR_BACKEND),Compose 拓扑也接好了线,体量上来再启用即可,本地运行并不需要。一上来就拉全套反而过重、束手束脚。
仓库分为三个主要执行面:
client/:面向操作员的 SPAbackend/:权威的 API 与工作流服务deployments/与scripts/:本地编排、启动辅助与运维手册
后端是以下内容的记录系统(system of record):
- 仿真运行
- 快照与事件
- AI 请求与决策
- 知识文档与分块
- 用户、角色与活动锁状态
graph TD
U[Operator / Analyst / AI Agent] --> C[React SPA]
C -->|REST / SSE / WS| A[FastAPI Backend]
A --> S[SimulationService]
A --> O[AIOrchestrator]
A --> F[ChatFlow]
A --> W[WargameActionFlow]
A --> R[RetrievalPipeline]
A --> M[Map / Overlay Services]
S --> SS[SimSession / SimSessionManager]
SS --> G[BLADE Game Kernel]
W --> X[WargameActionExecutor]
W --> V[Validator / Approval Gate]
W --> K[Context Assembler + RAG]
O --> Q[LLM Provider Adapters]
F --> Q
R --> DB[(PostgreSQL / SQLite)]
S --> DB
O --> DB
W --> DB
R --> VS[(sqlite-vec / Qdrant)]
A --> RS[RunStreamBroker]
RS --> C
A --> MI[(MinIO)]
A --> REDIS[(Redis)]
A --> TS[TileServer GL]
典型仿真流程:
- 客户端向
/api/v1/simulations/...发送命令。 SimulationService加载运行记录、解析出活跃的SimSession,并转发命令。SimSession持有进程内的Game实例,推进 tick 或应用变更。SimulationService持久化产生的快照与事件行。RunStreamBroker向 SSE/WebSocket 订阅者发布运行态更新。- 前端收到更新并刷新操作员视图。
AI 动作流程:
- 客户端或 side-agent 提交一个
AiActionRequest。 WargameActionFlow解析上下文、检索证据、提示词模板与 LLM 解析。- 审批门判定该动作是可自动执行、待审批、被拒绝,还是 dry-run。
- 已批准的动作经
WargameActionExecutor执行。 - 结果状态被持久化并广播给观察者。
AIOrchestrator是聊天、QA、提示词模板、provider 健康与请求日志的中心 AI 门面。ChatFlow是独立的聊天工作流,使用上下文防火墙与专属提示词注册表。WargameActionFlow是改变仿真状态的权威 AI 动作工作流。WargameAnalysisFlow处理运行分析、对比、摘要与解释任务。SimulationService持有运行生命周期、持久化、回放与流发布。SimSession持有单次运行的活跃可变仿真引擎状态。
仓库不使用单一的顶层 src/ 目录,而是按运行面组织代码。
scenarioengine/
├── client/ # React SPA 与操作员控制台
│ └── src/
│ ├── gui/ # 界面、对话框、地图、工具栏、工作台
│ ├── simulation/ # 流 / WebSocket hook 与同步控制器
│ ├── services/ # API 客户端、认证辅助、遥测
│ ├── runtime/ # 运行模式与权威性校验
│ ├── game/ # 本地场景 / 回放领域模型
│ └── locales/ # i18n 语言包
├── backend/ # FastAPI 后端
│ ├── app/
│ │ ├── api/ # REST、SSE、WebSocket 路由
│ │ ├── core/ # 配置、DB、认证、安全、日志
│ │ ├── domain/ # 仿真、RAG、AI 领域逻辑
│ │ ├── modules/ # 更高层工作流 / 限界上下文
│ │ ├── services/ # 应用服务与编排
│ │ ├── models/ # SQLAlchemy 实体
│ │ ├── schemas/ # Pydantic 请求/响应契约
│ │ ├── integrations/ # LLM / 向量 / 对象存储 / 地图适配器
│ │ ├── protocol/ # 共享协议对象与 v2 契约
│ │ ├── resources/ # 内置装备与机场数据
│ │ └── data/ # 本地包(预置、别名),供独立客户端使用
│ ├── scripts/ # init_db / init_config_center / init_vectordb、导入脚本
│ ├── alembic/ # 数据库迁移
│ └── tests/ # Pytest 测试集
├── gym/ # 仿真内核 / 场景逻辑
├── data/ # openmaptiles 配置 + 本地 .mbtiles(git 忽略)
├── models/ # 本地 embedding 模型 —— 见 models/README.md
├── tools/ # 本地工具(tileserver-gl)—— 见 tools/tileserver-gl/README.md
├── deployments/ # Docker Compose 与部署手册
├── scripts/ # 启动辅助、守卫检查、冒烟测试
├── docs/ # mkdocs 配置(规范文档在 <仓库根>/docs/)
└── reports/ # 生成的报告与产物
client/src/gui:面向用户的地图、工具栏、工作台、对话框与外壳布局client/src/simulation:SSE 与 WebSocket 运行流的传输 hookclient/src/runtime:保持各运行面互斥的运行模式守卫client/src/services:API 绑定与 UI 侧集成辅助backend/app/api:HTTP 入口与认证门backend/app/services:应用编排与持久化逻辑backend/app/domain:仿真、RAG 与 AI 的领域工作流backend/app/modules:更高层工作流与限界上下文backend/app/models:持久化 SQL 数据模型backend/app/schemas:请求/响应信封与 DTObackend/app/core:配置、DB 引导、安全、指标与日志deployments:环境级编排,非业务逻辑
backend/app/main.py 串联:
- 日志
- 安全告警
- RAG 启动检查
- 依赖引导
- 知识库对账器启动
- 仿真服务关停时的刷盘
- CORS
- 全局错误处理
/health与/metrics
backend/app/bootstrap.py 准备运行时:
- 在合适时机启动外部本地服务
- 初始化 SQLAlchemy 引擎
- 播种认证与 AI 默认值
- 重启后恢复或降级陈旧运行
- 恢复待处理的 KB 文档与陈旧 AI 动作
- 库为空时播种本地场景
为什么重要:
- 项目需要一套既适合本地开发、又适合类生产部署的统一启动序列。
- 恢复逻辑集中化,让重启行为可预测。
- 安全与 RAG 配置在启动时校验,而不是在系统已对外服务后才发现问题。
代码库中最强的架构决策:活跃仿真状态由 SimSession 持有,而不是客户端、也不是无状态的 API 处理器。
关键部件:
SimulationService是应用层门面。SimSessionManager是按run_code索引的进程内注册表。SimSession为每次运行持有唯一的活跃Game实例。SimulationService持久化快照/事件并发出流更新。
为什么这样设计:
- 系统必须为仿真状态保留单一事实源。
- 快照持久化与活跃仿真状态需保持同步。
- 该架构支撑确定性回放与重启恢复。
AIOrchestrator 持有通用的、面向 LLM 的能力:
- provider 注册表与模型配置
- 提示词模板存储
- 聊天会话管理
- QA 答案生成
- 请求日志
- 检索轨迹访问
编排器有意不再负责兵棋动作执行——该职责被分离到 WargameActionFlow 与 WargameAnalysisFlow。
为什么这样拆分:
- 聊天、QA、分析与动作执行有不同的风险画像。
- 共享 provider 代码保持可复用,而工作流专属策略保持隔离。
- 降低不相关 AI 路径之间的提示词与 schema 耦合。
backend/app/modules/wargame/action_flow/wargame_action_flow.py 是 AI 发起的仿真动作的权威管线。
流程:
- 构建或复用候选动作。
- 收集上下文与检索证据。
- 必要时解析 LLM 输出。
- 评估护栏与审批要求。
- 持久化
AiAction行。 - 仅在策略允许时执行。
重要的安全行为:
- 动作可 dry-run
- 执行前可能需要审批
- 无效或高风险动作被拒绝
- 重试受约束
为什么有效:
- 动作生命周期端到端可审计。
- 业务逻辑、审批策略与执行互不混淆。
- 每个阶段可独立测试。
backend/app/services/ai_side_agent.py 实现第二阶段的按阵营 agent 循环。
设计要点:
- agent 按阵营注册
- 默认 agent 是 no-op 桩
- 每个 agent 获得只读的
SideAgentContext - 循环是尽力而为(best-effort),不能阻塞 tick 引擎
- 每次运行对提议(proposal)限速
- 提议默认强制 dry-run
提示词设计:
- 稳定状态与逐 tick 易变状态分离
- doctrine/persona 文本以缓存友好的方式追加
- 事件过滤按阵营感知,降低信息泄露风险
为什么重要:
- 让自主行为变成可选且保守。
- 保留提示词缓存机会。
- 避免某个坏 agent 拖垮整个运行循环。
backend/app/domain/rag/retrieval_pipeline.py 是混合检索管线。
它组合了:
- 查询预处理与改写
- 基于 SQL 的关键词检索
- 向量检索
- 邻居扩展
- 去重
- 重排(rerank)
- 响应组装与遥测
后端还会对账 SQL 行与向量库之间的知识漂移。
为什么这样设计:
- SQL 仍是文档元数据与片段的事实源。
- 向量索引加速语义搜索,而不取代规范记录。
- 检索遥测让质量回退可度量。
backend/app/domain/sim/run_stream.py 提供运行流 broker 抽象。
支持的行为:
- 单进程开发的内存订阅
- 面向多实例就绪的 Redis 后端
- 运行房间(run room)与 actor 房间订阅
- SSE 与 WebSocket 广播
- 心跳跟踪与丢弃计数
为什么契合:
- 运行时可以从简单起步并保持可扩展。
- Redis 不可用时后端可优雅降级。
- 流健康的可观测性内建在 broker 里。
认证为基于 Cookie 的 JWT,对浏览器会话提供 CSRF 保护,并支持对直连请求使用 Bearer token。
安全控制包括:
- 基于角色的访问检查
- 对 Cookie 认证的状态变更请求强制 CSRF
- 非 dev 环境在启动时拒绝不安全的默认值
- 角色门控的 AI/模型/管理面
为什么重要:
- 项目面向共享的运维环境,而非单用户玩具应用。
- 安全默认值在启动时校验,配置错误尽早失败。
sequenceDiagram
participant U as Client / Operator
participant A as FastAPI API
participant S as SimulationService
participant SS as SimSession
participant DB as Database
participant RS as RunStreamBroker
participant C as Other Clients
U->>A: POST /api/v1/simulations/runs/{run_code}/step
A->>S: step()
S->>SS: handle_command_sync({type:"step"})
SS->>SS: advance Game one tick
SS-->>S: StateSnapshotV2
S->>DB: persist snapshot + event
S->>RS: publish run_state update
RS-->>C: SSE / WS update
RS-->>U: live refresh event
sequenceDiagram
participant U as Client / Agent
participant A as FastAPI API
participant W as WargameActionFlow
participant R as Retrieval / Context Assembler
participant L as LLM Provider
participant G as Guardrail / Approval Gate
participant X as Executor
participant DB as Database
U->>A: POST /api/v1/simulations/runs/{run_code}/ai/actions
A->>W: request_action(...)
W->>R: build context + retrieval
W->>L: parse or generate candidate
W->>G: evaluate risk / approval
W->>DB: persist AiAction
alt approved and auto-executable
W->>X: execute(candidate)
X->>DB: persist result
else dry-run / pending approval
W-->>A: return pending / dry-run record
end
- 请求路径显式、易于审计。
- 在每个重要步骤持久化状态转换。
- LLM 失败与仿真权威隔离。
- 实时订阅者无需轮询数据库即可拿到更新。
项目使用 SQLAlchemy ORM 模型,而非 Prisma、TypeORM 或 Mongoose。
| 实体 | 职责 | 核心字段 | 生命周期 |
|---|---|---|---|
SimScenario |
场景定义 | scenario_code、name、scenario_json、status、version_no |
由设计者创建,可版本化、克隆、导出、回滚 |
SimSimulationRun |
持久化运行记录 | run_code、scenario_code、status、snapshot_tick、pause_reason、parent_run_code、ai_autonomous_enabled |
从场景创建,随时间推进,暂停/停止,分支,软删除 |
SimStateSnapshot |
tick 快照 | run_code、tick、snapshot |
在权威 tick 与回放同步后写入 |
SimEvent |
事件审计轨迹 | run_code、event_type、tick、payload |
运行期追加,用于回放 / 分析 |
| 实体 | 职责 | 核心字段 | 生命周期 |
|---|---|---|---|
AiModelProvider |
provider 目录 | provider_code、name、enabled |
引导时播种,在管理 UI 维护 |
AiModelConfig |
模型绑定 | provider_code、model_name、base_url、api_key_ref、extra_config |
选为活跃模型,必要时应用到环境变量 |
AiPromptTemplate |
提示词模板 | 模板编码、版本、启用标志 | 由聊天、QA 与动作工作流使用 |
AiConversation |
聊天线程头 | conversation_id、title、created_by |
聊天开始时惰性创建 |
AiMessage |
聊天历史 | conversation_id、role、content、request_id |
每轮追加,按预算规则压缩 |
AiAction |
可审计 AI 动作 | action_id、run_code、scenario_id、status、risk_level、decision_json、command_json、patch_json、result_json |
起草、批准/拒绝/执行/失败,允许时重试 |
AiRequestLog |
LLM 审计日志 | 请求/响应载荷、token 用量、成本 | 写入聊天/QA/动作轨迹 |
AiRetrievalTrace |
检索轨迹 | request_id、document_code、chunk_no、score、rank |
存储 grounded 答案背后的证据 |
| 实体 | 职责 | 核心字段 | 生命周期 |
|---|---|---|---|
KbDocument |
文档头 | document_code、name、file_type、parse_status、index_status、last_index_error |
导入、索引、修复、重建索引 |
KbDocumentVersion |
版本化源文本 | document_code、version_no、content、content_hash |
保留历史内容以供修复与回滚 |
KbDocumentChunk |
分块级检索单元 | document_code、chunk_no、chunk_text、chunk_hash、embedding_model |
由分块与索引管线产生 |
KbEquipmentProfile |
结构化装备知识库 | equipment_code、name、name_zh_tw、category、platform_type |
作为关键词检索的旁路通道 |
| 实体 | 职责 | 核心字段 | 生命周期 |
|---|---|---|---|
SysUser |
本地用户账号 | username、display_name、password_hash、status |
为本地认证播种,由管理工具控制 |
SysRole |
角色目录 | role_code、name |
驱动授权检查 |
SysUserRole |
用户-角色关联 | username、role_code |
实现多对多授权映射 |
SysUserActivityLock |
活动租约 | user_id、kind、scope_type、scope_key、expires_at |
防止互相冲突的交互模式 |
erDiagram
SIM_SCENARIOS ||--o{ SIM_SIMULATION_RUNS : "scenario_code"
SIM_SIMULATION_RUNS ||--o{ SIM_STATE_SNAPSHOTS : "run_code"
SIM_SIMULATION_RUNS ||--o{ SIM_EVENTS : "run_code"
SIM_SIMULATION_RUNS ||--o{ AI_ACTION : "run_code"
AI_MODEL_PROVIDERS ||--o{ AI_MODEL_CONFIGS : "provider_code"
AI_CONVERSATIONS ||--o{ AI_MESSAGES : "conversation_id"
KB_DOCUMENTS ||--o{ KB_DOCUMENT_VERSIONS : "document_code"
KB_DOCUMENTS ||--o{ KB_DOCUMENT_CHUNKS : "document_code"
SYS_USERS ||--o{ SYS_USER_ROLES : "username"
SYS_USERS ||--o{ SYS_USER_ACTIVITY_LOCKS : "user_id"
- 场景定义只存一次,随后通过快照拷贝进运行。
- 运行以追加为主:快照与事件历史随时间增长。
- 知识文档做版本化,使索引错误可在不丢失源文本的前提下修复。
- AI 动作在执行决策做出后即为不可变的审计记录。
多数路由返回统一的成功信封:
{
"code": 0,
"message": "success",
"data": {},
"request_id": "req_..."
}错误使用结构化信封,含 code、message、error_type、trace_id 与 details。
| 端点 | 方法 | 请求 | 响应 |
|---|---|---|---|
/health |
GET | 无 | 纯文本健康状态 |
/metrics |
GET | 无 | Prometheus 风格文本指标 |
/api/v1/runtime-info |
GET | 无 | 部署/运行模式快照 |
/api/v1/auth/login |
POST | 用户名/口令 | 用户资料、会话 Cookie、CSRF Cookie |
/api/v1/auth/logout |
POST | 会话 Cookie + CSRF | 登出结果 |
/api/v1/auth/me |
GET | 认证 Cookie 或 Bearer | 当前用户 |
/api/v1/system/health |
GET | 需认证 | 系统健康摘要 |
/api/v1/system/ai-side-agent/status |
GET | 需认证 | side-agent 运行态快照 |
| 端点 | 方法 | 请求 | 响应 |
|---|---|---|---|
/api/v1/scenarios |
GET | 分页 + 关键词 | 场景分页 |
/api/v1/scenarios |
POST | ScenarioCreate |
场景行 |
/api/v1/scenarios/import |
POST | 导入载荷 | 导入的场景 |
/api/v1/scenarios/{id} |
GET | 需认证 | 场景详情 |
/api/v1/scenarios/{id} |
PUT | ScenarioUpdate |
更新后的场景 |
/api/v1/scenarios/{id}/patch |
POST | JSON Patch 请求 | patch 结果,可能创建新版本 |
/api/v1/scenarios/{id}/clone |
POST | name 查询参数 |
克隆的场景 |
/api/v1/scenarios/{id}/export |
GET | 需认证 | 导出包 |
/api/v1/scenarios/{id}/versions |
GET | 需认证 | 版本列表 |
/api/v1/scenarios/{id}/rollback/{version_no} |
POST | 无 | 回滚后的场景 |
| 端点 | 方法 | 请求 | 响应 |
|---|---|---|---|
/api/v1/simulations |
GET | 过滤条件 | 运行列表 |
/api/v1/simulations/runs |
POST | SimulationRunCreate |
新运行 |
/api/v1/simulations/runs/{run_code} |
GET | 无 | 运行详情 |
/api/v1/simulations/runs/{run_code}/step |
POST | 无 | 下一快照 |
/api/v1/simulations/runs/{run_code}/control |
PATCH | SimulationRunControl |
更新后的运行 |
/api/v1/simulations/runs/{run_code}/stop |
PATCH | SimulationRunStop |
停止的运行 |
/api/v1/simulations/runs/{run_code}/ai-mode |
POST | SimulationRunAiModeIn |
自主-AI 开关更新 |
/api/v1/simulations/runs/{run_code}/commands |
POST | move/step/batch/压缩命令 | 快照 |
/api/v1/simulations/runs/{run_code}/observability |
GET | 无 | 运行期可观测性载荷 |
/api/v1/simulations/runs/{run_code}/latest-snapshot |
GET | 无 | 最新快照 |
/api/v1/simulations/runs/{run_code}/events |
GET | 无 | 事件列表 |
/api/v1/simulations/runs/{run_code}/snapshots |
GET | 无 | 快照列表 |
/api/v1/simulations/runs/{run_code}/timeline |
GET | 无 | 时间线包 |
/api/v1/simulations/runs/{base}/compare/{compare} |
GET | 无 | 结构化对比 |
/api/v1/simulations/runs/{base}/compare/{compare}/ai |
GET | 无 | 对比 + AI 解读 |
/api/v1/simulations/runs/{run_code}/analysis |
GET | 无 | 态势分析 JSON |
/api/v1/simulations/runs/{run_code}/explain |
GET | 无 | 事件解释 JSON |
/api/v1/simulations/runs/{run_code}/summary |
GET | 无 | 摘要 JSON |
/api/v1/simulations/runs/{run_code}/branch/{tick} |
POST | 无 | 分支 run code |
/api/v1/simulations/runs/{run_code}/restore/{tick} |
POST | 无 | 恢复的快照 |
| 端点 | 方法 | 请求 | 响应 |
|---|---|---|---|
/api/v1/ai/models/providers |
GET/POST | provider 载荷 | provider 目录 |
/api/v1/ai/models/configs |
GET/POST | 模型配置载荷 | 配置行 |
/api/v1/ai/models/configs/quick |
POST | 快速配置载荷 | 单个配置 |
/api/v1/ai/models/configs/health |
GET | 无 | 活跃模型健康 |
/api/v1/ai/models/configs/apply-env |
POST | 无 | 环境应用结果 |
/api/v1/ai/models/prompts |
GET/POST | 提示词模板载荷 | 提示词模板 |
/api/v1/ai/models/logs |
GET/DELETE | limit 或无 | 请求日志 |
/api/v1/ai/models/governance |
GET/POST | 治理载荷 | 治理状态 |
/api/v1/search |
POST | KnowledgeSearchRequest |
混合检索响应 |
/api/v1/qa |
POST | QaRequest |
grounded 答案 |
/api/v1/qa/traces |
GET | request_id 查询 |
检索轨迹列表 |
/api/v1/documents |
GET/POST | 过滤或创建载荷 | 文档列表或详情 |
/api/v1/documents/import |
POST | multipart 上传 | 导入结果 |
/api/v1/documents/{document_code} |
GET/PUT | 文档详情或更新 | 文档详情 |
/api/v1/documents/{document_code}/versions |
GET/POST | 版本请求 | 版本行或更新详情 |
/api/v1/documents/{document_code}/chunks |
GET | 无 | 分块列表 |
/api/v1/documents/{document_code}/reindex |
POST | 无 | 重建索引的文档 |
/api/v1/kb/reconcile |
POST | auto_repair 查询 |
对账结果 |
| 端点 | 方法 | 请求 | 响应 |
|---|---|---|---|
/api/v1/map-config |
GET/PUT | 地图配置载荷 | 当前地图配置 |
/api/v1/map-config/providers |
GET | 无 | provider 列表 |
/api/v1/operational-overlay/scenarios/{scenario_code} |
GET | 无 | GeoJSON 图层 |
/api/v1/operational-overlay/runs/{run_code} |
GET | include_scenario_features 查询 |
GeoJSON 图层 |
| 端点 | 方法 | 请求 | 响应 |
|---|---|---|---|
/api/v1/activity-locks/acquire |
POST | 获取锁载荷 | 加锁结果 |
/api/v1/activity-locks/release |
POST | 释放锁载荷 | 释放结果 |
/api/v1/guest/... |
GET | 无 | 启用时的未认证只读镜像 |
| 端点 | 类型 | 用途 | 说明 |
|---|---|---|---|
/api/v1/simulations/runs/{run_code}/stream |
SSE | 运行可观测性流 | 前端与其他客户端使用 |
/api/v1/simulations/runs/{run_code}/stream/ws |
WebSocket | 运行可观测性流 | 接受 Cookie 或 token 认证 |
/api/v1/simulations/runs/{run_code}/actors/{actor_id}/stream/ws |
WebSocket | actor 专属流 | 实时 actor UI 更新 |
- 未实现 GraphQL 端点。
- 未实现 MCP 工具端点。
- 没有独立的公共 gRPC 面。
接口约定细节亦可参考后端代码与
docs/(如backend/docs/ai_rag_api_usage.md)。
前置:Git、Node.js 18.x、Python ≥3.11。所有命令在仓库根目录(含 scenarioengine/ 与 start_dev.py 的那一层)执行。
# 1) 在仓库根创建并激活虚拟环境 —— start_dev.py 要求 ./.venv
python -m venv .venv
# Windows: .venv\Scripts\activate
# macOS/Linux: source .venv/bin/activate
# 2) 后端依赖([local-embedding] extra 启用本地 KB 向量)
pip install -e "scenarioengine/backend[local-embedding]"
# 3) 前端依赖(可选:tileserver-gl 用于本地地图瓦片)
cd scenarioengine/client && npm install && cd ../..
# 可选:cd scenarioengine/tools/tileserver-gl && npm install && cd ../../..
# 4) 配置 —— 复制 env 模板,并在 backend/.env 填入真实 LLM Key 与密钥
cp scenarioengine/backend/.env.example scenarioengine/backend/.env
cp scenarioengine/client/.env.example scenarioengine/client/.env
# 5) 初始化数据库并启动整个栈
python start_dev.py start --init-db随后打开 http://127.0.0.1:3000 登录。数据库初始化会自动创建管理员账号(代码默认 admin / admin123),init_db 完成时会把登录信息打印出来。可用 backend/.env 的 LOCAL_ADMIN_* 覆盖,共享部署前请务必修改。
- AI 能力(对话、RAG、兵棋动作)需要配置 LLM provider + key —— 在
backend/.env设置,或登录后在应用内"配置中心"粘贴。- 不装 TileServer GL,地图会自动回退到在线 OSM 瓦片。
- 下面各小节是每一步的详细说明与 Docker 方式。
| 要求 | 推荐 / 支持 |
|---|---|
| Node.js | >=18.20.7 <=23.9.0 |
| npm | 9.6.3 或 >=10.5.0 <=10.9.2 |
| Python | >=3.11 |
| Docker | Compose 完整栈所需 |
| 数据库 | 默认 SQLite(本地/最小,无需服务);PostgreSQL 16 可选,用于 Compose/规模化拓扑 |
| Redis | 可选 —— 默认运行流为内存;启用 Redis 以支持多实例扩展 |
| MinIO | 可选 —— 仅在使用 Compose 拓扑时 |
| Qdrant | 可选 —— 仅用于 Compose 拓扑或 Qdrant 向量后端 |
| TileServer GL | 可选 —— 用于本地地图瓦片;在线 OSM 模式无需它(见 docs/RESOURCES.md §4) |
前端用 npm(仓库已签入 package-lock.json):
cd client
npm install跨平台提示:
tools/tileserver-gl下的原生模块与平台绑定,需在每个 OS(Win/macOS/Linux)各自npm install,不能跨平台拷贝node_modules。安装/用法见tools/tileserver-gl/README.md,数据与地图流程见docs/RESOURCES.md§4。(设MAP_RESOURCE_MODE=online可完全跳过它。)
后端 —— 在仓库根目录创建并激活虚拟环境(start_dev.py 要求 <根>/.venv),再安装后端包(加 [local-embedding] extra 启用本地 KB 向量):
python -m venv .venv # 在仓库根,不是在 backend/ 里
# 激活 —— Windows:.venv\Scripts\activate | macOS/Linux:source .venv/bin/activate
pip install -e "scenarioengine/backend[local-embedding]"仓库根另有锁定版
requirements.txt(pip install -r requirements.txt,完全可复现);上面的可编辑安装是开发默认的简便方式。
仓库提供 .env.example 模板(真实 .env 已被 .gitignore 忽略,不入仓)。
复制后填入真实值(LLM API Key、JWT_SECRET_KEY、管理员口令等):
cp backend/.env.example backend/.env
cp client/.env.example client/.env下面汇总后端的关键变量供参考:
APP_ENV=dev
DATABASE_TYPE=sqlite
APP_NAME=Scenario Engine API
APP_PORT=8000
# PostgreSQL config (disabled: switched to sqlite)
# POSTGRES_HOST=localhost
# POSTGRES_PORT=5432
# POSTGRES_DB=scenarioengine
# POSTGRES_USER=postgres
# POSTGRES_PASSWORD=123456
# SQLITE_DATABASE_FILENAME=scenarioengine.db
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_DB=0
MINIO_ENDPOINT=localhost:9000
MINIO_ACCESS_KEY=minioadmin
MINIO_SECRET_KEY=minioadmin
MINIO_BUCKET=uploads
QDRANT_HOST=localhost
QDRANT_PORT=6333
QDRANT_COLLECTION=knowledge_base
JWT_SECRET_KEY=replace_me
JWT_EXPIRE_MINUTES=1440
LOCAL_ADMIN_USERNAME=admin
LOCAL_ADMIN_PASSWORD=admin123
LOCAL_ADMIN_DISPLAY_NAME=Administrator
LLM_PROVIDER=openai
# LLM_BASE_URL=https://api.openai.com/v1
# LLM_API_KEY=your_api_key
# DEFAULT_MODEL=gpt-4o
# Optional provider-specific overrides (recommended when switching providers).
OPENAI_BASE_URL=https://api.openai.com/v1
OPENAI_API_KEY=your_api_key
OPENAI_MODEL=gpt-4o
QWEN_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
QWEN_API_KEY=your_api_key
QWEN_MODEL=qwen-flash
DEEPSEEK_BASE_URL=https://api.deepseek.com/v1
DEEPSEEK_API_KEY=your_api_key
DEEPSEEK_MODEL=deepseek-chat
# Use your OpenAI-compatible Gemini gateway URL if applicable.
GEMINI_BASE_URL=https://generativelanguage.googleapis.com/v1beta
GEMINI_API_KEY=your_api_key
GEMINI_MODEL=gemini-2.5-flash
OLLAMA_BASE_URL=http://127.0.0.1:11434/v1
OLLAMA_API_KEY=dummy
OLLAMA_MODEL=llama3.2
MAP_BASE_TILEJSON_URL=http://localhost:8080/data/openmaptiles-base.json
MAP_SATELLITE_TILEJSON_URL=http://localhost:8080/data/openmaptiles-satellite.json
MAP_GEOSERVER_WMS_URL=http://localhost:8081/geoserver/wms
CORS_ALLOW_ORIGINS=["http://localhost:3000","http://127.0.0.1:3000","http://localhost:3002"]
AUTO_START_EXTERNAL_SERVICES=True
EMBEDDING_LOCAL_MODEL=D:\projectx\Scenario_Engine\scenarioengine\models\bge-small-zh-v1.5
VECTOR_EMBEDDING_DIM=512
# EMBEDDING_REMOTE_ENABLED=true
数据库文件(*.db / *.db-wal / *.db-shm)不入仓——已被忽略,clone 后需在本地用脚本重建。
配置好 .env 后,在 backend/ 目录执行:
cd backend
# 1) 建表 + 播种默认数据(管理员账号、默认模型配置引用、预置想定);会提示确认,输入 y
python scripts/init_db.py reset
# 2) (重建)AI 配置中心表(providers / model configs)
python scripts/init_config_center.py
# 3) 初始化向量库(知识库 embedding 后端)
python scripts/init_vectordb.py init说明:
- API Key 从
.env读取(如OPENAI_API_KEY);播种的模型配置只存该环境变量的引用名,不存密钥本身。也可在启动后于应用内"配置中心"直接粘贴 key。 python scripts/init_db.py status可打印各表行数做健康检查。- 快捷方式:
python start_dev.py start --init-db会非交互地依次跑完这三步并随后启动整个栈;检测到空库时start_dev.py也会给出提示。 - 需要干净数据库时随时重跑这三条即可,DB 无需提交到仓库。
数据库就绪后,再准备数据资源(embedding 模型、装备/机场库、知识库、地图瓦片)——见资源准备指南。
仓库内完整栈最可靠的方式:
docker compose -f deployments/docker-compose.yml up --build本地无 Docker 的开发流程,用跨平台 Python 启动器(Win/macOS/Linux),从仓库根目录运行:
# 首次:初始化 DB 后启动整个栈
python start_dev.py start --init-db
# 之后
python start_dev.py若 tools/tileserver-gl/node_modules 缺失,在本机重装:
cd tools/tileserver-gl
npm install只起前端时,client 包用跨平台 Node 启动器(无需 PowerShell):
cd client
npm run dev仓库规范的可部署栈是 Compose 拓扑:
docker compose -f deployments/docker-compose.yml up --build该栈包含:
- PostgreSQL
- Redis
- MinIO
- Qdrant
- TileServer GL
- 后端 API
| 现象 | 处理 |
|---|---|
Missing virtualenv Python: .../.venv/... |
在仓库根建 venv(python -m venv .venv)并安装后端依赖。 |
| 端口被占(3000 / 8000 / 8080) | python start_dev.py stop 释放端口后再启动。 |
| 库是空的 / 无法登录 | 跑 python start_dev.py start --init-db(播种管理员),用 admin / admin123 登录。 |
| AI 对话/RAG 报认证或 provider 错误 | 在 backend/.env 配好 LLM key(如 OPENAI_API_KEY),或在应用内"配置中心"选模型。 |
| TileServer GL 起不来 / 原生模块报错 | 原生模块与平台绑定——在本机 tools/tileserver-gl 里 npm install,或改用在线模式 MAP_RESOURCE_MODE=online。 |
| 某子服务启动即退出 | start_dev.py 会回放该服务最后若干行日志——看错误上方的 [backend]/[tileserver]/[client] 输出。 |
cd client
npm test常用补充:
cd client
npm run lint
npm run test:governancecd backend
pytest -q本仓库常用的聚焦检查包括:
pytest backend/tests/test_service_ownership_boundaries.py -qpytest backend/tests/test_rag_pipeline.py -qpytest backend/tests/test_sim_session.py -vv -s
- 单元测试覆盖领域辅助、运行期守卫与纯转换。
- 集成测试覆盖 API 契约、流行为、认证与持久化。
- 治理测试保护运行边界与 UI 面归属。
仓库围绕短生命周期的功能分支与 PR 组织。
理由:
- 强调合并前的治理检查与回归守卫。
- 变更尽量收敛到单一行为关注点。
仓库未硬性强制提交格式。
建议约定:
- 功能与修复采用 Conventional Commits。
- 尽量将变更限定在一个行为关注点内。
前端:
- 在
client/tsconfig.app.json启用 TypeScript 严格模式 - ESLint 与 Prettier 是主要风格门
- React 代码按运行面与功能区域组织
后端:
- Python 3.11+
- Black / Ruff 行宽 88
- SQLAlchemy 模型与 Pydantic schema 分离
- 启动检查对不安全的生产配置有意 fail-fast
仓库在 scripts/ 下提供本地可运行的守卫与检查脚本,作为质量门:
scripts/repo_guard.py与scripts/check_repo_guards.{sh,ps1}:架构边界与历史营销名/旧包名回写守卫scripts/runstream_*:运行流就绪 / 采纳 / 发布检查scripts/smoke_http.{sh,ps1}:HTTP 冒烟- 前端
npm run test:governance:前端治理检查
当前仓库未提交 GitHub Actions 工作流;上述守卫脚本可在本地或自建 CI 中接入,把边界检查当作一等质量门,而非可选项。
deployments/docker-compose.yml 是规范的容器拓扑。
它串联:
- 后端
- PostgreSQL
- Redis
- MinIO
- Qdrant
- TileServer GL
仓库未签入 Kubernetes 清单。
推断:
- 后端已将应用代码与部署逻辑分离,容器化进 K8s 应较直接。
- 仍需在外部定义配置、密钥、ingress、持久卷与健康探针。
仓库未内置 Vercel、Railway 或 AWS 的一等部署清单。
推断:
- 前端可适配 Vercel 等托管。
- 后端仍需自备 Postgres、Redis、对象存储与向量库。
- 当前架构更契合容器编排,而非纯前端托管平台。
server:完整的后端权威模式local:后端可静态托管已构建的 SPA- 无 Docker 模式:通过仓库辅助脚本启动本地各服务
- SQLite 使用 WAL 模式、宽松的 busy timeout 与内存友好的 cache 设置,适配本地并发。
- 快照持久化使用后台执行器,并在关停时显式刷盘。
- 运行流发布在部署需要多实例 broker 时可切换 Redis。
- AI side-agent 提议按运行限速,避免成本失控。
- 稳定的提示词前缀与 persona 指纹有助于 provider 缓存。
- RAG 使用分块预算、top-k 限制、去重与重排,保持提示词有界。
- SSE 与 WebSocket 实时流降低 UI 侧的轮询开销。
- Qdrant 或
sqlite-vec让向量检索可超越纯关键词检索而扩展。
- 会话认证为基于 Cookie 的 JWT。
- 同时支持 Bearer token 请求。
auth/me与状态变更路由受当前用户依赖链保护。
- 角色检查通过
require_roles(...)强制。 - 仅管理员的面包括模型治理、用户/角色管理与许多数据变更路由。
- 密钥期望来自环境变量。
- 启动检查在非 dev 环境拒绝弱 JWT 与弱 LLM 默认值。
- MinIO 默认值在本地/dev 之外也被拦截。
- 后端存储引用与解析后的配置,而非广泛暴露原始密钥。
- LLM provider 配置集中在 AI 编排器。
PerRunRateLimiter限制 side-agent 的 LLM 调用。SysUserActivityLock防止互相冲突的交互模式。- 自主 AI 在部署级与运行级均为可选开启(opt-in)。
- Pydantic 校验请求载荷。
- FastAPI 异常处理器将校验错误归一化为结构化信封。
- 场景 patch 与 AI 动作走白名单工作流逻辑,而非客户端直接变更。
成熟、受治理约束的产品形态,已具备:
- 稳定的后端事实源(authority)模型
- 较完整的前端操作员控制台
- 成型的 AI 编排层
- 跨平台本地启动(Win/macOS/Linux,经
start_dev.py) - 已签入的
.env.example模板与脚本化的 DB 初始化流程
- 将长期运维文档与历史工程笔记进一步分离
- 运行流多实例 / 队列的可选加固
- 知识对账与 AI 动作审查的更多自动化
- 在
docs/RESOURCES.md补全卫星瓦片的来源与许可
- 文档分散在多个子树(
docs/、deployments/) - 部分子系统分阶段重构,旧笔记仍带历史措辞
- 把重复的运维指引收敛为单一主入口
- 多 worker 扩展成硬需求时,加固运行流 broker 的持久性
- 为 AI 编排与运行流路径补充架构图 / 时序图
- 持续收紧 AI 路径的提示词预算与可观测性
- 提升顶层仓库对新贡献者与 AI agent 的可发现性
维护任务的建议导览顺序:
backend/app/main.pybackend/app/bootstrap.pybackend/app/services/simulation_service.pybackend/app/domain/sim/session.pybackend/app/modules/wargame/action_flow/wargame_action_flow.pyclient/src/gui/app/BackendApp.tsxclient/src/simulation/useBackendRunStream.ts
ScenarioEngine 基于 Panopticon-AI 团队的优秀开源底座 Panopticon 构建——一个基于 Web 的军事仿真平台。感谢其作者与贡献者提供的原始引擎与设计,本项目在此基础上扩展而来。
ScenarioEngine 以 Apache License 2.0 协议开源。
版权所有 2024-2026 ScenarioEngine Contributors。







