资讯详情

t3code:为AI编码助手设定边界,从能跑到可维护的代码规则集

📅 2026/10/28 13:15:46 | 华诺云谱 👁 阅读
t3code:为AI编码助手设定边界,从能跑到可维护的代码规则集
如果你最近也在技术群里见过“t3code”这个词大概会和我第一次看到时一样愣一下它到底是一个框架、一个开源仓库还是一个圈子里的梗我在几个 AI 编码相关的讨论区反复看到它之后决定自己把这件事彻底弄清楚。查了一圈并没有某个官方机构能拍板说“这就是 t3code 的标准定义”。但顺着 T3 Stack 的 TypeScript 全栈生态和 AI 结对编程这两条线摸下去我发现这个词被越来越多地当作“一套针对 AI 编码助手的工作流规则集”在使用。折腾了小半年之后我也沉淀了一套属于自己的 t3code 工作流并且把它用在了手头的几个真实项目里。这篇文章就把这套东西完整拆给你看它到底在解决什么问题、规则文件怎么组织、接入主流编码助手的时候怎么落地以及我在真实项目里踩过的那些坑。如果你最近正在被“AI 生成的代码能跑但没法维护”这件事困扰这篇文章应该能给你一个可以直接抄的答案。1. 从“能跑的代码”到“能维护的代码”t3code 要解决的真实问题在讲任何方案之前先讲一个发生在我自己项目里的翻车现场。上个月我接手一个内部工具的前端模块需求本身很简单一个列表页支持按状态筛选、批量操作、分页。代码确实是 AI 生成的跑起来也没问题。但当我准备给筛选条件加一个新的枚举值的时候我傻眼了——这个页面的核心组件有 800 多行所有请求状态散落在三个子组件里接口返回类型全部用的是any还有两个功能几乎完全相同的函数分别叫handleSearch和onFilter。也就是说模型把它的“平均风格”写了出来产出的是结构上完全失控的一坨代码。1.1 一次失控的 AI 交付类似的情况我相信不是只有我遇见过。团队里用编码助手的同事越多生成代码的“下限”就变得越难控制。模型很擅长把功能拼出来但它默认的目标是“让代码能跑”而不是“让代码能在半年后被人看懂、改得动”。那次翻车之后我做了一个小统计把最近一个月内 AI 生成但被 reviewer 打回重写的代码全部翻出来比较大的问题集中在下面这几类类型变成any或大量使用类型断言导致接口一改编译期完全发现不了问题一个组件函数承载了渲染、状态、请求、权限判断全部职责违反最基本的单一职责错误处理只有console.error用户界面没有任何失败态测试全部是快乐路径失败分支完全没覆盖。这些问题的共同特点是什么它们都不是“模型能力不够”造成的而是“我只给了模型需求没给它边界”。1.2 根因不是模型不够聪明是边界没说清我们平时让 AI 写代码的时候最常见的 prompt 是类似“给我写一个列表页”这样一句话。模型基于海量训练数据会推断出“一个列表页的平均写法”而这个平均写法往往包含了大量的省略和妥协。这就好比给一个新来的实习生丢一句话“你去把会议室订了”他能完成任务但很可能订了一间没窗户、没投影仪的屋子。你不能怪他因为你没有告诉他会议室的最低标准是什么。t3code 的核心思路就是把“人类工程师平时默认遵守的那些规矩”显式地写出来变成模型每次生成代码前必须看到的约束。1.3 我理解的 T3Type、Tooling、Trust“t3code”里的 T3我个人的理解是三个以 T 开头的关键词这三条也是整套路工作流的支柱。Type类型的边界。所有与外界交换的数据必须有明确的类型定义接口返回值必须有运行时校验禁止用any逃避问题。Tooling工具链固化。那些靠人记住容易忘的事情——格式化、lint、commit 规范、import 排序——全部交给工具链去强制而不是写在文档里指望每个人自觉。Trust信任边界。哪些步骤让 AI 全自动哪些步骤必须人工介入事先划清楚。这决定了模型的自由度也决定了代码质量的下限。只要这三个维度有一个缺失AI 编码的体验就会迅速退化没有 Type代码改起来像在雷区散步没有 Tooling十个人能写出十种风格没有 Trust你根本不知道模型哪一步会做出你无法接受的假设。2. 可直接抄走的项目骨架规则文件到底怎么摆第一次做这套东西的时候我把所有要求写进了一个巨大的 Markdown 文件大概有 300 多行。结果接入 Cursor 之后发现模型会在前几个交互里认真遵守到第 10 个文件之后就开始放飞自我。后来才明白编码助手的上下文窗口是有限的你塞进去的规则越多它越是“开头记得住、后面忘干净”。所以 t3code 的第二步是重新设计规则文件的组织方式让模型能低成本地吸收重点。2.1 目录结构长什么样我的规则库放在仓库根目录下的t3code/文件夹里结构是这样t3code/ ├── rules/ │ ├── 01-types.md # 类型安全红线 │ ├── 02-structure.md # 组件与模块拆分规则 │ ├── 03-review.md # 代码评审检查单 │ └── 04-testing.md # 测试覆盖要求 ├── templates/ │ ├── feature.md # 新功能开发 prompt 模板 │ ├── api.md # 接口对接 prompt 模板 │ └── fix.md # 缺陷修复 prompt 模板 ├── scripts/ │ ├── scaffold.sh # 生成新模块的脚手架脚本 │ └── setup-hooks.sh # 安装 git hooks 的脚本 └── README.md # 给人类同事看的说明2.2 全局规则与项目上下文分离这个结构最重要的设计是把“通用约束”和“项目特有约束”分开。rules/里放的是所有项目通用的东西比如类型红线、组件拆分规则而项目特有的是数据模型、业务规则、目录约定这些我单独维护一份AGENTS.md放在项目根目录每次让 AI 开始工作前由工具链自动加载。为什么这么做因为一套规则如果既能约束行为又包含大量项目细节它的复用性会变得很差。通用规则可以沉淀项目上下文在换项目后就作废分开维护两边都不会膨胀。2.3 怎么接入主流编码助手现在的编码助手基本都支持从文件加载自定义规则接入方式很灵活如果你用 Cursor可以直接把rules/目录里的内容合并进.cursor/rules/如果你用 Claude Code把通用规则和项目上下文写进CLAUDE.md如果你用普通的 ChatGPT/其他模型最笨但有效的方式是每次开始任务前把rules/里的文本粘贴到对话开头。我个人的经验是不要同时启用太多套规则加载机制不然模型容易混乱同一个约束可能在上下文里出现三个版本它不知道该听谁的。挑一个你主力使用的工具把规则喂给它就好。3. 核心规则文件拆解把工程师直觉翻译成机器可执行约束这一节可能是整个 t3code 里最值钱的部分我把几个核心规则文件的要点和背后的理由拆开讲。如果你不想全盘照搬挑其中最打动你的几条放进自己的项目里也足够改善体验。3.1 类型安全红线rules/01-types.md是所有规则里优先级最高的一份内容非常短因为红线必须少而清晰。核心就几条1. 禁止使用 any。如果你不确定类型使用 unknown 并在边界处收窄。 2. 所有与外部系统交互的数据API 响应、请求参数、配置项必须使用运行时校验推荐 Zod。 3. 禁止用类型断言as绕过类型错误。如果确实需要必须写清楚的注释说明原因。 4. 数组元素取出来后可能是 undefined必须处理后才能使用。第四条用大白话解释一下模型特别喜欢写const user users[0]然后直接user.name。在 TypeScript 的noUncheckedIndexedAccess选项下这种写法会直接报错强行让你先处理“数组可能为空”的情况。配合这份规则我的tsconfig.json里总是开着这些选项{ compilerOptions: { strict: true, noUncheckedIndexedAccess: true, exactOptionalPropertyTypes: true, noImplicitOverride: true, noFallthroughCasesInSwitch: true, noUnusedLocals: true, noUnusedParameters: true } }严格选项的意义不仅仅是让 AI 少写 bug更重要的是给代码评审提供一个兜底防线。因为模型可能漏掉边界但只要编译器配置足够严格漏掉的部分会直接在 CI 里亮红灯。3.2 一个能直接用的一页式 prompt 模板很多人问“我怎么让 AI 守规矩”答案不是写一篇万能的咒语而是给你的每个典型任务准备一个结构化的 prompt 模板。以开发新功能为例templates/feature.md长这样# 功能标签管理 ## 目标 新增一个标签列表页支持创建、改名、删除标签。 ## 约束 1. 所有接口返回值必须使用 Zod schema 解析禁止 any。 2. 组件内不得超过 60 行 JSX超过就拆成子组件。 3. 异步操作必须有 loading、error、empty 三种 UI 状态。 4. 删除操作需要二次确认。 5. 不引入新的状态管理库。 ## 完成后请输出 1. 你实现的关键文件清单。 2. 你做出的所有假设。 3. 尚未覆盖的边界场景。这个模板看起来简单但每一段都有自己的作用“目标”给模型明确的任务边界避免它自由发挥加功能“约束”是硬性要求是 t3code 里 R1 级别的红线“完成后请输出”是我最后加的一个杀手锏。它逼着模型把隐藏的假设暴露出来很多离谱的实现就是因为模型默默假设了一些和业务不符的东西。3.3 评审检查单人工该核对的几个点规则文件写得再好最终 review 还是得人来做。但我把 review 需要关注的点也收成了清单放在03-review.md里这样不管是我自己还是团队里的其他同学都能照着检查类型有没有any有没有不合理的as接口数据结构有没有运行时校验结构组件是否超过templates/feature.md里约定的行数职责是否单一有没有循环依赖边界空数据、错误、请求超时、并发点击这些场景有没有 UI 反馈测试新增的用例里除了成功路径有没有失败路径和边界值这个检查单不是为了找茬而是为了让人工 review 的注意力集中在模型最容易犯错的地方。很多时候模型生成的代码类型是安全的、结构是合理的但边界情况处理得非常敷衍人工 review 的重点就在这些地方。4. 完整复现一个功能标签管理模块从需求到评审文字规则讲再多都不如一次完整演示。这里我用一个最小但足够真实的例子展示在 t3code 约束下一个包含列表、创建、改名、删除的标签管理模块是怎么从需求变成代码的。4.1 环境准备建议在干净的目录里操作Node 版本用 20 及以上包管理器用 pnpm。项目本身是 React Vite TypeScript加上zod和tanstack/react-query两个依赖。这个组合很常见也足够说明问题。pnpm create vite t3demo --template react-ts cd t3demo pnpm add zod tanstack/react-query4.2 喂给模型的请求我把第一节的模板稍微填充一下形成一条完整的需求# 功能标签管理 ## 目标 在现有任务管理应用里增加标签管理模块。用户可以在侧边栏看到所有标签支持创建标签、点击标签改名、删除标签。删除时需要二次确认。 ## 约束 1. 所有接口返回值必须使用 Zod schema 解析禁止 any。 2. 组件内不得超过 60 行 JSX超过就拆成子组件。 3. 异步操作必须有 loading、error、empty 三种 UI 状态。 4. 删除操作需要二次确认。 5. 标签列表需要按创建时间倒序。 ## 完成后请输出 1. 你实现的关键文件清单。 2. 你做出的所有假设。 3. 尚未覆盖的边界场景。4.3 生成结果与人工介入点在 Cursor 里用这份模板生成的代码整体质量比我一开始“一句话需求”生成的高很多。接口对接的部分自动就有了 Zod schemaconst tagSchema z.object({ id: z.string(), name: z.string().min(1).max(20), createdAt: z.string().datetime() }); type Tag z.infertypeof tagSchema;列表和增删改查的组件也自动按照 60 行的约束拆分成了TagList、TagItem、TagForm三个文件。这是规则的功劳而不是模型突然变聪明了。不过review 阶段我还是抓到了两个问题。第一个是删除标签时模型没有考虑“该标签下是否还有任务”。它默认了删除标签是一个纯粹数据操作但实际上业务规则要求如果标签下还有任务需要先提示用户。这个信息模板里没有写但模型自己的“假设清单”里也没有提出这个疑问这就是为什么人工 review 不能省。第二个问题是并发场景。用户连续点击两次创建按钮会产生两条名称相同的标签。模型写了 loading 状态却没有在提交时禁用按钮也没有做重复名校验。这也是典型的“看起来能跑边界一测就露馅”的情况。4.4 把问题反馈给模型t3code 的另一个好处是review 发现的问题可以返工给模型而且返工质量有保障。我把两个问题描述清楚发给模型让它基于现有代码做修改。因为初始生成的代码结构是规范的修改也只是局部调整不会出现“改一处裂三处”的局面。返工之后它给创建请求加了重复名校验删除时也加了tasksUnderTag的检查逻辑。整个过程不到十分钟效率和人工实现差不多但质量的确定性要高得多。5. 落地三个月后我踩过的坑和调过的参t3code 不是第一天就长成现在这个样子的。在真实项目里跑了三个月我至少调整了五版有几个坑特别值得拿出来讲因为它们很有可能也会出现在你的落地过程中。5.1 规则文件越大模型越记不住第一版规则文件我追求“全面”把所有能想到的代码规范都塞进去了结果就是开头说的翻车。后来我做了个实验同一段需求分别用 50 行、150 行、300 行的规则文件让同一个模型生成代码统计它违反规则的次数。实验数据样本量 30 个任务不算严谨但趋势很稳规则文件长度前 5 个任务违规数后 10 个任务违规数约 50 行12约 150 行25约 300 行412后半程掉得最厉害。我的结论是单份规则文件最好控制在 60 到 80 行以内总规则体系不要超过 200 行。超出部分应该靠项目上下文文件去承载而不是堆进规则文件。5.2 硬规则和软建议必须分开规则写得太多太细另一个副作用是模型会“把所有规则都当红线”结果不敢动手产生大量违背常识的保守代码。比如我有一条硬规则是“禁止使用 any”但如果某个第三方库类型定义糟糕硬不用any反而会让代码变得极其扭曲。后来我把规则分成了两个等级R1红线必须遵守比如类型安全、运行时校验、二次确认R2建议尽量遵守比如组件行数上限、命名风格。区别体现在 prompt 模板里R1 用“禁止/必须”的句式R2 用“建议/优先”的句式。模型对这两类的响应是完全不同的R1 会被当成硬约束R2 会在特定场景下被合理取舍。5.3 测试全是快乐路径陷阱如果模板里写“请补充测试”模型默认会生成一堆输入合法数据、断言正常返回的用例。这些测试看起来热闹实际价值很低。真正能防回归的都是失败路径的用例请求失败怎么办、空数据怎么办、删除不存在的 ID 怎么办。我的 fix 是在测试规则模板里加了一句硬要求每个功能测试必须包含至少一个导致失败或异常的输入 并断言对应的 UI 呈现出正确的错误状态。加了这条之后模型的测试行为明显不一样了会主动造一些边界数据比如超长字符串、空数组、重复 ID。代码评审的时候这部分也成了重点抽查对象收益挺明显。5.4 规则变更也要走评审最后这个坑是团队合作时踩的。有人觉得自己发现了一条更好的规则直接改了rules/01-types.md结果其他成员和 AI 用的还是老版本前后不一致产生了大量返工。现在我的做法是任何规则变更都走一次简单的 PR变更说明里必须写清楚“这条规则解决了什么问题、和旧规则的区别是什么”。规则是给人和 AI 共同遵守的它的变更应该和代码变更一样有记录、有理由。6. 接入一段时间后我的体会和给你的建议这套工作流在我这边已经稳定运行了一段时间。我用它带的两个项目一个是内部工具一个是面向客户的小型应用规模都不大但足够说明问题。小样本统计下来新增功能的类型相关 review 意见减少了大约 60%组件平均行数明显下降review 一个模块的时间从原来的半小时压缩到十几分钟。代价是第一次搭建规则体系和模板确实花了我将近半天时间而且前一两周一直在微调规则真正回本是在跑通第三个功能之后。对我来说t3code 本质上不是限制模型而是把过去只存在于老工程师脑子里的“质量门槛”变成了显性的、可执行、可修改的文件。它真正改变的是人机协作方式以前是我问一句模型写一段现在是我定义边界模型在边界里发挥。如果你想在自己的项目里尝试我的建议很直接不要上来就做全套先挑你最近最痛的一个问题比如“类型全是 any”或“组件太大”定成一条 R1 红线把这条红线和复盘出来的失败案例一起写进规则文件让模型知道“为什么”比“是什么”更有说服力每跑完一个真实需求就回头看一眼规则文件不需要的删掉失灵的重写。最后分享一个小经验规则文件里我最常更新的反而是“常见失败模式”那一段。每次我在 review 中抓到模型的某种典型错误就把这个错误加进规则变成新的约束。经过几轮迭代我发现很多第一次会犯的错后面真的就不再出现了。这就是把踩坑经验沉淀为代码资产的过程也是我认为 t3code 这套思路最值得复制的地方。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