做网站公司昆山wordpress虚拟卡密

张小明 2026/1/3 21:02:43
做网站公司昆山,wordpress虚拟卡密,网站建设团队分工,建站公司 长沙和西安本章对应源代码#xff1a;https://github.com/RealKai42/langchainjs-juejin/tree/main/node/rag 这一章#xff0c;我们将继续我们 RAG chat bot 的实现#xff0c;在之前的版本中并没有记忆功能#xff0c;只是获取向量库中的资料 根据返回的资料回答用户问题。 这一…本章对应源代码https://github.com/RealKai42/langchainjs-juejin/tree/main/node/rag这一章我们将继续我们 RAG chat bot 的实现在之前的版本中并没有记忆功能只是获取向量库中的资料 根据返回的资料回答用户问题。这一章讲是 RAG 模块的最终章这里我们会将 RAG 再往更好的完成度推进加入 llm 改写和 chat history成为更成熟的 llm 应用。llm 改写提问这是 Retriver 阶段更深入的优化因为 chat bot 面对的是普通用户的长对话用户会自然的通过代词去指代前面的内容例如Human: 这个故事的主角是谁 AI: 主角是小明 Human: 介绍他的故事在正常的 rag 逻辑中我们会使用 “介绍他的故事” 去检索向量数据库但这句话只有 “他” 并没有检索的关键词 “小明”就很难检索到正确的资料。所以为了提高检索的质量我们需要对用户的提问进行改写让他成为一个独立的问题包含检索的所有关键词例如上面的例子我们就可以改写成 “介绍小明的故事”这样检索时就能获得数据库中相关的文档从而获得高质量的回答。那应该用什么改写呢答案依旧是 -- LLM。所以又回到了我们前面提到的问题当做 LLM app 遇到问题时我们通常会尝试加入更多的 LLM 来解决问题。让我们来看代码应该怎么处理。我们先定义 prompt const rephraseChainPrompt ChatPromptTemplate.fromMessages([ [ system, 给定以下对话和一个后续问题请将后续问题重述为一个独立的问题。请注意重述的问题应该包含足够的信息使得没有看过对话历史的人也能理解。, ], new MessagesPlaceholder(history), [human, 将以下问题重述为一个独立的问题\n{question}], ]);这里我们通过 system prompt 去给 llm 确定任务根据聊天记录去把对话重新描述成一个独立的问题并强调重述问题的目标。然后我们据此构成一个 chainconst rephraseChain RunnableSequence.from([ rephraseChainPrompt, new ChatOpenAI({ temperature: 0.2, }), new StringOutputParser(), ]);这里我们将 model 的 temperature 定义的较低越低 llm 会越忠于事实减少自己的自由发挥。然后让我们简单测试一下效果const historyMessages [new HumanMessage(你好我叫小明), new AIMessage(你好小明)]; const question 你觉得我的名字怎么样; const standaloneQuestion await rephraseChain.invoke({ history: historyMessages, question }); console.log(standaloneQuestion); // 你认为小明这个名字怎么样可以看到我们这里使用了 “我的名字” 这个代词在 llm 的重述下将这个替换成了 “小明”。这个处理除了可以解决代词的问题也能解决一些自然语言灵活性带来的问题保证进行 retriver 时的问题是高质量的。当然这个技巧也可以根据我们业务的需要跟前面 Retriver 技术中的其他技巧结合来综合提高返回文档的质量。构建完整的 RAG chain这里我们就可以把前面章节涉及的知识点全部串联起来构造一个完整的 rag chain大家可以通过这个例子感受到 LCEL 抽象和模块化带来的优势我们非常容易的拆分和组合各种 Runnable 对象。注意这里我们使用了 Faiss 作为我们本地的数据库因为其中使用了 .node 相关的依赖所以代码需要运行在 Node 环境不能使用 Deno。我们首先准备一个独立的脚本去对给定的小说文本就是切割并保存在本地的数据库文件中这段代码的细节前面都讲解过了所以我们直接贴代码const baseDir __dirname; const loader new TextLoader(path.join(baseDir, ../../data/qiu.txt)); const docs await loader.load(); const splitter new RecursiveCharacterTextSplitter({ chunkSize: 500, chunkOverlap: 100, }); const splitDocs await splitter.splitDocuments(docs); const embeddings new OpenAIEmbeddings(); const vectorStore await FaissStore.fromDocuments(splitDocs, embeddings); await vectorStore.save(path.join(baseDir, ../../db/qiu));这部分代码执行后会将数据文件进行加载、切割、存储到向量数据库的文件中之后我们就再起一个新的脚本来写我们的 rag chain并将rephraseChain部分的粘贴进去。然后我们构建根据重写后的独立问题去读取数据库的中相关文档的 chain:async function loadVectorStore() { const directory path.join(__dirname, ../../db/qiu); const embeddings new OpenAIEmbeddings(); const vectorStore await FaissStore.load(directory, embeddings); return vectorStore; }const vectorStore await loadVectorStore(); const retriever vectorStore.asRetriever(2); const convertDocsToString (documents: Document[]): string { return documents.map((document) document.pageContent).join(\n); }; const contextRetrieverChain RunnableSequence.from([ (input) input.standalone_question, retriever, convertDocsToString, ]);这部分代码前面的章节都有解析就是简单的使用 retriever 获取相关文档然后转换成纯字符串。然后我们定义一个包含历史记录信息回答用户提问的 prompt const SYSTEM_TEMPLATE 你是一个熟读刘慈欣的《球状闪电》的终极原着党精通根据作品原文详细解释和回答问题你在回答时会引用作品原文。 并且回答时仅根据原文尽可能回答用户问题如果原文中没有相关内容你可以回答“原文中没有相关内容” 以下是原文中跟用户回答相关的内容 {context} ; const prompt ChatPromptTemplate.fromMessages([ [system, SYSTEM_TEMPLATE], new MessagesPlaceholder(history), [human, 现在你需要基于原文回答以下问题\n{standalone_question}], ]);这里我们使用MessagesPlaceholder去在 message 中给 history 去预留位置之后会这里会被 Message 数组填充。然后我定义一个 改写提问 根据改写后的提问获取文档 生成回复 的 rag chainconst model new ChatOpenAI(); const ragChain RunnableSequence.from([ RunnablePassthrough.assign({ standalone_question: rephraseChain, }), RunnablePassthrough.assign({ context: contextRetrieverChain, }), prompt, model, new StringOutputParser(), ]);这里有些 LCEL 节点的输入输出会绕一点 rag Chain 的输入会包含question和history两个输入前者是用户的原始问题后者是聊天记录由后面会定义的 chain 输入。所以第一个节点我们会在这个输入中通过RunnablePassthrough.assign去添加standalone_question这个 key。在这里前序输入的question和history会作为参数传入给rephraseChain并通过其中的运算将结果赋值给standalone_question然后传递给后续节点。所以在第一个节点运行完毕后传给下一个节点的数据就是question、history、standalone_question这三个 key分别是用户的原始提问、聊天记录和重写后的历史。同样的原理在第二个节点中这三个输入会传入给contextRetrieverChain中这个 chain 会使用standalone_question去获取到相关的文档作为结果赋值给context。 所以在这个节点运行结束后传递给下一个节点的数据就是question、history、standalone_question和context这四个 key。后面就是大家已经非常熟悉的生成 prompt、llm 返回数据、StringOutputParser提取数据中的文本内容。所以这里我们就构建了一个基础的 rag chain。 然后我们给这个 rag chain 去增加聊天记录的功能这里我们使用RunnableWithMessageHistory去管理 history。const ragChainWithHistory new RunnableWithMessageHistory({ runnable: ragChain, getMessageHistory: (sessionId) new JSONChatHistory({ sessionId, dir: chatHistoryDir }), historyMessagesKey: history, inputMessagesKey: question, });注意这里传给getMessageHistory的函数需要根据用户传入的 sessionId 去获取初始的 chat history这里我们复用了前面章节实现的JSONChatHistory来在本地存储用户的聊天记录。让我们测试一下const res await ragChainWithHistory.invoke( { question: 什么是球状闪电, }, { configurable: { sessionId: test-history }, } );返回根据原文球状闪电是一种极其罕见的现象是一个充盈着能量的弯曲的空间一个似有似无的空泡一个足球大小的 电子。它被描述为一个超现实的小东西仿佛梦之乡溢出的一粒灰尘暗示着宇宙的博大和神秘暗示着可能存在的与 我们现实完全不同的其他世界。球状闪电的确切性质和构成目前仍然是科学之谜但它不是小说中所描述的那种东西 而是一种真实存在的自然现象。因为聊天记录会被持久化在文件中并且在运行时加载所以我们直接修改问题再次运行代码即可const res await ragChain.invoke( { question: 这个现象在文中有什么故事, }, { configurable: { sessionId: test-history }, } );返回球状闪电在《球状闪电》这本小说中有着丰富的故事情节。小说中描述了一个年轻人因为观察到球状闪电而开始对它展 开研究的旅程。他发现球状闪电的特性和行为与以往所知的闪电形式有着明显不同它具有弯曲的空间、充盈的能量和 神秘的存在状态。在寻求解释和了解球状闪电的过程中他秘密调查了死去科学家的笔迹探索了前苏联的地下科技 城还遭遇了次世代的世界大战的种种阻碍。最终他发现球状闪电並非只是自然现象而是一种可以用作战争武器的 存在成为了决定祖国存亡的终极武器。 这个故事展示了球状闪电的不寻常和神秘之处以及对它进行研究和利用的影响和后果。球状闪电在小说中被描绘为一 种引人入胜的现象同时也成为了战争中的重要元素改变了整个世界的格局。可以看到经过自动改写的用户提问让 llm 检索到正确的数据从而生成了完整的回答。至此我们就完成成了一个非常完整的 rag chain有自动的提问改写、数据检索、聊天记录等基本的功能。借助 langchain 提供的丰富能力百行左右就能实现一个功能丰富的 chat bot。部署成 API就像我们前面介绍过的LCEL 提供了从 prototype 到 production 的能力我们前面写的 chain 不需要做任何修改就可以部署成 API并且提供 stream 能力。我们这里使用 express 简单写一个部署的 APIimport express from express; import { getRagChain } from .; const app express(); const port 8080; app.use(express.json()); app.post(/, async (req, res) { const ragChain await getRagChain(); const body req.body; const result await ragChain.stream( { question: body.question, }, { configurable: { sessionId: body.session_id } } ); res.set(Content-Type, text/plain); for await (const chunk of result) { res.write(chunk); } res.end(); }); app.listen(port, () { console.log(Server is running on port ${port}); });然后我们运行这个 sever然后写一个 client 的去读取 steam api 的代码const port 8080; async function fetchStream() { const response await fetch(http://localhost:${port}, { method: POST, headers: { content-type: application/json, }, body: JSON.stringify({ question: 什么是球状闪电, session_id: test-server, }), }); const reader response.body.getReader(); const decoder new TextDecoder(); while (true) { const { done, value } await reader.read(); if (done) break; console.log(decoder.decode(value)); } console.log(Stream has ended); } fetchStream();然后我们运行即可得到然后我们的 rag chain 就被部署成了 API可以给其他业务提供服务。小结这是 RAG 模块的最后一章我们经历了十几章 RAG 相关的基础知识让我们从 0 部署成功了一个 rag chain。这里我们解答一下同学们可能出现的问题。在这个模块中我们学习了非常多的 Retriver、Memory 等等策略我们在工程中到底应该使用什么这个确实取决于业务的情况大家可以看到最简单的 rag chain 就是没有聊天记录的维护只有根据用户提问回答问题使用的 llm 最少、每次消耗的 token 也少如果是给内部文档做简单的 chat bot我认为这就足够了每次提问都是独立的。如果是做复杂的 chat bot就要衡量成本和效果的权衡加入完整的 chat history 就意味着对 llm 上下文压力就很大且每次消耗的 token 就会变多。不追求质量的话基础的BufferWindowMemory就可以保留前两次的聊天记录辅以使用 llm 对用户问题的重写。如果是更复杂 chat bot这就需要根据业务、文档资料、聊天的类型去选择合适的 memory 机制可以先用 langchain 内置的 Memory 去测试效果选中合适的策略然后根据业务去参考实现一份加入自己对业务的理解。另外一个经常会问到的问题就是 prompt 用英语还是中文。在EntityMemory中大家会发现虽然人类和 llm 输出都是中文但内部的 entities 记录都是英语的因为EntityMemory提取实体时的 prompt 就是英语的所以内部记录的信息也是英语的。 因为 llm 有非常好的跨语言的理解能力基本的使用并不会有问题但对于纯中文的业务我建议还是根据其内置的 prompt 去翻译成中文并根据中文的特点进行修改以取得最好的效果。上面常见的问题我的建议都是根据业务和场景去选择。但我还想再强调一遍在 poc 期间不要纠结就全部用 langchain 内置的工具去做先看效果再根据效果和 chian 中间的步骤去一点点分析 导致效果不理想的问题出在哪里然后再去优化。 没必要在业务前期就陷入过早优化的陷阱。最后感谢大家在 RAG 模块的陪伴在一节我们将进入更加神奇的 Agent 模块我们会体会为什么多 Agent 的协同让我们看到了 AGI 的曙光
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

