mcpField
D
Design Pattern MCP

Design Pattern MCP

本地服务
github.com/olk开发工具03 天前更新

关于 Design Pattern MCP

Design Pattern MCP 是面向 AI 编码 Agent 的设计模式选择与设计生成服务。它基于自然语言需求检索模式,并可生成实现方案、评估质量属性;内置模式含多种语言变体。

主要功能

  1. 01按系统描述分析设计需求
  2. 02检索并选择设计模式
  3. 03生成参与者与实现步骤
  4. 04按八项质量属性评估设计
  5. 05异步提交并查询设计任务
  6. 06浏览和读取模式目录

适用场景

  1. 01为新系统选择合适的设计模式
  2. 02让编码 Agent 获取模式决策和理由
  3. 03评估现有设计的质量属性

MCP 相关

作为 MCP 服务向客户端提供模式分析、设计生成、设计评估、目录查询及异步任务工具,并提供工作流提示词和变体资源。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"olk-design-pattern": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"DESIGN_PATTERN_GENERATOR_API_KEY",
"-e",
"DESIGN_PATTERN_GENERATOR_PROVIDER",
"-e",
"DESIGN_PATTERN_GENERATOR_MODEL",
"-e",
"DESIGN_PATTERN_GENERATOR_BASE_URL",
"-e",
"DESIGN_PATTERN_PATTERN_DIRECTORY",
"-e",
"DESIGN_PATTERN_EMBEDDER_BASE_URL",
"-e",
"DESIGN_PATTERN_EMBEDDER_API_KEY",
"-e",
"DESIGN_PATTERN_RERANKER_BASE_URL",
"docker.io/olkowa/design-pattern-mcp:1.0.1"
],
"env": {
"DESIGN_PATTERN_GENERATOR_API_KEY": "<DESIGN_PATTERN_GENERATOR_API_KEY>",
"DESIGN_PATTERN_GENERATOR_PROVIDER": "<DESIGN_PATTERN_GENERATOR_PROVIDER>",
"DESIGN_PATTERN_GENERATOR_MODEL": "<DESIGN_PATTERN_GENERATOR_MODEL>",
"DESIGN_PATTERN_GENERATOR_BASE_URL": "<DESIGN_PATTERN_GENERATOR_BASE_URL>",
"DESIGN_PATTERN_PATTERN_DIRECTORY": "<DESIGN_PATTERN_PATTERN_DIRECTORY>",
"DESIGN_PATTERN_EMBEDDER_BASE_URL": "<DESIGN_PATTERN_EMBEDDER_BASE_URL>",
"DESIGN_PATTERN_EMBEDDER_API_KEY": "<DESIGN_PATTERN_EMBEDDER_API_KEY>",
"DESIGN_PATTERN_RERANKER_BASE_URL": "<DESIGN_PATTERN_RERANKER_BASE_URL>"
}
}
}
}
启动命令docker run -i --rm -e DESIGN_PATTERN_GENERATOR_API_KEY -e DESIGN_PATTERN_GENERATOR_PROVIDER -e DESIGN_PATTERN_GENERATOR_MODEL -e DESIGN_PATTERN_GENERATOR_BASE_URL -e DESIGN_PATTERN_PATTERN_DIRECTORY -e DESIGN_PATTERN_EMBEDDER_BASE_URL -e DESIGN_PATTERN_EMBEDDER_API_KEY -e DESIGN_PATTERN_RERANKER_BASE_URL docker.io/olkowa/design-pattern-mcp:1.0.1
需要配置的环境变量
DESIGN_PATTERN_GENERATOR_API_KEY密钥API key for the generator LLM (LiteLLM provider).
DESIGN_PATTERN_GENERATOR_PROVIDERLiteLLM provider prefix, e.g. openai, anthropic, openrouter.
DESIGN_PATTERN_GENERATOR_MODELModel name, combined as <provider>/<model> via LiteLLM.
DESIGN_PATTERN_GENERATOR_BASE_URLOpenAI-compatible base URL (LiteLLM api_base).
DESIGN_PATTERN_PATTERN_DIRECTORYDirectory with the catalog records (*.json main records plus per-language files). The image bakes the 438-record catalogue at /app/pattern.
DESIGN_PATTERN_EMBEDDER_BASE_URLRequired: the dense retrieval leg embeds the 438-record catalogue during startup warmup and the server refuses to start when the endpoint is unreachable. TEI embeddings endpoint: on the Docker host use http://host.docker.internal:8080 (add --add-host=host.docker.internal:host-gateway on Linux); on a shared Docker network use http://design-pattern-tei-embed:8080.
DESIGN_PATTERN_EMBEDDER_API_KEY密钥API key for the embedder. Keyless TEI accepts any non-empty value; use 'not-needed' there.
DESIGN_PATTERN_RERANKER_BASE_URLRequired: retrieval runs a mandatory TEI cross-encoder rerank whenever the fused pool has more than one candidate. On the Docker host use http://host.docker.internal:8080; on a shared Docker network use http://design-pattern-tei-rerank:8080.

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
ocidocker.io/olkowa/design-pattern-mcp:1.0.1

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

design-pattern-mcp

CI Python 3.12+ License: MIT M8ven Score

一个 MCP(Model Context Protocol)服务,为 AI 编码 Agent 提供设计模式选择方面的专业能力。给定对系统的自由文本描述,它会分析问题、检索匹配的设计模式(来自 486 个内置模式,每种模式均以 13 种具体语言和一种通用绑定实现),生成具体设计,其中包含主要模式、辅助模式、参与者、交互、实现步骤和语言绑定变体,并依据八个设计级质量维度(可测试性、可扩展性、可维护性、简洁性、性能、可靠性、安全性、可伸缩性)进行评估。其流水线(分析 → 权重 ∥ 检索 → 生成 → 评估 → 有界优化)及线协议契约详见 docs/implementation-guide.md。


目录


⚡ 快速开始

# 1. Clone
git clone https://git.odvlh.xyz/olli/design-pattern-mcp.git && cd design-pattern-mcp

# 2. Add your API key
export MINIMAXAI_API_KEY=your_key_here

# 3. Build + start (three images: MCP server + TEI embed + TEI rerank)
make docker-build-all
make docker-up

# 4. Demo (analyze-only: fast. For the full design: make client-design)
make client-analyze
make client-async     # full design via the background job trio

服务通过 streamable-http 在 http://localhost:8822/mcp 上启动(开发用 compose 将主机端口 8822 映射到容器端口 8050)。make client-analyze / make client-design 的目标地址为 http://localhost:8822/mcp;可通过 CLIENT_URL 覆盖。


通过 AI Agent 安装

如需让 AI 编码 Agent 使用预构建镜像安装 Docker 栈(无需本地构建),请将其指向 INSTALL.md — 这是供 Agent 使用的非交互式安装手册(包含可复制粘贴的命令、预期输出和验证探测)。

Clone this repo, then follow INSTALL.md Path A (compose stack, port 8822).
My generator API key is: sk-...

在 INSTALL.md 中选择一种方案:

  • 方案 A — Compose 栈(:8822):用于评估 / 开发,无需 sudo。使用自有 TEI sidecar 副本。
  • 方案 B — systemd 栈(:8812):持久运行的主机服务,开机时启动,需要 sudo。使用共享的 pattern-tei-infra TEI 栈。

