首页 > 基础资料 博客日记
Agent构建:声明式优于硬编码
2026-04-01 17:30:01基础资料围观1次
AI Agent 实操指南:用一份 Markdown 文件指挥 AI 干活
你大概已经用 AI 写过不少代码了——让它生成一个函数、解释一段逻辑、写个正则。但你有没有遇到过这种情况:
项目里有个老模块,散落在十几个文件里,全是回调地狱。你想让 AI 帮你重构成 async/await,顺便补上测试。结果呢?AI 改了三个文件就开始"失忆",改完 A 忘了 B 的依赖,测试一跑全红。
问题不在 AI 的能力,而在于你跟它的协作方式。
你一直在跟 AI 对话,但你真正需要的是给它一份工作手册。
这就是 Agent 思维的起点。
什么是 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 / 宿主程序),负责:
- 接收你的指令
- 把指令连同
AGENTS.md的内容一起发给大模型 - 解析大模型的回复——如果回复里包含工具调用请求(
tool_call),就去执行对应的操作(读文件、写文件、跑命令等) - 把执行结果喂回给大模型
- 重复 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 个文件包含回调风格代码:
- src/utils/fileHelper.js(无外部依赖,优先处理)
- src/services/userService.js(依赖 fileHelper)
- ...
开始处理第 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 后,会做几件事:
-
创建隔离工作目录:宿主程序(不是大模型)自动在一个临时区域为这个子 Agent 新建一个独立文件夹(比如
.agents/workspaces/api-parser-a3f1,带随机后缀避免冲突)。这个目录就是子 Agent 的"沙盒"——它的临时文件、中间产物都放在这里,不会污染主项目,也不会跟其他并行的子 Agent 互相干扰。 -
启动新的大模型会话:开一个全新的对话实例,把任务描述注入为系统指令。这个新实例的上下文是干净的——它只知道自己被分配的任务,不背负主 Agent 的历史包袱。
-
子 Agent 独立执行:在自己的沙盒里读文档、处理数据、生成结果。
-
返回结果,销毁实例:子 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/ 下的独立文件夹里。这不是多此一举,而是解决了两个实际问题:
-
防止并行冲突:如果你同时派了 3 个子 Agent 去解析 API 文档的不同模块,它们都往同一个
api-summary.json里写,结果就是互相覆盖、数据错乱。独立目录让每个子 Agent 有自己的"工位",互不干扰。 -
保持主项目干净:子 Agent 的中间产物(临时文件、草稿、调试日志)不会散落在你的
src/目录里。任务完成后,宿主程序可以根据策略清理这些工作目录,或者保留作为审计日志。
主 Agent 和子 Agent 怎么沟通?
这是多 Agent 协作中最关键的问题。目前主流有两种模式:
模式一:同步等待(最常见)
主 Agent 发出 spawn_agent 的 tool_call 后,自己就挂起了——就像你在代码里调了一个 await。子 Agent 独立运行,完成后把结果返回。宿主程序把这个结果作为 tool_call 的 response 喂回给主 Agent,主 Agent 被唤醒,继续往下走。
在主 Agent 看来,这就是一次普通的函数调用:传入任务描述,拿到执行结果。
模式二:异步协作(适合超大任务)
宿主程序同时启动多个子 Agent 并行执行,不让主 Agent 傻等。所有子 Agent 完成后,宿主程序收集各自的结果,一次性或分批喂回给主 Agent。
需要注意的是,大模型本身是无状态的(每次都是请求-响应),所以"异步"和"并行"都是宿主程序在调度,不是大模型自己在"同时想两件事"。主 Agent 和子 Agent 之间的协调,本质上都是宿主程序在中间传话。
在 AGENTS.md 里怎么写沟通规则?
你可以在 Agent 文件中明确规定汇报机制。比如:
## 子 Agent 沟通协议
### 任务委派时
- 向子 Agent 明确说明:任务目标、输入数据位置、期望的输出格式
### 结果接收时
- 子 Agent 必须返回结构化的 JSON 结果,包含:
- status: "success" | "partial" | "failed"
- result: 实际产出(数据、文件路径等)
- issues: 遇到的问题列表(如果有)
- 如果 status 为 "partial" 或 "failed",主 Agent 应评估是否需要重试或换策略
### 进度汇报(长时间任务)
- 子 Agent 每完成一个主要步骤后,
通过系统的 HTTP 工具向 http://localhost:3000/progress 发送进度通知
- 通知格式:{"agent": "api-parser", "step": "3/7", "message": "已解析用户模块"}
注意最后一段——进度汇报机制也是声明式的。你不需要在代码里写死 Webhook 地址或 Slack 通知逻辑。只要宿主程序提供了基础的 HTTP 请求工具,你在 Markdown 里写一句"用 HTTP 工具发个通知",AI 就会在合适的时机自己拼装请求去调用。
这就是声明式的魅力:连"怎么汇报工作"这件事,都不用硬编码。
顺便聊聊 SKILL.md:Agent 的"技能手册"
你可能注意到,AGENTS.md 关注的是"谁来做、按什么流程做、遇到问题怎么办"——这是编排层。
但有些知识是跨 Agent 通用的,比如:
- 怎么读取 PDF 文件的内容(毕竟它不是纯文本)
- 怎么调用公司内部的 API 网关
- 怎么按照团队的 UI 规范生成前端组件
这类"怎么做某件具体的事"的知识,适合写进 SKILL.md。
打个比方:
AGENTS.md是岗位职责书——定义这个人负责什么、工作流程是什么SKILL.md是操作手册——定义某项具体技能的步骤和规范
Agent 在执行任务时,会根据需要去"翻阅"相关的 SKILL 文件。比如重构 Agent 在处理文件读写时,可能会参考一份关于"Node.js 文件操作最佳实践"的 SKILL.md。
这篇文章不展开 SKILL.md 的细节,但记住这个分层:Agent 负责编排,Skill 负责执行细节。两者配合,才是完整的 Agent 架构。
安全网:反思层与人在回路
让 AI 自主干活,你难免会担心:万一它改出 bug 怎么办?万一它执行了不该执行的操作呢?
反思层:让 Agent 审查自己
在 AGENTS.md 里加一段"自检"规则:
## 质量保障
- 在提交任何改动前,切换到"资深代码审查者"的视角重新审视你的改动
- 检查清单:
- 是否引入了新的副作用?
- 错误处理是否完整?
- 是否有遗漏的边界情况?
- 如果发现问题,先修复再提交
- 如果不确定,标记为 TODO 并告知我
你甚至可以更进一步——让主 Agent 在提交代码前,专门 spawn 一个"Reviewer Agent"来审查:
## 代码审查流程
在提交任何代码变更前,启动一个临时的审查子 Agent。
它应站在 SRE(运维工程师)的角度审查你的 Patch:
- 是否有性能隐患?
- 是否有安全风险?
- 是否会影响现有服务的稳定性?
只有当审查 Agent 返回 "LGTM" 时,才能提交改动。
人在回路:关键操作必须人类确认
在真实的企业场景中(修改数据库、发送邮件、部署上线),我们不敢让 Agent 100% 自动化。
好的 Agent 工具都支持"人在回路"机制:当 Agent 要执行高危操作时,宿主程序会暂停执行,弹出确认框等你点"Yes"。
需要说清楚的是:这个拦截是宿主程序硬编码实现的,不是靠 Markdown 声明就能保证的。你在 AGENTS.md 里写"删除文件前要问我",AI 大概率会遵守,但这属于"软约束"——大模型有可能忽略。真正的安全保障,是宿主程序在工具层面做的拦截:比如当 AI 调用 delete_file 工具时,宿主程序无论如何都会先弹确认框。
所以最佳实践是双保险:宿主程序层面做硬拦截(这是底线),同时在 AGENTS.md 里也写上规则(让 AI 在决策阶段就尽量避免高危操作):
## 需要人类确认的操作
以下操作在执行前必须暂停并等待我的确认:
- 删除任何文件
- 修改数据库 schema
- 向外部服务发送请求
这跟 Prompt Engineering 有什么区别?
你可能觉得:这不就是写了个长 prompt 吗?
区别在三个地方:
| Prompt | AGENTS.md | |
|---|---|---|
| 生命周期 | 一次性,用完即弃 | 持久化,每次任务都生效 |
| 作用范围 | 单次对话 | 整个项目,所有对话 |
| 协作方式 | 你指挥,AI 执行 | 你定规则,AI 自主决策 |
Prompt 是"这次帮我做个什么"。AGENTS.md 是"你在这个项目里应该怎么工作"。
一个是临时工的任务单,一个是正式员工的岗位手册。
写在最后
Agent 不是什么遥远的未来技术。它就是:
把你脑子里"我会怎么做这件事"的过程,写成一份结构化的文档,然后让 AI 照着做。
你一直在用 AI 当计算器——给一个问题,要一个答案。但 Agent 模式下,AI 是你的同事——你给它一个目标、一套规范、一些工具,它自己去把事情办了。
核心思维转变:
- 以前:你写代码来实现功能
- 现在:你写 AGENTS.md 来描述"如何实现功能的过程"
现在打开 VS Code,在项目里建一个 .agents/ 目录,把你最头疼的那个重复性任务写成一份 Agent 文件。
不需要完美,先写一版,跑一次,看看 AI 怎么理解你的意图,然后迭代。
这就是 Agent 开发的正确打开方式——不是写代码,而是写规则;不是编程,而是管理。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!
标签:
相关文章
最新发布
- 关于列式存储(Column-base Storage)的几个要点解读
- 同样都是九年义务教育,他知道的AI算力科普好像比我多耶
- Slickflow 与 OpenClaw 结合实践:技术原理、集成方式与 Skill 说明
- 如何使用 UEFI Shell 执行 Hello World 程序
- Agent构建:声明式优于硬编码
- AI 可以取代运维了吗?
- 测试人必备的4个AI Skills(附下载地址和详细用法)
- 记一次Webshell流量分析2 | 添柴不加火
- 直击政企AI落地“深水区”,华为混合云推出OpenClaw本地部署方案
- FastAPI里玩转Redis和数据库的正确姿势,别让异步任务把你坑哭了!

