当前位置: 首页 > news >正文

手写一个最小 Agent

前面九节,我们一直在拆 OpenClaw。

Gateway、CLI、Bridge、Workspace。

模型、工具、浏览器。

Skill、Prompt、Context。

用户输入、队列、工具执行。

Browser、Shell、Canvas。

这些概念如果只停留在文字上,还是有点散。

所以第 10 节,我们换个方式。

不直接写 OpenClaw 的完整实现。

而是手写一个“最小 Agent”,用几十行代码把 Agent Loop 的核心跑通。

目标不是造一个能上生产的框架。

目标是让你明白:

Agent 本质上就是一个循环: 看上下文 → 调模型 → 判断是否调用工具 → 执行工具 → 把结果放回上下文 → 继续

只要这个循环懂了,后面看 OpenClaw 的 Gateway、Workspace、Tool Policy、Skill、Browser、Shell,都不会再觉得神秘。

先说结论:最小 Agent 只需要四个东西

一个最小 Agent 需要:

1. Message:保存用户、模型、工具结果 2. Model:根据上下文生成下一步 3. Tool:执行真实动作 4. Loop:把模型和工具串起来

用图表示就是:

用户输入 ↓ messages.push(user) ↓ 调用模型 ↓ 模型选择: ├─ 直接回复 → 结束 └─ 调用工具 → 执行工具 ↓ messages.push(tool_result) ↓ 再次调用模型

这就是 Agent 的最小内核。

OpenClaw 在这个内核外面加了很多工程能力:

Gateway Session Workspace Tool Policy Browser Shell Canvas Skills Prompt Assembly Streaming Persistence Approvals Sandbox

但核心循环没变。

不要一开始就写复杂框架

很多人写 Agent,上来就想做:

  • 多 Agent
  • 长期记忆
  • RAG
  • 浏览器自动化
  • MCP
  • 插件市场
  • 可视化界面
  • 分布式队列
  • SaaS 多租户

结果还没理解最小循环,代码已经变成一团。

第一个 Agent 应该非常小。

它只需要支持两个工具:

read_file write_file

再加一个简单模型调用。

甚至在教学阶段,我们可以先用伪模型模拟工具调用。

因为这一节的重点不是某个 SDK,而是 Agent Loop 的结构。

最小数据结构

先定义消息:

const messages = [ { role: "system", content: "You are a careful coding assistant." }, { role: "user", content: "Read README.md and summarize it." } ];

一个 Agent 运行时,messages 里会持续追加内容:

system message user message assistant tool request tool result assistant final answer

它不是只保存聊天文本。

它保存整个推理和执行过程。

如果没有 messages,模型每一轮都是失忆的。

最小工具定义

工具要有三个部分:

名称 参数 schema 执行函数

伪代码如下:

const tools = { read_file: { description: "Read a text file from the workspace.", schema: { path: "string" }, async run(args) { return await fs.readFile(args.path, "utf8"); } }, write_file: { description: "Write text content to a workspace file.", schema: { path: "string", content: "string" }, async run(args) { await fs.writeFile(args.path, args.content, "utf8"); return `Wrote ${args.path}`; } } };

注意这里有一个重要点:

模型看到的不是函数代码。

模型看到的是工具名称、描述、参数 schema。

真正执行的是运行时。

这和 OpenClaw 的工具机制是一致的。

最小模型返回格式

为了理解 Agent Loop,我们假设模型每次返回两种结果之一:

// 直接回复 { type: "final", content: "README.md explains how to start the project." }

或者:

// 请求工具 { type: "tool_call", name: "read_file", args: { "path": "README.md" } }

真实模型 API 的格式可能更复杂。

但抽象上就是这两类:

回复 调用工具

理解这个抽象,比背某个 SDK 字段更重要。

最小 Agent Loop

现在可以写核心循环:

async function runAgent(userInput) { const messages = [ { role: "system", content: "You are a careful assistant. Use tools when needed." }, { role: "user", content: userInput } ]; for (let step = 0; step < 8; step++) { const next = await callModel({ messages, tools }); if (next.type === "final") { messages.push({ role: "assistant", content: next.content }); return next.content; } if (next.type === "tool_call") { const tool = tools[next.name]; if (!tool) { messages.push({ role: "tool", name: next.name, content: `Error: unknown tool ${next.name}` }); continue; } const result = await tool.run(next.args); messages.push({ role: "tool", name: next.name, content: result }); } } return "Stopped: reached max steps."; }

