1. 引言

OpenClaw 是一个面向多平台消息应用的 AI 智能体框架,能够帮助开发者快速构建具备对话、工具调用和任务编排能力的机器人。grammY 则是 Telegram Bot API 生态中广受欢迎的 TypeScript/JavaScript 框架,以类型安全、中间件机制和丰富的插件生态著称。

将 OpenClaw 与 grammY 集成,可以让 Telegram 机器人获得 OpenClaw 的智能体能力,同时保留 grammY 成熟的开发体验。本文将通过丰富的代码实例,逐步演示如何完成这一集成。

2. 环境准备

在开始之前,请确保你的开发环境满足以下条件:

  • Node.js 18 或更高版本
  • 一个 Telegram Bot Token(通过 @BotFather 获取)
  • OpenClaw 框架依赖(可通过 npm 安装)

首先创建项目并安装依赖:

mkdir openclaw-grammy-demo
cd openclaw-grammy-demo
npm init -y
npm install grammy openclaw dotenv

3. 创建基础 grammY 机器人

我们先搭建一个最基础的 grammY 机器人,确保 Telegram 连接正常:

import { Bot } from "grammy";
import "dotenv/config";

const token = process.env.TELEGRAM_BOT_TOKEN;
if (!token) {
  throw new Error("TELEGRAM_BOT_TOKEN 环境变量未设置");
}

const bot = new Bot(token);

bot.command("start", (ctx) => {
  ctx.reply("你好!我是由 OpenClaw 驱动的 Telegram 机器人。");
});

bot.start();
console.log("机器人已启动");

运行上述代码后,在 Telegram 中向你的机器人发送 /start,即可收到回复。

4. 初始化 OpenClaw 智能体

接下来,我们在项目中初始化 OpenClaw 智能体。OpenClaw 提供了简洁的 API 来创建和管理智能体实例:

import { OpenClaw } from "openclaw";

const agent = new OpenClaw({
  model: {
    provider: "anthropic",
    model: "claude-sonnet-4-20250514",
    apiKey: process.env.ANTHROPIC_API_KEY,
  },
  systemPrompt: "你是一个乐于助人的 Telegram 助手,回答要简洁、准确。",
});

// 验证智能体是否可用
const response = await agent.chat("你好,请介绍一下你自己");
console.log(response.text);

这里我们使用 Anthropic 的 Claude 模型作为底层推理引擎。你也可以根据 OpenClaw 的文档配置其他模型提供商。

5. 将 OpenClaw 接入 grammY 消息处理

核心集成思路是:在 grammY 的中间件中接收用户消息,转发给 OpenClaw 智能体处理,再将回复发送回 Telegram。下面是一个完整的集成示例:

import { Bot } from "grammy";
import { OpenClaw } from "openclaw";
import "dotenv/config";

const token = process.env.TELEGRAM_BOT_TOKEN;
if (!token) {
  throw new Error("TELEGRAM_BOT_TOKEN 环境变量未设置");
}

const agent = new OpenClaw({
  model: {
    provider: "anthropic",
    model: "claude-sonnet-4-20250514",
    apiKey: process.env.ANTHROPIC_API_KEY,
  },
  systemPrompt: "你是一个乐于助人的 Telegram 助手,回答要简洁、准确。",
});

const bot = new Bot(token);

// 处理文本消息
bot.on("message:text", async (ctx) => {
  const userText = ctx.message.text;

  // 发送"正在输入"状态
  await ctx.replyWithChatAction("typing");

  try {
    const response = await agent.chat(userText);
    await ctx.reply(response.text);
  } catch (error) {
    console.error("OpenClaw 调用失败:", error);
    await ctx.reply("抱歉,我暂时无法处理你的请求,请稍后再试。");
  }
});

bot.start();
console.log("OpenClaw + grammY 机器人已启动");

这段代码实现了最基本的对话闭环:用户发送消息 → grammY 捕获 → 转发给 OpenClaw → 返回结果 → 回复用户。

6. 维护多用户会话上下文

为了让每个用户拥有独立的对话历史,我们需要按用户 ID 维护会话状态。OpenClaw 支持传入会话 ID 来隔离上下文:

import { Bot, Context } from "grammy";
import { OpenClaw } from "openclaw";
import "dotenv/config";

