开始
理解逐章搭建路径,定义最终要交付的 Agent 与贯穿教程的工程边界。
预计 15 分钟本页目录
Node.js 24、pnpm 12,以及一个空目录。
package.jsontsconfig.jsonsrc/index.tstests/
Step 1理解这条搭建路径
这不是一组彼此独立的代码片段。你会始终修改同一个 agent-from-scratch 项目,让它从只能接收命令行文本的程序,逐章成长为能够理解任务、规划、调用工具、修改代码并验证结果的 Agent。
每一章都遵循同一套学习契约:
- 搭建能力:完成一个边界清楚、可以运行的新能力,而不是只阅读概念。
- 理解组件:解释它解决什么问题、接收什么输入、产生什么输出,以及为什么不能把职责交给模型自由发挥。
- 加入约束:把能力接入 Harness,由代码控制状态转换、上下文与轮次预算、工具权限、完成证据和停止条件。
- 实际验证:使用本章指定的真实任务和 Checkpoint 验收;失败时先修正,不带着坏状态进入下一章。
最终系统的控制关系如下。模型只提出下一步行动,Harness 才是 Agent 的运行时控制层:
用户任务 ↓Harness ├─ 组装 Context + System Prompt ├─ 维护 Task State + Plan ├─ 调用 Model Adapter ├─ 校验 Tool Registry + Permission Policy └─ 检查 Budget + Evidence + Stop Conditions ↓ Agent 结果这里的“无框架”指不使用 LangChain 等 Agent 框架替你实现控制流。模型 SDK 只负责与模型通信;上下文组装、状态机、规划、工具调度、循环、恢复和安全策略都由你亲手实现,因此每个关键边界都是可见、可测试、可替换的。
教程的增量路线分成三段。第一段建立 CLI、模型、上下文、最小 Agent Loop 与工具协议,并立即赋予它搜索、读取、修改和验证仓库任务的能力;第二段把这个可用闭环升级成具有持久状态、预算、权限、规划、用户转向、Skills 与质量评测的工程系统;第三段再加入完整编排、上下文压缩、长程恢复和综合 Capstone。这样读者先看到 Agent 真正完成任务,再逐步理解可靠运行所需的控制层。
主线刻意停在一个可用、可审计、可恢复的单 Agent。多 Agent、MCP、RAG、浏览器操作、语音和复杂并行调度统一放入扩展篇,它们复用主线建立的 Model、Context、Tool、Policy、State、Trace 与 Eval 边界,但不是主线 Capstone 的前置条件。这样既避免在读者尚未掌握单 Agent 闭环时引入分布式复杂度,也为后续专题保留清晰接口。
Step 2确认本地工具链
先检查运行时和包管理器版本。教程只使用 pnpm,不混用 npm、Yarn 或 Bun。如果尚未安装,先从 Node.js 下载页 安装 Node 24,或用 fnm、Volta 等版本管理器固定项目版本;随后启用项目声明的 pnpm:
fnm install 24fnm use 24corepack enablecorepack prepare pnpm@12.4.1 --activate不使用 fnm 时只需替换前两条,最终版本检查相同。
node --versionpnpm --version第一条应输出 v24.x,第二条应输出 12.x。如果版本不一致,先用你习惯的 Node 版本管理器切换;不要带着不同运行时继续排查后续错误。
Step 3创建项目并安装开发依赖
在终端创建目录、初始化包,并安装 TypeScript 执行器、Node 类型与测试框架。教程后面的命令都从这个目录执行。
mkdir agent-from-scratchcd agent-from-scratchpnpm initpnpm add -D typescript@6.0.3 tsx@4.21.0 @types/node@24.10.4 vitest@5.0.0mkdir src tests这些工具各自只有一个职责:Node 运行程序,pnpm 管理依赖,TypeScript 检查类型,tsx 在开发阶段直接执行 .ts,Vitest 执行快速单元测试。
Step 4配置脚本与 TypeScript
把 package.json 改成下面这样。check 是贯穿教程的最低本地门禁。
{ "name": "agent-from-scratch", "private": true, "type": "module", "packageManager": "pnpm@12.4.1", "scripts": { "dev": "node --env-file-if-exists=.env --import tsx src/index.ts", "test": "vitest run", "typecheck": "tsc --noEmit", "check": "pnpm typecheck && pnpm test" }, "devDependencies": { "@types/node": "24.10.4", "tsx": "4.21.0", "typescript": "6.0.3", "vitest": "5.0.0" }}pnpm init 和 pnpm add 已经写入依赖;这里重点核对脚本,不要求手工覆盖 pnpm 解析出的实际版本。
创建 tsconfig.json:
{ "compilerOptions": { "target": "ES2023", "module": "NodeNext", "moduleResolution": "NodeNext", "lib": [ "ES2023" ], "types": [ "node" ], "strict": true, "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true, "skipLibCheck": true }, "include": [ "src/**/*.ts", "tests/**/*.ts" ]}NodeNext 让 TypeScript 按 Node ESM 规则解析模块,因此本地相对导入在源码中也要写 .js 后缀,例如 import { createModel } from "./model-factory.js"。
Step 5接收第一个任务
创建 src/index.ts。现在它还不是 Agent,只负责证明任务可以从 CLI 进入程序。
const task = process.argv.slice(2).join(" ").trim();if (!task) { throw new Error("请在命令后提供任务,例如:pnpm dev -- 分析这个仓库");}console.log({ task });创建 tests/cli.test.ts,先验证测试工具链工作:
import { describe, expect, it } from "vitest";describe("tutorial toolchain", () => { it("runs tests", () => { expect(true).toBe(true); });});Step 6写下最终完成标准
在项目根目录创建 GOAL.md,固定贯穿教程的验收任务:
# 最终任务给示例 CLI 增加 --name 参数并补充测试。Agent 必须能够:1. 搜索并读取相关文件;2. 修改实现与测试;3. 运行最窄相关检查;4. 根据失败继续修正;5. 汇报改动和验证证据。