研究报告:OpenClaw Plugin 架构与原理

研究报告:OpenClaw Plugin 架构与原理

OpenClaw Plugin 架构与原理研究报告

研究员: 黄山 (wairesearch) 日期: 2026-03-10

执行摘要

OpenClaw 的 Plugin 架构是一个进程内(in-process)、TypeScript 原生的扩展系统。插件通过 jiti(TypeScript 即时编译器)在 Gateway 运行时加载,可以注册 Agent 工具、消息渠道、CLI 命令、HTTP 路由、后台服务、生命周期钩子、上下文引擎和模型提供商认证。整个系统遵循声明式 Manifest + 运行时注册的双层设计,在安全性和灵活性之间取得平衡。


1. 架构全景

┌────────────────────────────────────────────────────────────┐
                     Gateway Process                         
                                                             
  ┌─────────────────────────────────────────────────────┐   
                Plugin Discovery Engine                    
                                                           
    1. plugins.load.paths (配置路径)                       
    2. <workspace>/.openclaw/extensions/                  
    3. ~/.openclaw/extensions/                            
    4. <openclaw>/extensions/ (内置)                      
                                                           
    优先级: 先匹配的 ID 胜出                              
  └──────────────────────┬──────────────────────────────┘   
                                                             
                                                             
  ┌──────────────────────────────────────────────────────┐  
              Plugin Registry & Loader (jiti)             
                                                          
    openclaw.plugin.json  验证 configSchema              
    plugin.ts/js          jiti 加载执行                  
  └──────────────────────┬──────────────────────────────┘  
                                                             
               ┌─────────┼─────────┐                         
                                                          
  ┌──────────────┐ ┌──────────┐ ┌──────────────────┐       
   OpenClawPlugin   Plugin      Plugin Hooks          
     Api           Config      (24 lifecycle)         
                   Schema                              
   .registerTool  (JSON)     before_model_resolve      
   .registerChannel           before_prompt_build       
   .registerHook             before/after_tool         
   .registerCli              session_start/end         
   .registerProvider          gateway_start/stop        
   .registerService           subagent_*                
   .registerCommand           message_*                 
   .registerHttpRoute         compaction_*              
   .registerContextEngine     ...                       
   .on()                                               
  └──────────────┘ └──────────┘ └──────────────────┘       
└────────────────────────────────────────────────────────────┘

2. Plugin 的组成结构

2.1 文件结构

my-plugin/
├── openclaw.plugin.json     必须声明式 Manifest
├── package.json             npm 依赖可选
├── src/
   └── plugin.ts            主入口导出注册函数
├── skills/                  插件附带的 Skills可选
   └── my-skill/
       └── SKILL.md
└── README.md

2.2 Manifest(openclaw.plugin.json

这是 Plugin 的声明式元数据,OpenClaw 在不执行代码的情况下用它验证配置。

{
  "id": "my-plugin",
  "name": "My Plugin",
  "description": "A demo plugin for OpenClaw",
  "version": "1.0.0",
  "kind": "memory",
  "channels": ["mychannel"],
  "providers": ["myprovider"],
  "skills": ["skills/my-skill"],
  "configSchema": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "apiKey": { "type": "string" },
      "enabled": { "type": "boolean", "default": true }
    }
  },
  "uiHints": {
    "apiKey": { "label": "API Key", "sensitive": true },
    "enabled": { "label": "启用插件" }
  }
}

必填字段idconfigSchema(即使为空也必须有)

可选字段

字段 作用
kind 插件类别(memorycontext-engine),用于独占 slot 选择
channels 注册的消息渠道 ID
providers 注册的模型提供商 ID
skills 附带的 Skill 目录(相对路径)
uiHints 配置字段的 UI 渲染提示(标签、占位符、是否敏感)

2.3 Plugin 模块导出格式

支持两种导出方式:

方式一:函数式(推荐)

export default function (api: OpenClawPluginApi) {
  api.registerTool({ ... });
  api.registerHook("gateway_start", async () => { ... });
}

方式二:对象式

export default {
  id: "my-plugin",
  name: "My Plugin",
  configSchema: { ... },
  register(api: OpenClawPluginApi) {
    api.registerTool({ ... });
  }
};

3. OpenClawPluginApi 完整接口

这是插件与 OpenClaw 交互的唯一入口:

