LangChain.js构建MCP智能体:快速接入微软Copilot平台实战指南
1. 项目概述:当LangChain.js遇见微软Copilot平台
如果你最近在捣鼓AI应用开发,特别是想把自己的工具或数据接入到像Microsoft 365 Copilot这样的企业级AI助手里去,那你很可能已经听说过“MCP”(Microsoft Copilot Platform)这个概念了。简单来说,MCP是微软为开发者提供的一套标准,让你能把自己的服务、API或者数据源,变成Copilot可以理解和调用的“技能”。这就像给你的私人AI助理装上了各种专业工具箱,让它不仅能聊天,还能帮你处理特定领域的任务。
而今天要聊的这个项目Azure-Samples/mcp-agent-langchainjs,就是一个非常典型的“桥梁”工程。它解决了一个很实际的问题:如何用当下最流行的LangChain.js框架,快速构建一个符合MCP标准的智能体(Agent)。LangChain.js大家应该不陌生,它是用JavaScript/TypeScript构建AI应用的事实标准,提供了链(Chains)、智能体(Agents)、工具(Tools)等一系列高级抽象,让开发者能像搭积木一样组合大语言模型(LLM)的能力。但直接用它写出来的应用,怎么才能被微软的Copilot平台“认出来”并集成呢?这个官方示例仓库,就是微软给出的标准答案和最佳实践模板。
我自己在尝试将内部知识库接入Teams Copilot时,就遇到了这个痛点。一开始东拼西凑,自己琢磨MCP的协议规范,费时费力还容易出错。直到发现了这个示例,它就像一份详尽的“施工图纸”,不仅展示了完整的结构,还附带了清晰的注释和可运行的代码。无论你是想快速验证一个MCP Agent的想法,还是正在为企业的Copilot扩展寻找技术方案,这个项目都能提供一个极高的起点。它清晰地演示了如何用LangChain.js定义工具、构建智能体逻辑,并最终通过一个标准的HTTP服务器,暴露MCP兼容的接口。接下来,我们就一层层拆解这个项目的设计精髓和实操要点。
2. 核心架构与MCP协议解析
在动手写代码之前,我们必须先理解两个核心概念:LangChain.js的智能体范式,以及MCP协议的基本要求。这个项目的价值,正是将二者优雅地结合了起来。
2.1 LangChain.js智能体基础
LangChain.js中的智能体,其核心思想是让大语言模型(LLM)具备使用“工具”的能力。一个典型的智能体工作流是这样的:
- 用户输入:用户提出一个请求,例如“帮我查一下北京明天天气怎么样?”
- 模型规划:LLM分析请求,判断是否需要调用工具,以及调用哪个工具。
- 工具执行:智能体调用相应的工具(比如一个天气查询API),并获取结果。
- 结果整合:LLM将工具返回的结果整合成自然语言回复给用户。
- 循环判断:如果任务复杂,LLM可能会决定继续调用其他工具,形成多轮对话和工具调用。
在这个流程中,工具(Tool)的定义是关键。在LangChain.js中,一个工具通常是一个包含name、description和invoke方法的对象。description尤为重要,因为LLM就是靠它来理解这个工具是干什么的、什么时候该用它。
2.2 MCP(Microsoft Copilot Platform)协议浅析
MCP定义了一套服务端与Copilot客户端(如Teams Copilot、Windows Copilot)之间的通信规范。你的服务(即MCP Server)需要暴露特定的端点(Endpoint),并按照固定的JSON格式进行交互。主要涉及以下几个方面:
- 清单(Manifest):一个
/.well-known/ai-plugin.json或类似的端点,用于向Copilot客户端描述你的服务:叫什么名字、有什么功能、认证方式是什么、有哪些可用的工具(即“技能”)。 - 工具发现(Tool Discovery):客户端通过某个API(例如
/tools)获取你的服务提供的所有工具列表,包括每个工具的详细模式(Schema),比如输入参数的类型、是否必填等。这通常遵循OpenAPI规范。 - 工具调用(Tool Invocation):客户端在需要时,向你的服务发送请求(例如
POST /tools/{toolName}),执行具体的工具,并期望返回结构化的结果。 - 认证与安全:MCP支持多种认证方式,如API Key、OAuth 2.0等,确保只有授权的Copilot实例可以调用你的服务。
这个项目的核心任务,就是将LangChain.js中定义的Tool对象,自动或手动地转换并暴露为符合MCP协议的工具端点。
2.3 项目架构设计拆解
打开Azure-Samples/mcp-agent-langchainjs的代码结构,你会发现它非常清晰:
src/ ├── agents/ # 智能体逻辑定义 ├── tools/ # 工具定义(核心) ├── server/ # HTTP服务器与MCP端点实现 ├── index.ts # 应用入口 └── ...这种结构遵循了关注点分离的原则:
tools/目录:这里是业务的基石。你在这里用LangChain.js的方式定义每一个具体的工具功能,比如CalculatorTool(计算器)、WebSearchTool(网络搜索)。每个工具都独立成文件,便于维护和测试。agents/目录:这里定义了如何组合和使用这些工具。你可以创建不同的智能体,配置不同的LLM(如Azure OpenAI、OpenAI API),并设定智能体的系统提示词(System Prompt)和行为逻辑。server/目录:这是“粘合剂”和“对外接口”。它负责:- 启动一个Express.js(或类似框架)的HTTP服务器。
- 读取
tools/目录下定义的所有工具。 - 为这些工具生成符合MCP/OpenAPI规范的JSON Schema。
- 实现
/tools(工具发现)和/tools/:name(工具调用)等端点。 - 将HTTP请求路由到对应的LangChain Tool的
invoke方法,并将结果包装成MCP要求的格式返回。
这种设计的好处是,作为业务开发者,你大部分时间只需要关注tools/和agents/里的内容,用你熟悉的LangChain.js模式开发功能。底层的MCP协议转换和服务器逻辑,项目已经帮你封装好了。
注意:MCP的规范细节可能随着Copilot平台的更新而演进。这个官方示例的价值在于,它代表了微软官方认可的、与当前平台兼容的实现方式,具有很高的参考价值,能帮你避免很多潜在的兼容性坑。
3. 从零开始构建你的第一个MCP工具
理论讲得再多,不如动手写一行代码。我们假设要构建一个最简单的“单位转换工具”,将它通过这个项目模板暴露给Copilot。
3.1 环境准备与项目初始化
首先,你需要一个基础环境。
# 1. 克隆示例仓库 git clone https://github.com/Azure-Samples/mcp-agent-langchainjs.git cd mcp-agent-langchainjs # 2. 安装依赖 npm install # 3. 配置环境变量 # 项目通常需要一个.env文件来配置LLM的API密钥和端点 cp .env.example .env # 编辑.env文件,填入你的Azure OpenAI或OpenAI的配置 # OPENAI_API_KEY=sk-... # AZURE_OPENAI_API_KEY=... # AZURE_OPENAI_ENDPOINT=... # AZURE_OPENAI_DEPLOYMENT_NAME=...关键依赖解析:
langchain: LangChain核心库。@langchain/core: LangChain的核心抽象和基础类型。@langchain/openai: 用于连接OpenAI或Azure OpenAI模型。express: Web服务器框架,用于提供HTTP API。zod: 用于定义和验证工具输入参数的模式(Schema),这对于生成准确的OpenAPI描述至关重要。- 其他工具库如
axios(用于网络请求)、cheerio(用于HTML解析)等,根据你需要的工具功能按需安装。
3.2 定义核心工具:单位转换器
现在,我们在src/tools/目录下创建一个新文件unit-converter.tool.ts。
// src/tools/unit-converter.tool.ts import { z } from "zod"; import { DynamicStructuredTool } from "@langchain/core/tools"; import { convert } from "some-unit-conversion-library"; // 假设使用一个现成的转换库 // 1. 使用Zod定义严格的输入参数模式 const UnitConverterInputSchema = z.object({ value: z.number().describe("需要转换的数值"), fromUnit: z.string().describe("原始单位,例如:meter, kilometer, pound, celsius"), toUnit: z.string().describe("目标单位,例如:foot, mile, kilogram, fahrenheit"), }); // 2. 定义工具类,继承自DynamicStructuredTool export const unitConverterTool = new DynamicStructuredTool({ name: "unit_converter", // 工具名称,在MCP中用于标识 description: "将一个数值从一种单位转换为另一种单位。支持长度、重量、温度等常见单位。", // 描述至关重要,LLM靠它理解工具用途 schema: UnitConverterInputSchema, // 绑定输入模式 func: async ({ value, fromUnit, toUnit }) => { // 3. 这里是工具的核心逻辑 try { // 调用实际的转换函数 const result = convert(value).from(fromUnit).to(toUnit); // 返回结构化的结果,最好包含原始输入和转换结果,便于LLM组织语言 return JSON.stringify({ original: `${value} ${fromUnit}`, converted: `${result} ${toUnit}`, note: `转换完成。` }); } catch (error) { // 错误处理很重要,需要给LLM清晰的反馈 return `单位转换失败:${error.message}。请检查单位名称是否正确且支持转换(例如:meter to foot, celsius to fahrenheit)。`; } }, });代码解读与实操要点:
- Schema定义是灵魂:
UnitConverterInputSchema不仅定义了参数类型,其.describe()方法生成的内容会直接成为MCP工具描述的一部分。描述必须清晰、无歧义,例如写“原始单位”而不是“from”,写“目标单位”而不是“to”,这能极大提高LLM调用工具的准确率。 - 工具名称(name):使用蛇形命名(
unit_converter)是常见约定,避免空格和特殊字符。这个名称会在MCP的API路径(如/tools/unit_converter)和请求中被使用。 - 返回值处理:虽然返回字符串即可,但返回结构化的JSON字符串是更佳实践。这样LLM可以更容易地提取关键数据(如
result.converted)来组织回答。同时,务必包含错误处理,返回友好的错误信息,帮助LLM理解问题所在并向用户解释。 - 依赖管理:示例中使用了假想的
some-unit-conversion-library。在实际项目中,你需要选择一个可靠、维护良好的单位转换库,或者自己实现核心转换逻辑。记得通过npm install安装它。
3.3 注册工具并配置智能体
定义好工具后,需要让它被项目感知。通常需要在工具索引文件(可能是src/tools/index.ts)中导出它。
// src/tools/index.ts export { unitConverterTool } from "./unit-converter.tool"; // ... 导出其他已存在的工具接下来,配置智能体来使用这个工具。查看src/agents/目录下的文件,例如basic.agent.ts。
// src/agents/basic.agent.ts (部分代码) import { ChatOpenAI } from "@langchain/openai"; import { createReactAgent } from "@langchain/langgraph/prebuilt"; import { unitConverterTool, calculatorTool, webSearchTool } from "../tools"; // 导入我们的新工具 import { SystemMessage } from "@langchain/core/messages"; export async function createBasicAgent() { // 1. 初始化LLM const llm = new ChatOpenAI({ modelName: "gpt-4", // 或你的部署名称 temperature: 0, // 对于工具调用,低温度(更确定性)通常更好 }); // 2. 定义工具数组 const tools = [unitConverterTool, calculatorTool, webSearchTool]; // 将新工具加入列表 // 3. 定义系统提示词,指导智能体行为 const systemMessage = new SystemMessage( `你是一个乐于助人的助手,可以使用工具来帮助用户。 当你被问到涉及计算、单位转换或需要最新信息的问题时,请务必使用相应的工具。 使用工具后,请将结果清晰、完整地解释给用户。` ); // 4. 创建智能体 const agent = createReactAgent({ llm, tools, messageModifier: systemMessage, }); return agent; }配置解析:
- 工具数组:这是智能体的“技能包”。把你希望智能体能使用的所有工具都放在这个数组里。智能体(背后的LLM)会根据用户问题和工具描述,自动决定何时调用哪个工具。
- 系统提示词(System Prompt):这部分非常关键。你需要在这里明确告知智能体:“你有这些工具,在遇到相关问题时应该去使用。”一个清晰的指令能显著提升工具调用的准确率和主动性。示例中的提示词就是一个很好的起点。
- LLM选择:对于工具调用任务,建议使用
gpt-4或更新、更强的模型。它们在理解复杂指令、规划工具使用顺序方面比gpt-3.5-turbo更可靠。temperature设为0或较低值,可以使工具调用的决策更稳定。
4. MCP服务器端点的实现与调试
工具和智能体都准备好了,下一步就是让它们通过HTTP服务暴露出来,成为真正的MCP Server。
4.1 服务器核心逻辑剖析
项目中的src/server/目录包含了MCP协议适配的核心。我们来看关键部分:
// src/server/mcp-adapter.ts (概念性代码,示意核心流程) import { Tool } from "@langchain/core/tools"; import express from "express"; export function setupMcpEndpoints(app: express.Express, tools: Tool[]) { // 1. 工具发现端点 (GET /tools) app.get("/tools", (req, res) => { const toolSchemas = tools.map(tool => { // 将LangChain Tool转换为OpenAPI格式的Schema return { name: tool.name, description: tool.description, input_schema: convertToOpenApiSchema(tool.schema), // 关键转换函数 }; }); res.json({ tools: toolSchemas }); }); // 2. 工具调用端点 (POST /tools/:name) app.post("/tools/:toolName", async (req, res) => { const { toolName } = req.params; const toolInput = req.body.arguments; // MCP请求通常将参数放在arguments字段 const targetTool = tools.find(t => t.name === toolName); if (!targetTool) { return res.status(404).json({ error: `Tool ${toolName} not found` }); } try { // 调用LangChain Tool的invoke方法 const result = await targetTool.invoke(toolInput); res.json({ tool_name: toolName, result: result, // 返回工具执行结果 }); } catch (error) { console.error(`Error invoking tool ${toolName}:`, error); res.status(500).json({ error: error.message }); } }); // 3. 清单端点 (GET /.well-known/ai-plugin.json) app.get("/.well-known/ai-plugin.json", (req, res) => { res.json({ schema_version: "v1", name_for_human: "我的智能助手工具集", name_for_model: "my_assistant_tools", description_for_human: "一个提供计算、单位转换和网络搜索功能的智能助手。", description_for_model: "提供数学计算、单位换算和信息检索的工具集。", auth: { type: "none" }, // 或 "api_key", "oauth"等 api: { type: "openapi", url: `${getServerUrl()}/openapi.json` }, logo_url: "https://your-server/logo.png", contact_email: "dev@example.com", legal_info_url: "https://your-server/terms", }); }); }关键转换函数convertToOpenApiSchema:这是适配器的核心魔法。它需要将Zod Schema(或LangChain支持的其他Schema)转换成标准的OpenAPI JSON Schema。Zod库本身提供了.describe()信息,但需要额外逻辑来提取并格式化成OpenAPI要求的properties、required等结构。这个示例项目应该已经实现了这个转换函数,或者使用了社区库(如zod-to-openapi)。你需要确保你定义的Zod Schema能被正确转换。
4.2 本地运行与测试
配置完成后,就可以在本地启动服务进行测试了。
# 启动开发服务器,通常配置在package.json的scripts里 npm run dev服务启动后(默认可能在http://localhost:3000),你可以用curl或Postman进行手动测试:
# 1. 测试工具发现端点 curl http://localhost:3000/tools # 2. 测试工具调用端点 curl -X POST http://localhost:3000/tools/unit_converter \ -H "Content-Type: application/json" \ -d '{ "arguments": { "value": 10, "fromUnit": "kilometer", "toUnit": "mile" } }'预期的工具发现响应应该包含unit_converter工具的完整Schema描述。工具调用响应应该返回类似{"tool_name":"unit_converter","result":"{\"original\":\"10 kilometer\",\"converted\":\"6.21371 mile\",\"note\":\"转换完成。\"}"}的结果。
4.3 集成到Microsoft 365 Copilot进行测试
本地测试通过后,真正的考验是让Copilot来调用。这通常需要一个公开的、HTTPS的端点。你可以使用内网穿透工具(如ngrok)快速暴露本地服务到公网,或者部署到Azure App Service、Azure Container Apps等云服务。
- 获取公开URL:例如,使用ngrok:
ngrok http 3000,你会得到一个https://xxxx.ngrok.io的地址。 - 配置清单文件:确保你的
/.well-known/ai-plugin.json中的api.url字段指向这个公开URL(例如https://xxxx.ngrok.io/openapi.json)。 - 在Copilot Studio或相应管理界面添加插件:在Microsoft 365管理员中心或Copilot Studio中,选择添加自定义插件/技能,并输入你的清单文件URL(
https://xxxx.ngrok.io/.well-known/ai-plugin.json)。 - 进行对话测试:在Teams或Word等集成Copilot的应用中,尝试提问:“10公里等于多少英里?” Copilot应该能识别你的工具,并调用它返回准确结果。
实操心得:调试是重头戏集成阶段的调试往往最耗时。务必打开服务器的详细日志,记录每一个 incoming request 和 outgoing response。Copilot对错误响应的格式要求严格,一个不规范的JSON或HTTP状态码都可能导致调用失败。建议先使用Postman完全模拟Copilot的请求格式进行测试,确保你的端点能返回MCP协议预期的精确结构。常见的坑包括:CORS头未设置、响应体缺少必需的字段(如
tool_name)、错误信息格式不兼容等。
5. 高级主题与生产环境考量
当你成功运行起第一个工具后,可能会考虑更复杂的场景和更高的要求。这部分分享一些进阶经验。
5.1 处理复杂工具与多步骤推理
有些任务不是一次工具调用就能完成的。例如,一个“旅行规划”工具,可能需要先调用“天气查询”,再调用“航班搜索”,最后调用“酒店比价”。LangChain.js的智能体框架(如ReAct Agent)本身支持多步推理和工具链调用。关键在于你的工具描述和系统提示词要设计得足够清晰。
对于MCP Server而言,它每次只处理一个工具调用请求。多步骤的协调是由Copilot客户端(或一个更上层的编排层)和你的智能体共同完成的。你的智能体在内部维护对话状态,决定下一步调用哪个工具。MCP Server只需要确保每个独立的工具调用请求能得到正确响应即可。
技巧:对于内部有状态的复杂流程,可以在工具调用时传入一个session_id或conversation_id参数,让你的服务器端能够关联同一会话中的多次调用,维护上下文。
5.2 认证、安全与限流
示例项目开始时可能为了简化,使用auth: { type: "none" }。在生产环境中,这是不可接受的。
- API密钥认证:这是最简单的方式。在清单中配置
auth: { type: "api_key", authorization_type: "bearer" }。你的服务器需要在每个请求的Authorization: Bearer <token>头部验证密钥。密钥应由管理员在Copilot配置界面设置,并安全地存储在你的服务器配置中。 - OAuth 2.0:如果需要访问用户特定的数据(如OneDrive文件、Outlook日历),必须使用OAuth 2.0。这涉及配置重定向URI、客户端ID/密钥,以及实现令牌获取和刷新逻辑。复杂度较高,但MCP协议支持。
- 限流与配额:为防止滥用,必须实施限流。可以使用Express中间件如
express-rate-limit,根据API密钥或IP地址来限制请求频率。 - 输入验证与清理:即使有Zod Schema,在工具执行前仍需进行额外的安全校验。特别是对于执行系统命令、访问数据库或调用外部API的工具,要对输入参数进行严格的过滤和转义,防止注入攻击。
5.3 监控、日志与错误处理
一个健壮的MCP服务离不开可观测性。
- 结构化日志:使用
winston或pino等日志库,记录每一个工具调用的详细信息:工具名、输入参数、执行耗时、成功/失败状态、错误信息。这对于排查问题和分析使用情况至关重要。 - 性能监控:监控工具调用的延迟和成功率。如果某个工具(如网络搜索)经常超时或失败,可能需要优化其实现或设置更短超时时间。
- 错误反馈:确保返回给Copilot的错误信息是用户友好的。不要将堆栈跟踪或内部错误码直接返回。可以定义一套标准的错误响应格式,包含一个简明的错误代码和面向用户的消息,例如:
{“error”: {“code”: “INVALID_UNIT”, “message”: “不支持所请求的单位转换类型。”}}。
5.4 部署与扩展
对于生产部署,你有多种选择:
- Azure App Service (Node.js):最简单快捷。将代码部署为一个Node.js Web应用即可。易于配置缩放、SSL和自定义域名。
- Azure Container Apps / Azure Kubernetes Service (AKS):如果你使用Docker容器化部署,或者需要更精细的资源控制和微服务架构,这是更好的选择。示例项目通常提供
Dockerfile。 - Serverless (Azure Functions):理论上也可以,但需要注意MCP Server通常是常驻的HTTP服务,而Functions是事件驱动的。可能需要通过Azure Functions的HTTP触发器来适配,并处理好冷启动延迟问题。
部署清单:
- [ ] 将
NODE_ENV设置为production。 - [ ] 确保所有敏感信息(API密钥、数据库连接字符串)通过Azure Key Vault或环境变量管理,绝不写入代码。
- [ ] 配置正确的CORS策略(如果前端需要直接调用)。
- [ ] 设置健康检查端点(如
GET /health),便于负载均衡器和监控系统检查服务状态。 - [ ] 考虑使用Azure Application Insights或类似服务进行应用性能管理(APM)。
6. 常见问题与排查实录
在实际开发和集成过程中,我踩过不少坑。这里总结一份速查表,希望能帮你节省时间。
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| Copilot找不到我的插件 | 1. 清单文件URL无法访问或返回错误。 2. 清单文件格式不符合规范。 3. 服务器未使用HTTPS(生产环境强制要求)。 | 1. 用浏览器直接访问清单URL,确认返回正确的JSON。 2. 使用JSON Schema验证器检查清单文件。 3. 确保公网访问地址是 https://开头。 |
| Copilot识别了插件,但显示“无可用工具” | 1./tools端点返回空数组或错误。2. 工具Schema转换失败,导致描述无效。 3. CORS问题阻止了客户端获取工具列表。 | 1. 直接调用/tools端点,检查返回的工具列表。2. 检查服务器日志,看Zod到OpenAPI的转换是否有报错。 3. 在浏览器开发者工具中查看网络请求,确认 /tools请求成功且响应头包含Access-Control-Allow-Origin: *(或指定域名)。 |
| 工具调用失败,返回“工具执行错误” | 1. 工具invoke方法内部抛出异常。2. 请求参数格式不正确,无法通过Zod验证。 3. 工具依赖的外部服务(如API)不可用或超时。 | 1. 查看服务器端错误日志,找到具体的异常堆栈。 2. 用Postman模拟Copilot的请求体,确保与工具Schema定义完全匹配。 3. 为工具调用添加超时和重试机制,并对外部API调用做好降级处理。 |
| 工具被调用,但结果不符合预期 | 1. 工具描述(description)不够清晰,导致LLM误解了工具用途。2. 系统提示词未有效引导智能体使用工具。 3. LLM模型能力不足(如使用了 gpt-3.5-turbo)。 | 1.优化工具描述:用更具体、无歧义的语言重写description,甚至可以举例说明使用场景。2.强化系统提示:在系统提示中明确列出工具及其适用场景。 3.升级LLM模型:切换到 gpt-4或更新模型,其在工具调用规划上准确率更高。 |
| 服务在高并发下响应慢或崩溃 | 1. 未实施限流,被突发流量打垮。 2. 工具本身执行慢(如网络请求),阻塞了Node.js事件循环。 3. 内存泄漏。 | 1. 立即添加API速率限制。 2. 对耗时工具操作进行异步化或队列处理,避免阻塞。 3. 使用 node --inspect和内存分析工具(如Chrome DevTools)排查内存泄漏点,特别是缓存逻辑。 |
| 认证失败 | 1. API密钥未在请求头中正确传递。 2. 服务器端验证逻辑有误。 3. 密钥已过期或被撤销。 | 1. 检查Copilot配置界面,确认密钥已正确设置。 2. 在服务器端日志中打印收到的 Authorization头,进行比对。3. 实现一个简单的令牌验证端点用于测试。 |
独家避坑技巧:
- 模拟测试先行:在尝试真正的Copilot集成前,强烈建议先写一个简单的测试脚本,模拟Copilot的行为来调用你的本地服务。这能帮你快速定位协议层和业务逻辑层的问题,比在Copilot的复杂环境中调试高效得多。
- 描述即契约:把工具的
name和description字段当作与LLM签订的“契约”。花时间反复打磨这些描述,使其精准、简洁、覆盖边界情况。这是提升工具调用准确率性价比最高的方法。 - 从简单到复杂:不要一开始就构建需要多轮交互的复杂智能体。先确保单个工具能被稳定、正确地调用。然后再逐步增加工具数量,最后再考虑智能体的复杂推理逻辑。每一步都充分测试。
- 关注官方动态:MCP和Copilot生态在快速演进。定期查看
Azure-Samples官方仓库的更新、Issues和Discussions,了解最新的协议变更、已知问题和社区解决方案。
这个项目作为一个起点,已经为你铺平了大部分道路。剩下的,就是发挥你的创意,用LangChain.js构建出真正有价值的工具,并通过微软Copilot这个强大的平台,将它们交付到数百万用户的手中。从一个小小的单位转换器开始,逐步构建你的AI应用生态,这个过程本身,就充满了挑战和乐趣。
