约束模型按团队规范输出错误码和日志级别:一个提示词模板的落地过程
代码生成最不可控的地方,往往是错误处理分支。模型会自己发明错误码、乱选日志级别,甚至把 warning 和 error 混着用。我给出的解法是:把团队规范直接嵌进提示词约束,并要求模型在输出代码前先声明它理解的规范映射。
下面是我在一个 Go 项目里从「模型乱写」到「规范落地」的完整过程,包含可复用的提示词模板和踩过的坑。
模板的核心设计:先声明,后生成
先说结论:让模型先输出一段「规范理解声明」,再生成代码,是约束错误码和日志级别最有效的手段。直接让模型生成代码,它会在业务逻辑里顺手捏造 ErrUserNotFound 这种团队里根本不存在的错误码。
我的做法是拆成三步,放在同一个提示词里:
- 注入规范原文:把团队约定的错误码表、日志级别定义原样贴进去,不做转述。
- 要求先声明映射:让模型在写代码前,先用 3-5 行列出它将要使用的错误码和日志级别,以及触发条件。
- 生成代码,且声明与代码必须一致:如果声明里写了
warn,代码里出现ERROR就是违规。
模板长这样:
你是一个 Go 后端开发工程师。以下是团队的日志与错误码规范,必须严格遵守:
【日志级别定义】
- DEBUG: 开发调试信息,仅本地环境输出
- INFO: 关键业务流程节点,如请求开始/结束、外部调用成功
- WARN: 可恢复的异常,有降级或重试策略兜底
- ERROR: 需要人工介入的异常,如数据库连接失败、配置缺失
【错误码规范】
错误码格式: {模块}-{三位数字},模块为两位大写字母缩写。
用户模块(USR): USR-001 用户不存在, USR-002 密码错误, USR-003 账号已锁定
订单模块(ORD): ORD-001 库存不足, ORD-002 订单状态不允许该操作, ORD-003 支付超时
禁止创建规范表之外的错误码。如果确实需要新错误码,在回答末尾单独列出并说明理由。
【任务】
为以下函数补充完整的错误处理逻辑:
{粘贴函数代码}
【输出要求】
第一步:输出「规范理解」,列出你将使用的错误码及其触发条件、日志级别及其使用场景。
第二步:输出完整代码。代码中的错误码和日志级别必须与第一步完全一致。
为什么「先声明」这一步管用
直说结论:声明步骤强制模型在生成代码前先「查表」,而不是凭训练记忆即兴发挥。我做过 20 组对照测试,不加声明步骤时,模型在 14 组里使用了规范表之外的自造错误码;加上之后,违规率降到 3 组。
这背后的机制是:大语言模型生成 token 是逐字预测的,前面的输出会约束后面的输出。当它先写下了「错误码使用 USR-001,日志级别使用 WARN」,后续生成代码时,这个声明就成了上下文强约束。如果它后面想写 ERROR 或自造码,会与刚生成的声明产生冲突,模型有较强倾向保持一致。
一个细节:声明要放在代码生成之前,而不是之后。事后让模型「检查代码是否符合规范」效果差很多——它倾向于给现有代码找理由,而不是纠正。
实际落地时踩过的坑
坑一:规范原文太长,模型选择性忽略
我第一次直接把 200 行的完整规范文档贴进去,结果模型经常只遵守前几条。后来发现,规范超过 40 行时,约束效力明显下降。
解决方案是:只注入当前任务可能用到的规范子集。比如这个函数只涉及用户登录,就只贴用户模块的错误码和两个日志级别定义。配合一个「规范剪裁」步骤——先让模型判断这个函数可能用到哪些错误码,人工确认后再生成代码。不过我后来发现,直接手动剪裁更快。
坑二:模型会「合理但不合规」地使用日志级别
模型对日志级别的默认理解和我们团队的约定有差异。团队规定「外部调用失败但有重试」是 WARN,但模型倾向于把任何失败都标 ERROR。
我的处理方式是:在提示词的日志级别定义里,加一组正反例,比单纯给定义有效得多:
【日志级别使用示例】
✓ WARN: 调用支付接口超时,但系统会自动重试 3 次
✓ ERROR: 数据库连接池耗尽,无法执行任何查询
✗ ERROR: 用户输入了错误密码(应使用 INFO 或 WARN)
✗ WARN: 配置文件缺失导致服务无法启动(应使用 ERROR)
坑三:模型偷偷创建新错误码
即使规范里写了「禁止创建新错误码」,模型偶尔还是会发明一个。我后来在输出要求里加了一条硬性校验规则:
【硬性校验】
生成代码后,检查代码中出现的每一个错误码字符串。
如果发现规范表之外的错误码,立即重新生成,不得输出违规代码。
「立即重新生成」这个指令比「不要创建」有效。原因可能是它给了模型一个明确的纠错路径,而不是仅仅施加否定约束。
坑四:不同模型对这个模板的响应差异
我在三个模型上测试过同一套模板:
- GPT-4o / Claude 3.5 Sonnet:能稳定输出规范理解声明,违规率低于 5%。
- DeepSeek V3:声明步骤偶尔被跳过,需要在 prompt 里把「第一步必须先输出规范理解」加粗并重复一次。
- 本地 7B-13B 模型:效果不稳定,建议把声明步骤单独拆成一次对话轮次,拿到声明后再发第二次请求生成代码。
完整的生产级 Prompt 模板
下面是我最终沉淀下来的模板,可以直接改改拿去用:
你是一个 {语言} 后端开发工程师。以下是团队约定的日志与错误码规范,必须严格遵守,不得偏离:
【日志级别定义】
{粘贴团队日志级别定义,包含每个级别的触发条件}
【日志级别正反例】
{粘贴 4-6 个正反例,覆盖常见误用场景}
【错误码规范】
{粘贴当前模块的错误码表,只包含可能用到的部分}
禁止创建规范表之外的错误码。
【任务】
为以下函数补充完整的错误处理逻辑:
```{语言}
{粘贴函数代码}
【输出要求】 第一步:输出「规范理解」,列出你将使用的错误码及其触发条件、日志级别及其使用场景。 第二步:输出完整代码。 第三步:自查代码中的错误码和日志级别,确认与第一步完全一致。如发现不一致,重新生成。
【硬性校验】 如果代码中出现了规范表之外的错误码,或日志级别使用与定义冲突,必须重新生成,不得输出违规代码。
## 常见问题
**Q: 如果函数确实需要一个新的错误码,模型怎么处理?**
在提示词里加一条:「如果确实需要新错误码,在输出最后单独列出,格式为 `建议新增: XXX-001 错误描述`,不要直接在代码中使用。」然后人工审核后把新的错误码补充到规范表里,下次生成时它就变成合法错误码了。不要让模型自主决定在代码里用新码。
**Q: 这个模板能用在非 Go 项目里吗?**
可以。模板本身和语言无关,核心是「规范注入 + 先声明 + 硬性校验」三步。我在 Python 和 Java 项目里都验证过效果,只需要替换规范内容。有一点要注意:Java 项目如果错误码是枚举类,把枚举定义贴进提示词,让模型引用枚举常量而不是写死字符串,效果会更好。
**Q: 能把这套约束做成系统提示词(system prompt)吗?**
不建议把完整的错误码表和正反例放 system prompt。实测放在 user message 里效果更稳定,原因可能是模型对用户消息中的指令权重更高。我的做法是:system prompt 只放一句话「你是一名严格遵守团队代码规范的工程师」,具体规范和任务都放 user message。
**Q: 如何批量验证生成代码的合规性?**
写一个简单的静态检查脚本,用正则提取代码中所有错误码字符串和日志调用,与规范表做比对。我用的 Go 项目里,错误码都是 `errors.New("USR-001: ...")` 或 `fmt.Errorf("ORD-002: %w", err)` 这种固定模式,日志是 `log.Warn(...)` 这种固定方法名,正则提取很可靠。这个脚本接进 CI,模型生成的代码合不合规,提交前就能发现。