NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

手把手教你在 JavaScript 中使用 LangChain,解锁 AI 应用能力

作者 | Matt Nikonorov

  • 2023-11-29
    北京
  • 本文字数:9102 字

    阅读完需:约 30 分钟

手把手教你在JavaScript中使用LangChain,解锁AI应用能力

JS 版的 LangChain,是一个功能丰富的 JavaScript 框架。不管你是开发者还是研究人员都可以利用该框架通过创建语言分析模型和 Agents 来开展各项实验。该框架还提供了十分丰富的功能设置,基于这些功能设置,NLP 爱好者可以通过构建自定义模型来提高文本数据的处理效率。与此同时,作为一个 JS 框架,开发人员可以轻松的将他们的 AI 应用集成到自己的 Web 应用中。


环境准备


安装下面的步骤,我们创建一个新目录并且安装 LangChain 的 npm 包:


1.执行如下命令,安装 LangChain 的 npm 包


npm install -S langchain
复制代码


2.在目录下面创建一个以.mjs 为后缀的文件(例如:test1.mjs)


Agents(智体)


在 LangChain 中,一个 Agent 代表的是一个具备理解和生成文本能力的实例。通过给这些 Agent 设置特定行为和数据源,就可以训练他们执行各种与语言相关的任务,从而使他们具备为更多的应用提供服务的能力。


创建 LangChain 的 Agent


利用 LangChain 框架创建的 Agent 在数据获取和响应优化上都支持“工具”的配置。请看下面的示例代码。该例中,Agent 体使用 Serp API(一个网络搜索 API)在互联网上搜索与输入内容相关的信息,然后根据搜索得到的内容完成响应数据的生成,与此同时,它还使用 llm-math 工具来执行诸如 转换单位、百分比对比等 数学运算任务。


// langchain 智能体引入import { initializeAgentExecutorWithOptions } from "langchain/agents";// 引入语言模型:OpenAiimport { ChatOpenAI } from "langchain/chat_models/openai";// 引入网络搜索工具import { SerpAPI } from "langchain/tools";// 引入计算函数 工具import { Calculator } from "langchain/tools/calculator";// OpenAI 的 API 访问的密钥process.env["OPENAI_API_KEY"] = "YOUR_OPENAI_KEY"// SerpAPI 访问密钥process.env["SERPAPI_API_KEY"] = "YOUR_SERPAPI_KEY"// 创建工具链const tools = [new Calculator(), new SerpAPI()];// 模型配置,这里用的是 OpenAI gpt-3.5-turboconst model = new ChatOpenAI({ modelName: "gpt-3.5-turbo", temperature: 0 });// 智能体初始化const executor = await initializeAgentExecutorWithOptions(tools, model, {  agentType: "openai-functions",  verbose: false,});// 执行,这里给出的问题是:"通过搜索互联网,找出自 2010 年以来 Boldy James 发行了多少张专辑,以及 Nas 自 2010 年以来发行了多少张专辑?找出谁发行了更多的专辑,并显示百分比的差异。"const result = await executor.run("By searching the Internet, find how many albums has Boldy James dropped since 2010 and how many albums has Nas dropped since 2010? Find who dropped more albums and show the difference in percent.");console.log(result);
复制代码


上述代码,在模型创建之后,通过 initializeAgentExecutorWithOptions 函数将模型和工具(SerpAPI 和 Calculator)进行合并,生成了一个 executor(执行者)。在输入端,我们要求 LLM(大语言模型) 通过搜索 Internet(使用 SerpAPI),找出自 2010 年以来,Nas 和 Boldy James 这两位艺术家中谁发行了更多专辑,并技术差值百分比(使用计算器)。


在该例子中,我通过明确地告诉 LLM“通过搜索互联网…”,以使它通过互联网获取最新数据,而不使用 OpenAI 的的默认数据(该数据截止 2021 年),从而得出正确答案。


译者注:OpenAI 于 2023 年 11 月 2 日发布会上,表示其模型数据已经更新到了 2023 年 4 月。


下面是上面代码的输出:


> node test1.mjs从 2010 年至今,Boldy James 发了 4 张专辑,Nas 发了 17 张因此,Nas 比 Boldy James 发行的专辑要多,两者发行专辑的差值是 13我们将使用如下公式:(差值 / 总值)*100,来计算差值百分比在这里,差值是 13,总值是 17因此差值百分比是:(13/17)*100 = 76.47%所以,从 2010 年至今,Nas 发布的专辑比 Boldy James 多了 76。47%
复制代码