const token = process.env.TELEGRAM_BOT_TOKEN;
if (!token) {
  throw new Error("TELEGRAM_BOT_TOKEN 环境变量未设置");
}

const agent = new OpenClaw({
  model: {
    provider: "anthropic",
    model: "claude-sonnet-4-20250514",
    apiKey: process.env.ANTHROPIC_API_KEY,
  },
  systemPrompt: "你是一个乐于助人的 Telegram 助手。",
});

const bot = new Bot(token);

bot.on("message:text", async (ctx: Context) => {
  const userId = String(ctx.from?.id ?? "anonymous");
  const userText = ctx.message.text;

  await ctx.replyWithChatAction("typing");

  try {
    // 使用 userId 作为会话标识,实现多用户隔离
    const response = await agent.chat(userText, {
      sessionId: userId,
    });
    await ctx.reply(response.text);
  } catch (error) {
    console.error("OpenClaw 调用失败:", error);
    await ctx.reply("抱歉,我暂时无法处理你的请求。");
  }
});

bot.start();

通过传入 sessionId,OpenClaw 会自动为每个用户维护独立的对话历史,避免不同用户之间的上下文互相干扰。

7. 添加工具调用能力

OpenClaw 的一大亮点是支持工具调用(Function Calling)。我们可以为智能体注册自定义工具,让它在对话中自动调用。下面演示如何添加一个查询天气的工具:

import { Bot } from "grammy";
import { OpenClaw } from "openclaw";
import "dotenv/config";

const token = process.env.TELEGRAM_BOT_TOKEN;
if (!token) {
  throw new Error("TELEGRAM_BOT_TOKEN 环境变量未设置");
}

const agent = new OpenClaw({
  model: {
    provider: "anthropic",
    model: "claude-sonnet-4-20250514",
    apiKey: process.env.ANTHROPIC_API_KEY,
  },
  systemPrompt: "你是一个实用的 Telegram 助手,可以查询天气信息。",
  tools: [
    {
      name: "get_weather",
      description: "查询指定城市的当前天气",
      parameters: {
        type: "object",
        properties: {
          city: {
            type: "string",
            description: "城市名称,例如:北京、上海",
          },
        },
        required: ["city"],
      },
      handler: async ({ city }: { city: string }) => {
        // 这里替换为真实的天气 API 调用
        const weatherData = {
          city,
          temperature: 25,
          condition: "晴",
        };
        return `当前${city}天气:${weatherData.condition},气温 ${weatherData.temperature}°C`;
      },
    },
  ],
});

const bot = new Bot(token);

bot.on("message:text", async (ctx) => {
  const userId = String(ctx.from?.id ?? "anonymous");
  const userText = ctx.message.text;

  await ctx.replyWithChatAction("typing");

  try {
    const response = await agent.chat(userText, {
      sessionId: userId,
    });
    await ctx.reply(response.text);
  } catch (error) {
    console.error("OpenClaw 调用失败:", error);
    await ctx.reply("抱歉,我暂时无法处理你的请求。");
  }
});

bot.start();

现在,当用户发送"北京天气怎么样"时,OpenClaw 会自动调用 get_weather 工具并返回结果。

8. 处理命令与富文本消息

除了普通文本,我们还可以让机器人响应命令,并支持 Markdown 格式的回复:

import { Bot } from "grammy";
import { OpenClaw } from "openclaw";
import "dotenv/config";

const token = process.env.TELEGRAM_BOT_TOKEN;
if (!token) {
  throw new Error("TELEGRAM_BOT_TOKEN 环境变量未设置");
}

const agent = new OpenClaw({
  model: {
    provider: "anthropic",
    model: "claude-sonnet-4-20250514",
    apiKey: process.env.ANTHROPIC_API_KEY,
  },
  systemPrompt: "你是一个乐于助人的 Telegram 助手。",
});

const bot = new Bot(token);

// 处理 /ai 命令,将命令参数作为问题
bot.command("ai", async (ctx) => {
  const question = ctx.match;
  if (!question) {
    await ctx.reply("用法:/ai 你的问题");
    return;
  }

  await ctx.replyWithChatAction("typing");

  try {
    const response = await agent.chat(question, {
      sessionId: String(ctx.from?.id ?? "anonymous"),
    });
    // 使用 Markdown 格式回复
    await ctx.reply(response.text, { parse_mode: "Markdown" });
  } catch (error) {
    console.error("OpenClaw 调用失败:", error);
    await ctx.reply("抱歉,处理失败,请稍后再试。");
  }
});

