首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >不用框架,800 行代码,从零到 Plan Agent。我给 Agent 加上了计划能力

不用框架,800 行代码,从零到 Plan Agent。我给 Agent 加上了计划能力

原创
作者头像
老码小张
修改2026-01-30 15:29:43
修改2026-01-30 15:29:43
1650
举报
文章被收录于专栏:玩转全栈玩转全栈

上一篇文章里,我用 300 行代码实现了一个能对话、能调用工具的 Agent。它能读写文件、执行命令、搜索代码。这已经算是一个很基础的 agent 的,然后我在前天 300 行的基础上,继续增加了可以执行 shell 命令,为了安全,我还增加了审核机制,比较危险的命令需要人工确认才可以执行。

然后,我就开始继续想,如果一个复杂的任务,需要多步来执行应该怎么办。现在其实我们知道了,很多编码工具都会做一个 TODO,所以,一个真正的助手,应该先想清楚要做什么,再一步步执行。这个已然是一个共识。

别急,我们先想想人是怎么做复杂任务的?

想象你要装修房子:

错误方式

买点油漆刷墙...等等,好像应该先拆旧墙?算了先刷着...

正确方式
  1. 先列个计划:拆除→水电→泥瓦→木工→油漆→软装
  2. 按计划一步步来
  3. 完成一步,划掉一步

Agent 也应该这样。这就是 Plan-and-Execute 模式。其实严格俩说,我们上一个版本的 agent 叫做 ReAct Agent ,不信反翻回上面的文章看俺他其实可以自主多步调用工具了,这是模型的能力,当模型判断当前任务还没完成,会自动寻找可以完成的路径去做执行。

静下心来,我想了下,我们需要什么?

想清楚后,需求很简单:

  1. 会话持久化 —— 对话要存下来,下次打开能继续
  2. 计划能力 —— 能创建计划、追踪进度
  3. 状态管理 —— 知道哪些步骤做完了,哪些还没做

为了实现这个,我选择用 jsonl 文件来存储我的会话和 plan。

那么,我为什么用 JSONL?

其直接原因还是因为我看了 Claude Code 的实现,他就是用 jsonl 来存储会话的。

对话历史用什么格式存?

方案

优点

缺点

普通 JSON

简单

每次写入要读取→修改→写入整个文件

SQLite

查询强大

太重了,杀鸡用牛刀

JSONL

追加写入、崩溃友好

读取要遍历

我选了 JSONL。每行一个 JSON:

代码语言:javascript
复制
{"type":"meta","id":"abc123","title":"创建React项目","created":"..."}
{"type":"message","role":"user","content":"帮我创建项目","ts":"..."}
{"type":"message","role":"assistant","content":"好的,我来规划...","ts":"..."}
{"type":"tool_call","tool_calls":[...],"ts":"..."}

为什么?

  1. 1. 追加友好 —— fs.appendFileSync,不用读取整个文件
  2. 2. 崩溃安全 —— 程序崩了最多丢最后一行,不会整个文件坏掉
  3. 3. 足够简单 —— 不需要引入数据库依赖

第一个决策:存在哪?

一开始我把 sessions 放在项目目录下:

代码语言:javascript
复制
agent/
├── sessions/     ← 不对!
│   └── xxx.jsonl
└── index.js

这有问题:

  • 污染项目目录
  • 可能被误提交到 git

正确做法是放在用户目录:

代码语言:javascript
复制
const AGENT_HOME = path.join(os.homedir(), ".agent");
const SESSIONS_DIR = path.join(AGENT_HOME, "sessions");
// → ~/.agent/sessions/

这是 Unix 惯例。npm 用 ~/.npm,git 用 ~/.gitconfig,我们用 ~/.agent

第二个决策:Plan 怎么存?

最初我把 Plan 也存在 JSONL 里:

代码语言:javascript
复制
{"type":"plan","steps":[{"id":1,"task":"创建项目","status":"pending"}]}
{"type":"plan_update","stepId":1,"status":"done"}
{"type":"plan_update","stepId":2,"status":"done"}

