Agent框架搭建的三个核心模块(详解优先级与选型理由)

基于 OpenClaw 的设计理念从零搭建 Agent 框架,第一步应该做的三个模块是:Gateway(消息路由与会话管理)、Agent Runtime(LLM 推理与工具执行)、Plugin System(扩展机制)。Gateway 是控制面,决定了消息怎么进、怎么出;Agent Runtime 是数据面,决定了智能怎么产生、工具怎么调;Plugin System 是扩展面,决定了框架能否在不改核心代码的前提下持续生长。三者构成最小可用闭环:消息进来→路由分发→Agent 推理→工具执行→结果返回,且后续的渠道接入、记忆系统、监控能力都能通过插件形式叠加上来。

一、为什么选这三个模块

Agent 框架的核心矛盾是”智能的不确定性”和”工程的确定性”之间的张力。LLM 输出不可预测,但消息路由必须可靠、工具执行必须安全、扩展能力必须可控。三个模块分别解决这三个问题:

模块 解决的核心矛盾 在 OpenClaw 中的角色
Gateway 消息进出的确定性与安全性 控制面,单一长运行进程
Agent Runtime LLM 推理与工具调用的编排 数据面,Brain + Hands
Plugin System 扩展能力与核心稳定性的平衡 扩展面,注册式 API

OpenClaw 采用 Hub-and-Spoke 架构,以一个 Gateway 作为 Hub,连接用户输入端与 Agent Runtime。Gateway 将接口层(消息来源)与助手运行时(智能与执行所在)解耦,用户通过任何消息平台都能访问拥有同一份记忆的 Agent,而对话状态和工具访问由自己的硬件集中管理(来源:clawdocs.org 架构概览)。

1.1 不选其他模块的理由

候选模块 为什么不选为前三 依赖关系
记忆系统 可用文件系统暂代,后续插件化 依赖 Agent Runtime 的上下文组装
多渠道接入 初期只需 CLI 或 Web 单渠道 依赖 Gateway 的路由能力
监控系统 前期可依赖日志,非核心路径 依赖 Plugin System 的钩子机制
心跳调度 自主任务在基础能力稳定后才有意义 依赖 Gateway 生命周期管理

记忆系统和多渠道接入都很重要,但它们可以后续以插件形式叠加。如果一开始就把精力分散到这些模块上,核心闭环反而难以快速跑通。

二、第一个模块:Gateway

Gateway 是整个框架的入口和控制面。没有它,消息无处可去,Agent 无从触发。OpenClaw 的 Gateway 是一个单一 Node.js 进程,承担 WebSocket 服务器、守护进程和进程管理器的角色(来源:clawdocs.org 架构概览)。

2.1 Gateway 的核心职责

职责 说明 实现要点
消息路由 将入站消息分发到正确的 Agent 绑定规则匹配,最具体优先
会话管理 维护对话状态和上下文 按 sessionKey 隔离
认证鉴权 拦截未授权请求 挑战-签名,设备配对
幂等去重 防止重复请求重复执行 idempotencyKey + dedupe Map
并发控制 防止请求打爆后端 会话级排队 + 全局并发限制

2.2 最小 Gateway 实现

从零搭建时,Gateway 的最小实现需要覆盖消息接收、路由分发和响应返回三个环节:

// 最小 Gateway:消息路由与会话管理
import { WebSocketServer } from "ws";

const gateway = new WebSocketServer({ port: 18789 });

// 会话状态表
const sessions = new Map<string, { agentId: string; history: string[] }>();

// 绑定规则:最简单的情况,直接绑定 agent
const bindings = [
  { agentId: "main", match: { channel: "cli" } }
];

// 幂等去重表
const dedupe = new Map<string, { ok: boolean; payload: unknown }>();

gateway.on("connection", (ws) => {
  ws.on("message", async (data) => {
    const req = JSON.parse(data.toString());

    // 1. 幂等检查
    if (req.idempotencyKey && dedupe.has(req.idempotencyKey)) {
      const cached = dedupe.get(req.idempotencyKey)!;
      ws.send(JSON.stringify({ type: "response", cached: true, ...cached }));
      return;
    }

    // 2. 路由匹配
    const binding = bindings.find(b => b.match.channel === req.channel);
    if (!binding) {
      ws.send(JSON.stringify({ type: "error", message: "no binding matched" }));
      return;
    }

    // 3. 会话管理
    const sessionKey = `agent:${binding.agentId}:${req.channel}`;
    if (!sessions.has(sessionKey)) {
      sessions.set(sessionKey, { agentId: binding.agentId, history: [] });
    }
    const session = sessions.get(sessionKey)!;
    session.history.push(req.message);

    // 4. 返回 runId(两阶段协议的第一阶段)
    const runId = `run_${Date.now()}`;
    ws.send(JSON.stringify({ type: "accepted", runId }));

    // 5. 调用 Agent Runtime(下一节实现)
    const result = await agentRuntime.execute({
      agentId: binding.agentId,
      message: req.message,
      history: session.history
    });

    // 6. 缓存结果并返回最终响应
    const response = { ok: true, payload: result };
    if (req.idempotencyKey) {
      dedupe.set(req.idempotencyKey, response);
    }
    ws.send(JSON.stringify({ type: "final", runId, ...response }));
  });
});

