LinOnward / Agent TutorialAgent Tutorial
章节1 / 18
00

开始

理解逐章搭建路径,定义最终要交付的 Agent 与贯穿教程的工程边界。

本页目录
本章任务创建 agent-from-scratch CLI 骨架,并让它接收“分析这个仓库”任务。
章节目标得到一个具备开发、类型检查和测试命令的 TypeScript CLI 项目,后续每章都在它上面继续修改。
开始之前

Node.js 24、pnpm 12,以及一个空目录。

本章涉及文件
  • package.json
  • tsconfig.json
  • src/index.ts
  • tests/

Step 1理解这条搭建路径

这不是一组彼此独立的代码片段。你会始终修改同一个 agent-from-scratch 项目,让它从只能接收命令行文本的程序,逐章成长为能够理解任务、规划、调用工具、修改代码并验证结果的 Agent。

每一章都遵循同一套学习契约:

  1. 搭建能力:完成一个边界清楚、可以运行的新能力,而不是只阅读概念。
  2. 理解组件:解释它解决什么问题、接收什么输入、产生什么输出,以及为什么不能把职责交给模型自由发挥。
  3. 加入约束:把能力接入 Harness,由代码控制状态转换、上下文与轮次预算、工具权限、完成证据和停止条件。
  4. 实际验证:使用本章指定的真实任务和 Checkpoint 验收;失败时先修正,不带着坏状态进入下一章。

最终系统的控制关系如下。模型只提出下一步行动,Harness 才是 Agent 的运行时控制层:

text
用户任务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:

shell
fnm install 24fnm use 24corepack enablecorepack prepare pnpm@12.4.1 --activate

不使用 fnm 时只需替换前两条,最终版本检查相同。

shell
node --versionpnpm --version

第一条应输出 v24.x,第二条应输出 12.x。如果版本不一致,先用你习惯的 Node 版本管理器切换;不要带着不同运行时继续排查后续错误。

Step 3创建项目并安装开发依赖

在终端创建目录、初始化包,并安装 TypeScript 执行器、Node 类型与测试框架。教程后面的命令都从这个目录执行。

shell
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 是贯穿教程的最低本地门禁。

json
{  "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 initpnpm add 已经写入依赖;这里重点核对脚本,不要求手工覆盖 pnpm 解析出的实际版本。

创建 tsconfig.json

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 进入程序。

typescript
const task = process.argv.slice(2).join(" ").trim();if (!task) {  throw new Error("请在命令后提供任务,例如:pnpm dev -- 分析这个仓库");}console.log({ task });

创建 tests/cli.test.ts,先验证测试工具链工作:

typescript
import { describe, expect, it } from "vitest";describe("tutorial toolchain", () => {  it("runs tests", () => {    expect(true).toBe(true);  });});

Step 6写下最终完成标准

在项目根目录创建 GOAL.md,固定贯穿教程的验收任务:

markdown
# 最终任务给示例 CLI 增加 --name 参数并补充测试。Agent 必须能够:1. 搜索并读取相关文件;2. 修改实现与测试;3. 运行最窄相关检查;4. 根据失败继续修正;5. 汇报改动和验证证据。