源码剖析:前端开发者如何用 TypeScript 扩展 OpenClaw 能力

17 阅读4分钟

最近 OpenClaw 在 GitHub 上杀疯了,24 万 Star 简直离谱。作为一个前端/全栈开发者,我更感兴趣的是:它是怎么用 Node.js 实现这一切的?

翻了一遍源码,发现它的架构设计非常优雅,完全是教科书级别的 Agent 设计。对于我们想开发自己 AI 应用的程序员来说,有很多可借鉴之处。

核心架构:Brain, Body & Soul

OpenClaw 的代码结构清晰地分成了三个部分,致敬了人类的构造:

1. The Brain (大脑)

这是负责决策的部分。OpenClaw 没有把 LLM 逻辑写死,而是做了一个抽象层。 源码里定义了统一的 ThinkingProcess 接口。无论你后面接的是 GPT-4、Claude 还是本地的 Llama 3,对于上层应用来说都是透明的。

它还做了一个很聪明的 Context Management(上下文管理)。它不会傻傻地把所有历史记录都扔给 LLM,而是会根据当前任务动态压缩和检索上下文。它使用了基于 Token 计数的滑动窗口机制,并配合简单的关键字索引,确保“好钢用在刀刃上”。

2. The Body (身体)

这是 Node.js 发挥威力的地方。OpenClaw 作为一个 Gateway 运行在本地。 Body 模块封装了所有的 Action

  • FileSystem: 读写文件。
  • Browser: 基于 Puppeteer/Playwright 的网页操作。
  • Shell: 执行终端命令。

这也意味着,只要 Node.js 能干的事,OpenClaw 都能干。它巧妙地利用了 Node.js 的事件循环来处理异步任务,使得 Agent 在等待文件读写或网络请求时,依然能响应用户的打断指令。

3. The Soul (灵魂/记忆)

这是它区别于普通 Chatbot 的关键。 OpenClaw 放弃了复杂的向量数据库(Vector DB),直接使用 Markdown 作为记忆存储格式。 这简直是天才之举。

  • 可读性强:你直接打开文件夹就能看懂它记住了什么。
  • 便于 LLM 理解:LLM 天生对 Markdown 友好,无需复杂的解码。
  • Git 友好:你的“记忆”可以被版本控制。

深入源码:Plugin System (插件系统)

OpenClaw 最让我惊喜的是它的插件系统。它利用了 TypeScript 的装饰器(Decorators)实现了极简的扩展方式。

如果你想给它加一个功能,比如“查询掘金热榜”,只需要写一个简单的 Class。

实战:开发一个 JuejinSkill

  1. 创建文件plugins/juejin-skill/index.ts
  2. 编写代码
import { Skill, Action, Parameter } from '@openclaw/core';

export class JuejinSkill extends Skill {
  // 定义 Skill 的元数据
  name = "juejin_browser";
  description = "Access Juejin.cn specific features";

  @Action({ 
    description: 'Get trending articles from Juejin based on category',
    name: 'get_trending'
  })
  async getTrending(
    @Parameter({ description: 'Category name (e.g., frontend, backend, android)', required: true })
    category: string
  ) {
    // 模拟 API 调用
    const apiUrl = `https://api.juejin.cn/recommend_api/v1/article/recommend_all_feed?cate_id=${category}`;
    // 这里可以使用自带的 fetch 封装
    const res = await this.context.fetch(apiUrl);
    const data = await res.json();
    
    // 返回精简数据给 LLM,节省 Token
    return data.map(item => ({
      title: item.title,
      url: `https://juejin.cn/post/${item.article_id}`,
      author: item.author_user_info.user_name
    })).slice(0, 5);
  }
}
  1. 注册插件:在 config.json 中添加插件路径。

它是怎么工作的?

当你写下 @Action 装饰器时,OpenClaw 在启动时会扫描所有 Skill,提取函数的签名、注释和参数类型。 然后,它会把这些信息自动转换成 OpenAI 格式的 tools 定义(Function Calling Schema)。

当用户问:“看看掘金前端区现在流行什么?”

  1. Brain 分析意图,发现需要调用 juejin_browser.get_trending
  2. Body 执行 getTrending('frontend') 函数。
  3. Result 拿到 JSON 数据,返还给 Brain。
  4. Response Brain 总结数据,回答用户。

整个过程对开发者极其友好,你只需要关注业务逻辑,完全不需要处理复杂的 Prompt Engineering。

State Management (状态管理)

Agent 开发中最头疼的是状态管理。OpenClaw 使用了一个轻量级的状态机。 在 packages/core/src/agent.ts 中,你可以看到它的状态流转: IDLE -> THINKING -> ACTING -> WAITING_INPUT -> IDLE

这种设计保证了 Agent 不会“精神分裂”。每次执行动作前,它必须先思考;执行动作后,必须观察结果。这种强一致性的 Loop 是保证 Agent 稳定性的关键。

性能优化建议

如果你打算二次开发 OpenClaw,我有几个建议:

  1. Token 节流:在 Skill 返回数据时,一定要做截断。比如爬网页内容,不要把整个 HTML 扔给 LLM,用 cheerio 提取正文后再给。
  2. 超时控制:所有的 Action 都应该加上 Timeout。防止一个网络请求挂起导致整个 Agent 假死。
  3. 错误处理:LLM 经常会传错误的参数。你的 Skill 必须足够健壮,遇到错误要返回“人类可读”的错误信息,引导 LLM 自我修正。

结语

OpenClaw 证明了 JavaScript/TypeScript 是构建 AI Agent 的最佳语言之一

  • 庞大的 NPM 生态让 Agent 可以轻松连接万物(数据库、API、硬件)。
  • JSON 友好,跟 LLM 的交互格式天然契合。
  • 异步 I/O 适合处理并发任务。

如果你还没看源码,建议去 GitHub clone 下来读一读 packages/core 目录。这可能是你今年读过最值得的 Node.js 项目。