系统架构设计工具

一个通过结构化未来、明确权衡和Excalidraw图生成、压力测试和管理软件架构的MCP服务器和LangGraph主机。

  • by gowriks12
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 gowriks12/speculative-system-designer

使用说明

推测系统设计师

MCP服务器+LangGraph主机,通过结构化期货、显式权衡和Excalidraw图生成、压力测试和管理软件架构。


这是什么?

大多数架构审查过程发生得太晚,也太礼貌了。团队提出一个系统,对其进行简短辩论,然后附带未解决的假设。

推测系统设计师 翻转它。它强制执行通常跳过的三件事:

  1. 不可谈判的限制 宣布 之前 设计开始--称为 根
  2. 悲观的未来 模拟的 反对 提出后的设计
  3. 明确的权衡 接受 有记录的 在最终架构发布之前

该项目分为两个独立的层:

层 它做什么
服务器 (server/mcp_server.py) FastMCP服务器——公开工具、执行治理规则、管理状态
主机/客户端 (host/) LangGraph编排——通过有状态图驱动服务器工具,连接Excalidraw

仓库的规划

SpeculativeSystemDesigner/
├── server/
│   ├── mcp_server.py           ← FastMCP entry point (all tools registered here)
│   ├── architectures.py        ← Architecture model + submit_architecture factory
│   ├── critiques.py            ← Critique model, CRITIQUE_STORE, helpers
│   ├── futures.py              ← Loads futures.json
│   ├── roots.py                ← Loads roots.json + prompt formatter
│   ├── store.py                ← In-memory REVIEW_STORE
│   ├── declare_tradeoff.py     ← Records an accepted tradeoff
│   ├── TOOLS.md                ← Tool-by-tool API reference
│   ├── CONCEPTS.md             ← Deep-dive into Roots, Futures, Tradeoffs
│   └── data/
│       ├── roots.json          ← Non-negotiable architectural constraints
│       └── futures.json        ← Pessimistic stress-test scenarios
│
├── host/
│   ├── __init__.py
│   ├── state.py                ← DesignState TypedDict
│   ├── handlers.py             ← MCP sampling + elicitation callbacks
│   ├── nodes.py                ← LangGraph node implementations
│   ├── graph.py                ← Graph definition and routing logic
│   └── run.py                  ← CLI entry point
│
├── graph_flow.svg              ← Visual graph flow reference
├── requirements.txt
├── pyproject.toml
├── .env.example
└── README.md

关键概念

概念 描述
根 不可协商的架构约束(例如“必须可由≤6名工程师操作”)。违规行为会阻止审批。定义于 server/data/roots.json.
未来 系统可能不得不在一种悲观的情况下运行——扩展10倍、安全滥用、监管变化。定义于 server/data/futures.json.
批评 通过根据架构模拟未来而产生的结构化LLM反馈。包含a summary 最多3个 risks.
权衡 一种明确的、人类接受的妥协,可以解决批评。必须在发布最终架构之前声明。

架构概述

┌─────────────────────────────────────────────────────────────┐
│                   LangGraph Host (host/)                    │
│   run.py ──► graph.py ──► nodes.py                          │
│                  │                                          │
│   handlers.py (sampling + elicitation callbacks)            │
└─────────────┬───────────────────┬──────────────────────────┘
              │ MCP stdio         │ MCP streamable-http
              ▼                   ▼
┌─────────────────────┐  ┌────────────────────────┐
│  SSD MCP Server     │  │  Excalidraw MCP Server  │
│  (mcp_server.py)    │  │  mcp.excalidraw.com/mcp │
│                     │  └────────────────────────┘
│  Tools              │
│  ├─ generate_arch   │
│  ├─ simulate_future │   Resources
│  ├─ propose_trdoff  │   ├─ roots://governance
│  ├─ finalize_arch   │   └─ roots://futures
│  ├─ evaluate_arch   │
│  ├─ list_roots      │   State (in-memory)
│  ├─ list_futures    │   └─ REVIEW_STORE + CRITIQUE_STORE
│  └─ write_arch      │
│                     │
│  data/              │
│  ├─ server/data/    │
│  │  ├─ roots.json   │
│  │  └─ futures.json │
└─────────────────────┘