问题

  • 更新一个步骤要追加一行
  • 读取当前状态要遍历所有行
  • 计划越改,记录越多

更好的做法:Plan 单独存成 JSON 文件,直接覆盖更新:

代码语言:javascript
复制
~/.agent/sessions/
├── 2024-01-15_abc123.jsonl      # 对话历史(追加)
└── 2024-01-15_abc123.plan.json  # 计划(覆盖)
代码语言:javascript
复制
// plan.json - 直接读写,状态实时
{
"steps":[
    {"id":1,"task":"创建项目","status":"done"},
    {"id":2,"task":"安装依赖","status":"pending"}
],
"updated":"2024-01-15T10:05:00Z"
}

原则:追加型数据用 JSONL,状态型数据用 JSON。

为了实现 planAgent ,我们需要有配套的工具才可以

给 Agent 加了三个新工具:

代码语言:javascript
复制
// 1. 创建计划
createPlan({ steps: ["步骤1", "步骤2", ...] })

// 2. 更新状态
updatePlanStep({ stepId: 1, status: "done", result: "项目创建成功" })

// 3. 查看计划
getPlan()

工具的 Schema 长这样:

代码语言:javascript
复制
export const createPlan = {
schema: {
    type: "function",
    function: {
      name: "createPlan",
      description: "创建执行计划。复杂任务时先规划再执行。",
      parameters: {
        type: "object",
        properties: {
          steps: {
            type: "array",
            items: { type: "string" },
            description: "计划的步骤列表",
          },
        },
        required: ["steps"],
      },
    },
  },
execute: async ({ steps }, context) => {
    context.createPlan(steps);
    return"📋 已创建执行计划:\n" + steps.map((s, i) =>`  ${i+1}. [ ] ${s}`).join("\n");
  },
};

关键在 description:告诉 AI 什么时候该用这个工具。

效果展示

图片
图片
图片
图片
图片
图片

整个过程完成下来,我们这个800 行的 agent 就可以创建一个完整的工程,并且跑起来项目了。

图片
图片

最神奇的是:我没写任何控制逻辑

AI 自己知道要先创建计划,然后一步步执行,完成一步就更新状态。这就是工具描述的力量。

在这个过程中,我学到了什么

1. 数据格式要匹配使用模式
  • 追加写入 → JSONL
  • 频繁更新 → JSON
  • 复杂查询 → SQLite
2. Plan 让 Agent 更可控

没有 Plan:AI 是个黑盒,你不知道它要做什么,无法自我驱动 有了 Plan:你能看到它的计划,能中断,能调整

4. 工具描述比代码更重要
代码语言:javascript
复制
description: "创建执行计划。复杂任务时先规划再执行。"

这一句话,决定了 AI 什么时候会用这个工具。Prompt Engineering 不只是写系统提示词,工具描述同样关键。

下一步我在思考能做啥

现在的 Agent 还缺什么?

  1. 上下文窗口管理 —— 对话太长时自动压缩,可以发现 Claude Code 这种工具都会会话压缩,我们还不具备
  2. 错误恢复 —— 某步失败时重试或跳过
  3. 多 Agent 协作 —— 规划 Agent + 执行 Agent 分离

但这些都是锦上添花。核心已经有了:一个能记忆、能规划、能执行的 Agent

需要源码?建议还是自己实现把,不实现一次,真的你很难发现这种乐趣~

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 别急,我们先想想人是怎么做复杂任务的?
    • 错误方式
    • 正确方式
  • 静下心来,我想了下,我们需要什么?
  • 那么,我为什么用 JSONL?
  • 第一个决策:存在哪?
  • 第二个决策:Plan 怎么存?
  • 为了实现 planAgent ,我们需要有配套的工具才可以
  • 效果展示
  • 在这个过程中,我学到了什么
    • 1. 数据格式要匹配使用模式
    • 2. Plan 让 Agent 更可控
    • 4. 工具描述比代码更重要
  • 下一步我在思考能做啥
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档