AI Coding 全流程实战:从需求到上线,我用 AI 开发了一个 NPM 包

16 阅读14分钟

AI Coding 全流程实战:从需求到上线,我用 AI 开发了一个 NPM 包

本文以一个真实项目 md-wx(微信公众号 Markdown 渲染组件)为例,完整记录从需求文档到任务拆分再到项目规则约束 AI 的全流程。每个阶段都附带真实 AI 提示词和代码片段,你可以直接照着做。

背景:为什么要用 AI 开发一个 NPM 包

微信公众号编辑器不支持直接粘贴 Markdown,开发者写完文章后要手动调格式,代码块没有高亮,引用块没有样式边框。市面上的排版工具要么是 Web 应用(不能集成到自己的工具链),要么样式不可定制。

md-wx 要解决的问题是:输入 Markdown 字符串,输出带内联样式的 HTML,直接粘贴到公众号编辑器就能用。以 NPM 包形式发布,支持自定义主题。

整个项目用 AI Coding 的方式完成。下面按开发顺序,拆成五个阶段来讲。


一、需求文档:让 AI 从模糊到清晰

模糊需求阶段:AI 头脑风暴

我的初始需求只有一句话:"把 Markdown 转成公众号能用的格式"。不确定该支持哪些语法、要不要主题系统、API 怎么设计。这时候需要 AI 帮我拓展思路。

给 AI 的提示词:

我想开发一个 NPM 包 md-wx,把 Markdown 转成微信公众号编辑器能识别的 HTML。

请从以下维度帮我分析需求:
1. 核心功能:应该支持哪些 Markdown 语法?公众号编辑器对 HTML 有哪些限制?
2. 用户界面:作为 NPM 包,需要提供 React 组件还是纯函数 API?
3. 可配置性:是否需要支持自定义主题?主题系统怎么设计?
4. 边界情况:有哪些 Markdown 语法在公众号里会渲染异常?

请列出功能清单和优先级建议。

AI 返回的分析帮我收敛出一份需求清单:

优先级功能说明
P0Markdown 解析支持 md 标准语法,基于 markdown-it
P0内联样式输出所有样式写成 inline style,不依赖外部 CSS
P1主题系统内置 3 套主题(默认/暗色/优雅),支持自定义
P1React 组件提供 <MdwxRenderer /> 组件,支持 props 传参
P2CLI 工具命令行直接转文件,npx md-wx input.md

知识点:PRD(Product Requirements Document) PRD 是产品需求文档,由产品经理编写,描述产品要做什么、为谁做、每个功能的具体规则。一份合格的 PRD 包含:背景与目标、用户画像、功能列表、交互逻辑、验收标准。在 AI Coding 流程中,PRD 是喂给 AI 的第一份"规格说明",直接决定后续生成代码的方向。

知识点:MVP(Minimum Viable Product) MVP 是最小可行产品——用最少的开发成本做出能跑通核心流程的版本。上表中 P0 功能就是 MVP 的边界:能解析 Markdown、能输出带内联样式的 HTML,就算可用。P1 和 P2 是后续迭代。

清晰需求阶段:AI 完善文档

需求方向确定后,让 AI 把散落的想法整理成结构化文档:

根据上面的需求分析,请帮我输出一份完整的 PRD 文档,包含:
- 项目背景与目标
- 功能清单(按 P0/P1/P2 分级)
- 技术约束(公众号编辑器对 HTML 的限制)
- API 设计草案
- 验收标准

项目技术栈:React 18 + TypeScript 5

AI 输出的 PRD 中,有一段关键技术约束我之前没注意到:

微信公众号编辑器会过滤 <style> 标签和外部 CSS 文件,只保留元素的 style 属性。因此所有样式必须以内联方式写入 HTML 标签。此外,公众号不支持 <script>,不支持外部图片引用(需要转成 base64 或使用公众号图床)。

这条约束直接影响了后面的技术方案设计。


二、技术架构设计:AI 调研 + 方案选型

用 Tavily 补充实时信息

大模型的训练数据有截止日期,问它"markdown-it 最新版本是多少"可能得到过时答案。这时候用 Tavily 搜索 API 先抓取最新信息,再让 AI 基于这些信息做判断。

知识点:Tavily Tavily 是专为大模型和 AI Agent 打造的搜索 API。和普通搜索引擎不同,它的输出是结构化的网页检索内容,可以直接喂给大模型补充实时网络信息。在技术选型时,用 Tavily 先搜索"markdown-it vs marked 2026 对比"拿到的数据,再让 AI 分析,比直接问 AI 可靠得多。

