返回笔记首页

第 12 集:从 Vibe Coding 到 Agentic Engineering

主题配置

一、两个概念的本质区别

Vibe Coding

工作模式:你有想法 → 你描述 → AI 执行一次 → 你看结果 → 你再描述 → AI 再执行

关键特征:

  • 你是发起者,每次任务由你触发
  • AI 执行单个任务
  • 完成一步,等你给下一步指令

Agentic Engineering

工作模式:你给出高层目标 → Agent 系统自动分解任务 → 多个 Agent 协作执行 → 遇到需要人决策的节点才来问你

关键特征:

  • 你是监督者,不需要每步都参与
  • 多个 AI Agent 协作完成复杂任务
  • Agent 有自我纠错能力(测试失败会自动重试)
  • 只有真正需要人工判断的地方才暂停

一个具体的例子

Vibe Coding 方式实现"用户积分系统"

plain
你:帮我设计积分表结构
AI:[给出表结构]
你:好,帮我生成 Prisma Schema
AI:[生成 Schema]
你:帮我生成 PointsService
AI:[生成 Service]
你:帮我生成测试
AI:[生成测试]
你:测试失败了,帮我修复
AI:[修复]
... 共 10 轮对话
Agentic Engineering 方式
plain
你:实现用户积分系统,字段参考 PRD.md,需要完整的 CRUD、单元测试、Swagger 文档
Agent 系统:[自动完成以下步骤]
  1. 需求分析 Agent 读取 PRD.md,生成任务清单
  2. 代码生成 Agent 生成 Schema、Service、Controller
  3. 测试 Agent 生成并运行测试
  4. 测试失败 → 代码修复 Agent 自动修复 → 重新运行测试
  5. 全绿后,Review Agent 做安全扫描
  6. 所有步骤完成,向你汇报
你:[去干别的事,回来看结果]

二、Agent 的三要素

2.1 Goal(目标)

Goal 决定了 Agent 的职责边界和成功标准。

写清楚的 Goal

plain
需求分析 Agent 的 Goal:
- 输入:原始需求文档(自然语言)
- 职责:识别模糊需求、拆解成具体任务、输出任务清单
- 成功标准:输出的任务清单包含所有功能点,每条任务边界清晰,可以直接交给代码生成 Agent 执行
- 失败处理:如果需求里有无法确定的部分,标记出来,等待人工确认
写模糊的 Goal(效果差)
plain
需求分析 Agent 的 Goal:分析需求

Goal 写得越清晰,Agent 的行为越可预测。

2.2 Tools(工具)

Tools 决定了 Agent 能做什么,是 Agent 和外部世界交互的接口。

工具本质上就是 Function Calling 里的 function,Agent 决定什么时候调用、传什么参数。

常见工具类型

typescript
// 文件操作工具
readFile(path: string): string
writeFile(path: string, content: string): void
listFiles(directory: string): string[]

// 代码执行工具
executeCommand(command: string): { stdout: string, stderr: string, exitCode: number }
runTests(pattern?: string): TestResult

// 搜索工具
searchCode(query: string, directory: string): SearchResult[]
searchDocs(query: string): string

// 外部 API 工具
callApi(url: string, method: string, body?: object): ApiResponse
sendNotification(message: string, channel: string): void
工具设计原则
  • 每个工具职责单一,不要一个工具做太多事
  • 输入输出类型要明确,方便 Agent 解析
  • 有副作用的工具(文件写入、API 调用)要在描述里说清楚

2.3 Memory(记忆)

短期记忆(Session Memory)

就是当前对话的上下文。Agent 在一次任务里能"记住"之前做了什么、发现了什么。

局限:Token 窗口有限,超长任务里早期的上下文会被截断。

长期记忆(Long-term Memory)

跨任务的持久化知识,通常用向量数据库(RAG)实现:

plain
把以下内容存入向量数据库:
- 项目规范文档(.cursorrules、code-style.md)
- 历史上出现过的 Bug 和解决方案
- 架构设计决策文档

Agent 需要时通过语义搜索检索相关内容

三、Multi-Agent 协作的四种模式

模式一:串行流水线(Sequential Pipeline)

plain
Agent A → Agent B → Agent C → Agent D

每个 Agent 处理完把结果传给下一个,形成流水线。

适用场景:步骤有明确的先后依赖关系

例子:开发流水线

plain
需求分析 Agent
    ↓ 输出:任务清单
代码生成 Agent
    ↓ 输出:代码文件
测试生成 Agent
    ↓ 输出:测试文件
安全扫描 Agent
    ↓ 输出:扫描报告

优点:简单、可预测、好调试

缺点:前面的 Agent 出问题,后面全卡住;总耗时是所有 Agent 耗时之和

模式二:并行执行(Parallel Execution)

plain
┌──→ Agent B ──┐
Agent A ─┤              ├─→ Agent D(合并结果)
         └──→ Agent C ──┘

多个 Agent 同时执行,最后合并结果。

适用场景:步骤之间没有依赖关系,可以同时做

例子:代码审查

plain
生成的代码
    ├──→ 安全扫描 Agent(扫描漏洞)
    ├──→ 性能检查 Agent(扫描 N+1 查询)
    └──→ 规范检查 Agent(检查代码风格)
          ↓
    汇总报告 Agent(合并三份报告)

优点:总耗时是最慢那个 Agent 的耗时,不是所有 Agent 的总和

模式三:带条件的流转(Conditional Routing)

plain
Agent A → [判断结果] ──成功──→ Agent B
                    └──失败──→ 修复 Agent → 重试 Agent A(最多 N 次)

Agent 根据上一步的结果决定下一步走哪条路。

适用场景:有质量标准,不达标要重试或走备用方案

例子:代码生成 + 自动修复

typescript
async function codeGenerationWithRetry(task: string, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const code = await codeGenerationAgent(task);
    const testResult = await testRunnerAgent(code);

    if (testResult.passed) {
      return code;  // 测试通过,返回代码
    }

    // 测试失败,把错误信息传给修复 Agent,重试
    task = `修复以下代码的问题:\n${testResult.errors}\n原始代码:\n${code}`;
  }

  throw new Error(`代码生成失败,已重试 ${maxRetries} 次`);
}

模式四:人工干预节点(Human-in-the-Loop)

plain
Agent A → [需要确认] → 暂停,等待人工输入 → Agent B

在关键决策点暂停,等待人工确认后继续。

什么时候必须有人工干预节点

操作类型 是否需要人工确认
数据库 Schema 变更(migration) ✅ 必须
生产环境部署 ✅ 必须
删除数据操作 ✅ 必须
发送邮件/通知 ✅ 建议
调用第三方付费 API ✅ 建议
读取文件 ❌ 不需要
生成代码 ❌ 不需要
运行测试 ❌ 不需要

四、工程化的关键考量

4.1 幂等性(Idempotency)

Agent 执行的操作应该是幂等的——重复执行多次和执行一次的结果相同。

重要性:Agent 系统里有网络失败、超时重试,如果操作不是幂等的,重试会产生副作用。

typescript
// 非幂等(危险):多次调用会创建多条记录
async createOrder(dto: CreateOrderDto) {
  return await this.prisma.order.create({ data: dto });
}

// 幂等(安全):先查是否存在,存在则返回已有记录
async createOrderIdempotent(dto: CreateOrderDto, idempotencyKey: string) {
  const existing = await this.prisma.order.findUnique({
    where: { idempotencyKey },
  });
  if (existing) return existing;

  return await this.prisma.order.create({
    data: { ...dto, idempotencyKey },
  });
}

4.2 错误处理和重试策略