权限属于服务器。 治理提示——根约束、未来场景、批评结构——都存在于MCP服务器内部。客户无法绕过它们。

创意属于客户。 客户端LLM处理开放式综合:提出架构、生成权衡选项、编写最终文档。


服务器功能

工具

服务器通过MCP公开了八个工具。五个是异步的(它们使用MCP采样将LLM调用委托回客户端),三个是同步实用程序。

generate_architecture_tool (异步)

生成满足中定义的所有根的系统架构 server/data/roots.json。它使用 MCP采样 将提示(包括所有根约束)逐字发送到客户端LLM。结果立即保存到 REVIEW_STORE 和a architecture_id 对于所有后续的工具调用,都会返回。

simulate_future_tool (异步)

根据单个未来场景对保存的架构进行压力测试。发送未来的 review_prompt +通过采样将架构文本发送到客户端LLM,并期望得到JSON响应 summary (字符串)和 risks (列表)。创建并存储 Critique 对象。

propose_tradeoff_tool (异步)

解决批评的两阶段工具:

  1. 采样阶段 --LLM生成三个权衡选项(A、B、C),每个选项都有一个 statement, sacrifice,以及 benefit.
  2. 激发阶段 --选项通过以下方式呈现给人类 MCP激发人挑一个;服务器通过以下方式记录它 declare_tradeoff 并标志着批评已解决。

服务器从不让LLM选择权衡——这个决定总是属于人类的。

evaluate_architecture_tool (async--编排器)

全面评估运行的高级入口点。内部通话 simulate_future_tool 为了每一个未来 server/data/futures.json那么 propose_tradeoff_tool 对于每一个由此产生的批评,那么 finalize_architecture_tool用户在未来每次都会被提示(通过Elicitation)选择一个折衷方案。

finalize_architecture_tool (异步)

生成包含所有公认折衷的最终治理架构。如果没有声明折衷,则拒绝执行——服务器强制要求必须首先解决每个Critique。使用采样将合成委托给客户端LLM。

list_roots_scope (同步)

返回当前从加载的根约束ID的列表 server/data/roots.json.

list_futures_scope (同步)

返回当前加载的未来ID列表 server/data/futures.json。由LangGraph主机在启动时使用,无需硬编码即可动态发现期货。

write_architecture (同步)

将架构文档(初始、模拟未来或最终)写入 architectures/<use_case>/ 在磁盘上。

资源

服务器公开了两个任何客户端都可以直接读取的MCP资源:

URI 内容
roots://governance 满 server/data/roots.json
roots://futures 满 server/data/futures.json

状态管理

所有运行时状态都存在于两个内存字典中(在服务器重新启动时重置):

店铺 位置 内容
REVIEW_STORE store.py 每个架构一个条目:初始文本、权衡列表、评论ID列表、最终文本
CRITIQUE_STORE critiques.py 每个条目一个 Critique 对象,由UUID键控

默认根目录(server/data/roots.json)

根ID 约束
team_constraints 系统必须可由≤6名工程师构建和操作。
cost_discipline 基线基础设施成本必须是可预测的,并且对非技术利益相关者来说是可防御的。
operational_observability 系统必须可诊断,而无需生产中的专用仪器。
reversibility 重大的架构决策必须是可逆的,无需完全重写。

默认期货(server/data/futures.json)

未来ID 假设 立场
scaling 流量和数据量在18个月内增长了10倍 悲观
security_abuse 攻击者有能力;内部配置错误将会发生 对抗性
regulatory_compliance 新的合规要求在系统发货后很快就会到来 字面意思

主机/客户端(LangGraph)

这 host/ 包是一个LangGraph编排层,它通过有状态的有向图驱动SSD服务器工具。它同时维护两个MCP会话——一个到SSD服务器(stdio),一个到Excalidraw MCP服务器(HTTP)。

图形流

generate
  └─► draw_initial (Excalidraw)
          │
          ├─[--no-eval / run_evaluation=False]──────────────► END
          │
          └─[run_evaluation=True]──► simulate_future ◄────────┐
                                          │                    │
                                          ▼                    │ (more futures)
                                    propose_tradeoff           │
                                          │                    │
                                          ├─[more futures]─────┘
                                          │
                                          └─[all done]──► finalize
                                                              │
                                                              ▼
                                                        draw_final (Excalidraw)
                                                              │
                                                              ▼
                                                             END

