阅读视图

发现新文章,点击刷新页面。

FLutter的Cursor Skills 实战分享

聊聊 Cursor 的 Skills 功能,用 Flutter 项目举例

最近网上一直在炒 Agent Skills 功能, 年底不忙了摸索了一下 Cursor 的Agent Skills 这个功能。结果用了几天之后... 哇偶真香。

今天就来聊聊这玩意儿怎么用,顺便分享下我踩的坑。


这东西到底是干嘛的?

其实说白了,就是让你"调教" AI 的一种方式。

你有没有遇到过这种情况:让 AI 帮你写个 Flutter Widget,它写出来的代码风格跟你项目里的完全不一样?你说"加个 const",它下次又忘了。你说"用 GetX",它给你整个 Provider...

Skills 就是解决这个问题的。你写一个配置文件,告诉 AI "我们项目是这么干的",它就会照着来。


文件放哪儿?

两个地方可以放:

个人目录~/.cursor/skills/你的技能名/SKILL.md

  • 所有项目都能用
  • 比如你的代码风格偏好、常用的工具链配置

项目目录项目根目录/.cursor/skills/你的技能名/SKILL.md

  • 只有当前项目用
  • 可以提交 Git,团队共享

因为公司只有我一个移动端开发, 所以我一般是通用的放个人目录,项目特定的放项目里。


入门:写个最简单的

然后来个最简单的感受一下。

~/.cursor/skills/flutter-widget/ 下面建个 SKILL.md

---
name: flutter-widget
description:  Flutter Widget 的时候用这个。创建组件、写页面、搞 UI 的时候会自动触发。
---

# 我的 Widget 写法

别废话,直接上规矩:

1. 能用 StatelessWidget 就别用 StatefulWidget
2. 构造函数必须加 const
3. 参数必填的用 required

就这样写:

```dart
class UserCard extends StatelessWidget {
  const UserCard({
    super.key,
    required this.name,
  });

  final String name;

  @override
  Widget build(BuildContext context) {
    return Text(name);
  }
}

别给我整什么 Key? key 老写法,直接 super.key 完事。


保存。这就完事了???

现在你让 AI "帮我写个用户卡片组件",它就会按这个风格来。

---

## 进阶:description 很重要!

这里有个坑我踩过——description 写得太随意,AI 根本不触发你的技能。

**错误示范**:
```yaml
description: Flutter 开发

这太模糊了,AI 不知道什么时候该用。

正确示范

description: 写 Flutter Widget 的时候用。当用户说"创建组件""写页面""搞个 UI""弄个卡片"的时候触发。

关键是要写清楚什么时候用。AI 是根据这个 description 来判断要不要加载你的技能的。


中级玩法:加点料

用了一阵之后,我发现光写 Widget 规范不够。导入顺序、文件命名这些也得管,不然代码还是乱。

---
name: flutter-dev
description: Flutter 开发全套规范。写代码、建文件、搞页面的时候用。
---

# Flutter 开发规范(我的版本)

## 文件怎么命名

我习惯这样:
- Widget 文件:`user_card.dart`(小写下划线)
- 页面文件:`user_page.dart`  `user_view.dart`
- 服务类:`user_service.dart`

类名当然还是大驼峰 `UserCard`。

## import 顺序

这个我有强迫症,必须这么排:

```dart
// 1. dart 自带的
import 'dart:async';

// 2. flutter 
import 'package:flutter/material.dart';

// 3. 第三方包
import 'package:get/get.dart';

// 4. 自己项目的
import '../services/api.dart';

中间空一行分隔,看着舒服。

GetX Controller 怎么写

我们项目用 GetX,controller 这么写:

class UserController extends GetxController {
  final _loading = false.obs;
  bool get loading => _loading.value;

  final _user = Rxn<User>();
  User? get user => _user.value;

  Future<void> loadUser() async {
    _loading.value = true;
    try {
      _user.value = await api.getUser();
    } finally {
      _loading.value = false;
    }
  }
}

注意几点:

  • 私有变量用下划线
  • 对外暴露 getter
  • loading 状态别忘了 finally 里关掉

页面结构

class UserPage extends StatelessWidget {
  const UserPage({super.key});

  @override
  Widget build(BuildContext context) {
    return GetBuilder<UserController>(
      init: UserController(),
      builder: (c) => Scaffold(
        appBar: AppBar(title: const Text('用户')),
        body: Obx(() {
          if (c.loading) {
            return const Center(child: CircularProgressIndicator());
          }
          return _buildContent(c);
        }),
      ),
    );
  }

  Widget _buildContent(UserController c) {
    // 内容
  }
}

---

## 高级玩法:文件拆分

技能写多了之后,一个文件塞不下了。而且每次 AI 都要读整个文件,Token 哗哗的烧。

这时候就要拆分。

**目录结构**:

~/.cursor/skills/flutter-pro/
├── SKILL.md # 主文件,放最常用的
├── getx.md # GetX 详细用法
├── api.md # 网络请求规范
└── widgets.md # 组件规范


**SKILL.md 里这么写**:

```markdown
---
name: flutter-pro
description: Flutter 开发完整规范。写代码、搞状态管理、调接口的时候用。
---

# Flutter 开发

## 快速参考

### 状态管理
 GetX。详细的看 [getx.md](getx.md)

### 网络请求  
 Dio + 拦截器。详细的看 [api.md](api.md)

### 组件开发
const 构造、StatelessWidget 优先。详细的看 [widgets.md](widgets.md)

## 最常用的代码

(这里放几个最常用的模板)

这样 AI 平时只读主文件,需要详细信息的时候才去读子文件。省 Token。


省 Token 的一些心得

用了一段时间,总结了几个省钱技巧:

1. 别写废话

AI 比你想象的聪明。什么是 StatelessWidget、什么是 const,它都知道。你只需要告诉它"用 const"就行了,不用解释为什么。

别这样

## 关于 const 关键字

const 是 Dart 中的编译时常量关键字。使用 const 可以让 Flutter 在编译时就确定 Widget 的值,从而优化性能。当 Widget 的所有属性都是编译时常量时,应该使用 const...

这样就够了

## 规矩
- 构造函数加 const
- 能 const 的 Widget 都 const

2. 用模板代替解释

与其写一大段"表单验证应该怎么做",不如直接贴个模板:

TextFormField(
  validator: (v) => v!.isEmpty ? '必填' : null,
  decoration: const InputDecoration(labelText: '用户名'),
)

代码就是最好的文档。

3. 渐进式披露

主文件放最常用的 20%,剩下 80% 拆到子文件。AI 需要的时候自己会去读。


我现在的配置

分享一下我自己的配置,给你参考:

个人目录~/.cursor/skills/):

  • dart-style/ - Dart 代码风格(命名、注释这些)
  • git-msg/ - Git commit 信息格式

项目目录.cursor/skills/):

  • project-api/ - 项目的 API 接口规范
  • project-db/ - 本地数据库操作规范

这样分的好处是:换个项目,个人偏好还在,项目相关的配置跟着项目走。


一些坑

技能没生效?

检查一下:

  1. description 写得够不够具体
  2. 文件名是不是 SKILL.md(大小写敏感)
  3. yaml 格式有没有写错(冒号后面要有空格)

Skills 和 Rules 有啥区别?

Rules 是每次对话都会加载的,Skills 是按需加载的。

所以:

  • 简单的、每次都要用的偏好 → 放 Rules
  • 复杂的、特定场景才用的 → 放 Skills

最后

这功能我觉得挺值得花时间配置的。一次配置,后面省很多事。

刚开始别贪多,先搞一个最简单的,比如 Widget 规范。用顺了再慢慢加。

有问题欢迎交流。

❌