用 AGENTS.md 规则文件引导 AI 生成现代 Angular 代码:Angular 仓库官方 Persona 与最佳实践全解读
导读:本文基于 adev/src/context/AGENTS.md,系统解读 Angular 官方开源仓库为 AI 编码助手设计的一套规则文件——它定义了 "Persona + 黄金示例 + 最佳实践" 三层结构,目标是把大模型生成代码的行为约束到 Angular v20+ 的现代范式上:signals 状态管理、standalone 组件、内置控制流。读完本文,你将理解这套规则每条背后对应的框架机制(含仓库源码证据),并能把它接入 JetBrains、Copilot、Cursor 等 AI IDE,让 AI 从"能写出 Angular 代码"升级为"写出的就是符合官方规范的 Angular 代码"。
一、这份文件是什么:给 AI 助手的"官方编码人格"
1.1 文件定位
AGENTS.md 是当前 Angular 主仓库在 adev/src/context/ 目录下维护的一组 AI 上下文规则文件之一。它既不是一份给人类看的教程,也不是框架源码本身,而是一份写给 AI 编码助手/Agent 看的"角色设定 + 编码规范"指令。其核心思想是:大模型虽然能"生成能跑的代码",但对于像 Angular 这样快速演进的框架,经常生成的是基于旧范式(NgModule、*ngIf、@Input 装饰器)的过时代码。通过一套结构化的系统提示词,可以把 AI 的输出引导到框架当前推荐的写法上。
与 AGENTS.md 同目录的还有三份内容相近、面向不同工具生态的姐妹文件:
| 仓库内文件 | 面向的 AI 环境 | 使用方式 |
|---|---|---|
| adev/src/context/AGENTS.md | JetBrains IDE(如 IntelliJ/WebStorm 内置 AI) | 配置为 IDE 级 AGENTS.md |
| adev/src/context/guidelines.md | GitHub Copilot、VS Code、Windsurf | 配置为 .github/copilot-instructions.md / .instructions.md / guidelines.md |
| adev/src/context/angular-20.mdc | Cursor | 配置为 Cursor Rules(.cursor/rules 下的 .mdc 文件) |
| adev/src/context/GEMINI.md | Antigravity 等支持规则文件的工具 | 配置为 GEMINI.md |
这一生态定位在 adev/src/content/ai/develop-with-ai.md 中有完整说明。官方在文档中强调:这些文件会随 Angular 约定演进而定期更新,因此在使用时建议从源文件拉取最新版本,而不是复制一份永久保存。文件同样可以脱离 IDE 使用——作为"系统指令"注入任意 LLM 工具,或随提示词作为上下文一并提供。
1.2 适用边界与前提
需要说明的是,该文件面向的是当前 Angular 主线版本(Persona 明确定位为 "Angular v20+")的代码生成。仓库根目录 package.json 表明主线正处于 22.2.0-next.x 的开发阶段,因此文件中几乎所有规则都指向"signals 作为一等公民、standalone 成为默认"这一自 Angular 19 起逐步固化、并在 v20+ 强化的方向。若你正在维护基于旧版本(如 v15/v16 或仍使用 NgModules 的传统项目),应审慎对待其中"禁止/不要"类的激进规则。
二、Persona:先让 AI 进入"现代 Angular 开发者"角色
文件的第一部分是 Persona(角色设定),这也是它在结构上区别于普通 lint 规则的地方。原文设定可归纳为四句话:
- 用最新的框架特性构建应用——AI 默认应使用 v20+ 的 API 而不是历史 API;
- 使用 signals 做响应式状态管理,而不是可变的类属性加手工变更检测;
- 拥抱 standalone 组件,简化架构、减少模板胶水代码(NgModule 声明与导出);
- 使用新的内置控制流(
@if/@for/@switch)编写更直观的模板逻辑。
把角色设定放在规则之前是有意为之:对 LLM 而言,一个明确的"身份/立场锚点"比一长串禁令更能稳定地影响输出风格。Persona 之后才是一组"作为 v20+ 开发者"自然推导出的规范,这比"禁止使用 X"更不易被模型忽略。
三、黄金示例逐行解读:一个 signals 驱动的完整组件
Persona 部分附带了一个"用 signals 写 Angular 20 组件"的完整三文件示例(TS 逻辑 / CSS 样式 / HTML 模板),这是全文唯一一段可直接运行的代码,值得逐段拆解。
3.1 TypeScript:组件类与信号状态
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
@Component({
selector: '{{tag-name}}-root',
templateUrl: '{{tag-name}}.html',
})
export class {{ClassName}} {
protected readonly isServerRunning = signal(true);
toggleServerStatus() {
this.isServerRunning.update(isServerRunning => !isServerRunning);
}
}
值得注意的细节及其背后的含义:
{{tag-name}}与{{ClassName}}是模板占位符:这明确说明文件是给 AI 的"样例模板",而非可编译的真实组件。AI 在生成代码时应把selector的前缀与类名替换成用户项目实际需要的名称(如app-root/AppRoot)。这一点也从侧面印证:本文件的消费方是 LLM,规则文件使用占位符可防止生成器把示例类名照抄进用户项目。- 没有显式写
standalone: true:这与下文"不要在装饰器里写standalone: true"的规则严格自洽。Angular 19 起组件默认即为 standalone,无需(也建议不要)显式声明。仓库中面向 Cursor 的 angular-20.mdc 给出了 Good/Bad 对照:"Bad:standalone: true";"Good:省略(implied by default)"。 protected修饰符:模板只使用signal,并不需要向外部暴露字段;protected相比public缩小了 API 面,是组件封装性的体现。signal(true)与update():可变的状态被包装为响应式信号;切换布尔值不使用isServerRunning = !isServerRunning直接赋值,而是调用update(prev => !prev)——这正是 State Management 一节"不要用mutate,用update或set"的直接示范(下文 6.2 详述)。signal、update等 API 在 packages/core/src/render3/reactivity/computed.ts 及@angular/core的authoring目录(packages/core/src/authoring)中有完整实现与类型定义。- 模板中调用
isServerRunning():模板通过函数调用读取信号值,Angular 会在信号变更时精准触发相关视图刷新,这是"基于信号"的变更检测区别于"整棵树脏检查"的核心机制,也是"Performance is paramount"(性能至上)这一 Persona 设定的底层来源。
3.2 CSS:模板相对路径下的样式文件
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
button {
margin-top: 10px;
}
}
样式中嵌套的 button 规则依赖现代 CSS 原生嵌套(Angular CLI 默认构建链支持),配合 display: flex; flex-direction: column 实现纵向居中布局。示例刻意保持样式与组件模板解耦,呼应文件末尾"把逻辑放 TS、样式放 CSS、模板放 HTML"以及"外部模板/样式使用相对路径"的两条约定。
3.3 HTML:内置控制流 @if / @else
<section class="container">
@if (isServerRunning()) {
<span>Yes, the server is running</span>
} @else {
<span>No, the server is not running</span>
}
<button (click)="toggleServerStatus()">Toggle Server Status</button>
</section>
这段模板示范了三件事:
- 用
@if/@else取代*ngIf,模板条件分支以"块"语法直白呈现; - 条件表达式直接调用信号
isServerRunning(); - 事件绑定沿用
(click),与 signals 状态更新配合形成完整的"点击 →update翻转 → 视图自动刷新"闭环。
对 AI 生成器而言,这段三文件示例就是"最小可行范式":告诉它生成组件时应该输出哪些结构、把逻辑/样式/模板各放哪个文件。
四、TypeScript 与通用编码规范
文件把 TypeScript 基础规范放在 Angular 专项之前,说明它默认 AI 生成的代码首先要是质量合格且类型安全的 TypeScript:
- 开启严格类型检查(strict type checking):所有可能为
null/undefined的场景都应被显式处理,而不是依赖运行时报错兜底; - 类型明显时优先类型推断:
const name = 'Angular'优于const name: string = 'Angular',减少噪音(angular-20.mdc 中给出了对应的 Good/Bad 对照); - 避免
any,类型不确定时用unknown:unknown保留了类型安全,需要使用时再通过收窄(narrowing)转化为具体类型,而any会彻底关闭类型检查。
Angular 层面则要求:每个功能路由都做懒加载。这与仓库中真实文档站点 adev 的路由组织方式一致——该站点大量页面与内容通过 Angular 路由按需加载。从源码结构看,这条规则的核心收益是缩小首屏包体:路由级懒加载让编译器可以为每个 loadComponent/loadChildren 边界切分独立的异步 chunk。
五、框架级别优先规则:哪些 API 被"替换",为什么
文件在 "Angular Best Practices" 中给出了一组高度凝练的现代 API 对照,是全文信息密度最高的部分。逐条展开并附仓库源码佐证如下:
| 规则要点 | 含义 | 仓库证据 |
|---|---|---|
| 始终用 standalone 组件而非 NgModule | 新代码不再需要 declarations/exports/imports 模块桥接 |
同上,v19 起默认 standalone |
装饰器内不写 standalone: true |
已为默认,显式声明是冗余(即 v19+ 默认值) | angular-20.mdc 的 Good/Bad 示例 |
| 用 signals 管理状态 | 组件字段状态交给响应式信号 | packages/core/src/authoring 目录 |
| 功能路由懒加载 | 按路由切分异步加载 | adev 站点的路由/内容组织 |
不用 @HostBinding/@HostListener |
改用装饰器中的 host 对象声明宿主绑定与监听 |
@angular/core 组件/指令装饰器 host 元数据 |
静态图片用 NgOptimizedImage |
内置图片指令自动做响应式尺寸与懒加载优化 | @angular/common 的 NgOptimizedImage 指令 |
其中两点需展开解释:
-
@HostBinding/@HostListener→host对象。文件明确要求把宿主绑定放进@Component/@Directive的host元数据中,例如host: { class: 'card', '(click)': 'onClick()' }。从实现角度看,host元数据是声明式的、可被编译器静态分析的,而装饰器方案在装饰器已被标记为可选的当下属于旧范式。AI 生成器极易从旧代码库中学到@HostBinding,因此文件用强语气(Do NOT)来纠偏。 -
NgOptimizedImage的例外:文件补了一句"NgOptimizedImage对内联 base64 图片无效"——这条例外提示 AI,当遇到内联 base64 资源时应退回普通img或其他处理方式,而非机械套用指令。
六、组件、状态管理与可访问性规范
6.1 组件 API:信号化输入输出
- 用
input()信号取代@Input()装饰器:组件对外接口用函数式输入,支持类型、别名、必填/默认值等配置; - 用
output()函数取代@Output()装饰器:事件发射改为函数式声明; - 用
computed()处理派生状态:由其他信号计算而来、随源信号自动更新的只读信号。
这三组 API 在源码中均位于 packages/core/src/authoring 目录下(input/input.ts、output/output.ts、model/model.ts 等),是 @angular/core 信号化改造的基础设施。文件还要求"组件保持小而专一(single responsibility)"、"小组件优先内联模板"、"优先 Reactive Forms 而非模板驱动表单"。
6.2 状态管理三原则
- 本地组件状态用信号,派生状态用
computed(); - 状态转换保持纯函数与可预测,即更新逻辑只依赖入参、无副作用;
- 禁止对信号调用
mutate,改用update/set。
禁止 mutate 的理由值得 AI 特别注意:mutate 直接修改信号内部的数组/对象内容,会绕过 Angular 对引用的追踪语义,使部分变更检测与调试工具失效;而 set(整体替换)与 update(基于旧值变换出新值)保持"不可变更新"路径,配合示例中 update(isServerRunning => !isServerRunning) 的写法,才能让基于信号的计算与视图刷新完全可预测。
6.3 可访问性:硬性门槛
- 必须通过全部 AXE 检查:AXE 是业内主流无障碍自动化测试引擎,此项要求意味着生成代码需要语义化标签、恰当的角色与可访问名称;
- 必须满足 WCAG AA 最低标准:包含焦点管理(focus management)、颜色对比度(color contrast)与 ARIA 属性。
注意原文使用 MUST(必须)而非 should——这是生成代码的硬性验收线,AI 在生成表单、弹窗、导航等交互组件时必须自检键盘可操作性,而不能只追求视觉还原。
七、模板与样式约束
模板规范是 AI 生成"跑得起来"代码的常见事故区,文件给出了四条硬约束:
- 用内置控制流
@if/@for/@switch,替代*ngIf/*ngFor/*ngSwitch; - 不要假定
new Date()这类全局对象在模板里可用:模板求值环境是受限的,涉及时间/随机等逻辑应放在组件类中; - Observable 用
asyncpipe 处理;使用内置 pipe 时必须在组件中 import 对应 pipe(Angular 15+ 起,组件默认不再隐式获得CommonModule的全部 pipe); - 使用外部模板/样式时,路径相对组件 TS 文件写,保证可移植性。
样式层面,文件要求不使用 ngClass 与 ngStyle,改用 class 与 style 属性绑定。原因是普通属性绑定([class.active]="cond"、[style.color]="c")是语言原生语义、更利于编译器优化与信号响应式,而指令式 API 属于历史包袱。
八、服务规范:依赖注入的现代写法
最后一条规范针对服务层,是 AI 生成可测试代码的关键:
- 服务围绕单一职责设计;
- 单例服务用
providedIn: 'root':让服务在根注入器中注册,避免在模块/组件里手工提供; - 用
inject()函数替代构造函数注入:private readonly http = inject(HttpClient)写法更简洁,天然适配类字段初始化的时序,也便于在信号/工具函数等非组件上下文中使用依赖。
九、实战落地:把 AGENTS.md 接入你的 AI 工具链
9.1 作为 JetBrains IDE 规则文件
这是该文件在本仓库中的第一用途。根据 develop-with-ai.md 的说明,JetBrains 系 IDE(通过 Junie 等 AI 助手)可识别项目中的 AGENTS.md 作为 guidelines 来源。官方页面提供了该文件的下载入口,建议将最新版内容放入项目约定位置,使 IDE 内置 AI 在每次对话时自动加载 Persona 与规范。
9.2 作为通用 LLM 上下文/系统提示
脱离具体 IDE,你可以把 AGENTS.md 的内容:
- 直接粘贴为聊天工具/Agent 的系统指令(System Prompt);
- 或在每次生成 Angular 代码时作为附加上下文提供给模型。
由于文件同时包含"角色设定 → 代码示例 → 正向规则"三段式内容,对主流 LLM 的指令遵循效果通常优于零散口述的"请用最佳实践写"这类弱提示。
9.3 姊妹规则文件如何选择
若你的开发环境并非 JetBrains,可参照第一节的映射表选择适配文件:Copilot/VS Code 用 guidelines.md,Cursor 用 angular-20.mdc(.mdc 内含 globs 元数据,可限定其仅对 *.ts/*.html/*.scss/*.css 生效),Antigravity 用 GEMINI.md。三者在核心规则上与 AGENTS.md 一致(同源维护),差异主要体现为各工具支持的文件格式细节——例如 .mdc 增加了 frontmatter 与 glob 作用域,而 .md 规则文件则更便于整段粘贴。
9.4 使用时注意版本漂移
规则文件会随框架演进更新(官方在 AI 文档中明确提示 "will be updated on a regular basis")。结合本仓库主线版本处于 22.x 开发阶段可以推断:文件中的 Persona 定位 "v20+",在主线版本继续向前演进后,最准确的规则永远以仓库中最新内容为准。在 AI 生成的代码合并前,仍应通过测试、类型检查与无障碍扫描来兜底验证——规则文件提升的是"平均质量基线",而非取代工程化验收。
十、结语:把"规范"变成 AI 的"默认值"
AGENTS.md 这类规则文件的本质,是把 Angular 团队数年来沉淀的编码约定——从 signals 状态管理、standalone 默认、内置控制流,到 input()/output()/computed() 函数式 API、inject() 依赖注入与 WCAG AA 无障碍要求——编码为可被大模型稳定遵循的结构化指令。对开发者而言,它既是一份可直接接入 AI IDE 的现成配置,也是一份浓缩的"Angular v20+ 现代写法清单":当你困惑于该用 @Input 还是 input()、该写 *ngIf 还是 @if 时,这份文件的每一条规则都可以回溯到框架本身的演进方向与源码实现(如 packages/core/src/authoring 中的信号化 API)。让 AI 从一开始就站在这些默认值上,比事后逐条 review 再重构高效得多。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00