看 graph_flow.svg 对于视觉版本。

节点(host/nodes.py)

节点 MCP工具调用 它的作用
generate generate_architecture_tool 生成初始架构;种子 architecture_id, architecture_text,重置循环索引
draw_initial 退场 create_drawing 转换架构文本→ 排除JSON元素(通过LLM)→ 创建图表,存储 initial_diagram_url
simulate_future simulate_future_tool 模拟列表中的下一个未来;在状态后附加批评,递增 current_future_index
propose_tradeoff propose_tradeoff_tool 为最新的《评论》提出选项;启发式回调解决了选择问题;附加到 tradeoffs
finalize finalize_architecture_tool 从初始设计+所有声明的权衡中综合出最终架构
draw_final 退场 create_drawing 与 draw_initial 但对于最终的架构;商店 final_diagram_url

路由逻辑(host/graph.py)

两条条件边控制流:

  • 之后 draw_initial:分支上 state["run_evaluation"] --前往 simulate_future 如果 True,否则立即结束。受控于 --no-eval CLI标志。
  • 之后 propose_tradeoff:循环回到 simulate_future 当 current_future_index < len(future_ids),然后继续 finalize 当所有的未来都耗尽时。

未来的ID通过以下方式从服务器动态获取 list_futures_scope 在图构建时,主机永远不会硬编码未来的名称。

国家(host/state.py)

class DesignState(TypedDict):
    problem_statement: str
    run_evaluation: bool            # True = simulate futures, False = generate + draw only
    architecture_id: Optional[str]
    architecture_text: Optional[str]
    critiques: List[dict]           # [{id, future, summary, risks, ...}]
    tradeoffs: List[dict]           # [{critique_id, selected, ...}]
    final_architecture: Optional[str]
    current_future_index: int       # loop counter through futures
    future_ids: List[str]
    initial_diagram_url: Optional[str]
    final_diagram_url: Optional[str]

采样和采集处理人员(host/handlers.py)

主机向MCP注册两个回调 ClientSession:

sampling_handler --每当SSD服务器调用时调用 ctx.session.create_message。将消息转发到配置的OpenAI模型并返回结果。这就是服务器在不需要自己的API密钥的情况下将所有LLM工作委托给客户端的方式。

elicitation_handler --每当SSD服务器调用时调用 ctx.elicit (目前在 propose_tradeoff_tool).行为取决于 ELICITATION_MODE:

模式 行为
llm (默认) LLM读取A/B/C选项并自动选择最实用的选项
human LangGraph interrupt() 暂停图形;人类用以下方式恢复它 Command(resume="B")

Excalidraw集成

主机连接到Excalidraw MCP服务器 https://mcp.excalidraw.com/mcp (可通过 EXCALIDRAW_MCP_URL).对于每个绘图节点,它:

  1. 调用LLM(gpt-4o-mini)将架构散文转换为有效的Excalidraw元素JSON数组(服务为矩形,数据流为箭头)。
  2. 调用Excalidraw create_drawing 具有这些元素的工具。
  3. 将返回的可共享URL存储在 DesignState.

每次完整运行都会生成两个图表——初始和最终——这两个URL都会在会话结束时打印出来。


设置

先决条件

  • Python 3.11+
  • 克劳德桌面版 或任何MCP兼容客户端
  • OpenAI API密钥(用于LangGraph主机)

安装

git clone https://github.com/yourname/speculative-system-designer
cd speculative-system-designer

python -m venv .venv
# Windows
.venv\Scripts\activate
# Unix / macOS
source .venv/bin/activate

pip install -r requirements.txt

配置

cp .env.example .env
# Edit .env — set OPENAI_API_KEY at minimum

关键环境变量:

变量 默认值 描述
OPENAI_API_KEY -- LangGraph主机需要
SERVER_PYTHON .venv/Scripts/python.exe (赢)/ .venv/bin/python (Unix) 通往venv Python的路径
SERVER_MODULE server.mcp_server MCP服务器的Python模块路径
ELICITATION_MODE llm llm 对于完全代理, human 每次权衡时都要停下来
LLM_MODEL gpt-4o-mini 用于采样和启发的OpenAI模型
EXCALIDRAW_MCP_URL https://mcp.excalidraw.com/mcp 排除MCP服务器URL

