首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >300 行代码,我从零手写了一个 Agent,抓住本质

300 行代码,我从零手写了一个 Agent,抓住本质

原创
作者头像
老码小张
发布2026-01-30 15:21:03
发布2026-01-30 15:21:03
2610
举报
文章被收录于专栏:玩转全栈玩转全栈

为什么要重复造轮子?这可能是你非常想问的,2025 年,Agent 框架遍地开花。LangChain、AutoGPT、CrewAI、Dify... 每周都有新工具出现,每个都宣称能让你"5 分钟构建 AI Agent"。现在非常火爆的 clawd.bot ,现在改名为了 moltbot,其实本质上就是一个 agent。(笑死,据说作者被 Claude 给告了,没办法改名了)

图片
图片

作为一个技术人,我肯定首选的是直接用他们,但是我更加期望了解他们,所以我需要自己造一个,哪怕是最最简单的实现,这会让我有一种掌控感,我能毫无保留的了解他内部的原理。

所以,上面 langchain这些 agent 框架,不是因为它们不好,而是因为我想搞清楚一件事:当这些框架都过时的时候,什么东西是不变的?

直接看看效果

查看时间
查看时间

查看时间

写一个小说
写一个小说

写一个小说

注意写小说,他会先看看当前目录,然后在目录下创建一个 ./novel.txt 的文件写入小说。这是不是和 cursor new 一个新的文件及其类似,没什么神神秘秘的。

更加复杂点的

检索内容
检索内容

检索内容

注意,检索内容,他会调用 rg 工具,如果你要复刻我实现,你需要

brew install ripgrep ,这个工具搜索文件内容不错,比 grep 更好用,感觉就是为了追这波 agent 而制造的。

变化的是工具,不变的是本质

回想一下,jQuery 火了,然后是 Angular,然后是 React,然后是 Vue,现在 Svelte 也在崛起。前端框架换了一茬又一茬,但 DOM 操作的本质没变过——你始终在操作一棵树。

Agent 也一样。

LangChain 可能会过时,AutoGPT 可能会被淘汰,但 Agent 的本质不会变:

代码语言:javascript
复制
用户输入 → LLM 思考 → 需要工具?
→ 是 → 执行工具 
→ 拿到结果 → 回到 LLM 思考
         ↓
         否 → 输出最终回复

这个循环,叫 ReAct(Reasoning + Acting)。不管框架怎么包装,底层都是这个循环。

我构建了什么

用 300 行 JavaScript,我实现了一个完整的 Agent:

代码语言:javascript
复制
agent/
├── index.js      # Agent 循环 + 流式输出
├── context.js    # 上下文管理(记忆)
├── llm.js        # LLM 客户端
└── tools/
    └── file.js   # 工具定义和实现

它能做什么?

  • • 对话,并记住之前说过什么
  • • 读写文件
  • • 用 ripgrep 搜索代码
  • • 流式输出(打字机效果)

不多,但每一行代码我都知道为什么要写

其实Agent 就是一个 while(true)

当我写完核心循环,我愣住了。就这?

代码语言:javascript
复制
async functionchat(userMessage) {
  context.addUserMessage(userMessage);

while (true) {
    const response = await llm.chat({
      messages: context.getMessages(),
      tools: getToolSchemas(),
    });

    // AI 想用工具
    if (response.tool_calls) {
      for (const call of response.tool_calls) {
        const result = awaitexecuteTool(call.name, call.args);
        context.addToolResult(result);
      }
      continue; // 继续循环,让 AI 看到工具结果
    }

    // AI 直接回复
    return response.content;
  }
}

就是一个 while(true),不断循环,直到 AI 决定不再调用工具。

所有框架,不管多复杂,核心都是这个。LangChain 的 AgentExecutor?本质上就是这个循环加上一堆抽象。

工具调用:告诉 AI "你能做什么"

工具就是一个 JSON Schema

代码语言:javascript
复制
{
  type: "function",
function: {
    name: "searchContent",
    description: "搜索文件内容,支持正则表达式",
    parameters: {
      type: "object",
      properties: {
        pattern: { type: "string", description: "搜索模式" },
        path: { type: "string", description: "搜索路径" }
      },
      required: ["pattern"]
    }
  }
}

