基于Next.js与TypeScript构建ChatGPT区块链插件:EthGPT项目实战解析
ChatGPT插件开发是当前AI应用集成的重要方向,其核心原理是通过OpenAPI规范让AI模型理解并调用外部Web服务。在Web3领域,将AI与区块链结合能显著降低用户与链上数据交互的门槛,提升操作的自然性和效率。EthGPT作为一个开源模板项目,采用Next.js框架和TypeScript语言,为开发者提供了构建ChatGPT区块链插件的完整实践方案。该项目通过定义清晰的API接口,使Chat
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服务。整个过程可以概括为“描述自己,等待调用”:
- 插件清单(
/.well-known/ai-plugin.json) :这是插件的“身份证”。当你在ChatGPT界面配置插件时,它会首先访问这个文件。清单里包含了插件的基本信息,如名称、描述、开发者信息,以及最重要的—— OpenAPI规范(Swagger)文件的URL 。 - OpenAPI规范(
/openapi.yaml或/openapi.json) :这是插件的“能力说明书”。它严格定义了你的插件对外提供了哪些API接口(/api/ens,/api/balance等)、每个接口需要什么参数(比如name代表ENS域名)、返回什么格式的数据。ChatGPT的AI模型会阅读这份规范,从而“学会”在什么情况下应该调用你的哪个接口。 - 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,让我们一步步来:
-
克隆项目并安装依赖 :
git clone https://github.com/xinbenlv/ethgpt.git cd ethgpt npm install # 或 yarn 或 pnpm这一步会安装所有必要的包,包括
next,react,ethers.js,typescript等。 -
配置环境变量 : 复制环境变量示例文件,并填入你自己的配置。
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这类可靠的服务商提供的免费层节点。自己搭建全节点门槛高、同步慢,不适合快速开发。
-
运行开发服务器 :
npm run dev如果一切顺利,终端会显示
> Ready on http://localhost:3000。
4.2 在ChatGPT中安装与配置插件(需插件权限)
由于插件功能处于测试阶段,以下流程基于测试期的经验:
- 在ChatGPT Web界面,选择GPT-4模型,在下拉菜单中选择 “Plugins” 模式。
- 点击插件商店图标,选择 “Develop your own plugin” 或类似选项。
- 在弹出的对话框中,输入你的本地开发服务器地址:
http://localhost:3000。 - ChatGPT会尝试访问你的
http://localhost:3000/.well-known/ai-plugin.json。如果成功,它会读取清单并显示你的插件名称和描述。 - 启用你的插件。现在,你就可以在对话中开始使用它了。
4.3 测试与交互
回到ChatGPT聊天窗口,你可以尝试用自然语言发出指令:
- “请帮我解析一下
vitalik.eth这个ENS域名。” - “查询一下地址
0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045的ETH余额。”
观察ChatGPT的回复。它会先“思考”(决定调用哪个插件接口),然后显示“使用以太坊助手”的提示,最后将插件返回的原始数据(如地址 0x... )组织成一句流畅的话回复给你。
同时,在你的终端里,可以看到服务器接收到请求的日志,这非常便于调试。
4.4 扩展你的插件功能
EthGPT模板只提供了ENS和余额查询两个示例。你可以轻松地添加更多Web3功能:
- 添加新的API端点 :在
pages/api下新建一个文件,例如token.ts,用于查询ERC20代币余额。 - 更新OpenAPI规范 :在
openapi.yaml文件的paths节点下,仿照现有格式,为你新的/api/token路径添加完整的接口定义,包括参数、响应格式等。 - 实现业务逻辑 :在
token.ts中,使用ethers.js调用代币合约的balanceOf函数。 - 更新插件描述 :别忘了修改
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的官方合作平台,部署体验无缝。
- 将你的代码推送到GitHub、GitLab或Bitbucket仓库。
- 登录 Vercel ,点击“New Project”,导入你的仓库。
- 在项目配置页面,Vercel会自动识别为Next.js项目。你需要添加环境变量
ETHEREUM_RPC_URL。 - 点击“Deploy”。几分钟后,你的插件就拥有了一个线上的域名,例如
https://ethgpt.vercel.app。
5.2 更新插件配置
部署成功后,你需要修改两个地方:
- 更新
ai-plugin.json:将文件中所有的http://localhost:3000替换为你的生产域名,例如https://ethgpt.vercel.app。确保logo_url、api.url等字段都指向正确的线上地址。 - 更新
openapi.yaml:将顶部的servers部分的url也改为你的生产域名。
重要提示 :修改这些文件后,需要重新提交并推送代码,触发Vercel重新部署。或者,更专业的做法是使用环境变量来动态配置域名,避免硬编码。
5.3 生产环境优化与安全加固
- 自定义域名与HTTPS :Vercel等平台提供免费的HTTPS。建议绑定一个自定义域名(如
plugin.yourdomain.com),看起来更专业可信。 - 环境变量管理 :在生产环境中,务必使用平台提供的环境变量管理功能来设置
ETHEREUM_RPC_URL,不要使用本地的.env.local文件。 - 启用CORS(如果需要) :虽然ChatGPT插件调用通常不受CORS限制,但如果你计划让其他前端也调用这些API,需要在Next.js配置中正确设置CORS头。
- 监控与日志 :利用Vercel的日志功能或集成Sentry等工具,监控API的错误和性能。
- 速率限制 :实现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流畅地调用你的服务并返回准确的链上数据时,那种成就感是非常独特的。
更多推荐



所有评论(0)