typescript
async function withRetry<T>(
  fn: () => Promise<T>,
  maxRetries = 3,
  delayMs = 1000,
): Promise<T> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;

      // 指数退避:第 1 次等 1 秒,第 2 次等 2 秒,第 3 次等 4 秒
      await new Promise(resolve => setTimeout(resolve, delayMs * Math.pow(2, attempt)));
    }
  }
  throw new Error('Max retries exceeded');
}

4.3 可观测性(Observability)

Agent 系统需要能看到执行过程,不能是黑盒。

最小化的日志记录:

typescript
async function orchestrator(requirement: string) {
  this.logger.log(`[Orchestrator] 开始处理需求:${requirement}`);

  const tasks = await requirementAgent(requirement);
  this.logger.log(`[需求 Agent] 拆解出 ${tasks.length} 个任务`);

  for (const task of tasks) {
    this.logger.log(`[代码 Agent] 开始处理任务:${task.description}`);
    const code = await codeGenerationAgent(task);
    this.logger.log(`[代码 Agent] 任务完成,生成文件:${code.files.join(', ')}`);
  }
}

五、一个简单的多 Agent 协作示例

以下代码展示 Multi-Agent 协作的基本结构,使用 TypeScript 伪代码(不依赖具体的 LangChain 或 LangGraph):

typescript
// src/agent-demo/pipeline.ts

interface Task {
  id: string;
  description: string;
  type: 'schema' | 'service' | 'controller' | 'test';
}

interface AgentResult {
  success: boolean;
  output: string;
  nextAction?: 'continue' | 'retry' | 'human_review';
  error?: string;
}

// Agent 1:需求分析
async function requirementAgent(rawRequirement: string): Promise<Task[]> {
  // 调用 LLM,把需求拆解成任务列表
  const prompt = `
    把以下需求拆解成具体的开发任务,每个任务类型是以下之一:schema、service、controller、test
    需求:${rawRequirement}
    输出格式:JSON 数组,每项包含 id、description、type
  `;
  // const result = await llm.invoke(prompt);
  // return JSON.parse(result);

  // 模拟输出
  return [
    { id: '1', description: '创建 Points Prisma Schema', type: 'schema' },
    { id: '2', description: '实现 PointsService,包含 addPoints 和 deductPoints', type: 'service' },
    { id: '3', description: '实现 PointsController,包含 Swagger 注解', type: 'controller' },
    { id: '4', description: '为 PointsService 生成单元测试', type: 'test' },
  ];
}

// Agent 2:代码生成
async function codeGenerationAgent(task: Task): Promise<AgentResult> {
  // 根据任务类型,生成对应的代码
  const prompt = `
    生成以下任务的 NestJS 代码:
    ${task.description}
    技术约束:Prisma ORM、TypeScript strict、返回 ResponseDto
  `;
  // const code = await llm.invoke(prompt);
  return { success: true, output: '// 生成的代码...', nextAction: 'continue' };
}

// Agent 3:测试执行和验证
async function testAgent(code: string): Promise<AgentResult> {
  // 实际运行测试命令
  // const result = await exec('npm test -- --passWithNoTests');
  // if (result.exitCode !== 0) {
  //   return { success: false, output: result.stderr, nextAction: 'retry', error: result.stderr };
  // }
  return { success: true, output: '所有测试通过', nextAction: 'continue' };
}

