什么是 Agent?一句话版本

传统用法:你说一句,AI 做一步。你是指挥官,AI 是传话兵。

Agent 用法:你给一个目标和规则,AI 自己拆解任务、调用工具、验证结果、遇到问题还能自我修正。

用公式表达:

Agent = LLM(推理能力)+ 工具调用(读写文件、跑命令)+ 工作流(按步骤执行)+ 约束规则(什么能做什么不能做)

关键区别不是 AI 变聪明了,而是你给了它上下文和边界


核心理念:声明式优于硬编码

传统开发里,你用代码控制逻辑——写一堆 if/else、状态机、流程引擎来编排 AI 的行为。这叫命令式(Imperative)

但在 Agent 场景下,还有另一条路:用自然语言文档控制 AI 的行为。这叫声明式(Declarative)

你不写代码去约束 AI,而是写一份 Markdown 文件,告诉它:

  • 你的角色是什么
  • 工作流程是什么
  • 哪些事绝对不能做
  • 遇到问题怎么处理

为什么 Markdown 能管用?因为 Markdown 的标题层级、列表、缩进,天然地把信息组织成了清晰的层次结构。大模型在处理这种结构化文本时,能更准确地理解"哪些是规则、哪些是步骤、哪些是禁区",大幅减少歧义。一份层次清晰的 .md 文件,对 AI 来说就像一份合同——结构越清晰,它的遵循度越高。

这份文件,我们统一叫它 AGENTS.md

你可能见过 CLAUDE.md(Claude Code 专用)或 .cursorrules(Cursor 专用)。这些本质上都是同一件事——给 Agent 写工作手册。AGENTS.md 是一个更通用的命名约定,不绑定任何厂商。随着 VS Code、Cursor、Kiro 等工具对 Agent 模式的支持越来越成熟,一个标准化的文件名会让你的配置跨工具复用。


底层到底发生了什么?

在你动手之前,有必要先理解 Agent 的运行机制。别担心,不复杂。

你日常使用的 AI 编码工具(VS Code + Copilot、Cursor、Kiro 等),其实已经内建了一个 Agent。这个 Agent 的"骨架"是用代码写死的——一个循环程序(通常叫 Orchestrator / 宿主程序),负责:

  1. 接收你的指令
  2. 把指令连同 AGENTS.md 的内容一起发给大模型
  3. 解析大模型的回复——如果回复里包含工具调用请求(tool_call),就去执行对应的操作(读文件、写文件、跑命令等)
  4. 把执行结果喂回给大模型
  5. 重复 2-4,直到任务完成

大模型本身虽然经过了指令微调,具备了推理和规划能力,但它终究只能"输出文本"——它自己不会读文件、不会跑命令、不会发请求。外面这层硬编码的宿主程序,才是让它"有手有脚"的关键。

而 AGENTS.md 的角色,就是在第 2 步被注入——它成为大模型的"系统指令"的一部分,影响大模型在整个任务过程中的每一次决策。


动手:在 VS Code 里配置你的第一个 Agent

不需要装额外插件,不需要命令行工具。你只需要 VS Code + 一个支持 Agent 模式的 AI 扩展(比如 GitHub Copilot、Kiro、Continue 等)。

项目结构

在你的项目根目录下,创建一个 .agents/ 目录。每个 Agent 是一个独立的 .md 文件:

your-project/
├── .agents/
│   ├── modernizer.md      ← 代码现代化专家
│   ├── reviewer.md        ← 代码审查专家
│   └── bug-fixer.md       ← Bug 修复专家
├── src/
│   └── ...
├── tests/
│   └── ...
└── package.json

为什么每个 Agent 一个文件,而不是全塞进一个 AGENTS.md

道理跟你不会把所有业务逻辑写进一个 index.js 一样——关注点分离。当你有 5 个不同职责的 Agent 时,独立文件让你能精确地告诉 AI:"这次用 modernizer.md 的规则来干活",而不是让它在一份巨大的文档里自己猜该遵守哪段。

你也可以在项目根目录放一个 AGENTS.md 作为全局规则(比如代码风格、Git 提交规范),让所有 Agent 都遵守。子目录的 Agent 文件则定义各自的专属职责。这种分层设计,跟你在软件架构里做的模块解耦是一回事。

