IDE上下文工程实战:编写高质量.cursorrules与Prompt模板

封面信息图

在日常使用 Cursor、GitHub Copilot 或 Claude Dev 等 AI 辅助编程工具时,许多开发者会经历这样的落差:

  • 为什么 AI 给别人生成的代码结构严密、类型规范、直接可用?
  • 而 AI 给我生成的代码总是引入过时的库方法、用 any 糊弄类型、甚至完全无视我项目里的 Tailwind 配置?

差异的核心不在于模型本身,而在于你是否为 IDE 注入了高质量的项目级上下文规则(Context Engineering)。

在 Cursor 中,根目录下的 .cursorrules 文件就像是项目的“架构白皮书”。它会在每一次与 AI 对话和代码补全时自动作为隐式 System Prompt 生效。

本文分享一套在全栈 TypeScript + Next.js + Tailwind 项目中打磨出的 .cursorrules 实战配置模板与上下文工程心法。

上下文工程的四大败笔与反思

在编写 IDE 规则文件时,很多人容易踩入以下四大误区:

  1. 写满假大空的宏观废话(如“请写出优雅、高效、世界一流的代码”——对大模型毫无实际指导意义);
  2. 规则过于庞大导致上下文截断(塞入上万字的开发手册,挤占了模型处理真实业务代码的有效 Token 窗口);
  3. 未指明技术栈具体主版本号(导致 Next.js 14 的项目经常被生成 Next.js 12 的 pages/_app.tsx 旧语法);
  4. 缺乏具体的代码正反模式对比(Negative Examples)。

生产级 .cursorrules 核心模板拆解

一个精炼且高效的 .cursorrules 文件应控制在 150 行以内,聚焦在 技术栈定义、类型约束、状态与样式规范、反模式清单 四大板块:

# 项目核心上下文与工程规范

## 1. 技术栈基准 (Tech Stack Versions)
- Framework: Next.js 14+ (App Router, React 18, Server Components)
- Language: TypeScript 5.0+ (Strict mode enabled)
- Styling: Tailwind CSS 3.4+ (Mobile-first responsive design)
- State Management: TanStack Query v5 (Server State) + Zustand (Client Global)
- Database & ORM: SQLite (better-sqlite3) + Drizzle ORM
- Validation: Zod 3.x

## 2. 代码编写核心原则 (Coding Directives)
- **纯函数优先**:将业务计算逻辑抽离为无副作用的独立纯函数,并放置在 `src/lib/` 目录下。
- **显式类型声明**:严禁使用 `any` 或 `unknown` 作为快捷兜底;所有 API 请求入参、出参必须由 Zod 推导类型。
- **服务端组件与客户端组件边界**:
  - 默认所有页面和组件均为 Server Component。
  - 仅在需要 `useState`、`useEffect`、`useQuery` 或监听 DOM 事件时,在文件最顶部添加 `'use client'` 指令。

## 3. 样式与 UI 规范 (Tailwind Guidelines)
- 严禁在 JSX 中直接编写 `style={{ ... }}` 行内样式。
- 严禁在 JSX 中内嵌 raw `<svg>` 标签,统一从 `lucide-react` 中具名导入对应组件。
- 容器排版必须采用弹性响应式网格(`grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4`)。

## 4. 严禁反模式 (Strictly Forbidden Anti-Patterns)
- ❌ 绝对不要在客户端组件中直接导入后端数据库驱动(如 `drizzle`, `better-sqlite3`)。
- ❌ 绝对不要使用 `fetch` 的绝对内网 IP 地址,统一使用相对路径 `/api/...`。
- ❌ 绝对不要在 `useEffect` 内部直接发起数据获取,必须使用 `@tanstack/react-query` 的 `useQuery`。
- ❌ 绝对不要使用 `default export`,除 Next.js 页面入口外,一律使用具名导出(Named Export)。

实战效果对比:有无规则的惊人差异

当向 AI 发出同一个指令:“请帮我写一个获取用户历史周报列表的组件”时:

未配置 .cursorrules 时的生成结果(混乱过时):

// ❌ 传统混乱写法:使用了废弃语法,混入 useEffect,使用 any
import React, { useState, useEffect } from 'react';
import axios from 'axios';

export default function UserReports() {
  const [data, setData] = useState<any[]>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    axios.get('/api/reports').then(res => {
      setData(res.data);
      setLoading(false);
    });
  }, []);

  if (loading) return <div style={{ color: '#666' }}>Loading...</div>;

  return (
    <div style={{ width: '1000px', display: 'flex' }}>
      {data.map(item => (
        <div key={item.id}><h3>{item.title}</h3></div>
      ))}
    </div>
  );
}

配置了高质量 .cursorrules 后的生成结果(完全契合现代架构):

// ✅ 完美生成:严格遵循 'use client'、TanStack Query、Tailwind 和具名导出
'use client';

import React from 'react';
import { useQuery } from '@tanstack/react-query';
import { FileText, Loader2 } from 'lucide-react';

interface ReportItem {
  id: string;
  title: string;
  createdAt: string;
}

export const UserReportList: React.FC<{ userId: string }> = ({ userId }) => {
  const { data: reports, isLoading, isError } = useQuery<ReportItem[]>({
    queryKey: ['reports', userId],
    queryFn: async () => {
      const res = await fetch(`/api/reports?userId=${userId}`);
      if (!res.ok) throw new Error('拉取历史周报失败');
      return res.json();
    }
  });

  if (isLoading) {
    return (
      <div className="flex items-center justify-center p-8 text-slate-500">
        <Loader2 className="w-5 h-5 animate-spin mr-2" />
        <span>加载历史记录中...</span>
      </div>
    );
  }

  if (isError || !reports?.length) {
    return (
      <div className="text-center p-8 bg-slate-50 border border-dashed rounded-xl border-slate-200 text-slate-500 text-sm">
        暂无生成的历史周报记录
      </div>
    );
  }

  return (
    <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
      {reports.map((report) => (
        <div
          key={report.id}
          className="p-4 bg-white rounded-lg border border-slate-200 hover:border-blue-500 transition-colors shadow-sm flex items-start space-x-3"
        >
          <FileText className="w-5 h-5 text-blue-600 mt-0.5 flex-shrink-0" />
          <div className="flex-1 min-w-0">
            <h4 className="text-sm font-semibold text-slate-900 truncate">{report.title}</h4>
            <p className="text-xs text-slate-500 mt-1">{new Date(report.createdAt).toLocaleDateString()}</p>
          </div>
        </div>
      ))}
    </div>
  );
};

维护上下文工程的最佳实践

  1. 随项目重构动态演进:每当团队确立了新的架构约定或淘汰了某个旧库,第一时间同步更新 .cursorrules;
  2. 利用 @Docs 引入官方最新文档索引:对于频繁迭代的第三方框架,在 Cursor 对话中显式指定文档链接;
  3. 将规则纳入 Git 版本管理:确保团队内所有协作开发者与 AI 协同工具共享同一套严密的代码准则。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