Skip to content

Rule 规则系统

Rule 是让 AI 遵守你的编码规范的方式。不同于传统在 README 里写"请遵循某某规范"——那种做法 AI 记不住。Rule 是系统级约束,Qoder 会根据规则类型自动或按需注入到提示中。

但好消息是:你不用关心规则文件怎么写,告诉 AI 你想要什么就行。


使用篇

1. 创建 Rule

在 Growth 项目中创建一条规则,只需要在对话里说一句:

创建一个 rule,内容为:所有接口方法必须有 XML 文档注释

AI 会自动在 .qoder/rules/ 下生成对应的 .md 文件。你不需要打开文件管理器,不需要写 YAML,不需要知道目录结构。

想加什么约束,直接告诉 AI:

  • "创建 rule:函数不超过 30 行"
  • "创建 rule:变量命名用 camelCase"
  • "创建 rule:每次 commit 前先跑测试"

AI 会帮你写好 frontmatter(name、description、trigger 类型),放到正确的位置。

2. 修改和删除 Rule

修改也是一句话的事:

把 rule coding-conventions 里的函数行数限制改成 50 行

删除同理:

删除 rule release-checklist,用不上了

不需要自己去找文件在哪,不需要手动编辑 YAML。Rule 的维护完全可以通过对话完成。

3. Rule 文件是什么样的

虽然你不用手动写,但了解它的结构有助于理解"AI 到底在读什么"。一个 Rule 文件由三部分组成:

markdown
---
trigger: always_on            # 生效方式:always_on / model_decision / manual / file_glob
---
## 规则内容

- 项目符号、编号列表、代码示例
- AI 会严格按这些规则执行

元数据只有一个关键字段:

字段作用
trigger规则何时生效(always_on / model_decision / manual / file_glob)
globstrigger=file_glob 时,匹配的文件路径模式
descriptiontrigger=model_decision 时,告诉 AI 什么场景触发

实际项目中最常见的三种类型:

类型适用场景例子
always_on全局必须遵守的规范编码规范、技术栈
model_decision特定场景触发创建模块、生成测试
manual偶尔使用的检查清单架构审查

Rule 四种触发机制


实践篇

4. Rule 示例:code-check

以下是在 Growth Components 项目中积累的规则汇总,命名为 code-check。你可以把它作为一个模版,根据自己项目的实际情况调整:

markdown
---
trigger: manual
---

# 代码检查清单

## Early Return(提前返回)

- 先排除错误,再做正事
- 函数开头通过卫语句排除边缘情况后,主逻辑保持在最外层
- 消除深层 if-else 嵌套

## 异常处理

- 顶层类捕获异常,记录日志,返回失败结果
- 内部业务类不包 try-catch,异常透明上抛
- 必需字段校验失败直接抛出 `InvalidOperationException`

## Logger 规范

- 统一使用 Serilog + LogFormatHelper + LoggerConfig
- 每个类定义 `LoggerName`
- EnterScope / ExitScope 成对出现
- Debug 记中间过程,Info 记关键路径,Warn 记边缘情况,Error 记严重错误

## 访问修饰符

- Interfaces/ 下为 public
- Implementations/ 下为 internal
- 业务代码为 internal
- Module 入口类为 public

## 接口命名

- 接口名:`I` + 功能名 + `Service`
- 实现类名:功能名 + `ServiceImpl`
- 方法名使用动词开头(Get/Find/Create/Update/Delete)
- 异步方法以 Async 结尾,返回 `Task``Task<T>`

## 文档注释

- 所有接口方法必须有 XML 文档注释
- 说明功能、参数和返回值

5. Growth 中的 Rule 体系

在 Growth 项目中,我们建了 14 条规则,按功能分四类:

全局规范(always_on)——每次对话自动加载:

规则作用
tech-stack项目技术栈(.NET 8、Serilog、EF Core 等)
project-overview项目架构概览(21 个项目、模块分层)
coding-conventions编码规范(Early Return、Logger、Try-Catch)

场景触发(model_decision)——AI 判断场景后自动加载:

规则触发描述
ai-agent修改 Agent 逻辑
workflow-node创建/修改工作流节点
repository-pattern添加数据库持久化
new-module-template创建新模块
test-execution运行或编写测试
document-generation生成需求文档

文件匹配(file_glob)——编辑特定文件时自动加载:

规则匹配模式
interface-rules**/Interfaces/*.cs
module-entry-files**/*Module.cs**/LoggerConfig.cs**/LogFormatHelper.cs
node-executor-files**/Enhanced*Executor.cs

手动调用(manual)——需要时通过 @rule 触发:

规则作用
module-architecture-check模块架构检查清单
debug-common-pitfalls常见调试陷阱

这 14 条规则构成了 Growth 项目的"编码宪法"——AI 在做任何修改时,都被这层约束框在团队规范内。

6. 唯一最佳实践

能用场景触发就别用全局加载。

  • always_on 的规则每次对话都会加载,占用上下文
  • 只有所有对话都必须遵守的规范(如技术栈、编码基础)才用 always_on
  • 特定场景的规范用 model_decisionfile_glob,让 AI 按需加载

实践中,3 条 always_on + 若干场景规则的组合效果最好。多了反而浪费上下文窗口。


知识篇

7. Rule 的运行原理