写你的第一份 Agent 文件

假设你的任务是:把项目里的老式回调代码重构成 async/await。

创建 .agents/modernizer.md

# 代码现代化 Agent

## 角色
你是一个 Node.js 代码重构专家。你的任务是将项目中的回调风格异步代码
(Callbacks、.then() 链)重构为 async/await 语法。

## 工作流程

### 1. 扫描
- 搜索项目中所有包含 `.then(`、`callback`、`fs.readFile` 等模式的文件
- 输出一份待重构文件清单,按依赖关系排序(被依赖最少的先改)

### 2. 逐个重构
- 每次只改一个文件
- 改完后立即运行 `npm test`
- 如果测试通过,继续下一个文件
- 如果测试失败,最多尝试修复 3 次

### 3. 遇到阻塞
- 如果某个文件 3 次修复都失败,回滚该文件的改动
- 记录失败原因,继续处理下一个文件
- 最后汇总所有阻塞点,报告给我

## 规则
- 不要修改 package.json 的 dependencies 或 version 字段
- 不要重构没有对应测试用例的文件(没测试 = 不动)
- 每个文件改完后必须跑测试,不能攒着一起跑
- 如果不确定某个改动是否安全,先问我

## 代码风格
- 使用 try/catch 包裹 await 调用
- 错误处理保持与原代码一致的粒度
- 保留原有注释,必要时更新

这不是 prompt,这是工作规范。AI 每次执行任务时都会读取这份文件,就像新员工入职时读 wiki 一样。

给 Agent 下达任务

在 VS Code 的 AI 聊天窗口中,你可以这样说:

请按照 .agents/modernizer.md 中的工作流程,开始重构 src/ 目录下的异步代码。

一个好的 Agent 会这样响应:

我已读取 modernizer.md。开始扫描阶段。

发现以下 7 个文件包含回调风格代码:

  1. src/utils/fileHelper.js(无外部依赖,优先处理)
  2. src/services/userService.js(依赖 fileHelper)
  3. ...

开始处理第 1 个文件:src/utils/fileHelper.js

它不是在"聊天",它在执行工作流


当任务变大:子 Agent 与上下文隔离

上面的重构案例还算简单——一个 Agent 就能搞定。但现实中,任务往往更复杂。

比如你要"根据 OpenAPI 文档实现所有 API 接口"。这份文档可能有几千行,涉及 30 个接口。如果让一个 Agent 把文档全读进去再写代码,它的上下文窗口很快就会被撑满——这就是上下文爆炸。AI 读了太多杂乱信息后,会开始"软忽略"早期的指令,质量急剧下降。

解决方案:拆任务,派子 Agent

子 Agent 是怎么被创建的?

这是整个 Agent 架构里最精彩的部分。你可能会好奇:一份 Markdown 文件,怎么就能让 AI "生"出另一个 AI?

答案是:本质上就是一次 tool_call

还记得前面说的宿主程序吗?它给大模型提供了一系列工具(读文件、写文件、跑命令等)。其中有一个特殊的工具,类似于 spawn_agent——"启动一个新的 Agent"。

当主 Agent 在执行任务时,如果它判断"这个子任务太大了,我应该派个人去专门处理",它就会输出一段 JSON:

{
  "tool": "spawn_agent",
  "args": {
    "task": "阅读 docs/api-spec.yaml,提取所有接口的路径、方法、请求/响应 schema,输出精简的 JSON 摘要"
  }
}

宿主程序收到这个 tool_call 后,会做几件事:

  1. 创建隔离工作目录:宿主程序(不是大模型)自动在一个临时区域为这个子 Agent 新建一个独立文件夹(比如 .agents/workspaces/api-parser-a3f1,带随机后缀避免冲突)。这个目录就是子 Agent 的"沙盒"——它的临时文件、中间产物都放在这里,不会污染主项目,也不会跟其他并行的子 Agent 互相干扰。

  2. 启动新的大模型会话:开一个全新的对话实例,把任务描述注入为系统指令。这个新实例的上下文是干净的——它只知道自己被分配的任务,不背负主 Agent 的历史包袱。

  3. 子 Agent 独立执行:在自己的沙盒里读文档、处理数据、生成结果。

  4. 返回结果,销毁实例:子 Agent 完成后,宿主程序把结果作为那次 tool_call 的返回值喂回给主 Agent。子 Agent 的会话随即被宿主程序销毁,释放上下文资源。谁来销毁?始终是宿主程序——大模型自己没有管理进程生命周期的能力。