让 AI 做技术选型

给 AI 的提示词:

我需要为 md-wx 选择一个 Markdown 解析库。请对比以下两个方案:

方案 A:markdown-it
方案 B:marked

对比维度:
1. 解析速度
2. 插件生态(是否支持自定义渲染规则,这关系到内联样式注入)
3. TypeScript 支持
4. 社区活跃度

我的核心需求是:解析 Markdown 后,能在渲染阶段给每个 HTML 标签注入内联 style 属性。

AI 给出的分析结论是 markdown-it 更合适——它的渲染规则是可配置的,可以通过 renderer.rules 自定义每种标签的输出,这正好满足"注入内联样式"的需求。而 marked 的自定义能力相对弱,改渲染输出需要 hack 源码。

架构设计产出

最终确认的架构如下:

md-wx/
├── src/
│   ├── parser/          # Markdown 解析层
│   │   └── index.ts     # 初始化 markdown-it,配置渲染规则
│   ├── themes/          # 主题样式层
│   │   ├── default.ts   # 默认主题
│   │   ├── dark.ts      # 暗色主题
│   │   └── elegant.ts   # 优雅主题
│   ├── renderer/        # 渲染层
│   │   └── index.ts     # 把 token 转成带内联样式的 HTML
│   ├── components/      # React 组件层
│   │   └── MdwxRenderer.tsx
│   └── index.ts         # 包入口
├── cli/
│   └── index.ts         # CLI 工具入口
├── AGENTS.md            # 项目规则文件
├── tasks.md             # 任务清单
└── package.json

数据流很清晰:

Markdown 字符串 → markdown-it 解析 → token 流 → renderer 注入内联样式 → HTML 字符串 → React 组件 / CLI 输出

三、原型设计:AI 生成可交互的 MVP

技术方案确定后,先让 AI 快速产出一个可运行的原型,验证"Markdown → 内联样式 HTML"这条路走得通。

给 AI 的提示词:

基于以下架构设计,生成一个可运行的原型代码。

要求:
1. 用 markdown-it 解析一段示例 Markdown
2. 自定义 renderer.rules,给每个标签注入内联 style
3. 暂时硬编码一套样式,不需要主题系统
4. 输出一个 HTML 文件,双击能在浏览器打开,样式不丢失

示例 Markdown:
# 标题测试
**加粗文本**
> 引用块
- 列表项1
- 列表项2

```js
console.log('hello')

AI 生成的核心代码片段:

```typescript
import MarkdownIt from 'markdown-it'
import { themeDefault } from './themes/default'

const md = new MarkdownIt()

// 自定义渲染规则:给每个标签注入内联样式
const originalRender = md.renderer.rules
const rules = ['heading_open', 'paragraph_open', 'blockquote_open', 'code_block', 'list_item_open']

rules.forEach(rule => {
  md.renderer.rules[rule] = (tokens, idx, options, env, self) => {
    const token = tokens[idx]
    // 根据 token 类型和主题配置,注入对应的 inline style
    const style = getStyleForToken(token, themeDefault)
    if (style) {
      token.attrSet('style', style)
    }
    return originalRender[rule]?.(tokens, idx, options, env, self) || self.renderToken(tokens, idx)
  }
})

export function render(markdown: string): string {
  return md.render(markdown)
}

主题配置文件 themes/default.ts

import type { Theme } from './types'

export const themeDefault: Theme = {
  h1: 'font-size: 24px; font-weight: bold; color: #333; margin: 20px 0 16px;',
  h2: 'font-size: 20px; font-weight: bold; color: #333; margin: 18px 0 14px;',
  p: 'font-size: 16px; line-height: 1.8; color: #555; margin: 10px 0;',
  blockquote: 'border-left: 4px solid #ddd; padding: 8px 12px; color: #888; background: #f9f9f9; margin: 12px 0;',
  code: 'background: #f6f8fa; padding: 2px 6px; border-radius: 3px; font-size: 14px; font-family: monospace;',
  pre: 'background: #1e1e1e; color: #d4d4d4; padding: 16px; border-radius: 6px; overflow-x: auto;',
  ul: 'padding-left: 24px; margin: 10px 0;',
  li: 'font-size: 16px; line-height: 1.8; color: #555; margin: 4px 0;',
  strong: 'font-weight: bold; color: #333;',
}

原型跑通后,确认技术路线没问题:markdown-it 的 renderer.rules 确实能逐个标签注入内联样式,输出结果直接粘贴到公众号编辑器,样式不丢失。


四、任务拆分:像管理者一样拆任务

