个人Agent:TypeScript 实现路线图参考(MVP 篇)
我个人学习项目(自建 AI Harness)的路线图。 环境快照(2026-08):Node.js 22+、Vercel AI SDK 7、模型
K3、GLM5.2、DSV4FGA、K2.7HS、HY3。依赖版本变化很快,以 npm 最新为准。
一、目标定位
MVP 范围
参考本系列第 5 篇《Harness Engineering 四大支柱》的成熟度评估模型,MVP 目标定位于 Level 1-2 之间:
| 能力 | MVP 必须 | v2 可选 |
|---|---|---|
| Agent Loop(ReAct) | ✅ | — |
| 5-7 个核心工具 | ✅ | — |
| 工具调用 + 参数 schema | ✅ | — |
| 基础权限(allow/ask/deny) | ✅ | — |
| 上下文管理(observation 屏蔽) | ✅ | — |
| 持久化记忆(progress 文件) | ✅ | — |
| Compaction | ⚠️ 简化版 | 完整 4 级 |
| 子 Agent | ❌ | ✅ |
| Plan/Act 分离 | ❌ | ✅ |
| MCP 集成 | ❌ | ✅ |
| Hooks 系统 | ❌ | ✅ |
| 沙盒 | ❌ | ✅ |
| 多 Agent 编排 | ❌ | ✅ |
不做的事(避免过度工程)
- 一上来就多 agent — 先榨干单 agent
- 一上来就 MCP — 先把内置工具做扎实
- 一上来就完整压缩管道 — 先做 observation 屏蔽
- 一上来就 Plan/Act — 先跑通 ReAct
二、技术栈选型
推荐(参考 OpenHarness / coding-agents-from-scratch)
| 层 | 选择 | 理由 |
|---|---|---|
| 语言 | TypeScript | 类型安全,生态成熟 |
| Runtime | Node.js 22+(或 Bun) | Node 稳定;Bun 更快但生态略新(AI SDK 7 与 execa 10 均要求 Node 22+) |
| LLM 调用 | Vercel AI SDK 7 | 统一接口、流式输出、工具调用 |
| Provider | OpenAI-compatible | 可配置 base URL,接 GPT/Claude/本地模型 |
| Schema 验证 | Zod 4 | 与 Vercel AI SDK 配套 |
| 终端 UI(可选) | React + Ink | 像 Claude Code 一样;MVP 先用 readline |
| Shell 执行 | execa 10 或 shelljs | 跨平台 |
| 流式 | Async Generator | 与 Claude Code 一致 |
| 日志 | pino | 结构化、低开销 |
| 测试 | Vitest 4 | Vite 生态,ESM 友好 |
| 评测 | Laminar(可选) | 结构化评测(https://www.lmnr.ai ) |
极简依赖树(MVP 起步,版本截至 2026-08)
{
"dependencies": {
"ai": "^7.x", // Vercel AI SDK
"@ai-sdk/openai": "^4.x",
"zod": "^4.x",
"execa": "^10.x"
},
"devDependencies": {
"typescript": "^5.x",
"vitest": "^4.x",
"@types/node": "^22.x"
}
}
三、参考项目
直接参考源码
| 项目 | 链接 | 为什么学 |
|---|---|---|
| coding-agents-from-scratch TypeScript 版 | https://linzzzzzz.github.io/coding-agents-from-scratch/typescript-zh/(仓库:https://github.com/linzzzzzz/coding-agents-from-scratch ) | 16 章从零搭一个 CLI coding agent,最贴近你的目标;注意原版 Python/Go 仓库已下架,这是现役的 TS 版 |
| OpenHarness | https://open-harness.dev/ | MIT 协议、基于 Vercel AI SDK 的 composable harness 原语 |
| puristajs/harness | https://github.com/puristajs/harness | TypeScript 写的 AI Harness(Apache-2.0,2026-05 创建,很早期的个人项目,仅作参考) |
| OpenCode | https://opencode.ai/ | provider 无关的开源终端 agent |
| Claude Code 文档 | https://code.claude.com/docs/en/overview | Anthropic 官方 |
| Harness Engineering 完全指南 | https://wanlanglin.github.io/-awesome-cc-harness/zh/ | Claude Code 源码逆向工程教科书(仓库:https://github.com/WanLanglin/-awesome-cc-harness ) |
参考的Agent设计
| 项目 | 链接 | 对照点 |
|---|---|---|
| Cline | https://github.com/cline/cline | Plan/Act 分离、MCP 集成 |
| Aider | https://github.com/Aider-AI/aider | git 原生、repo map、编辑格式 |
| mini-SWE-agent | https://github.com/SWE-agent/mini-swe-agent | 最小参考实现,适合学循环 |
四、项目结构
参考 coding-agents-from-scratch,适配 harness 命名:
myHarness/
├── docs/ # 研究资料
├── src/
│ ├── agent/
│ │ ├── run.ts # 核心 agent loop
│ │ ├── executeTool.ts # 工具分发器
│ │ ├── tools/
│ │ │ ├── index.ts # 工具注册表
│ │ │ ├── file.ts # 文件操作(Read/Write/Edit)
│ │ │ ├── bash.ts # Shell 命令
│ │ │ ├── glob.ts # 文件搜索
│ │ │ ├── grep.ts # 内容搜索
│ │ │ └── webFetch.ts # 网页抓取(可选)
│ │ ├── context/
│ │ │ ├── index.ts
│ │ │ ├── tokenEstimator.ts
│ │ │ ├── observationMask.ts # observation 屏蔽
│ │ │ └── compaction.ts # 简化版压缩
│ │ └── system/
│ │ ├── prompt.ts # 系统提示
│ │ └── permissionRules.ts # 权限规则
│ ├── memory/
│ │ ├── progressFile.ts # claude-progress.txt
│ │ ├── featureList.ts # feature_list.json
│ │ └── agentsMd.ts # AGENTS.md 读写
│ ├── permission/
│ │ ├── decision.ts # 权限决策管道
│ │ └── modes.ts # default/acceptEdits/plan
│ ├── types.ts
│ └── index.ts
├── evals/ # 评测
├── package.json
└── tsconfig.json
五、分阶段实现步骤
Stage 1:最小 ReAct 循环(目标:能跑工具调用)
步骤
npm init,装 Vercel AI SDK + Zod- 写最简的
run():接收 messages + 输入,调 LLM,流式输出 - 定义一个工具(如
read_file),用 Zod schema - 把工具注册到 AI SDK 的
tools参数 - 实现循环:
- 模型输出 → 检测
tool_calls - 有 → 执行 → 结果作为
tool_result喂回 → 继续循环 - 没有 → 输出最终文本,退出
- 模型输出 → 检测
验收
- 模型能调用
read_file读取本地文件 - 多轮对话能维持(至少 5 轮不丢)
- 能流式打印 token
Stage 2:核心工具集(目标:能处理代码库)
步骤
- 加
write_file/edit_file工具 - 加
bash工具(用 execa) - 加
glob工具(文件名搜索) - 加
grep工具(内容搜索) - (可选)加
web_fetch(用 fetch) - 工具接口抽象:每个工具有
name、description、inputSchema、call、isReadOnly
关键决策
isReadOnly=true的工具可并发isReadOnly=false的工具必须串行- 工具结果大小限制(防止几 MB 的 transcript 爆上下文)
验收
- 让 agent 在你工作目录里读文件、改文件、跑命令
- 能跑通"找到 README,总结,写到 SUMMARY.md"这种任务
Stage 3:权限与审批(目标:不让 agent 闯祸)
步骤
- 实现 3 档权限:
allow/ask/deny - 实现
default模式(敏感操作询问) - 实现
acceptEdits模式(自动批准文件编辑) - 实现
bypassPermissions模式(危险,自动批准一切) - 加
.harness/settings.json(类似 Claude Code 的 settings)读写 - 加用户审批 prompt(readline 即可)
权限规则示例(类似 Claude Code)
{
"permissions": {
"allow": ["Read(*)", "Glob(*)", "Grep(*)", "Bash(git *)"],
"ask": ["Write(*)", "Edit(*)", "Bash(npm *)"],
"deny": ["Bash(rm -rf *)", "Bash(sudo *)"]
}
}
验收
- 启动 agent,它读文件不问,写文件先问
rm -rf之类命令硬拒绝acceptEdits模式下写文件不问
Stage 4:上下文管理(目标:长对话不爆上下文)
步骤
- 实现 token 估算(用
tiktoken或粗略的字符数/4) - 实现 observation 屏蔽:N 轮前的工具结果替换为
[Previous: used {tool}] - 实现简化版 compaction:接近上限时,让 LLM 自己总结对话历史
- 实现
taskBudgetRemaining追踪
验收
- 跑一个会让上下文膨胀的任务(如"读 100 个文件,总结")
- 不爆上下文,能持续推进
- agent 不丢失关键信息(架构决策、未完成 todo)
Stage 5:持久化记忆(目标:跨会话连续性)
步骤
- 实现
AGENTS.md读写(项目级持久上下文) - 实现
progress.md写入(每会话结束更新) - 实现
feature_list.json读写(JSON 格式,避免被模型乱改) - 实现 Initializer 模式检测:首次会话检查
feature_list.json是否存在 - 实现 Coding 模式启动序列:pwd → 读 git log → 读 progress → 读 feature_list → 选最高优先级未完成
关键文件格式
// feature_list.json
{
"features": [
{
"id": "F001",
"description": "User can create a new chat",
"steps": ["...", "..."],
"passes": false,
"priority": "high"
}
]
}
# progress.md
## 2026-07-28 Session 3
- Implemented F001 (new chat creation)
- Bug: sidebar not updating after new chat
- Next: F002 (message sending)
验收
- 跑会话 1(Initializer)→ 生成 feature_list、init.sh、初始 git commit
- 跑会话 2(Coding)→ 自动接上,实现一个 feature,git commit,更新 progress
- 跑会话 3(Coding)→ 自动接上,从上次中断处继续
Stage 6:验证循环(目标:agent 能自检)
步骤
- 让 agent 在标记 feature
passes: true前先跑测试 - 系统提示加强措辞:“It is unacceptable to remove or edit tests”
- (可选)加
puppeteerMCP 做浏览器端到端测试
验收
- agent 不会过早标记完成
- 失败的测试会被识别并修复
六、最小 ReAct 循环骨架代码
这是 Stage 1 的目标代码,不是生产级。生产级实现要处理大量边界情况(参考 Claude Code 数千行的实现)。
// src/agent/run.ts
import { streamText, Tool } from "ai";
import { openai } from "@ai-sdk/openai";
import { z } from "zod";
import { readFileSync } from "node:fs";
// 1. 定义工具
const tools = {
read_file: {
description: "Read the contents of a file",
parameters: z.object({
path: z.string().describe("Absolute file path"),
}),
execute: async ({ path }) => readFileSync(path, "utf-8"),
},
// ... write_file, bash, glob, grep
} satisfies Record<string, Tool>;
// 2. Agent Loop
type Message = any; // 简化
async function run(
messages: Message[],
userInput: string,
): Promise<Message[]> {
const state = { messages: [...messages, { role: "user", content: userInput }] };
while (true) {
const result = await streamText({
model: openai("gpt-5.4"),
system: "You are a helpful coding agent. Use tools to gather context and act.",
messages: state.messages,
tools,
maxSteps: 20, // 防止无限循环
});
// 流式打印
for await (const delta of result.fullStream) {
if (delta.type === "text-delta") {
process.stdout.write(delta.textDelta);
}
}
// 检查是否有工具调用
const toolCalls = await result.toolCalls;
if (toolCalls.length === 0) {
// 没有工具调用 = 最终答案
const finalText = await result.text;
state.messages.push({ role: "assistant", content: finalText });
return state.messages;
}
// 有工具调用 → 工具结果加入 messages → 继续循环
const toolResults = await result.toolResults;
state.messages.push({ role: "assistant", content: toolCalls });
state.messages.push({ role: "tool", content: toolResults });
}
}
// 3. 入口
const userInput = process.argv[2] ?? "Hello";
run([], userInput).then(finalMessages => {
console.log(`\n[Done] ${finalMessages.length} messages`);
});
按 概念 AI SDK 4/5 的 API 编写(手动循环以说明原理,maxSteps 参数在 AI SDK 4/5 的 streamText 中内置了 agent loop)。升级到 AI SDK 7 后,建议改用官方的 ToolLoopAgent(内置 agent 循环、含 sandbox/shell 工具与 toolApproval 工具审批钩子),或继续手动循环并把 maxSteps 换成 stopWhen。
七、测试陷阱
1. 不要一上来就多 agent
MVP 阶段:单 agent + 多会话(Anthropic 长跑模式)。多 agent 的复杂度是数量级提升。
2. 不要相信模型会"记得"
任何跨会话的状态都必须落到文件。模型记忆 = 上下文窗口,窗口清空就没了。
3. 不要让上下文越长越好
参考本系列第 1 篇的 Smart Zone 数据:前 40% 是 Smart Zone,超过 40% 进入 Dumb Zone。
4. 不要写完代码就标完成
参考 Anthropic 第四个失败模式。加强措辞系统提示 + 强制跑测试。
5. 不要让 agent 自动跑 rm -rf 之类
硬编码拒绝列表,即使 bypassPermissions 模式也不放过。
6. JSON 比 Markdown 更适合结构化状态
agent 不太容易乱改 JSON,但很容易"优化"Markdown 描述。
7. git commit 是免费的 checkpoint
不要自己实现状态持久化,直接用 git。
八、个人评测
参考 SWE-agent 的思路:
单轮评测
- 给一个任务,检查 agent 选对了工具
- 写 golden / secondary / negative 测试用例
多轮评测
- 用 mock 工具测试完整对话
- 用 LLM-as-judge 给输出打分
- 评估工具调用顺序、避免使用 forbidden tool
端到端评测
- 跑真实任务(例如"修这个 repo 的某个 issue")
- 看是否产出可工作的代码
也可以从最后开始~
- 对照 coding-agents-from-scratch TypeScript 版 开始跟练
- 对照 OpenHarness 的 API 设计
附:2026 年 8 月更新与补充阅读
- Vercel AI SDK 7 已发布(
ai7.0.48,2026-08-02):新增ToolLoopAgent(内置 agent 循环的类,含 sandbox/shell 工具)、Output.object()结构化输出、模型字符串直连 Vercel AI Gateway;文档站新增「AI SDK Harnesses」章节与 Terminal UI 支持,并有官方的toolApproval工具审批参数——本路线图 Stage 3 的权限设计现在可以借力 SDK,不必全部自研。 - OpenHarness 是"对照 API 设计"的最佳活参考:MIT 协议、基于 Vercel AI SDK,提供可组合中间件(重试/压缩/持久化)、子 Agent 层级、两阶段上下文压缩、异步工具审批回调、MCP 集成与 AGENTS.md 自动注入。
- coding-agents-from-scratch TS 版现状:2026-05 创建(17 stars,很新),GitHub Pages 已启用;原版(Python/Go)仓库已下架,引用时以学习参考为主。
- Claude Code 逆向指南仓库:https://github.com/WanLanglin/-awesome-cc-harness (87 stars),与本文骨架同源。
参考来源
- Vercel AI SDK(npm
ai):https://www.npmjs.com/package/ai - OpenHarness:https://open-harness.dev/ ;仓库:https://github.com/MaxGfeller/open-harness
- coding-agents-from-scratch TS 版:https://linzzzzzz.github.io/coding-agents-from-scratch/