对主 Agent 来说,整个过程就像调用了一个耗时稍长的函数——传入参数,拿到返回值,继续干活。

在 AGENTS.md 里怎么写,才能引导 AI 启动子 Agent?

关键在于:你要在工作流中明确描述什么条件下应该拆分任务,以及子任务的边界是什么。AI 不会无缘无故地去 spawn 子 Agent——它需要你在"宪法"里给出清晰的指引。

来看一个具体的例子。我们扩展前面的重构场景,加入 API 实现的需求:

# API 实现 Agent

## 角色
你负责根据 OpenAPI 文档实现所有后端 API 接口。

## 工作流程

### 阶段一:文档解析(委派子 Agent)
这个阶段的工作量大且独立,必须委派给一个子 Agent 处理:
- 子 Agent 的任务:阅读 docs/api-spec.yaml,提取所有接口的路径、方法、
  请求参数和响应 schema,输出为精简的 JSON 摘要
- 子 Agent 应在自己的隔离工作区中完成,不要在主项目目录下创建临时文件
- 等待子 Agent 返回 JSON 摘要后,再进入阶段二

### 阶段二:逐个实现
- 基于阶段一返回的 JSON 摘要(不要再去读原始 yaml 文件)
- 按接口逐个实现
- 每实现一个接口,写一个对应的集成测试
- 每个接口实现后跑一次测试

### 阶段三:汇总
- 列出所有已实现的接口和测试覆盖情况
- 标注未能实现的接口及原因

## 规则
- 阶段一必须通过子 Agent 完成,不要自己直接读取完整的 API 文档
- 如果 API 文档超过 3000 行,可以按模块拆分为多个子 Agent 并行解析

注意"阶段一"的写法——它没有用任何代码或 JSON 去"调用"子 Agent,而是用自然语言描述了:

  • 什么时候该拆:"这个阶段的工作量大且独立"
  • 子 Agent 该做什么:"阅读 yaml,提取 schema,输出 JSON 摘要"
  • 隔离要求:"在自己的隔离工作区中完成"
  • 同步机制:"等待子 Agent 返回后,再进入阶段二"

大模型读到这些指令后,会自己决定在合适的时机发出 spawn_agent 的 tool_call。你用声明式的语言描述了"意图",宿主程序和大模型配合完成了"执行"。

为什么要隔离工作目录?

你可能注意到了,子 Agent 不是在主项目目录里干活,而是在 .agents/workspaces/ 下的独立文件夹里。这不是多此一举,而是解决了两个实际问题:

  1. 防止并行冲突:如果你同时派了 3 个子 Agent 去解析 API 文档的不同模块,它们都往同一个 api-summary.json 里写,结果就是互相覆盖、数据错乱。独立目录让每个子 Agent 有自己的"工位",互不干扰。

  2. 保持主项目干净:子 Agent 的中间产物(临时文件、草稿、调试日志)不会散落在你的 src/ 目录里。任务完成后,宿主程序可以根据策略清理这些工作目录,或者保留作为审计日志。


主 Agent 和子 Agent 怎么沟通?

这是多 Agent 协作中最关键的问题。目前主流有两种模式:

模式一:同步等待(最常见)

主 Agent 发出 spawn_agent 的 tool_call 后,自己就挂起了——就像你在代码里调了一个 await。子 Agent 独立运行,完成后把结果返回。宿主程序把这个结果作为 tool_call 的 response 喂回给主 Agent,主 Agent 被唤醒,继续往下走。

在主 Agent 看来,这就是一次普通的函数调用:传入任务描述,拿到执行结果。

模式二:异步协作(适合超大任务)

宿主程序同时启动多个子 Agent 并行执行,不让主 Agent 傻等。所有子 Agent 完成后,宿主程序收集各自的结果,一次性或分批喂回给主 Agent。

需要注意的是,大模型本身是无状态的(每次都是请求-响应),所以"异步"和

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