原型验证通过后,进入正式开发。这一步最容易犯的错误是把整个项目丢给 AI 一次性完成。

为什么不能给 AI 分配大任务

原因一:上下文窗口限制。

知识点:上下文窗口(Context Window) 大模型的上下文窗口指它在一次对话中能"记住"的信息总量,单位是 token(大约 1 个汉字 ≈ 1-2 个 token)。现代模型窗口从早期的 4K 扩展到 128K 甚至更长,但在处理长任务时,模型对早期输入的关注度会下降。学术界把这种现象称为 "Lost in the Middle"——中间位置的信息最容易被遗忘。

具体表现:你要求用函数式组件,写到第三个文件时 AI 可能开始写 class 组件;你要求 TypeScript,写到 utils 时它可能开始用 JavaScript。早期约定的规则在长任务中逐渐被遗忘。

原因二:细节处理能力下降。

一次性处理的内容越多,AI 对每个细节的关注度越低。代码的命名一致性、错误处理完整性、边界条件覆盖度都会打折扣。

tasks.md:任务拆分的产出

把项目拆成 5 个独立任务,每个有明确的输入和输出,写进 tasks.md

# md-wx 任务清单

## Task 1: 项目初始化
- **状态**: 待办
- **输入**: 技术栈选型(React 18 + TypeScript 5 + markdown-it + Vite)
- **输出**: 可运行的空项目脚手架,包含 package.json、tsconfig、vite.config
- **验收**: `npm run dev` 能启动,`npm run build` 能打包

## Task 2: Markdown 解析模块
- **状态**: 待办
- **输入**: Markdown 字符串
- **输出**: markdown-it 实例,配置好 renderer.rules 钩子
- **验收**: 输入示例 Markdown,能输出标准 HTML(此时不带内联样式)
- **依赖**: Task 1

## Task 3: 主题样式系统
- **状态**: 待办
- **输入**: 主题配置对象(Theme 类型)
- **输出**: getStyleForToken() 函数,根据 token 类型返回内联样式字符串
- **验收**: 切换不同主题,输出的内联样式对应变化
- **依赖**: Task 2

## Task 4: React 渲染组件
- **状态**: 待办
- **输入**: Markdown 字符串 + 主题配置(可选)
- **输出**: <MdwxRenderer markdown="# hello" theme={customTheme} /> 组件
- **验收**: 组件渲染出的 HTML 带内联样式,可直接粘贴到公众号
- **依赖**: Task 2, Task 3

## Task 5: CLI 工具
- **状态**: 待办
- **输入**: Markdown 文件路径
- **输出**: 转换后的 HTML 文件
- **验收**: `npx md-wx input.md` 生成 output.html,样式完整
- **依赖**: Task 2, Task 3

知识点:tasks.md tasks.md 是任务清单文件,记录项目拆分后的所有任务及状态(待办/进行中/已完成)。它同时服务两个角色:给 AI 看——明确当前该做什么、做到什么程度算完成;给人看——追踪项目进度。类似于传统项目管理里的 Jira 看板,但更轻量,直接放在项目根目录。

拆分原则

每个任务遵循三个原则:

  • 独立性:完成一个就能看到可见结果,不需要等全部做完
  • 可验收:有明确的验收标准,不是"写完就行"
  • 小粒度:一个任务对应一个模块,不超过 200 行代码

拆完任务后,先审查一遍依赖链是否合理,再让 AI 逐个执行。每完成一个就检查,发现问题立刻修正,而不是等五个任务全做完再统一检查。


五、项目规则:用 AGENTS.md 管住 AI

任务拆好了,还有一个问题:怎么保证 AI 执行每个任务时不自由发挥,而是严格遵守项目约定?

答案是项目根目录放一个 AGENTS.md 文件,AI 在开始工作前会自动读取。

知识点:AGENTS.md AGENTS.md 是放在项目根目录的规则文件,AI 编程助手在开始工作前会自动读取。类似给新员工的"项目手册"——新人入职先读手册再干活。区别在于,新员工可能读完就忘,AI 每次对话都重新加载规则。在 Cursor 里叫 .cursorrules,在 Windsurf 里叫 .windsurfrules,作用相同。

md-wx 的 AGENTS.md

这是实际使用的项目规则文件:

# md-wx 项目规则

## 技术栈
- React 18 + TypeScript 5
- 构建工具: Vite
- Markdown 解析: markdown-it
- 不引入其他 Markdown 解析库,不引入 CSS-in-JS 方案
- 样式方案: 内联 style 属性(公众号编辑器限制,不能用外部 CSS)

