- 后端
- 微服务
- 云原生
【免费下载链接】midway
🍔 A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 🌈
导读
Midway 主仓中并不缺少文档、API 符号、Changelog 等知识原材料,缺的是"适合 Agent 稳定查询的数据契约"。本篇文章围绕仓库内 openspec/changes/add-midway-agent-knowledge/design.md 展开,讲解 Midway 如何将site/docs、typedoc API 数据、包元数据与版本演进信息归一化为版本化、可结构化查询的知识快照(bundle),并由@midwayjs/skill-midway包落地为统一查询 CLI 与多 AI 产品可安装的 skill。读完本文,你将掌握知识快照的四层架构、五类查询契约语义、版本解析与新鲜度策略,以及如何用midway-skill命令构建 bundle、查询文档/API/包/Changelog 并将 skill 安装到 Codex、Cursor、Trae 等 20+ 个 AI 客户端。
背景:缺口不在"有没有内容",而在"有没有数据契约"
Midway 主仓已经具备构建 Agent 知识层的核心原材料:
site/docs与site/versioned_docs:教程、组件、扩展、迁移文档;site/versions.json与 site/docusaurus.config.js 中的 Docusaurus 当前版本配置:版本边界;api-typedoc.json类结构化 API 符号与源码链接;- CHANGELOG.md:版本演进;
- packages/mcp:Midway 自身的 MCP 承载能力;
@signalwire/docusaurus-plugin-llms-txt:面向 LLM 的文本出口。
设计文档的结论是:当前缺口不在内容本身,而在于缺少一份"适合 Agent 稳定查询的数据契约"。如果 skill、@midwayjs/skill-midway、MCP 各自去抓取站点页面并自行解析,就会产生重复抓取、重复解析、口径不一致的问题;把知识以统一契约快照的形式固化下来,才是让 Agent 稳定回答 Midway 相关问题的前提。
从仓库现状看,这一设计已经落地为@midwayjs/skill-midway包(版本 4.2.3,见 packages/skill-midway/package.json),其bin入口为midway-skill,依赖@midwayjs/bootstrap、@midwayjs/commander与@midwayjs/core,要求 Node.js >= 20。该包同时提供了"bundle 构建器 + 打包快照与查询命令 + 可安装到多种 AI 产品的 skill 工件"三样东西。
Goals / Non-Goals:设计边界
Goals(要做的事)
- 产出一套官方、版本化、可结构化查询的知识快照;
- 同时覆盖文档、API 符号、包维度和 changelog 语义;
- 为 skill、
@midwayjs/skill-midway、MCP 提供统一数据源,而不是各自抓站点; - 保持中英文信息与版本命中关系;
- 把"最新"明确落在当前文档版本与生成时间上。
Non-Goals(明确不做的事)
- 不在本 change 中实现向量搜索或复杂排序系统;
- 不让 skill 文件承载大量领域正文;
- 不把 consumer 绑定为单一命令行工具或单一 MCP 实现;
- 不引入非官方内容源。
这段边界决定了后面所有设计:知识本体放在 bundle 里,skill 只定义 SOP(标准操作流程),查询逻辑与 transport 解耦,搜索先用简单评分而非向量检索。
四层架构:从原材料到可查询快照
设计文档将整体划分为 4 层,对应实现可见 packages/skill-midway/src/bundle/builder.ts。
1. Source Collection Layer(源收集层)
输入源包括:
site/docs/**;site/i18n/en/docusaurus-plugin-content-docs/current/**;site/versioned_docs/version-*/**;site/.docusaurus/api-typedoc-default.json或对应 versionedapi-typedoc.json;site/versions.json;CHANGELOG.md;- 相关
packages/*/package.json。
该层只负责收集,不负责面向 consumer 的查询逻辑。在builder.ts中对应collectDocRecords、collectApiRecords、collectChangelogRecords、collectWorkspacePackages四条收集路径。
2. Normalization Layer(归一化层)
将多源内容转换为稳定记录:DocRecord、ApiRecord、PackageRecord、ChangelogRecord、VersionRecord。完整字段定义见 packages/skill-midway/src/types.ts。
每条记录至少包含:
| 字段 | 含义 |
|---|---|
id | 全局唯一记录 ID |
kind | 记录类型(doc/api/changelog 等) |
version | 所属 Midway 版本 |
locale | 语言区域(如zh-cn、en) |
title | 标题 |
summary | 摘要 |
sourcePath | 仓库内相对路径 |
sourceUrl | 源码/文档链接 |
API 记录额外包含:
| 字段 | 含义 |
|---|---|
packageName | 所属包名 |
symbolName | 符号名 |
symbolKind | 符号类别(Class/Interface/Function 等) |
qualifiedName | 限定名(如MidwayMCPFramework) |
since | 引入版本 |
deprecated | 是否废弃 |
在types.ts中可以看到实现细节:DocRecord还带有slug与headings两个用于匹配的字段;ApiRecord通过deprecated: boolean承载废弃标记;ChangelogRecord拆出了releaseVersion、releaseDate、majorVersion、summary、content与packageNames,便于按版本区间和包名过滤;PackageRecord则记录了包名、版本、描述与关键词。
builder.ts的归一化关键逻辑:
- 当前版本通过正则从
site/docusaurus.config.js的current: { label: '...' }中提取(对应extractCurrentVersionFromConfig),历史版本读取site/versions.json,最终版本列表为[currentVersion, ...historicalVersions]。当前仓库中site/versions.json的内容为["3.0.0", "2.0.0", "1.0.0"],而 site/docusaurus.config.js 中 current 的 label 为4.0.0,因此快照会覆盖 4.0.0 / 3.0.0 / 2.0.0 / 1.0.0 四个版本; - API 数据仅在当前版本收集:
const apiSupported = version === currentVersion;,历史版本不产出api.json; - 文档按 locale 根目录解析:当前版本取
site/docs(zh-cn)与site/i18n/en/docusaurus-plugin-content-docs/current(en),历史版本取site/versioned_docs/version-<v>与对应的 i18n 目录,不存在的目录自动跳过。
文档归一化(packages/skill-midway/src/bundle/docs.ts)会递归扫描docsRoot下所有.md/.mdx文件,用slug(去掉扩展名的相对路径)作为主键,并通过一个零依赖的 front matter 解析器(packages/skill-midway/src/bundle/markdown.ts)提取title、首个非标题段作为summary、全部#标题作为headings;标题缺失时回退到文件名。
API 归一化(packages/skill-midway/src/bundle/typedoc.ts)解析 typedoc JSON 树,维护一张ReflectionKind数值到标签的映射表(如 128=Class、256=Interface、2048=Method),并排除 Project/Module/签名/参数等噪声节点;qualifiedName由祖先链拼接而成,废弃标记同时识别flags.isDeprecated与@deprecated修饰标签,源码链接则优先采用 typedoc 的sources[0](fileName + line)。
Changelog 归一化(packages/skill-midway/src/bundle/changelog.ts)用正则^##\s+v?([^\s]+)\s+\(([^)]+)\)\s*$切分发布区块,并从正文反引号代码片段中抽取涉及的包名列表(去@midwayjs/前缀)。
3. Bundle Distribution Layer(快照分发层)
知识快照输出为 transport-neutral bundle,建议目录结构如下:
midway-skill/ manifest.json versions/ 4.0.0/ docs.json api.json packages.json changelog.json 3.0.0/ docs.json api.json packages.json changelog.jsonmanifest.json提供:当前版本、历史版本列表、生成时间、支持的 locale、每个 bundle 文件的路径与摘要。在实现中,KnowledgeManifest(types.ts)包含schemaVersion: 1、generatedAt(ISO 时间戳)、currentVersion、repoUrl与versions: VersionBundleManifest[];每个版本的VersionBundleManifest还记录了docsFile/apiFile/packagesFile/changelogFile的相对路径、各文件记录条数,以及capabilities: { docs, api, changelog }能力开关。这正是设计文档中"manifest 显式记录每个 version 的 docs/api 可用性"这一风险缓解措施的实现。
buildKnowledgeBundle(builder.ts)会先清空输出目录,再为每个版本写四个 JSON 文件(历史版本跳过api.json),最后写出manifest.json。
4. Consumer Layer(消费层)
官方只冻结查询契约,不冻结唯一 transport。典型 consumer:
- 官方 skill;
@midwayjs/skill-midway;- 基于
packages/mcp的参考 knowledge server; - 站点调试工具页。
也就是说,无论 Agent 最终以何种形态接入(本地 CLI、MCP server、站点页面),其背后查询的都是同一份 bundle 与同一套查询函数。
Query Contract:五类查询语义
consumer 侧必须至少支持以下查询语义,全部实现在 packages/skill-midway/src/lookup/query.ts:
1.resolveVersion(target)
- 输入:
current、显式 semver、latest; - 输出:
resolvedVersion、matchType。
实现中的matchType有三种取值:alias(current/latest别名命中当前版本)、exact(显式版本精确命中)、fallback(未命中时回退)。回退策略为:提取请求版本的主版本号,在同 major 下挑选最高的已发布快照;若同 major 也没有,则整体回退到currentVersion。比较时使用compareSemverish处理v前缀与 prerelease 后缀(见query.ts中parseSemverish)。
2.lookupDocs({ query, version, locale })
按主题、标题、slug、标题层级匹配文档。实现中按title、slug、summary、headings四个字段打分,可用--locale过滤(如zh-cn/en),默认返回前 10 条。
3.lookupApi({ symbol, packageName?, version })
按导出名、限定名、包名查 API。实现中会对symbolName、qualifiedName、packageName、summary打分,支持--package精确过滤包名;若目标版本capabilities.api === false,直接返回空数组——这呼应了 README 中"历史版本的 API 查询不做保证"的版本行为说明。
4.lookupPackages({ query, version })
按包名、关键词、分类查 Midway 包。实现对name、description、keywords打分,包数据来自packages、packages-serverless、packages-resource三个工作区下所有含package.json的目录(见collectWorkspacePackages)。
5.lookupChangelog({ fromVersion, toVersion?, packageName? })
返回变更条目和关联版本范围。实现支持--package(自动兼容带/不带@midwayjs/前缀)与--from-version/--to-version区间过滤,结果按版本号降序,默认取前 10 条。
所有查询返回都必须带:resolvedVersion、sourceKind、sourcePath、sourceUrl、confidence或matchType。底层打分算法(computeScore)为:字段精确等于查询词得 100 分、前缀命中得 50 分、包含命中得 10 分,取各字段最高分排序后截断——这是设计文档 Non-Goals 中"不做向量检索/复杂排序"的直接落地。
CLI 层通过@midwayjs/commander注册了全部命令(见 packages/skill-midway/src/cli/app.ts 的preloadModules列表),每个查询命令以结构化 JSON 输出到 stdout,方便 Agent 与脚本消费。例如lookup-docs命令(packages/skill-midway/src/cli/commands/lookup-docs.command.ts)会一并返回bundleRoot、query、requestedVersion、resolvedVersion、matchType、capabilities、count与records字段。
官方 Skill 设计:只定义 SOP,不复制知识正文
官方 skill 文件位于 packages/skill-midway/skills/midway/SKILL.md,其设计原则是"skill 只定义 SOP,不直接复制知识正文",因为 skill 的职责是强制 Agent 查询官方源,而不是变成另一本维护成本极高的手册。
最小要求:
- 触发范围:Midway 框架、包、装饰器、配置、生命周期、命令行工具、MCP、部署、迁移相关问题;
- 默认流程:先解析版本 → 再查 knowledge bundle → 命中不足时回退到官方文档页面或源码位置;
- 输出约束:必须说明命中的 Midway 版本;必须优先引用官方来源;推断内容要显式标注是推断。
SKILL.md的具体流程(Workflow)为:先用resolve-version <version>解析用户请求的版本(未指定则用current);再按问题类型调用lookup-docs --query "<topic>"、lookup-api --symbol "<symbol>"、lookup-packages --query "<package or feature>"、lookup-changelog --package "<package>";最后在回答中引用 bundle 解析出的版本、命中结果与源码路径。
SKILL.md的 Rules 明确了 Agent 的行为边界:优先 bundle 结果而非记忆;历史主版本只保证 docs 与 changelog;当resolve-version报告api: false时不得断言历史 API 细节;结果为空时如实说明"bundle 中没有匹配"而不是编造;已知时优先使用@midwayjs/scope 的包名。Output 部分则强制回答必须说明解析出的 Midway 版本、概括命中的记录,并尽量保留 bundle 记录中的链接与源码路径。
多目标安装与更新:一个 skill,多种 AI 产品
midway-skill install与midway-skill update命令将内置 skill 工件安装到当前项目,目标适配层实现在 packages/skill-midway/src/targets/registry.ts,当前支持 20+ 个目标:
amazon-q antigravity auggie claude cline codebuddy codex continue costrict crush cursor factory gemini github-copilot iflow kilocode kiro opencode pi qoder qwen roocode trae windsurf不同目标的产物格式不同:Codex 与 Trae 安装为SKILL.md(含资源文件),Cursor/iflow 安装为/opsx-midway斜杠命令,Gemini/Qwen 安装为 TOML,Continue 安装为.continue/prompts,GitHub Copilot 安装为.github/prompts,其余多为.md描述文件。skill 内容统一从skills/midway/SKILL.md读取并解析 front matter(packages/skill-midway/src/targets/content.ts),各 adapter 负责把同一份内容渲染成对应产品要求的格式。
安装逻辑(packages/skill-midway/src/cli/install.ts)要点:
- 默认项目级安装,写入当前工作目录(可用
--dest覆盖); --target支持逗号分隔多目标,all表示全部安装;- 目标已存在且未指定
overwrite时抛出错误,update命令本质上是带overwrite: true的安装; - 非交互终端(无 TTY)下必须显式传
--target,否则报错。
这种"项目作用域安装"的方式保证了已安装 skill 的版本与项目依赖的@midwayjs/skill-midway版本保持一致,避免 Agent 用过期记忆回答新版问题。
版本策略(Versioning Strategy)
current对应站点当前文档版本标签(本仓库为4.0.0);- 历史版本来自
site/versions.json(本仓库为3.0.0、2.0.0、1.0.0); - 查询显式版本时优先 exact match;
- 无 exact match 时可回退到"同 major 下最近的已发布快照",并向 consumer 暴露
fallback=true(实现中即matchType: 'fallback')。
配套的版本行为(README 与 builder 双重印证):当前主版本能力为docs + api + changelog;历史主版本只有docs + changelog;历史 API 查询不做保证,能力缺失时返回空结果。因此任何版本敏感的问题都应先跑resolve-version,让调用方看清结果是精确命中还是主版本回退。
新鲜度策略(Freshness Strategy)
知识快照的生成应与文档/API 构建绑定,而不是独立手工维护。最低要求:
- 文档构建时生成当前版本 bundle;
- 版本化文档构建时保留历史 bundle;
- 生成产物记录
generatedAt(KnowledgeManifest.generatedAt已实现); - CI 对以下情况给出失败信号:
- 当前文档存在但当前 bundle 缺失;
- 当前 API typedoc 存在但 API bundle 缺失;
- 版本清单与 bundle 目录不一致。
build命令(packages/skill-midway/src/cli/commands/build.command.ts)默认输出到site/.midway-skill,并同步到包内发布目录packages/skill-midway/bundle(随 npm 包一起发布),也支持--repo-root、--site-root、--output、--package-bundle覆盖路径。
关键决策(Decisions)
| 决策 | 原因 |
|---|---|
| 先做 bundle,再做 transport | @midwayjs/skill-midway、MCP、skill 共享同一份数据契约,避免重复抓取和重复解析 |
| 以 docs + typedoc 为双主源 | Midway 的"怎么用"主要在 docs,"能调什么"主要在 typedoc,两者缺一不可 |
latest不直接指 npm registry | 对 Agent 来说,最可信的"最新"应是当前站点发布并完成 bundle 生成的版本,而不是尚未同步文档的包版本 |
| skill 与数据分离 | skill 的职责是强制 Agent 查询官方源,而不是变成另一本维护成本极高的手册 |
风险与权衡(Risks / Trade-offs)
- 风险:docs 与 typedoc 的版本边界不完全一致Mitigation:manifest 中显式记录每个 version 的 docs/api 可用性(
capabilities字段正是为此设计)。 - 风险:历史版本文档结构差异较大,归一化复杂Mitigation:先定义最小公共字段,保留
rawSourcePath作为兜底(实现中每条记录均带sourcePath/sourceUrl指向原始文件)。 - 风险:consumer 直接依赖站点内部生成文件路径,导致后续改动成本高Mitigation:consumer 只依赖 manifest 和 bundle contract,不依赖 Docusaurus 内部目录细节(
loadManifest/loadVersionBundle只按 manifest 中的相对路径读取)。
迁移计划(Migration Plan)
- 在
site构建链路中加入 knowledge bundle 生成; - 为当前版本与历史版本产出统一 manifest;
- 增加官方 skill 文件(已完成,见 packages/skill-midway/skills/midway/SKILL.md);
- 由
@midwayjs/skill-midway与 MCP 等 consumer 消费该 bundle,而不是自行爬站点。
实践:在仓库中构建与查询知识快照
在 Midway 主仓环境下,可直接通过 pnpm 使用@midwayjs/skill-midway的命令:
# 查看帮助 pnpm exec midway-skill --help # 构建知识快照(默认写入 site/.midway-skill,并同步到包内 bundle 目录) pnpm exec midway-skill build # 自定义路径构建 pnpm exec midway-skill build \ --repo-root /path/to/midway \ --site-root /path/to/midway/site \ --output /path/to/output # 先解析版本 pnpm exec midway-skill resolve-version 3.20.12 # 查询文档 pnpm exec midway-skill lookup-docs --query "mcp" pnpm exec midway-skill lookup-docs --query "configuration" --locale en # 查询 API 符号 pnpm exec midway-skill lookup-api --symbol "Configuration" pnpm exec midway-skill lookup-api --symbol "MidwayMCPFramework" --package "@midwayjs/mcp" # 查询包元数据 pnpm exec midway-skill lookup-packages --query "mcp" # 查询 changelog pnpm exec midway-skill lookup-changelog --package "@midwayjs/mcp" pnpm exec midway-skill lookup-changelog --from-version 4.0.0 --to-version 4.0.1 # 安装 skill 到 AI 产品 pnpm exec midway-skill install --target codex pnpm exec midway-skill install --target cursor pnpm exec midway-skill install --target trae pnpm exec midway-skill install --target all pnpm exec midway-skill install --target codex --dest /path/to/project # 覆盖更新已安装的 skill pnpm exec midway-skill update --target codex pnpm exec midway-skill update --target all注意:当包内已打包 bundle 快照时,查询命令优先读取包内 bundle;在 Midway 源码仓库中,也可以用--bundle-root显式指向site/.midway-skill。所有 lookup 命令都在 stdout 输出结构化 JSON,便于 Agent 与脚本直接消费。
质量验证:测试用例如何印证契约
packages/skill-midway/test/index.test.ts 用 fixture 完整验证了设计文档的每一条契约:
- 构建契约:断言
manifest.json、当前版本docs.json/api.json/packages.json/changelog.json存在,历史版本(3.0.0)api.json不存在,且capabilities分别为{ docs: true, api: true, changelog: true }与{ docs: true, api: false, changelog: true }; - 版本解析:
resolveVersion(manifest, 'latest')返回matchType: 'alias'且解析到当前版本;resolveVersion(manifest, '3.20.12')回退到3.0.0且matchType: 'fallback'; - 查询行为:
lookupDocs支持 locale 过滤并命中标题;lookupApi在当前版本命中Configuration、在历史版本返回空数组;lookupPackages按包名命中;lookupChangelog按包名过滤返回对应 release; - CLI 行为:
build命令产出 bundle 并同步 package-bundle;resolve-version命令输出 JSON 载荷;lookup-docs/lookup-api命令返回带resolvedVersion/capabilities/count的结构化结果;install/update命令验证了 CodexSKILL.md、Cursor 斜杠命令、TraeSKILL.md的写入、覆盖与 TTY 交互保护。
Open Questions:仍在演进中的问题
设计文档保留了三个开放问题,也体现了该体系的边界意识:
- 官方 skill 最终是保留在主仓,还是镜像发布到独立 skill 仓库?
- bundle 是直接随站点静态文件发布,还是同步发布一个轻量 npm 数据包(首选名
@midwayjs/skill-midway)?——目前仓库中@midwayjs/skill-midway已作为 npm 包形态存在,并将 bundle 随包发布; lookupDocs是否需要在第一阶段支持全文倒排索引,还是先以标题/slug/heading 命中为主?——当前实现以标题/slug/heading/摘要的加权打分为主,与 Non-Goals 中的"不实现向量搜索"保持一致。
小结
从设计文档到落地实现,Midway Agent 知识层的核心思路可以概括为:先固化数据契约,再放开 transport。@midwayjs/skill-midway用四层架构把 docs、typedoc、packages、changelog 归一为版本化 JSON 快照,用manifest.json统一描述版本边界与能力开关,用五个查询函数冻结查询语义,再用一个只定义 SOP 的SKILL.md约束 Agent 优先查官方源。对希望为自家框架构建 Agent 知识体系的开发者来说,这份 design + 实现组合本身就是一个可复用的参考范式:内容不重复维护、版本不靠猜、查询不靠爬。
- 后端
- 微服务
- 云原生
【免费下载链接】midway
🍔 A Node.js Serverless Framework for front-end/full-stack developers. Build the application for next decade. Works on AWS, Alibaba Cloud, Tencent Cloud and traditional VM/Container. Super easy integrate with React and Vue. 🌈
相关推荐
StripedHyena-Nous-7B长文本处理技巧:高效驾驭32K上下文长度的终极指南
StripedHyena Nous 7B长文本处理技巧:高效驾驭32K上下文长度的终极指南 StripedHyena Nous 7B是一款支持32K上下文长度的
RPCS3 中文补丁配置:6步让PS3游戏菜单显示中文
RPCS3 中文补丁配置:6步让PS3游戏菜单显示中文 模拟器装好了,固件也配了,游戏能开机,但菜单全是英文。你搜到一份RPCS3中文补丁,教程让你把YAML文
虚拟化图形学调试器graphify query 深度解析:OpenCode Skill 的知识图谱查询工作流(query、path、explain 与受约束查询扩展)
graphify query 深度解析:OpenCode Skill 的知识图谱查询工作流(query、path、explain 与受约束查询扩展) 本文基于
人工智能知识图谱RAGAI 技能开发工具MCP 服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考