Agent 需要克隆的仓库、已加入用户组的 Docker ≥ v2.20、约 8 GB 可用空间、一个 MINIMAXAI_API_KEY(或按 INSTALL.md#switching-the-generator-llm 使用其他提供方),以及 linux/amd64 环境(在 arm64 上会通过 make docker-build-all 在本地构建)。开发栈和 systemd 栈可在默认主机端口上同时运行(8822 与 8812)。安装完成后,请继续阅读下方的连接你的 Agent。


🔌 连接你的 Agent

Claude Code
# Install (one-time)
uv pip install -e .

# Run as stdio subprocess — pass the API key via env
claude mcp add design-patterns \
  -e GENERATOR_PROVIDER=minimax \
  -e GENERATOR_MODEL=minimax/MiniMax-M2.7 \
  -e GENERATOR_BASE_URL=https://api.minimax.io/v1 \
  -e GENERATOR_API_KEY=your_key \
  -- design-pattern-mcp --transport stdio

Stdio 模式需要能够访问 TEI 端点(默认地址为 http://design-pattern-tei-embed:8080,重排器 URL 来自 config/config.json)——可以运行 compose 堆栈的 sidecar,也可以将 EMBEDDER_BASE_URL / RERANKER_BASE_URL 设置为你自己的地址。若要进行无需网络的冒烟测试,请使用 --offline 启动(采用确定性的纯词法检索,而非 TEI)。

OpenCode

OpenCode 使用 HTTP 传输。先启动服务端,然后配置 opencode:

# Terminal 1: start the server
make docker-up
# or locally:
uv run design-pattern-mcp --transport streamable-http --port 8050

# Terminal 2: add to ~/.config/opencode/opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "design-patterns": {
      "type": "remote",
      "url": "http://localhost:8822/mcp"
    }
  }
}

**注意:**生成器 API 密钥由服务端从其配置文件(config/config.json,{env:...} 占位符)读取,而不是从 opencode 的环境中读取。

Codex CLI
# Install (one-time)
uv pip install -e .

添加到 ~/.codex/config.toml:

[mcp_servers.design-patterns]
command = "design-pattern-mcp"
args = ["--transport", "stdio"]

[mcp_servers.design-patterns.env]
GENERATOR_PROVIDER = "minimax"
GENERATOR_MODEL = "minimax/MiniMax-M2.7"
GENERATOR_BASE_URL = "https://api.minimax.io/v1"
GENERATOR_API_KEY = "your_key"

或通过 CLI:

codex mcp add design-patterns \
  -e GENERATOR_API_KEY=your_key \
  -- design-pattern-mcp --transport stdio

🧑‍🏫 面向 AI Agent 的 SKILL

skills/design-pattern-mcp/ 中的 SKILL 是为 Oh My Pi (OMP) 编写的。在 OMP 中,此服务的工具可通过 xd://mcp__design_pattern_local_* 设备访问,且每个 MCP 请求都有截止时间(OMP_MCP_TIMEOUT_MS → 每服务的 timeout → 30 s)。它会教 Agent 如何选择符合截止时间的入口点、如何读取结果,以及完整的工作流配方。

skills/design-pattern-mcp/
├── SKILL.md                 # OMP constraints, entry-point decision guide, device quick reference
└── references/
    ├── tools.md             # 9 tool signatures, arg shapes, status codes
    └── workflows.md         # workflow recipes, result interpretation, troubleshooting

为 OMP 安装——将技能目录复制到 OMP 的用户技能根目录:

cp -r skills/design-pattern-mcp ~/.omp/agent/skills/

随后,技能会告诉 Agent:

  • 哪个入口点符合 OMP 的 30 s 截止时间:默认使用异步任务三件套;select_design_patterns(完整流水线)需要 2–10 min
  • 哪条路径适合该任务:Agent 自行编写代码时使用 analyze_design(提供决策和理由,不生成设计);调用方需要设计时使用完整流水线
  • job_id 是唯一持久句柄——请持久化保存(SQLite 任务存储,JOBS_DB)
  • 如何编写 description(组件名称 + 职责 + 约束),并将 language、paradigm、focus 作为单独的结构化参数传入
  • 如何解读 overview.score(0–100)、findings[] 和各部分的选择结果

references/ 中的工具 schema 与客户端无关;只有截止时间和设备相关指南是 OMP 专用的。


🧪 使用工具

所有流水线工具都将自由文本 description 作为主要参数。下面的示例展示了确切的工具调用形式,因此你可以在任何 MCP 客户端或 API 使用方中使用。

设计你的第一个选择

在 Claude Code(或任何 MCP 客户端)中,粘贴以下自然语言指令:

We're building the ingestion path of an IoT platform: a Kafka consumer
service parses 10k events/sec, an enricher adds geolocation from Redis,
and a writer persists to InfluxDB and S3. Components: consumer, parser,
enricher, sink. Constraints: at-least-once delivery, backpressure, Python.

你的 Agent 会在内部调用 select_design_patterns。服务端会返回 DesignResult:overview(主要模式、辅助模式、原则、分数、推理过程)、applications[](参与者、交互、实施步骤、代码草图、包含绑定变体的语言绑定)、interactions[]、quality_attributes、test_strategy 和 risks[]。

**自行编写代码的编码 Agent 应改为调用 analyze_design。**它会运行相同的 ANALYZE 阶段(§1–§8:需求修复 → 决策部分 → 按部分检索 → 质量权重 → 选择),并在此处停止:你将获得修复后的需求、决策部分以及每个部分的一个选择结果(主要模式、辅助模式、排序后的备选方案、否决记录、权重),但不会生成应用方案,也不会进行评估。选择结果只指出每个部分要应用 什么,而不是 如何 应用——参与者、实施步骤、代码草图和语言绑定由 generate_design 根据该数据生成(也可以按模式通过 get_design_pattern 读取);应根据应用方案实施,切勿仅凭模式名称实施。select_design_patterns 仍是设计路径——它会继续执行 GENERATE → EVALUATE,而完整运行的大部分耗时都花在这两个阶段。无论选择哪种方式,决策都来自相同的 ANALYZE 阶段——每次调用都会重新进行 LLM 分析,因此两种路径都不具幂等性;如果之后需要生成具体的应用方案,请将 analyze_design 的载荷传递给 generate_design。

也可以直接从你的 Agent 调用工具:

Call select_design_patterns with:
  description: "IoT ingestion path: Kafka consumer (10k events/sec) → JSON parse
               → Redis geo-enrich → InfluxDB + S3 sink. At-least-once, backpressure."
  language: "python"

Call list_design_patterns()                       # all 486 patterns
Call list_design_patterns(category="workflow-messaging")
Call get_design_pattern(name="process-manager")
异步作业模式:submit_design_job + get_design_status

适用于请求超时较短的客户端。submit_design_job 会立即返回 job_id;轮询 get_design_status,直到作业完成:

# Step 1: start the job
Call submit_design_job with:
  description: "IoT ingestion path: Kafka consumer → parse → Redis enrich → InfluxDB + S3"

# Step 2: poll every 10-30 seconds
Call get_design_status with:
  job_id: "<job_id from step 1>"

# → status is "pending" | "running" | "completed" | "failed" | "cancelled"
# When status is "completed", the full DesignResult is in result
# When status is "failed", the error is in error

在 Python 中(通过 MCP 客户端 API——参见 examples/design_pattern_client_async.py):

import asyncio
from fastmcp import Client

SERVER = "http://localhost:8822/mcp"
POLL_EVERY = 15  # seconds

async def main():
    client = Client(SERVER)
    async with client:
        # Step 1: start the job
        result = await client.call_tool(
            "submit_design_job",
            {"description": "IoT ingestion: Kafka → parse → enrich → sink"},
        )
        job_id = result.data["job_id"]
        print(f"Job started: {job_id}")

        # Step 2: poll until terminal state
        while True:
            await asyncio.sleep(POLL_EVERY)
            status = await client.call_tool("get_design_status", {"job_id": job_id})
            data = status.data
            print(f"  status={data['status']}")
            if data["status"] in ("completed", "failed", "cancelled"):
                break

        print(data.get("result", data))  # full DesignResult when completed

asyncio.run(main())

完整的可运行示例请参见 examples/design_pattern_client_async.py。运行方式:

make docker-up          # Terminal 1
make client-async       # Terminal 2

🛠️ 工具一览

