揭露 AI Agent 背后的运作原理和常见误解,帮助程序员理性认识 Agent 技术。130+ 社区互动,是理解 Agent 本质的必读内容。
很长一段时间以来,我一直有种感觉,AI Agent 被一种神秘的光晕所笼罩。没人真正知道它们在做什么,它们可能很快就要接管世界了,如果你想自己构建一个……嗯,显然你需要一个框架。
如果我告诉你这都不是真的呢?你可以用大约 80 行代码构建自己的 AI Agent。
我得承认,这周还不错。工作上发生了很多事。除此之外,我还收到了一封自动拒绝邮件,对应我提交的一个会议演讲。通常,这种事最多会占据我的思绪五分钟,因为会议拒绝只是这个行业的一部分。
但是……我其实被那个会议邀请了。"你已经被接受了,只需要在 CFP 中提交演讲详情。"因为有这个邀请,我婉拒了另外两个会议机会。算了,至少我现在 9 月份有空了。😉
不管怎样,生活还要继续。今天是我的生日,所以作为送给自己(也送给你们!)的小礼物,我写了这篇文章。😄 希望你会喜欢!
让我们直奔主题。
LangChain、CrewAI 或 Mastra 这样的框架并不是在玩魔法。它们简化了对话历史、工具执行、重试、降级等功能。
一旦你理解了底层机制,就会更容易判断何时框架才真正值得使用。即使你最后还是选择使用一个框架,你也会明白它在引擎盖下做的是什么。
所以我决定构建一个小演示,看看 AI Agent 实际需要多少代码。
我用 Node.js 写了一个 AI Agent,大约 80 行代码……好吧,核心循环确实只有约 80 行。还有工具、提供者抽象和一些周边逻辑。但是说句实话,"一个 80 行的 AI Agent"听起来听得多了。😄
这是仓库:
https://github.com/sylwia-lask/code-review-agent
既然今天是我的生日……如果你喜欢这个项目,可以给它一个 ⭐。当然,只有在你真的喜欢它的时候。😄
这个应用是一个简单的代码审查 Agent。嗯……不完全是这样。
认识 Steve:一位拥有 15 年代码审查经验的软件工程师。Steve 不会轻信任何事情。当然,他有时候可能有点讽刺……但很难反驳他的结论。
他的一个代码审查是这样的:
或者当你有空的 diff 时:
目前,Steve 审查本地 Git diff。这基本上意味着……他在审查自己。所以我想我已经构建了一个自愈 Agent 的原型,根据 @nitsancohen770 的说法,这个东西有一天会让我失业。
如你所见,我基本上是在帮助自动化自己失去工作。也许现在是时候开始考虑退休了。😄
在我之前的文章中,我拿那些声称 AI Agent 不过是一个循环的人开玩笑。嗯……我的 Agent 甚至不是 while 循环。它是一个 for 循环,因为我想保护自己不要意外地创建无限循环,并因 token 花费太多钱。😄
好吧,说实话,循环本身实际上没有做任何事情。它只是负责编排整个过程。但有趣的是,大多数 Agent 框架在引擎盖下做的东西也是相当类似的。
循环本身写起来很轻松。真正的挑战正好在你期望的地方。
构建一个 AI Agent 始于……选择一个 LLM。😄 这次我选择了 Gemini API,因为这类项目的 token 便宜得离谱。我绝对想用本地模型构建下一个版本,但……慢着。😄
我立即遇到了一个问题:某些 Gemini 模型过载了,所以我一直收到 503 响应。这意味着我必须实现框架通常开箱即用的东西——一个简单的重试机制。
我的重试机制有意很基础。生产框架通常提供更多功能,比如指数退避、抖动或自动降级到另一个模型。
下一个挑战当然是写出正确的 prompt。在那之后,一切都变得出乎意料地简单。
这比你想象的简单得多。
步骤 1:发送 prompt 和可用工具
我们向模型发送两样东西:
{
"model": "gemini-2.5-flash",
"contents": [
{
"role": "user",
"parts": [
{
"text": "Please review the current git diff."
}
]
}
],
"config": {
"systemInstruction": "You are Steve, a senior software engineer with 15 years of experience...",
"tools": [
{
"functionDeclarations": [
{
"name": "getDiff",
"description": "Get the git diff of the current repository...",
"parameters": {
"type": "OBJECT",
"properties": {},
"required": []
}
},
{
"name": "getFile",
"description": "Read a file from the repository...",
"parameters": {
"type": "OBJECT",
"properties": {
"path": {
"type": "STRING",
"description": "Path to the file relative to the repository root"
}
},
"required": ["path"]
}
},
{
"name": "listFiles",
"description": "List files and directories at a given path...",
"parameters": {
"type": "OBJECT",
"properties": {
"path": {
"type": "STRING",
"description": "Directory path relative to the repository root"
}
},
"required": ["path"]
}
}
]
}
]
}
}
步骤 2:等待模型的响应
模型可以用三种方式响应:
如果它返回纯文本,我们完成了:那就是我们最终的代码审查。如果它要求我们调用工具,我们进行到步骤 3。
例如,我们可能会收到:
{
"candidates": [
{
"content": {
"role": "model",
"parts": [
{
"text": "Let's see what damage we're dealing with today..."
},
{
"functionCall": {
"id": "call_001",
"name": "getDiff",
"args": {}
}
}
]
}
}
]
}
步骤 3:本地执行工具
现在轮到我们的应用了。
我们在本地执行请求的工具。例如,运行 git diff 或从仓库读取文件,然后将结果作为对话中的另一条消息发送回模型。
这个演示中可用的工具有:
换句话说,就是一个好的代码审查者需要的一切。😄
步骤 4:重复直到模型完成
然后我们简单地回到步骤 2。为了避免陷入无限循环,我将最大迭代次数限制为 10。
不过还有一个重要的细节。
看看下一个请求。注意我们是否在将整个对话历史发送回模型:
{
"contents": [
{
"role": "user",
"parts": [
{
"text": "Please review the current git diff."
}
]
},
{
"role": "model",
"parts": [
{
"text": "Let's see what damage we're dealing with today..."
},
{
"functionCall": {
"id": "call_001",
"name": "getDiff",
"args": {}
}
}
]
},
{
"role": "user",
"parts": [
{
"functionResponse": {
"id": "call_001",
"name": "getDiff",
"response": {
"result": "diff --git a/src/auth.ts b/src/auth.ts\n--- a/src/auth.ts\n+++ b/src/auth.ts\n@@ -12,7 +12,7 @@\n- if (password === storedHash) {\n+ if (password == storedHash) {\n"
}
}
}
]
}
]
}
就这样。LLM 决定使用哪个工具,以及何时完成。其他一切——执行工具、处理重试、强制迭代限制和编排循环——是我们应用的责任。
很简单,不是吗?如果你喜欢可视化,ChatGPT 为我们准备了一个 😉
我希望在将来至少写两篇后续文章。一篇关于将 Steve 连接到 MCP,另一篇关于用本地 LLM 替换托管模型。
但是……慢着。一步一步来。😄
如果你只是来这里学习如何构建 AI Agent 的,你现在可能可以停止阅读了。😄
这一部分是给好奇的人的。因为迟早有人会问:"Sylwia,你在说什么?你说你在构建自己的 AI Agent,但你只是在使用 Gemini SDK。你发送 JSON,得到 JSON 返回。"
而且,正如 @darkwiiplayer 经常指出的那样,LLM 基本上是一个非常复杂的下一个 token 预测器,不是某种神奇的 JSON 生成器。
那么……当我们向模型发送 JSON 时,它怎么知道该做什么?如果我们用的不是 Gemini,而是某个旧的本地 Llama 模型,会发生什么?
Gemini SDK 是否暗中预先添加了某个特殊的 prompt?或者是模型本身被训练了这个功能?
诚实的答案是我们不知道所有的细节。我们知道的是像 Gemini 和 GPT 这样的模型对工具调用有原生支持。SDK 负责正确格式化请求并与 API 通信,而模型本身理解工具声明,并可以在它认为需要的时候生成函数调用。
换句话说,如果我们拿一个更旧的 Llama 模型,我们仍然可以写一个 prompt,解释如何解释 JSON,并要求它用特定的 JSON 格式响应。
然后我们简单地调用 JSON.parse()……
……假设模型实际上返回有效的 JSON,而不是 Markdown、解释或它决定添加的几个"有帮助"的注释。😄
也就是说,值得一提的是,越来越多的新开源模型也开始原生支持工具调用。
说实话。现在是 2026 年。这个 Agent 主要是由……另一个 AI Agent 编写的。😄
由于我做了很长一段时间的 AWS Community Builder,我取消了 Claude Code 订阅,改用 Kiro:一个 AI IDE,内置支持多个 LLM,包括 Claude、GPT 和 Gemini。价格差不多,但由于该计划,我可以免费使用它。
到目前为止,我真的很喜欢它。感觉有点像是 VS Code 顶部的一个 Agent 驱动的层,所以我立即感到了宾至如归。我还有种感觉,我目前可能只在使用它能做的东西的 10%,所以我相当确定我以后会写更多关于它的内容。
现在我只是希望 AWS 最后能给我寄一些周边产品。😄 我特别梦想着他们的一件 T 恤。多年前,我们在波兰实际上有一个叫 AWS 的政党,所以我绝对很想看看一些年长的人的表情。😄
AWS……如果你在阅读这个……我在等待!!😄
如你所见,AI Agent 不一定要从框架开始。有时你只需要一个 LLM、工具、对话历史和一个简单的循环。其他一切都是便利、生产强化和生活质量的改进。
你觉得 Steve 怎么样?你觉得这种构建 AI Agent 的方法怎么样?😄
如果你喜欢这篇文章,你也可以在 LinkedIn 上关注我。
一些评论可能只对登录访问者可见。登录查看所有评论。
要采取进一步的行动,你可以考虑阻止此人和/或举报滥用。