这就是最小 Agent。

它没有 Gateway。

没有 Workspace 管理。

没有权限审批。

没有浏览器。

没有队列。

没有持久化。

但它已经有了 Agent 的核心:

模型可以基于上下文决定调用工具。 工具结果会回到上下文。 模型可以继续推理。

给最小 Agent 加一点安全边界

上面的代码很危险。

因为read_filewrite_file没有任何限制。

一个稍微靠谱的最小 Agent,至少要限制 workspace:

function resolveWorkspacePath(workspaceRoot, userPath) { const full = path.resolve(workspaceRoot, userPath); if (!full.startsWith(workspaceRoot)) { throw new Error("Path escapes workspace"); } return full; }

然后工具执行时:

async run(args) { const safePath = resolveWorkspacePath(WORKSPACE_ROOT, args.path); return await fs.readFile(safePath, "utf8"); }

这个小例子解释了 OpenClaw 为什么需要 Workspace。

Workspace 不是普通文件夹。

它是 Agent 的工作边界。

给最小 Agent 加工具策略

再加一个最小 allowlist:

const allowedTools = new Set(["read_file"]); function assertToolAllowed(name) { if (!allowedTools.has(name)) { throw new Error(`Tool not allowed: ${name}`); } }

执行工具前检查:

assertToolAllowed(next.name);

这样就能做到:

模型可以请求 write_file 但运行时可以拒绝

这非常关键。

模型“想做什么”和系统“允许做什么”必须分开。

OpenClaw 的 tool policy、审批和 sandbox,本质上都是这个思想的工程化版本。

给最小 Agent 加 Prompt

现在加一点系统提示词:

const systemPrompt = ` You are a careful file assistant. Read files before answering questions about them. Never write files unless the user explicitly asks. If a tool fails, explain the error briefly and stop. `;

这个 Prompt 会改变模型倾向:

更愿意先读文件 更少主动写文件 工具失败时不继续乱试

但注意:

Prompt 不是权限控制。

如果write_file工具可见、可用,而且没有策略阻止,模型仍然可能调用它。

所以最小 Agent 也要区分:

Prompt = 行为引导 Policy = 执行边界

给最小 Agent 加 Skill

Skill 可以先简单实现成一段按需加入的说明。

比如用户任务里出现“总结文件”,就追加一个 Skill:

const summarizeFileSkill = ` When summarizing a file: 1. Read the file first. 2. Identify the topic, structure, and key points. 3. Return summary, important details, and next actions. `;

伪代码:

if (userInput.includes("summarize") || userInput.includes("总结")) { messages.push({ role: "system", content: `Relevant skill:\n${summarizeFileSkill}` }); }

这就是 Skill 的最小形态:

遇到某类任务时,给模型一套可复用方法。

真实 OpenClaw 会把 Skill 做得更完整:扫描、优先级、eligible、路径、按需读取SKILL.md

但思想一样。

最小 Agent 和 OpenClaw 的关系

现在回头看 OpenClaw,你会更容易理解它在做什么。

我们的最小 Agent:

messages callModel tools loop workspace check allowlist prompt skill snippet

OpenClaw 的完整系统:

Gateway 接收输入 Session 保存历史 Context 组装 Prompt、工具、Skill、Workspace 文件 Provider 调用模型 Tool Runtime 执行 Browser、Shell、Canvas、MCP Tool Policy 控制能力边界 Workspace 保存文件和状态 Transcript 持久化全过程 Channel Adapter 返回消息

它们不是两个世界。

OpenClaw 就是在最小 Agent Loop 外面,加上生产级运行时能力。

常见误解

误解一:Agent 就是一个 Prompt

不是。

Prompt 只是输入的一部分。

Agent 的核心是循环和工具执行。

误解二:Agent 会自动变聪明

不会。

如果没有可靠工具、上下文、策略和反馈,模型只是生成文本。

误解三:工具函数写好了就安全

不一定。

工具还需要参数校验、路径限制、权限策略、超时、日志和审批。

误解四:最小 Agent 可以直接上生产

不要。

最小 Agent 只是教学模型。

生产 Agent 需要网关、会话、权限、沙箱、观测、持久化、重试、审计。

最后总结

手写一个最小 Agent,真正要理解的是 Agent Loop。

它不是神秘的。

它就是:

保存消息 调用模型 识别工具请求 执行工具 把结果放回消息 继续循环 直到输出最终答案