工具描述
select_design_patterns面向需要生成设计的调用方的设计路径:完整流水线(分析 → 权重 ∥ 检索 → 生成 → 评估 → 优化,最多尝试 LOOP_MAX_TRIES 次),返回包含参与者、实现步骤、绑定变体、质量属性、测试策略和风险的应用。运行时间较长(2–10 分钟)。采用心跳保护。
analyze_design面向自行编写代码的编码 Agent 的仅分析路径:需求 → 简述、决策部分及各部分的选择(主要、辅助、备选、否决项、权重),不生成设计。编码前,使用相同的负载调用 generate_design,以获取参与者、步骤和语言绑定。运行时间较长(约 1 分钟)。
generate_design根据先前 analyze_design 的负载或明确指定的模式生成应用。运行时间较长(约 1 分钟)。
evaluate_design根据八个质量维度对现有设计 JSON 评分。运行时间较长(约 30 秒)。
submit_design_job启动后台选择作业并立即返回 job_id(由 SQLite 提供支持,服务重启后仍可保留)。适用于请求超时较短的客户端。
get_design_status轮询作业状态;作业完成后返回完整的 DesignResult。
cancel_design取消正在运行的作业(尽力而为;在下一个流水线阶段边界生效)。
list_design_patterns列出模式及其名称/类别/描述;可按 category 和/或 language 筛选。
get_design_pattern获取单个名称对应的完整模式 JSON(可由加载器解析,并支持别名)。