模型(Models)


LangChain 中支持三种类型的模型使用方式:


  1. LLM(大语言模型)

  2. Chat Model(对话模型)

  3. Embeddings(Embeddings 技术是一种将高纬数据转为低维数据的技术)


下面通过示例,我们一起来了解这三种模型的使用。


语言模型


LangChain 为 JavaScript 提供了使用语言模型能力,通过该能力 JS 可以根据文本输出生成文本输出。它不像聊天模型那么复杂,最适合处理简单的输入 - 输出的语言任务。下面是一个基于 OpenAI 模型的代码示例:


import { OpenAI } from "langchain/llms/openai";const llm = new OpenAI({  openAIApiKey: "你自己的 OpenAI 的密钥",  model: "gpt-3.5-turbo",  temperature: 0});const res = await llm.call("List all red berries");console.log(res);
复制代码


如你所见,该例是要求 OpenAI 的 gpt-3.5-turbo 模型罗列所有的红色浆果。其中,我将 temperature 设为 0,其目的是为了确保 LLM 输出结果的准确性。下面是输出的结果:


1. Strawberries2. Cranberries3. Raspberries4. Redcurrants5. Red Gooseberries6. Red Elderberries7. Red Huckleberries8. Red Mulberries
复制代码


对话模型


如果你需要更复杂的答案和对话,则需要使用对话模型。对话模型在技术上与语言模型有何不同?好吧,用 LangChain 官方文档 的话来说:


对话模型是语言模型的一个变体。虽然对话模型在底层使用的依然是大语言模型,但是他们在接口上略有不同。对话模型没有使用“文本输入、文本输出”格式的 API,而是使用了一个基于“聊天消息”来实现输入输出的接口。


下面是一个简单的 JavaScript 对话模型脚本(该示例相当无用但很有趣)。


import { ChatOpenAI } from "langchain/chat_models/openai";import { PromptTemplate } from "langchain/prompts";// 创建对话,配置密钥、模型版本、和 temperatureconst chat = new ChatOpenAI({  openAIApiKey: "YOUR_OPENAI_KEY",  model: "gpt-3.5-turbo",  temperature: 0});// 通过提示词模版,创建提示词const prompt = PromptTemplate.fromTemplate(`你现在扮演一个诗人的角色,在回答时请保持语言的韵律: {question}`);const runnable = prompt.pipe(chat);// 对话执行const response = await runnable.invoke({ question: "Djokovic, Federer 和 Nadal,三人中谁是最好的网球运动员?" });console.log(response);
复制代码


如你所见,上面的代码首先发送了一条系统消息给对话机器人,告诉它,当前扮演的是一个诗人角色,且在回答的时候要始终使用押韵的方式。然后再向对话机器人发送一条用户消息,让它给出 Djokovic、Federer 和 Nadal 这三人中,谁是最好的网球运动员。如果你运行这个脚本,将会看到如下内容:


// AI 消息体AIMessage.content:'In the realm of tennis, they all shine bright,\n' +'Djokovic, Federer, and Nadal, a glorious sight.\n' +'Each with their unique style and skill,\n' +'Choosing the best is a difficult thrill.\n' +'\n' +'Djokovic, the Serb, a master of precision,\n' +'With agility and focus, he plays with decision.\n' +'His powerful strokes and relentless drive,\n' +"Make him a force that's hard to survive.\n" +'\n' +'Federer, the Swiss maestro, a true artist,\n' +'Graceful and elegant, his game is the smartest.\n' +'His smooth technique and magical touch,\n' +'Leave spectators in awe, oh so much.\n' +'\n' +'Nadal, the Spaniard, a warrior on clay,\n' +'His fierce determination keeps opponents at bay.\n' +'With his relentless power and never-ending fight,\n' +'He conquers the court, with all his might.\n' +'\n' +"So, who is better? It's a question of taste,\n" +"Each player's greatness cannot be erased.\n" +"In the end, it's the love for the game we share,\n" +'That makes them all champions, beyond compare.'
复制代码


译注:这是一首诗,实在翻译不来,就不翻译了哈。


Embeddings


Embeddings 支持将文本数据转换为向量数据,以便于和其他相关的内容进行关联。这可能听起来有点抽象,让我们直接来看一个例子:


import { OpenAIEmbeddings } from "langchain/embeddings/openai";
process.env["OPENAI_API_KEY"] = "YOUR_OPENAI_KEY"
const embeddings = new OpenAIEmbeddings();
const res = await embeddings.embedQuery("谁是万维网之父?");console.log(res)
复制代码


这里是数据返回,是一大串的浮点数据:


[  0.02274114,  -0.012759142,   0.004794503,  -0.009431809,    0.01085313,  0.0019698727,  -0.013649924,   0.014933698, -0.0038185727,  -0.025400387,  0.010794181,   0.018680222,   0.020042595,   0.004303263,   0.019937797,  0.011226473,   0.009268062,   0.016125774,  0.0116391145, -0.0061765253,  -0.0073358514, 0.00021696436,   0.004896026,  0.0034026562,  -0.018365828,  ... 1501 more items]
复制代码


这就是 Embeddings 的形态。仅仅是为了六个单词,就用了那么多浮点数!利用 Embeddings 技术,可以将输入文本与潜在答案、相关文本、名称等进行关联。


下面让我们来看一个 Embeddings 模型的一个使用案例


在下面的脚本中,我们向模型提问:“世界上最重的动物是什么?”。然后我们借助 Embeddings 技术让模型能从我们提供的参考答案中找出最佳答案。


import { OpenAIEmbeddings } from "langchain/embeddings/openai";
process.env["OPENAI_API_KEY"] = "YOUR_OPENAI_KEY"
const embeddings = new OpenAIEmbeddings();// 余弦相似度函数function cosinesim(A, B) { var dotproduct = 0; var mA = 0; var mB = 0;
for(var i = 0; i < A.length; i++) { dotproduct += A[i] * B[i]; mA += A[i] * A[i]; mB += B[i] * B[i]; }
mA = Math.sqrt(mA); mB = Math.sqrt(mB); var similarity = dotproduct / (mA * mB);
return similarity;}// 嵌入 1:蓝鲸是世界上最重的动物const res1 = await embeddings.embedQuery("The Blue Whale is the heaviest animal in the world");// 嵌入 2:乔治·奥威尔写了《一九八四》这本书const res2 = await embeddings.embedQuery("George Orwell wrote 1984");// 嵌入 3:随机内容const res3 = await embeddings.embedQuery("Random stuff");// 源内容数组const text_arr = ["The Blue Whale is the heaviest animal in the world", "George Orwell wrote 1984", "Random stuff"]// 利用 embeddings 转换之后的数据数组const res_arr = [res1, res2, res3]// 问题:世界上最重的动物是什么?const question = await embeddings.embedQuery("What is the heaviest animal?");// 相似度数组const sims = []for (var i=0;i<res_arr.length;i++){ // 这里利用 cosinesim 函数,计算问题和每个答案的相识度 sims.push(cosinesim(question, res_arr[i]))}// 给数组挂载求最大值的函数 (数组本身不具备, 通过原型赋予)Array.prototype.max = function() { return Math.max.apply(null, this);};// 输出相识度最大的 结果console.log(text_arr[sims.indexOf(sims.max())])
复制代码


在上面的代码中,先定义了一个计算相识度的函数:cosinesim(A, B),其次利用 embeddings 技术将每个答案转换为了向量数据,接着使用 cosinesim 函数计算出了每个答案和输入问题的相识度值,最高拿到相识度最高的答案,完成输出。下面是输出的结果:


The Blue Whale is the heaviest animal in the world// 蓝鲸是世界上最重的动物
复制代码


Chunks(数据块)


由于 LangChain 模型在生产响应的时候不支持大文本的输入。所以需要用到诸如文本分割等数据分块的技术将大文本数据分割成多个 Chunk。下面我向你演示 LangChain 中两种简单的文本数据分割方法,以实现大文本输入。


方法一、CharacterTextSplitter


为了避免分割之后,Chunk 中内容中断,可以使用换行符来进行文本拆分,该方法是在每次出现换行符时执行分割,可以通过 CharacterTextSplitter 来实现,示例代码如下:


import { Document } from "langchain/document";import { CharacterTextSplitter } from "langchain/text_splitter";// 创建一个分割器,使用换行符进行分割,每个区块的大小是 7,区块的重叠度是 3const splitter = new CharacterTextSplitter({  separator: "\n",  chunkSize: 7,  chunkOverlap: 3,});const output = await splitter.createDocuments([your_text]);
复制代码


