[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"similar-liaokongVFX--LangChain-Chinese-Getting-Started-Guide":3,"tool-liaokongVFX--LangChain-Chinese-Getting-Started-Guide":62},[4,18,26,36,46,54],{"id":5,"name":6,"github_repo":7,"description_zh":8,"stars":9,"difficulty_score":10,"last_commit_at":11,"category_tags":12,"status":17},4358,"openclaw","openclaw\u002Fopenclaw","OpenClaw 是一款专为个人打造的本地化 AI 助手，旨在让你在自己的设备上拥有完全可控的智能伙伴。它打破了传统 AI 助手局限于特定网页或应用的束缚，能够直接接入你日常使用的各类通讯渠道，包括微信、WhatsApp、Telegram、Discord、iMessage 等数十种平台。无论你在哪个聊天软件中发送消息，OpenClaw 都能即时响应，甚至支持在 macOS、iOS 和 Android 设备上进行语音交互，并提供实时的画布渲染功能供你操控。\n\n这款工具主要解决了用户对数据隐私、响应速度以及“始终在线”体验的需求。通过将 AI 部署在本地，用户无需依赖云端服务即可享受快速、私密的智能辅助，真正实现了“你的数据，你做主”。其独特的技术亮点在于强大的网关架构，将控制平面与核心助手分离，确保跨平台通信的流畅性与扩展性。\n\nOpenClaw 非常适合希望构建个性化工作流的技术爱好者、开发者，以及注重隐私保护且不愿被单一生态绑定的普通用户。只要具备基础的终端操作能力（支持 macOS、Linux 及 Windows WSL2），即可通过简单的命令行引导完成部署。如果你渴望拥有一个懂你",349277,3,"2026-04-06T06:32:30",[13,14,15,16],"Agent","开发框架","图像","数据工具","ready",{"id":19,"name":20,"github_repo":21,"description_zh":22,"stars":23,"difficulty_score":10,"last_commit_at":24,"category_tags":25,"status":17},3808,"stable-diffusion-webui","AUTOMATIC1111\u002Fstable-diffusion-webui","stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面，旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点，将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。\n\n无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师，还是想要深入探索模型潜力的开发者与研究人员，都能从中获益。其核心亮点在于极高的功能丰富度：不仅支持文生图、图生图、局部重绘（Inpainting）和外绘（Outpainting）等基础模式，还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外，它内置了 GFPGAN 和 CodeFormer 等人脸修复工具，支持多种神经网络放大算法，并允许用户通过插件系统无限扩展能力。即使是显存有限的设备，stable-diffusion-webui 也提供了相应的优化选项，让高质量的 AI 艺术创作变得触手可及。",162132,"2026-04-05T11:01:52",[14,15,13],{"id":27,"name":28,"github_repo":29,"description_zh":30,"stars":31,"difficulty_score":32,"last_commit_at":33,"category_tags":34,"status":17},1381,"everything-claude-code","affaan-m\u002Feverything-claude-code","everything-claude-code 是一套专为 AI 编程助手（如 Claude Code、Codex、Cursor 等）打造的高性能优化系统。它不仅仅是一组配置文件，而是一个经过长期实战打磨的完整框架，旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。\n\n通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能，everything-claude-code 能显著提升 AI 在复杂任务中的表现，帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略，使得模型响应更快、成本更低，同时有效防御潜在的攻击向量。\n\n这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库，还是需要 AI 协助进行安全审计与自动化测试，everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目，它融合了多语言支持与丰富的实战钩子（hooks），让 AI 真正成长为懂上",160015,2,"2026-04-18T11:30:52",[14,13,35],"语言模型",{"id":37,"name":38,"github_repo":39,"description_zh":40,"stars":41,"difficulty_score":42,"last_commit_at":43,"category_tags":44,"status":17},8272,"opencode","anomalyco\u002Fopencode","OpenCode 是一款开源的 AI 编程助手（Coding Agent），旨在像一位智能搭档一样融入您的开发流程。它不仅仅是一个代码补全插件，而是一个能够理解项目上下文、自主规划任务并执行复杂编码操作的智能体。无论是生成全新功能、重构现有代码，还是排查难以定位的 Bug，OpenCode 都能通过自然语言交互高效完成，显著减少开发者在重复性劳动和上下文切换上的时间消耗。\n\n这款工具专为软件开发者、工程师及技术研究人员设计，特别适合希望利用大模型能力来提升编码效率、加速原型开发或处理遗留代码维护的专业人群。其核心亮点在于完全开源的架构，这意味着用户可以审查代码逻辑、自定义行为策略，甚至私有化部署以保障数据安全，彻底打破了传统闭源 AI 助手的“黑盒”限制。\n\n在技术体验上，OpenCode 提供了灵活的终端界面（Terminal UI）和正在测试中的桌面应用程序，支持 macOS、Windows 及 Linux 全平台。它兼容多种包管理工具，安装便捷，并能无缝集成到现有的开发环境中。无论您是追求极致控制权的资深极客，还是渴望提升产出的独立开发者，OpenCode 都提供了一个透明、可信",144296,1,"2026-04-16T14:50:03",[13,45],"插件",{"id":47,"name":48,"github_repo":49,"description_zh":50,"stars":51,"difficulty_score":32,"last_commit_at":52,"category_tags":53,"status":17},2271,"ComfyUI","Comfy-Org\u002FComfyUI","ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎，专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式，采用直观的节点式流程图界面，让用户通过连接不同的功能模块即可构建个性化的生成管线。\n\n这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景，也能自由组合模型、调整参数并实时预览效果，轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性，不仅支持 Windows、macOS 和 Linux 全平台，还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构，并率先支持 SDXL、Flux、SD3 等前沿模型。\n\n无论是希望深入探索算法潜力的研究人员和开发者，还是追求极致创作自由度的设计师与资深 AI 绘画爱好者，ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能，使其成为当前最灵活、生态最丰富的开源扩散模型工具之一，帮助用户将创意高效转化为现实。",109154,"2026-04-18T11:18:24",[14,15,13],{"id":55,"name":56,"github_repo":57,"description_zh":58,"stars":59,"difficulty_score":32,"last_commit_at":60,"category_tags":61,"status":17},6121,"gemini-cli","google-gemini\u002Fgemini-cli","gemini-cli 是一款由谷歌推出的开源 AI 命令行工具，它将强大的 Gemini 大模型能力直接集成到用户的终端环境中。对于习惯在命令行工作的开发者而言，它提供了一条从输入提示词到获取模型响应的最短路径，无需切换窗口即可享受智能辅助。\n\n这款工具主要解决了开发过程中频繁上下文切换的痛点，让用户能在熟悉的终端界面内直接完成代码理解、生成、调试以及自动化运维任务。无论是查询大型代码库、根据草图生成应用，还是执行复杂的 Git 操作，gemini-cli 都能通过自然语言指令高效处理。\n\n它特别适合广大软件工程师、DevOps 人员及技术研究人员使用。其核心亮点包括支持高达 100 万 token 的超长上下文窗口，具备出色的逻辑推理能力；内置 Google 搜索、文件操作及 Shell 命令执行等实用工具；更独特的是，它支持 MCP（模型上下文协议），允许用户灵活扩展自定义集成，连接如图像生成等外部能力。此外，个人谷歌账号即可享受免费的额度支持，且项目基于 Apache 2.0 协议完全开源，是提升终端工作效率的理想助手。",100752,"2026-04-10T01:20:03",[45,13,15,14],{"id":63,"github_repo":64,"name":65,"description_en":66,"description_zh":67,"ai_summary_zh":67,"readme_en":68,"readme_zh":69,"quickstart_zh":70,"use_case_zh":71,"hero_image_url":72,"owner_login":73,"owner_name":74,"owner_avatar_url":75,"owner_bio":76,"owner_company":76,"owner_location":77,"owner_email":76,"owner_twitter":76,"owner_website":76,"owner_url":78,"languages":76,"stars":79,"forks":80,"last_commit_at":81,"license":76,"difficulty_score":32,"env_os":82,"env_gpu":82,"env_ram":82,"env_deps":83,"category_tags":92,"github_topics":93,"view_count":32,"oss_zip_url":76,"oss_zip_packed_at":76,"status":17,"created_at":97,"updated_at":98,"faqs":99,"releases":140},8092,"liaokongVFX\u002FLangChain-Chinese-Getting-Started-Guide","LangChain-Chinese-Getting-Started-Guide","LangChain 的中文入门教程","LangChain-Chinese-Getting-Started-Guide 是一份专为中文开发者打造的 LangChain 框架入门教程。它旨在降低大语言模型（LLM）应用开发的门槛，解决开发者在使用 OpenAI 等模型时面临的本地数据隔离、无法联网搜索及难以处理长文档等痛点。通过本指南，用户可以轻松实现连接外部数据源（如 PDF、网页、YouTube 视频）、构建私有知识库问答系统以及开发具备自主规划能力的智能代理。\n\n该资源特别适合希望快速上手 LLM 应用开发的程序员、技术研究人员及 AI 爱好者。其核心亮点在于将复杂的概念转化为通俗易懂的实战案例，系统讲解了数据加载器（Loader）、文本分割（Text Splitter）、向量数据库（Vectorstores）及智能链（Chain）等关键模块。教程不仅提供了从基础调用到高级代理开发的完整代码示例，还配套了在线 GitBook 文档和可运行的 Colab 笔记，帮助学习者边学边练。鉴于 LangChain 迭代迅速，该项目也鼓励社区协作更新，确保内容紧跟技术前沿，是中文社区探索大模型应用开发的高效起点。","# LangChain 中文入门教程\n\n> 为了便于阅读，已生成gitbook：[https:\u002F\u002Fliaokong.gitbook.io\u002Fllm-kai-fa-jiao-cheng\u002F](https:\u002F\u002Fliaokong.gitbook.io\u002Fllm-kai-fa-jiao-cheng\u002F)\n>\n> github地址：[https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FLangChain-Chinese-Getting-Started-Guide](https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FLangChain-Chinese-Getting-Started-Guide)\n>\n> 另外一篇[《Model Context Protocol(MCP) 编程极速入门》](https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FMCP-Chinese-Getting-Started-Guide)\n> \n> 《LangChain技术解密：构建大模型应用的全景指南》现已出版：[https:\u002F\u002Fitem.jd.com\u002F14598210.html](https:\u002F\u002Fitem.jd.com\u002F14598210.html)\n> \n> 低价 国内外 ai 模型 api 中转：[https:\u002F\u002Fapi.91ai.me](https:\u002F\u002Fapi.91ai.me\u002F)\n\n> 因为langchain库一直在飞速更新迭代，但该文档写与4月初，并且我个人精力有限，所以colab里面的代码有可能有些已经过时。如果有运行失败的可以先搜索一下当前文档是否有更新，如文档也没更新欢迎提issue，或者修复后直接提pr，感谢~\n\n> 加了个 [CHANGELOG](CHANGELOG.md),更新了新的内容我会写在这里，方便之前看过的朋友快速查看新的更新内容\n\n> 如果想把 OPENAI API 的请求根路由修改成自己的代理地址，可以通过设置环境变量 “OPENAI\\_API\\_BASE” 来进行修改。\n>\n> 相关参考代码：[https:\u002F\u002Fgithub.com\u002Fopenai\u002Fopenai-python\u002Fblob\u002Fd6fa3bfaae69d639b0dd2e9251b375d7070bbef1\u002Fopenai\u002F\\_\\_init\\_\\_.py#L48](https:\u002F\u002Fgithub.com\u002Fopenai\u002Fopenai-python\u002Fblob\u002Fd6fa3bfaae69d639b0dd2e9251b375d7070bbef1\u002Fopenai\u002F\\_\\_init\\_\\_.py#L48)\n>\n> 或在初始化OpenAI相关模型对象时，传入“openai\\_api\\_base” 变量。\n>\n> 相关参考代码：[https:\u002F\u002Fgithub.com\u002Fhwchase17\u002Flangchain\u002Fblob\u002Fmaster\u002Flangchain\u002Fllms\u002Fopenai.py#L148](https:\u002F\u002Fgithub.com\u002Fhwchase17\u002Flangchain\u002Fblob\u002Fmaster\u002Flangchain\u002Fllms\u002Fopenai.py#L148)\n\n## 介绍\n\n众所周知 OpenAI 的 API 无法联网的，所以如果只使用自己的功能实现联网搜索并给出回答、总结 PDF 文档、基于某个 Youtube 视频进行问答等等的功能肯定是无法实现的。所以，我们来介绍一个非常强大的第三方开源库：`LangChain` 。\n\n> 文档地址：https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002F\n\n这个库目前非常活跃，每天都在迭代，已经有 22k 的 star，更新速度飞快。\n\nLangChain 是一个用于开发由语言模型驱动的应用程序的框架。他主要拥有 2 个能力：\n\n1. 可以将 LLM 模型与外部数据源进行连接\n2. 允许与 LLM 模型进行交互\n\n> LLM 模型：Large Language Model，大型语言模型\n\n##\n\n## 基础功能\n\nLLM 调用\n\n* 支持多种模型接口，比如 OpenAI、Hugging Face、AzureOpenAI ...\n* Fake LLM，用于测试\n* 缓存的支持，比如 in-mem（内存）、SQLite、Redis、SQL\n* 用量记录\n* 支持流模式（就是一个字一个字的返回，类似打字效果）\n\nPrompt管理，支持各种自定义模板\n\n拥有大量的文档加载器，比如 Email、Markdown、PDF、Youtube ...\n\n对索引的支持\n\n* 文档分割器\n* 向量化\n* 对接向量存储与搜索，比如 Chroma、Pinecone、Qdrand\n\nChains\n\n* LLMChain\n* 各种工具Chain\n* LangChainHub\n\n## 必知概念\n\n相信大家看完上面的介绍多半会一脸懵逼。不要担心，上面的概念其实在刚开始学的时候不是很重要，当我们讲完后面的例子之后，在回来看上面的内容会一下明白很多。\n\n但是，这里有几个概念是必须知道的。\n\n##\n\n### Loader 加载器\n\n顾名思义，这个就是从指定源进行加载数据的。比如：文件夹 `DirectoryLoader`、Azure 存储 `AzureBlobStorageContainerLoader`、CSV文件 `CSVLoader`、印象笔记 `EverNoteLoader`、Google网盘 `GoogleDriveLoader`、任意的网页 `UnstructuredHTMLLoader`、PDF `PyPDFLoader`、S3 `S3DirectoryLoader`\u002F`S3FileLoader`、\n\nYoutube `YoutubeLoader` 等等，上面只是简单的进行列举了几个，官方提供了超级的多的加载器供你使用。\n\n> https:\u002F\u002Fpython.langchain.com\u002Fdocs\u002Fhow_to\u002F#document-loaders\n\n###\n\n### Document 文档\n\n当使用loader加载器读取到数据源后，数据源需要转换成 Document 对象后，后续才能进行使用。\n\n###\n\n### Text Spltters 文本分割\n\n顾名思义，文本分割就是用来分割文本的。为什么需要分割文本？因为我们每次不管是做把文本当作 prompt 发给 openai api ，还是还是使用 openai api embedding 功能都是有字符限制的。\n\n比如我们将一份300页的 pdf 发给 openai api，让他进行总结，他肯定会报超过最大 Token 错。所以这里就需要使用文本分割器去分割我们 loader 进来的 Document。\n\n###\n\n### Vectorstores 向量数据库\n\n因为数据相关性搜索其实是向量运算。所以，不管我们是使用 openai api embedding 功能还是直接通过向量数据库直接查询，都需要将我们的加载进来的数据 `Document` 进行向量化，才能进行向量运算搜索。转换成向量也很简单，只需要我们把数据存储到对应的向量数据库中即可完成向量的转换。\n\n官方也提供了很多的向量数据库供我们使用。\n\n> https:\u002F\u002Fpython.langchain.com\u002Fdocs\u002Fintegrations\u002Fvectorstores\u002F\n\n###\n\n### Chain 链\n\n我们可以把 Chain 理解为任务。一个 Chain 就是一个任务，当然也可以像链条一样，一个一个的执行多个链。\n\n###\n\n### Agent 代理\n\n我们可以简单的理解为他可以动态的帮我们选择和调用chain或者已有的工具。\n\n执行过程可以参考下面这张图:\n\n![image-20230406213322739](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_3917f56dd040.png)\n\n### Embedding\n\n用于衡量文本的相关性。这个也是 OpenAI API 能实现构建自己知识库的关键所在。\n\n他相比 fine-tuning 最大的优势就是，不用进行训练，并且可以实时添加新的内容，而不用加一次新的内容就训练一次，并且各方面成本要比 fine-tuning 低很多。\n\n> 具体比较和选择可以参考这个视频：https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=9qq6HTr7Ocw\n\n##\n\n## 实战\n\n通过上面的必备概念大家应该已经可以对 LangChain 有了一定的了解，但是可能还有有些懵。\n\n这都是小问题，我相信看完后面的实战，你们就会彻底的理解上面的内容，并且能感受到这个库的真正强大之处。\n\n因为我们 OpenAI API 进阶，所以我们后面的范例使用的 LLM 都是以Open AI 为例，后面大家可以根据自己任务的需要换成自己需要的 LLM 模型即可。\n\n当然，在这篇文章的末尾，全部的全部代码都会被保存为一个 colab 的 ipynb 文件提供给大家来学习。\n\n> 建议大家按顺序去看每个例子，因为下一个例子会用到上一个例子里面的知识点。\n>\n> 当然，如果有看不懂的也不用担心，可以继续往后看，第一次学习讲究的是不求甚解。\n\n###\n\n### 完成一次问答\n\n第一个案例，我们就来个最简单的，用 LangChain 加载 OpenAI 的模型，并且完成一次问答。\n\n在开始之前，我们需要先设置我们的 openai 的 key，这个 key 可以在用户管理里面创建，这里就不细说了。\n\n```python\nimport os\nos.environ[\"OPENAI_API_KEY\"] = '你的api key'\n```\n\n然后，我们进行导入和执行\n\n```py\nfrom langchain.llms import OpenAI\n\nllm = OpenAI(model_name=\"text-davinci-003\",max_tokens=1024)\nllm(\"怎么评价人工智能\")\n```\n\n![image-20230404232621517](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_6a41141b0b10.png)\n\n这时，我们就可以看到他给我们的返回结果了，怎么样，是不是很简单。\n\n### 通过 Google 搜索并返回答案\n\n接下来，我们就来搞点有意思的。我们来让我们的 OpenAI api 联网搜索，并返回答案给我们。\n\n这里我们需要借助 Serpapi 来进行实现，Serpapi 提供了 google 搜索的 api 接口。\n\n首先需要我们到 Serpapi 官网上注册一个用户，https:\u002F\u002Fserpapi.com\u002F 并复制他给我们生成 api key。\n\n然后我们需要像上面的 openai api key 一样设置到环境变量里面去。\n\n```python\nimport os\nos.environ[\"OPENAI_API_KEY\"] = '你的api key'\nos.environ[\"SERPAPI_API_KEY\"] = '你的api key'\n```\n\n然后，开始编写我的代码\n\n```python\nfrom langchain.agents import load_tools\nfrom langchain.agents import initialize_agent\nfrom langchain.llms import OpenAI\nfrom langchain.agents import AgentType\n\n# 加载 OpenAI 模型\nllm = OpenAI(temperature=0,max_tokens=2048) \n\n # 加载 serpapi 工具\ntools = load_tools([\"serpapi\"])\n\n# 如果搜索完想再计算一下可以这么写\n# tools = load_tools(['serpapi', 'llm-math'], llm=llm)\n\n# 如果搜索完想再让他再用python的print做点简单的计算，可以这样写\n# tools=load_tools([\"serpapi\",\"python_repl\"])\n\n# 工具加载后都需要初始化，verbose 参数为 True，会打印全部的执行详情\nagent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)\n\n# 运行 agent\nagent.run(\"What's the date today? What great events have taken place today in history?\")\n```\n\n![image-20230404234236982](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_3822665834a0.png)\n\n我们可以看到，他正确的返回了日期（有时差），并且返回了历史上的今天。\n\n在 chain 和 agent 对象上都会有 `verbose` 这个参数，这个是个非常有用的参数，开启他后我们可以看到完整的 chain 执行过程。\n\n可以在上面返回的结果看到，他将我们的问题拆分成了几个步骤，然后一步一步得到最终的答案。\n\n关于agent type 几个选项的含义（理解不了也不会影响下面的学习，用多了自然理解了）：\n\n* zero-shot-react-description: 根据工具的描述和请求内容的来决定使用哪个工具（最常用）\n* react-docstore: 使用 ReAct 框架和 docstore 交互, 使用`Search` 和`Lookup` 工具, 前者用来搜, 后者寻找term, 举例: `Wipipedia` 工具\n* self-ask-with-search 此代理只使用一个工具: Intermediate Answer, 它会为问题寻找事实答案(指的非 gpt 生成的答案, 而是在网络中,文本中已存在的), 如 `Google search API` 工具\n* conversational-react-description: 为会话设置而设计的代理, 它的prompt会被设计的具有会话性, 且还是会使用 ReAct 框架来决定使用来个工具, 并且将过往的会话交互存入内存\n\n> reAct 介绍可以看这个：https:\u002F\u002Farxiv.org\u002Fpdf\u002F2210.03629.pdf\n>\n> LLM 的 ReAct 模式的 Python 实现: https:\u002F\u002Ftil.simonwillison.net\u002Fllms\u002Fpython-react-pattern\n>\n> agent type 官方解释：\n>\n> https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Fagents\u002Fagents\u002Fagent_types.html?highlight=zero-shot-react-description\n\n> 有一点要说明的是，这个 `serpapi` 貌似对中文不是很友好，所以提问的 prompt 建议使用英文。\n\n当然，官方已经写好了 `ChatGPT Plugins` 的 agent，未来 chatgpt 能用啥插件，我们在 api 里面也能用插件，想想都美滋滋。\n\n不过目前只能使用不用授权的插件，期待未来官方解决这个。\n\n感兴趣的可以看这个文档：https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Fagents\u002Ftools\u002Fexamples\u002Fchatgpt_plugins.html\n\n> Chatgpt 只能给官方赚钱，而 Openai API 能给我赚钱\n\n### 对超长文本进行总结\n\n假如我们想要用 openai api 对一个段文本进行总结，我们通常的做法就是直接发给 api 让他总结。但是如果文本超过了 api 最大的 token 限制就会报错。\n\n这时，我们一般会进行对文章进行分段，比如通过 tiktoken 计算并分割，然后将各段发送给 api 进行总结，最后将各段的总结再进行一个全部的总结。\n\n如果，你用是 LangChain，他很好的帮我们处理了这个过程，使得我们编写代码变的非常简单。\n\n废话不多说，直接上代码。\n\n```python\nfrom langchain.document_loaders import UnstructuredFileLoader\nfrom langchain.chains.summarize import load_summarize_chain\nfrom langchain.text_splitter import RecursiveCharacterTextSplitter\nfrom langchain import OpenAI\n\n# 导入文本\nloader = UnstructuredFileLoader(\"\u002Fcontent\u002Fsample_data\u002Fdata\u002Flg_test.txt\")\n# 将文本转成 Document 对象\ndocument = loader.load()\nprint(f'documents:{len(document)}')\n\n# 初始化文本分割器\ntext_splitter = RecursiveCharacterTextSplitter(\n    chunk_size = 500,\n    chunk_overlap = 0\n)\n\n# 切分文本\nsplit_documents = text_splitter.split_documents(document)\nprint(f'documents:{len(split_documents)}')\n\n# 加载 llm 模型\nllm = OpenAI(model_name=\"text-davinci-003\", max_tokens=1500)\n\n# 创建总结链\nchain = load_summarize_chain(llm, chain_type=\"refine\", verbose=True)\n\n# 执行总结链，（为了快速演示，只总结前5段）\nchain.run(split_documents[:5])\n```\n\n首先我们对切割前和切割后的 document 个数进行了打印，我们可以看到，切割前就是只有整篇的一个 document，切割完成后，会把上面一个 document 切成 317 个 document。\n\n![image-20230405162631460](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_fa9aca708b11.png)\n\n最终输出了对前 5 个 document 的总结。\n\n![image-20230405162937249](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_b6db54d605aa.png)\n\n这里有几个参数需要注意：\n\n**文本分割器的 `chunk_overlap` 参数**\n\n这个是指切割后的每个 document 里包含几个上一个 document 结尾的内容，主要作用是为了增加每个 document 的上下文关联。比如，`chunk_overlap=0`时， 第一个 document 为 aaaaaa，第二个为 bbbbbb；当 `chunk_overlap=2` 时，第一个 document 为 aaaaaa，第二个为 aabbbbbb。\n\n不过，这个也不是绝对的，要看所使用的那个文本分割模型内部的具体算法。\n\n> 文本分割器可以参考这个文档：https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Findexes\u002Ftext_splitters.html\n\n**chain 的 `chain_type` 参数**\n\n这个参数主要控制了将 document 传递给 llm 模型的方式，一共有 4 种方式：\n\n`stuff`: 这种最简单粗暴，会把所有的 document 一次全部传给 llm 模型进行总结。如果document很多的话，势必会报超出最大 token 限制的错，所以总结文本的时候一般不会选中这个。\n\n`map_reduce`: 这个方式会先将每个 document 进行总结，最后将所有 document 总结出的结果再进行一次总结。\n\n![image-20230405165752743](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_7be22246db61.png)\n\n`refine`: 这种方式会先总结第一个 document，然后在将第一个 document 总结出的内容和第二个 document 一起发给 llm 模型在进行总结，以此类推。这种方式的好处就是在总结后一个 document 的时候，会带着前一个的 document 进行总结，给需要总结的 document 添加了上下文，增加了总结内容的连贯性。\n\n![image-20230405170617383](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_08d533987a67.png)\n\n`map_rerank`: 这种一般不会用在总结的 chain 上，而是会用在问答的 chain 上，他其实是一种搜索答案的匹配方式。首先你要给出一个问题，他会根据问题给每个 document 计算一个这个 document 能回答这个问题的概率分数，然后找到分数最高的那个 document ，在通过把这个 document 转化为问题的 prompt 的一部分（问题+document）发送给 llm 模型，最后 llm 模型返回具体答案。\n\n### 构建本地知识库问答机器人\n\n在这个例子中，我们会介绍如何从我们本地读取多个文档构建知识库，并且使用 Openai API 在知识库中进行搜索并给出答案。\n\n这个是个很有用的教程，比如可以很方便的做一个可以介绍公司业务的机器人，或是介绍一个产品的机器人。\n\n```python\nfrom langchain.embeddings.openai import OpenAIEmbeddings\nfrom langchain.vectorstores import Chroma\nfrom langchain.text_splitter import CharacterTextSplitter\nfrom langchain import OpenAI\nfrom langchain.document_loaders import DirectoryLoader\nfrom langchain.chains import RetrievalQA\n\n# 加载文件夹中的所有txt类型的文件\nloader = DirectoryLoader('\u002Fcontent\u002Fsample_data\u002Fdata\u002F', glob='**\u002F*.txt')\n# 将数据转成 document 对象，每个文件会作为一个 document\ndocuments = loader.load()\n\n# 初始化加载器\ntext_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)\n# 切割加载的 document\nsplit_docs = text_splitter.split_documents(documents)\n\n# 初始化 openai 的 embeddings 对象\nembeddings = OpenAIEmbeddings()\n# 将 document 通过 openai 的 embeddings 对象计算 embedding 向量信息并临时存入 Chroma 向量数据库，用于后续匹配查询\ndocsearch = Chroma.from_documents(split_docs, embeddings)\n\n# 创建问答对象\nqa = RetrievalQA.from_chain_type(llm=OpenAI(), chain_type=\"stuff\", retriever=docsearch.as_retriever(), return_source_documents=True)\n# 进行问答\nresult = qa({\"query\": \"科大讯飞今年第一季度收入是多少？\"})\nprint(result)\n```\n\n![image-20230405173730382](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_eadcc5828c6a.png)\n\n我们可以通过结果看到，他成功的从我们的给到的数据中获取了正确的答案。\n\n> 关于 Openai embeddings 详细资料可以参看这个连接: https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fguides\u002Fembeddings\n\n### 构建向量索引数据库\n\n我们上个案例里面有一步是将 document 信息转换成向量信息和embeddings的信息并临时存入 Chroma 数据库。\n\n因为是临时存入，所以当我们上面的代码执行完成后，上面的向量化后的数据将会丢失。如果想下次使用，那么就还需要再计算一次embeddings，这肯定不是我们想要的。\n\n那么，这个案例我们就来通过 Chroma 和 Pinecone 这两个数据库来讲一下如何做向量数据持久化。\n\n> 因为 LangChain 支持的数据库有很多，所以这里就介绍两个用的比较多的，更多的可以参看文档:https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Findexes\u002Fvectorstores\u002Fgetting\\_started.html\n\n**Chroma**\n\nchroma 是个本地的向量数据库，他提供的一个 `persist_directory` 来设置持久化目录进行持久化。读取时，只需要调取 `from_document` 方法加载即可。\n\n```python\nfrom langchain.vectorstores import Chroma\n\n# 持久化数据\ndocsearch = Chroma.from_documents(documents, embeddings, persist_directory=\"D:\u002Fvector_store\")\ndocsearch.persist()\n\n# 加载数据\ndocsearch = Chroma(persist_directory=\"D:\u002Fvector_store\", embedding_function=embeddings)\n\n```\n\n**Pinecone**\n\nPinecone 是一个在线的向量数据库。所以，我可以第一步依旧是注册，然后拿到对应的 api key。https:\u002F\u002Fapp.pinecone.io\u002F\n\n> 免费版如果索引14天不使用会被自动清除。\n\n然后创建我们的数据库：\n\nIndex Name：这个随意\n\nDimensions：OpenAI 的 text-embedding-ada-002 模型为 OUTPUT DIMENSIONS 为 1536，所以我们这里填 1536\n\nMetric：可以默认为 cosine\n\n选择starter plan\n\n![image-20230405184646314](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_8f979aa7233f.png)\n\n持久化数据和加载数据代码如下\n\n```python\n# 持久化数据\ndocsearch = Pinecone.from_texts([t.page_content for t in split_docs], embeddings, index_name=index_name)\n\n# 加载数据\ndocsearch = Pinecone.from_existing_index(index_name, embeddings)\n```\n\n一个简单从数据库获取 embeddings，并回答的代码如下\n\n```python\nfrom langchain.text_splitter import CharacterTextSplitter\nfrom langchain.document_loaders import DirectoryLoader\nfrom langchain.vectorstores import Chroma, Pinecone\nfrom langchain.embeddings.openai import OpenAIEmbeddings\nfrom langchain.llms import OpenAI\nfrom langchain.chains.question_answering import load_qa_chain\n\nimport pinecone\n\n# 初始化 pinecone\npinecone.init(\n  api_key=\"你的api key\",\n  environment=\"你的Environment\"\n)\n\nloader = DirectoryLoader('\u002Fcontent\u002Fsample_data\u002Fdata\u002F', glob='**\u002F*.txt')\n# 将数据转成 document 对象，每个文件会作为一个 document\ndocuments = loader.load()\n\n# 初始化加载器\ntext_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=0)\n# 切割加载的 document\nsplit_docs = text_splitter.split_documents(documents)\n\nindex_name=\"liaokong-test\"\n\n# 持久化数据\n# docsearch = Pinecone.from_texts([t.page_content for t in split_docs], embeddings, index_name=index_name)\n\n# 加载数据\ndocsearch = Pinecone.from_existing_index(index_name,embeddings)\n\nquery = \"科大讯飞今年第一季度收入是多少？\"\ndocs = docsearch.similarity_search(query, include_metadata=True)\n\nllm = OpenAI(temperature=0)\nchain = load_qa_chain(llm, chain_type=\"stuff\", verbose=True)\nchain.run(input_documents=docs, question=query)\n```\n\n![image-20230407001803057](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_5f4a41c475b5.png)\n\n### 使用GPT3.5模型构建油管频道问答机器人\n\n在 chatgpt api（也就是 GPT-3.5-Turbo）模型出来后，因钱少活好深受大家喜爱，所以 LangChain 也加入了专属的链和模型，我们来跟着这个例子看下如何使用他。\n\n```python\nimport os\n\nfrom langchain.document_loaders import YoutubeLoader\nfrom langchain.embeddings.openai import OpenAIEmbeddings\nfrom langchain.vectorstores import Chroma\nfrom langchain.text_splitter import RecursiveCharacterTextSplitter\nfrom langchain.chains import ChatVectorDBChain, ConversationalRetrievalChain\n\nfrom langchain.chat_models import ChatOpenAI\nfrom langchain.prompts.chat import (\n  ChatPromptTemplate,\n  SystemMessagePromptTemplate,\n  HumanMessagePromptTemplate\n)\n\n# 加载 youtube 频道\nloader = YoutubeLoader.from_youtube_url('https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=Dj60HHy-Kqk')\n# 将数据转成 document\ndocuments = loader.load()\n\n# 初始化文本分割器\ntext_splitter = RecursiveCharacterTextSplitter(\n  chunk_size=1000,\n  chunk_overlap=20\n)\n\n# 分割 youtube documents\ndocuments = text_splitter.split_documents(documents)\n\n# 初始化 openai embeddings\nembeddings = OpenAIEmbeddings()\n\n# 将数据存入向量存储\nvector_store = Chroma.from_documents(documents, embeddings)\n# 通过向量存储初始化检索器\nretriever = vector_store.as_retriever()\n\nsystem_template = \"\"\"\nUse the following context to answer the user's question.\nIf you don't know the answer, say you don't, don't try to make it up. And answer in Chinese.\n-----------\n{question}\n-----------\n{chat_history}\n\"\"\"\n\n# 构建初始 messages 列表，这里可以理解为是 openai 传入的 messages 参数\nmessages = [\n  SystemMessagePromptTemplate.from_template(system_template),\n  HumanMessagePromptTemplate.from_template('{question}')\n]\n\n# 初始化 prompt 对象\nprompt = ChatPromptTemplate.from_messages(messages)\n\n\n# 初始化问答链\nqa = ConversationalRetrievalChain.from_llm(ChatOpenAI(temperature=0.1,max_tokens=2048),retriever,condense_question_prompt=prompt)\n\n\nchat_history = []\nwhile True:\n  question = input('问题：')\n  # 开始发送问题 chat_history 为必须参数,用于存储对话历史\n  result = qa({'question': question, 'chat_history': chat_history})\n  chat_history.append((question, result['answer']))\n  print(result['answer'])\n```\n\n我们可以看到他能很准确的围绕这个油管视频进行问答\n\n![image-20230406211923672](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_7347cadc13a4.png)\n\n使用流式回答也很方便\n\n```python\nfrom langchain.callbacks.base import CallbackManager\nfrom langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler\n\nchat = ChatOpenAI(streaming=True, callback_manager=CallbackManager([StreamingStdOutCallbackHandler()]), verbose=True, temperature=0)\nresp = chat(chat_prompt_with_values.to_messages())\n```\n\n### 用 OpenAI 连接万种工具\n\n我们主要是结合使用 `zapier` 来实现将万种工具连接起来。\n\n所以我们第一步依旧是需要申请账号和他的自然语言 api key。https:\u002F\u002Fzapier.com\u002Fl\u002Fnatural-language-actions\n\n他的 api key 虽然需要填写信息申请。但是基本填入信息后，基本可以秒在邮箱里看到审核通过的邮件。\n\n然后，我们通过右键里面的连接打开我们的api 配置页面。我们点击右侧的 `Manage Actions` 来配置我们要使用哪些应用。\n\n我在这里配置了 Gmail 读取和发邮件的 action，并且所有字段都选的是通过 AI 猜。\n\n![image-20230406233319250](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_fc21b487d183.png)\n\n![image-20230406234827815](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_338740425695.png)\n\n配置好后，我们开始写代码\n\n```python\nimport os\nos.environ[\"ZAPIER_NLA_API_KEY\"] = ''\n```\n\n```python\nfrom langchain.llms import OpenAI\nfrom langchain.agents import initialize_agent\nfrom langchain.agents.agent_toolkits import ZapierToolkit\nfrom langchain.utilities.zapier import ZapierNLAWrapper\n\n\nllm = OpenAI(temperature=.3)\nzapier = ZapierNLAWrapper()\ntoolkit = ZapierToolkit.from_zapier_nla_wrapper(zapier)\nagent = initialize_agent(toolkit.get_tools(), llm, agent=\"zero-shot-react-description\", verbose=True)\n\n# 我们可以通过打印的方式看到我们都在 Zapier 里面配置了哪些可以用的工具\nfor tool in toolkit.get_tools():\n  print (tool.name)\n  print (tool.description)\n  print (\"\\n\\n\")\n\nagent.run('请用中文总结最后一封\"******@qq.com\"发给我的邮件。并将总结发送给\"******@qq.com\"')\n```\n\n![image-20230406234712909](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_309697c1c2b4.png)\n\n我们可以看到他成功读取了`******@qq.com`给他发送的最后一封邮件，并将总结的内容又发送给了`******@qq.com`\n\n这是我发送给 Gmail 的邮件。\n\n![image-20230406234017369](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_97e7781f43f6.png)\n\n这是他发送给 QQ 邮箱的邮件。\n\n![image-20230406234800632](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_51ab24d2b34a.png)\n\n这只是个小例子，因为 `zapier` 有数以千计的应用，所以我们可以轻松结合 openai api 搭建自己的工作流。\n\n## 小例子们\n\n一些比较大的知识点都已经讲完了，后面的内容都是一些比较有趣的小例子，当作拓展延伸。\n\n### **执行多个chain**\n\n因为他是链式的，所以他也可以按顺序依次去执行多个 chain\n\n```python\nfrom langchain.llms import OpenAI\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.chains import SimpleSequentialChain\n\n# location 链\nllm = OpenAI(temperature=1)\ntemplate = \"\"\"Your job is to come up with a classic dish from the area that the users suggests.\n% USER LOCATION\n{user_location}\n\nYOUR RESPONSE:\n\"\"\"\nprompt_template = PromptTemplate(input_variables=[\"user_location\"], template=template)\nlocation_chain = LLMChain(llm=llm, prompt=prompt_template)\n\n# meal 链\ntemplate = \"\"\"Given a meal, give a short and simple recipe on how to make that dish at home.\n% MEAL\n{user_meal}\n\nYOUR RESPONSE:\n\"\"\"\nprompt_template = PromptTemplate(input_variables=[\"user_meal\"], template=template)\nmeal_chain = LLMChain(llm=llm, prompt=prompt_template)\n\n# 通过 SimpleSequentialChain 串联起来，第一个答案会被替换第二个中的user_meal，然后再进行询问\noverall_chain = SimpleSequentialChain(chains=[location_chain, meal_chain], verbose=True)\nreview = overall_chain.run(\"Rome\")\n```\n\n![image-20230406000133339](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_544a871712bf.png)\n\n### **结构化输出**\n\n有时候我们希望输出的内容不是文本，而是像 json 那样结构化的数据。\n\n```python\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\nfrom langchain.prompts import PromptTemplate\nfrom langchain.llms import OpenAI\n\nllm = OpenAI(model_name=\"text-davinci-003\")\n\n# 告诉他我们生成的内容需要哪些字段，每个字段类型式啥\nresponse_schemas = [\n    ResponseSchema(name=\"bad_string\", description=\"This a poorly formatted user input string\"),\n    ResponseSchema(name=\"good_string\", description=\"This is your response, a reformatted response\")\n]\n\n# 初始化解析器\noutput_parser = StructuredOutputParser.from_response_schemas(response_schemas)\n\n# 生成的格式提示符\n# {\n#\t\"bad_string\": string  \u002F\u002F This a poorly formatted user input string\n#\t\"good_string\": string  \u002F\u002F This is your response, a reformatted response\n#}\nformat_instructions = output_parser.get_format_instructions()\n\ntemplate = \"\"\"\nYou will be given a poorly formatted string from a user.\nReformat it and make sure all the words are spelled correctly\n\n{format_instructions}\n\n% USER INPUT:\n{user_input}\n\nYOUR RESPONSE:\n\"\"\"\n\n# 将我们的格式描述嵌入到 prompt 中去，告诉 llm 我们需要他输出什么样格式的内容\nprompt = PromptTemplate(\n    input_variables=[\"user_input\"],\n    partial_variables={\"format_instructions\": format_instructions},\n    template=template\n)\n\npromptValue = prompt.format(user_input=\"welcom to califonya!\")\nllm_output = llm(promptValue)\n\n# 使用解析器进行解析生成的内容\noutput_parser.parse(llm_output)\n```\n\n![image-20230406000017276](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_a1abe80772c6.png)\n\n### **爬取网页并输出JSON数据**\n\n有些时候我们需要爬取一些\u003Cmark style=\"color:red;\">**结构性比较强**\u003C\u002Fmark>的网页，并且需要将网页中的信息以JSON的方式返回回来。\n\n我们就可以使用 `LLMRequestsChain` 类去实现，具体可以参考下面代码\n\n> 为了方便理解，我在例子中直接使用了Prompt的方法去格式化输出结果，而没用使用上个案例中用到的 `StructuredOutputParser`去格式化，也算是提供了另外一种格式化的思路\n\n```python\nfrom langchain.prompts import PromptTemplate\nfrom langchain.llms import OpenAI\nfrom langchain.chains import LLMRequestsChain, LLMChain\n\nllm = OpenAI(model_name=\"gpt-3.5-turbo\", temperature=0)\n\ntemplate = \"\"\"在 >>> 和 \u003C\u003C\u003C 之间是网页的返回的HTML内容。\n网页是新浪财经A股上市公司的公司简介。\n请抽取参数请求的信息。\n\n>>> {requests_result} \u003C\u003C\u003C\n请使用如下的JSON格式返回数据\n{{\n  \"company_name\":\"a\",\n  \"company_english_name\":\"b\",\n  \"issue_price\":\"c\",\n  \"date_of_establishment\":\"d\",\n  \"registered_capital\":\"e\",\n  \"office_address\":\"f\",\n  \"Company_profile\":\"g\"\n\n}}\nExtracted:\"\"\"\n\nprompt = PromptTemplate(\n    input_variables=[\"requests_result\"],\n    template=template\n)\n\nchain = LLMRequestsChain(llm_chain=LLMChain(llm=llm, prompt=prompt))\ninputs = {\n  \"url\": \"https:\u002F\u002Fvip.stock.finance.sina.com.cn\u002Fcorp\u002Fgo.php\u002FvCI_CorpInfo\u002Fstockid\u002F600519.phtml\"\n}\n\nresponse = chain(inputs)\nprint(response['output'])\n```\n\n我们可以看到，他很好的将格式化后的结果输出了出来\n\n\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_e2f45d954865.png\" alt=\"\">\u003Cfigcaption>\u003C\u002Ffigcaption>\u003C\u002Ffigure>\n\n### **自定义agent中所使用的工具**\n\n```python\nfrom langchain.agents import initialize_agent, Tool\nfrom langchain.agents import AgentType\nfrom langchain.tools import BaseTool\nfrom langchain.llms import OpenAI\nfrom langchain import LLMMathChain, SerpAPIWrapper\n\nllm = OpenAI(temperature=0)\n\n# 初始化搜索链和计算链\nsearch = SerpAPIWrapper()\nllm_math_chain = LLMMathChain(llm=llm, verbose=True)\n\n# 创建一个功能列表，指明这个 agent 里面都有哪些可用工具，agent 执行过程可以看必知概念里的 Agent 那张图\ntools = [\n    Tool(\n        name = \"Search\",\n        func=search.run,\n        description=\"useful for when you need to answer questions about current events\"\n    ),\n    Tool(\n        name=\"Calculator\",\n        func=llm_math_chain.run,\n        description=\"useful for when you need to answer questions about math\"\n    )\n]\n\n# 初始化 agent\nagent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)\n\n# 执行 agent\nagent.run(\"Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?\")\n\n```\n\n![image-20230406002117283](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_cca181f14782.png)\n\n自定义工具里面有个比较有意思的地方，使用哪个工具的权重是靠 `工具中描述内容` 来实现的，和我们之前编程靠数值来控制权重完全不同。\n\n比如 Calculator 在描述里面写到，如果你问关于数学的问题就用他这个工具。我们就可以在上面的执行过程中看到，他在我们请求的 prompt 中数学的部分，就选用了Calculator 这个工具进行计算。\n\n### **使用Memory实现一个带记忆的对话机器人**\n\n上一个例子我们使用的是通过自定义一个列表来存储对话的方式来保存历史的。\n\n当然，你也可以使用自带的 memory 对象来实现这一点。\n\n```python\nfrom langchain.memory import ChatMessageHistory\nfrom langchain.chat_models import ChatOpenAI\n\nchat = ChatOpenAI(temperature=0)\n\n# 初始化 MessageHistory 对象\nhistory = ChatMessageHistory()\n\n# 给 MessageHistory 对象添加对话内容\nhistory.add_ai_message(\"你好！\")\nhistory.add_user_message(\"中国的首都是哪里？\")\n\n# 执行对话\nai_response = chat(history.messages)\nprint(ai_response)\n```\n\n### **使用 Hugging Face 模型**\n\n使用 Hugging Face 模型之前，需要先设置环境变量\n\n```python\nimport os\nos.environ['HUGGINGFACEHUB_API_TOKEN'] = ''\n```\n\n使用在线的 Hugging Face 模型\n\n```python\nfrom langchain import PromptTemplate, HuggingFaceHub, LLMChain\n\ntemplate = \"\"\"Question: {question}\nAnswer: Let's think step by step.\"\"\"\n\nprompt = PromptTemplate(template=template, input_variables=[\"question\"])\nllm = HuggingFaceHub(repo_id=\"google\u002Fflan-t5-xl\", model_kwargs={\"temperature\":0, \"max_length\":64})\nllm_chain = LLMChain(prompt=prompt, llm=llm)\n\nquestion = \"What NFL team won the Super Bowl in the year Justin Beiber was born?\"\nprint(llm_chain.run(question))\n```\n\n将 Hugging Face 模型直接拉到本地使用\n\n```python\nfrom langchain import PromptTemplate, LLMChain\nfrom langchain.llms import HuggingFacePipeline\nfrom transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, AutoModelForSeq2SeqLM\n\nmodel_id = 'google\u002Fflan-t5-large'\ntokenizer = AutoTokenizer.from_pretrained(model_id)\nmodel = AutoModelForSeq2SeqLM.from_pretrained(model_id)\n\npipe = pipeline(\n    \"text2text-generation\",\n    model=model,\n    tokenizer=tokenizer,\n    max_length=100\n)\n\nlocal_llm = HuggingFacePipeline(pipeline=pipe)\nprint(local_llm('What is the capital of France? '))\n\n\ntemplate = \"\"\"Question: {question} Answer: Let's think step by step.\"\"\"\nprompt = PromptTemplate(template=template, input_variables=[\"question\"])\n\nllm_chain = LLMChain(prompt=prompt, llm=local_llm)\nquestion = \"What is the capital of England?\"\nprint(llm_chain.run(question))\n```\n\n将模型拉到本地使用的好处：\n\n* 训练模型\n* 可以使用本地的 GPU\n* 有些模型无法在 Hugging Face 运行\n\n### **通过自然语言执行SQL命令**\n\n我们通过 `SQLDatabaseToolkit` 或者 `SQLDatabaseChain` 都可以实现执行SQL命令的操作\n\n```python\nfrom langchain.agents import create_sql_agent\nfrom langchain.agents.agent_toolkits import SQLDatabaseToolkit\nfrom langchain.sql_database import SQLDatabase\nfrom langchain.llms.openai import OpenAI\n\ndb = SQLDatabase.from_uri(\"sqlite:\u002F\u002F\u002F..\u002Fnotebooks\u002FChinook.db\")\ntoolkit = SQLDatabaseToolkit(db=db)\n\nagent_executor = create_sql_agent(\n    llm=OpenAI(temperature=0),\n    toolkit=toolkit,\n    verbose=True\n)\n\nagent_executor.run(\"Describe the playlisttrack table\")\n```\n\n```python\nfrom langchain import OpenAI, SQLDatabase, SQLDatabaseChain\n\ndb = SQLDatabase.from_uri(\"mysql+pymysql:\u002F\u002Froot:root@127.0.0.1\u002Fchinook\")\nllm = OpenAI(temperature=0)\n\ndb_chain = SQLDatabaseChain(llm=llm, database=db, verbose=True)\ndb_chain.run(\"How many employees are there?\")\n```\n\n这里可以参考这两篇文档：\n\n[https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Fagents\u002Ftoolkits\u002Fexamples\u002Fsql\\_database.html](https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Fagents\u002Ftoolkits\u002Fexamples\u002Fsql\\_database.html)\n\n[https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Fchains\u002Fexamples\u002Fsqlite.html](https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Fchains\u002Fexamples\u002Fsqlite.html)\n\n## 总结\n\n所有的案例都基本已经结束了，希望大家能通过这篇文章的学习有所收获。这篇文章只是对 LangChain 一个初级的讲解，高级的功能希望大家继续探索。\n\n并且因为 LangChain 迭代极快，所以后面肯定会随着AI继续的发展，还会迭代出更好用的功能，所以我非常看好这个开源库。\n\n希望大家能结合 LangChain 开发出更有创意的产品，而不仅仅只搞一堆各种一键搭建chatgpt聊天客户端的那种产品。\n\n这篇标题后面加了个 `01` 是我希望这篇文章只是一个开始，后面如何出现了更好的技术我还是希望能继续更新下去这个系列。\n\n本文章的所有范例代码都在这里，祝大家学习愉快。\n\nhttps:\u002F\u002Fcolab.research.google.com\u002Fdrive\u002F1ArRVMiS-YkhUlobHrU6BeS8fF57UeaPQ?usp=sharing \n","# LangChain 中文入门教程\n\n> 为了便于阅读，已生成gitbook：[https:\u002F\u002Fliaokong.gitbook.io\u002Fllm-kai-fa-jiao-cheng\u002F](https:\u002F\u002Fliaokong.gitbook.io\u002Fllm-kai-fa-jiao-cheng\u002F)\n>\n> github地址：[https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FLangChain-Chinese-Getting-Started-Guide](https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FLangChain-Chinese-Getting-Started-Guide)\n>\n> 另外一篇[《Model Context Protocol(MCP) 编程极速入门》](https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FMCP-Chinese-Getting-Started-Guide)\n> \n> 《LangChain技术解密：构建大模型应用的全景指南》现已出版：[https:\u002F\u002Fitem.jd.com\u002F14598210.html](https:\u002F\u002Fitem.jd.com\u002F14598210.html)\n> \n> 低价 国内外 ai 模型 api 中转：[https:\u002F\u002Fapi.91ai.me](https:\u002F\u002Fapi.91ai.me\u002F)\n\n> 因为langchain库一直在飞速更新迭代，但该文档写与4月初，并且我个人精力有限，所以colab里面的代码有可能有些已经过时。如果有运行失败的可以先搜索一下当前文档是否有更新，如文档也没更新欢迎提issue，或者修复后直接提pr，感谢~\n\n> 加了个 [CHANGELOG](CHANGELOG.md),更新了新的内容我会写在这里，方便之前看过的朋友快速查看新的更新内容\n\n> 如果想把 OPENAI API 的请求根路由修改成自己的代理地址，可以通过设置环境变量 “OPENAI\\_API\\_BASE” 来进行修改。\n>\n> 相关参考代码：[https:\u002F\u002Fgithub.com\u002Fopenai\u002Fopenai-python\u002Fblob\u002Fd6fa3bfaae69d639b0dd2e9251b375d7070bbef1\u002Fopenai\u002F\\_\\_init\\_\\_.py#L48](https:\u002F\u002Fgithub.com\u002Fopenai\u002Fopenai-python\u002Fblob\u002Fd6fa3bfaae69d639b0dd2e9251b375d7070bbef1\u002Fopenai\u002F\\_\\_init\\_\\_.py#L48)\n>\n> 或在初始化OpenAI相关模型对象时，传入“openai\\_api\\_base” 变量。\n>\n> 相关参考代码：[https:\u002F\u002Fgithub.com\u002Fhwchase17\u002Flangchain\u002Fblob\u002Fmaster\u002Flangchain\u002Fllms\u002Fopenai.py#L148](https:\u002F\u002Fgithub.com\u002Fhwchase17\u002Flangchain\u002Fblob\u002Fmaster\u002Flangchain\u002Fllms\u002Fopenai.py#L148)\n\n## 介绍\n\n众所周知 OpenAI 的 API 无法联网的，所以如果只使用自己的功能实现联网搜索并给出回答、总结 PDF 文档、基于某个 Youtube 视频进行问答等等的功能肯定是无法实现的。所以，我们来介绍一个非常强大的第三方开源库：`LangChain` 。\n\n> 文档地址：https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002F\n\n这个库目前非常活跃，每天都在迭代，已经有 22k 的 star，更新速度飞快。\n\nLangChain 是一个用于开发由语言模型驱动的应用程序的框架。他主要拥有 2 个能力：\n\n1. 可以将 LLM 模型与外部数据源进行连接\n2. 允许与 LLM 模型进行交互\n\n> LLM 模型：Large Language Model，大型语言模型\n\n##\n\n## 基础功能\n\nLLM 调用\n\n* 支持多种模型接口，比如 OpenAI、Hugging Face、AzureOpenAI ...\n* Fake LLM，用于测试\n* 缓存的支持，比如 in-mem（内存）、SQLite、Redis、SQL\n* 用量记录\n* 支持流模式（就是一个字一个字的返回，类似打字效果）\n\nPrompt管理，支持各种自定义模板\n\n拥有大量的文档加载器，比如 Email、Markdown、PDF、Youtube ...\n\n对索引的支持\n\n* 文档分割器\n* 向量化\n* 对接向量存储与搜索，比如 Chroma、Pinecone、Qdrand\n\nChains\n\n* LLMChain\n* 各种工具Chain\n* LangChainHub\n\n## 必知概念\n\n相信大家看完上面的介绍多半会一脸懵逼。不要担心，上面的概念其实在刚开始学的时候不是很重要，当我们讲完后面的例子之后，在回来看上面的内容会一下明白很多。\n\n但是，这里有几个概念是必须知道的。\n\n##\n\n### Loader 加载器\n\n顾名思义，这个就是从指定源进行加载数据的。比如：文件夹 `DirectoryLoader`、Azure 存储 `AzureBlobStorageContainerLoader`、CSV文件 `CSVLoader`、印象笔记 `EverNoteLoader`、Google网盘 `GoogleDriveLoader`、任意的网页 `UnstructuredHTMLLoader`、PDF `PyPDFLoader`、S3 `S3DirectoryLoader`\u002F`S3FileLoader`、\n\nYoutube `YoutubeLoader` 等等，上面只是简单的进行列举了几个，官方提供了超级的多的加载器供你使用。\n\n> https:\u002F\u002Fpython.langchain.com\u002Fdocs\u002Fhow_to\u002F#document-loaders\n\n###\n\n### Document 文档\n\n当使用loader加载器读取到数据源后，数据源需要转换成 Document 对象后，后续才能进行使用。\n\n###\n\n### Text Spltters 文本分割\n\n顾名思义，文本分割就是用来分割文本的。为什么需要分割文本？因为我们每次不管是做把文本当作 prompt 发给 openai api ，还是还是使用 openai api embedding 功能都是有字符限制的。\n\n比如我们将一份300页的 pdf 发给 openai api，让他进行总结，他肯定会报超过最大 Token 错。所以这里就需要使用文本分割器去分割我们 loader 进来的 Document。\n\n###\n\n### Vectorstores 向量数据库\n\n因为数据相关性搜索其实是向量运算。所以，不管我们是使用 openai api embedding 功能还是直接通过向量数据库直接查询，都需要将我们的加载进来的数据 `Document` 进行向量化，才能进行向量运算搜索。转换成向量也很简单，只需要我们把数据存储到对应的向量数据库中即可完成向量的转换。\n\n官方也提供了很多的向量数据库供我们使用。\n\n> https:\u002F\u002Fpython.langchain.com\u002Fdocs\u002Fintegrations\u002Fvectorstores\u002F\n\n###\n\n### Chain 链\n\n我们可以把 Chain 理解为任务。一个 Chain 就是一个任务，当然也可以像链条一样，一个一个的执行多个链。\n\n###\n\n### Agent 代理\n\n我们可以简单的理解为他可以动态的帮我们选择和调用chain或者已有的工具。\n\n执行过程可以参考下面这张图:\n\n![image-20230406213322739](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_3917f56dd040.png)\n\n### Embedding\n\n用于衡量文本的相关性。这个也是 OpenAI API 能实现构建自己知识库的关键所在。\n\n他相比 fine-tuning 最大的优势就是，不用进行训练，并且可以实时添加新的内容，而不用加一次新的内容就训练一次，并且各方面成本要比 fine-tuning 低很多。\n\n> 具体比较和选择可以参考这个视频：https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=9qq6HTr7Ocw\n\n##\n\n## 实战\n\n通过上面的必备概念大家应该已经可以对 LangChain 有了一定的了解，但是可能还有有些懵。\n\n这都是小问题，我相信看完后面的实战，你们就会彻底的理解上面的内容，并且能感受到这个库的真正强大之处。\n\n因为我们 OpenAI API 进阶，所以我们后面的范例使用的 LLM 都是以Open AI 为例，后面大家可以根据自己任务的需要换成自己需要的 LLM 模型即可。\n\n当然，在这篇文章的末尾，全部的全部代码都会被保存为一个 colab 的 ipynb 文件提供给大家来学习。\n\n> 建议大家按顺序去看每个例子，因为下一个例子会用到上一个例子里面的知识点。\n>\n> 当然，如果有看不懂的也不用担心，可以继续往后看，第一次学习讲究的是不求甚解。\n\n###\n\n### 完成一次问答\n\n第一个案例，我们就来个最简单的，用 LangChain 加载 OpenAI 的模型，并且完成一次问答。\n\n在开始之前，我们需要先设置我们的 openai 的 key，这个 key 可以在用户管理里面创建，这里就不细说了。\n\n```python\nimport os\nos.environ[\"OPENAI_API_KEY\"] = '你的api key'\n```\n\n然后，我们进行导入和执行\n\n```py\nfrom langchain.llms import OpenAI\n\nllm = OpenAI(model_name=\"text-davinci-003\",max_tokens=1024)\nllm(\"怎么评价人工智能\")\n```\n\n![image-20230404232621517](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_6a41141b0b10.png)\n\n这时，我们就可以看到他给我们的返回结果了，怎么样，是不是很简单。\n\n### 通过 Google 搜索并返回答案\n\n接下来，我们就来搞点有意思的。我们来让我们的 OpenAI api 联网搜索，并返回答案给我们。\n\n这里我们需要借助 Serpapi 来进行实现，Serpapi 提供了 google 搜索的 api 接口。\n\n首先需要我们到 Serpapi 官网上注册一个用户，https:\u002F\u002Fserpapi.com\u002F 并复制他给我们生成 api key。\n\n然后我们需要像上面的 openai api key 一样设置到环境变量里面去。\n\n```python\nimport os\nos.environ[\"OPENAI_API_KEY\"] = '你的api key'\nos.environ[\"SERPAPI_API_KEY\"] = '你的api key'\n```\n\n然后，开始编写我的代码\n\n```python\nfrom langchain.agents import load_tools\nfrom langchain.agents import initialize_agent\nfrom langchain.llms import OpenAI\nfrom langchain.agents import AgentType\n\n# 加载 OpenAI 模型\nllm = OpenAI(temperature=0,max_tokens=2048) \n\n # 加载 serpapi 工具\ntools = load_tools([\"serpapi\"])\n\n# 如果搜索完想再计算一下可以这么写\n# tools = load_tools(['serpapi', 'llm-math'], llm=llm)\n\n# 如果搜索完想再让他再用python的print做点简单的计算，可以这样写\n# tools=load_tools([\"serpapi\",\"python_repl\"])\n\n# 工具加载后都需要初始化，verbose 参数为 True，会打印全部的执行详情\nagent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)\n\n# 运行 agent\nagent.run(\"What's the date today? What great events have taken place today in history?\")\n```\n\n![image-20230404234236982](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_3822665834a0.png)\n\n我们可以看到，他正确的返回了日期（有时差），并且返回了历史上的今天。\n\n在 chain 和 agent 对象上都会有 `verbose` 这个参数，这个是个非常有用的参数，开启他后我们可以看到完整的 chain 执行过程。\n\n可以在上面返回的结果看到，他将我们的问题拆分成了几个步骤，然后一步一步得到最终的答案。\n\n关于agent type 几个选项的含义（理解不了也不会影响下面的学习，用多了自然理解了）：\n\n* zero-shot-react-description: 根据工具的描述和请求内容的来决定使用哪个工具（最常用）\n* react-docstore: 使用 ReAct 框架和 docstore 交互, 使用`Search` 和`Lookup` 工具, 前者用来搜, 后者寻找term, 举例: `Wipipedia` 工具\n* self-ask-with-search 此代理只使用一个工具: Intermediate Answer, 它会为问题寻找事实答案(指的非 gpt 生成的答案, 而是在网络中,文本中已存在的), 如 `Google search API` 工具\n* conversational-react-description: 为会话设置而设计的代理, 它的prompt会被设计的具有会话性, 且还是会使用 ReAct 框架来决定使用来个工具, 并且将过往的会话交互存入内存\n\n> reAct 介绍可以看这个：https:\u002F\u002Farxiv.org\u002Fpdf\u002F2210.03629.pdf\n>\n> LLM 的 ReAct 模式的 Python 实现: https:\u002F\u002Ftil.simonwillison.net\u002Fllms\u002Fpython-react-pattern\n>\n> agent type 官方解释：\n>\n> https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Fagents\u002Fagents\u002Fagent_types.html?highlight=zero-shot-react-description\n\n> 有一点要说明的是，这个 `serpapi` 貌似对中文不是很友好，所以提问的 prompt 建议使用英文。\n\n当然，官方已经写好了 `ChatGPT Plugins` 的 agent，未来 chatgpt 能用啥插件，我们在 api 里面也能用插件，想想都美滋滋。\n\n不过目前只能使用不用授权的插件，期待未来官方解决这个。\n\n感兴趣的可以看这个文档：https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Fagents\u002Ftools\u002Fexamples\u002Fchatgpt_plugins.html\n\n> Chatgpt 只能给官方赚钱，而 Openai API 能给我赚钱\n\n### 对超长文本进行总结\n\n假如我们想要用 openai api 对一个段文本进行总结，我们通常的做法就是直接发给 api 让他总结。但是如果文本超过了 api 最大的 token 限制就会报错。\n\n这时，我们一般会进行对文章进行分段，比如通过 tiktoken 计算并分割，然后将各段发送给 api 进行总结，最后将各段的总结再进行一个全部的总结。\n\n如果，你用是 LangChain，他很好的帮我们处理了这个过程，使得我们编写代码变的非常简单。\n\n废话不多说，直接上代码。\n\n```python\nfrom langchain.document_loaders import UnstructuredFileLoader\nfrom langchain.chains.summarize import load_summarize_chain\nfrom langchain.text_splitter import RecursiveCharacterTextSplitter\nfrom langchain import OpenAI\n\n# 导入文本\nloader = UnstructuredFileLoader(\"\u002Fcontent\u002Fsample_data\u002Fdata\u002Flg_test.txt\")\n# 将文本转成 Document 对象\ndocument = loader.load()\nprint(f'documents:{len(document)}')\n\n# 初始化文本分割器\ntext_splitter = RecursiveCharacterTextSplitter(\n    chunk_size = 500,\n    chunk_overlap = 0\n)\n\n# 切分文本\nsplit_documents = text_splitter.split_documents(document)\nprint(f'documents:{len(split_documents)}')\n\n# 加载 llm 模型\nllm = OpenAI(model_name=\"text-davinci-003\", max_tokens=1500)\n\n# 创建总结链\nchain = load_summarize_chain(llm, chain_type=\"refine\", verbose=True)\n\n# 执行总结链，（为了快速演示，只总结前5段）\nchain.run(split_documents[:5])\n```\n\n首先我们对切割前和切割后的 document 个数进行了打印，我们可以看到，切割前就是只有整篇的一个 document，切割完成后，会把上面一个 document 切成 317 个 document。\n\n![image-20230405162631460](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_fa9aca708b11.png)\n\n最终输出了对前 5 个 document 的总结。\n\n![image-20230405162937249](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_b6db54d605aa.png)\n\n这里有几个参数需要注意：\n\n**文本分割器的 `chunk_overlap` 参数**\n\n这个是指切割后的每个 document 里包含几个上一个 document 结尾的内容，主要作用是为了增加每个 document 的上下文关联。比如，`chunk_overlap=0`时， 第一个 document 为 aaaaaa，第二个为 bbbbbb；当 `chunk_overlap=2` 时，第一个 document 为 aaaaaa，第二个为 aabbbbbb。\n\n不过，这个也不是绝对的，要看所使用的那个文本分割模型内部的具体算法。\n\n> 文本分割器可以参考这个文档：https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Findexes\u002Ftext_splitters.html\n\n**chain 的 `chain_type` 参数**\n\n这个参数主要控制了将 document 传递给 llm 模型的方式，一共有 4 种方式：\n\n`stuff`: 这种最简单粗暴，会把所有的 document 一次全部传给 llm 模型进行总结。如果document很多的话，势必会报超出最大 token 限制的错，所以总结文本的时候一般不会选中这个。\n\n`map_reduce`: 这个方式会先将每个 document 进行总结，最后将所有 document 总结出的结果再进行一次总结。\n\n![image-20230405165752743](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_7be22246db61.png)\n\n`refine`: 这种方式会先总结第一个 document，然后在将第一个 document 总结出的内容和第二个 document 一起发给 llm 模型在进行总结，以此类推。这种方式的好处就是在总结后一个 document 的时候，会带着前一个的 document 进行总结，给需要总结的 document 添加了上下文，增加了总结内容的连贯性。\n\n![image-20230405170617383](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_08d533987a67.png)\n\n`map_rerank`: 这种一般不会用在总结的 chain 上，而是会用在问答的 chain 上，他其实是一种搜索答案的匹配方式。首先你要给出一个问题，他会根据问题给每个 document 计算一个这个 document 能回答这个问题的概率分数，然后找到分数最高的那个 document ，在通过把这个 document 转化为问题的 prompt 的一部分（问题+document）发送给 llm 模型，最后 llm 模型返回具体答案。\n\n### 构建本地知识库问答机器人\n\n在这个例子中，我们会介绍如何从我们本地读取多个文档构建知识库，并且使用 Openai API 在知识库中进行搜索并给出答案。\n\n这个是个很有用的教程，比如可以很方便的做一个可以介绍公司业务的机器人，或是介绍一个产品的机器人。\n\n```python\nfrom langchain.embeddings.openai import OpenAIEmbeddings\nfrom langchain.vectorstores import Chroma\nfrom langchain.text_splitter import CharacterTextSplitter\nfrom langchain import OpenAI\nfrom langchain.document_loaders import DirectoryLoader\nfrom langchain.chains import RetrievalQA\n\n# 加载文件夹中的所有txt类型的文件\nloader = DirectoryLoader('\u002Fcontent\u002Fsample_data\u002Fdata\u002F', glob='**\u002F*.txt')\n# 将数据转成 document 对象，每个文件会作为一个 document\ndocuments = loader.load()\n\n# 初始化加载器\ntext_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)\n# 切割加载的 document\nsplit_docs = text_splitter.split_documents(documents)\n\n# 初始化 openai 的 embeddings 对象\nembeddings = OpenAIEmbeddings()\n# 将 document 通过 openai 的 embeddings 对象计算 embedding 向量信息并临时存入 Chroma 向量数据库，用于后续匹配查询\ndocsearch = Chroma.from_documents(split_docs, embeddings)\n\n# 创建问答对象\nqa = RetrievalQA.from_chain_type(llm=OpenAI(), chain_type=\"stuff\", retriever=docsearch.as_retriever(), return_source_documents=True)\n# 进行问答\nresult = qa({\"query\": \"科大讯飞今年第一季度收入是多少？\"})\nprint(result)\n```\n\n![image-20230405173730382](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_eadcc5828c6a.png)\n\n我们可以通过结果看到，他成功的从我们的给到的数据中获取了正确的答案。\n\n> 关于 Openai embeddings 详细资料可以参看这个连接: https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fguides\u002Fembeddings\n\n### 构建向量索引数据库\n\n我们上个案例里面有一步是将 document 信息转换成向量信息和embeddings的信息并临时存入 Chroma 数据库。\n\n因为是临时存入，所以当我们上面的代码执行完成后，上面的向量化后的数据将会丢失。如果想下次使用，那么就还需要再计算一次embeddings，这肯定不是我们想要的。\n\n那么，这个案例我们就来通过 Chroma 和 Pinecone 这两个数据库来讲一下如何做向量数据持久化。\n\n> 因为 LangChain 支持的数据库有很多，所以这里就介绍两个用的比较多的，更多的可以参看文档:https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Findexes\u002Fvectorstores\u002Fgetting\\_started.html\n\n**Chroma**\n\nchroma 是个本地的向量数据库，他提供的一个 `persist_directory` 来设置持久化目录进行持久化。读取时，只需要调取 `from_document` 方法加载即可。\n\n```python\nfrom langchain.vectorstores import Chroma\n\n# 持久化数据\ndocsearch = Chroma.from_documents(documents, embeddings, persist_directory=\"D:\u002Fvector_store\")\ndocsearch.persist()\n\n# 加载数据\ndocsearch = Chroma(persist_directory=\"D:\u002Fvector_store\", embedding_function=embeddings)\n\n```\n\n**Pinecone**\n\nPinecone 是一个在线的向量数据库。所以，我可以第一步依旧是注册，然后拿到对应的 api key。https:\u002F\u002Fapp.pinecone.io\u002F\n\n> 免费版如果索引14天不使用会被自动清除。\n\n然后创建我们的数据库：\n\nIndex Name：这个随意\n\nDimensions：OpenAI 的 text-embedding-ada-002 模型为 OUTPUT DIMENSIONS 为 1536，所以我们这里填 1536\n\nMetric：可以默认为 cosine\n\n选择starter plan\n\n![image-20230405184646314](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_8f979aa7233f.png)\n\n持久化数据和加载数据代码如下\n\n```python\n# 持久化数据\ndocsearch = Pinecone.from_texts([t.page_content for t in split_docs], embeddings, index_name=index_name)\n\n# 加载数据\ndocsearch = Pinecone.from_existing_index(index_name, embeddings)\n```\n\n一个简单从数据库获取 embeddings，并回答的代码如下\n\n```python\nfrom langchain.text_splitter import CharacterTextSplitter\nfrom langchain.document_loaders import DirectoryLoader\nfrom langchain.vectorstores import Chroma, Pinecone\nfrom langchain.embeddings.openai import OpenAIEmbeddings\nfrom langchain.llms import OpenAI\nfrom langchain.chains.question_answering import load_qa_chain\n\nimport pinecone\n\n# 初始化 pinecone\npinecone.init(\n  api_key=\"你的api key\",\n  environment=\"你的Environment\"\n)\n\nloader = DirectoryLoader('\u002Fcontent\u002Fsample_data\u002Fdata\u002F', glob='**\u002F*.txt')\n# 将数据转成 document 对象，每个文件会作为一个 document\ndocuments = loader.load()\n\n# 初始化加载器\ntext_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=0)\n# 切割加载的 document\nsplit_docs = text_splitter.split_documents(documents)\n\nindex_name=\"liaokong-test\"\n\n# 持久化数据\n# docsearch = Pinecone.from_texts([t.page_content for t in split_docs], embeddings, index_name=index_name)\n\n# 加载数据\ndocsearch = Pinecone.from_existing_index(index_name,embeddings)\n\nquery = \"科大讯飞今年第一季度收入是多少？\"\ndocs = docsearch.similarity_search(query, include_metadata=True)\n\nllm = OpenAI(temperature=0)\nchain = load_qa_chain(llm, chain_type=\"stuff\", verbose=True)\nchain.run(input_documents=docs, question=query)\n```\n\n![image-20230407001803057](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_5f4a41c475b5.png)\n\n### 使用GPT3.5模型构建油管频道问答机器人\n\n在 chatgpt api（也就是 GPT-3.5-Turbo）模型出来后，因钱少活好深受大家喜爱，所以 LangChain 也加入了专属的链和模型，我们来跟着这个例子看下如何使用他。\n\n```python\nimport os\n\nfrom langchain.document_loaders import YoutubeLoader\nfrom langchain.embeddings.openai import OpenAIEmbeddings\nfrom langchain.vectorstores import Chroma\nfrom langchain.text_splitter import RecursiveCharacterTextSplitter\nfrom langchain.chains import ChatVectorDBChain, ConversationalRetrievalChain\n\nfrom langchain.chat_models import ChatOpenAI\nfrom langchain.prompts.chat import (\n  ChatPromptTemplate,\n  SystemMessagePromptTemplate,\n  HumanMessagePromptTemplate\n)\n\n# 加载 YouTube 频道\nloader = YoutubeLoader.from_youtube_url('https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=Dj60HHy-Kqk')\n# 将数据转成 document\ndocuments = loader.load()\n\n# 初始化文本分割器\ntext_splitter = RecursiveCharacterTextSplitter(\n  chunk_size=1000,\n  chunk_overlap=20\n)\n\n# 分割 YouTube documents\ndocuments = text_splitter.split_documents(documents)\n\n# 初始化 OpenAI 嵌入模型\nembeddings = OpenAIEmbeddings()\n\n# 将数据存入向量存储\nvector_store = Chroma.from_documents(documents, embeddings)\n# 通过向量存储初始化检索器\nretriever = vector_store.as_retriever()\n\nsystem_template = \"\"\"\n请根据以下上下文回答用户的问题。\n如果不知道答案，请直接说明不知道，不要编造。请用中文作答。\n-----------\n{question}\n-----------\n{chat_history}\n\"\"\"\n\n# 构建初始 messages 列表，这里可以理解为是 OpenAI 传入的 messages 参数\nmessages = [\n  SystemMessagePromptTemplate.from_template(system_template),\n  HumanMessagePromptTemplate.from_template('{question}')\n]\n\n# 初始化 prompt 对象\nprompt = ChatPromptTemplate.from_messages(messages)\n\n\n# 初始化问答链\nqa = ConversationalRetrievalChain.from_llm(ChatOpenAI(temperature=0.1,max_tokens=2048),retriever,condense_question_prompt=prompt)\n\n\nchat_history = []\nwhile True:\n  question = input('问题：')\n  # 开始发送问题 chat_history 为必须参数,用于存储对话历史\n  result = qa({'question': question, 'chat_history': chat_history})\n  chat_history.append((question, result['answer']))\n  print(result['answer'])\n```\n\n我们可以看到他能很准确的围绕这个油管视频进行问答\n\n![image-20230406211923672](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_7347cadc13a4.png)\n\n使用流式回答也很方便\n\n```python\nfrom langchain.callbacks.base import CallbackManager\nfrom langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler\n\nchat = ChatOpenAI(streaming=True, callback_manager=CallbackManager([StreamingStdOutCallbackHandler()]), verbose=True, temperature=0)\nresp = chat(chat_prompt_with_values.to_messages())\n```\n\n### 用 OpenAI 连接万种工具\n\n我们主要是结合使用 `Zapier` 来实现将万种工具连接起来。\n\n所以我们第一步依旧是需要申请账号和他的自然语言 API key。https:\u002F\u002Fzapier.com\u002Fl\u002Fnatural-language-actions\n\n他的 API key 虽然需要填写信息申请。但是基本填入信息后，基本可以秒在邮箱里看到审核通过的邮件。\n\n然后，我们通过右键里面的连接打开我们的 API 配置页面。我们点击右侧的 `Manage Actions` 来配置我们要使用哪些应用。\n\n我在这里配置了 Gmail 读取和发邮件的 action，并且所有字段都选的是通过 AI 猜。\n\n![image-20230406233319250](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_fc21b487d183.png)\n\n![image-20230406234827815](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_338740425695.png)\n\n配置好后，我们开始写代码\n\n```python\nimport os\nos.environ[\"ZAPIER_NLA_API_KEY\"] = ''\n```\n\n```python\nfrom langchain.llms import OpenAI\nfrom langchain.agents import initialize_agent\nfrom langchain.agents.agent_toolkits import ZapierToolkit\nfrom langchain.utilities.zapier import ZapierNLAWrapper\n\n\nllm = OpenAI(temperature=.3)\nzapier = ZapierNLAWrapper()\ntoolkit = ZapierToolkit.from_zapier_nla_wrapper(zapier)\nagent = initialize_agent(toolkit.get_tools(), llm, agent=\"zero-shot-react-description\", verbose=True)\n\n# 我们可以通过打印的方式看到我们都在 Zapier 里面配置了哪些可以用的工具\nfor tool in toolkit.get_tools():\n  print (tool.name)\n  print (tool.description)\n  print (\"\\n\\n\")\n\nagent.run('请用中文总结最后一封\"******@qq.com\"发给我的邮件。并将总结发送给\"******@qq.com\"')\n```\n\n![image-20230406234712909](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_309697c1c2b4.png)\n\n我们可以看到他成功读取了`******@qq.com`给他发送的最后一封邮件，并将总结的内容又发送给了`******@qq.com`\n\n这是我发送给 Gmail 的邮件。\n\n![image-20230406234017369](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_97e7781f43f6.png)\n\n这是他发送给 QQ 邮箱的邮件。\n\n![image-20230406234800632](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_51ab24d2b34a.png)\n\n这只是个小例子，因为 `Zapier` 有数以千计的应用，所以我们可以轻松结合 OpenAI API 搭建自己的工作流。\n\n## 小例子们\n\n一些比较大的知识点都已经讲完了，后面的内容都是一些比较有趣的小例子，当作拓展延伸。\n\n### **执行多个 chain**\n\n因为他是链式的，所以他也可以按顺序依次去执行多个 chain\n\n```python\nfrom langchain.llms import OpenAI\nfrom langchain.chains import LLMChain\nfrom langchain.prompts import PromptTemplate\nfrom langchain.chains import SimpleSequentialChain\n\n# location 链\nllm = OpenAI(temperature=1)\ntemplate = \"\"\"Your job is to come up with a classic dish from the area that the users suggests.\n% 用户所在地\n{user_location}\n\n你的回复：\n\"\"\"\nprompt_template = PromptTemplate(input_variables=[\"user_location\"], template=template)\nlocation_chain = LLMChain(llm=llm, prompt=prompt_template)\n\n# meal 链\ntemplate = \"\"\"Given a meal, give a short and simple recipe on how to make that dish at home.\n% 餐食\n{user_meal}\n\n你的回复：\n\"\"\"\nprompt_template = PromptTemplate(input_variables=[\"user_meal\"], template=template)\nmeal_chain = LLMChain(llm=llm, prompt=prompt_template)\n\n# 通过 SimpleSequentialChain 串联起来，第一个答案会被替换第二个中的user_meal，然后再进行询问\noverall_chain = SimpleSequentialChain(chains=[location_chain, meal_chain], verbose=True)\nreview = overall_chain.run(\"罗马\")\n```\n\n![image-20230406000133339](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_544a871712bf.png)\n\n### **结构化输出**\n\n有时候我们希望输出的内容不是文本，而是像 JSON 那样结构化的数据。\n\n```python\nfrom langchain.output_parsers import StructuredOutputParser, ResponseSchema\nfrom langchain.prompts import PromptTemplate\nfrom langchain.llms import OpenAI\n\nllm = OpenAI(model_name=\"text-davinci-003\")\n\n# 告诉他我们生成的内容需要哪些字段，每个字段类型式啥\nresponse_schemas = [\n    ResponseSchema(name=\"bad_string\", description=\"这是一个格式不正确的用户输入字符串\"),\n    ResponseSchema(name=\"good_string\", description=\"这是你的回复，一个重新格式化的响应\")\n]\n\n# 初始化解析器\noutput_parser = StructuredOutputParser.from_response_schemas(response_schemas)\n\n# 生成的格式提示符\n# {\n#\t\"bad_string\": string  \u002F\u002F 这是一个格式不正确的用户输入字符串\n#\t\"good_string\": string  \u002F\u002F 这是你的回复，一个重新格式化的响应\n#}\nformat_instructions = output_parser.get_format_instructions()\n\ntemplate = \"\"\"\n你将会收到用户提供的一个格式不正确的字符串。\n请将其重新格式化，并确保所有单词拼写正确。\n\n{format_instructions}\n\n% 用户输入：\n{user_input}\n\n你的回复：\n\"\"\"\n\n# 将我们的格式描述嵌入到 prompt 中去，告诉 llm 我们需要他输出什么样格式的内容\nprompt = PromptTemplate(\n    input_variables=[\"user_input\"],\n    partial_variables={\"format_instructions\": format_instructions},\n    template=template\n)\n\npromptValue = prompt.format(user_input=\"welcom to califonya!\")\nllm_output = llm(promptValue)\n\n# 使用解析器进行解析生成的内容\noutput_parser.parse(llm_output)\n```\n\n![image-20230406000017276](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_a1abe80772c6.png)\n\n### **爬取网页并输出JSON数据**\n\n有些时候我们需要爬取一些\u003Cmark style=\"color:red;\">**结构性比较强**\u003C\u002Fmark>的网页，并且需要将网页中的信息以JSON的方式返回回来。\n\n我们就可以使用 `LLMRequestsChain` 类去实现，具体可以参考下面代码\n\n> 为了方便理解，我在例子中直接使用了Prompt的方法去格式化输出结果，而没用使用上个案例中用到的 `StructuredOutputParser`去格式化，也算是提供了另外一种格式化的思路\n\n```python\nfrom langchain.prompts import PromptTemplate\nfrom langchain.llms import OpenAI\nfrom langchain.chains import LLMRequestsChain, LLMChain\n\nllm = OpenAI(model_name=\"gpt-3.5-turbo\", temperature=0)\n\ntemplate = \"\"\"在 >>> 和 \u003C\u003C\u003C 之间是网页的返回的HTML内容。\n网页是新浪财经A股上市公司的公司简介。\n请抽取参数请求的信息。\n\n>>> {requests_result} \u003C\u003C\u003C\n请使用如下的JSON格式返回数据\n{{\n  \"company_name\":\"a\",\n  \"company_english_name\":\"b\",\n  \"issue_price\":\"c\",\n  \"date_of_establishment\":\"d\",\n  \"registered_capital\":\"e\",\n  \"office_address\":\"f\",\n  \"Company_profile\":\"g\"\n\n}}\nExtracted:\"\"\"\n\nprompt = PromptTemplate(\n    input_variables=[\"requests_result\"],\n    template=template\n)\n\nchain = LLMRequestsChain(llm_chain=LLMChain(llm=llm, prompt=prompt))\ninputs = {\n  \"url\": \"https:\u002F\u002Fvip.stock.finance.sina.com.cn\u002Fcorp\u002Fgo.php\u002FvCI_CorpInfo\u002Fstockid\u002F600519.phtml\"\n}\n\nresponse = chain(inputs)\nprint(response['output'])\n```\n\n我们可以看到，他很好的将格式化后的结果输出了出来\n\n\u003Cfigure>\u003Cimg src=\"https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_e2f45d954865.png\" alt=\"\">\u003Cfigcaption>\u003C\u002Ffigcaption>\u003C\u002Ffigure>\n\n### **自定义agent中所使用的工具**\n\n```python\nfrom langchain.agents import initialize_agent, Tool\nfrom langchain.agents import AgentType\nfrom langchain.tools import BaseTool\nfrom langchain.llms import OpenAI\nfrom langchain import LLMMathChain, SerpAPIWrapper\n\nllm = OpenAI(temperature=0)\n\n# 初始化搜索链和计算链\nsearch = SerpAPIWrapper()\nllm_math_chain = LLMMathChain(llm=llm, verbose=True)\n\n# 创建一个功能列表，指明这个 agent 里面都有哪些可用工具，agent 执行过程可以看必知概念里的 Agent 那张图\ntools = [\n    Tool(\n        name = \"Search\",\n        func=search.run,\n        description=\"useful for when you need to answer questions about current events\"\n    ),\n    Tool(\n        name=\"Calculator\",\n        func=llm_math_chain.run,\n        description=\"useful for when you need to answer questions about math\"\n    )\n]\n\n# 初始化 agent\nagent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)\n\n# 执行 agent\nagent.run(\"Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?\")\n\n```\n\n![image-20230406002117283](https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_readme_cca181f14782.png)\n\n自定义工具里面有个比较有意思的地方，使用哪个工具的权重是靠 `工具中描述内容` 来实现的，和我们之前编程靠数值来控制权重完全不同。\n\n比如 Calculator 在描述里面写到，如果你问关于数学的问题就用他这个工具。我们就可以在上面的执行过程中看到，他在我们请求的 prompt 中数学的部分，就选用了Calculator 这个工具进行计算。\n\n### **使用Memory实现一个带记忆的对话机器人**\n\n上一个例子我们使用的是通过自定义一个列表来存储对话的方式来保存历史的。\n\n当然，你也可以使用自带的 memory 对象来实现这一点。\n\n```python\nfrom langchain.memory import ChatMessageHistory\nfrom langchain.chat_models import ChatOpenAI\n\nchat = ChatOpenAI(temperature=0)\n\n# 初始化 MessageHistory 对象\nhistory = ChatMessageHistory()\n\n# 给 MessageHistory 对象添加对话内容\nhistory.add_ai_message(\"你好！\")\nhistory.add_user_message(\"中国的首都是哪里？\")\n\n# 执行对话\nai_response = chat(history.messages)\nprint(ai_response)\n```\n\n### **使用 Hugging Face 模型**\n\n使用 Hugging Face 模型之前，需要先设置环境变量\n\n```python\nimport os\nos.environ['HUGGINGFACEHUB_API_TOKEN'] = ''\n```\n\n使用在线的 Hugging Face 模型\n\n```python\nfrom langchain import PromptTemplate, HuggingFaceHub, LLMChain\n\ntemplate = \"\"\"Question: {question}\nAnswer: Let's think step by step.\"\"\"\n\nprompt = PromptTemplate(template=template, input_variables=[\"question\"])\nllm = HuggingFaceHub(repo_id=\"google\u002Fflan-t5-xl\", model_kwargs={\"temperature\":0, \"max_length\":64})\nllm_chain = LLMChain(prompt=prompt, llm=llm)\n\nquestion = \"What NFL team won the Super Bowl in the year Justin Beiber was born?\"\nprint(llm_chain.run(question))\n```\n\n将 Hugging Face 模型直接拉到本地使用\n\n```python\nfrom langchain import PromptTemplate, LLMChain\nfrom langchain.llms import HuggingFacePipeline\nfrom transformers import AutoTokenizer, AutoModelForCausalLM, pipeline, AutoModelForSeq2SeqLM\n\nmodel_id = 'google\u002Fflan-t5-large'\ntokenizer = AutoTokenizer.from_pretrained(model_id)\nmodel = AutoModelForSeq2SeqLM.from_pretrained(model_id)\n\npipe = pipeline(\n    \"text2text-generation\",\n    model=model,\n    tokenizer=tokenizer,\n    max_length=100\n)\n\nlocal_llm = HuggingFacePipeline(pipeline=pipe)\nprint(local_llm('What is the capital of France? '))\n\n\ntemplate = \"\"\"Question: {question} Answer: Let's think step by step.\"\"\"\nprompt = PromptTemplate(template=template, input_variables=[\"question\"])\n\nllm_chain = LLMChain(prompt=prompt, llm=local_llm)\nquestion = \"What is the capital of England?\"\nprint(llm_chain.run(question))\n```\n\n将模型拉到本地使用的好处：\n\n* 训练模型\n* 可以使用本地的 GPU\n* 有些模型无法在 Hugging Face 运行\n\n### **通过自然语言执行SQL命令**\n\n我们通过 `SQLDatabaseToolkit` 或者 `SQLDatabaseChain` 都可以实现执行SQL命令的操作\n\n```python\nfrom langchain.agents import create_sql_agent\nfrom langchain.agents.agent_toolkits import SQLDatabaseToolkit\nfrom langchain.sql_database import SQLDatabase\nfrom langchain.llms.openai import OpenAI\n\ndb = SQLDatabase.from_uri(\"sqlite:\u002F\u002F\u002F..\u002Fnotebooks\u002FChinook.db\")\ntoolkit = SQLDatabaseToolkit(db=db)\n\nagent_executor = create_sql_agent(\n    llm=OpenAI(temperature=0),\n    toolkit=toolkit,\n    verbose=True\n)\n\nagent_executor.run(\"Describe the playlisttrack table\")\n```\n\n```python\nfrom langchain import OpenAI, SQLDatabase, SQLDatabaseChain\n\ndb = SQLDatabase.from_uri(\"mysql+pymysql:\u002F\u002Froot:root@127.0.0.1\u002Fchinook\")\nllm = OpenAI(temperature=0)\n\ndb_chain = SQLDatabaseChain(llm=llm, database=db, verbose=True)\ndb_chain.run(\"How many employees are there?\")\n```\n\n这里可以参考这两篇文档：\n\n[https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Fagents\u002Ftoolkits\u002Fexamples\u002Fsql\\_database.html](https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Fagents\u002Ftoolkits\u002Fexamples\u002Fsql\\_database.html)\n\n[https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Fchains\u002Fexamples\u002Fsqlite.html](https:\u002F\u002Fpython.langchain.com\u002Fen\u002Flatest\u002Fmodules\u002Fchains\u002Fexamples\u002Fsqlite.html)\n\n## 总结\n\n所有的案例都基本已经结束了，希望大家能通过这篇文章的学习有所收获。这篇文章只是对 LangChain 一个初级的讲解，高级的功能希望大家继续探索。\n\n并且因为 LangChain 迭代极快，所以后面肯定会随着AI继续的发展，还会迭代出更好用的功能，所以我非常看好这个开源库。\n\n希望大家能结合 LangChain 开发出更有创意的产品，而不仅仅只搞一堆各种一键搭建chatgpt聊天客户端的那种产品。\n\n这篇标题后面加了个 `01` 是我希望这篇文章只是一个开始，后面如何出现了更好的技术我还是希望能继续更新下去这个系列。\n\n本文章的所有范例代码都在这里，祝大家学习愉快。\n\nhttps:\u002F\u002Fcolab.research.google.com\u002Fdrive\u002F1ArRVMiS-YkhUlobHrU6BeS8fF57UeaPQ?usp=sharing","# LangChain 中文快速上手指南\n\n本指南基于 `LangChain-Chinese-Getting-Started-Guide` 整理，旨在帮助开发者快速掌握利用 LangChain 框架构建大语言模型（LLM）应用的核心流程。\n\n## 环境准备\n\n在开始之前，请确保您的开发环境满足以下要求：\n\n*   **操作系统**：Windows \u002F macOS \u002F Linux\n*   **Python 版本**：推荐 Python 3.9 或更高版本\n*   **前置依赖**：\n    *   `pip` 包管理工具\n    *   OpenAI API Key（或其他支持的 LLM API Key）\n    *   （可选）SerpAPI Key（用于联网搜索功能）\n    *   （可选）向量数据库账号（如 Pinecone）或本地存储路径\n\n> **提示**：如果您在国内访问 OpenAI API 受限，可通过设置环境变量 `OPENAI_API_BASE` 指向代理地址，或在初始化模型时传入 `openai_api_base` 参数。\n\n## 安装步骤\n\n使用 pip 安装 LangChain 核心库及常用依赖。建议同时安装嵌入模型和向量存储支持。\n\n```bash\n# 安装 langchain 核心库\npip install langchain\n\n# 安装 OpenAI 相关依赖\npip install langchain-openai\n\n# 安装文档加载器依赖 (如处理 PDF, HTML 等)\npip install unstructured pdf2image pydantic lxml\n\n# 安装向量数据库依赖 (以 Chroma 为例，本地轻量级)\npip install chromadb\n\n# 安装联网搜索工具依赖 (如需使用 Google 搜索)\npip install google-search-results\n```\n\n> **国内加速建议**：如果下载缓慢，可使用国内镜像源安装：\n> ```bash\n> pip install -i https:\u002F\u002Fpypi.tuna.tsinghua.edu.cn\u002Fsimple langchain langchain-openai chromadb unstructured\n> ```\n\n## 基本使用\n\n以下是三个最核心的应用场景示例，涵盖基础问答、联网搜索和本地知识库构建。\n\n### 1. 基础 LLM 问答\n\n最简单的调用方式，直接与大模型进行对话。\n\n```python\nimport os\nfrom langchain_openai import ChatOpenAI\n\n# 设置 API Key\nos.environ[\"OPENAI_API_KEY\"] = \"你的-api-key\"\n\n# 初始化模型\nllm = ChatOpenAI(model_name=\"gpt-3.5-turbo\", temperature=0)\n\n# 执行问答\nresponse = llm.invoke(\"怎么评价人工智能？\")\nprint(response.content)\n```\n\n### 2. 联网搜索 Agent\n\n让模型具备联网能力，实时获取信息并回答问题（需 SerpAPI Key）。\n\n```python\nimport os\nfrom langchain.agents import load_tools, initialize_agent, AgentType\nfrom langchain_openai import ChatOpenAI\n\n# 设置 Keys\nos.environ[\"OPENAI_API_KEY\"] = \"你的-openai-key\"\nos.environ[\"SERPAPI_API_KEY\"] = \"你的-serpapi-key\"\n\n# 初始化模型\nllm = ChatOpenAI(temperature=0)\n\n# 加载工具 (serpapi 用于搜索)\ntools = load_tools([\"serpapi\"], llm=llm)\n\n# 初始化 Agent\nagent = initialize_agent(\n    tools, \n    llm, \n    agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, \n    verbose=True\n)\n\n# 运行任务\nagent.run(\"今天历史上发生了什么重大事件？\")\n```\n\n### 3. 构建本地知识库问答 (RAG)\n\n读取本地文档，建立向量索引，并基于文档内容进行问答。\n\n```python\nfrom langchain.document_loaders import DirectoryLoader\nfrom langchain.text_splitter import CharacterTextSplitter\nfrom langchain_openai import OpenAIEmbeddings, ChatOpenAI\nfrom langchain.vectorstores import Chroma\nfrom langchain.chains import RetrievalQA\n\n# 1. 加载文档 (读取指定文件夹下的所有 txt 文件)\nloader = DirectoryLoader('.\u002Fdata', glob='**\u002F*.txt')\ndocuments = loader.load()\n\n# 2. 文本分割 (避免超过 Token 限制)\ntext_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)\nsplit_docs = text_splitter.split_documents(documents)\n\n# 3. 创建向量存储 (自动计算 Embedding 并存入 Chroma)\nembeddings = OpenAIEmbeddings()\ndocsearch = Chroma.from_documents(split_docs, embeddings)\n\n# 4. 创建问答链\nllm = ChatOpenAI(temperature=0)\nqa = RetrievalQA.from_chain_type(\n    llm=llm, \n    chain_type=\"stuff\", \n    retriever=docsearch.as_retriever(),\n    return_source_documents=True\n)\n\n# 5. 执行问答\nquery = \"科大讯飞今年第一季度收入是多少？\"\nresult = qa({\"query\": query})\nprint(result[\"result\"])\n```\n\n### 关键概念简述\n\n*   **Loader (加载器)**：负责从各种数据源（PDF, URL, Notion, GitHub 等）加载数据。\n*   **Document (文档)**：加载后的标准数据对象，包含页面内容和元数据。\n*   **Text Splitter (文本分割)**：将长文本切分为小块，以适应 LLM 的上下文窗口限制。\n*   **Vectorstore (向量数据库)**：存储文本的向量表示，用于语义相似度搜索（如 Chroma, Pinecone）。\n*   **Chain (链)**：将多个组件（如提示词模板、LLM、输出解析器）串联起来执行特定任务。\n*   **Agent (代理)**：允许 LLM 动态选择工具（如搜索、计算器）来解决复杂问题。","某初创公司的后端工程师小张，急需为公司内部知识库构建一个能自动总结 PDF 报告并回答员工提问的 AI 助手。\n\n### 没有 LangChain-Chinese-Getting-Started-Guide 时\n- **语言门槛高**：面对全英文的官方文档和复杂的概念（如 Chain、Agent），非英语母语开发者理解成本极高，容易在半途放弃。\n- **环境配置困难**：不清楚如何正确设置 API 代理地址或处理国内网络问题，导致代码在第一步调用模型时就频繁报错。\n- **核心逻辑模糊**：难以理解如何将几百页的 PDF 文档进行合理的“文本分割”和“向量化”，常常因超出 Token 限制而束手无策。\n- **试错成本巨大**：缺乏系统的实战案例指引，只能盲目搜索零散代码片段，花费数天时间仍无法跑通第一个\"Hello World\"级别的问答流程。\n\n### 使用 LangChain-Chinese-Getting-Started-Guide 后\n- **快速上手概念**：通过中文教程对 Loader、Text Splitters、Vectorstores 等核心概念的通俗解读，迅速理清了数据从加载到检索的全链路逻辑。\n- **解决本地化难题**：直接参考文档中关于修改 `OPENAI_API_BASE` 环境变量和使用国内中转 API 的指导，几分钟内便打通了模型连接。\n- **掌握关键技法**：依据教程中的实战章节，轻松实现了将大型 PDF 文档自动切片、存入向量数据库（如 Chroma）并进行语义搜索的功能。\n- **高效落地应用**：跟随循序渐进的 Colab 代码示例，一天内就完成了从“读取文件”到“智能问答”的原型开发，大幅缩短研发周期。\n\nLangChain-Chinese-Getting-Started-Guide 通过消除语言障碍和提供本土化实战路径，让开发者能将精力专注于业务逻辑创新，而非消耗在基础环境的搭建与概念理解上。","https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002FliaokongVFX_LangChain-Chinese-Getting-Started-Guide_6a41141b.png","liaokongVFX","了空","https:\u002F\u002Foss.gittoolsai.com\u002Favatars\u002FliaokongVFX_21b240af.jpg",null,"Hangzhou, China","https:\u002F\u002Fgithub.com\u002FliaokongVFX",8926,707,"2026-04-15T14:48:30","未说明",{"notes":84,"python":82,"dependencies":85},"本项目为 LangChain 中文入门教程，主要依赖 OpenAI API 及第三方服务（如 SerpAPI、Pinecone）。运行示例代码需配置 OPENAI_API_KEY 等环境变量。部分功能（如向量数据库持久化）支持本地 Chroma 或云端 Pinecone。文档提到代码基于 4 月初版本，可能因 LangChain 库快速迭代而过时，建议结合最新文档使用。",[86,87,88,89,90,91],"langchain","openai","chroma","pinecone-client","serpapi","tiktoken",[35,14,45],[94,86,87,95,96],"chatgpt","openai-api","aigc","2026-03-27T02:49:30.150509","2026-04-18T21:06:00.157132",[100,105,110,115,120,125,130,135],{"id":101,"question_zh":102,"answer_zh":103,"source_url":104},36216,"如何让 LangChain 对超长文本的总结输出为中文而不是英文？","需要在 Prompt 模板中明确指定使用中文。可以在 `prompt_template` 末尾添加 \"CONCISE SUMMARY IN CHINESE:\"，并在 `refine_template` 中添加 \"Given the new context, refine the original summary in CHINESE\" 等指令，强制模型用中文输出。","https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FLangChain-Chinese-Getting-Started-Guide\u002Fissues\u002F12",{"id":106,"question_zh":107,"answer_zh":108,"source_url":109},36213,"在国内无法访问 OpenAI 时，如何修改 LangChain 的 base_url？遇到 AttributeError 报错怎么办？","可以通过设置 API_BASE 来修改地址。如果遇到 'AttributeError: 'str' object has no attribute 'get'' 错误，通常是因为 LangChain 的 OPENAIEmbeddings 使用了旧版 engine 接口，而部分第三方接口不支持。建议检查 LangChain 版本是否已合并了相关修复 PR，或者尝试更新到最新版本以支持新接口。","https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FLangChain-Chinese-Getting-Started-Guide\u002Fissues\u002F1",{"id":111,"question_zh":112,"answer_zh":113,"source_url":114},36214,"运行 YouTube 视频问答示例时，第二次提问报错 'Missing some input keys: {context}' 如何解决？","这是因为 LangChain 后续版本修改了模板变量名称。解决方法是将 system_template 中的 `{context}` 改为 `{question}`。同时，初始化问答链时需将 `qa_prompt` 参数替换为 `condense_question_prompt`，例如：`ConversationalRetrievalChain.from_llm(..., condense_question_prompt=prompt)`。","https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FLangChain-Chinese-Getting-Started-Guide\u002Fissues\u002F26",{"id":116,"question_zh":117,"answer_zh":118,"source_url":119},36215,"构建本地知识库问答机器人时，提示 'maximum context length is 4097 tokens' 超出限制怎么办？","总内容长度由内置 Prompt 模板、问题长度和检索到的文档内容组成。解决方法包括：1. 减小搜索时的 k 值（检索文档条数）；2. 调整文本分割器，推荐使用 `RecursiveCharacterTextSplitter` 以获得语义相关性更强的分块；3. 减小 `chunk_size` 值，确保单个 document 不会过长。","https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FLangChain-Chinese-Getting-Started-Guide\u002Fissues\u002F19",{"id":121,"question_zh":122,"answer_zh":123,"source_url":124},36217,"导入 `load_tools` 时出现 'ImportError: cannot import name load_tools' 错误是什么原因？","这通常是版本兼容性问题。在 langchain 0.286 等较新版本中，`load_tools` 依然存在于 `langchain.agents` 模块中。请检查您的 langchain 安装版本，确保使用的是与教程代码匹配的受支持版本，或者查看官方源码确认导入路径是否正确。","https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FLangChain-Chinese-Getting-Started-Guide\u002Fissues\u002F62",{"id":126,"question_zh":127,"answer_zh":128,"source_url":129},36218,"LangChain 的 MapReduce Chain 是并发执行还是顺序执行？","LangChain 的 MapReduce Chain 实现上是同步顺序执行的，即每一个文档（doc）总结完成后才执行下一个，最后进行合并（Reduce）。文档中的流程图仅表示逻辑上的分而治之，并不代表代码实际是异步并发执行的。","https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FLangChain-Chinese-Getting-Started-Guide\u002Fissues\u002F43",{"id":131,"question_zh":132,"answer_zh":133,"source_url":134},36219,"如何使用 PHP 构建本地知识库并对接 Pinecone 向量数据库？","可以使用 `langchain-php` 库（需注意可能需要 PHP 8.1+），或者直接调用 Pinecone 和 OpenAI 的 API 自行编写。Pinecone 提供了 RESTful API 和 PHP 请求示例，可参考其官方文档进行集成，无需强依赖 LangChain 的 PHP 封装。","https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FLangChain-Chinese-Getting-Started-Guide\u002Fissues\u002F37",{"id":136,"question_zh":137,"answer_zh":138,"source_url":139},36220,"项目有官方的交流群吗？","目前项目暂无官方交流群，维护者担心群组变成闲聊或潜水群。建议用户直接通过 GitHub Issues 提问以获得更准确的解答。社区用户曾自发建立过 QQ 群（如 697568038），但非官方维护。","https:\u002F\u002Fgithub.com\u002FliaokongVFX\u002FLangChain-Chinese-Getting-Started-Guide\u002Fissues\u002F18",[]]