// 处理普通文本消息
bot.on("message:text", async (ctx) => {
  const userId = String(ctx.from?.id ?? "anonymous");
  const userText = ctx.message.text;

  await ctx.replyWithChatAction("typing");

  try {
    const response = await agent.chat(userText, { sessionId: userId });
    await ctx.reply(response.text);
  } catch (error) {
    console.error("OpenClaw 调用失败:", error);
    await ctx.reply("抱歉,我暂时无法处理你的请求。");
  }
});

bot.start();

这样用户既可以通过 /ai 问题 命令提问,也可以直接发送文本消息与机器人对话。

9. 错误处理与日志

在生产环境中,完善的错误处理和日志记录至关重要。下面是一个增强版本:

import { Bot } from "grammy";
import { OpenClaw } from "openclaw";
import "dotenv/config";

const token = process.env.TELEGRAM_BOT_TOKEN;
if (!token) {
  throw new Error("TELEGRAM_BOT_TOKEN 环境变量未设置");
}

const agent = new OpenClaw({
  model: {
    provider: "anthropic",
    model: "claude-sonnet-4-20250514",
    apiKey: process.env.ANTHROPIC_API_KEY,
  },
  systemPrompt: "你是一个乐于助人的 Telegram 助手。",
});

const bot = new Bot(token);

// 全局错误处理
bot.catch((err) => {
  console.error("grammY 全局错误:", err.error);
});

bot.on("message:text", async (ctx) => {
  const userId = String(ctx.from?.id ?? "anonymous");
  const userText = ctx.message.text;

  console.log(`[${new Date().toISOString()}] 用户 ${userId}: ${userText}`);

  await ctx.replyWithChatAction("typing");

  try {
    const response = await agent.chat(userText, { sessionId: userId });
    console.log(`[${new Date().toISOString()}] 回复 ${userId}: ${response.text}`);
    await ctx.reply(response.text);
  } catch (error) {
    console.error(`[${new Date().toISOString()}] OpenClaw 调用失败:`, error);
    await ctx.reply("抱歉,我暂时无法处理你的请求,请稍后再试。");
  }
});

bot.start();

10. 完整项目结构

为了方便读者参考,这里给出一个完整的项目文件结构:

openclaw-grammy-demo/
├── src/
│   ├── index.ts          # 入口文件
│   ├── agent.ts          # OpenClaw 智能体配置
│   ├── bot.ts            # grammY 机器人配置
│   └── tools/
│       └── weather.ts    # 自定义工具
├── .env                  # 环境变量
├── package.json
└── tsconfig.json

其中 agent.ts 可以这样组织:

import { OpenClaw } from "openclaw";

export function createAgent() {
  return new OpenClaw({
    model: {
      provider: "anthropic",
      model: "claude-sonnet-4-20250514",
      apiKey: process.env.ANTHROPIC_API_KEY,
    },
    systemPrompt: "你是一个乐于助人的 Telegram 助手。",
  });
}

bot.ts 负责组装:

import { Bot } from "grammy";
import { createAgent } from "./agent";

export function createBot(token: string) {
  const bot = new Bot(token);
  const agent = createAgent();

  bot.on("message:text", async (ctx) => {
    const userId = String(ctx.from?.id ?? "anonymous");
    await ctx.replyWithChatAction("typing");
    try {
      const response = await agent.chat(ctx.message.text, { sessionId: userId });
      await ctx.reply(response.text);
    } catch (error) {
      console.error(error);
      await ctx.reply("抱歉,处理失败。");
    }
  });

  return bot;
}

11. 总结

本文从零开始演示了如何将 OpenClaw 与 grammY 集成,构建一个具备 AI 对话能力的 Telegram 机器人。我们覆盖了以下关键点:

  • 基础 grammY 机器人的搭建
  • OpenClaw 智能体的初始化与调用
  • 多用户会话上下文的隔离
  • 工具调用(Function Calling)的接入
  • 命令处理与富文本回复
  • 错误处理与日志记录
  • 模块化的项目结构组织

这套集成方案可以进一步扩展,例如接入数据库持久化会话、添加更多自定义工具、支持图片和语音消息等。希望本文的代码实例能为你的开发工作提供参考。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