跑步

选项A——LangGraph主机(完全代理运行)

# Full run: generate → evaluate all futures → finalize → draw both diagrams
python -m host.run

# Skip evaluation: generate + draw initial diagram only
python -m host.run --no-eval

运行结束输出:

========================================
DESIGN SESSION COMPLETE
========================================
Architecture ID      : <uuid>
Initial diagram      : https://excalidraw.com/#...
Futures simulated    : 3
Tradeoffs declared   : 3
Final diagram        : https://excalidraw.com/#...

FINAL ARCHITECTURE:
...

选项B——克劳德桌面

⚠️ Claude桌面兼容性

此分支上的服务器(main)用途 MCP采样 和 MCP激发 --Claude Desktop目前不支持的两个功能。将此服务器直接连接到Claude Desktop将导致工具调用静默失败或挂起。

要在Claude Desktop中使用推测系统设计器,请切换到 simple-server 分支,它提供了一个与克劳德兼容的服务器,用自包含的工具逻辑替换采样和启发式:

git checkout simple-server

然后按照该分支的README中的设置和Claude Desktop配置说明进行操作。

选项C-HTTP传输

# In server/mcp_server.py, change the last line to:
mcp.run(transport="streamable-http")
python -m server.mcp_server
# Server available at http://127.0.0.1:8000/mcp

人在循环模式

集 ELICITATION_MODE=human 在 .env。图表在每个时间点暂停 propose_tradeoff_tool 通过LangGraph调用 interrupt().

要继续,请执行以下操作:

from langgraph.types import Command

config = {"configurable": {"thread_id": "design-session-1"}}

# First ainvoke pauses at the first tradeoff
result = await graph.ainvoke(initial_state, config=config)

# Resume with the human's choice
result = await graph.ainvoke(Command(resume="B"), config=config)

定制根和未来

这两个文件都是纯JSON格式,不需要更改代码。

添加根(server/data/roots.json)

{
  "your_root_id": {
    "id": "your_root_id",
    "statement": "The constraint in plain language.",
    "rationale": "Why this constraint exists.",
    "violation_examples": [
      "concrete example of something that breaks this rule"
    ]
  }
}

根被注入到下一个 generate_architecture_tool 自动呼叫。

添加未来(server/data/futures.json)

{
  "your_future_id": {
    "id": "your_future_id",
    "description": "What this scenario assumes.",
    "assumption": "The specific pessimistic assumption.",
    "stance": "pessimistic | adversarial | literal",
    "review_prompt": "You are a [role]. Given this architecture... Respond ONLY in JSON: {\"summary\": \"...\", \"risks\": [\"...\"]}"
  }
}

这 review_prompt 必须 指示模型返回JSON summary (字符串)和 risks (字符串数组)。LangGraph主机通过以下方式自动获取新的期货 list_futures_scope 在图形构建时。


交换LLM(主机)

主机默认使用OpenAI。要切换到Anthropic,请编辑 host/handlers.py 和 host/nodes.py:

from anthropic import AsyncAnthropic
_client = AsyncAnthropic()   # reads ANTHROPIC_API_KEY

# In sampling_handler, replace the openai call with:
response = await _client.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=800,
    messages=messages,
)
text = response.content[0].text

使用的MCP功能

功能 位置
工具 全部 @mcp.tool() 功能在 mcp_server.py
资源 roots://governance, roots://futures
采样 (ctx.session.create_message) 架构生成、未来模拟、权衡选项生成、最终确定——服务器将LLM调用委托给客户端
引出 (ctx.elicit) propose_tradeoff_tool --服务器向人类呈现选择并等待选择

设计原则

权限属于服务器。 MCP服务器内的治理提示是实时的。客户不能跳过或更改它们。

创意属于客户。 客户端LLM处理开放式合成。

权衡是一流的产物。 每一个被接受的权衡都是坚持的 REVIEW_STORE 并逐字传递到定稿提示中。没有什么是被默默抛弃的。

服务器可以拒绝。 finalize_architecture_tool 在每一个批评都得到解决之前,拒绝产生最终的架构。