AI技能开发脚手架:从零构建大模型应用的标准化起点

news2026/5/16 8:29:07
1. 项目概述一个为AI技能开发量身定制的脚手架如果你正在或打算开发一个基于大语言模型的AI技能Skill无论是想集成到ChatGPT的GPTs里还是想构建一个独立的AI Agent那么你大概率会遇到一个共同的起点问题从零开始搭建项目结构。你需要考虑如何定义技能描述、如何处理用户输入、如何调用外部API、如何管理对话状态、以及如何打包和部署。这个过程充满了重复性的基础工作很容易让人在真正开始实现核心逻辑之前就感到疲惫。NextFrontierBuilds/skill-scaffold这个项目就是为了解决这个“从0到1”的痛点而生的。它是一个专门为AI技能开发设计的项目脚手架Scaffold。简单来说它就像是一个已经为你搭好了骨架、装好了门窗、甚至预埋好了水电管道的“毛坯房”。你拿到手之后不需要再从打地基开始而是可以直接进行“精装修”——也就是专注于实现你这个技能独一无二的业务逻辑。这个脚手架的核心价值在于“标准化”和“提效”。它定义了一套清晰、可扩展的项目结构并预先集成了开发AI技能时最常用的一些工具和模式。无论你是想做一个查询天气的简单技能还是一个需要多轮对话、复杂推理的智能助手都可以基于这个脚手架快速启动避免在项目组织、配置管理等琐事上浪费精力。对于有一定开发经验的工程师来说它能让你跳过繁琐的初始化步骤对于新手而言它提供了一个最佳实践范例是学习AI技能开发范式的绝佳起点。2. 核心架构与设计哲学解析2.1 为什么需要专门的AI技能脚手架在通用软件开发中我们有像create-react-app、Vue CLI这样的脚手架它们为Web前端开发提供了标准化的起点。AI技能开发尤其是基于大语言模型LLM的对话式应用虽然也属于软件范畴但其开发范式与传统Web或移动应用有显著不同。首先AI技能的核心是“意图理解”和“对话管理”。用户输入是自然语言充满不确定性技能需要解析意图、抽取关键参数实体并根据上下文决定下一步动作。其次AI技能常常需要与外部服务API、数据库进行交互以获取信息或执行操作。再者技能的描述如名称、指令、能力声明需要以一种机器可读且平台兼容的格式如OpenAI的GPTs定义格式来呈现。最后开发流程可能涉及本地测试、模拟对话、一键部署到技能市场或平台。一个优秀的脚手架需要将这些共性需求抽象出来并提供相应的解决方案。skill-scaffold正是基于这样的思考其设计哲学可以概括为三点约定优于配置Convention Over Configuration它预先定义好了目录结构、文件命名规范和核心接口。开发者遵循这些约定就能快速构建出结构清晰、易于维护的项目无需在配置文件中花费大量时间。关注点分离Separation of Concerns它将技能描述、业务逻辑、工具集成、对话状态管理等不同职责划分到不同的模块或目录中。这使得代码更易于理解和测试。开发者体验Developer Experience优先它内置了本地开发服务器、对话模拟器、一键打包等工具链让开发者能像开发Web应用一样拥有热重载、实时调试的流畅体验。2.2 项目结构深度拆解让我们深入脚手架生成的项目骨架看看每个部分都承担着什么职责。一个典型的基于skill-scaffold初始化的项目目录可能如下所示my-weather-skill/ ├── package.json ├── skill.json ├── src/ │ ├── index.ts │ ├── skill/ │ │ ├── WeatherSkill.ts │ │ └── types.ts │ ├── tools/ │ │ └── getWeather.ts │ └── utils/ │ └── apiClient.ts ├── tests/ │ └── WeatherSkill.test.ts └── README.md关键文件与目录解析skill.json(核心配置文件)这是技能的“身份证”和“说明书”。它采用结构化格式如遵循OpenAI的GPT定义规范描述了技能的基本信息name: 技能名称如“天气查询助手”。description: 技能的功能描述用于在技能商店中展示。instructions: 给AI模型的系统指令定义了技能的角色、能力边界和对话风格。这是决定技能行为质量的关键。tools: 声明技能可以调用的外部工具列表每个工具对应src/tools/下的一个函数。files(可选): 技能可以访问的知识库文件列表。这个文件是技能与运行平台如ChatGPT之间的契约脚手架会利用这个文件来生成部署包。src/index.ts(应用入口)这是技能的启动文件。它通常负责初始化技能实例、注册工具、启动本地开发服务器或导出供服务器less函数使用的处理器handler。脚手架可能在这里集成了像Express.js这样的Web框架提供一个/chat端点来接收和处理对话请求。src/skill/(技能核心逻辑)这里是存放技能主类的地方。例如WeatherSkill.ts。这个类继承自脚手架提供的一个基类如BaseSkill并实现核心的生命周期方法onStart(conversation): 对话开始时的初始化逻辑。onMessage(message, conversation): 处理用户每一条消息的核心方法。在这里你可以编写逻辑来决定是直接回复还是调用某个工具。onStop(conversation): 对话结束时的清理逻辑。这个设计将技能建模为一个有状态的对象conversation对象则封装了当前的对话历史、用户信息等上下文。src/tools/(工具函数目录)AI技能通过“工具调用”Tool Calling来扩展能力。这个目录存放所有具体的工具实现。每个工具都是一个独立的函数例如getWeather.ts中导出一个异步函数它接收地点参数调用外部天气API并返回结构化的结果。脚手架会自动化地将这些函数注册到技能中并在skill.json里声明。src/utils/(工具函数)存放共享的辅助函数如API客户端、数据格式化工具、日志工具等。tests/(测试目录)包含对技能类和工具函数的单元测试和集成测试。良好的脚手架会预设测试框架如Jest的配置鼓励测试驱动开发。package.json定义了项目依赖、脚本命令。脚手架通常会预设好关键的scripts如npm run dev: 启动带热重载的本地开发服务器。npm run build: 将TypeScript代码编译成JavaScript并打包技能。npm run deploy: 将技能部署到目标平台如某个技能市场。npm test: 运行测试套件。注意以上结构是一个通用性示例NextFrontierBuilds/skill-scaffold的具体实现可能会有所不同但其核心思想是相通的。关键在于理解这种将配置、逻辑、工具分离的架构模式这是构建可维护、可扩展AI技能的基石。3. 从零开始使用脚手架快速初始化你的第一个技能3.1 环境准备与项目创建在开始之前你需要确保本地开发环境已经就绪。首先你需要安装Node.js建议使用LTS版本如18.x或20.x和配套的包管理器npm或yarn。你可以从Node.js官网下载安装包。接下来创建你的技能项目。虽然skill-scaffold可能提供了类似create-skill-app的全局命令但更常见的做法是直接使用Git克隆模板仓库或者使用像degit这样的工具来获取干净的副本。这里我们假设使用克隆的方式# 克隆脚手架仓库这里以假设的仓库地址为例 git clone https://github.com/NextFrontierBuilds/skill-scaffold.git my-first-skill cd my-first-skill # 安装项目依赖 npm install安装完成后花几分钟时间浏览一下package.json中的脚本和依赖项以及根目录下的配置文件如tsconfig.json、.eslintrc等这有助于你了解项目的技术栈和代码规范。3.2 核心配置文件skill.json的定制这是你第一个需要深度修改的文件。打开skill.json你会看到一个模板。你需要将其填充为你自己的技能信息。{ name: 你的技能名称, description: 一段清晰描述技能功能的文字例如一个可以查询全球主要城市当前天气和未来预报的助手。, instructions: 你是一个专业的天气查询助手。你的主要职责是根据用户提供的地点信息查询并返回准确、友好的天气信息。如果用户没有提供明确地点你应该礼貌地询问。你的回复应该简洁明了包含温度、天气状况、体感温度、湿度等关键信息并可以适当给出穿衣或出行建议。不要回答与天气无关的问题。, tools: [ { type: function, function: { name: get_current_weather, description: 获取指定城市的当前天气信息, parameters: { type: object, properties: { location: { type: string, description: 城市名称例如北京 San Francisco } }, required: [location] } } } ] }关键字段详解与编写技巧instructions(系统指令)这是最重要的部分直接“教导”大模型如何扮演你的技能。编写优秀的指令是一门艺术角色定义要清晰“你是一个专业的天气查询助手。”职责边界要明确“只回答与天气相关的问题。”行为规范要具体“如果用户没有提供地点要礼貌询问。”“回复应包含温度、天气状况等信息。”风格要一致“回复应该简洁明了、友好。”你可以通过添加示例对话Few-shot Learning来进一步提升效果例如“示例用户‘上海天气怎么样’ 助手‘上海当前天气晴气温25°C湿度65%东风2级体感舒适建议穿着短袖衣物。’”tools(工具声明)这里声明了技能可用的外部函数。name必须与src/tools/目录下你将要创建的函数名严格对应。description要准确描述工具功能因为大模型会据此决定是否以及如何调用它。parameters定义了工具的输入使用JSON Schema格式务必确保其完备性和准确性。3.3 实现你的第一个工具函数根据skill.json中的声明我们需要在src/tools/目录下创建对应的工具文件。创建src/tools/getCurrentWeather.ts。// src/tools/getCurrentWeather.ts import type { ToolFunction } from ‘../skill/types‘; // 假设脚手架定义了ToolFunction类型 // 定义工具的参数类型与skill.json中的parameters对应 interface GetCurrentWeatherParams { location: string; } // 实现工具函数 export const getCurrentWeather: ToolFunctionGetCurrentWeatherParams async ({ location }) { // 1. 参数验证与预处理 if (!location || location.trim() ‘’) { throw new Error(‘地点参数不能为空‘); } const city location.trim(); // 2. 调用外部天气API这里以模拟数据为例实际应调用如OpenWeatherMap, 和风天气等API console.log([Tool Call] 正在查询 ${city} 的天气...); // 模拟API调用延迟 await new Promise(resolve setTimeout(resolve, 300)); // 3. 模拟API返回数据实际开发中替换为真实的HTTP请求 const mockWeatherData { location: city, temperature: 22, unit: ‘celsius‘, condition: ‘晴朗‘, humidity: 65, windSpeed: 10, feelsLike: 24, forecast: ‘未来24小时天气持续晴朗‘ }; // 4. 处理API响应构造返回给AI模型的结果 // 返回的结果应该是一个结构化的字符串方便AI模型整合到回复中 const resultText 在${mockWeatherData.location}当前天气${mockWeatherData.condition}气温${mockWeatherData.temperature}°C体感温度${mockWeatherData.feelsLike}°C湿度${mockWeatherData.humidity}%风速${mockWeatherData.windSpeed}km/h。${mockWeatherData.forecast}; // 5. 返回结果 return { success: true, data: resultText, // 也可以返回原始结构化数据取决于你的技能如何处理 rawData: mockWeatherData }; }; // 工具的元数据用于自动注册 getCurrentWeather.definition { name: ‘get_current_weather‘, // 必须与skill.json中的name一致 description: ‘获取指定城市的当前天气信息‘, parameters: { type: ‘object‘, properties: { location: { type: ‘string‘, description: ‘城市名称例如北京 San Francisco‘ } }, required: [‘location‘] } };实操心得错误处理是关键工具函数内部必须有完善的错误处理try-catch。网络请求可能失败API可能返回错误参数可能无效。确保工具函数在任何情况下都能返回一个结构化的结果包含success: false和error信息而不是抛出未捕获的异常这能保证技能的鲁棒性。结果格式化返回给AI模型的数据最好是清晰、简洁的文本方便模型直接引用。同时保留一份结构化数据rawData在返回对象中以备技能逻辑需要进一步处理。添加日志在工具函数的开始和结束添加日志输出对于调试复杂的工具调用链至关重要。3.4 编写技能核心逻辑类接下来在src/skill/目录下创建你的技能主类例如WeatherSkill.ts。// src/skill/WeatherSkill.ts import { BaseSkill, type Conversation, type UserMessage } from ‘./BaseSkill‘; // 假设有BaseSkill基类 import { getCurrentWeather } from ‘../tools/getCurrentWeather‘; export class WeatherSkill extends BaseSkill { // 可以在这里定义技能所需的初始化数据或客户端 // private weatherApiClient: WeatherApiClient; constructor() { super(); // this.weatherApiClient new WeatherApiClient(API_KEY); // 注册本技能用到的所有工具 this.registerTool(getCurrentWeather); } /** * 处理用户消息的核心方法 * param message 用户消息 * param conversation 当前对话上下文 */ async onMessage(message: UserMessage, conversation: Conversation): Promisevoid { const userInput message.content; // 1. 简单的意图识别在实际复杂技能中你可能需要集成NLU服务 // 这里只是一个示例检查用户输入是否包含“天气”关键词 const wantsWeather /天气|weather|temperature|下雨|晴天/i.test(userInput); if (!wantsWeather) { // 如果意图不匹配可以返回一个引导性回复 await this.sendMessage(‘我是一个天气查询助手目前只能帮您查询天气信息。请告诉我您想查询哪个城市的天气呢‘, conversation); return; } // 2. 尝试从用户输入中提取地点实体这里使用简单正则生产环境应用更强大的NER const locationMatch userInput.match(/(?:在|于|查询)?\s*([\u4e00-\u9fa5A-Za-z\s]?)(?:的?天气|天气如何)/i); let location locationMatch ? locationMatch[1].trim() : null; if (!location) { // 如果没提取到地点询问用户 await this.sendMessage(‘请问您想查询哪个城市的天气呢‘, conversation); // 可以在这里设置一个对话状态等待用户下一次输入的地点 conversation.setState(‘awaitingLocation‘, true); return; } // 3. 清除可能存在的等待状态 conversation.setState(‘awaitingLocation‘, false); // 4. 调用工具函数获取天气信息 try { const toolResult await this.executeTool(‘get_current_weather‘, { location }); if (toolResult.success) { // 5. 将工具返回的结果发送给用户 await this.sendMessage(根据查询结果${toolResult.data}, conversation); } else { await this.sendMessage(抱歉查询${location}的天气时遇到了问题${toolResult.error}, conversation); } } catch (error) { console.error(‘工具调用失败:‘, error); await this.sendMessage(‘系统繁忙请稍后再试。‘, conversation); } } // 可以重写其他生命周期方法如onStart, onStop async onStart(conversation: Conversation): Promisevoid { await this.sendMessage(‘您好我是天气助手随时为您查询全球天气。‘, conversation); } }注意事项意图识别与实体抽取上面的示例使用了极其简单的正则匹配这仅适用于演示。对于真实技能你需要更强大的自然语言理解NLU能力。可以考虑使用大模型自身的函数调用能力让模型决定何时调用工具。集成专门的NLU服务或库。编写更复杂的规则或机器学习模型。对话状态管理conversation.setState和conversation.getState是管理多轮对话的关键。例如当用户说“查天气”你询问“哪个城市”此时需要设置一个状态以便在用户下一次输入时你知道他是在回答地点问题。工具执行封装this.executeTool是一个假设的基类方法它负责查找已注册的工具、匹配参数并执行。在实际的脚手架中这个机制可能由框架底层自动完成你只需要在onMessage中返回一个包含工具调用指令的响应即可。4. 本地开发、测试与调试实战4.1 启动本地开发服务器大多数现代脚手架都集成了本地开发服务器。查看你的package.json通常会有一个dev脚本。npm run dev执行后终端会输出类似以下信息 my-first-skill1.0.0 dev ts-node-dev src/index.ts [INFO] 技能服务启动在 http://localhost:3000 [INFO] 技能描述已加载: 你的技能名称 [INFO] 已注册工具: get_current_weather现在你的技能已经作为一个本地Web服务运行起来了。它可能会提供一个简单的聊天界面通过内置的静态页面或者一个标准的HTTP API端点如POST /chat。4.2 使用模拟聊天界面进行测试如果脚手架提供了Web界面打开浏览器访问http://localhost:3000。你会看到一个简单的聊天窗口。尝试输入“北京天气怎么样”“帮我查一下纽约的天气。”“天气” 看它是否会询问地点“明天会下雨吗” 测试超出预设工具范围的回复通过这个界面你可以直观地测试技能的对话流、工具调用和回复内容。这是功能测试和体验调试最快捷的方式。4.3 进行API接口测试对于没有UI的脚手架或者你想进行自动化测试你需要直接调用技能提供的API。通常是一个接收JSON的POST端点。使用curl或 Postman 进行测试curl -X POST http://localhost:3000/chat \ -H “Content-Type: application/json“ \ -d ‘{ “message“: “上海今天天气如何“, “conversationId“: “test_conv_123“ # 可选用于维持对话会话 }‘预期的响应应该包含AI助手的回复如果触发了工具调用响应里可能还会包含工具调用的信息和结果。调试技巧查看服务器日志所有console.log和工具调用信息都会在运行npm run dev的终端中输出。这是排查问题的一线窗口。使用调试器在package.json的dev脚本中可能已经配置了--inspect标志。你可以在VSCode等编辑器中附加Node.js调试器在onMessage或工具函数中设置断点进行单步调试。结构化日志在关键位置如工具函数开始/结束、状态变更时输出结构化的JSON日志便于使用日志分析工具进行追踪。4.4 编写单元测试为了保证代码质量特别是工具函数的可靠性编写测试是必不可少的。在tests/目录下为你的工具和技能逻辑创建测试文件。// tests/getCurrentWeather.test.ts import { getCurrentWeather } from ‘../src/tools/getCurrentWeather‘; describe(‘getCurrentWeather Tool‘, () { it(‘should return weather data for a valid location‘, async () { const result await getCurrentWeather({ location: ‘北京‘ }); expect(result.success).toBe(true); expect(result.data).toContain(‘北京‘); expect(result.data).toContain(‘气温‘); // 检查返回文本中包含关键信息 expect(result.rawData).toHaveProperty(‘temperature‘); expect(result.rawData).toHaveProperty(‘condition‘); }); it(‘should handle empty location parameter‘, async () { // 注意这里测试的是函数内部抛出的错误还是返回了 {success: false} // 根据你的实际错误处理方式调整断言 await expect(getCurrentWeather({ location: ‘‘ })) .rejects .toThrow(‘地点参数不能为空‘); // 或者 // const result await getCurrentWeather({ location: ‘‘ }); // expect(result.success).toBe(false); // expect(result.error).toBeDefined(); }); it(‘should handle API simulation delay‘, async () { const startTime Date.now(); await getCurrentWeather({ location: ‘Test‘ }); const duration Date.now() - startTime; // 确保延迟大约在300ms左右考虑误差 expect(duration).toBeGreaterThan(250); expect(duration).toBeLessThan(350); }); });运行测试npm test实操心得为工具函数编写测试时要重点覆盖正常成功路径、各种边界情况空参数、无效参数、网络错误或API返回错误的模拟。使用jest.mock或sinon来模拟外部HTTP请求避免在测试中真正调用外部服务。5. 构建、打包与部署流程详解5.1 构建生产版本开发完成后你需要将TypeScript代码编译成JavaScript并打包成适合部署的格式。npm run build这个命令通常会做以下几件事类型检查运行tsc --noEmit确保没有类型错误。代码编译将src/下的TypeScript文件编译到dist/或build/目录。依赖打包可能会使用webpack、esbuild或ncc等工具将项目代码和必要的node_modules依赖打包成一个或几个独立的JS文件以减少部署体积和依赖问题。资源复制复制skill.json、README.md等静态文件到输出目录。构建完成后检查dist/目录你应该能看到所有运行所需的文件。5.2 部署到技能平台部署的目标平台取决于你的技能脚手架是为哪个生态系统设计的。常见的有OpenAI GPTs如果你的技能遵循OpenAI的GPTs Action规范打包结果可能是一个符合特定结构的ZIP文件里面包含skill.json(或openapi.yaml) 和打包后的代码。你可以通过GPTs编辑器上传并配置。自定义服务器/Serverless更多情况下技能被部署为一个独立的HTTP服务。你可以将dist/目录下的文件部署到任何可以运行Node.js的环境传统云服务器如AWS EC2, Google Cloud VM。容器服务将应用Docker化部署到AWS ECS, Google Cloud Run, Kubernetes。Serverless函数这是非常流行的方式因为AI技能的请求模式通常是突发、无状态的。你可以部署到Vercel/Netlify对于前端友好的Serverless平台。AWS Lambda/Google Cloud Functions/Azure Functions主流云厂商的FaaS服务。腾讯云云函数/阿里云函数计算国内云厂商的同类服务。脚手架通常已经配置好了针对某个平台的部署脚本。例如package.json里可能有一个deploy脚本{ “scripts“: { “deploy“: “vercel --prod“ } }或者它可能提供了详细的部署指南在DEPLOY.md文件中。5.3 部署后的监控与维护技能上线后工作并未结束。日志与监控确保你的部署环境有完善的日志收集如使用Winston、Pino等日志库并集成到云日志服务。监控技能的响应时间、错误率和工具调用成功率。错误报警设置报警机制当错误率超过阈值或关键工具如天气API持续失败时能及时通知到你。性能优化冷启动对于Serverless部署冷启动延迟是常见问题。可以考虑使用预置并发、将技能保持在“温暖”状态或优化代码包大小。外部API调用工具函数中对外部API的调用是主要的性能瓶颈和潜在故障点。务必添加超时、重试和熔断机制。迭代更新根据用户反馈和监控数据持续优化你的instructions、工具函数和对话逻辑。建立一套可靠的CI/CD流程实现自动化测试和部署。6. 进阶技巧与最佳实践6.1 设计复杂的多轮对话简单的单轮问答QA技能很容易实现。但一个强大的AI技能往往需要处理复杂的多轮对话。这依赖于有效的对话状态管理。策略一显式状态机在技能类中定义一个清晰的状态枚举并在conversation对象中存储当前状态。enum ConversationState { IDLE ‘idle‘, AWAITING_LOCATION ‘awaiting_location‘, AWAITING_DATE ‘awaiting_date‘, CONFIRMING_FORECAST ‘confirming_forecast‘ } async onMessage(message: UserMessage, conversation: Conversation) { const currentState conversation.getStateConversationState(‘state‘) || ConversationState.IDLE; const userInput message.content; switch (currentState) { case ConversationState.IDLE: if (userInput.includes(‘天气预报‘)) { await this.sendMessage(‘请问您想查询哪个城市未来几天的天气‘, conversation); conversation.setState(‘state‘, ConversationState.AWAITING_LOCATION); } break; case ConversationState.AWAITING_LOCATION: const location extractLocation(userInput); conversation.setState(‘location‘, location); await this.sendMessage(好的查询${location}。请问您想查询哪一天例如明天后天或未来几天, conversation); conversation.setState(‘state‘, ConversationState.AWAITING_DATE); break; case ConversationState.AWAITING_DATE: // ... 处理日期然后调用工具最后进入确认状态或返回IDLE break; } }策略二让大模型管理状态更推荐对于更复杂的对话一个更强大的模式是将对话历史完全交给大模型并利用其函数调用能力。你的onMessage方法会变得非常简单async onMessage(message: UserMessage, conversation: Conversation) { // 1. 将整个对话历史包括之前的工具调用结果整理成OpenAI API所需的messages格式 const messages this.buildOpenAIMessages(conversation.history); // 2. 调用大模型API如gpt-4并传入你定义的工具列表来自skill.json const openAIResponse await openai.chat.completions.create({ model: ‘gpt-4‘, messages, tools: this.getToolDefinitions(), // 从skill.json或注册的工具中获取 tool_choice: ‘auto‘, // 让模型决定是否调用工具 }); const responseMessage openAIResponse.choices[0].message; // 3. 检查模型是否想调用工具 if (responseMessage.tool_calls) { // 4. 并行执行所有被调用的工具 const toolResults await Promise.all( responseMessage.tool_calls.map(tc this.executeToolById(tc.id, tc.function)) ); // 5. 将工具执行结果作为新的消息追加到对话历史 conversation.addToolResults(toolResults); // 6. 递归调用onMessage让模型基于工具结果生成最终回复 return this.onMessage({ role: ‘user‘, content: ‘继续‘ }, conversation); // 发送一个虚拟消息触发下一轮 } else { // 7. 模型生成了最终文本回复发送给用户 await this.sendMessage(responseMessage.content, conversation); } }这种方式将复杂的对话状态管理、意图识别和上下文理解都交给了更擅长此事的大模型你的代码只需专注于可靠地执行工具和编排流程。这是目前构建复杂AI技能的主流范式。6.2 工具函数的优化与设计模式工具聚合不要为每一个细粒度的API都创建一个工具。考虑创建“聚合工具”。例如一个search_web工具可以处理多种信息查询而不是分别创建search_weather、search_news、search_flight。参数验证与默认值在工具函数内部进行严格的参数验证和清洗。为可选参数提供合理的默认值。异步与超时所有工具函数都应该是async的。为任何外部HTTP请求设置明确的超时如使用axios的timeout配置或Promise.race避免一个缓慢的工具拖垮整个技能响应。缓存策略对于频繁查询、结果变化不快的工具如天气几分钟内变化不大可以考虑引入简单的内存缓存如node-cache或分布式缓存以提升响应速度和降低外部API调用成本。错误重试与降级实现指数退避的重试逻辑。对于非核心功能设计降级方案如天气API失败时返回一个友好的错误信息而不是崩溃。6.3 安全性与隐私考量API密钥管理绝对不要将API密钥硬编码在代码或提交到版本库中。使用环境变量.env文件由dotenv读取或云平台的密钥管理服务如AWS Secrets Manager。输入净化对用户输入和工具参数进行严格的验证和净化防止注入攻击。输出过滤对从外部API获取并最终返回给用户的数据进行审查避免返回敏感或不当信息。权限控制如果你的技能涉及用户数据或敏感操作确保实现适当的身份验证和授权机制。合规性了解并遵守目标部署平台如OpenAI GPT商店的政策以及你所在地区的数据隐私法规如GDPR。使用skill-scaffold这样的脚手架最大的好处是它为你处理了80%的通用、繁琐的工程问题让你能集中精力在剩下的20%——即你的技能独一无二的逻辑和用户体验上。从配置技能描述到实现工具函数再到管理对话流每一步都有迹可循。随着你构建的技能越来越多你会逐渐形成自己的一套模式和工具库而这个脚手架就是你坚实且可复用的起点。记住最好的学习方式就是动手做一个。从今天这个简单的天气技能开始尝试加入更多功能比如查询空气质量、穿衣建议或者整合日历工具来安排户外活动在实践中不断迭代和深化你的理解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2608150.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…