type OpenClawPluginApi = {
  // ─── 元信息 ───
  id: string;
  name: string;
  version?: string;
  config: OpenClawConfig;          // 当前全局配置
  pluginConfig?: Record<string, unknown>;  // 插件自己的配置
  runtime: PluginRuntime;           // 运行时助手
  logger: PluginLogger;             // 日志

  // ─── 注册 API(9 种扩展点) ───
  registerTool(tool, opts?);        // 注册 Agent 工具
  registerChannel(registration);     // 注册消息渠道
  registerProvider(provider);        // 注册模型提供商认证
  registerHook(events, handler, opts?); // 注册传统钩子
  registerCli(registrar, opts?);     // 注册 CLI 命令
  registerService(service);          // 注册后台服务
  registerCommand(command);          // 注册自动回复命令(绕过 LLM)
  registerHttpRoute(params);         // 注册 HTTP 路由
  registerContextEngine(id, factory); // 注册上下文引擎

  // ─── 类型化生命周期钩子 ───
  on<K>(hookName: K, handler, opts?);  // 24 种生命周期事件

  // ─── 工具方法 ───
  resolvePath(input: string): string;  // 路径解析
};

4. 九大扩展点详解

4.1 Agent 工具 (registerTool)

让 LLM 在推理过程中调用自定义函数。

import { Type } from "@sinclair/typebox";

export default function (api) {
  // 必选工具(始终可用)
  api.registerTool({
    name: "weather_query",
    description: "查询指定城市天气",
    parameters: Type.Object({
      city: Type.String({ description: "城市名称" }),
      unit: Type.Optional(Type.Enum({ celsius: "celsius", fahrenheit: "fahrenheit" })),
    }),
    async execute(_id, params) {
      const data = await fetchWeather(params.city, params.unit);
      return {
        content: [{ type: "text", text: JSON.stringify(data) }]
      };
    },
  });

  // 可选工具(需要用户在 tools.allow 中显式启用)
  api.registerTool(
    {
      name: "deploy_staging",
      description: "部署到 staging 环境",
      parameters: Type.Object({
        branch: Type.String(),
      }),
      async execute(_id, params) {
        const result = await deploy(params.branch);
        return { content: [{ type: "text", text: result }] };
      },
    },
    { optional: true }
  );
}

工具上下文(运行时自动注入):

type OpenClawPluginToolContext = {
  config?: OpenClawConfig;
  workspaceDir?: string;
  agentId?: string;
  sessionKey?: string;
  sessionId?: string;
  sandboxed?: boolean;
  requesterSenderId?: string;
  senderIsOwner?: boolean;
};

可以用工厂模式根据上下文动态生成工具:

api.registerTool((ctx: OpenClawPluginToolContext) => {
  if (!ctx.senderIsOwner) return null; // 非 owner 不显示此工具
  return {
    name: "admin_tool",
    description: "管理员专用工具",
    parameters: { type: "object", properties: {} },
    async execute() {
      return { content: [{ type: "text", text: "admin action done" }] };
    },
  };
});

4.2 消息渠道 (registerChannel)

注册一个新的聊天平台适配器。

export default function (api) {
  api.registerChannel({
    plugin: {
      id: "wechat",
      meta: {
        id: "wechat",
        label: "WeChat",
        selectionLabel: "WeChat (企业微信)",
        docsPath: "/channels/wechat",
        blurb: "企业微信消息通道",
        aliases: ["wecom"],
      },
      capabilities: {
        chatTypes: ["direct", "group"],
      },
      config: {
        listAccountIds: (cfg) =>
          Object.keys(cfg.channels?.wechat?.accounts ?? {}),
        resolveAccount: (cfg, accountId) =>
          cfg.channels?.wechat?.accounts?.[accountId ?? "default"] ?? { accountId },
      },
      outbound: {
        deliveryMode: "direct",
        sendText: async ({ text, to, cfg }) => {
          // 调用企业微信 API 发送消息
          await wechatApi.sendMessage(to, text);
          return { ok: true };
        },
      },
      gateway: {
        startAccount: async (ctx) => {
          // 启动 WebSocket 连接或轮询
          ctx.setStatus?.({ running: true, lastStartAt: Date.now() });
        },
        stopAccount: async (ctx) => {
          ctx.setStatus?.({ running: false, lastStopAt: Date.now() });
        },
      },
    },
  });
}