你把这个 Schema 发给 LLM,它就"知道"自己能搜索文件了。当用户说"帮我找一下项目里所有的 TODO",AI 会自动调用这个工具。

没有魔法,就是把能力描述清楚

上下文管理:说实话这个比较难

简单的Agent 的"记忆"是怎么实现的?

代码语言:javascript
复制
messages = [
  { role: "system", content: "你是一个编程助手..." },
  { role: "user", content: "你好" },
  { role: "assistant", content: "你好!有什么可以帮你?" },
  { role: "user", content: "我叫小明" },
  { role: "assistant", content: "你好小明!" },
  { role: "user", content: "我叫什么?" },
  // AI 能回答"小明",因为历史都在这个数组里
]

每次调用 API,把这个数组全部发过去。AI 就"记住"了。

当然,这会越来越长,token 越来越贵。所以有了滑动窗口、摘要压缩、向量检索等策略。但本质没变——记忆就是把历史消息发给 AI

但是,这么简单肯定不够,这就需要上下文工程。

我们看看主流Agent 框架的做法

框架

策略

LangChain

提供多种 Memory 类:BufferMemory、SummaryMemory、VectorStoreMemory

AutoGPT

使用向量数据库 + 摘要

Claude/ChatGPT

滑动窗口 + 后台摘要(官方未公开细节)

Cursor

对长文件使用 semantic search 而非全部发送

当然,我们可以更具需要来实现,先从基本开始,在扩展。

流式输出:一个字一个字蹦出来

用户体验的关键。不是等 AI 全部想完再显示,而是边想边输出:

代码语言:javascript
复制
const stream = await llm.chat({ stream: true, ... });

for await (const chunk of stream) {
  process.stdout.write(chunk.content); // 不换行,逐字输出
}

就这么简单。stream: true,然后遍历流。

整个过程半小时,做完,我学到了什么

  1. 1. Agent = LLM + 工具 + 循环。没有更多了。
  2. 2. 工具调用不是魔法。就是把能力用 JSON 描述清楚,AI 就会用。
  3. 3. 记忆不是魔法。就是把历史消息发给 AI。
  4. 4. 框架的价值在于抽象,但抽象也是成本。当你不理解底层,抽象就是黑盒。
  5. 5. 300 行代码能做很多事。不需要引入 10 个依赖。

给同样想动手的人

如果你也想理解 Agent,我建议:

  1. 先不要用框架。用最原始的 API 调用,写一个能对话的程序。
  2. 加上记忆。就是一个数组,把历史消息存起来。
  3. 加一个工具。比如获取当前时间。体验一下 AI 是怎么"决定"调用工具的。
  4. 加上循环。让 AI 能连续调用多个工具,最后给出答案。

做完这四步,你就理解了 Agent 的 80%。剩下的 20% 是优化:更好的 prompt、更智能的记忆管理、更多的工具、更好的错误处理。

最后

技术圈永远有新工具。追不完的。

但如果你能抓住不变的本质,新工具出来的时候,你会发现:哦,这不就是那个东西换了个壳吗。

这就是我手写 Agent 的原因。

不是为了重复造轮子,而是为了知道轮子长什么样

需要源码?你还是先自己写下吧,写不出来再找我。

这就完了吗,没有,我想再接入下mcp,skills,再继续做一个能迭代特性的coding agent,但是我不会用他来做真实开发。因为有更好的,还是那句话,这个项目就是用极简的方式帮我了解现在这层出不穷的工具的本质。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 直接看看效果
  • 变化的是工具,不变的是本质
  • 我构建了什么
    • 其实Agent 就是一个 while(true)
    • 工具调用:告诉 AI "你能做什么"
    • 上下文管理:说实话这个比较难
      • 我们看看主流Agent 框架的做法
    • 流式输出:一个字一个字蹦出来
    • 整个过程半小时,做完,我学到了什么
    • 给同样想动手的人
    • 最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档