建站公司推广网站文章发布

U-2-Net深度解析:从架构原理到实战应用的完整指南 【免费下载链接】U-2-Net U-2-Net - 用于显著对象检测的深度学习模型,具有嵌套的U型结构。 项目地址: https://gitcode.com/gh_mirrors/u2/U-2-Net U-2-Net作为显著对象检测领域的深度学习模型&a…

张小明 2025/12/25 21:48:03 网站建设

专业做网站服务企业网站建设报价方案

当人工智能从内容生成(AIGC)迈向服务重塑(AIGS),软件行业正迎来前所未有的范式变革。对于深耕 Java 技术栈的企业而言,如何快速接入 AI 能力、完成系统智能化升级,成为破局增长的关键命题。JBol…

张小明 2025/12/25 3:20:04 网站建设

python和php做网站c2c模式

Langchain-Chatchat 集成二维码分享:打通本地知识库的移动传播链路 在企业数字化转型不断深化的今天,知识不再只是文档堆叠在服务器里,而是需要被快速触达、高效复用的核心生产力。尤其是在金融、医疗、制造等行业,大量敏感信息必…

张小明 2025/12/25 17:25:43 网站建设

网站建设设计风格描述做网站选什么主机

RuoYi-Vue3:现代化企业级后台管理系统开发框架深度解析 【免费下载链接】RuoYi-Vue3 🎉 (RuoYi)官方仓库 基于SpringBoot,Spring Security,JWT,Vue3 & Vite、Element Plus 的前后端分离权限管理系统 项目地址: h…

张小明 2025/12/25 14:51:15 网站建设

十堰高端网站建设武城网站建设电话

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容: 开发一个基于LangChain Agent的智能客服聊天机器人,能够理解用户问题并给出准确回答。机器人应支持多轮对话,能够根据上下文调整回答策略。集成常见问题库和…

张小明 2026/1/1 19:14:13 网站建设