// Orchestrator:协调所有 Agent
async function orchestrator(requirement: string) {
  console.log('Step 1: 需求分析...');
  const tasks = await requirementAgent(requirement);

  console.log(`Step 2: 代码生成(共 ${tasks.length} 个任务)...`);
  const generatedCode: string[] = [];

  for (const task of tasks) {
    let result: AgentResult;
    let retries = 0;
    const MAX_RETRIES = 3;

    do {
      result = await codeGenerationAgent(task);

      if (!result.success && retries < MAX_RETRIES) {
        console.log(`任务 ${task.id} 失败,第 ${retries + 1} 次重试...`);
        retries++;
      }
    } while (!result.success && retries < MAX_RETRIES);

    if (!result.success) {
      console.error(`任务 ${task.id} 重试 ${MAX_RETRIES} 次后仍失败,需要人工介入`);
      // 触发人工干预节点
      break;
    }

    generatedCode.push(result.output);
  }

  console.log('Step 3: 运行测试验证...');
  const testResult = await testAgent(generatedCode.join('\n'));

  if (!testResult.success) {
    console.log('测试失败,代码需要修复...');
    // 触发修复循环
  }

  console.log('完成!所有步骤执行成功。');
  return { tasks, generatedCode, testResult };
}

// 使用示例
orchestrator('实现用户积分系统,支持积分发放、扣减、查询余额和查询历史');

六、演示操作步骤

准备工作

Step 1:在项目里创建 Agent 演示目录

bash
mkdir -p src/agent-pipeline
touch src/agent-pipeline/pipeline.ts

Step 2:把上面第五章的代码写入 src/agent-pipeline/pipeline.ts

架构图演示

用 Excalidraw(excalidraw.com)画出以下两张图并截图:

图一:Vibe Coding vs Agentic Engineering 对比

plain
左侧:Vibe Coding
人 → [描述] → AI → [结果] → 人 → [描述] → AI → [结果] → ...
(人在每一步都参与)

右侧:Agentic Engineering
人 → [高层目标] → Orchestrator → 需求 Agent → 代码 Agent → 测试 Agent
                                                              ↓
                      [有问题?] ← 修复 Agent ←─────────────┘
                          ↓否
                      [汇报结果] → 人
(人只在开始和结束参与)
图二:四种协作模式

分别画出串行、并行、条件路由、人工干预的流程图。

代码讲解

打开 src/agent-pipeline/pipeline.ts,逐段讲解:

讲解点一:任务结构

typescript
interface Task {
  id: string;
  description: string;
  type: 'schema' | 'service' | 'controller' | 'test';
}

每个任务有明确的类型,Agent 根据类型决定用什么策略生成代码。

讲解点二:重试逻辑
typescript
do {
  result = await codeGenerationAgent(task);
  retries++;
} while (!result.success && retries < MAX_RETRIES);

Agent 系统里的失败是正常的,关键是有合理的重试机制。

讲解点三:人工干预节点
typescript
if (!result.success) {
  console.error(`任务 ${task.id} 需要人工介入`);
  // 触发人工干预节点
  break;
}

最大重试次数之后,不能让 Agent 无限循环,必须升级给人处理。

讲解点四:Orchestrator 的职责
typescript
async function orchestrator(requirement: string) {
  // 1. 分解任务
  // 2. 调度各个 Agent
  // 3. 处理失败和重试
  // 4. 决定什么时候需要人工介入
}

Orchestrator 是 Multi-Agent 系统的核心,它不做具体的工作,只负责协调。


七、工程师角色的转变

传统工程师 vs Agentic Engineering 时代的工程师

能力维度 传统工程师 Agentic 时代
核心工作 写代码 设计 Agent 系统、审查 AI 输出
技术能力要求 语法熟练度、框架知识 系统设计、任务拆解、质量判断
价值来源 代码产出量 任务拆解质量、质量把控能力
低价值工作 写样板代码 被 AI 替代
高价值工作 架构决策、业务理解 更加凸显

三个核心能力

1. 任务拆解能力

把复杂需求拆解成边界清晰的小任务,分配给不同的 Agent。

拆得好,Agent 系统高效运作;拆不好,Agent 做出意想不到的决定,结果一塌糊涂。

2. 质量守门能力

Agent 会犯错,AI 会产生幻觉,生成的代码可能有 Bug 和安全漏洞。

工程师需要能识别哪些输出可以用,哪些需要退回重做。这需要扎实的技术功底,不是不懂技术就能做到的。