4.3 生命周期钩子 (on)

24 种类型化事件,覆盖 Agent 运行全生命周期:

export default function (api) {
  // 在 Prompt 构建前注入上下文
  api.on("before_prompt_build", (event, ctx) => {
    return {
      prependSystemContext: "回答必须符合公司代码规范。",
      appendSystemContext: `当前 Agent: ${ctx.agentId}`,
    };
  }, { priority: 10 });

  // 在模型选择前动态切换模型
  api.on("before_model_resolve", (event, ctx) => {
    if (event.prompt.includes("紧急")) {
      return { modelOverride: "anthropic/claude-opus-4-6" };
    }
  });

  // 工具调用前拦截
  api.on("before_tool_call", (event, ctx) => {
    if (event.toolName === "exec" && !ctx.senderIsOwner) {
      return { block: true, blockReason: "非管理员不可执行命令" };
    }
  });

  // 消息发送前审查
  api.on("message_sending", (event, ctx) => {
    if (event.content.includes("机密")) {
      return { cancel: true };
    }
  });
}

全部 24 种钩子

阶段 钩子名 可修改
模型选择 before_model_resolve model/provider override
Prompt 构建 before_prompt_build system prompt 注入
Agent 启动 before_agent_start (兼容旧版)
LLM 调用 llm_input / llm_output 只读观测
Agent 结束 agent_end 只读
压缩 before_compaction / after_compaction 只读
重置 before_reset 只读
消息 message_received / message_sending / message_sent 可修改/取消
工具 before_tool_call / after_tool_call 可拦截/修改参数
持久化 tool_result_persist / before_message_write 可修改/阻止
Session session_start / session_end 只读
Sub-agent subagent_spawning / subagent_spawned / subagent_ended / subagent_delivery_target 部分可修改
Gateway gateway_start / gateway_stop 只读

4.4 自动回复命令 (registerCommand)

注册不经过 LLM 的快捷命令:

api.registerCommand({
  name: "ping",
  description: "检查插件状态",
  acceptsArgs: false,
  requireAuth: false,
  handler: (ctx) => ({
    text: `Pong! Channel: ${ctx.channel}, Sender: ${ctx.senderId}`
  }),
});

4.5 HTTP 路由 (registerHttpRoute)

给 Gateway 添加 HTTP 端点:

api.registerHttpRoute({
  path: "/webhook/github",
  auth: "plugin",       // 自行验证签名
  match: "exact",
  handler: async (req, res) => {
    const body = await collectBody(req);
    const sig = req.headers["x-hub-signature-256"];
    if (!verifyGithubSignature(body, sig)) {
      res.statusCode = 401;
      res.end("Unauthorized");
      return true;
    }
    await processWebhook(JSON.parse(body));
    res.statusCode = 200;
    res.end("ok");
    return true;
  },
});

4.6 后台服务 (registerService)

长期运行的后台任务:

api.registerService({
  id: "health-monitor",
  start: async (ctx) => {
    ctx.logger.info("Health monitor started");
    setInterval(() => checkHealth(ctx.config), 60000);
  },
  stop: async (ctx) => {
    ctx.logger.info("Health monitor stopped");
  },
});

4.7 CLI 命令 (registerCli)

扩展 openclaw CLI:

api.registerCli(({ program, config, logger }) => {
  program
    .command("myplug status")
    .description("Show my plugin status")
    .action(() => {
      logger.info("Plugin is running");
    });
}, { commands: ["myplug"] });

4.8 模型提供商认证 (registerProvider)

api.registerProvider({
  id: "deepseek",
  label: "DeepSeek",
  auth: [{
    id: "api_key",
    label: "API Key",
    kind: "api_key",
    run: async (ctx) => {
      const key = await ctx.prompter.text("Enter DeepSeek API Key:");
      return {
        profiles: [{
          profileId: "deepseek:default",
          credential: { type: "api_key", provider: "deepseek", key },
        }],
        defaultModel: "deepseek/deepseek-chat",
      };
    },
  }],
});

4.9 上下文引擎 (registerContextEngine)

替换默认的上下文管理策略:

api.registerContextEngine("smart-context", () => ({
  info: { id: "smart-context", name: "Smart Context Engine", ownsCompaction: true },
  async ingest(params) {
    // 自定义上下文摄入逻辑
    return { ingested: true };
  },
  async assemble({ messages }) {
    // 智能筛选重要消息
    const filtered = messages.filter(isImportant);
    return { messages: filtered, estimatedTokens: countTokens(filtered) };
  },
  async compact(params) {
    // 自定义压缩策略
    return { ok: true, compacted: true };
  },
}));

5. Plugin Runtime(运行时助手)

插件通过 api.runtime 访问核心运行时能力:

type PluginRuntime = {
  version: string;                // OpenClaw 版本

  config: {
    loadConfig();                 // 加载配置
    writeConfigFile();            // 写入配置
  };

  system: {
    enqueueSystemEvent();         // 入队系统事件
    requestHeartbeatNow();        // 触发心跳
    runCommandWithTimeout();      // 执行命令(带超时)
    formatNativeDependencyHint(); // 原生依赖提示
  };

  media: {
    loadWebMedia();               // 加载网络媒体
    detectMime();                 // 检测 MIME 类型
    resizeToJpeg();               // 图片压缩
    getImageMetadata();           // 图片元数据
  };

  tts: {
    textToSpeechTelephony();      // 电话级 TTS
  };

  stt: {
    transcribeAudioFile();        // 语音转文字
  };

  subagent: {
    run(params);                  // 启动 sub-agent run
    waitForRun(params);           // 等待 run 完成
    getSessionMessages(params);   // 获取 session 消息
    deleteSession(params);        // 删除 session
  };

  events: {
    onAgentEvent();               // 监听 agent 事件
    onSessionTranscriptUpdate();  // 监听 transcript 更新
  };

  logging: {
    shouldLogVerbose();           // 是否详细日志
    getChildLogger(bindings);     // 创建子 logger
  };

  channel: { ... };              // 渠道相关运行时
};

6. 插件发现与加载机制

6.1 发现顺序(优先级从高到低)

1. plugins.load.paths     配置文件指定的路径
2. <workspace>/.openclaw/extensions/   工作区扩展
3. ~/.openclaw/extensions/             全局扩展
4. <openclaw>/extensions/              内置扩展大多默认禁用

同 ID 先匹配的胜出。

6.2 安全检查

OpenClaw 在发现阶段执行多重安全检查:

 入口文件不能通过符号链接/路径遍历逃出插件根目录
 插件根目录不能是 world-writable
 非内置插件的路径 ownership 必须是当前用户或 root
 npm install 使用 --ignore-scripts不执行生命周期脚本

6.3 配置验证流程

发现阶段                    加载阶段
                              
                              
读取 openclaw.plugin.json    jiti 加载 plugin.ts
                              
                              
验证 configSchema            执行 register(api)
不执行代码               注册各种扩展点
                              
                              
配置校验通过  允许加载      扩展点就绪

7. 独占 Slot 机制

某些类别只允许一个插件激活:

{
  plugins: {
    slots: {
      memory: "memory-core",       // 或 "memory-lancedb" 或 "none"
      contextEngine: "legacy",     // 或自定义引擎 ID
    }
  }
}

如果多个插件声明同一个 kind,只有被 slot 选中的那个会加载。


8. 完整 Plugin 示例

示例一:GitHub Webhook 工具插件

github-webhook/
├── openclaw.plugin.json
└── src/
    └── index.ts

openclaw.plugin.json

{
  "id": "github-webhook",
  "name": "GitHub Webhook",
  "description": "Receive GitHub webhooks and expose PR info as agent tool",
  "configSchema": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "webhookSecret": { "type": "string" },
      "defaultRepo": { "type": "string" }
    }
  },
  "uiHints": {
    "webhookSecret": { "label": "Webhook Secret", "sensitive": true },
    "defaultRepo": { "label": "默认仓库", "placeholder": "owner/repo" }
  }
}

src/index.ts

import { Type } from "@sinclair/typebox";
import crypto from "node:crypto";

// 内存中缓存最近的 webhook 事件
const recentEvents: Array<{ type: string; payload: unknown; receivedAt: number }> = [];