描述、语言、范式、重点都是结构化参数——应将它们作为单独的工具参数传入,而不是嵌入描述文本。变体选择基于信号:不存在覆盖整个目录的 variant_id 枚举(变体 ID 按(模式,语言)分别设置,并会随目录编辑而变化;有效 ID 可通过 design-patterns://variants 资源和以往运行的 bound_variant 发现)。


💬 提示词

此服务还提供四个由用户调用的工作流提示词(MCP 客户端中的斜杠命令)。与工具不同,大模型不会自主调用提示词——用户选择一个提示词并填写其参数。每个提示词都封装了一套经过测试的工具编排方案,且都不会硬编码模式名称(类别指导会引用实时目录自身的结构)。

提示词参数功能
/select_design_patterns_workflowdescription*、language、architecture_style、paradigm、focus引导式端到端选择工作流
/explore_pattern_catalogcategory通过 design-patterns://variants 资源和决策探查,发现实时目录内容
/evaluate_my_designdescription*将目录中的选择结果与现有设计进行比较
/compare_pattern_candidatesdecision*、candidates*针对一个决策并列比较两个或三个指定模式;每个候选模式运行一次选择

* = 必填参数

仅支持工具的客户端

仅支持工具协议(不支持原生 prompts/list 或 prompts/get)的客户端,可通过生成的 list_prompts 和 get_prompt 工具访问全部四个工作流提示词。这些工具会经过服务的中间件链路,其处理方式与原生提示词调用完全相同。


📖 模式目录

通过 MCP 工具(推荐 — 适用于所有客户端)
list_design_patterns()                                        # all 486 patterns
list_design_patterns(category="concurrency-resilience")       # filter by category
get_design_pattern(name="acceptor-connector")                 # full pattern JSON

有效的 category 值(九个决策组,即目录第 1–9 节):domain-modeling、construction-composition、behavior-selection、interaction-boundary、workflow-messaging、persistence-state、concurrency-resilience、security-verification、specialized-components。

通过 MCP 资源
mcp_read_resource(uri="design-patterns://variants")

按语言、再按模式汇总每种模式的语言实现,提供 language/paradigm/focus 提示和变体选择所需的实现词汇。

每条模式记录包含的内容

加载器(src/patterns/loader.py)会合并 14 个文件中的记录:一个通用条目,以及每种具体语言各一个(13 种语言:C、C++、C#、Go、Java、JavaScript、Kotlin、Python、Ruby、Rust、Scala、Swift、TypeScript)。每个语言绑定都包含 support(native/idiomatic/discouraged)、idiom_name、implementation_notes、可选的 code_sketch、pitfalls,以及在支持级别为 discouraged 时必需的 alternative。语言绑定可以声明 variants[](按语言划分的实现,目录中共有 4,953 个)及 default_variant。每条记录还会声明 related_patterns(仅限加载器可解析的规范名称)和 related_patterns_notes(对每个关联的区别说明)。

别名解析已内置:加载器会将 993 个原始别名条目 → 经过大小写折叠后得到 978 个不同别名 → 建立 966 个索引别名映射,并丢弃有歧义的别名(别名本身是另一条记录的名称,或被两条记录同时声明;ambiguous_aliases 健康状态字段会列出这些别名),因此 get_design_pattern(name="circuit-breaker") 及其别名拼写都会解析到同一条记录。当目录中的枚举与 docs/pattern-schema.json 不一致时,启动会立即失败(assert_enums_in_sync)。


与 architecture-pattern-mcp 协同使用

此服务回答的是 如何编写每个单元(设计模式);其姊妹项目 architecture-pattern-mcp 回答的是 要构建哪种系统形态(架构)。架构模式用于构建整个系统的结构——包括其组件、组件之间的关系,以及 API/数据/事件契约(例如 event-driven、pipe-and-filter、microservices,选自姊妹项目的 40 种模式目录)。设计模式则用于解决单个组件内部反复出现的实现问题——包括参与者、交互方式和绑定语言的代码(例如 observer、process-manager、circuit-breaker,选自上方的 486 种模式目录,每种模式均提供 13 种语言绑定)。

建议顺序——先宏观,后微观:

1. Call the sibling's design_architecture with:
     requirements: "ETL pipeline for IoT: Kafka → JSON → Redis geo-enrich → InfluxDB + S3"
     domain: "data-processing"
   # → components (Kafka source, parser filter, enricher, sinks),
   #   relationships, API contracts, data models, event contracts
   # Keep design_architecture for callers that want the design: the sibling's LLM
   # generates the architecture artifact (5–10 min) rather than only advising.

2. For each component with non-trivial internal logic, ask for the pattern decisions:
   - coding agent writes the code itself → analyze_design with:
       description: "<component name + responsibilities + constraints from step 1>"
       language: "python"
     # → decision parts + per-part selection with rationale; no generated applications
   - caller wants the generated pattern design → select_design_patterns with:
       description: "<component name + responsibilities + constraints from step 1>"
       language: "python"
     # → primary + supporting patterns, participants, implementation_steps,
     #   code_sketch with the bound language variant

两个模式调用都会运行相同的 ANALYZE 阶段(§1–§8);analyze_design 会在此处停止,不进入生成和评估阶段。每次调用都会单独运行 LLM 分析(这两个工具都不是幂等的),因此针对相同描述的两次调用可能会选出不同模式。

IoT 示例中的具体衔接方式:姊妹项目会生成 pipe-and-filter 架构(Kafka 源 → JSON 解析器过滤器 → 地理位置增强器 → InfluxDB/S3 接收端,契约中包含至少一次投递和背压)。接下来,地理位置增强器的缓存未命中路径就交由此服务处理:当你的 Agent 编写增强器时,analyze_design 会返回 circuit-breaker + retry 决策及其理由;而当调用方需要生成的设计时,select_design_patterns 还会进一步生成具体应用内容(参与者、implementation_steps、Python code_sketch)。这些内部细节会被架构层面的组件契约引用,但不会在架构层实现。 对于 analyze_design 路径,在编写增强器代码前,先对返回的载荷运行 generate_design(或运行 get_design_pattern("circuit-breaker"),查看 Python 绑定和注意事项)。

同时运行两个服务(开发主机端口为 :8060(架构)、:8822(设计模式);systemd 端口为 :8050/:8812)。两者彼此独立——探索时先运行哪个都可以——但先处理架构有助于稳定组件边界,再由此服务补充内部实现。

安装替代方案

Docker(手动)
# Build the three images (dense vector cache generated and baked in)
make docker-build-all

# Run with your API key
MINIMAXAI_API_KEY=your_key make docker-up

首先,docker-build-all 会通过 TEI 嵌入侧车生成 FAISS 稠密缓存(data/dense-cache/),并将其打包进服务镜像;make docker-build-nocache 则会跳过此步骤(首次启动时会嵌入语料,约需 19 分钟)。

两个 compose 堆栈都使用命名 Docker 卷(design-pattern-mcp-dev-dense-cache/design-pattern-mcp-systemd-dense-cache,挂载于 /app/data/dense-cache)保存该缓存目录。新卷会从镜像内置的快照初始化,之后所有回写都会保存到卷中——因此,重启或重新创建容器时会重新加载向量,而不是重新嵌入整个模式目录(只需嵌入一次探测文本,而非约 486 份文档)。docker compose down 会保留该卷。

这会带来两项运维后果:镜像重建后,已有卷会遮蔽较新的内置快照,此时指纹检查会强制重新嵌入一次——因此,在目录或模型发生变化后重建镜像时,请先删除该卷(docker volume rm design-pattern-mcp-dev-dense-cache),再让 up -d 重新初始化它。此外,DENSE_CACHE_MODE=off 会完全禁用缓存——compose 堆栈会将主机上的值传入容器,而主机上运行的服务会直接读取该值。详情请参阅:稠密嵌入缓存。

本地开发(uv)

前置条件: Python 3.12+、uv

# Install
make install

# Configure — the shipped wire config with {env:...} placeholders
export GENERATOR_PROVIDER=minimax
export GENERATOR_MODEL=minimax/MiniMax-M2.7
export GENERATOR_BASE_URL=https://api.minimax.io/v1
export GENERATOR_API_KEY=your_key
# Dense cache (host runs): the image default /app/data/dense-cache does not exist
# on a workstation, so point it at the gitignored repo snapshot. `make embed-cache`
# fills it; otherwise the first start embeds once and writes it (later starts warm).
export DENSE_CACHE_PATH="$PWD/data/dense-cache"

# Run the server
uv run design-pattern-mcp --transport stdio               # for Claude Code / Codex
uv run design-pattern-mcp --transport streamable-http --port 8050   # HTTP
uv run design-pattern-mcp --health                        # offline readiness check (config + catalog + index)

也可使用已安装的控制台脚本(运行 make install 后):design-pattern-mcp。

要获得完整的检索质量,需要 TEI sidecar:启动时会融合一个稠密检索通路(通过 embed sidecar 使用 Qwen3-Embedding-0.6B)和一个 BM25 检索通路(service_healthy 顺序保证 embedder 在服务接受请求前启动;如果索引预热失败,服务将拒绝启动)。Reranker sidecar(gte-reranker-modernbert-base)会对候选模式重新排序。如果 sidecar 无法访问,请使用 --offline 启动(仅进行确定性的词法检索,不访问网络)。

TEI 启动: 两个 sidecar 镜像(docker/Dockerfile.tei-embed、docker/Dockerfile.tei-rerank)都包含自行构建的 TEI router(v1.9.4 + 尚未合并的 PR #884),默认设置 WARMUP_TOKENS=0——这会跳过合成预热过程(实测 embed 约需 131 s,rerank 约需 78 s),让容器仅在权重加载后就绪。可通过 TEI_WARMUP_TOKENS / TEI_RERANK_WARMUP_TOKENS 分别覆盖各 sidecar 的设置(正整数 N 会改为使用 N 个 token 预热;大于 MAX_BATCH_TOKENS 的值会在启动时被拒绝)。

GPU TEI: 随附的 sidecar 是 CPU 镜像(cpu-1.9)。在配备 TEI-CUDA 支持的 NVIDIA GPU(计算能力 ≥ 7.5)及 NVIDIA 容器工具包的主机上,make docker-build-tei-embed-gpu 会基于 CUDA 镜像(ghcr.io/huggingface/text-embeddings-inference:cuda-1.9)构建 embed sidecar;make docker-up-gpu 则会使用 docker/docker-compose.gpu.yml 启动开发栈(分配 1 个 GPU)。此覆盖配置仅适用于 embed sidecar——reranker 仍使用 CPU。在 GPU 上,可将 WARMUP_TOKENS 设为较小的正数,以便在启动时预热内核,而不是跳过预热过程。

已运行的 embedder/reranker: 如果 embedding 和 reranking 端点已在其他服务器上运行,可通过 EMBEDDER_BASE_URL(OpenAI 兼容路由,http://<host>:8080/v1)和 RERANKER_BASE_URL(http://<host>:8080)将 MCP 服务指向这些端点,并跳过 sidecar。embedder 会通过 LiteLLM 转发 EMBEDDER_MODEL(默认值为 openai//data/embedding-model)和 EMBEDDER_API_KEY——提供商/模型语法见 LiteLLM embedding 文档。reranker 不是 LiteLLM 客户端——它会直接向 {base_url}/rerank 发送 POST 请求(src/patterns/safe_tei_rerank.py),因此 RERANKER_MODEL(默认值为 Alibaba-NLP/gte-reranker-modernbert-base)是 TEI 模型名称,而不是 LiteLLM 模型字符串。使用不同模型的远程 embedder 会导致预构建的稠密缓存失效——请运行 make embed-cache 重新生成缓存,确保向量与所用模型一致。


配置

config.json

服务会读取相对于仓库路径的 config/config.json(可通过 --config-path 或 CONFIG_PATH 覆盖)。每个值都是 {env:VAR:-default} 占位符,会在加载时展开,因此随附文件也可作为环境变量参考。架构(节选):

{
  "logging_level": "{env:LOGGING_LEVEL:-INFO}",
  "transport": "{env:TRANSPORT:-stdio}",
  "host": "{env:HOST:-0.0.0.0}",
  "port": "{env:PORT:-8050}",
  "generator": {
    "provider": "{env:GENERATOR_PROVIDER:-openai}",
    "config": {
      "model": "{env:GENERATOR_MODEL:-gpt-4o-mini}",
      "base_url": "{env:GENERATOR_BASE_URL:-https://api.openai.com/v1}",
      "api_key": "{env:GENERATOR_API_KEY:-}",
      "temperature": "{env:GENERATOR_TEMPERATURE:-0.1}",
      "timeout_seconds": "{env:GENERATOR_TIMEOUT_SECONDS:-120.0}",
      "generation_batch_size": "{env:GENERATOR_GENERATION_BATCH_SIZE:-5}",
      "generation_max_concurrency": "{env:GENERATION_MAX_CONCURRENCY:-2}",
      "circuit_breaker_failure_threshold": "{env:GENERATOR_CIRCUIT_BREAKER_FAILURE_THRESHOLD:-3}",
      "circuit_breaker_cooldown_seconds": "{env:GENERATOR_CIRCUIT_BREAKER_COOLDOWN_SECONDS:-60.0}"
    }
  },
  "embedder":  { "provider": "{env:EMBEDDER_PROVIDER:-tei}", "config": { "base_url": "{env:EMBEDDER_BASE_URL:-http://design-pattern-tei-embed:8080}" } },
  "retrieval": { "bm25_weight": "{env:RETRIEVAL_BM25_WEIGHT:-0.3}", "dense_weight": "{env:RETRIEVAL_DENSE_WEIGHT:-0.7}", "max_concurrent_parts": "{env:RETRIEVAL_MAX_CONCURRENT_PARTS:-1}" },
  "reranker":  { "rerank_text": "{env:RERANK_TEXT:-full}", "rerank_top_n": "{env:RERANK_TOP_N:-10}" },
  "reasoning": { "enabled": "{env:REASONING_ENABLED:-true}", "per_phase": { "analyze": { "enabled": "{env:REASONING_ANALYZE_ENABLED:-true}" }, "weights": { "enabled": "{env:REASONING_WEIGHTS_ENABLED:-true}" }, "generate": { "enabled": "{env:REASONING_GENERATE_ENABLED:-true}" }, "evaluate": { "enabled": "{env:REASONING_EVALUATE_ENABLED:-true}" } }, "max_injected_chars": "{env:REASONING_MAX_INJECTED_CHARS:-}" },
  "validation": { "max_retries": "{env:VALIDATION_MAX_RETRIES:-1}", "retry_on_fail": "{env:VALIDATION_RETRY_ON_FAIL:-true}", "truncation_rerun": "{env:VALIDATION_TRUNCATION_RERUN:-repair}", "truncation_boost_max_completion_tokens": "{env:VALIDATION_TRUNCATION_BOOST_TOKENS:-65536}" },
  "prompts": { "stable_prefix_first": "{env:PROMPT_STABLE_PREFIX:-false}" },
  "loop":  { "max_tries": "{env:LOOP_MAX_TRIES:-2}", "min_quality_score": "{env:LOOP_MIN_QUALITY_SCORE:-50}" },
  "tasks": { "deadline_seconds": "{env:TASKS_DEADLINE_SECONDS:-1800.0}", "heartbeat_enabled": "{env:TASKS_HEARTBEAT_ENABLED:-true}", "heartbeat_interval_seconds": "{env:TASKS_HEARTBEAT_INTERVAL_SECONDS:-30}" },
  "jobs":  { "db_path": "{env:JOBS_DB:-~/.config/design-pattern-mcp/jobs.db}" }
}
生成器大模型(LlamaIndex LiteLLM)

生成器大模型通过 LlamaIndex LiteLLM 集成访问。所有提供商设置都遵循 LiteLLM 的模型语法:<provider>/<model>。开发栈和基准测试框架默认使用 MiniMax:

配置 / 环境变量开发栈默认值
GENERATOR_PROVIDERminimax
GENERATOR_MODELminimax/MiniMax-M2.7
GENERATOR_BASE_URLhttps://api.minimax.io/v1
GENERATOR_API_KEY回退使用 MINIMAXAI_API_KEY(主机环境变量或 .env)

提供商列表及语法:LiteLLM 提供商文档。temperature、top_p、top_k、timeout_seconds 和熔断器参数会映射到相应的 LiteLLM/提供商参数。

稠密 embedding 缓存(重启后仍持久的检索)

默认启用。 随附配置解析为 dense_cache.mode=auto,且 write=true(Pydantic 默认值和 config/config.json 均如此;两个 compose 栈也都显式设置了相同值),服务路径始终会传入缓存——容器栈完全不需要配置缓存,主机运行只需导出一个变量(DENSE_CACHE_PATH,见“本地开发”部分)。只有在明确要求时才会关闭缓存:设置 DENSE_CACHE_MODE=off(用于 compose 栈或主机运行),在配置文件中设置 mode=off,使用 --offline/--health 路径(确定性嵌入器,不使用缓存),以及使用基准测试的 compose 覆盖配置(测量冷启动)。 tests/unit/test_config.py::test_dense_cache_defaults 和 ::test_shipped_config_validates 固定了这些默认值。

密集检索环节使用一个 FAISS 索引,涵盖目录中的所有记录(486 条记录 → 启动时生成 486 个 document_text 嵌入)。该矩阵会与清单一起快照到磁盘,并在下次启动时重新加载,因此重启只需生成一个探测嵌入,而不必遍历整个语料库(在 CPU TEI 旁路容器上约需 19 分钟)。

  • 路径:DENSE_CACHE_PATH(镜像中的路径为 /app/data/dense-cache)。 内容:manifest.json(提交标记)+ vectors.npy。没有可用清单的目录会被视为普通未命中;mode=require 会将未命中转为启动错误(ERR_008),mode=off 则完全跳过读取缓存。
  • 写入时机:冷启动嵌入完成后立即写入(DENSE_CACHE_WRITE=true),因此即使之后的启动步骤失败,快照也已写入磁盘。先写入向量文件,再写入清单,因此如果写入中途崩溃,下次启动会将该目录视为未命中。
  • 容器会将其持久化到命名卷 (design-pattern-mcp-dev-dense-cache / design-pattern-mcp-systemd-dense-cache)——因此快照在容器重建、执行 docker compose down 和升级镜像后仍会保留。新建卷会从镜像内置的快照初始化;现有卷则保留自身内容,因此在更改目录或模型后重新构建时,应在执行 up -d 前删除该卷(docker volume rm <name>),否则校验会强制重新嵌入一次(约 19 分钟)并重写该卷。要获得真正的冷缓存,需要使用不含缓存的镜像(make docker-build-nocache)或设置 mode=off——DENSE_CACHE_MODE=off 同时适用于 compose 堆栈和主机运行。
  • 自动重建:嵌入函数发生变化(模型字符串、文本指令、声明的 model_repo/onnx_variant)、目录发生变化(记录数量、名称顺序或任何 document_text——corpus_sha256)、vectors.npy 缺失/形状无效/范数异常,或探测向量显示相同配置背后的模型已变更(重新部署的 TEI sidecar;余弦值低于 dense_cache.probe_min_cosine)时,都会触发重建。每次此类变更只会重新嵌入一次:重建的快照会以新身份写回,因此下次重启时会再次命中(由较早版本构建的缓存,例如缺少 EMBED_MODEL_REPO 时构建的缓存,也会因相同原因未命中一次)。每项决策都会记录所用目录(compose 堆栈中的 JSON 日志字段):Dense cache hit(path、records、mode)、Dense cache miss(reason、path)、Dense cache written(path、records、dimension)、Dense cache disabled(mode、path)、Dense cache write failed(path、reason)——此外,检索器还会记录摘要 Dense vectors resolved(source = cache-hit / embedded / disabled,documents)。
  • 尽力写入:缓存目录为只读或已满时,会记录 Dense cache write failed,运行会继续使用刚刚嵌入的向量——缓存写入不会导致启动失败。
  • 单写入者:不使用锁。每个缓存目录只运行一个服务进程(dev 和 systemd 堆栈使用不同的卷;基准测试工具会固定使用自己的临时 data/dense-cache,并在缓存为冷缓存时拒绝运行,除非设置 mode=off)。
  • 主机运行(uv run python -m src.main)必须将 DENSE_CACHE_PATH 指向可写目录——随附的默认路径 /app/data/dense-cache 仅存在于镜像中。可以执行 export DENSE_CACHE_PATH=$PWD/data/dense-cache 以复用 make embed-cache 生成的快照,也可以将其指向 ~/.config/design-pattern-mcp/dense-cache,让首次启动时写入缓存。
关键环境变量
变量默认值说明
GENERATOR_API_KEY(必填)Generator API 密钥(开发环境技术栈会回退使用 MINIMAXAI_API_KEY)
GENERATOR_PROVIDERopenaiLiteLLM 提供商前缀(minimax、openai、anthropic、openrouter……)
GENERATOR_MODELgpt-4o-mini模型名称;minimax/MiniMax-M2.7 是经过测量的开发环境技术栈默认值
GENERATOR_BASE_URLhttps://api.openai.com/v1API 基础 URL(LiteLLM api_base)
GENERATOR_TEMPERATURE0.1采样温度
GENERATOR_TIMEOUT_SECONDS120.0限制向模型发送的单个 HTTP 请求
GENERATOR_GENERATION_BATCH_SIZE5每个 GENERATE 批次的模式数
GENERATION_MAX_CONCURRENCY2同时进行的 GENERATE 批次数
GENERATOR_CIRCUIT_BREAKER_FAILURE_THRESHOLD3连续发生符合条件的提供商故障(超时、连接故障、408/429/5xx、空响应)后打开熔断器;身份验证/配置类 4xx 永不计入
GENERATOR_CIRCUIT_BREAKER_COOLDOWN_SECONDS60.0打开状态的持续时间,之后进行一次半开探测
EMBEDDER_BASE_URLhttp://design-pattern-tei-embed:8080TEI 嵌入器端点
EMBEDDER_BATCH_SIZE16嵌入批次大小
DENSE_CACHE_PATH/app/data/dense-cache(镜像中)Dense 端快照目录(manifest.json + vectors.npy):重启时重新加载,无需调用语料嵌入;嵌入器/语料/探测发生任何变化时重建。主机运行时会将其覆盖为可写路径
DENSE_CACHE_MODEautoauto(未命中时重新嵌入)、require(未命中时在启动时引发 ERR_008)、off(永不读取或写入缓存)
DENSE_CACHE_WRITEtrue持久化重新嵌入的语料(尽力而为——写入失败会记录 Dense cache write failed,运行仍会保留其向量)
RETRIEVAL_DENSE_WEIGHT0.7Dense 端融合权重(与 ..._BM25_WEIGHT 之和必须为 1.0 ± 1e-3——经配置验证;某一端低于 0.05 时会记录警告)
RETRIEVAL_BM25_WEIGHT0.3BM25 端融合权重
RETRIEVAL_MAX_CONCURRENT_PARTS1每个部分的重排并发数。上限设为 2 会让 CPU TEI 重排 sidecar 的 16,384-token 缓冲区达到饱和(HTTP 429)——除非已对 sidecar 进行测量,否则保持为 1
RERANK_TEXTfull重排输入文本:full(排序结果如文档所述)或 capsule(快 3.6–4.3 倍,但排序结果会有差异——需显式启用)
RERANK_TOP_N10重排前 N 项
REASONING_ENABLEDtrue预 LLM 推理层的总开关
REASONING_{ANALYZE,WEIGHTS,GENERATE,EVALUATE}_ENABLEDtrue各推理阶段的开关;禁用的阶段会提供空推理上下文(不调用生成器、不启动子进程、不写入缓存条目),而启用阶段发生故障时会静默降级为提示词内的脚手架
REASONING_{...}_THOUGHTS2 / 阶段每个阶段的主调用前所需推理步骤数
REASONING_STEP_TIMEOUT_SECONDS20每次思考的工具调用超时
REASONING_MAX_TOTAL_STEPS8每个阶段的推理步骤数上限
REASONING_MAX_INJECTED_CHARS不限注入下游提示词的渲染后推理轨迹上限;超出部分会被截断,并标记为 (reasoning trace truncated at N chars)(经测量的延迟调节项)
REASONING_FAIL_FASTfalse推理工具不可达时令服务启动失败(默认:降级并记录 ERROR)
REASONING_QUIET_STDERRtrue禁止推理子进程向 stderr 输出;设为 false 可调试启动失败问题
VALIDATION_MAX_RETRIES1结构化输出修复额度(仅适用于模型输出失败——提供商错误会重新抛出,绝不会触发修复提示词)
VALIDATION_TRUNCATION_RERUNrepair截断处理:repair(默认)、boost(优先处理截断:使用 boost 上限重新运行一次,不会在相同上限下进行修复)、off
VALIDATION_TRUNCATION_BOOST_TOKENS65536boost 重运行的 max_completion_tokens(MiniMax M2.x 推荐上限)
PROMPT_STABLE_PREFIXfalse调整每个操作的用户提示词顺序,使静态响应契约块置前、每次运行的负载置后(MiniMax 被动提示词缓存优化;两种顺序的内容完全相同)
LOOP_MAX_TRIES2设计循环 GENERATE→EVALUATE 尝试次数
LOOP_MIN_QUALITY_SCORE50.0提前停止的分数阈值
TASKS_DEADLINE_SECONDS1800.0单次工具调用/作业的全程运行时限;到期时运行会以 ERR_014 结束(管道内部的 llama-index Workflow 超时为该值的 0.9 倍)
TASKS_HEARTBEAT_INTERVAL_SECONDS30进度通知间隔(应低于客户端的空闲超时时间)
JOBS_DB~/.config/design-pattern-mcp/jobs.db异步作业三件套使用的 SQLite 路径
PATTERN_DIRECTORYpattern/模式文件目录
LOGGING_LEVELINFODEBUG 会捕获每次推理思考和每一步的工具响应
TRANSPORTstdiostdio 或 streamable-http
PORT8050HTTP 绑定端口(容器中为 8050;开发主机为 8822,systemd 主机为 8812)
CONFIG_PATHconfig/config.json配置文件路径
CLI 参数
参数说明
--config-path配置文件路径(默认:config/config.json)
--transport {stdio,streamable-http}覆盖传输模式
--host覆盖 HTTP 绑定主机(默认:0.0.0.0)
--port覆盖 HTTP 端口(默认:8050)
--health运行离线就绪检查(配置 + 目录 + 索引)并退出
--offline使用确定性离线嵌入器/重排器提供服务(无网络;仅词法检索)

结构化推理

在每次提示词 LLM 阶段调用(analyze / weights / generate / evaluate)之前,服务都会运行一个有界的 ThoughtGenerator 循环:每个步骤由生成器 LLM 编写(每个步骤调用一次补全),并提交到 shannonthinking 和/或 code-reasoning MCP 服务——这些结构化思考草稿本会验证、编号并记录每个步骤。生成的轨迹会作为 <reasoning_context> 块注入阶段提示词。约定:每条思路 = 1 次 LLM 补全 + 1 次 MCP 工具调用,上限由 REASONING_MAX_TOTAL_STEPS 控制(默认值为 8)。每个阶段的工具列表默认包含两个草稿本;启动健康检查会准确检查已启用阶段所用的工具。

主要特性:

  • 内置于 Docker — 镜像会将两个 npm 包打包进镜像;运行时通过 node 直接调用它们(无需网络,也不使用 npx)。
  • 在 Docker 外自动回退到 npx — 找不到内置入口时,会回退到 npx -y <pkg>(首次调用时下载)。
  • 单次调用静默降级 — 已启用阶段中的任何进程启动、超时或工具故障都会记录 WARNING,阶段随后会使用降级版的提示词内思考框架继续运行;推理中断不会导致工具调用失败。通过 REASONING_<PHASE>_ENABLED=false 禁用的阶段则会提供空的推理上下文——不会调用生成器、启动子进程或创建缓存条目。
  • 启动时报错,运行时软失败 — 生命周期健康检查会报告推理健康状态;设置 REASONING_FAIL_FAST=true 可在工具故障时改为使启动失败。
  • 轨迹缓存 — analyze 和 generate 轨迹会针对每个设计请求计算一次,并在设计循环的多次尝试中复用;weights 和 evaluate 轨迹则每次运行都会重新计算。
  • REASONING_MAX_INJECTED_CHARS — 可限制注入下游的渲染轨迹长度(默认不设上限),以减少每次下游调用的输入令牌数。

延迟说明:完整运行会串行启动子进程,调用 8 次推理工具(每个阶段 2 次);推理占端到端延迟的比重较大。在 Stage-0 基准测试中测得(MiniMax-M2.7 生成器,18 个场景,NO_WARMUP=1):发布配置(所有阶段均启用)的 p50 为 288.4 s/p95 为 439.6 s;设置 REASONING_WEIGHTS_ENABLED=false REASONING_EVALUATE_ENABLED=false 后,p50 为 253.0 s/p95 为 413.9 s——两组均通过质量门槛(总体命中率 ≥ 基线 Wilson 下限)。各阶段开关是文档所述的选择性启用方式。


长时间运行的工具与超时

select_design_patterns 会运行多阶段流水线,每次调用需要数分钟。这由工作负载本身决定:生成器 LLM 会处理融合后的检索候选项、各部分的质量权重以及所有前序阶段的完整输出,并逐个令牌生成大型且严格遵循结构的 JSON 文档。设计循环会重复执行 generate → evaluate,最多达到 LOOP_MAX_TRIES 次。如果调用方只需要模式决策(由 Agent 自行编写代码),analyze_design 只运行 §1–§8,并跳过 generate → evaluate 循环。

四种边界共同约束一次运行——不要混淆
边界默认值范围
GENERATOR_TIMEOUT_SECONDS120 s向模型发起的一次 HTTP 请求
VALIDATION_MAX_RETRIES1修复时只会重新发起一次调用,且仅针对模型输出失败
LOOP_MAX_TRIES2GENERATE→EVALUATE 设计循环的尝试次数
TASKS_DEADLINE_SECONDS1800 s整次运行;超时会取消正在进行的工作,并以 ERR_014 结束
心跳防护(默认启用)

每个长时间运行的工具都会由并行协程每 30 秒发送一次 progress 通知(TASKS_HEARTBEAT_INTERVAL_SECONDS)。只要接收到任何数据就会重置空闲计时器的客户端,可以在整个流水线运行期间保持连接。

TS-SDK 客户端(Claude Desktop、Cursor)不会因 progress 通知而重置超时计时器。

异步作业三件套(适用于超时受限的客户端)
submit_design_job(description, language?, ...)  → job_id
get_design_status(job_id)                       → {status, result | error}
cancel_design(job_id)                           → best-effort, next stage boundary

submit_design_job 会在毫秒内返回 job_id;流水线会在后台任务中运行,存储使用 SQLite(JOBS_DB)。每隔 10–30 秒轮询一次。这是适用于 TS-SDK 客户端的有效解决方案。

使用直接 HTTP 客户端绕过客户端超时

examples/design_pattern_client.py 是一个直接的 Python HTTP 客户端,没有客户端空闲超时——发起一个阻塞请求,无论耗时多久都会返回完整响应:

make docker-up          # Terminal 1
make client-analyze     # Terminal 2: analyze_design only
make client-design      # Terminal 2: select_design_patterns, the long synchronous call

两个目标都会调用同一个直接客户端(--tool analyze|design)。make client-design 展示了服务端能够正确完成长时间请求——超时问题完全出在客户端。封装了 MCP 的宿主应用(Claude Desktop、Cursor 等)会施加自己的超时限制;在这些应用中请使用异步作业三件套。


基准测试与验证

本仓库将选择质量和流水线延迟视为可测量的属性,而非口头宣称。

基准测试工具(tests/benchmark/、make benchmark-*):包含 18 个场景并划分留出集;make benchmark-live NO_WARMUP=1 OUT=benchmarks/<arm> RUN_ID=<id> 会在进程内运行完整流水线,并按阶段归因(reasoning.、llm.、rerank、embed——调用次数、延迟、字符/秒、修复计数)。make benchmark-analyze 使用相同的评估环节,在 ANALYZE 阶段后停止(选择命中率/召回率/得分,不进行生成);make benchmark-compare 接受一组 analyze/live 配对结果,并报告命中率的 Newcombe 区间、选择指标的变化和命中翻转情况。由于端到端差异来自跳过的生成工作,p95 延迟规则会标记为不适用。make benchmark-selfcheck 会逐项人工核验每个指标公式。make benchmark-compare A=<baseline> B=<candidate> 会应用预先登记的规则——当且仅当候选版本的留出集端到端 p95 改善 ≥ 15 %,且候选版本整体可接受主选项命中率 ≥ 基线整体 Wilson 下界时,候选版本才算胜出——并在候选版本落败时以状态码 1 退出。端到端模式测量的是已部署的 compose 堆栈,不能与进程内模式进行比较。

参考组(已提交至 benchmarks/,均使用 MiniMax-M2.7,包含 18 个场景):

组配置端到端 p50端到端 p95
base-fresh已发布的默认值(所有阶段均启用推理)288.4 s439.6 s
cfg-reasoning+ 关闭 weights/evaluate 推理(通过环境变量选择启用)253.0 s413.9 s
code-levers+ L5 截断增强、L6 跟踪上限、L7 稳定前缀(默认均关闭,由环境变量控制)223.6 s379.2 s
analyze-20261025仅 analyze 组(不执行 generate/evaluate),配置/环境变量与 live-20261025 相同161.5 s378.1 s
live-20261025完整流水线,NO_WARMUP=1,已发布的默认值273.0 s474.6 s

analyze 与 live 配对结果(2026-10-25,基线 live-20261025,候选版本 analyze-20261025) 测得整体可接受主选项命中数分别为 12/18 和 12/18(Newcombe Δ +0.000 [−0.286, +0.286]); 留出集分别为 4/6 和 5/6(Δ −0.167 [−0.558, +0.295]),recall@5 分别为 0.378 和 0.367。两个场景向每个方向翻转(总计 4 个),因此相同的总数对应的是不同场景;所有划分的区间都包含零。没有依据这些结果更改默认值。 代码开关以可选环境配置的形式提供,不作为默认设置:累计收益声明通过了针对 base-fresh 的预注册门槛(留出集 p95 从 410.9 → 297.5 s = 27.6 % ≥ 15 %,整体 13/18 ≥ 下限),但与 cfg-reasoning 的归因比较记录到候选方案表现较差(+12.5 % < 15 %),因此默认行为保持不变。启用方法:

export VALIDATION_TRUNCATION_RERUN=boost
export REASONING_MAX_INJECTED_CHARS=4000
export PROMPT_STABLE_PREFIX=true

验证层(本仓库的差异化之处):

层级内容位置
L1单元测试(收集到 418 项,362 个测试函数)tests/unit/
L2Hypothesis 属性预言机(test_config_properties.py 中有 15 项;共收集到 115 项验证测试)tests/verification/
L3规范花园(FG-* 变异体)verify/,make verify-fizz-garden
L4FizzBee 穷举模型(8 个规范:作业运行器/协议、流水线控制、设计循环、推理重试、TEI 回退、检索融合、稠密缓存)verify/fizz/,make verify-fizz
—变异测试门槛(mutmut 基线;新增存活变异体会导致 make test-mutations 失败,在 nightly CI 中仅作提示)verify/mutmut-baseline.json,make test-mutations
—台账(门控)+ 交叉一致性(提示性自然语言文档分流)make verify-ledger,make verify-cross-consistency

每个 .fizz 断言都必须至少杀死一个规范花园变异体,或附带 # spec-explains: 说明;修改决策模块时,必须在同一个 PR 中更新对应的 .fizz 模型。规范性流水线规范见 docs/implementation-guide.md(按 § 编号,并镜像翻译为德语,见 docs/selektions-process-de.md);工具结果的线协议契约见 docs/result-schema.json,目录记录契约见 docs/pattern-schema.json。


故障排查

服务已启动,但看不到工具
  1. 检查 Agent 的 MCP 连接:Claude Code 使用 /mcp,OpenCode 使用 opencode mcp list,Codex 使用 codex mcp list
  2. 确认服务进程已启动且目录已加载:uv run design-pattern-mcp --health 会输出 OK 和 JSON 就绪报告(记录、语言文件、别名)
  3. 确认 TEI 嵌入器运行正常:docker compose -f docker/docker-compose.yml ps(健康检查的嵌入模型启动等待期为 120 s)
“Connection refused”或启动失败

嵌入器无法访问时,索引预热会拒绝启动服务(快速失败,而不是让你的第一个请求失败):

docker compose -f docker/docker-compose.yml logs design-pattern-tei-embed

本地非 Docker 运行必须将 EMBEDDER_BASE_URL / RERANKER_BASE_URL 指向可访问的端点,或使用 --offline 启动。

大模型提供商错误(502 / 401)
  • 确认已设置 GENERATOR_API_KEY(或开发栈中的 MINIMAXAI_API_KEY),且密钥未过期
  • 确认 GENERATOR_BASE_URL 与你的提供商端点一致
  • 连续发生 3 次传输失败后,熔断器会打开 60 s(..._CIRCUIT_BREAKER_* 参数);身份验证/配置类 4xx 错误不会计入其中
ERR_012 / ERR_014
  • ERR_012 = 已取消(通过 cancel_design 取消,或客户端断开连接后在下一阶段边界处取消)
  • ERR_014 = 超出整次运行的截止时间(TASKS_DEADLINE_SECONDS);对于确实需要更长时间的运行,请显式调高该值——正在执行的提供商协程会被取消,部分结果会被丢弃
重排器出现 429

一次完整的全文重排请求就已耗尽 CPU TEI sidecar 的 16,384-token 推理缓冲区(MAX_BATCH_TOKENS=8192 会影响请求打包;测量日期为 2026-09-25):retrieve_many 中并发数为 2 的分支会直接失败,并返回 HTTP 429“Model is overloaded”。请保持 RETRIEVAL_MAX_CONCURRENT_PARTS=1(随附默认值);服务端不变量也会确保 dense_top_k + bm25_top_k ≤ sidecar 的 MAX_CLIENT_BATCH_SIZE(48)。

模式 JSON 文件未加载
  • 每种模式的记录由 14 个文件合并而成(pattern/<name>.generic.json + 13 个 <language>.json);通用文件为必需文件
  • 使用 ./scripts/verify-patterns.sh 验证目录(两个 schema,以及 ajv 无法表达的变体检查;映射一致性和孤立项由启动门禁强制检查)
  • 如果枚举与 schema 不一致,启动会失败(assert_enums_in_sync)——这是有意为之;应修复数据,而不是防护机制

构建与开发

常用 make 目标:

目标描述
make install将依赖同步到 .venv
make install-mcps全局安装推理 MCP 服务(本地开发使用;Docker 镜像中已包含)
make check-lintruff
make check-static-typing对 src/ 执行 mypy --strict(60 个文件)
make check-deadcode / make check-depcheckvulture / deptry
make check-all全部四项检查门禁
make test-unit单元测试(tests/unit/)
make test-oracles可执行预言机:L1 canary、L2 属性预言机、spec-garden 回放(test_fizz_garden);test_fizz_traces/test_fizz_conformance 已规划,尚未落地
make test-mutations针对 verify/mutmut-baseline.json 执行 mutmut 递进检查
make verify-fizz穷举式 FizzBee 模型检查(L4)
make verify-ledger / make verify-cross-consistencyLedger + NL 文档一致性门禁
make benchmark-live / make benchmark-analyze / make benchmark-compare / make benchmark-selfcheck基准测试工具(见上文)
make embed-cache强制重新生成 data/dense-cache/
make docker-build-all构建全部三个镜像(内置 dense cache)
make docker-up / make docker-down启动 / 停止开发栈
make client-analyze / make client-design / make client-async针对 http://localhost:8822/mcp 的演示客户端
make docker-publish将服务镜像推送至 Docker Hub + GHCR(并添加 git 标签)

开发工作流:

make install               # first-time setup
uv run pre-commit install  # First-time setup: commit hook
make check-all             # before pushing
make test-unit             # behavioral oracle
uv run mypy --strict       # src/ is strict; must exit 0
make docker-up             # after image-affecting changes

基本规则(来自 AGENTS.md):src/ 使用 mypy 严格模式;schema 变更时,必须在同一提交中更新 docs/implementation-guide.md、schema 和代码;流水线控制流变更时,必须在同一 PR 中更新对应的 FizzBee 模型。


发布

全部三个镜像都会同时发布到两个注册表:

镜像Docker HubGHCR标签
MCP 服务olkowa/design-pattern-mcpghcr.io/olk/design-pattern-mcp$(DOCKER_TAG)、latest
TEI 嵌入器olkowa/pattern-tei-embedghcr.io/olk/pattern-tei-embed$(DOCKER_TAG)、latest
TEI 重排序器olkowa/pattern-tei-rerankghcr.io/olk/pattern-tei-rerank$(DOCKER_TAG)、latest

全部三个镜像共用同一个 $(DOCKER_TAG)(取自 pyproject.toml 的版本)。TEI 镜像也由同级的 architecture-pattern-mcp 服务共用,且很少变更——blob 去重使未变更的 TEI 镜像重新打标签的成本很低;sidecar 未变更时,也可以跳过推送 TEI 镜像。

带宽说明: TEI 嵌入器镜像约为 5 GB(内置 ONNX fp32 权重)。首次推送到每个注册表时,需上传约 5 GB。后续推送采用增量方式——只传输变更的层。

前置条件

Docker Hub——本地已完成身份验证(docker login)。

GitHub Container Registry——需要具备 write:packages 权限范围的 classic PAT。无需担心 2FA——PAT 可绕过它。登录后令牌会被丢弃;凭据会保留在 ~/.docker/config.json 中,直到你登出。

发布(一次性设置 + 每个会话)
# 1. Login to GHCR (interactive — paste token at the password prompt)
docker login ghcr.io -u olk

# 2. Build and push all three images (MCP + TEI embedder + TEI reranker)
#    The umbrella target builds the MCP image, tags it, pushes it, creates the git tag,
#    then builds and pushes each TEI image in sequence.
make docker-publish-all

# 3. Logout from GHCR immediately after publishing
#    (removes the ghcr.io credential from ~/.docker/config.json)
docker logout ghcr.io

后续发布时重复步骤 1–3。如果 PAT 已过期,请通过上方链接生成新的 PAT。make docker-publish 只推送 MCP 服务镜像(并添加 v$(DOCKER_TAG) git 标签,以及通过 mcp-publisher 发布的 MCP Registry 条目);make docker-publish-tei 只推送两个 TEI sidecar。

首次推送——将软件包设为公开(仅 GHCR)

GHCR 软件包默认是私有的。首次运行 make docker-publish-all 后,将这三个软件包都设为公开:

软件包设置 URL
MCP 服务https://github.com/users/olk/packages/container/design-pattern-mcp/settings
TEI 嵌入器https://github.com/users/olk/packages/container/pattern-tei-embed/settings
TEI 重排器https://github.com/users/olk/packages/container/pattern-tei-rerank/settings

将每个软件包设为公开并保存。

部分失败后的恢复

如果推送中途失败(例如,尚未配置 GHCR 身份验证),Docker Hub 层已经上传。修复身份验证后,重新运行 make docker-publish-all 是安全的——每个注册表都会报告已上传层的缓存命中,并完成剩余推送。若要针对性重试,可使用 make docker-publish-tei 推送 TEI sidecar。


systemd 服务(Linux)

该服务可在任何基于 systemd 的 Linux 主机上作为 systemd 服务运行。它会在启动时自动启动 Docker Compose 堆栈。完整的 Agent 运维手册安装说明见:INSTALL.md(路径 B)。systemd/ 包含:

文件用途
systemd/design-pattern-mcp.servicesystemd 单元
systemd/docker-compose.yml生产环境 compose 变体(无 build:、绝对路径、容器端口 8050)
systemd/README.md完整运维手册:安装、验证、故障排除

生产环境 compose 是开发文件的部署变体:仅使用预构建镜像、采用绝对路径,可部署到 /etc/design-pattern-mcp/。TEI sidecar 位于共享的 pattern-tei-infra 堆栈中;此堆栈会加入其 Docker 网络,并通过 DNS 名称访问这些 sidecar。只有在共享 TEI 基础设施处于 active (running) 状态后,才能启动该服务。

# Fast path (see INSTALL.md Path B for the full verified sequence):
VERSION=$(grep -m 1 '^version' pyproject.toml | sed -E 's/.*"([^"]+)".*/\1/')
docker pull "olkowa/design-pattern-mcp:${VERSION}"
docker tag "olkowa/design-pattern-mcp:${VERSION}" design-pattern-mcp:latest
sudo install -d /etc/design-pattern-mcp/config
sudo install -m 644 systemd/docker-compose.yml /etc/design-pattern-mcp/
sudo install -m 644 config/config.json /etc/design-pattern-mcp/config/
sudo install -m 644 systemd/design-pattern-mcp.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable --now design-pattern-mcp

日常操作:使用 systemctl start|stop|restart design-pattern-mcp,通过 journalctl -u design-pattern-mcp -f 查看日志。详情请见 systemd/README.md。


许可证

MIT License。版权所有 (c) 2026 Oliver Kowalke。请参阅源文件中的许可证声明。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。