为什么要重复造轮子?这可能是你非常想问的,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 的本质不会变:
用户输入 → LLM 思考 → 需要工具?
→ 是 → 执行工具
→ 拿到结果 → 回到 LLM 思考
↓
否 → 输出最终回复这个循环,叫 ReAct(Reasoning + Acting)。不管框架怎么包装,底层都是这个循环。
用 300 行 JavaScript,我实现了一个完整的 Agent:
agent/
├── index.js # Agent 循环 + 流式输出
├── context.js # 上下文管理(记忆)
├── llm.js # LLM 客户端
└── tools/
└── file.js # 工具定义和实现它能做什么?
不多,但每一行代码我都知道为什么要写。
当我写完核心循环,我愣住了。就这?
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?本质上就是这个循环加上一堆抽象。
工具就是一个 JSON Schema。
{
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 的"记忆"是怎么实现的?
messages = [
{ role: "system", content: "你是一个编程助手..." },
{ role: "user", content: "你好" },
{ role: "assistant", content: "你好!有什么可以帮你?" },
{ role: "user", content: "我叫小明" },
{ role: "assistant", content: "你好小明!" },
{ role: "user", content: "我叫什么?" },
// AI 能回答"小明",因为历史都在这个数组里
]每次调用 API,把这个数组全部发过去。AI 就"记住"了。
当然,这会越来越长,token 越来越贵。所以有了滑动窗口、摘要压缩、向量检索等策略。但本质没变——记忆就是把历史消息发给 AI。
但是,这么简单肯定不够,这就需要上下文工程。
框架 | 策略 |
|---|---|
LangChain | 提供多种 Memory 类:BufferMemory、SummaryMemory、VectorStoreMemory |
AutoGPT | 使用向量数据库 + 摘要 |
Claude/ChatGPT | 滑动窗口 + 后台摘要(官方未公开细节) |
Cursor | 对长文件使用 semantic search 而非全部发送 |
当然,我们可以更具需要来实现,先从基本开始,在扩展。
用户体验的关键。不是等 AI 全部想完再显示,而是边想边输出:
const stream = await llm.chat({ stream: true, ... });
for await (const chunk of stream) {
process.stdout.write(chunk.content); // 不换行,逐字输出
}就这么简单。stream: true,然后遍历流。
如果你也想理解 Agent,我建议:
做完这四步,你就理解了 Agent 的 80%。剩下的 20% 是优化:更好的 prompt、更智能的记忆管理、更多的工具、更好的错误处理。
技术圈永远有新工具。追不完的。
但如果你能抓住不变的本质,新工具出来的时候,你会发现:哦,这不就是那个东西换了个壳吗。
这就是我手写 Agent 的原因。
不是为了重复造轮子,而是为了知道轮子长什么样。
需要源码?你还是先自己写下吧,写不出来再找我。
这就完了吗,没有,我想再接入下mcp,skills,再继续做一个能迭代特性的coding agent,但是我不会用他来做真实开发。因为有更好的,还是那句话,这个项目就是用极简的方式帮我了解现在这层出不穷的工具的本质。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。