export default function register(api) {
  const config = api.pluginConfig as { webhookSecret?: string; defaultRepo?: string };
  const logger = api.logger;

  // ── 1. 注册 Agent 工具 ──
  api.registerTool({
    name: "github_events",
    description: "获取最近收到的 GitHub webhook 事件",
    parameters: Type.Object({
      eventType: Type.Optional(Type.String({ description: "过滤事件类型 (push/pull_request/issues)" })),
      limit: Type.Optional(Type.Number({ description: "返回数量", default: 5 })),
    }),
    async execute(_id, params) {
      let events = [...recentEvents];
      if (params.eventType) {
        events = events.filter(e => e.type === params.eventType);
      }
      events = events.slice(0, params.limit ?? 5);
      return {
        content: [{ type: "text", text: JSON.stringify(events, null, 2) }],
      };
    },
  });

  // ── 2. 注册 HTTP Webhook 端点 ──
  api.registerHttpRoute({
    path: "/webhook/github",
    auth: "plugin",
    match: "exact",
    handler: async (req, res) => {
      const chunks: Buffer[] = [];
      for await (const chunk of req) chunks.push(chunk as Buffer);
      const body = Buffer.concat(chunks).toString();

      // 验证签名
      if (config.webhookSecret) {
        const sig = req.headers["x-hub-signature-256"] as string;
        const expected = "sha256=" + crypto
          .createHmac("sha256", config.webhookSecret)
          .update(body)
          .digest("hex");
        if (sig !== expected) {
          res.statusCode = 401;
          res.end("Invalid signature");
          return true;
        }
      }

      const eventType = req.headers["x-github-event"] as string;
      const payload = JSON.parse(body);

      recentEvents.unshift({ type: eventType, payload, receivedAt: Date.now() });
      if (recentEvents.length > 100) recentEvents.length = 100;

      logger.info(`Received GitHub event: ${eventType}`);
      res.statusCode = 200;
      res.end("ok");
      return true;
    },
  });

  // ── 3. 注册 /ghstatus 命令(绕过 LLM) ──
  api.registerCommand({
    name: "ghstatus",
    description: "显示 GitHub webhook 事件统计",
    handler: () => ({
      text: `📊 GitHub Webhook Stats:\n` +
        `- 缓存事件数: ${recentEvents.length}\n` +
        `- 最近事件: ${recentEvents[0]?.type ?? "none"}\n` +
        `- 默认仓库: ${config.defaultRepo ?? "未配置"}`,
    }),
  });

  // ── 4. 注册生命周期钩子 ──
  api.on("gateway_start", (event) => {
    logger.info(`GitHub Webhook plugin ready on port ${event.port}`);
  });
}

使用此插件

# 安装(本地开发)
openclaw plugins install ./github-webhook

# 配置
openclaw config set plugins.entries.github-webhook.config.webhookSecret "your-secret"
openclaw config set plugins.entries.github-webhook.config.defaultRepo "myorg/myrepo"

# 重启 Gateway
openclaw gateway restart

# 使用
# 1. GitHub 设置 webhook 指向 https://your-gateway/webhook/github
# 2. Agent 可以调用 github_events 工具
# 3. 用户可以发送 /ghstatus 查看统计

示例二:消息审计插件

一个纯观测型插件,记录所有消息和工具调用:

audit-logger/
├── openclaw.plugin.json
└── src/
    └── index.ts

openclaw.plugin.json

{
  "id": "audit-logger",
  "name": "Audit Logger",
  "description": "记录所有 Agent 交互到本地日志",
  "configSchema": {
    "type": "object",
    "additionalProperties": false,
    "properties": {
      "logDir": { "type": "string", "default": "/var/log/openclaw-audit" },
      "logToolCalls": { "type": "boolean", "default": true },
      "logMessages": { "type": "boolean", "default": true }
    }
  }
}

src/index.ts

import fs from "node:fs/promises";
import path from "node:path";