这是拆分文本的一种有用的方法,同时,你可以使用任何字符作为 Chunk 的分隔符,而不仅仅是换行符(\n)


方法二、RecursiveCharacterTextSplitter


如果要严格按一定长度的字符拆分文本,可以使用 RecursiveCharacterTextSplitter 来实现,示例代码如下:


import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";const splitter = new RecursiveCharacterTextSplitter({  // chunk 的大小  chunkSize: 100,  // chunk 的重叠度  chunkOverlap: 15,});const output = await splitter.createDocuments([your_text]);
复制代码


在此示例中,会将文本按照每 100 个字符进行一次拆分,每个 Chunk 的重叠度为 15 个字符。


Chunk 的大小和重叠度


通过上面的示例,想必你已经迫不及待的想知道 Chunk 的大小和重叠度这两个参数确切的含义以及它们对性能的影响了吧。下面我简单从两方面解释下:


  • chunkSize 决定了每个 Chunk 中的字符数量。chunkSize 的值越大,那么 Chunk 中的字符数就越多,LangChain 处理该 Chunk 和产生对应输出所需的时间就越长,反之亦然。

  • chunkOverlap 是用于设置了每个 Chunk 之间共享上下文的大小。chunkOverlap 的值越高,Chunk 的冗余度就越高 ;chunkOverlap 的值越低,Chunk 之间共享的上下文就越少。通常将 chunkOverlap 设置在 Chunk 大小的 10% 到 20% 之间会比较理想,当然,真正理想 chunkOverlap 值还是要根据不同的文本类型和使用场景来确定。


Chains(模型链)


通过单个 LLM 的输入输出是无法完成一些更为复杂的任务,因此需要利用 Chains,通过将多个 LLM 的功能链接一起来完成。下面是一个很有意思的例子:


import { ChatPromptTemplate } from "langchain/prompts";import { LLMChain } from "langchain/chains";import { ChatOpenAI } from "langchain/chat_models/openai";
process.env["OPENAI_API_KEY"] = "YOUR_OPENAI_KEY"
// 这是一段知识库const wiki_text = `Alexander Stanislavovich 'Sasha' Bublik (Александр Станиславович Бублик; born 17 June 1997) is a Kazakhstani professional tennis player. He has been ranked as high as world No. 25 in singles by the Association of Tennis Professionals (ATP), which he achieved in July 2023, and is the current Kazakhstani No. 1 player...
Alexander Stanislavovich Bublik was born on 17 June 1997 in Gatchina, Russia and began playing tennis at the age of four. He was coached by his father, Stanislav. On the junior tour, Bublik reached a career-high ranking of No. 19 and won eleven titles (six singles and five doubles) on the International Tennis Federation (ITF) junior circuit.[4][5]...`const chat = new ChatOpenAI({ temperature: 0 });const chatPrompt = ChatPromptTemplate.fromMessages([ [ "system", "You are a helpful assistant that {action} the provided text", ], ["human", "{text}"],]);// 这里将 2 个模型进行了链接const chainB = new LLMChain({ prompt: chatPrompt, llm: chat,});
const resB = await chainB.call({ action: "lists all important numbers from", text: wiki_text,});console.log({ resB });
复制代码


在上面的代码中,我在提示词中设置了一个变量,同时通过将 LLM 的 temperature 设置为 0,以要求 LLM 给出一个基于事实的回答。该例中,我要求 LLM 基于给定的简短知识库,输出我最喜欢网球运动员的关键数据。以下是 LLM 给出的回答:


{  resB: {    text: 'Important numbers from the provided text:\n' +      '\n' +      "- Alexander Stanislavovich 'Sasha' Bublik's date of birth: 17 June 1997\n" +      "- Bublik's highest singles ranking: world No. 25\n" +      "- Bublik's highest doubles ranking: world No. 47\n" +      "- Bublik's career ATP Tour singles titles: 3\n" +      "- Bublik's career ATP Tour singles runner-up finishes: 6\n" +      "- Bublik's height: 1.96 m (6 ft 5 in)\n" +      "- Bublik's number of aces served in the 2021 ATP Tour season: unknown\n" +      "- Bublik's junior tour ranking: No. 19\n" +      "- Bublik's junior tour titles: 11 (6 singles and 5 doubles)\n" +      "- Bublik's previous citizenship: Russia\n" +      "- Bublik's current citizenship: Kazakhstan\n" +      "- Bublik's role in the Levitov Chess Wizards team: reserve member"  }}
复制代码


很酷,但这还没有真正展示 Chains 的全部能力。再看一个更实际的例子:


import { z } from "zod";import { zodToJsonSchema } from "zod-to-json-schema";import { ChatOpenAI } from "langchain/chat_models/openai";import {  ChatPromptTemplate,  SystemMessagePromptTemplate,  HumanMessagePromptTemplate,} from "langchain/prompts";import { JsonOutputFunctionsParser } from "langchain/output_parsers";process.env["OPENAI_API_KEY"] = "YOUR_OPENAI_KEY"const zodSchema = z.object({  albums: z    .array(      z.object({        name: z.string().describe("The name of the album"),        artist: z.string().describe("The artist(s) that made the album"),        length: z.number().describe("The length of the album in minutes"),        genre: z.string().optional().describe("The genre of the album"),      })    )    .describe("An array of music albums mentioned in the text"),});const prompt = new ChatPromptTemplate({  promptMessages: [    SystemMessagePromptTemplate.fromTemplate(      "List all music albums mentioned in the following text."    ),    HumanMessagePromptTemplate.fromTemplate("{inputText}"),  ],  inputVariables: ["inputText"],});const llm = new ChatOpenAI({ modelName: "gpt-3.5-turbo", temperature: 0 });const functionCallingModel = llm.bind({  functions: [    {      name: "output_formatter",      description: "Should always be used to properly format output",      parameters: zodToJsonSchema(zodSchema),    },  ],  function_call: { name: "output_formatter" },});const outputParser = new JsonOutputFunctionsParser();const chain = prompt.pipe(functionCallingModel).pipe(outputParser);const response = await chain.invoke({  inputText: "My favorite albums are: 2001, To Pimp a Butterfly and Led Zeppelin IV",});console.log(JSON.stringify(response, null, 2));
复制代码


此脚本通过读取输入的文本信息,识别所有提到的音乐专辑以及将每张专辑的名称、艺术家、长度和流派,最后将所有数据转换为 JSON 格式进行输出。以下是输入“我最喜欢的专辑是:2001 年、To Pimp a Butterfly 和 Led Zeppelin IV”的输出:


{  "albums": [    {      "name": "2001",      "artist": "Dr. Dre",      "length": 68,      "genre": "Hip Hop"    },    {      "name": "To Pimp a Butterfly",      "artist": "Kendrick Lamar",      "length": 79,      "genre": "Hip Hop"    },    {      "name": "Led Zeppelin IV",      "artist": "Led Zeppelin",      "length": 42,      "genre": "Rock"    }  ]}
复制代码


虽然这只是一个有趣的例子,但通过该技术可以将非结构化的文本数据转为结构化的数据,从而使用在其他应用系统中。


不止 OpenAI


尽管在演示 LangChain 不同功能的示例中,我一直都是使用 OpenAI 模型。但其实 LangChain 并不局限于 OpenAI 模型。你可以将 LangChain 与许多其他 LLM 和 AI 服务一起使用。在 LangChain 的官方文档中可以找到 LangChain 的 JS 版本所支持集成的完整 LLM 列表。


例如,你可以将 Cohere 与 LangChain 一起使用。再使用 npm install cohere-ai 安装 Cohere 之后,你就可以像下面示例代码一样,使用 LangChain 和 Cohere 编写一个简单的问答脚本:


import { Cohere } from "langchain/llms/cohere";const model = new Cohere({  maxTokens: 50,  apiKey: "YOUR_COHERE_KEY", // In Node.js defaults to process.env.COHERE_API_KEY});const res = await model.call(  "Come up with a name for a new Nas album" // 给 Nas 的新专辑起个名字);console.log({ res });
复制代码


输出的结果如下:


{  res: ' Here are a few possible names for a new Nas album:\n' +    '\n' +    "- King's Landing\n" +    "- God's Son: The Sequel\n" +    "- Street's Disciple\n" +    '- Izzy Free\n' +    '- Nas and the Illmatic Flow\n' +    '\n' +    'Do any'}
复制代码


总结


读完本篇文章,相信你已经对 JS 版的 LangChain 各方面能力都有所了解了。现在你可以通过 LangChain 用 JS 开发各种基于 AI 的应用和体验 LLM 了。当然,也请你必参考 LangChainJS 的官方文档,以了解更多有关特定功能的详细信息。


最后,预祝你在 JavaScript 中愉快的使用 LangChain 进行编码和体验!如果你喜欢这篇文章,你可能还想阅读如何在 Python 中使用 LangChain 这篇文章:


https://www.sitepoint.com/langchain-python-complete-guide/


原文链接:


https://www.sitepoint.com/langchain-javascript-complete-guide/


相关阅读:

LangChain 的问题所在

OpenAI 用 45 分钟重塑游戏规则!干掉 MJ、LangChain,创造“不会编程的应用开发者”新职业

LangChain:2023 年最潮大语言模型 Web 开发框架

理论 + 实践详解最热的 LLM 应用框架 LangChain

公众号推荐:

跳进 AI 的奇妙世界,一起探索未来工作的新风貌!想要深入了解 AI 如何成为产业创新的新引擎?好奇哪些城市正成为 AI 人才的新磁场?《中国生成式 AI 开发者洞察 2024》由 InfoQ 研究中心精心打造,为你深度解锁生成式 AI 领域的最新开发者动态。无论你是资深研发者,还是对生成式 AI 充满好奇的新手,这份报告都是你不可错过的知识宝典。欢迎大家扫码关注「AI前线」公众号,回复「开发者洞察」领取。

2023-11-29 13:584676

评论

发布
暂无评论
发现更多内容

Vue3必会技巧-自定义Hooks

yyds2026

Vue

5年经验年薪百万,一位阿里P8分享自己的成长干货

钟奕礼

Java java面试 java编程 程序员、

理解NodeJS多进程

coder2028

node.js

Java语言标识符的命名规范(超详细讲解)

千锋IT教育

面试阿里P6,却被MySQL难倒,二战阿里,挤进天猫团队(Java岗)

钟奕礼

Java 程序员 java面试 java编程

web技术分享| 图片上传与图片裁剪结合 vue3

anyRTC开发者

Vue 前端 Web 图片上传 图片裁剪

Vue3知识点之数据侦测

yyds2026

Vue

《中国指标中台市场研究报告》线上发布会

Kyligence

数据分析 指标中台

2023年北京企业办理备案流程详解

行云管家

等保 等保备案 北京

阿里p8私藏MyBatis笔记,从入门到精通,纵享源码细节

钟奕礼

Java 程序员 java面试 java编程

理解Nodejs中的进程间通信

coder2028

node.js

我服了!腾讯专家手敲《Redis源码日志笔记》,字字如金

钟奕礼

Java 程序员 java面试 java编程

2022年11月国产数据库大事记-墨天轮

墨天轮

数据库 tdsql 国产数据库 达梦 polarDB

Jvm上如何运行其他语言?JSR223规范最详细讲解

架构师之道

Java JVM

用 nodejs 搭建脚手架

coder2028

node.js

彻底搞懂JS原型与原型链

hellocoder2029

JavaScript

阿里技术官珍藏JVM全优笔记,细节满分,吃透写精通没问题

钟奕礼

Java 程序员 java面试 java编程

Java程序员开发3年如何能拿到年薪40W?(强烈推荐涨薪必备)

钟奕礼

Java 程序员 java面试 java编程

ha集群是什么意思?一般有几个节点?

行云管家

高可用 ha ha集群

细说JavaScript闭包

hellocoder2029

JavaScript

模块一

GeekMLS

构架

龙蜥大讲堂12月预告来了!来自统信软件、移动云和浪潮信息等多位技术专家在线分享

OpenAnolis小助手

ebpf 移动云 龙蜥大讲堂 直播预告 统信软件

Webpack中的高级特性

Geek_02d948

webpack

手写vue-router核心原理

hellocoder2029

JavaScript

1业务架构作业

梁山伯

还在写代码处理映射关系? 动动手指,MatrixDB 4.4 轻松让 JSON 入表!

YMatrix 超融合数据库

kafka 产品发布 超融合数据库 YMatrix MatrixGate

Webpack完整打包流程分析

Geek_02d948

webpack

惊喜!Alibaba架构师手写《Java一无所知到精通》文档

钟奕礼

Java 程序员 java面试 java编程

Webpack插件核心原理

Geek_02d948

webpack

上帝视角一览大数据开发体系

JAVA旭阳

Java 大数据

不知如何优选达人?火山引擎VeDI零售行业解决方案一键解决!

字节跳动数据平台

大数据 数据分析 营销 12 月 PK 榜

手把手教你在JavaScript中使用LangChain,解锁AI应用能力_生成式 AI_InfoQ精选文章