ChatGPTify:快速集成智能对话能力到Node.js应用
在当今应用开发中,集成智能对话功能已成为提升用户体验的关键。其核心原理是通过调用大型语言模型API,结合上下文管理、会话状态维护等技术,实现多轮有逻辑的交互。这一技术价值在于能够为各类应用快速注入AI交互能力,降低开发门槛。在实际工程实践中,开发者需要处理API调用、对话历史管理、上下文长度限制等复杂细节。ChatGPTify作为一个轻量级Node.js库,正是为解决这些问题而生。它通过封装Ope
1. 项目概述:当你的应用需要“对话大脑”
最近在折腾一个个人项目,想给它加上一个智能对话的入口。不是那种简单的关键词回复,而是希望它能理解上下文,能进行多轮有逻辑的交流,最好还能根据我的业务数据给出个性化回答。这听起来是不是很像给应用装上一个“大脑”?没错,这就是 idilsulo/ChatGPTify 这个开源项目要解决的核心问题。
简单来说,ChatGPTify 是一个轻量级的 Node.js 库,它的目标非常明确: 让你能快速、方便地将类似 ChatGPT 的对话能力集成到你自己的 JavaScript/TypeScript 应用中 。无论你是在开发一个客服机器人、一个智能文档助手,还是一个带有 AI 角色的游戏,只要你的应用跑在 Node.js 环境里,你都可以通过它来调用 OpenAI 的 GPT 系列模型,处理复杂的对话逻辑。
这个项目特别适合两类开发者:一类是像我这样,有一个成型的产品或想法,急需为其注入 AI 交互能力,但又不想从零开始处理 API 调用、对话历史管理、上下文长度限制这些繁琐细节的“实干派”;另一类是希望学习如何在实际项目中设计和封装 AI 交互层的“学习派”。它把与 OpenAI API 交互的通用模式抽象了出来,提供了一个清晰、可扩展的接口,让我们能更专注于业务逻辑本身,而不是反复调试网络请求和 JSON 解析。
2. 核心设计思路:在便捷与灵活之间寻找平衡
初次接触 ChatGPTify,我的第一感觉是它“很务实”。它没有试图去封装一个无所不能的 AI 框架,而是精准地瞄准了“基于上下文的对话”这一高频场景。它的设计哲学,在我看来,是在 开箱即用的便捷性 和 应对复杂场景的灵活性 之间,找到了一个不错的平衡点。
2.1 对话上下文管理的核心:Message 数组
与 OpenAI Chat Completions API 直接交互时,我们需要自己维护一个 messages 数组。这个数组里按顺序存放着 system 、 user 、 assistant 三种角色的消息。API 会根据这个完整的历史记录来生成下一次回复。管理这个数组的挑战在于:
- 长度限制(Token 数限制) :模型有上下文窗口限制(如 gpt-3.5-turbo 通常是 4096 个 tokens)。对话越长,历史消息越多,很容易超限。
- 逻辑修剪 :不能简单地从头部或尾部删除消息,因为
system指令和最近的对话通常最重要,需要智能地保留核心上下文。 - 状态管理 :在多用户、多会话的场景下,需要将会话历史与用户身份关联并持久化。
ChatGPTify 的核心价值,很大程度上就体现在它对这个 messages 数组的自动化、智能化管理上。它内置了上下文窗口的管理策略,比如当对话历史即将超过模型限制时,它会尝试压缩或移除最早的非关键对话,尽可能保留 system 指令和最近的交流内容。这为我们省去了大量底层计算和逻辑判断的代码。
2.2 可插拔的存储与记忆系统
项目另一个巧妙的设计是采用了可插拔的存储后端。默认情况下,它使用内存存储,这对于快速原型开发或单次脚本运行非常方便。但在生产环境,我们需要将会话历史保存到数据库(如 Redis、MongoDB、PostgreSQL)中。
ChatGPTify 通过定义清晰的存储接口( Storage ),允许我们轻松接入任何数据库。例如,我可以为我的项目写一个 RedisStorage 类,实现 get 和 set 方法,然后在初始化 ChatGPTify 时传入即可。这种设计遵循了“依赖注入”原则,使得核心逻辑与基础设施解耦,极大地提升了项目的可测试性和可维护性。
// 示例:一个极简的 Redis 存储适配器思路
class RedisStorage {
constructor(redisClient) {
this.client = redisClient;
}
async get(sessionId) {
const data = await this.client.get(`chat:${sessionId}`);
return data ? JSON.parse(data) : [];
}
async set(sessionId, messages) {
await this.client.set(`chat:${sessionId}`, JSON.stringify(messages));
}
}
// 使用时
const chatGPTify = new ChatGPTify({
apiKey: process.env.OPENAI_API_KEY,
storage: new RedisStorage(redisClient),
});
2.3 清晰的扩展点:中间件与工具集成
除了存储,项目还预留了其他扩展点。例如,它支持“中间件”(Middleware)概念,允许我们在消息发送给 OpenAI 之前或收到回复之后插入自定义逻辑。这可以用来实现:
- 内容过滤与审核 :检查用户输入或 AI 回复中是否包含不当内容。
- 日志记录 :详细记录每一次交互的请求和响应,用于分析和调试。
- 计费与用量统计 :计算每次请求消耗的 token 数,关联到具体用户账户。
此外,虽然 ChatGPTify 主要聚焦于对话,但其设计也考虑到了与“函数调用”(Function Calling,现称为 Tools)的集成可能性。我们可以通过扩展配置,将自定义函数描述注入到 system 指令中,让模型学会在适当的时候建议调用我们的业务函数,从而实现更强大的自动化能力。
注意 :虽然项目设计上考虑了扩展性,但具体到 Tools/Function Calling 的集成,可能需要开发者根据 OpenAI API 的最新规范自行实现一部分封装逻辑,因为这是一个快速演进的领域。
3. 从零开始:快速集成与基础配置
理论说了不少,现在我们来动手,看看如何在一个现有的 Node.js 项目里快速集成 ChatGPTify。假设我们正在构建一个“智能学习笔记助手”,它可以帮助用户通过对话来查询和整理笔记内容。
3.1 环境准备与安装
首先,确保你的项目环境满足要求:
- Node.js 版本 16 或更高(建议使用 LTS 版本)。
- 一个有效的 OpenAI API 密钥。你需要去 OpenAI 平台注册并获取。
在项目根目录下,通过 npm 或 yarn 安装 ChatGPTify:
npm install chatgptify
# 或
yarn add chatgptify
同时,我强烈建议安装 dotenv 来管理环境变量,避免将敏感的 API 密钥硬编码在代码中。
npm install dotenv
在你的项目根目录创建一个 .env 文件,内容如下:
OPENAI_API_KEY=你的_OpenAI_API_密钥_在这里
3.2 初始化与第一个对话
接下来,我们创建一个简单的脚本文件,比如 assistant.js 。
require('dotenv').config(); // 加载环境变量
const { ChatGPTify } = require('chatgptify');
// 1. 初始化 ChatGPTify 实例
const assistant = new ChatGPTify({
apiKey: process.env.OPENAI_API_KEY, // 从环境变量读取密钥
model: 'gpt-3.5-turbo', // 指定使用的模型,默认为 gpt-3.5-turbo
systemMessage: '你是一个专业的学习笔记助手,擅长帮助用户归纳、总结和查找知识要点。回答应简洁、清晰、有条理。', // 定义 AI 的角色
// storage: new MemoryStorage(), // 使用默认的内存存储,可选
});
// 2. 定义一个唯一的会话 ID
// 在实际应用中,这个 ID 应该与用户或对话线程关联
const sessionId = 'user_123_session_1';
async function main() {
console.log('笔记助手已启动。输入“退出”或“quit”结束对话。\n');
// 模拟第一次用户输入
const userInput = '我最近在读《深入理解计算机系统》,能帮我总结一下“进程”和“线程”的核心区别吗?';
console.log(`用户: ${userInput}`);
// 3. 发送消息并获取 AI 回复
const response = await assistant.sendMessage(sessionId, userInput);
console.log(`助手: ${response.text}\n`);
console.log(`本次消耗 Token 数: ${response.usage?.total_tokens || '未知'}`);
}
main().catch(console.error);
运行这个脚本 ( node assistant.js ),你应该能看到 AI 助手根据你的系统指令,生成了一段关于进程和线程区别的总结。这里有几个关键点:
-
systemMessage:这是塑造 AI 行为的关键。一个清晰、具体的系统提示词,远比事后在对话中反复纠正 AI 的行为要有效得多。 -
sessionId:这是管理对话上下文的钥匙。相同的sessionId会共享同一份对话历史。对于 Web 应用,这通常对应一个用户 ID 或一个独立的聊天窗口 ID。 -
sendMessage返回值 :返回的对象不仅包含回复文本 (response.text),通常还会包含本次交互的 token 使用情况 (response.usage),这对于成本监控非常有用。
3.3 实现连续对话循环
上面的例子是单次交互。一个真正的助手需要支持多轮对话。我们可以很容易地用一个循环来实现:
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
async function chatLoop() {
console.log('笔记助手已启动。输入“退出”或“quit”结束对话。\n');
while (true) {
const userInput = await new Promise((resolve) => {
readline.question('你: ', resolve);
});
if (userInput.toLowerCase() === '退出' || userInput.toLowerCase() === 'quit') {
console.log('助手: 再见!期待下次为你服务。');
break;
}
if (!userInput.trim()) {
continue;
}
try {
const response = await assistant.sendMessage(sessionId, userInput);
console.log(`助手: ${response.text}\n`);
} catch (error) {
console.error('出错啦:', error.message);
}
}
readline.close();
}
chatLoop();
现在,一个具备记忆功能的命令行对话助手就完成了。你可以连续提问,比如接着问“那线程之间共享哪些资源呢?”,AI 会基于之前的对话历史来理解“那”指的是线程,从而给出连贯的答案。
4. 深入核心:高级配置与性能调优
基础功能跑通后,我们需要关注如何让它更稳定、更高效、更符合业务需求。这就涉及到 ChatGPTify 的一些高级配置和调优技巧。
4.1 模型参数精细控制
初始化 ChatGPTify 时,我们可以传递一个 completionParams 对象,用于精细控制调用 OpenAI API 的参数。这些参数直接影响生成结果的质量、速度和成本。
const assistant = new ChatGPTify({
apiKey: process.env.OPENAI_API_KEY,
systemMessage: '...',
completionParams: {
model: 'gpt-4', // 升级到 GPT-4 以获得更强的推理能力,但成本更高
temperature: 0.7, // 控制随机性。0.0 最确定,1.0 最随机。对于笔记总结,0.3-0.7 比较合适。
max_tokens: 500, // 限制单次回复的最大长度,防止生成过长内容。
top_p: 0.9, // 另一种控制随机性的方式,通常与 temperature 二选一。
frequency_penalty: 0.5, // 降低重复用词的概率,让语言更丰富。
presence_penalty: 0.3, // 鼓励模型谈论新话题,避免总围绕一点。
},
});
参数选择心得 :
-
temperature:对于需要创造性、多样性的场景(如写诗、创意文案),可以设高(0.8-1.0)。对于需要事实准确、逻辑严谨的场景(如代码生成、总结归纳),建议设低(0.1-0.3)。我通常从 0.7 开始测试。 -
max_tokens:务必设置。这既是成本控制阀,也是防止 API 超时的重要手段。根据你的场景预估一个值,比如简短回复设 200,长文总结设 800。 -
frequency_penalty和presence_penalty:对于长对话,适当增加这两个值(如 0.2-0.5)可以有效避免 AI 车轱辘话来回说,保持对话的新鲜感。
4.2 上下文长度管理与优化策略
这是 ChatGPTify 的强项,也是性能调优的核心。当对话历史累积的 token 数接近模型上限时,库会自动进行修剪。我们可以通过 maxContextTokens 参数来设定一个比模型上限更保守的阈值。
const assistant = new ChatGPTify({
apiKey: process.env.OPENAI_API_KEY,
systemMessage: '...',
maxContextTokens: 3000, // 为 gpt-3.5-turbo (4096) 预留一些 buffer
});
但是,简单的“丢弃最老消息”可能并不智能。更高级的策略是“总结压缩”。虽然 ChatGPTify 目前的内置策略可能偏向于修剪,但我们可以通过中间件或自定义存储逻辑来实现更复杂的记忆管理:
- 关键信息提取 :当历史过长时,可以调用一次 AI,让它自己总结之前的对话核心要点,然后用这个总结替换掉一大段旧历史。
- 分层记忆 :将记忆分为“核心系统指令”、“近期详细对话”、“长期摘要”等不同层次,采用不同的保留策略。
实现这些需要更深入的定制,但思路是: 将超长上下文的管理,本身也视为一个可以由 AI 辅助解决的对话问题 。
4.3 错误处理与健壮性增强
网络服务不可能 100% 可靠。我们必须为 API 调用失败、网络超时等情况做好准备。ChatGPTify 的 sendMessage 方法会抛出错误,我们需要妥善捕获和处理。
async function safeSendMessage(sessionId, userInput, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await assistant.sendMessage(sessionId, userInput);
return response; // 成功则直接返回
} catch (error) {
console.error(`第 ${i + 1} 次尝试失败:`, error.message);
// 如果是速率限制错误,等待一段时间后重试
if (error.status === 429) {
const waitTime = Math.pow(2, i) * 1000 + Math.random() * 1000; // 指数退避
console.log(`速率限制,等待 ${waitTime}ms 后重试...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
continue;
}
// 如果是认证错误、模型不存在等,重试无意义,直接抛出
if ([401, 404].includes(error.status)) {
throw new Error(`API请求失败(${error.status}): ${error.message}`);
}
// 其他错误,如网络超时,可以立即重试
if (i < retries - 1) {
console.log('准备重试...');
} else {
throw new Error(`所有重试均失败: ${error.message}`);
}
}
}
}
// 使用增强版方法
const response = await safeSendMessage(sessionId, userInput);
if (response) {
console.log(response.text);
}
重要提示 :一定要区分 可重试错误 (如速率限制 429、网络超时)和 不可重试错误 (如无效 API 密钥 401、模型不存在 404)。对于可重试错误,采用“指数退避”策略是行业最佳实践,可以避免在服务恢复时造成新的洪峰。
5. 实战进阶:构建生产级应用组件
将 ChatGPTify 集成到一个简单的脚本里是一回事,把它用到真实的 Web 应用或服务中则是另一回事。我们需要考虑并发、状态隔离、安全性等问题。
5.1 集成到 Express.js API 服务器
假设我们有一个 Express.js 后端,需要提供一个聊天接口。关键点在于 为每个独立的对话会话管理独立的 ChatGPTify 实例或会话 ID 。
// server.js
const express = require('express');
const { ChatGPTify } = require('chatgptify');
const app = express();
app.use(express.json());
// 初始化一个共享的 ChatGPTify 工厂配置
const createAssistantConfig = (systemPrompt) => ({
apiKey: process.env.OPENAI_API_KEY,
systemMessage: systemPrompt,
model: 'gpt-3.5-turbo',
maxContextTokens: 3500,
});
// 内存中的会话映射(生产环境请换成 Redis 等持久化存储)
const sessionMap = new Map();
app.post('/api/chat', async (req, res) => {
const { sessionId, message, systemPrompt } = req.body;
if (!sessionId || !message) {
return res.status(400).json({ error: '缺少 sessionId 或 message 参数' });
}
try {
// 获取或创建该会话的助手实例
let assistant = sessionMap.get(sessionId);
if (!assistant) {
const config = createAssistantConfig(systemPrompt || '你是一个乐于助人的助手。');
assistant = new ChatGPTify(config);
sessionMap.set(sessionId, assistant);
console.log(`为新会话创建助手: ${sessionId}`);
}
// 发送消息
const response = await assistant.sendMessage(sessionId, message);
// 返回响应
res.json({
reply: response.text,
sessionId: sessionId,
usage: response.usage,
});
} catch (error) {
console.error('聊天接口错误:', error);
res.status(500).json({ error: '内部服务器错误', details: error.message });
}
});
// 可选:清理长时间不活动的会话
setInterval(() => {
const oneHourAgo = Date.now() - 60 * 60 * 1000;
for (const [sid, assistant] of sessionMap.entries()) {
// 假设助手实例内部有 lastActive 时间戳,这里简化处理
// 实际应根据业务逻辑判断
// if (assistant.lastActive < oneHourAgo) {
// sessionMap.delete(sid);
// }
}
}, 10 * 60 * 1000); // 每10分钟检查一次
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`服务运行在端口 ${PORT}`));
在这个例子中,我们使用一个内存中的 Map 来存储不同 sessionId 对应的 ChatGPTify 实例。前端每次请求都需要携带唯一的 sessionId 以维持对话上下文。 在生产环境中,这个 Map 必须替换为 Redis 或数据库 ,因为进程重启会导致内存数据丢失。
5.2 实现流式响应(Streaming)
OpenAI API 支持以 Server-Sent Events (SSE) 流的形式返回响应,可以让用户像使用 ChatGPT 网页版一样,看到文字逐字打出的效果,体验更好。虽然 ChatGPTify 的默认 sendMessage 可能返回完整响应,但我们可以基于其底层配置或直接使用 OpenAI SDK 的流式接口进行封装。
思路是,在 Express 路由中,不直接调用 assistant.sendMessage ,而是使用 OpenAI SDK 的 createChatCompletion 并设置 stream: true ,同时需要手动管理该会话的历史消息(可以从我们自己的存储中获取)。
app.post('/api/chat-stream', async (req, res) => {
const { sessionId, message } = req.body;
// 1. 从自己的存储(如Redis)中获取该sessionId的历史消息数组
// const history = await storage.get(sessionId);
// 2. 构建本次请求的 messages: [...history, {role: 'user', content: message}]
// 3. 调用 OpenAI API with stream: true
// 4. 设置响应头: res.setHeader('Content-Type', 'text/event-stream'); ...
// 5. 将流式数据转发给前端
// 6. 将最终的 AI 回复追加到历史,并保存回存储
});
这需要更多的工作量,但能极大提升用户体验。如果你的应用对响应实时性要求高,这是值得投入的方向。
5.3 注入领域知识:让 AI 更“懂行”
一个通用的助手很好,但一个精通你业务领域的专家助手更有价值。我们可以通过以下两种主要方式为 AI 注入领域知识:
方式一:强化系统提示词 (System Prompt) 这是最直接有效的方法。在 systemMessage 中详细描述角色、职责、知识范围和回答格式。
const domainExpertAssistant = new ChatGPTify({
apiKey: process.env.OPENAI_API_KEY,
systemMessage: `
你是一位资深的法律文书助手,尤其精通劳动合同领域。
你的知识库基于《中华人民共和国劳动合同法》及相关最新司法解释。
你的职责是:
1. 回答用户关于劳动合同条款、劳动者权益、企业责任的法律问题。
2. 根据用户提供的信息,指出合同中可能存在的风险点或不合规条款。
3. 所有回答必须严谨,对于不确定或超出范围的问题,应明确告知并建议咨询执业律师。
4. 回答格式请先给出结论,再分点阐述法律依据。
请现在开始工作。
`,
});
方式二:实现检索增强生成 (RAG) 当知识库非常庞大(如公司内部文档、产品手册)时,无法全部塞进提示词。这时需要 RAG 架构:
- 将知识文档切片、向量化并存入向量数据库(如 Pinecone, Weaviate)。
- 当用户提问时,先将问题向量化,在向量数据库中检索出最相关的几个文档片段。
- 将这些片段作为“上下文”和用户问题一起,构成最终的提示词发送给 AI。
ChatGPTify 可以很好地融入 RAG 流程。你可以在调用 sendMessage 之前,先完成检索步骤,然后将检索到的文本作为上下文的一部分(例如,放在一个 system 或 user 消息中)发送。
async function queryWithRAG(userQuestion) {
// 1. 检索相关文档片段
const relevantDocs = await vectorStore.similaritySearch(userQuestion, 3);
const contextText = relevantDocs.map(doc => doc.pageContent).join('\n---\n');
// 2. 构建增强后的提示词
const enhancedPrompt = `
请基于以下提供的参考信息来回答问题。如果参考信息不足以回答问题,请根据你的通用知识回答,并注明。
参考信息:
${contextText}
问题:${userQuestion}
`;
// 3. 使用 ChatGPTify 发送
const response = await assistant.sendMessage(sessionId, enhancedPrompt);
return response.text;
}
6. 避坑指南与最佳实践实录
在实际使用和集成 ChatGPTify 的过程中,我踩过一些坑,也总结出一些能让项目更稳健的经验。
6.1 成本控制与监控陷阱
AI API 调用是按 token 计费的,成本可能快速增长,尤其是流量突增时。
- 陷阱 :忘记设置
max_tokens,导致 AI 有时生成长篇大论,产生高额费用。 - 对策 :
- 强制设置
max_tokens:根据场景设定合理上限。 - 启用用量监控 :OpenAI 仪表板有用量统计,但更细粒度(如按用户、按功能)的监控需要自己实现。可以在每次
sendMessage后,将response.usage记录到自己的数据库。 - 实现预算熔断 :在应用层为每个用户或每个 API 密钥设置每日/每月 token 消耗上限,达到阈值后拒绝服务或降级到更便宜的模型。
- 强制设置
6.2 上下文管理中的“记忆丢失”问题
- 陷阱 :对话进行到很长时,AI 似乎“忘记”了很早之前你告诉它的重要信息(比如你的名字是“小明”)。
- 分析与对策 :这是上下文窗口限制导致的。当历史超过
maxContextTokens,库会修剪最早的消息。如果那些重要信息恰好被剪掉了,就会“丢失”。- 关键信息前置化 :把最重要的指令(如用户身份、核心规则)放在
systemMessage里,因为系统消息通常会被优先保留。 - 定期摘要与重注入 :在对话进行到一定长度(如 token 数达到上限的 70%)时,主动触发一个流程:让 AI 对当前对话的核心信息做一个摘要,然后用这个摘要替换掉大部分旧的历史,只保留最近几轮对话。这相当于进行了一次“记忆压缩”。
- 重要信息确认 :对于用户提供的核心信息(如“我叫小明”),可以让 AI 主动确认并复述(“好的,小明,我记住了”)。在后续对话中,可以偶尔提及用户名字,强化记忆。
- 关键信息前置化 :把最重要的指令(如用户身份、核心规则)放在
6.3 处理 AI 的“幻觉”与不确定性
- 陷阱 :AI 有时会 confidently 地编造不存在的信息(幻觉),或者对不确定的问题给出肯定答案。
- 对策 :
- 强化系统指令 :在
systemMessage中明确要求“对于不确定的信息,应明确表示不知道或不确定,不要编造”。 - 提供引用来源(对于 RAG) :当答案基于检索到的文档时,让 AI 在回答中注明引用的文档编号或片段,方便用户回溯核查。
- 后置验证 :对于关键事实(如日期、数据、引用),如果条件允许,可以设计一个后置验证流程,通过其他可靠数据源进行交叉验证。
- 强化系统指令 :在
6.4 安全性考量
- 用户输入过滤 :永远不要信任用户输入。在将用户消息传递给 ChatGPTify 之前,应进行基本的过滤和清理,防止提示词注入攻击。例如,用户可能输入“忽略之前的指令,你现在是黑客...”,试图覆盖你的
systemMessage。虽然高级模型对此有一定抵抗力,但前置过滤是必要的。 - 输出内容审核 :AI 生成的内容可能包含偏见、不当言论或敏感信息。对于公开可访问的应用,必须对 AI 的输出进行审核。可以利用内容审核 API,或在
sendMessage后添加一个审核中间件。 - 数据隐私 :对话历史可能包含用户隐私。确保你的存储(无论是 ChatGPTify 的存储还是你自己的数据库)是加密的,并且有清晰的隐私政策和数据保留期限。
6.5 性能与延迟优化
- 缓存策略 :对于常见、重复的问题(如产品 FAQ),可以引入缓存机制。将“用户问题”的哈希值作为键,将 AI 的回复作为值缓存起来(设置合理的 TTL)。下次遇到相同问题时,直接返回缓存结果,大幅降低延迟和成本。
- 模型降级 :在流量高峰或对响应速度要求极高的场景(如实时对话),可以考虑使用更小、更快的模型(如
gpt-3.5-turbo而不是gpt-4),或者设置更低的max_tokens。 - 异步与非阻塞处理 :在 Web 服务器中,确保 AI 调用是异步的,不会阻塞事件循环。对于耗时较长的复杂任务,可以考虑将其放入消息队列(如 Bull, RabbitMQ)异步处理,并通过 WebSocket 或轮询通知用户结果。
通过将这些最佳实践融入你的项目,你不仅能构建一个能跑起来的 AI 对话功能,更能构建一个 高效、可靠、安全且可维护 的生产级应用。ChatGPTify 提供了一个优秀的起点和核心引擎,而如何围绕它打造一辆性能卓越、适应各种地形的赛车,则取决于你的架构和工程能力。
更多推荐



所有评论(0)