## 代码风格
- 使用 2 空格缩进
- 字符串使用单引号
- 组件使用函数式组件 + Hooks,不使用 class 组件
- 命名: 组件用 PascalCase,函数用 camelCase,类型用 PascalCase
- 所有导出函数必须有 TypeScript 类型注解

## 任务执行边界
- 每次只执行 tasks.md 中标记为"待办"的下一个任务
- 不要修改当前任务范围之外的文件
- 完成任务后停下来,在 tasks.md 中更新状态,等待确认再继续
- 遇到不确定的技术决策,列出 2 个备选方案的优缺点,等待选择,不要自行决定

## 目录结构约定
- src/parser/     → Markdown 解析逻辑
- src/themes/     → 主题配置
- src/renderer/   → 渲染逻辑
- src/components/ → React 组件
- cli/            → CLI 工具
- 不要在 src 下创建新的顶级目录

## 测试要求
- 每个模块至少覆盖 3 个测试用例(正常输入、空输入、边界输入)
- 测试文件放在同目录下,命名为 *.test.ts

四个维度的规则解析

1. 任务执行边界 —— 控制 AI 何时开始、何时停止。写明"每次只做一个任务,不要越界改其他模块"。防止 AI 在修一个 bug 时顺手重构了半个项目。

2. 代码风格 —— 确保生成代码统一。缩进、引号、组件写法、命名规范全部明确。没有这条,AI 可能第一个文件用单引号,第二个文件用双引号,第三个文件又混着用。

3. 技术栈遵循 —— 锁死技术选型。"不引入其他 Markdown 解析库,不引入 CSS-in-JS 方案"这条规则,防止 AI 自作主张引入 marked 或者 styled-components。

4. 沟通方式 —— 规定遇到不确定决策时不要自己拍板。列出备选方案让你选,避免 AI 在不知情的情况下做了一个影响深远的架构决策。


实际执行效果

有了 tasks.md 和 AGENTS.md,我逐个执行任务,每个任务的提示词结构都是:

请执行 tasks.md 中的 Task N。

项目规则见 AGENTS.md,请严格遵守。
当前任务的验收标准是:[从 tasks.md 复制]

完成后请:
1. 更新 tasks.md 中该任务状态为"已完成"
2. 不要修改其他任务的文件
3. 等待我的确认后再执行下一个任务

以 Task 3(主题样式系统)为例,AI 生成的代码:

// src/themes/index.ts
import type { Theme } from './types'
import { themeDefault } from './default'
import { themeDark } from './dark'
import { themeElegant } from './elegant'

export const themes: Record<string, Theme> = {
  default: themeDefault,
  dark: themeDark,
  elegant: themeElegant,
}

export function getStyleForToken(
  token: { type: string; tag: string },
  theme: Theme
): string | null {
  // 根据 token 的 tag 名查主题配置
  const tag = token.tag
  if (tag && theme[tag as keyof Theme]) {
    return theme[tag as keyof Theme] as string
  }
  return null
}

// src/themes/types.ts
export interface Theme {
  h1?: string
  h2?: string
  h3?: string
  p?: string
  blockquote?: string
  code?: string
  pre?: string
  ul?: string
  ol?: string
  li?: string
  strong?: string
  em?: string
  [key: string]: string | undefined
}

AI 严格遵守了 AGENTS.md 的约定:用了 TypeScript 类型注解、函数式写法、单引号、2 空格缩进,没有越界修改 parser 或 renderer 目录的代码。完成后自动更新了 tasks.md 的状态,停下来等我确认。

五个任务全部执行完成后,项目结构完整,代码风格统一, npm run build 打包成功,发布到 NPM。


总结:五步工作流

需求文档(PRD)→ 技术架构设计 → 原型设计 → 任务拆分 → 项目规则 → 逐个执行

前三个阶段解决"做什么":需求文档定义功能和交互,技术架构定义技术方案,原型设计验证可行性。

后两个阶段解决"怎么管 AI":任务拆分确保 AI 一次只做一件小事,项目规则确保 AI 做每件事时都守规矩。

核心原则:把 AI 当成一个能力很强但需要明确指令的新员工来管理。 给它清晰的任务、明确的边界、一致的规则,它就能成为可靠的编码助手。反过来,模糊地描述需求然后期待魔法发生,大概率会收获一堆能跑但没法维护的代码。

这套流程不仅适用于 NPM 包开发,任何用 AI 编程助手做项目的场景都可以套用:先写需求,再定架构,验证原型,拆任务,立规矩,最后逐个执行。