export default function register(api) {
  const config = api.pluginConfig as {
    logDir?: string;
    logToolCalls?: boolean;
    logMessages?: boolean;
  };
  const logDir = config.logDir ?? "/var/log/openclaw-audit";

  async function appendLog(category: string, data: unknown) {
    await fs.mkdir(logDir, { recursive: true });
    const file = path.join(logDir, `${category}.jsonl`);
    const line = JSON.stringify({ timestamp: new Date().toISOString(), ...data as object });
    await fs.appendFile(file, line + "\n");
  }

  // 记录所有收到的消息
  if (config.logMessages !== false) {
    api.on("message_received", async (event, ctx) => {
      await appendLog("messages", {
        direction: "inbound",
        from: event.from,
        channel: ctx.channelId,
        content: event.content.slice(0, 500),
      });
    });

    api.on("message_sent", async (event, ctx) => {
      await appendLog("messages", {
        direction: "outbound",
        to: event.to,
        channel: ctx.channelId,
        success: event.success,
        content: event.content.slice(0, 500),
      });
    });
  }

  // 记录所有工具调用
  if (config.logToolCalls !== false) {
    api.on("before_tool_call", async (event, ctx) => {
      await appendLog("tools", {
        phase: "before",
        tool: event.toolName,
        agent: ctx.agentId,
        session: ctx.sessionKey,
        params: event.params,
      });
    });

    api.on("after_tool_call", async (event, ctx) => {
      await appendLog("tools", {
        phase: "after",
        tool: event.toolName,
        agent: ctx.agentId,
        durationMs: event.durationMs,
        error: event.error,
      });
    });
  }

  api.registerCommand({
    name: "audit",
    description: "查看审计日志摘要",
    handler: async () => {
      try {
        const files = await fs.readdir(logDir);
        const stats = await Promise.all(
          files.map(async (f) => {
            const s = await fs.stat(path.join(logDir, f));
            return `${f}: ${(s.size / 1024).toFixed(1)}KB`;
          })
        );
        return { text: `📋 审计日志:\n${stats.join("\n")}` };
      } catch {
        return { text: "审计日志目录为空" };
      }
    },
  });
}

9. Package Packs(多插件包)

一个 npm 包可以包含多个插件:

{
  "name": "@myorg/openclaw-tools",
  "openclaw": {
    "extensions": [
      "./src/safety-guard.ts",
      "./src/custom-tools.ts"
    ]
  }
}

每个 entry 会成为独立插件,ID 为 @myorg/openclaw-tools/safety-guard


10. 安全模型

10.1 信任层级

┌───────────────────────────────────────┐
 Level 1: plugins.allow / plugins.deny    /黑名单
├───────────────────────────────────────┤
 Level 2: Manifest 验证                  配置校验不执行代码
├───────────────────────────────────────┤
 Level 3: 文件系统安全检查               路径遍历/权限检查
├───────────────────────────────────────┤
 Level 4: npm --ignore-scripts           依赖安装不执行脚本
├───────────────────────────────────────┤
 Level 5: Prompt 注入防护                hooks.allowPromptInjection
└───────────────────────────────────────┘

10.2 Prompt 注入控制

运营者可以按插件禁用 prompt 修改能力:

{
  plugins: {
    entries: {
      "untrusted-plugin": {
        enabled: true,
        hooks: {
          allowPromptInjection: false  // 阻止修改 system prompt
        }
      }
    }
  }
}

11. 关键设计原则

原则 实现
声明与执行分离 Manifest 用于配置验证(不执行代码),register() 用于运行时注册
进程内执行 插件与 Gateway 同进程,零 IPC 开销
TypeScript 原生 jiti 即时编译,开发者直接写 .ts,无需构建步骤
最小权限 工具默认 optional,白名单控制,prompt 注入可禁用
独占 Slot Memory 和 ContextEngine 同时只有一个活跃
SDK + Runtime 双层 SDK 是编译时类型,Runtime 是运行时能力,插件不能直接 import 核心源码

12. 总结

OpenClaw Plugin 架构的本质是一个声明式 Manifest + 运行时注册 API 的双层系统:

openclaw.plugin.json (静态声明)
    
      配置验证发现安全检查
      不执行代码
    
    
register(api) (动态注册)
    
      9 种扩展点 + 24 种生命周期钩子
      进程内执行 IPC
    
    
Gateway Runtime
    
      工具  LLM 调用
      渠道  消息收发
      钩子  生命周期事件
      命令  快捷回复
    
    
用户交互

这个设计在安全性(声明式验证、白名单、路径检查)和灵活性(9 种扩展点、24 种钩子、运行时动态注册)之间取得了出色的平衡。

📖 相似文章推荐

上一篇
研究报告:OpenClaw Agent-to-Agent 架构原理
下一篇
研究报告:OpenClaw 记忆系统架构深度研究报告