1. 项目概述与核心价值

最近在捣鼓一些AI与区块链结合的有趣玩意儿,发现了一个挺有意思的开源项目:EthGPT。简单来说,这是一个用TypeScript写的ChatGPT插件(同时也是一个模板),它的核心能力是让ChatGPT这个“语言大脑”能够直接与以太坊以及各种EVM兼容的区块链网络进行交互。想象一下,你不再需要记住复杂的合约地址、ABI接口或者RPC节点URL,只需要像和朋友聊天一样告诉ChatGPT:“帮我查一下 xinbenlv.eth 这个ENS域名对应的地址”,或者“看看我钱包里还有多少ETH”,它就能帮你搞定。这听起来是不是有点像给ChatGPT装上了“区块链之手”?

目前,OpenAI的ChatGPT插件功能还处于早期测试阶段,需要申请加入等待列表才能使用。但这并不妨碍我们提前了解和学习如何构建这样一个插件。EthGPT项目本身基于Next.js框架,提供了一个清晰、可扩展的模板。无论你是想快速搭建一个自己的区块链AI助手,还是想学习ChatGPT插件开发的完整流程,这个项目都是一个极佳的起点。它解决了开发者在集成AI与Web3时面临的几个核心痛点:如何让AI理解区块链操作、如何安全地处理链上请求,以及如何构建一个符合OpenAI标准的插件架构。

2. 项目架构与核心思路拆解

2.1 为什么选择Next.js + TypeScript?

EthGPT选择Next.js作为基础框架,这是一个非常务实且高效的选择。Next.js提供了开箱即用的API路由功能( pages/api app/api ),这正好契合了ChatGPT插件需要对外提供API接口的核心需求。你不需要额外配置复杂的Express或Fastify服务器,直接在 api 目录下创建文件,Next.js就会自动将其处理为服务器端接口。这对于快速原型开发和部署来说,极大地简化了流程。

TypeScript的加入则是为了应对区块链开发中固有的复杂性。智能合约的ABI、交易对象、事件日志等数据结构都非常严谨且嵌套深。TypeScript的静态类型检查可以在编码阶段就捕获大量潜在的类型错误,比如将 string 类型的地址误传为 number ,或者漏掉了某个必需的交易字段。这在处理真实资产时至关重要,能有效避免因低级错误导致的经济损失。此外,一个定义良好的TypeScript接口,本身就是一份绝佳的API文档,方便后续的维护和协作。

2.2 ChatGPT插件的工作原理与规范