2.3 Gateway 的设计决策

决策点 OpenClaw 的选择 理由
进程模型 单进程 部署简单,无需进程间通信
绑定位置 localhost 默认 安全,外部不可直接访问
协议 WebSocket + JSON 文本帧 透明可调试,双向通信
配置格式 JSON 人可读,工具可解析

单进程模型是 OpenClaw 的核心设计决策。一个 Gateway 管理一切,不需要微服务、不需要容器、不需要进程间通信。Node.js 事件循环天然处理并发,部署只需要一个二进制和一个配置文件。代价是垂直扩展是主要选项——要水平扩展需要跑多个 Gateway 实例放在负载均衡器后面(来源:clawdocs.org 架构概览)。

三、第二个模块:Agent Runtime

Gateway 只管消息进出,真正的智能在 Agent Runtime 中产生。Agent Runtime 端到端运行 AI 循环:从会话历史和记忆中组装上下文,调用模型,对系统提供的能力执行工具调用,并持久化更新后的状态。

3.1 Agent Runtime 的核心循环

Agent Runtime 的核心是一个”思考-决策-执行-反馈”的闭环:

  1. 组装上下文:从 SOUL.md(身份)、AGENTS.md(指令)、记忆检索、会话历史、活跃技能中拼装 Prompt
  2. 调用模型:将组装好的上下文发送给 LLM,获取响应
  3. 解析响应:判断模型输出的是文本回复还是工具调用
  4. 执行工具:如果是工具调用,执行对应工具并获取结果
  5. 循环反馈:将工具结果送回模型,重复步骤 2-4 直到模型输出最终回复
上下文来源 典型大小 说明
SOUL.md 200-1000 tokens Agent 身份与人格
AGENTS.md / TOOLS.md 100-500 tokens 操作规则与可用能力
记忆检索结果 默认上限 2000 tokens 混合检索的相关记忆
活跃技能 100-500 tokens/技能 匹配到的技能指令
会话历史 可变 最近的消息

(来源:clawdocs.org 架构概览)

3.2 最小 Agent Runtime 实现

// 最小 Agent Runtime:LLM 推理 + 工具执行
import { Anthropic } from "@anthropic-ai/sdk";

const client = new Anthropic();
const tools = new Map<string, (params: any) => Promise<string>>();

// 注册工具
function registerTool(name: string, handler: (params: any) => Promise<string>) {
  tools.set(name, handler);
}

async function executeAgent(req: {
  agentId: string;
  message: string;
  history: string[];
}) {
  const messages = [
    { role: "user", content: req.message }
  ];

  // Agent 循环
  while (true) {
    const response = await client.messages.create({
      model: "claude-sonnet-4-20250514",
      max_tokens: 4096,
      system: "You are a helpful assistant. Use tools when needed.",
      messages,
      tools: Array.from(tools.keys()).map(name => ({
        name,
        description: `Tool: ${name}`,
        input_schema: { type: "object", properties: {} }
      }))
    });

    // 如果模型输出文本,返回最终结果
    if (response.stop_reason === "end_turn") {
      const text = response.content
        .filter(b => b.type === "text")
        .map(b => b.text)
        .join("");
      return text;
    }

    // 如果模型请求工具调用,执行工具并继续循环
    if (response.stop_reason === "tool_use") {
      const toolUse = response.content.find(b => b.type === "tool_use");
      if (toolUse && tools.has(toolUse.name)) {
        const result = await tools.get(toolUse.name)!(toolUse.input);
        messages.push({ role: "assistant", content: response.content });
        messages.push({
          role: "user",
          content: [{ type: "tool_result", tool_use_id: toolUse.id, content: result }]
        });
      }
    }
  }
}

export { executeAgent, registerTool };

3.3 模型抽象层的必要性

Agent Runtime 中对底层模型的抽象封装是第二优先级的设计。OpenClaw 支持多种模型提供商,通过统一接口屏蔽差异:

提供商类型 代表 接入方式
云端 API OpenAI、Anthropic API Key 认证
本地模型 Ollama、vLLM 本地 HTTP 端点
兼容协议 第三方 OpenAI 兼容 替换 base URL

模型抽象的目标是避免模型绑定,提高可迁移性。不同角色可以分配不同模型:需要强推理的协调者用 Claude Opus,简单重复任务用本地 Llama,隐私敏感操作用本地模型(来源:clawdocs.org 架构概览)。

四、第三个模块:Plugin System

前两个模块搭出了核心闭环,但一个框架能否持续生长取决于扩展机制。Plugin System 让第三方在不碰核心代码的前提下注册新渠道、新工具、新 Hook。

4.1 插件系统的核心设计要素