3. 系统设计能力

什么场景用串行流水线,什么场景用并行,哪些操作需要人工确认——这些设计决策决定了系统的效率和安全性。

这是 AI 暂时替代不了的能力。


Spec Coding 实战补充:12 从 VibeCoding 到 AgenticEngineering

来源:Spec Coding实战/12 从 VibeCoding 到 AgenticEngineering.md,已合并到本章节。

1. 三个阶段的演进

软件工程里引入 AI 这件事,目前大概经历了三个阶段:

阶段一:AI 补全工具(2021-2023) AI 是你的打字加速器。Copilot 帮你补全函数、生成注释。开发者是绝对主导,AI 是辅助。

阶段二:对话式 VibeCoding(2023-2024) AI 是你的结对程序员。你描述意图,AI 生成完整实现。开发者主导设计,AI 负责实现细节。

阶段三:Agentic Engineering(2025 起) AI 是能自主完成任务的工程 Agent。你给出目标和约束,AI 自主规划、分解任务、调用工具、执行并验证。开发者转变为任务定义者和质量把关者

这三个阶段不是互相替代,而是层层叠加。Agentic Engineering 不意味着你不再写代码,而是意味着你的工作重心从"怎么写"转移到"写什么"和"验证对不对"


2. Agentic Engineering 的核心特征

2.1 Agent 思维:从单步到规划

VibeCoding 是单步式的:你提一个问题,AI 给一个答案。

Agent 思维是规划式的:给 AI 一个目标,AI 自主分解成多个步骤,依次执行,遇到障碍自己想办法绕过。

VibeCoding 方式
plain
你:帮我写一个创建用户的 API
AI:[给代码]
你:加一下参数校验
AI:[改代码]
你:再加一下重复邮箱的校验
AI:[再改]
...(重复 10 轮)
Agentic 方式
plain
你:按照 @spec/user.md 实现用户模块,
    包括完整的参数校验、业务逻辑、单元测试,
    最后运行测试确认通过

AI:
  → 读取 spec/user.md
  → 分析项目结构(src/modules/)
  → 生成 DTOs
  → 生成 Service(含错误处理)
  → 生成 Controller
  → 生成单元测试
  → 执行 npm test
  → 发现 2 个测试失败
  → 定位问题、修复
  → 重新运行测试
  → 全部通过,返回结果

你只定义了"什么",AI 自主完成了"怎么"。


2.2 工具调用(Tool Use)

Agentic 的关键能力:AI 能调用工具扩展自己的能力边界。