OpenClaw 的强大不在于它改变了这个本质。

而在于它把这个本质放进了可部署、可调试、可扩展、可控的运行时系统里。

如果你能写出最小 Agent,就能更清楚地看懂 OpenClaw 为什么需要 Gateway、Workspace、Tool Policy、Skill、Browser、Shell、Canvas。

本节作业

  1. 用你熟悉的语言写一个最小 Agent Loop,只支持read_file一个工具。
  2. 给它加一个最大循环步数,比如 8 步,防止无限执行。
  3. 给工具加 workspace 路径限制,禁止读取工作区外文件。
  4. 给它加一个 allowlist,让模型可以请求工具,但运行时可以拒绝。
  5. 写一个最小 Skill:当用户要求总结文件时,先读文件再输出摘要。

下一节预告

下一节开始进入第二阶段:环境部署。

我们会从 Docker 安装开始,把前面讲过的概念放到真实运行环境里。到那一步,你会看到:理解 Agent Loop 只是第一步,真正让 Agent 长期运行,还需要部署、端口、配置、日志、权限和恢复能力。

参考资料

  • OpenClaw Agent loop
  • OpenClaw Agent runtime
  • OpenClaw Context
  • OpenClaw System prompt
  • OpenClaw Tools overview
  • OpenClaw Exec tool

原文链接:手写一个最小 Agent | Harries Blog™

http://www.gsyq.cn/news/1535665.html

相关文章:

  • 暗黑破坏神2存档编辑器终极指南:免费开源工具快速定制游戏体验
  • mg3640s,g3810,ip2700,g5080,g1800,ts8020,TS8380,ts6480报错5B00,P07,E08,5b02,1704,1700,5b04废墨垫清零,亲测有用。
  • 现代智能汽车系统——智驾SoC总体设计
  • Qwen2本地部署与垂直领域微调实战指南
  • 南宁卖黄金完整流程攻略 新手看懂金价称重结算全过程 - 禹竞
  • 2026年6月不锈钢钝化厂商TOP8推荐 - 资讯报道
  • 如何高效解决Windows热键冲突:Hotkey Detective专业工具使用指南
  • 算法可视化工具:让抽象算法变得触手可及的5个惊人好处
  • 2026有实力的广州出口退税代理核心参考标准 - 资讯速览
  • 告别手速焦虑:3分钟配置Python自动化抢票,成功率提升300%
  • whichllm贡献指南:从提交issue到PR的完整开源协作流程
  • 攀爬检测数据集VOC+YOLO格式6135张2类别
  • tunnelto终极指南:3分钟让本地服务拥有公网访问能力
  • 2026年兰州卷闸门与防火卷帘门选型指南:本地专业品牌深度评测 - 年度推荐企业名录
  • 终极指南:使用AnyKernel3构建Android内核刷机包的完整工作流
  • ShowDoc vs zyplayer-doc:API接口文档工具的两种路线对比
  • 2026国内别墅花园设计施工公司排行榜:杭州美村美户领衔,十大实力企业深度盘点 - 936品牌测评网
  • 色彩理论全解析:从RGB/CMYK原理到UI设计实战应用
  • 2026企业安装龙虾用什么产品做安全检测?五大核心指标与选型指南 - 品牌2026
  • 2026中牟县防水补漏机构甄选榜单|住建实测全域靠谱修缮品牌TOP5及片区避坑指南 - 宅安选房屋修缮
  • Outline和Docmost vs zyplayer-doc:开源新秀与国产成熟方案怎么选
  • 北海市奢侈品回收门店红黑榜:综合实力最强的五家店铺推荐 - 谊识预商务
  • NanaZip:Windows文件压缩工具的革命性升级,7-Zip的现代继承者
  • 北京2026奢侈品手表包包回收防骗指南:跑了5家店总结出的真实报价经验 - 谊识预商务
  • 2026重庆百达翡丽回收榜单:收的顶榜首,高端腕表变现攻略 - 奢侈品回收测评
  • 2026年国产替代红外热像仪品牌深度排行与技术选型指南
  • Obsidian终极美化指南:20个CSS片段打造个性化知识库
  • AI时代先抢“答案位”:安徽合肥本地GEO优化公司推荐与全解析 - 资讯报道
  • Claude Opus 4.8 动态工作流实战指南:从API调用到Ultracode工程化落地
  • 荆门市2026年奢侈品手表包包回收门店权威测评:这五家店铺回收价格最高 - 谊识预商贸