要理解EthGPT,必须先搞清楚ChatGPT插件是如何运作的。它本质上是一个遵循OpenAI特定规范的Web服务。整个过程可以概括为“描述自己,等待调用”:

  1. 插件清单( /.well-known/ai-plugin.json :这是插件的“身份证”。当你在ChatGPT界面配置插件时,它会首先访问这个文件。清单里包含了插件的基本信息,如名称、描述、开发者信息,以及最重要的—— OpenAPI规范(Swagger)文件的URL
  2. OpenAPI规范( /openapi.yaml /openapi.json :这是插件的“能力说明书”。它严格定义了你的插件对外提供了哪些API接口( /api/ens , /api/balance 等)、每个接口需要什么参数(比如 name 代表ENS域名)、返回什么格式的数据。ChatGPT的AI模型会阅读这份规范,从而“学会”在什么情况下应该调用你的哪个接口。
  3. API接口实现 :这就是EthGPT项目中 pages/api 目录下的实际代码。当ChatGPT根据对话上下文决定调用某个接口时,它会向你的服务发送一个HTTP请求。你的服务处理这个请求(例如,连接以太坊节点查询数据),然后将结果以JSON格式返回给ChatGPT。最后,ChatGPT会把这个结果融入它的自然语言回复中,呈现给用户。

注意 :插件本身没有用户界面。它的所有交互都发生在ChatGPT的聊天界面中。你的工作是提供“能力”,ChatGPT负责“调度”和“表达”。

2.3 安全与权限模型考量

让AI直接操作区块链,安全是头等大事。EthGPT作为一个模板,在安全设计上给我们提供了清晰的思路:

  • 无私钥管理 :这是最重要的原则。插件服务端 绝对不应该 存储或接触用户的私钥。所有需要签名的交易(比如转账、交互合约),都应该引导用户在自己的钱包(如MetaMask)中完成。插件的角色仅限于“查询”和“构建未签名的交易数据”。
  • 最小权限原则 :在 openapi.yaml 中定义接口时,要仔细斟酌每个接口的必要性。只暴露最少的、必要的查询功能。例如,可以提供“查询余额”、“解析ENS”,但避免直接提供“发送交易”的接口。
  • 输入验证与清洗 :所有从ChatGPT传来的用户输入都必须进行严格验证。例如,对于ENS域名,要检查其格式是否符合规范;对于地址,要校验其有效性。这可以防止注入攻击或无效请求对服务造成影响。
  • 速率限制与鉴权 :虽然模板可能未直接实现,但在生产环境中,你必须为API接口添加速率限制(Rate Limiting)以防止滥用。同时,可以考虑通过API Key或OAuth等方式,对调用方进行简单的鉴权,确保只有你的ChatGPT插件(或可信来源)可以调用这些接口。

3. 核心模块解析与实操要点

3.1 项目结构深度解读

让我们打开EthGPT的仓库,看看它的目录结构,这能帮助我们理解一个标准插件的骨架:

ethgpt/
├── pages/
│   └── api/
│       ├── ens.ts        # 处理ENS域名解析的API端点
│       └── balance.ts    # 处理余额查询的API端点
├── public/
│   ├── .well-known/
│   │   └── ai-plugin.json # 插件清单文件
│   ├── openapi.yaml      # OpenAPI规范文件
│   └── logo.png          # 插件图标
├── lib/
│   └── ethers.ts         # 封装的以太坊交互工具库
├── .env.example          # 环境变量示例
├── next.config.js        # Next.js配置
├── package.json
└── tsconfig.json
  • pages/api/ :这是业务逻辑的核心。每个 .ts 文件对应一个API路由。例如,访问 https://your-domain.com/api/ens 就会触发 ens.ts 中的处理函数。
  • public/.well-known/ai-plugin.json :静态托管的关键文件。Next.js会自动将 public 目录下的文件暴露在根路径。这个文件必须放在精确的路径下,ChatGPT才会识别。
  • public/openapi.yaml :同样被静态托管。它定义了API的细节,是AI理解插件功能的桥梁。
  • lib/ethers.ts :这是一个最佳实践——将区块链交互的通用逻辑(如初始化Provider、定义ABI)抽象到一个单独的工具文件中。这避免了在各个API端点中重复编写相同的连接代码,便于维护和更新节点配置。

3.2 关键文件详解与配置

1. 插件清单 ( ai-plugin.json ) 这个文件告诉ChatGPT“你是谁”。一个典型的配置如下:

{
  "schema_version": "v1",
  "name_for_human": "以太坊助手",
  "name_for_model": "ethereum_assistant",
  "description_for_human": "一个可以帮助你查询以太坊链上信息的AI助手,如ENS解析、余额查询等。",
  "description_for_model": "当用户需要查询以太坊或EVM链上的信息时使用此插件。可以解析ENS域名、查询地址的ETH或代币余额。",
  "auth": {
    "type": "none" // 生产环境可考虑改为"service_http"或"oauth"
  },
  "api": {
    "type": "openapi",
    "url": "http://localhost:3000/openapi.yaml", // 指向你的OpenAPI规范
    "is_user_authenticated": false
  },
  "logo_url": "http://localhost:3000/logo.png",
  "contact_email": "your-email@example.com",
  "legal_info_url": "http://your-domain.com/legal"
}
  • description_for_model 字段至关重要,它是给AI看的“提示词”,需要清晰、简洁地说明插件的用途和调用场景。

2. OpenAPI规范 ( openapi.yaml ) 这是技术核心,定义了AI能调用的所有操作。以ENS解析接口为例:

openapi: 3.0.1
info:
  title: EthGPT Plugin API
  version: 'v1'
servers:
  - url: http://localhost:3000
paths:
  /api/ens:
    get:
      operationId: resolveENS
      summary: 解析ENS域名到以太坊地址
      description: 给定一个ENS域名(如xinbenlv.eth),返回其对应的以太坊地址。
      parameters:
        - name: name
          in: query
          description: ENS域名,例如 xinbenlv.eth
          required: true
          schema:
            type: string
      responses:
        '200':
          description: 成功解析
          content:
            application/json:
              schema:
                type: object
                properties:
                  address:
                    type: string
                    description: 解析出的以太坊地址
                  name:
                    type: string
                    description: 查询的ENS域名
  • 每个 path (如 /api/ens )对应一个API端点。
  • parameters 定义了AI需要从用户对话中提取哪些参数。
  • responses 中的 schema 定义了返回数据的结构,这帮助AI理解如何解析和使用返回的结果。

3. API端点实现 ( pages/api/ens.ts ) 这是执行实际逻辑的地方。Next.js API路由要求默认导出一个请求处理函数。

import type { NextApiRequest, NextApiResponse } from 'next';
import { ethers } from 'ethers';
import { getProvider } from '../../lib/ethers'; // 从工具库获取配置好的Provider

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  // 1. 只处理GET请求
  if (req.method !== 'GET') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  // 2. 获取并验证查询参数
  const { name } = req.query;
  if (!name || typeof name !== 'string') {
    return res.status(400).json({ error: 'Missing or invalid ENS name' });
  }

  // 3. 基本的ENS格式验证(简单示例)
  if (!name.endsWith('.eth')) {
    return res.status(400).json({ error: 'Invalid ENS name format. Must end with .eth' });
  }

  try {
    // 4. 使用工具库中的Provider
    const provider = getProvider();
    
    // 5. 核心逻辑:解析ENS
    const address = await provider.resolveName(name);
    
    if (!address) {
      return res.status(404).json({ error: `ENS name "${name}" not found or not configured.` });
    }

    // 6. 返回标准化的成功响应
    return res.status(200).json({
      address,
      name,
    });
  } catch (error) {
    // 7. 捕获并处理所有异常,避免服务器暴露内部错误信息
    console.error(`Failed to resolve ENS ${name}:`, error);
    return res.status(500).json({ 
      error: 'Failed to resolve ENS due to network or server issue.' 
    });
  }
}

3.3 区块链交互层封装 ( lib/ethers.ts )

将区块链基础设施的初始化逻辑集中管理是专业的表现。这个文件可能包含:

import { ethers } from 'ethers';

// 从环境变量读取RPC节点URL,这是关键配置!
const RPC_URL = process.env.ETHEREUM_RPC_URL || 'https://mainnet.infura.io/v3/YOUR_INFURA_KEY';

// 使用一个全局变量或缓存来避免重复创建Provider实例
let provider: ethers.providers.JsonRpcProvider | null = null;

export function getProvider(): ethers.providers.JsonRpcProvider {
  if (!provider) {
    if (!RPC_URL) {
      throw new Error('ETHEREUM_RPC_URL environment variable is not set.');
    }
    provider = new ethers.providers.JsonRpcProvider(RPC_URL);
    // 可以在这里配置更多选项,如超时时间、重试次数等
  }
  return provider;
}

// 你可以继续添加其他链的Provider,或者封装常用合约的实例
// export function getOptimismProvider() { ... }

实操心得 :一定要将RPC URL、API Keys等敏感信息放在环境变量( .env.local )中,切勿硬编码在代码里。 .env.example 文件就是用来提示合作者需要配置哪些环境变量的。

4. 从零开始:开发与调试全流程

4.1 本地开发环境搭建

假设你已经有了Node.js环境(建议版本16+)和Git,让我们一步步来:

  1. 克隆项目并安装依赖

    git clone https://github.com/xinbenlv/ethgpt.git
    cd ethgpt
    npm install  # 或 yarn 或 pnpm
    

    这一步会安装所有必要的包,包括 next , react , ethers.js , typescript 等。

  2. 配置环境变量 : 复制环境变量示例文件,并填入你自己的配置。

    cp .env.example .env.local
    

    编辑 .env.local 文件,最关键的是配置一个可用的以太坊RPC节点:

    ETHEREUM_RPC_URL=https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID
    # 或者使用其他服务如 Alchemy, QuickNode 等
    # ETHEREUM_RPC_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_ALCHEMY_KEY
    

    避坑指南 :对于开发和测试,强烈建议使用Infura、Alchemy这类可靠的服务商提供的免费层节点。自己搭建全节点门槛高、同步慢,不适合快速开发。

  3. 运行开发服务器

    npm run dev
    

    如果一切顺利,终端会显示 > Ready on http://localhost:3000

4.2 在ChatGPT中安装与配置插件(需插件权限)

由于插件功能处于测试阶段,以下流程基于测试期的经验:

  1. 在ChatGPT Web界面,选择GPT-4模型,在下拉菜单中选择 “Plugins” 模式。
  2. 点击插件商店图标,选择 “Develop your own plugin” 或类似选项。
  3. 在弹出的对话框中,输入你的本地开发服务器地址: http://localhost:3000
  4. ChatGPT会尝试访问你的 http://localhost:3000/.well-known/ai-plugin.json 。如果成功,它会读取清单并显示你的插件名称和描述。
  5. 启用你的插件。现在,你就可以在对话中开始使用它了。

4.3 测试与交互

回到ChatGPT聊天窗口,你可以尝试用自然语言发出指令:

  • “请帮我解析一下 vitalik.eth 这个ENS域名。”
  • “查询一下地址 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 的ETH余额。”

观察ChatGPT的回复。它会先“思考”(决定调用哪个插件接口),然后显示“使用以太坊助手”的提示,最后将插件返回的原始数据(如地址 0x... )组织成一句流畅的话回复给你。

同时,在你的终端里,可以看到服务器接收到请求的日志,这非常便于调试。

4.4 扩展你的插件功能

EthGPT模板只提供了ENS和余额查询两个示例。你可以轻松地添加更多Web3功能:

  1. 添加新的API端点 :在 pages/api 下新建一个文件,例如 token.ts ,用于查询ERC20代币余额。
  2. 更新OpenAPI规范 :在 openapi.yaml 文件的 paths 节点下,仿照现有格式,为你新的 /api/token 路径添加完整的接口定义,包括参数、响应格式等。
  3. 实现业务逻辑 :在 token.ts 中,使用 ethers.js 调用代币合约的 balanceOf 函数。
  4. 更新插件描述 :别忘了修改 ai-plugin.json 中的 description_for_model ,告诉AI你的插件新增了代币查询功能。

一个简单的代币查询接口实现框架:

// pages/api/token.ts
import { ethers } from 'ethers';
import { getProvider } from '../../lib/ethers';

const ERC20_ABI = [
  "function balanceOf(address owner) view returns (uint256)",
  "function decimals() view returns (uint8)",
  "function symbol() view returns (string)"
];

export default async function handler(req, res) {
  const { address, contractAddress } = req.query; // 用户地址和代币合约地址
  // ... 参数验证
  const provider = getProvider();
  const contract = new ethers.Contract(contractAddress, ERC20_ABI, provider);
  
  const [balance, decimals, symbol] = await Promise.all([
    contract.balanceOf(address),
    contract.decimals(),
    contract.symbol()
  ]);
  
  const formattedBalance = ethers.utils.formatUnits(balance, decimals);
  
  res.status(200).json({ balance: formattedBalance, symbol, address, contractAddress });
}

5. 部署上线与生产环境考量

本地开发测试无误后,就可以考虑部署了。Next.js应用可以轻松部署到Vercel、Netlify、AWS等平台。

5.1 部署到Vercel(推荐)

Vercel是Next.js的官方合作平台,部署体验无缝。

  1. 将你的代码推送到GitHub、GitLab或Bitbucket仓库。
  2. 登录 Vercel ,点击“New Project”,导入你的仓库。
  3. 在项目配置页面,Vercel会自动识别为Next.js项目。你需要添加环境变量 ETHEREUM_RPC_URL
  4. 点击“Deploy”。几分钟后,你的插件就拥有了一个线上的域名,例如 https://ethgpt.vercel.app

5.2 更新插件配置

部署成功后,你需要修改两个地方:

  1. 更新 ai-plugin.json :将文件中所有的 http://localhost:3000 替换为你的生产域名,例如 https://ethgpt.vercel.app 。确保 logo_url api.url 等字段都指向正确的线上地址。
  2. 更新 openapi.yaml :将顶部的 servers 部分的 url 也改为你的生产域名。

重要提示 :修改这些文件后,需要重新提交并推送代码,触发Vercel重新部署。或者,更专业的做法是使用环境变量来动态配置域名,避免硬编码。

5.3 生产环境优化与安全加固

  1. 自定义域名与HTTPS :Vercel等平台提供免费的HTTPS。建议绑定一个自定义域名(如 plugin.yourdomain.com ),看起来更专业可信。
  2. 环境变量管理 :在生产环境中,务必使用平台提供的环境变量管理功能来设置 ETHEREUM_RPC_URL ,不要使用本地的 .env.local 文件。
  3. 启用CORS(如果需要) :虽然ChatGPT插件调用通常不受CORS限制,但如果你计划让其他前端也调用这些API,需要在Next.js配置中正确设置CORS头。
  4. 监控与日志 :利用Vercel的日志功能或集成Sentry等工具,监控API的错误和性能。
  5. 速率限制 :实现API速率限制,防止恶意爬虫或滥用。可以使用 next-rate-limit 等中间件库。
    npm install next-rate-limit
    
    // 在API路由中应用
    import { rateLimit } from 'next-rate-limit';
    const limiter = rateLimit({ interval: 60 * 1000, // 1分钟
      uniqueTokenPerInterval: 500, // 最多500个用户/分钟
    });
    export default async function handler(req, res) {
      try {
        await limiter.check(res, 10, 'CACHE_TOKEN'); // 每个用户10次请求/分钟
        // ... 你的业务逻辑
      } catch {
        res.status(429).json({ error: 'Rate limit exceeded' });
      }
    }
    

6. 常见问题与排查技巧实录

在实际开发和调试中,你几乎一定会遇到下面这些问题。这里是我踩过坑后总结的排查清单:

问题现象 可能原因 排查步骤与解决方案
ChatGPT提示“无法安装插件”或“找不到插件清单” 1. 本地服务器未运行。
2. ai-plugin.json 文件路径或内容错误。
3. 本地开发时,ChatGPT无法访问 localhost
1. 确认终端 npm run dev 运行正常,无报错。
2. 直接在浏览器访问 http://localhost:3000/.well-known/ai-plugin.json ,看是否能正确下载JSON文件。检查JSON格式是否正确(可用JSON验证工具)。
3. 这是最常见的问题 :ChatGPT运行在远程服务器,无法直接访问你本机的 localhost 解决方案 :使用内网穿透工具,如 ngrok localtunnel 。安装后运行 ngrok http 3000 ,它会给你一个临时的公网地址(如 https://abc123.ngrok.io ),用这个地址去配置插件。
插件已安装,但AI不调用或调用错误 1. openapi.yaml 文件描述不清晰或语法错误。
2. description_for_model 不够准确。
3. 用户提问方式不符合AI对插件功能的理解。
1. 使用 Swagger Editor 在线验证你的 openapi.yaml 语法。
2. 精炼 description_for_model ,用最直白的语言告诉AI“在什么情况下使用我”。例如:“当用户询问以太坊地址、ENS域名、钱包余额、代币信息或Gas价格时使用此插件。”
3. 在提问时,更明确地提及关键实体,如“用以太坊助手插件查一下...”。
API接口返回错误或超时 1. RPC节点不可用或网络问题。
2. 代码逻辑错误(如未处理异常)。
3. 请求参数格式错误。
1. 首先在浏览器或使用 curl 直接测试你的API端点,例如 curl "http://localhost:3000/api/ens?name=vitalik.eth" 。这能隔离ChatGPT,直接定位后端问题。
2. 查看服务器终端日志,是否有未捕获的异常抛出。确保所有 await 操作都有 try...catch 包裹。
3. 在代码中增加详细的日志,打印出入参和中间状态。
部署后插件失效 1. 生产环境环境变量未正确设置。
2. ai-plugin.json openapi.yaml 中的域名未更新为生产地址。
3. 生产服务器防火墙或安全组策略阻止了访问。
1. 登录Vercel等部署平台的控制台,确认环境变量 ETHEREUM_RPC_URL 已正确配置。
2. 再次检查生产环境下 /.well-known/ai-plugin.json /openapi.yaml 的内容,确保URL指向生产域名且可通过公网访问。
3. 如果用了自定义域名,检查DNS解析是否生效。
处理复杂查询时AI理解偏差 AI可能无法从一段复杂的自然语言中精确提取出API所需的参数。 在设计API时,尽量让参数简单、明确。如果必须处理复杂输入,可以在 description_for_model 中给出更详细的例子,或者考虑在API内部加入一些简单的自然语言解析逻辑(但这会复杂很多)。目前阶段,保持接口简单可靠是上策。

最后一点个人体会 :开发ChatGPT插件,尤其是与区块链这种复杂领域结合,三分在技术,七分在“调教”。你需要不断调整 openapi.yaml description_for_model ,就像在训练一个新手如何正确使用你的工具。多从用户角度出发,思考他们会怎么提问,然后让你的API描述尽可能贴近那些问题。遇到问题时,把链条拆开——先确保API本身能通过HTTP工具直接调通,再确保插件清单能被正确读取,最后才是优化AI调用的准确性。这个过程充满挑战,但当看到ChatGPT流畅地调用你的服务并返回准确的链上数据时,那种成就感是非常独特的。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