在 Cursor Agent 和 Claude Code 里,AI 可以:

  • 读写文件系统
  • 执行 shell 命令(npm installnpm testgit diff
  • 搜索代码库
  • 查阅外部文档

这让 AI 的能力从"生成文本"变成了"执行任务"。

plain
你:有一个 bug,用户列表页在搜索时偶尔会崩溃

AI:
  → 搜索代码库里的 user.service.ts
  → 读取 findAll 方法
  → 识别到问题:search 参数未做 SQL 特殊字符转义
  → 查看测试文件,确认没有覆盖这个场景
  → 修复代码
  → 补充测试用例
  → 执行测试验证
  → 报告完成

2.3 反馈循环(Feedback Loop)

真正的 Agent 有自我校正能力:执行 → 验证结果 → 发现问题 → 修复 → 再验证。

在 Cursor Agent 里,这个循环已经初步实现:Agent 生成代码后,如果你告诉它"编译报错了",它会主动去读错误信息,定位问题,修复,再让你验证。

Claude Code 里,你可以直接让它"生成完运行一下,不通过就自己修":

bash
> 帮我实现用户搜索功能,写完后跑单元测试,
  如果测试失败自己分析原因并修复,直到全部通过

3. 多 Agent 协作开发

单个 Agent 已经很强了,但对于复杂的软件系统,更高级的形态是多个 Agent 分工协作

分工模式一:按职能分工

plain
需求 Agent    → 读取 PRD,生成 spec.md
架构 Agent    → 读取 spec,设计系统结构、数据模型
开发 Agent    → 按架构文档实现代码
测试 Agent    → 读取实现,生成并执行测试
Review Agent  → 扫描代码,输出安全和质量报告

每个 Agent 有自己的职责范围,上下游之间通过文档交接。

分工模式二:并行开发

plain
前端 Agent  ┐
后端 Agent  ┼→ 最终合并到主分支
测试 Agent  ┘

前端、后端、测试同时进行,通过 spec.md 保持接口契约一致。

这种模式对 spec 的质量要求极高——spec 是多 Agent 之间的唯一"合同",不清楚的地方会导致各 Agent 理解不一致。

目前的实现方式

多 Agent 完全自主协作目前还在发展中,但你现在就可以用一种"半手动"的方式实现:

bash
# 终端1:Claude Code 做后端
cd backend
claude "按照 @spec/user.md 实现用户模块"

# 终端2:Claude Code 做前端
cd frontend
claude "按照 @spec/user.md 实现用户管理页面,接口格式参考 spec 文档"

# 你:偶尔巡逻,解决卡住的问题,最后做集成验证

4. 开发者角色的转变

在 Agentic Engineering 时代,开发者做的事情变了:

传统开发 Agentic Engineering
写代码实现 定义规格(spec.md)
人工 Code Review 验证 AI 的输出
调试 bug 分析 Agent 为什么理解错了
写测试用例 定义验收标准
维护文档 维护 spec 和 rules

这不意味着你不需要懂技术了。恰恰相反:不懂技术的人,写不出能指导 AI 正确执行的规格文档

Agentic Engineering 要求开发者具备"系统思维"——能清晰地把一个复杂问题分解成可执行的子任务,能定义清楚每个任务的输入、输出和验收标准。这是更高级的技术能力,不是更低级的。


5. 工程化能力依然是核心

Agentic 时代,以下能力会重要,不是更不重要:

架构设计能力 AI 很难凭空设计好的系统架构。你需要先想清楚模块划分、数据模型、接口设计,AI 才能按你的架构正确实现。

需求分析能力 如果你说不清楚要什么,AI 只会给你一个看起来对但实际上不对的东西。需求越清晰,AI 的产出越准确。

质量判断能力 AI 生成的代码,你要能快速判断对不对、好不好。这需要你有扎实的基础。

调试能力 Agent 出错时,你要能定位是 spec 写得不清楚、rules 有遗漏、还是 AI 本身出了问题,才能有效纠正。


6. 从现在开始的实践路径

第一步(现在):Spec Coding

  • 开始为每个功能写 spec.md
  • 完善 .cursorrules
  • 用 Cursor Agent 驱动开发,减少对话轮次
第二步(3-6 个月):流程自动化
  • 把 AI Review 集成到 CI
  • 用 Claude Code 自动化重复性任务(生成模块、生成测试)
  • 建立团队的 Rules 和 Spec 模板库
第三步(6-12 个月):多 Agent 实验
  • 尝试前后端并行开发
  • 建立标准化的 Agent 交接格式(spec 作为 API 契约)
  • 探索适合团队的多 Agent 工作流

7. 小结

从 VibeCoding 到 Agentic Engineering,不是技术更迭,是思维方式的跃迁:

  • VibeCoding:我告诉 AI 怎么做
  • Spec Coding:我告诉 AI 做什么,规范它怎么做
  • Agentic Engineering:我定义目标和约束,AI 自主规划并完成

这个演进方向很清楚,但每一步的基础是相同的:清晰的表达、结构化的思维、对系统的深度理解

技术能力不会因为 AI 变强而变得不重要,它会以新的形式继续发挥价值——只是从"写代码"变成了"驾驭 AI 写出好代码"。