设计要素 关键问题 推荐方案
插件发现 怎么找到第三方代码 清单文件声明,运行时按需加载
能力契约 谁定义接口标准 核心定义契约,插件注册实现
注册接口 插件怎么告诉核心自己的能力 集中式 API 对象注入
安全边界 信任哪些插件 allowlist + 路径安全检查
生命周期 插件何时介入 命名钩子覆盖全链路

4.2 最小插件系统实现

// 最小 Plugin System:注册式 API + 生命周期钩子
type Plugin = {
  id: string;
  name: string;
  register: (api: PluginApi) => void;
};

type PluginApi = {
  registerTool: (tool: ToolDef) => void;
  registerHook: (event: string, handler: Function) => void;
  registerChannel: (channel: ChannelDef) => void;
  runtime: {
    tools: Map<string, ToolDef>;
    hooks: Map<string, Function[]>;
    channels: Map<string, ChannelDef>;
  };
};

function createPluginApi(): PluginApi {
  const tools = new Map<string, ToolDef>();
  const hooks = new Map<string, Function[]>();
  const channels = new Map<string, ChannelDef>();

  return {
    registerTool: (tool) => tools.set(tool.name, tool),
    registerHook: (event, handler) => {
      if (!hooks.has(event)) hooks.set(event, []);
      hooks.get(event)!.push(handler);
    },
    registerChannel: (channel) => channels.set(channel.id, channel),
    runtime: { tools, hooks, channels }
  };
}

// 加载插件
async function loadPlugin(pluginPath: string, api: PluginApi) {
  const mod = await import(pluginPath);
  const plugin: Plugin = mod.default;
  plugin.register(api);
}

// 触发钩子
async function triggerHook(api: PluginApi, event: string, payload: any) {
  const handlers = api.runtime.hooks.get(event) || [];
  for (const handler of handlers) {
    await handler(payload);
  }
}

4.3 插件系统的设计决策

从零搭建时,插件系统有几个关键决策需要提前确定:

  1. 插件运行在进程内还是隔离环境:进程内性能好但崩溃会拖垮核心,隔离环境安全但有 IPC 开销。OpenClaw 选择进程内运行,用契约测试和清单校验替代沙箱
  2. 插件配置如何校验:在 register 调用前用 JSON Schema 校验用户配置,非法配置直接拒绝加载
  3. 核心与插件的依赖方向:插件只能依赖核心暴露的 API,核心不反向依赖插件。这保证了插件可以独立开发和分发

五、三个模块的协作关系

三个模块搭好后,一次完整的请求处理流程如下:

  1. 用户通过渠道发送消息,Gateway 接收
  2. Gateway 执行认证、幂等检查、路由匹配,确定目标 Agent
  3. Gateway 调用 Agent Runtime,传入消息和会话上下文
  4. Agent Runtime 组装上下文,调用 LLM 获取响应
  5. LLM 请求工具调用,Agent Runtime 从插件系统注册的工具中查找并执行
  6. 工具结果返回 LLM,循环直到产出最终回复
  7. Agent Runtime 将结果返回 Gateway
  8. Gateway 将回复发送回渠道
渠道消息 → Gateway(路由/鉴权/幂等)→ Agent Runtime(推理/工具)→ 插件系统(工具执行)
                ↑                          |                           |
                └────────── 最终回复 ←──────┘                           |
                              ↑                                         |
                              └─────────── 工具结果 ←───────────────────┘
阶段 主导模块 协作模块
消息接收 Gateway —
路由分发 Gateway Plugin System(提供渠道插件)
上下文组装 Agent Runtime Plugin System(提供记忆插件)
LLM 推理 Agent Runtime —
工具执行 Plugin System Agent Runtime(调用工具)
响应返回 Gateway —

六、后续可叠加的模块

三个核心模块跑通后,以下能力都能以插件形式逐步叠加:

后续模块 叠加方式 前置依赖
记忆系统 Plugin System 注册 memory 工具 Agent Runtime 的上下文组装
多渠道接入 Plugin System 注册 channel 插件 Gateway 的路由能力
心跳调度 Plugin System 注册 service Gateway 的生命周期管理
监控告警 Plugin System 注册 hook 全链路钩子
审批流程 Plugin System 注册中间件 Gateway 的请求管线

OpenClaw 的实践验证了这条路径。它的记忆系统、OpenTelemetry 遥测、26 个消息平台桥接,全部以插件形式存在,核心只保留 Gateway、Agent Runtime 和 Plugin System 三件套(来源:clawdocs.org 架构概览)。

常见问题(FAQ)

Q1:为什么记忆系统不放在前三个模块里? 前期可用文件系统暂代,记忆检索可后续通过插件注册工具接入。

Q2:单进程 Gateway 能扛住高并发吗? 单进程靠事件循环处理并发,垂直扩展为主,需更高吞吐时跑多实例加负载均衡。

Q3:插件系统为什么不直接用沙箱隔离? 沙箱有 IPC 开销。OpenClaw 用契约测试和清单校验替代沙箱,换取更简的部署。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 qiqicto@qq.com 举报,一经查实,本站将立刻删除。
赞 (0)
其AI的头像其AI普通用户

相关推荐

返回顶部