
一、凌晨2点47分,工程师被电话惊醒的真相
凌晨2点47分,手机铃声划破深夜的寂静,正在熟睡的工程师猛地惊醒——生产环境崩了,数据 corruption 严重,用户投诉电话被打爆,没人知道问题出在哪,更不知道要花多久才能修复。
折腾到天亮才查清,祸根竟然是六周前一个周二的下午:为了赶进度,工程师用AI写了50行代码,仅用4秒就生成完毕,看着代码能运行、能编译,随手就部署上线。没人多想,没人测试,没人给AI明确的生产标准,直到这场深夜危机爆发。
这不是AI的错,而是无数工程师都在踩的坑:我们总以为AI写代码,拼的是Prompt技巧,却忘了一个扎心真相——Vibe Coding(氛围编码)的核心,10%是Prompt,90%是技能、规范和框架工程。
今天要讲的vibe-coding-harness,就是能帮工程师避开这类深夜危机的开源工具,它完全免费、开源可商用,是一套成熟的AI辅助开发BKM框架,能让AI生成的代码直接适配生产环境,零故障上线。
二、核心拆解:Vibe Coding的5个BKM步骤,附可直接运行代码
vibe-coding-harness的核心逻辑很简单:在给AI发Prompt之前,先做好90%的准备工作——定规范、搭框架、做测试,让AI“有章可循”,而不是让它凭空即兴发挥。这套框架包含5个核心BKM(最佳实践方法),每一步都有具体操作和代码,新手也能直接上手。
1. 先搞懂:为什么AI写的代码会出生产故障?
许多工程师用AI写代码,只丢一句“写一个任务管理器”“写一个URL短链接工具”,看似高效,实则藏着巨大隐患。就像下面这个50行的Python任务管理器,AI生成后能运行、能测试,但藏着7个生产级bug,足以导致系统崩溃。
import uuid
from datetime import datetime
tasks = {} # 全局状态,存在线程安全问题
def create_task(title):
id = str(uuid.uuid4())
tasks[id] = {"id": id, "title": title, "status": "todo", "created": datetime.now()}
return tasks[id] # 返回可变引用,调用者可篡改内部状态
def complete_task(id):
if id in tasks:
tasks[id]["status"] = "done"
# 任务不存在时静默返回None,排查困难
def set_status(id, status):
tasks[id]["status"] = status # 无id校验,易报KeyError;状态无限制,可输入任意字符串
def list_tasks():
return list(tasks.values()) # 返回所有任务,包括已归档的,不符合实际需求
这7个bug的危害的如下,每一个都可能引发生产危机:
- 严重级:无持久化,服务重启后所有任务丢失;无并发保护,高负载下数据错乱
- 高危级:无标题校验,空标题可正常创建;无状态限制,任意字符串可作为状态
- 中危级:返回可变引用,调用者可篡改内部状态;无异常捕获,易报KeyError导致服务崩溃
问题的根源,不是AI写得差,而是我们没给AI明确的“生产标准”——它不知道要做持久化、不知道要处理并发、不知道要校验输入,只能即兴发挥,写出“能运行但不能用”的代码。
2. 5个BKM实战步骤,让AI写的代码零故障上线
vibe-coding-harness的5个BKM,本质上就是帮我们给AI制定“生产规则”,从源头杜绝bug。每一步都有具体操作,附代码示例,直接套用即可。
BKM1:先定规范,再写Prompt(Product Planning First)
在打开任何AI工具之前,先写一份context_spec.md,明确“要做什么、怎么做、什么算成功”,这是避免AI即兴发挥的核心。这份规范必须包含5个核心部分,缺一不可:
# Context Spec: 任务管理器v1
## 我们要构建什么?
单用户任务管理器,支持SQLite持久化,实现任务的增删改查,数据必须能在服务重启后保留。
## 成功的标准是什么?
- 创建任务:能正常显示在列表中,且重启服务后不丢失
- 完成任务:完成后默认不显示在任务列表中
- 输入校验:空标题、超过500字符的标题,均抛出明确的ValueError
- 性能要求:100个任务时,列表查询耗时不超过50毫秒
## 系统约束
- Python 3.11+,仅使用标准库(不添加额外依赖)
- 使用SQLite(通过sqlite3),不使用任何ORM框架
- 所有公共方法必须有类型提示和文档字符串
## 不在范围内的功能(v2再实现)
- 用户认证
- 任务分页
- REST接口(单独作为另一个服务)
## 至少5个边缘场景
1. 空标题 → 抛出ValueError
2. 标题超过500字符 → 抛出ValueError
3. 查询不存在的任务ID → 返回None(不报错)
4. 重复标记已完成的任务 → 幂等操作(不报错,不改变状态)
5. 删除不存在的任务 → 静默成功(不报错)
记住:如果写不出这份规范,说明你还不知道自己要做什么,此时绝对不要给AI发Prompt——否则只会生成一堆无法用于生产的“demo代码”。
BKM2:上下文工程,让AI记住你的项目规则(Context Engineering)
AI的会话是无状态的,每次开启新会话,它都会“忘记”之前的规则,很容易出现前后矛盾的代码。上下文工程,就是帮AI“记住”项目的固定规则和当前会话的目标,分为两个核心文件:
第一个是全局上下文文件(CLAUDE.md,根据工具不同名称略有差异),相当于项目的“永久记忆”,存放AI无法从代码中推断的规则,列如架构决策、不变量、常用命令等,必须控制在200行以内(2026年ETH Zurich研究表明,AI最多能稳定遵循150-200条指令)。
# 任务管理器 — 项目上下文
## 技术栈
Python 3.11 · SQLite · pytest
## 核心不变量(绝对不能违反)
- 任务状态仅支持TODO、DONE、ARCHIVED三种(严格枚举)
- 所有数据库操作必须使用参数化SQL,禁止字符串拼接(防止SQL注入)
- 所有外部调用必须包裹异常处理,禁止裸except
## 当前迭代重点
正在开发:任务列表查询功能(按状态筛选)
禁止修改:/models/task.py(数据库迁移中,截至2026-05-15)
## 常用命令
- make test-unit:仅运行单元测试(快速,不依赖数据库)
- make migrate:执行数据库迁移(本地环境)
- make lint:代码检查(ruff + mypy)
## 已知技术债务(不扩展,计划Q3删除)
- /utils/legacy_mapper.py:旧数据映射工具,暂不修改
第二个是会话上下文包,相当于“当日任务简报”,明确当前会话的目标、角色、数据模型,避免AI偏离方向:
# 会话上下文 — 2026-05-01
## 角色
资深Python工程师,注重代码健壮性,不写裸异常,所有公共方法必须有文档字符串。
## 数据模型
Task: { id: uuid4, title: str(1-500), status: TODO|DONE|ARCHIVED,
created_at: UTC datetime, updated_at: UTC datetime }
## 已确定的决策(不重新讨论)
- 使用SQLite,不使用PostgreSQL(v1无需复杂基础设施)
- 不使用ORM,仅用标准库sqlite3
- 任务状态为严格枚举,不允许任意字符串
## 今日目标
仅实现list_tasks(status: Optional[TaskStatus])方法,不做其他功能。
## 涉及文件
- src/task_manager.py(仅修改list_tasks方法)
- tests/test_harness.py(仅扩展第4层测试)
BKM3:先写测试,再写代码(Harness Engineering)
许多工程师习惯“先写代码,再写测试”,但用AI写代码时,这种方式只会踩坑——AI会写出刚好能通过测试的代码,却忽略潜在隐患。正确的做法是:先写测试 harness(测试框架),再让AI写代码,让测试成为“放行门槛”。
测试 harness 分为4层,从基础到核心,层层递进,所有测试用例都来自context_spec.md,确保AI不会遗漏任何边缘场景。以下是完整的测试代码,可直接复制运行:
import pytest
from task_manager import TaskManager, TaskStatus
import time
class VibeSafeHarness:
def __init__(self, db_path=":memory:"):
self.tm = TaskManager(db_path)
def _expect_error(self, func, error_type):
"""断言执行func会抛出指定类型的异常"""
with pytest.raises(error_type):
func()
def _assert_none(self, value):
"""断言值为None"""
assert value is None
def _assert_idempotent(self, tm, status):
"""断言标记已完成任务是幂等操作"""
task_id = tm.create("测试幂等性").id
tm.complete(task_id)
first_status = tm.get(task_id).status
tm.complete(task_id)
second_status = tm.get(task_id).status
assert first_status == second_status == status
def _assert_fields(self, task, fields):
"""断言任务包含所有必填字段"""
for field in fields:
assert hasattr(task, field)
def _assert_type(self, value, expected_type):
"""断言值的类型符合预期"""
assert isinstance(value, expected_type)
def _assert_frozen(self, task):
"""断言任务是不可变的"""
with pytest.raises(AttributeError):
task.title = "修改测试"
def _assert_persists(self, tm):
"""断言任务在服务重启后仍存在"""
task_id = tm.create("持久化测试").id
# 模拟服务重启(重新初始化TaskManager)
new_tm = TaskManager(":memory:")
assert new_tm.get(task_id) is not None
def _assert_performance(self, tm, count=100, max_ms=50):
"""断言列表查询性能符合要求"""
# 创建count个测试任务
for i in range(count):
tm.create(f"测试任务{i}")
# 测试查询耗时
start = time.time()
tm.list_tasks()
end = time.time()
耗时 = (end - start) * 1000 # 转换为毫秒
assert 耗时 < max_ms
def run_all_tests(self):
"""运行所有4层测试"""
self.layer_1_smoke()
self.layer_2_edge_cases()
self.layer_3_contracts()
self.layer_4_acceptance()
print("✅ 所有测试通过,可进入下一步")
def layer_1_smoke(self):
"""第1层:冒烟测试(基础可用性)"""
self._assert_none(self._expect_error(lambda: __import__('task_manager'), ImportError))
self._assert_none(self._expect_error(lambda: TaskManager(":memory:"), Exception))
print("✓ 冒烟测试通过")
def layer_2_edge_cases(self):
"""第2层:边缘场景测试(来自context_spec.md)"""
self._expect_error(lambda: self.tm.create(""), ValueError)
self._expect_error(lambda: self.tm.create("x" * 501), ValueError)
self._assert_none(self.tm.get("nonexistent-id"))
self._assert_idempotent(self.tm, TaskStatus.DONE)
print("✓ 边缘场景测试通过")
def layer_3_contracts(self):
"""第3层:契约测试(数据模型、接口规范)"""
task = self.tm.create("契约测试")
self._assert_fields(task, ["id", "title", "status", "created_at", "updated_at"])
self._assert_type(task.status, TaskStatus)
self._assert_frozen(task)
print("✓ 契约测试通过")
def layer_4_acceptance(self):
"""第4层:验收测试(符合成功标准)"""
self._assert_persists(self.tm)
self._assert_performance(self.tm, count=100, max_ms=50)
print("✓ 验收测试通过")
# 运行测试
if __name__ == "__main__":
harness = VibeSafeHarness()
harness.run_all_tests()
这里有3个关键规则,必须严格遵守:① 测试由人类编写,不能让AI写(AI会写自己能通过的测试,失去校验意义);② 测试必须在代码之前写,用测试定义“正确的代码”;③ 测试失败必须阻塞上线,不能“先上线再修复”。
BKM4:结构化Prompt,拒绝自由发挥(Prompt Patterns)
自由Prompt(列如“写一个list_tasks方法”)是导致AI写坏代码的主要缘由之一。生产级开发,必须用结构化Prompt,明确AI的角色、上下文、任务和约束,让AI“只能按规则写代码”。
结构化Prompt固定格式为[ROLE][CONTEXT][TASK][CONSTRAINTS],示例如下,可直接替换内容套用:
[ROLE]
资深Python工程师,注重代码健壮性和可维护性。所有公共方法必须有类型提示和文档字符串,禁止使用裸except,数据库操作必须使用参数化SQL。
[CONTEXT]
数据模型:Task: { id: uuid4, title: str(1-500), status: TODO|DONE|ARCHIVED, created_at: UTC datetime, updated_at: UTC datetime }
数据库:SQLite(标准库sqlite3),启用WAL模式,无ORM。
核心约束:任务状态是严格枚举,不允许输入任意字符串;所有输入必须校验。
[TASK]
在TaskManager类中实现create(title: str) -> Task方法。
具体要求:1. 校验标题(非空、去空格、最大500字符);2. 生成uuid4作为任务ID;3. 设置created_at和updated_at为当前UTC时间;4. 将任务持久化到SQLite;5. 返回不可变的Task数据类。
[CONSTRAINTS]
1. 代码不超过60行;
2. 校验失败时,抛出ValueError并附带明确的错误信息;
3. 禁止使用字符串插值或format拼接SQL,必须用参数化查询;
4. 必须能通过test_harness.py的第1层和第2层测试,无需修改测试代码。
BKM5:双重校验,守住最后一道防线(LLM-as-Judge + Human-as-Judge)
即使代码通过了4层测试,也不能直接上线——测试只能检查“是否符合规范”,却无法检查语义漏洞(列如SQL注入隐患、敏感数据泄露、逻辑漏洞)。此时需要双重校验,守住最后一道防线。
第一步:LLM-as-Judge(AI自动审核),用另一个AI模型对代码进行语义审核,捕捉测试遗漏的问题。以下是完整的审核脚本,需安装anthropic SDK(pip install anthropic),配置API密钥后可直接运行:
import anthropic
import sys
def llm_judge(code):
client = anthropic.Anthropic(api_key="你的API密钥")
REVIEW_PROMPT = f"""
[ROLE] 资深Python代码审核专家,严格排查代码中的问题,标注行号,直言不讳,不遗漏任何隐患。
[TASK] 按照以下级别分类问题,仅返回JSON格式结果,不添加任何多余内容:
CRITICAL: 数据丢失、安全漏洞、崩溃风险、静默数据损坏
MAJOR: 逻辑错误、契约破坏、缺失必要校验
MINOR: 代码风格、可读性、性能优化提议
[CONSTRAINT] 返回格式必须严格遵循以下JSON结构,不可修改字段:
{{
"critical": [{{"line": 数字, "issue": "问题描述", "fix": "修复提议"}}],
"major": [{{"line": 数字, "issue": "问题描述", "fix": "修复提议"}}],
"minor": [{{"line": 数字, "issue": "问题描述", "fix": "修复提议"}}],
"verdict": "SHIP | SHIP WITH MINOR FIXES | DO NOT SHIP",
"summary": "一句话总结审核结果"
}}
[CODE] {code}
"""
response = client.messages.create(
model="claude-3-sonnet-20240229",
max_tokens=1024,
messages=[{"role": "user", "content": REVIEW_PROMPT}]
)
return response.content
# 读取代码文件并进行审核
if __name__ == "__main__":
if len(sys.argv) != 2:
print("用法:python llm_judge.py <代码文件路径>")
sys.exit(1)
with open(sys.argv[1], "r", encoding="utf-8") as f:
code = f.read()
result = llm_judge(code)
print("LLM审核结果:")
print(result)
第二步:Human-as-Judge(人类审核),这是最终防线。不同类型的代码,需要不同角色的人审核,避免遗漏关键隐患:
- 新数据模型/ schema变更:技术负责人、DBA审核
- 外部API集成:安全团队、平台团队审核
- 涉及权限、支付、健康数据的代码:产品+工程负责人审核
- 测试框架修改:资深工程师审核
3. 项目目录结构:让AI“看懂”你的项目架构
合理的目录结构,相当于给AI提供了“项目地图”,让它清楚每个文件的作用,避免出现代码放错位置、依赖混乱的问题。vibe-coding-harness的标准目录结构如下,可直接复用:
my-project/
│
├── CLAUDE.md ← 全局上下文(每次会话加载,<200行)
├── CLAUDE.local.md ← 个人配置,不提交到git
├── context_spec.md ← 当前迭代的功能规范
│
├── skills/ ← 可复用知识模块(团队共享)
│ ├── api-design.md ← API设计规范
│ ├── testing.md ← 测试最佳实践
│ ├── database.md ← 数据库操作规范
│ ├── error-handling.md ← 异常处理规范
│ └── security.md ← 安全规范
│
├── src/ ← 核心代码
│ ├── routes/ ← HTTP接口(仅处理请求)
│ ├── services/ ← 业务逻辑(仅处理业务规则)
│ ├── repositories/ ← 数据访问(仅操作数据库)
│ ├── models/ ← 数据模型
│ ├── schemas/ ← 数据校验 schema
│ └── shared/ ← 共享工具(权限、日志等)
│
├── tests/ ← 测试目录
│ ├── test_harness.py ← 4层测试框架(先于代码编写)
│ ├── unit/ ← 单元测试
│ ├── integration/ ← 集成测试
│ └── e2e/ ← 端到端测试
│
├── docs/ ← 文档目录
│ ├── architecture.md ← 架构文档
│ ├── technical-debt.md ← 技术债务记录(AI日志)
│ └── adr/ ← 架构决策记录
│
└── commands/ ← 常用命令脚本
├── setup.sh ← 项目初始化
├── test.sh ← 测试执行
└── deploy.sh ← 部署脚本
4. SKILL.md系统:让团队标准统一落地
许多团队用AI写代码,会出现“每个人的风格不一样、规则不一样”的问题,导致代码混乱、隐患丛生。SKILL.md系统,就是把团队的最佳实践(5个BKM)编码成结构化文件,让每个工程师、每个AI会话都能统一遵循。
SKILL.md的核心是“加载即生效”,在每个AI会话开始时,只需输入“Load SKILL.md”,AI就会继承团队的所有标准和决策,新工程师入职第一天也能快速上手。SKILL.md的标准格式如下:
# SKILL.md
name: vibe-coding-bkm
skills:
- skills/product_planning.md # BKM1:先定规范
- skills/context_engineering.md # BKM2:上下文工程
- skills/harness_engineering.md # BKM3:测试框架
- skills/prompt_patterns.md # BKM4:结构化Prompt
- skills/llm_judge.md # BKM5:双重校验
# 每个skill文件的示例(以harness_engineering.md为例)
# Skill: 测试框架工程
## 适用场景
任何涉及持久化、外部状态、业务逻辑的功能开发。
## 实施步骤
1. 编写context_spec.md后,再编写4层测试框架
2. 测试用例必须来自context_spec.md的边缘场景和成功标准
3. 给AI发Prompt时,附上测试框架,要求“写代码通过该测试”
4. 代码生成后,先运行测试,失败则重新生成
5. 测试通过后,再运行LLM-as-Judge审核
## 不可协商的约束
- 禁止AI编写测试框架
- 禁止“先写代码,再补测试”
- 测试失败必须阻塞上线,不允许临时绕过
## 反模式(禁止做的事)
❌ “这只是原型,不用写测试”——原型最终都会上线
❌ 信任“能运行”的代码,忽略测试
❌ 测试用例只覆盖正常场景,忽略边缘场景
## 模板地址
- context_spec.md模板:/docs/templates/context_spec.md
- 测试框架模板:/tests/test_harness.py
- 结构化Prompt模板:/docs/templates/structured_prompt.md
三、辩证分析:AI辅助开发,效率与安全如何平衡?
不可否认,AI写代码的效率是革命性的——以前需要几小时甚至几天的开发任务,目前AI几分钟就能完成,这让工程师能从重复的编码工作中解放出来,专注于更有价值的架构设计、需求分析。vibe-coding-harness的价值,从来不是否定AI的效率,而是让AI的效率“落地到生产”。
但许多工程师陷入了一个误区:把AI当成“万能工具”,以为只要Prompt写得好,就能直接生成生产级代码。实际上,AI的核心能力是“生成符合语法、看起来合理的代码”,而不是“生成符合生产标准、没有隐患的代码”——它没有项目的上下文,没有团队的规则,没有生产的经验,只能根据Prompt即兴发挥,这就注定了“自由Prompt+AI”的模式,必然会出现生产故障。
这里的核心矛盾,从来不是“AI好用还是不好用”,而是“我们如何用对AI”。vibe-coding-harness给出的答案,是用“规范+框架+测试”约束AI的即兴发挥,把工程师的经验、团队的标准,变成AI能理解、能遵循的规则,让AI从“生成demo代码”升级为“生成生产代码”。
值得思考的是:未来的工程师,核心竞争力不再是“写代码的速度”,而是“制定规则、搭建框架、把控质量的能力”。AI能帮我们写代码,但不能帮我们定规范、做测试、控风险——这才是工程师不可替代的价值,也是vibe-coding-harness真正想传递的理念。
四、现实意义:这套框架,能帮工程师解决哪些实际问题?
对于一线工程师来说,vibe-coding-harness不是“花里胡哨的工具”,而是能直接解决工作痛点、规避职业风险的“保命神器”,它的现实意义,体目前三个核心层面:
第一,规避生产故障,摆脱“深夜救火”的内耗。许多工程师由于AI写的代码出故障,被迫深夜加班、排查问题,不仅影响休憩,还可能承担职业风险。这套框架通过“先规范、再测试、后生成”的流程,从源头杜绝70%以上的生产级bug,让工程师不用再为AI的“即兴发挥”买单。
第二,提升开发效率,真正实现“AI辅助开发”。许多工程师用AI写代码,看似快,实则要花大量时间修改bug、调整格式、适配生产,反而更耗时。vibe-coding-harness让AI“一次生成、一次通过”,减少返工时间,真正把AI的效率转化为工作效率,让工程师能专注于核心业务。
第三,统一团队标准,降低协作成本。对于团队而言,每个人的编码风格、Prompt技巧都不一样,很容易出现代码混乱、规则不一的问题,后续维护成本极高。SKILL.md系统和标准目录结构,能让整个团队的AI开发流程统一,新成员快速上手,老成员减少沟通成本,提升团队整体效率。
更重大的是,这套框架完全开源免费,无需额外付费,支持所有主流AI编码工具(Cursor、Claude Code、Windsurf、GitHub Copilot、Google Antigravity),不管是个人开发者还是团队,都能直接复用,零成本上手。
五、互动话题:你用AI写代码时,踩过哪些坑?
AI写代码的时代,我们都在探索更高效、更安全的开发方式。或许你也曾由于AI写的代码出过错,深夜加班排查故障;或许你已经摸索出了自己的AI开发技巧,避开了许多坑;或许你对这套vibe-coding-harness框架有疑问,想知道如何适配自己的项目。
评论区留下你的经历和疑问:你用AI写代码时,最常踩的坑是什么?你觉得这套5个BKM框架,哪个最能解决你的痛点?你还有哪些AI高效开发的技巧,欢迎分享给身边的工程师,一起摆脱“深夜救火”,提升开发效率!