Rule 的本质是条件注入。Qoder 在每次调用模型时,按规则类型决定是否把规则内容注入到系统提示中:

  • always_on:每次调用都注入
  • model_decision:AI 评估描述后决定
  • file_glob:当前文件匹配 glob 模式时注入
  • manual:用户通过 @rule 手动引用时注入

所有激活的规则合计不超过 100,000 字符,超出部分被截断。

8. Rule vs Skill

RuleSkill
本质约束(不能怎么做)指令(帮我去做什么)
生效自动或半自动用户通过 / 主动触发
场景编码规范、命名约定代码审查、文档生成
数量10~20 条可以很多

简单理解:Rule 是贴在墙上的团队规范,Skill 是操作手册。Rule 让 AI "不做错事",Skill 让 AI "高效做事"。

9. 从框架角度理解 Rule

如果你熟悉 Microsoft AI Agent 框架(Microsoft.Agents.AI + Microsoft.Extensions.AI),你会发现 Qoder 的 Rule 系统本质上就是该框架 AIContextProvider 机制的自然语言版本。两者的底层逻辑完全一致——在大模型执行前,按条件向上下文中注入约束信息

AIContextProvider:框架中的 Rule

在微软框架中,AIContextProvider 是一个抽象接口,定义了 Agent 执行前/后两个生命周期阶段:

csharp
public interface AIContextProvider
{
    // Agent 执行前调用——相当于 Qoder 的规则注入
    Task InvokingAsync(AgentRequest request, IAgentContext context, ...);

    // Agent 执行后调用——相当于规则执行后的清理
    Task InvokedAsync(AgentRequest request, AgentResponse response, ...);
}

每个 Provider 在 InvokingAsync 中判断条件,决定是否向 context.Instructions 中注入内容。这正是 Qoder Rule 做的事情——只不过 Qoder 通过自然语言 + LLM 判断,而微软框架通过 C# 代码 + 类型系统来实现。

映射关系

Qoder RuleMicrosoft AIContextProvider
规则文件 .mdProvider 类(CustomXxxProvider
trigger: always_onProvider 注册时不加条件,始终执行
trigger: model_decisionInvokingAsync 内写判断逻辑
trigger: file_globInvokingAsync 内检查文件名模式
trigger: manualToolApprovalAgent 审批模式
注入到系统提示context.Instructions.Add(...)
Tick 优先级控制规则类型间的加载优先级

条件注入的两种实现

微软框架(代码实现):

csharp
public class FileBasedProvider : AIContextProvider
{
    public async Task InvokingAsync(AgentRequest request, IAgentContext context, ...)
    {
        // 文件名条件注入
        if (request.Text.Contains("Interfaces/"))
        {
            context.Instructions.Add(new AgentMessage
            {
                Role = ChatRole.System,
                Content = "接口命名:I + 功能名 + Service"
            });
        }
    }
}

Qoder(自然语言实现):

markdown
trigger: file_glob
globs: "**/Interfaces/*.cs"
---
接口命名:I + 功能名 + Service
实现类命名:功能名 + ServiceImpl

两种方式做的是同一件事:当编辑接口文件时,把接口命名规范注入到对话中。区别只是一个用 if 判断文件名,一个用 globs 匹配文件名。

Tick 机制与规则优先级

微软框架通过 Tick 值控制 Provider 的执行顺序:

csharp
provider.Use<AgentInstructionsProvider>(tick: 10);   // 先执行
provider.Use<ChatHistoryMemoryProvider>(tick: 20);   // 后执行
provider.Use<AgentModeProvider>(tick: 30);            // 更后执行

Qoder 虽然没有显式的 Tick,但规则加载顺序隐含了优先级:always_on 最先注入(始终存在),然后是 model_decision(AI 判断后追加),接着是 file_glob(文件匹配后追加)。这个顺序是合理的——全局规范先确立框架,场景规范再补充细节。

理解了这个映射,你就能理解

  1. 为什么 recommends 用 always_on 而不是 model_decision——因为框架中每个 Provider 都会执行 InvokingAsync,全部执行完才调模型;同理,always_on 规则每次对话都会加载。
  2. 为什么 file_globalways_on 更节省上下文——因为框架中 Provider 按需注册,不是每个请求都触发所有 Provider。
  3. 为什么规则多了会影响响应速度——因为 Provider 多了 InvokingAsync 的执行时间也会变长。
  4. 为什么说两种框架设计哲学一致——微软框架用代码写条件注入,Qoder 用自然语言写条件注入,都是"不到执行的那一刻,绝不加载全部能力"。

这种映射关系也解释了为什么 Skill 章节引入了微软框架的装饰器管道——Qoder 的整个上下文工程体系(Rule + Skill + Agent)和 Microsoft AI Agent 框架的 Provider + Decorator + Agent 架构是一脉相承的。自然语言是新的类型系统,LLM 是新的运行时。


写在最后

Rule 是 Qoder 框架中最"隐形"的基础设施。它不像 Skill 那样需要主动触发,也不像 Agent 那样有完整的角色定义。但正是这些简单的约束文件,在每一次对话中静默地工作,确保 AI 的输出始终符合团队标准。

最好的标准,是让 AI 不需要被提醒。你把规范写进 Rule 文件,就再也不用在每次对话中反复交代"请注意我们的编码规范"。