很多教程告诉你"写好提示词就能让 AI 一次给出正确答案",但现实是:你不可能一开始就知道所有细节 。真正高效的 AI 协作,是在对话中逐步明确需求。这篇文章通过一个完整的 UnoCSS 配置案例,展示我和 TRAE SOLO 的真实交互过程------从模糊想法到完整方案,中间经历了哪些沟通和调整。
这是《AI 编程实战:TRAE SOLO 全栈开发指南》专栏的第四篇文章,带你学会如何与 AI 正确的沟通协作。
一、开篇:别被"完美提示词"骗了
1.1 一个常见的误区
网上很多 AI 教程会给你看这样的"完美提示词":
txt
帮我配置 UnoCSS,项目环境和需求如下:
【项目环境】UniApp + Vue3 + Vite,目标平台微信小程序
【功能需求】支持 attributify、@apply、图标、安全区适配
【已知问题】小程序 transform 类需要预设 CSS 变量
【输出要求】完整的 uno.config.ts 配置文件
然后告诉你:"看,一次就能得到完美答案!"
但问题是:
- 你一开始怎么知道需要"安全区适配"?
- 你怎么知道"transform 类需要预设 CSS 变量"?
- 这些都是踩坑之后才知道的
1.2 真实的 AI 协作是什么样的
真实的 AI 协作是一个渐进式对话的过程:
txt
第 1 轮:我有个模糊的需求
↓
AI:给出初步方案 + 执行计划
↓
第 2 轮:我发现问题 / 补充细节
↓
AI:调整方案
↓
第 3 轮:遇到报错 / 样式不生效
↓
AI:排查问题 + 修复
↓
最终:得到完整可用的方案
接下来,我会完整展示和 TRAE SOLO 配置 UnoCSS 的真实对话过程。
二、第一轮对话:从模糊需求开始
2.1 我的第一句话
刚开始,我对 UnoCSS 的了解很有限,只知道它是"原子化 CSS"。我的第一句话很简单:
txt
我:项目需要用 UnoCSS,帮我配置一下
2.2 TRAE SOLO 的响应:先给执行计划
TRAE SOLO 没有直接开始写代码,而是先给出了执行计划:
txt
TRAE SOLO:好的,我来帮你配置 UnoCSS。在开始之前,我需要先了解一些信息:
📋 执行计划:
1. 分析项目结构,确定技术栈
2. 选择合适的 UnoCSS 预设
3. 生成配置文件
4. 配置 Vite 插件
🤔 我有几个问题:
1. 这是什么类型的项目?(Vue/React/UniApp)
2. 目标运行平台是什么?(Web/小程序/App)
3. 有没有特别想要的功能?(图标/attributify 模式等)
请告诉我这些信息,或者我可以先分析你的项目结构来判断。
关键点 :TRAE SOLO 主动询问上下文,而不是瞎猜。
2.3 我补充信息
txt
我:UniApp + Vue3 项目,主要跑微信小程序,也要支持 H5。
功能的话,我也不太清楚,你看着配吧,常用的都加上。
2.4 TRAE SOLO 分析项目后给出方案
txt
TRAE SOLO:我分析了你的项目结构,发现:
- 框架:UniApp + Vue3 + Vite
- UI 库:已安装 wot-design-uni
- 目标:微信小程序 + H5
📋 更新执行计划:
1. 安装依赖
- unocss
- @uni-helper/unocss-preset-uni (UniApp 专用预设,必须)
- @iconify-json/carbon (图标库,可选)
2. 创建 uno.config.ts,包含:
- presetUni:小程序适配
- presetAttributify:支持属性化写法
- presetIcons:图标支持
- transformerDirectives:支持 @apply 指令
3. 修改 vite.config.ts,添加 UnoCSS 插件
4. 在 main.ts 中引入 uno.css
是否按这个计划执行?或者你想调整什么?
2.5 我确认执行
txt
我:可以,就按这个来
txt
TRAE SOLO:好的,开始执行...
✅ 正在安装依赖...
✅ 创建 uno.config.ts...
✅ 修改 vite.config.ts...
✅ 修改 main.ts...
配置完成!你可以这样使用:
<view class="flex items-center gap-4 p-4 bg-white rounded-xl">
<text class="text-lg font-bold">Hello UnoCSS</text>
</view>
运行 pnpm dev:mp-weixin 试试看效果。
三、第二轮对话:遇到问题,继续沟通
3.1 我发现样式不生效
运行项目后,我发现部分样式不生效:
txt
我:样式大部分生效了,但是 translate-x-2 这个类没效果,
元素没有移动
3.2 TRAE SOLO 排查问题
txt
TRAE SOLO:让我检查一下...
我查看了生成的 CSS,发现 translate-x-2 生成的代码是:
transform: translateX(var(--un-translate-x));
问题在于:小程序环境没有预设 --un-translate-x 这个 CSS 变量。
在浏览器中,UnoCSS 会通过 :root 选择器预设这些变量,
但小程序不支持 :root 选择器。
🔧 修复方案:
在 uno.config.ts 中添加 preflights,手动为小程序元素预设变量。
是否需要我帮你修复?
3.3 我让它修复
txt
我:帮我修复吧
txt
TRAE SOLO:好的,我来修改 uno.config.ts...
添加了以下配置:
preflights: [
{
layer: 'unocss-transform-fix',
getCSS: () => `
page, view, text, image {
--un-translate-x: 0;
--un-translate-y: 0;
--un-rotate: 0;
--un-scale-x: 1;
--un-scale-y: 1;
/* ... 其他变量 */
}
`,
},
],
✅ 已修复,重新运行项目试试。
3.4 我验证修复成功
txt
我:好了,translate 生效了
四、第三轮对话:追加新需求
4.1 我想添加安全区适配
开发过程中,我发现 iPhone 底部有安全区域遮挡内容:
txt
我:iPhone 底部有个横条会挡住内容,UnoCSS 能处理这个吗?
4.2 TRAE SOLO 给出方案
txt
TRAE SOLO:这是 iPhone 的安全区域问题。可以通过自定义 UnoCSS 规则来解决。
📋 方案:
添加以下自定义规则:
- pb-safe:底部安全区内边距
- pt-safe:顶部安全区内边距(刘海屏)
- p-safe:四边安全区内边距
使用方式:
<view class="pb-safe">底部内容会避开安全区</view>
是否需要我添加这些规则?
txt
我:加上吧
txt
TRAE SOLO:好的,在 uno.config.ts 的 rules 中添加:
rules: [
['pb-safe', { 'padding-bottom': 'env(safe-area-inset-bottom)' }],
['pt-safe', { 'padding-top': 'env(safe-area-inset-top)' }],
['p-safe', {
padding: 'env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)',
}],
],
✅ 已添加,现在可以使用 pb-safe 类了。
五、第四轮对话:优化开发体验
5.1 我觉得类名太长了
txt
我:flex items-center justify-between 每次都要写这么长,
有没有办法简化?
5.2 TRAE SOLO 介绍 shortcuts
txt
TRAE SOLO:可以用 UnoCSS 的 shortcuts 功能,把常用组合定义成短类名。
比如:
- center = flex justify-center items-center
- between = flex justify-between items-center
你想定义哪些快捷方式?或者我根据你的代码分析常用组合?
txt
我:你分析一下吧,看哪些用得多
5.3 TRAE SOLO 分析代码后给出建议
txt
TRAE SOLO:我扫描了你的代码,发现以下组合出现频率较高:
📊 使用频率分析:
1. flex items-center (出现 23 次)
2. flex items-center justify-between (出现 15 次)
3. flex items-center justify-center (出现 12 次)
4. flex flex-col (出现 8 次)
5. bg-white rounded-xl p-4 (出现 7 次)
🔧 建议添加的 shortcuts:
shortcuts: [
{ 'center': 'flex justify-center items-center' },
{ 'between': 'flex justify-between items-center' },
{ 'col': 'flex flex-col' },
{ 'card': 'bg-white rounded-xl p-4' },
],
是否按这个配置?或者你想调整?
txt
我:可以,就这样
六、第五轮对话:处理动态类名问题
6.1 我遇到动态类名不生效
txt
我:我有个地方根据状态切换颜色:
<text :class="`text-${status}-500`">状态</text>
status 可能是 red、green、blue,但样式不生效
6.2 TRAE SOLO 解释原因并给方案
txt
TRAE SOLO:这是 UnoCSS 的一个限制。
🔍 原因:
UnoCSS 在构建时静态扫描代码,`text-${status}-500` 这种
动态拼接的类名无法被识别,所以不会生成对应的 CSS。
🔧 解决方案有三种:
【方案一】对象语法(推荐)
<text :class="{
'text-red-500': status === 'red',
'text-green-500': status === 'green',
'text-blue-500': status === 'blue',
}">状态</text>
【方案二】safelist 预声明
在 uno.config.ts 中添加:
safelist: ['text-red-500', 'text-green-500', 'text-blue-500']
【方案三】CSS 变量
<text class="text-[var(--status-color)]"
:style="{ '--status-color': statusColor }">
状态
</text>
你的场景用哪种方案比较合适?
txt
我:颜色就这三种,用方案二吧,简单
txt
TRAE SOLO:好的,已添加到 safelist:
safelist: [
'text-red-500',
'text-green-500',
'text-blue-500',
'i-carbon-code', // 之前已有的图标
],
✅ 现在动态类名可以正常工作了。
七、最终配置:多轮对话的成果
经过 5 轮对话,最终的 uno.config.ts 是这样的:
typescript
// uno.config.ts
// 这个配置是通过多轮对话逐步完善的,不是一次性写出来的
import { presetUni } from '@uni-helper/unocss-preset-uni'
import {
defineConfig,
presetAttributify,
presetIcons,
transformerDirectives,
transformerVariantGroup,
} from 'unocss'
export default defineConfig({
// 【第 1 轮】基础预设
presets: [
presetUni({
attributify: {
prefixedOnly: true,
},
}),
presetIcons({
scale: 1.2,
warn: true,
extraProperties: {
'display': 'inline-block',
'vertical-align': 'middle',
},
}),
presetAttributify(),
],
// 【第 1 轮】转换器
transformers: [
transformerDirectives(),
transformerVariantGroup(),
],
// 【第 2 轮】修复小程序 transform 不生效
preflights: [
{
layer: 'unocss-transform-fix',
getCSS: () => `
page, view, text, image {
--un-translate-x: 0;
--un-translate-y: 0;
--un-translate-z: 0;
--un-rotate: 0;
--un-rotate-x: 0;
--un-rotate-y: 0;
--un-rotate-z: 0;
--un-skew-x: 0;
--un-skew-y: 0;
--un-scale-x: 1;
--un-scale-y: 1;
--un-scale-z: 1;
}
`,
},
],
// 【第 3 轮】安全区适配
rules: [
['p-safe', {
padding: 'env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)',
}],
['pt-safe', { 'padding-top': 'env(safe-area-inset-top)' }],
['pb-safe', { 'padding-bottom': 'env(safe-area-inset-bottom)' }],
],
// 【第 4 轮】常用快捷方式
shortcuts: [
{ 'center': 'flex justify-center items-center' },
{ 'between': 'flex justify-between items-center' },
{ 'col': 'flex flex-col' },
{ 'card': 'bg-white rounded-xl p-4' },
],
// 【第 5 轮】动态类名预声明
safelist: [
'text-red-500',
'text-green-500',
'text-blue-500',
'i-carbon-code',
],
// 【第 1 轮】主题配置
theme: {
colors: {
primary: 'var(--wot-color-theme, #0957DE)',
},
fontSize: {
'2xs': ['20rpx', '28rpx'],
'3xs': ['18rpx', '26rpx'],
},
},
})
八、组件开发:同样是对话式协作
8.1 开发回复卡片组件
配置完成后,我开始开发业务组件。同样是对话式协作:
txt
我:帮我写一个回复卡片组件,用来展示 AI 生成的回复。
左边是语气标签(比如"高情商"),中间是回复文字,右边是复制按钮。
txt
TRAE SOLO:好的,我来帮你开发这个组件。
📋 执行计划:
1. 创建 ReplyCard.vue 组件
2. 定义 Props:tone(语气)、text(文本)
3. 定义 Events:copy(复制)
4. 使用 UnoCSS 原子类实现样式
🤔 几个问题:
1. 语气标签的颜色是固定的还是根据内容变化?
2. 复制按钮是图标还是文字?
3. 有没有设计稿可以参考?
txt
我:标签颜色根据语气类型自动变,用哈希算法分配吧。
复制按钮用图标。设计稿没有,你自己设计一个好看的。
txt
TRAE SOLO:明白了,我来实现:
【设计方案】
- 卡片:白色背景、圆角、内边距
- 标签:小圆角、根据文字哈希分配 5 种颜色
- 文本:深灰色、支持多行
- 按钮:圆形点击区域、图标居中
开始生成代码...
8.2 TRAE SOLO 生成的组件
vue
<!-- components/ReplyCard.vue -->
<template>
<view class="flex items-center gap-2.5 bg-white rounded-xl p-4 pr-2">
<!-- 语气标签 -->
<view
v-show="!hideTag"
class="text-xs font-bold rounded-sm px-2 py-1 flex-shrink-0"
:style="{ backgroundColor: tagStyle.bg, color: tagStyle.text }"
>
{{ tone }}
</view>
<!-- 回复文本 -->
<view class="text-sm text-#1F2937 flex-1">
{{ text }}
</view>
<!-- 复制按钮 -->
<view
class="w-9 h-9 center cursor-pointer"
@click="$emit('copy', text)"
>
<image src="/static/images/home/copy.svg" mode="aspectFit" class="w-5 h-5" />
</view>
</view>
</template>
<script setup lang="ts">
import { computed } from 'vue';
interface Props {
tone: string;
text: string;
hideTag?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
hideTag: false,
});
defineEmits<{
copy: [text: string];
}>();
// 5 种预设颜色
const COLORS = [
{ bg: '#F3E8FF', text: '#8B5CF6' }, // 紫色
{ bg: '#E6FFFA', text: '#319795' }, // 青色
{ bg: '#FFF5E6', text: '#F56500' }, // 橙色
{ bg: '#FFE4E6', text: '#E11D48' }, // 粉色
{ bg: '#E0F2FE', text: '#0284C7' }, // 蓝色
];
// 根据语气文字哈希分配颜色
const tagStyle = computed(() => {
let hash = 0;
for (let i = 0; i < props.tone.length; i++) {
hash = (hash + props.tone.charCodeAt(i)) % COLORS.length;
}
return COLORS[hash];
});
</script>
8.3 我提出修改意见
txt
我:不错,但我想加一个功能:有时候不需要显示标签,能不能加个 prop 控制?
txt
TRAE SOLO:已经有了,就是 hideTag 这个 prop。
使用方式:
<ReplyCard tone="高情商" text="回复内容" :hide-tag="true" />
设置 hide-tag 为 true 就会隐藏标签。
txt
我:哦对,我没注意看。那再加个需求:复制成功后给个反馈
txt
TRAE SOLO:复制反馈建议在父组件处理,因为:
1. 卡片组件应该保持简单,只负责 UI
2. 复制逻辑和 toast 提示是业务逻辑,放父组件更合适
父组件这样用:
<ReplyCard
tone="高情商"
text="回复内容"
@copy="handleCopy"
/>
const handleCopy = async (text: string) => {
await copyText(text);
toast.success('已复制');
};
你觉得这样合理吗?还是希望把 toast 放在组件内部?
txt
我:你说得对,放父组件更好
九、核心经验:与 AI 协作的正确姿势
9.1 不要追求"一次完美"
| 错误做法 | 正确做法 |
|---|---|
| 花 30 分钟写一个"完美提示词" | 花 1 分钟说出需求,让 AI 提问 |
| 一次性想清楚所有细节 | 边做边发现问题,逐步完善 |
| 把 AI 当执行工具 | 把 AI 当协作伙伴,可以对话 |
9.2 让 AI 先给执行计划
每次提需求后,让 AI 先给出执行计划:
txt
我:[需求描述]
AI:📋 执行计划:
1. xxx
2. xxx
3. xxx
🤔 有几个问题:
1. xxx?
2. xxx?
确认后我开始执行。
好处:
- 确保 AI 理解正确
- 发现遗漏的需求
- 可以在执行前调整方向
9.3 遇到问题时提供上下文
❌ 错误方式:
txt
我:样式不生效
✅ 正确方式:
txt
我:translate-x-2 这个类在小程序里不生效,但在 H5 正常。
我看了生成的 CSS,是 transform: translateX(var(--un-translate-x))。
是不是变量没定义?
9.4 让 AI 解释它的方案
当 AI 给出方案时,追问原理:
txt
我:为什么要用 preflights?直接写 CSS 不行吗?
txt
TRAE SOLO:preflights 是 UnoCSS 的预设样式注入机制,和直接写 CSS 的区别:
1. preflights 会被注入到所有生成的 CSS 之前,确保优先级正确
2. 可以通过 layer 控制加载顺序
3. 统一管理,修改时只需要改配置文件
直接写 CSS 也可以,但需要确保加载顺序正确,否则可能被覆盖。
好处:理解原理后,下次遇到类似问题可以自己判断。
十、总结:对话式协作 > 完美提示词
10.1 本文的核心观点
- 不要追求"一次完美的提示词",真实的 AI 协作是多轮对话
- 让 AI 先给执行计划,确认后再执行
- 遇到问题时提供上下文,帮助 AI 定位问题
- 追问原理,理解 AI 的方案,下次才能举一反三
10.2 5 轮对话完成的工作
| 轮次 | 需求 | 成果 |
|---|---|---|
| 第 1 轮 | 基础配置 | presets、transformers、theme |
| 第 2 轮 | 修复 transform 问题 | preflights |
| 第 3 轮 | 安全区适配 | 自定义 rules |
| 第 4 轮 | 简化常用类名 | shortcuts |
| 第 5 轮 | 动态类名支持 | safelist |
10.3 下一篇预告
《【AI 编程实战】第 5 篇:Pinia 状态管理不会写?让 AI 手把手教你最佳实践》
下一篇继续展示对话式协作,教你:
- 如何让 AI 设计 Store 结构
- 状态持久化的对话过程
- 用户登录态管理的多轮沟通
与 AI 协作的关键不是"写出完美提示词",而是学会和 AI 对话。
如果这篇文章对你有帮助,请点赞、收藏!