├── README.md ├── docs ├── .nojekyll ├── C1 │ ├── 1. 什么是⼤模型.md │ ├── 2. ⼤模型的能⼒和特点.md │ ├── 3. 常⻅⼤模型.md │ └── 4. 什么是 LangChain.md ├── C2 │ ├── 1. 基本概念.md │ ├── 2. 调用ChatGPT.md │ ├── 3. 调用百度文心.md │ ├── 4. 调用讯飞星火.md │ ├── 5. 调用智谱 AI(ChatGLM).md │ ├── 6. 调用智谱 AI(ChatGLM)生成 embedding.md │ ├── 7. 总结.md │ ├── 附1.LangChain自定义 LLM.md │ ├── 附2.将大模型 API 封装成本地 API.md │ └── 附3.LangChain 自定义 LLM embedding.md ├── C3 │ ├── 1. 大模型开发流程.md │ ├── 2. 项目流程简析.md │ └── 3. 项目架构简析.md ├── C4 │ ├── 1. 知识库文档处理.md │ ├── 2. 向量数据库的介绍及使用.md │ └── 3. 构建项目数据库.md ├── C5 │ ├── 1.Prompt 设计的原则和技巧.md │ ├── 2.基于问答助⼿的 Prompt 构建.md │ └── 3.添加历史对话的记忆功能.md ├── C6 │ ├── 1. 验证迭代的一般思路.md │ ├── 2. 解决Bad Case.md │ └── 3. 大模型评估方法.md ├── C7 │ ├── 1. Gradio 的介绍与前端界面的搭建.md │ └── 2. fast api 进行前后端分离.md ├── README.md ├── _sidebar.md ├── figures │ ├── 2023-10-02-12-57-39.png │ ├── AI_eval.png │ ├── Agents.png │ ├── Bard.png │ ├── Claude.png │ ├── GPT-series.png │ ├── LLM_developing.png │ ├── LLM_developing_whole.png │ ├── LLM_eval.png │ ├── LLMs-0623-final.png │ ├── Modular_components.png │ ├── Summary_of_Closed_Source_LLM.png │ ├── Summary_of_Open_Source_LLM.png │ ├── baichuan.png │ ├── baidu_qianfan_1.png │ ├── baidu_qianfan_2.png │ ├── baidu_qianfan_3.png │ ├── baidu_qianfan_4.png │ ├── chatglm.png │ ├── data_collection.png │ ├── eval.png │ ├── example-splitter.png │ ├── flow_chart.png │ ├── langchain_model_input_output.png │ ├── memory.png │ ├── openai-choose.png │ ├── openai-get-key.png │ ├── prompt.png │ ├── prompt_example.png │ ├── recently_LLM.png │ ├── spark_1.png │ ├── spark_2.png │ ├── structure.jpg │ ├── types-of-splitters.png │ ├── zhipuai_api.png │ ├── zhipuai_home.png │ ├── zhipuai_overview.png │ ├── zhipuai_pay.png │ ├── 文心一言.PNG │ ├── 星火.png │ └── 通义千问.png └── index.html ├── figures ├── 2023-10-02-12-57-39.png ├── AI_eval.png ├── Agents.png ├── Bard.png ├── Claude.png ├── GPT-series.png ├── LLM_developing.png ├── LLM_developing_whole.png ├── LLM_eval.png ├── LLMs-0623-final.png ├── Modular_components.png ├── Summary_of_Closed_Source_LLM.png ├── Summary_of_Open_Source_LLM.png ├── baichuan.png ├── baidu_qianfan_1.png ├── baidu_qianfan_2.png ├── baidu_qianfan_3.png ├── baidu_qianfan_4.png ├── chatglm.png ├── data_collection.png ├── eval.png ├── example-splitter.png ├── flow_chart.png ├── langchain_model_input_output.png ├── memory.png ├── openai-choose.png ├── openai-get-key.png ├── prompt.png ├── prompt_example.png ├── recently_LLM.png ├── spark_1.png ├── spark_2.png ├── structure.jpg ├── types-of-splitters.png ├── zhipuai_api.png ├── zhipuai_home.png ├── zhipuai_overview.png ├── zhipuai_pay.png ├── 文心一言.PNG ├── 星火.png └── 通义千问.png ├── notebook ├── C1 大模型简介 │ ├── 1. 什么是⼤模型.md │ ├── 2. ⼤模型的能⼒、特点.md │ ├── 3. 常⻅⼤模型.md │ └── 4. 什么是 LangChain.md ├── C2 调用大模型 API │ ├── .env │ ├── .ipynb_checkpoints │ │ ├── 2. 调用ChatGPT-checkpoint.ipynb │ │ ├── 3. 调用百度文心-checkpoint.ipynb │ │ ├── 4. 调用讯飞星火-checkpoint.ipynb │ │ ├── 5. 调用智谱 AI(ChatGLM)-checkpoint.ipynb │ │ ├── 6. 调用智谱 AI(ChatGLM)生成 embedding-checkpoint.ipynb │ │ ├── 附1.LangChain自定义 LLM-checkpoint.ipynb │ │ ├── 附2.将大模型 API 封装成本地 API-checkpoint.ipynb │ │ └── 附3.LangChain 自定义 LLM embedding-checkpoint.ipynb │ ├── 1. 基本概念.md │ ├── 2. 调用ChatGPT.ipynb │ ├── 3. 调用百度文心.ipynb │ ├── 4. 调用讯飞星火.ipynb │ ├── 5. 调用智谱 AI(ChatGLM).ipynb │ ├── 6. 调用智谱 AI(ChatGLM)生成 embedding.ipynb │ ├── 7. 总结.md │ ├── SparkApi.py │ ├── SparkApiSelf.py │ ├── __pycache__ │ │ ├── SparkApi.cpython-39.pyc │ │ ├── SparkApiSelf.cpython-39.pyc │ │ └── wenxin_llm.cpython-39.pyc │ ├── spark_api.py │ ├── wenxin_llm.py │ ├── 附1.LangChain自定义 LLM.ipynb │ ├── 附2.将大模型 API 封装成本地 API.ipynb │ └── 附3.LangChain 自定义 LLM embedding.ipynb ├── C3 大模型开发流程及架构 │ ├── 1. 大模型开发流程.md │ ├── 2. 项目流程简析.md │ └── 3. 项目架构简析.md ├── C4 数据库搭建 │ ├── .env │ ├── .ipynb_checkpoints │ │ ├── 1. 知识库文档处理-checkpoint.ipynb │ │ ├── 2. 向量数据库的介绍及使用-checkpoint.ipynb │ │ └── 3. 构建项目数据库-checkpoint.ipynb │ ├── 1. 知识库文档处理.ipynb │ ├── 2. 向量数据库的介绍及使用.ipynb │ ├── 3. 构建项目数据库.ipynb │ ├── __pycache__ │ │ └── zhipuai_embedding.cpython-310.pyc │ ├── create_db.py │ ├── zhipuai_embedding.py │ └── zhipuai_llm.py ├── C5 prompt设计 │ ├── .ipynb_checkpoints │ │ ├── 1.Prompt 设计的原则和技巧-checkpoint.ipynb │ │ ├── 2.基于问答助⼿的 Prompt 构建-checkpoint.ipynb │ │ └── 3.添加历史对话的记忆功能-checkpoint.ipynb │ ├── 1.Prompt 设计的原则和技巧.ipynb │ ├── 2.基于问答助⼿的 Prompt 构建.ipynb │ └── 3.添加历史对话的记忆功能.ipynb ├── C6 验证迭代 │ ├── .ipynb_checkpoints │ │ ├── 2. 解决Bad Case-checkpoint.ipynb │ │ └── 3. 大模型评估方法-checkpoint.ipynb │ ├── 1. 验证迭代的一般思路.md │ ├── 2. 解决Bad Case.ipynb │ └── 3. 大模型评估方法.ipynb ├── C7 前后端搭建 │ ├── .ipynb_checkpoints │ │ ├── 1. Gradio 的介绍与前端界面的搭建-checkpoint.ipynb │ │ └── 2. fast api 进行前后端分离-checkpoint.ipynb │ ├── 1. Gradio 的介绍与前端界面的搭建.ipynb │ └── 2. fast api 进行前后端分离.ipynb ├── knowledge_base │ ├── chroma │ │ ├── chroma-collections.parquet │ │ ├── chroma-embeddings.parquet │ │ └── index │ │ │ ├── id_to_uuid_0a21ea39-d07d-45a7-80e3-a7e68cca4cb8.pkl │ │ │ ├── id_to_uuid_1c24e063-9da4-403a-9153-f6b210c294d6.pkl │ │ │ ├── index_0a21ea39-d07d-45a7-80e3-a7e68cca4cb8.bin │ │ │ ├── index_1c24e063-9da4-403a-9153-f6b210c294d6.bin │ │ │ ├── index_metadata_0a21ea39-d07d-45a7-80e3-a7e68cca4cb8.pkl │ │ │ ├── index_metadata_1c24e063-9da4-403a-9153-f6b210c294d6.pkl │ │ │ ├── uuid_to_id_0a21ea39-d07d-45a7-80e3-a7e68cca4cb8.pkl │ │ │ └── uuid_to_id_1c24e063-9da4-403a-9153-f6b210c294d6.pkl │ ├── easy_rl │ │ ├── 强化学习入门指南.json │ │ ├── 强化学习入门指南.mp4 │ │ ├── 强化学习入门指南.srt │ │ ├── 强化学习入门指南.tsv │ │ ├── 强化学习入门指南.txt │ │ └── 强化学习入门指南.vtt │ ├── prompt_engineering │ │ ├── 1. 简介 Introduction.md │ │ ├── 2. 提示原则 Guidelines.md │ │ ├── 3. 迭代优化 Iterative.md │ │ ├── 4. 文本概括 Summarizing.md │ │ ├── 5. 推断 Inferring.md │ │ ├── 6. 文本转换 Transforming.md │ │ ├── 7. 文本扩展 Expanding.md │ │ ├── 8. 聊天机器人 Chatbot.md │ │ └── 9. 总结 Summary.md │ └── pumkin_book │ │ └── pumpkin_book.pdf └── readme.md └── project ├── database ├── __init__.py └── create_db.py ├── embedding ├── __init__.py ├── call_embedding.py └── zhipuai_embedding.py ├── llm ├── .env ├── __pycache__ │ ├── call_llm.cpython-310.pyc │ ├── self_llm.cpython-310.pyc │ ├── spark_llm.cpython-310.pyc │ ├── wenxin_llm.cpython-310.pyc │ └── wenxin_llm_.cpython-310.pyc ├── call_llm.py ├── self_llm.py ├── spark_llm.py ├── test.ipynb ├── wenxin_llm.py └── zhipuai_llm.py ├── qa_chain ├── Chat_QA_chain_self.py ├── QA_chain_self.py ├── get_vectordb.py └── model_to_llm.py ├── readme.md └── serve ├── api.py ├── run_api.sh └── run_gradio.py /README.md: -------------------------------------------------------------------------------- 1 | # 动手学大模型应用开发 2 | 3 | ## 项目简介 4 | 5 | 本项目是一个面向小白开发者的大模型应用开发教程,旨在结合个人知识库助手项目,通过一个课程完成大模型开发的重点入门,主要内容包括: 6 | 7 | 1. 大模型简介,何为大模型、大模型特点是什么、LangChain 是什么,针对小白开发者的简单介绍; 8 | 2. 如何调用大模型 API,本节介绍了国内外知名大模型产品 API 的多种调用方式,包括调用原生 API、封装为 LangChain LLM、封装为 Fastapi 等调用方式,同时将包括百度文心、讯飞星火、智谱AI等多种大模型 API 进行了统一形式封装; 9 | 3. 大模型开发流程及架构,大模型应用开发的基本流程、一般思想和本项目的架构分析; 10 | 4. 数据库搭建,不同类型知识库文档的加载、处理,向量数据库的搭建; 11 | 5. Prompt 设计,如何设计 Prompt 来让大模型完成特定任务,Prompt Engineering 的原则和技巧有哪些; 12 | 6. 验证迭代,大模型开发如何实现验证迭代,一般的评估方法有什么; 13 | 7. 前后端开发,如何使用 Gradio、FastAPI 等框架快速开发大模型 Demo,展示应用能力。 14 | 15 | 16 | **目录结构说明:** 17 | 18 | notebook:教程源码,可运行的 Notebook,更新频率最高,更新速度最快。 19 | docs:在线阅读版本,基于 notebook 源码订正。 20 | figures:图片文件。 21 | project:个人知识库助手项目代码。 22 | 23 | ## 立项理由 24 | 25 | LLM 正逐步成为信息世界的新革命力量,其通过强大的自然语言理解、自然语言生成能力,为开发者提供了新的、更强大的应用开发选择。随着国内外井喷式的 LLM API 服务开放,如何基于 LLM API 快速、便捷地开发具备更强能力、集成 LLM 的应用,开始成为开发者的一项重要技能。 26 | 27 | 目前,关于 LLM 的介绍以及零散的 LLM 开发技能课程已有不少,但质量参差不齐,且没有很好地整合,开发者需要搜索大量教程并阅读大量相关性不强、必要性较低的内容,才能初步掌握大模型开发的必备技能,学习效率低,学习门槛也较高。 28 | 29 | 本项目从实践出发,结合最常见、通用的个人知识库助手项目,深入浅出逐步拆解 LLM 开发的一般流程、步骤,旨在帮助没有算法基础的小白通过一个课程完成大模型开发的基础入门。同时,我们也对项目本身做了清晰、全面的逐层规划及封装,实现了不同 LLM API 到项目的统一整合,帮助开发者能够自由、统一调用不同 LLM,充分降低学习门槛。 30 | 31 | ## 项目受众 32 | 33 | 所有具备基础 Python 能力,想要掌握 LLM 应用开发技能的开发者。 34 | 35 | 本项目对学习者的人工智能基础、算法基础没有任何要求,仅需要掌握基本 Python 语法、掌握初级 Python 开发技能即可。 36 | 37 | 本项目对本地硬件基本没有要求,不需要 GPU 环境,个人电脑及服务器均可用于学习。 38 | 39 | ## 项目亮点 40 | 41 | 1. 充分面向实践,动手学习大模型开发。相较于其他从理论入手、与实践代差较大的类似教程,本教程基于具有通用性的个人知识库助手项目打造,将普适的大模型开发理念融合在项目实践中,帮助学习者通过动手搭建个人项目来掌握大模型开发技能。 42 | 43 | 2. 从零开始,全面又简短的大模型教程。本项目针对个人知识库助手项目,对相关大模型开发理论、概念和基本技能进行了项目主导的重构,删去不需要理解的底层原理和算法细节,涵盖所有大模型开发的核心技能。教程整体时长在数小时之内,但学习完本教程,可以掌握基础大模型开发的所有核心技能。 44 | 45 | 3. 兼具统一性与拓展性。本项目对 GPT、百度文心、讯飞星火、智谱GLM 等国内外主要 LLM API 进行了统一封装,支持一键调用不同的 LLM,帮助开发者将更多的精力放在学习应用与模型本身的优化上,而不需要花时间在繁琐的调用细节上;同时,本教程拟上线 [奇想星球 | AIGC共创社区平台](https://1aigc.cn/),支持学习者自定义项目为本教程增加拓展内容,具备充分的拓展性。 46 | 47 | ## 项目规划 48 | 49 | ### 时间规划 50 | 51 | 2023.10.01~2023.10.22 完成初稿 52 | 2023.10.23~10.31 内测 53 | 2023.11.01 开放公测 54 | 2023.11.15 正式上线 55 | 56 | ### 示例 57 | 58 | 正在开发仓库:https://github.com/logan-zou/Tutorial_for_developing_LLM_application 59 | 60 | 61 | ### 内容大纲及对应负责人 62 | 63 | **目录:** 64 | 65 | 第一章 大模型简介 @徐虎 66 | 67 | 1. 什么是大模型 68 | 2. 大模型的能力、特点 69 | 3. 常见大模型 70 | 4. 什么是 LangChain 71 | 72 | 第二章 调用大模型 API @邹雨衡 73 | 74 | 1. 基本概念 75 | 2. 调用 ChatGPT 76 | 3. 调用百度文心 77 | 4. 调用讯飞星火 78 | 5. 调用智谱GLM 79 | 6. 总结 80 | 81 | 第三章 大模型开发流程及架构 @邹雨衡 82 | 83 | 1. 大模型一般开发流程简介 84 | 2. 个人知识库助手项目流程简析 85 | 86 | 第四章 数据库搭建 @高立业 87 | 88 | 1. 知识库文档处理 89 | 2. 向量数据库简介及使用 90 | 3. 构建项目数据库 91 | 92 | 第五章 Prompt 设计 @徐虎 93 | 94 | 1. Prompt 设计的原则及技巧 95 | 2. 基于问答助手的 Prompt 构建 96 | 3. 添加历史对话功能 97 | 98 | 第六章 验证迭代 @邹雨衡 99 | 100 | 1. 验证迭代的一般思路 101 | 2. 解决 Bad Case 102 | 3. 大模型评估方法 103 | 104 | 第七章 前后端搭建 @高立业 105 | 106 | 1. Gradio 简介与页面搭建 107 | 2. FastAPI 进行前后端分离 108 | 109 | 第八章 总结及拓展 @邹雨衡 110 | 111 | 112 | ## 项目负责人 113 | 114 | 邹雨衡 115 | 116 | 微信:Logan12120421 117 | 118 | Github主页:https://github.com/logan-zou 119 | 120 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/.nojekyll -------------------------------------------------------------------------------- /docs/C1/1. 什么是⼤模型.md: -------------------------------------------------------------------------------- 1 | 2 | # 一. 什么是LLM(大语言模型)? 3 | 4 | ## 1. 发展历程 5 | 6 | 语言建模的研究始于`20世纪90年代`,最初采用了统计学习方法,通过前面的词汇来预测下一个词汇。然而,这种方法在理解复杂语言规则方面存在一定局限性。 7 | 8 | 随后,研究人员不断尝试改进,其中在`2003年`,深度学习先驱**Bengio**在他的经典论文《A Neural Probabilistic Language Model》中,首次将深度学习的思想融入到语言模型中,使用了更强大的**神经网络模型**,这相当于为计算机提供了更强大的"大脑"来理解语言。这种方法让模型可以更好地捕捉语言中的复杂关系,虽然这一步很重要,但仍有改进的空间。 9 | 10 | 大约在`2018年左右`,研究人员引入了**Transformer架构的神经网络模型**,通过大量文本数据训练这些模型,使它们能够通过阅读大量文本来深入理解语言规则和模式,就像让计算机阅读整个互联网一样。所以它对语言有了更深刻的理解。这种方法在很多任务上表现得非常好。 11 | 12 | 与此同时,研究人员发现,随着语言模型规模的扩大(增加模型大小或使用更多数据),模型展现出了一些惊人的能力,通常在各种任务中表现显著提升。这时我们进入了大语言模型(LLM)时代。 13 | 14 | ## 2. 大语言模型的概念 15 | 16 | **大语言模型(英文:Large Language Model,缩写LLM),也称大型语言模型,是一种人工智能模型,旨在理解和生成人类语言**。 17 | 18 | 通常,大语言模型 (LLM) 指包含**数百亿(或更多)参数的语言模型**,这些模型在大量的文本数据上进行训练,例如国外的有GPT-3 、GPT-4、PaLM 、Galactica 和 LLaMA 等,国内的有ChatGLM、文心一言、通义千问、讯飞星火等。 19 | 20 | 在这个阶段,计算机的“大脑”变得非常巨大,拥有数十亿甚至数千亿的参数。这就像是将计算机的大脑升级到了一个巨型超级计算机。这让计算机可以在各种任务上表现得非常出色,有时甚至比人类还要聪明。 21 | 22 | 为了探索性能的极限,许多研究人员开始训练越来越庞大的语言模型 ,例如拥有1750亿参数的 GPT-3 和5400亿参数的 PaLM 。尽管这些大型语言模型与小型语言模型(例如 BERT 的3.3亿参数和 GPT-2 的15亿参数)使用相似的架构和预训练任务,但它们展现出截然不同的能力,尤其在解决复杂任务时表现出了惊人的潜力,这被称为“**涌现能力**”。以 GPT-3 和 GPT-2 为例,GPT-3 可以通过学习上下文来解决少样本任务,而 GPT-2 在这方面表现较差。因此,研究界给这些庞大的语言模型起了个名字,称之为“大语言模型(LLM)”。而 LLM 的一个杰出应用就是 **ChatGPT** ,它是 GPT 系列 LLM 用于与人类对话式应用的大胆尝试,展现出了非常流畅和自然的表现。 23 | 24 | 25 | 26 | ### LLM的应用和影响 27 | 28 | LLM已经在许多领域产生了深远的影响。在**自然语言处理**领域,它可以帮助计算机更好地理解和生成文本,包括写文章、回答问题、翻译语言等。在**信息检索**领域,它可以改进搜索引擎,让我们更轻松地找到所需的信息。在**计算机视觉**领域,研究人员还在努力让计算机理解图像和文字,以改善多媒体交互。 29 | 30 | 最重要的是,LLM的出现让人们重新思考了**通用人工智能(AGI)**的可能性。AGI 是一种像人类一样思考和学习的人工智能。LLM 被认为是 AGI 的一种早期形式,这引发了对未来人工智能发展的许多思考和计划。 31 | 32 | 总之,LLM 是一种令人兴奋的技术,它让计算机更好地理解和使用语言,正在改变着我们与技术互动的方式,同时也引发了对未来人工智能的无限探索。希望这篇文章让你对LLM有了更清晰的认识! 33 | 34 | 35 | 36 | 【**参考内容**】: 37 | https://arxiv.org/abs/2303.18223 38 | -------------------------------------------------------------------------------- /docs/C1/2. ⼤模型的能⼒和特点.md: -------------------------------------------------------------------------------- 1 | 2 | # 大模型的能力和特点 3 | 4 | 5 | ## 1. 大模型的能力 6 | 7 | ### 1.1 涌现能力(emergent abilities) 8 | 9 | 区分大语言模型(LLM)与以前的预训练语言模型(PLM)最显著的特征之一是它们的`涌现能力`。涌现能力指的是一种令人惊讶的能力,它在小型模型中不明显,但在大型模型中显著出现。可以类比到物理学中的相变现象,涌现能力的显现就像是模型性能随着规模增大而迅速提升,超过了随机水平,也就是我们常说的量变引起了质变。 10 | 11 | 具体来说,涌现能力可以定义为与某些复杂任务相关的能力,但我们更关注的是它们具备的通用能力,也就是能够应用于解决各种任务的能力。接下来,让我们简要介绍三个典型的LLM涌现能力: 12 | 13 | 1. **上下文学习**:上下文学习能力是由 GPT-3 首次引入的。这种能力允许语言模型在提供自然语言指令或多个任务示例的情况下,通过理解上下文并生成相应输出的方式来执行任务,而无需额外的训练或参数更新。 14 | 15 | 2. **指令遵循**:通过使用自然语言描述的多任务数据进行微调,也就是所谓的指令微调,LLM 被证明在同样使用指令形式化描述的未见过的任务上表现良好。这意味着LLM能够根据任务指令执行任务,而无需事先见过具体示例,这展示了其强大的泛化能力。 16 | 17 | 3. **逐步推理**:小型语言模型通常难以解决涉及多个推理步骤的复杂任务,例如数学问题。然而,LLM通过采用"思维链"推理策略,可以利用包含中间推理步骤的提示机制来解决这些任务,从而得出最终答案。据推测,这种能力可能是通过对代码的训练获得的。 18 | 19 | 这些涌现能力让LLM在处理各种任务时表现出色,使它们成为了解决复杂问题和应用于多领域的强大工具。 20 | 21 | ### 1.2 作为基座模型支持多元应用的能力 22 | 23 | 在2021年,斯坦福大学等多所高校的研究人员提出了基座模型(foundation model)的概念,这更清晰地描述了之前学界所称的预训练模型的作用。这是一种全新的AI技术范式,借助于海量无标注数据的训练,获得可以适用于大量下游任务的大模型(单模态或者多模态)。这样,多个应用可以只依赖于一个或少数几个大模型进行统一建设 24 | 25 | 大语言模型是这个新模式的典型例子,使用统一的大模型可以极大地提高研发效率,相比于分散的模型开发方式,这是一项本质上的进步。大型模型不仅可以缩短每个具体应用的开发周期,减少所需人力投入,也可以基于大模型的推理、常识和写作能力,获得更好的应用效果。因此,大模型可以成为AI应用开发的大一统基座模型,这是一个一举多得、全新的范式,值得大力推广 26 | 27 | 28 | ### 1.3 支持对话作为统一入口的能力 29 | 30 | 让大语言模型真正火爆的契机,是基于对话聊天的ChatGPT。事实上,业界很早就发现了用户对于对话交互的特殊偏好,陆奇在微软期间2016年就推进“对话即平台(conversation as a platform)”的战略。此外,苹果Siri、亚马逊Echo等基于语音对话的产品也非常受欢迎,反映出互联网用户对于聊天和对话这种交互模式的偏好。虽然之前的聊天机器人存在各种问题,但大型语言模型的出现再次让聊天机器人这种交互模式可以重新想像。用户愈发期待像钢铁侠中“贾维斯”一样的人工智能,无所不能、无所不知。这引发我们对于智能体(Agent)类型应用前景的思考,Auto-GPT、微软Jarvis等项目已经出现并受到关注,相信未来会涌现出很多类似的以对话形态让助手完成各种具体工作的项目 31 | 32 | ## 2.大模型的特点 33 | 34 | 大语言模型(LLM,Large Language Models)具有多种显著特点,这些特点使它们在自然语言处理和其他领域中引起了广泛的兴趣和研究。以下是大语言模型的一些主要特点: 35 | 36 | 1. **巨大的规模:** LLM通常具有巨大的参数规模,可以达到数十亿甚至数千亿个参数。这使得它们能够捕捉更多的语言知识和复杂的语法结构。 37 | 38 | 2. **预训练和微调:** LLM采用了预训练和微调的学习方法。它们首先在大规模文本数据上进行预训练(无标签数据),学会了通用的语言表示和知识,然后通过微调(有标签数据)适应特定任务,从而在各种NLP任务中表现出色。 39 | 40 | 3. **上下文感知:** LLM在处理文本时具有强大的上下文感知能力,能够理解和生成依赖于前文的文本内容。这使得它们在对话、文章生成和情境理解方面表现出色。 41 | 42 | 4. **多语言支持:** LLM可以用于多种语言,不仅限于英语。它们的多语言能力使得跨文化和跨语言的应用变得更加容易。 43 | 44 | 5. **多模态支持:** 一些LLM已经扩展到支持多模态数据,包括文本、图像和声音。这意味着它们可以理解和生成不同媒体类型的内容,实现更多样化的应用。 45 | 46 | 6. **涌现能力:** LLM表现出令人惊讶的涌现能力,即在大规模模型中出现但在小型模型中不明显的性能提升。这使得它们能够处理更复杂的任务和问题。 47 | 48 | 7. **多领域应用:** LLM已经被广泛应用于文本生成、自动翻译、信息检索、摘要生成、聊天机器人、虚拟助手等多个领域,对人们的日常生活和工作产生了深远的影响。 49 | 50 | 8. **伦理和风险问题:** 尽管LLM具有出色的能力,但它们也引发了伦理和风险问题,包括生成有害内容、隐私问题、认知偏差等。因此,研究和应用LLM需要谨慎。 51 | 52 | 总之,大语言模型是一种具有强大语言处理能力的技术,已经在多个领域展示了潜力。它们为自然语言理解和生成任务提供了强大的工具,同时也引发了对其伦理和风险问题的关注。这些特点使LLM成为了当今计算机科学和人工智能领域的重要研究和应用方向。 53 | 54 | 55 | 参考内容: 56 | https://arxiv.org/abs/2303.18223 57 | https://xueqiu.com/1389978604/248392718 -------------------------------------------------------------------------------- /docs/C1/4. 什么是 LangChain.md: -------------------------------------------------------------------------------- 1 | # 什么是 LangChain 2 | 3 | ChatGPT 的巨大成功激发了越来越多的开发者兴趣,他们希望利用 OpenAI 提供的 API 或者私有化模型,来开发基于大型语言模型的应用程序。尽管大型语言模型的调用相对简单,但要创建完整的应用程序,仍然需要大量的定制开发工作,包括API集成、互动逻辑、数据存储等等。 4 | 5 | 为了解决这个问题,从2022年开始,许多机构和个人相继推出了多个开源项目,旨在**帮助开发者们快速构建基于大型语言模型的端到端应用程序或工作流程**。其中一个备受关注的项目就是LangChain框架。**LangChain框架是一个开源工具,充分利用了大型语言模型的强大能力,以便开发各种下游应用。它的目标是为各种大型语言模型应用提供通用接口,从而简化应用程序的开发流程**。具体来说,LangChain框架可以实现数据感知和环境互动,也就是说,它能够让语言模型与其他数据来源连接,并且允许语言模型与其所处的环境进行互动。 6 | 7 | 在接下来的部分中,我们将重点介绍 LangChain 的 6 种标准化、可扩展的接口并且可以外部集成的核心模块: 8 | 9 | - **模型输入/输出(Model I/O)**:与语言模型交互的接口 10 | - **数据连接(Data connection)**:与特定应用程序的数据进行交互的接口 11 | - **链(Chains)**:将组件组合实现端到端应用。 12 | - **记忆(Memory)**:用于链的多次运行之间持久化应用程序状态; 13 | - **代理(Agents)**:扩展模型的推理能力。用于复杂的应用的调用序列; 14 | - **回调(Callbacks)**:扩展模型的推理能力。用于复杂的应用的调用序列; 15 | 16 | ## 1. 模型输入/输出 17 | 18 | LangChain 中模型输入/输出模块是与各种大语言模型进行交互的基本组件,是大语言模型应用的核心元素。**模型 I/O 允许您管理 prompt(提示),通过通用接口调用语言模型以及从模型输出中提取信息**。该模块的基本流程如下图所示。 19 | 20 | ![](../figures/langchain_model_input_output.png) 21 | 22 | 主要包含以下部分:`Prompts`、`Language Models`以及 `Output Parsers`。**用户原始输入与模型和示例进行组合,然后输入给大语言模型,再根据大语言模型的返回结果进行输出或者结构化处理**。 23 | 24 | ## 2. 数据连接 25 | 26 | 大语言模型(Large Language Model, LLM), 比如 ChatGPT , 可以回答许多不同的问题。**但是大语言模型的知识来源于其训练数据集,并没有用户的信息(比如用户的个人数据,公司的自有数据),也没有最新发生时事的信息(在大模型数据训练后发表的文章或者新闻)**。因此大模型能给出的答案比较受限。如果能够让大模型在训练数据集的基础上,利用我们自有数据中的信息来回答我们的问题,那便能够得到更有用的答案。 27 | 28 | 为了支持上述应用的构建,LangChain 数据连接(Data connection)模块通过以下方式提供组件来**加载、转换、存储和查询数据**:`Document loaders`、`Document transformers`、`Text embedding models`、`Vector stores` 以及 `Retrievers`。数据连接模块部分的基本框架如下图所示。 29 | 30 | ![](../figures/data_collection.png) 31 | 32 | ## 3. 链(Chain) 33 | 34 | 虽然独立使用大型语言模型能够应对一些简单任务,但**对于更加复杂的需求,可能需要将多个大型语言模型进行链式组合,或与其他组件进行链式调用**。链允许将多个组件组合在一起,创建一个单一的、连贯的应用程序。例如,可以创建一个链,接受用户输入,使用 PromptTemplate 对其进行格式化,然后将格式化后的提示词传递给大语言模型。也可以通过将多个链组合在一起或将链与其他组件组合来构建更复杂的链。 35 | 36 | 大语言模型链(LLMChain)是一个简单但非常强大的链,也是后面我们将要介绍的许多链的基础。我们以它为例,进行介绍: 37 | 38 | ```python 39 | import warnings 40 | warnings.filterwarnings('ignore') 41 | 42 | from langchain.chat_models import ChatOpenAI 43 | from langchain.prompts import ChatPromptTemplate 44 | from langchain.chains import LLMChain 45 | 46 | # 这里我们将参数temperature设置为0.0,从而减少生成答案的随机性。 47 | # 如果你想要每次得到不一样的有新意的答案,可以尝试调整该参数。 48 | llm = ChatOpenAI(temperature=0.0) 49 | 50 | #初始化提示模版 51 | prompt = ChatPromptTemplate.from_template("描述制造{product}的一个公司的最佳名称是什么?") 52 | 53 | #将大语言模型(LLM)和提示(Prompt)组合成链 54 | chain = LLMChain(llm=llm, prompt=prompt) 55 | 56 | #运行大语言模型链 57 | product = "大号床单套装" 58 | chain.run(product) 59 | ``` 60 | 运行输出: 61 | >'"豪华床纺"' 62 | 63 | 除了上例中给出的 LLMChain,LangChain 中链还包含 RouterChain、SimpleSequentialChain、SequentialChain、TransformChain 等。 64 | 65 | - `RouterChain` 可以**根据输入数据的某些属性/特征值,选择调用不同的子链**(Subchain)。 66 | - `SimpleSequentialChain` 是最简单的序列链形式,其中每个步骤具有单一的输入/输出,**上一个步骤的输出是下一个步骤的输入**。 67 | - `SequentialChain` 是简单顺序链的更复杂形式,允许**多个输入/输出**。 68 | - `TransformChain` 可以引入**自定义转换函数,对输入进行处理后进行输出**。 69 | 70 | 以下是使用 SimpleSequentialChain 的代码示例: 71 | 72 | ```python 73 | from langchain.chains import SimpleSequentialChain 74 | llm = ChatOpenAI(temperature=0.9) 75 | 76 | #创建两个子链 77 | 78 | # 提示模板 1 :这个提示将接受产品并返回最佳名称来描述该公司 79 | first_prompt = ChatPromptTemplate.from_template( 80 | "描述制造{product}的一个公司的最好的名称是什么" 81 | ) 82 | chain_one = LLMChain(llm=llm, prompt=first_prompt) 83 | 84 | # 提示模板 2 :接受公司名称,然后输出该公司的长为20个单词的描述 85 | second_prompt = ChatPromptTemplate.from_template( 86 | "写一个20字的描述对于下面这个\ 87 | 公司:{company_name}的" 88 | ) 89 | chain_two = LLMChain(llm=llm, prompt=second_prompt) 90 | 91 | #构建简单顺序链 92 | #现在我们可以组合两个LLMChain,以便我们可以在一个步骤中创建公司名称和描述 93 | overall_simple_chain = SimpleSequentialChain(chains=[chain_one, chain_two], verbose=True) 94 | 95 | 96 | #运行简单顺序链 97 | product = "大号床单套装" 98 | overall_simple_chain.run(product) 99 | ``` 100 | 运行输出: 101 | 102 | 103 | > Entering new SimpleSequentialChain chain... 104 | 优床制造公司 105 | 优床制造公司是一家专注于生产高品质床具的公司。 106 | 107 | > Finished chain. 108 | 109 | 110 | '优床制造公司是一家专注于生产高品质床具的公司。' 111 | 112 | 113 | ## 4. 记忆(Meomory) 114 | 115 | 在 LangChain 中,记忆(Memory)指的是大语言模型(LLM)的短期记忆。为什么是短期记忆?那是因为LLM训练好之后 (获得了一些长期记忆),它的参数便不会因为用户的输入而发生改变。当用户与训练好的LLM进行对话时,LLM 会暂时记住用户的输入和它已经生成的输出,以便预测之后的输出,而模型输出完毕后,它便会“遗忘”之前用户的输入和它的输出。因此,之前的这些信息只能称作为 LLM 的短期记忆。 116 | 117 | 正如上面所说,在与语言模型交互时,你可能已经注意到一个关键问题:它们并不记忆你之前的交流内容,这在我们构建一些应用程序(如聊天机器人)的时候,带来了很大的挑战,使得对话似乎缺乏真正的连续性。因此,在本节中我们将介绍 LangChain 中的记忆模块,即如何将先前的对话嵌入到语言模型中的,使其具有连续对话的能力。 118 | 119 | ![](../figures/memory.png) 120 | 121 | ## 5. 代理(Agents) 122 | 123 | **大型语言模型(LLMs)非常强大,但它们缺乏“最笨”的计算机程序可以轻松处理的特定能力**。LLM 对逻辑推理、计算和检索外部信息的能力较弱,这与最简单的计算机程序形成对比。例如,语言模型无法准确回答简单的计算问题,还有当询问最近发生的事件时,其回答也可能过时或错误,因为无法主动获取最新信息。这是由于当前语言模型仅依赖预训练数据,与外界“断开”。要克服这一缺陷, LangChain 框架提出了 “代理”( Agent ) 的解决方案。**代理作为语言模型的外部模块,可提供计算、逻辑、检索等功能的支持,使语言模型获得异常强大的推理和获取信息的超能力**。 124 | 125 | ![](../figures/Agents.png) 126 | 127 | ## 6.回调(Callback) 128 | 129 | LangChain提供了一个**回调系统,允许您连接到LLM应用程序的各个阶段。这对于日志记录、监视、流式处理和其他任务非常有用**。 130 | 131 | **Callback 模块扮演着记录整个流程运行情况的角色,充当类似于日志的功能。在每个关键节点,它记录了相应的信息,以便跟踪整个应用的运行情况**。例如,在 Agent 模块中,它记录了调用 Tool 的次数以及每次调用的返回参数值。Callback 模块可以将收集到的信息直接输出到控制台,也可以输出到文件,甚至可以传输到第三方应用程序,就像一个独立的日志管理系统一样。通过这些日志,可以分析应用的运行情况,统计异常率,并识别运行中的瓶颈模块以进行优化。 132 | 133 | Callback 模块的具体实现包括两个主要功能,对应`CallbackHandler` 和 `CallbackManager` 的基类功能: 134 | 135 | - CallbackHandler 用于记录**每个应用场景(如 Agent、LLchain 或 Tool )的日志**,它是单个日志处理器,主要记录单个场景的完整日志信息。 136 | - 而CallbackManager则**封装和管理所有的 CallbackHandler** ,包括单个场景的处理器,也包括整个运行时链路的处理器。" 137 | 138 | #### 在哪里传入回调 ? 139 | 140 | 该参数可用于整个 API 中的大多数对象(链、模型、工具、代理等),位于两个不同位置:: 141 | 142 | `构造函数回调`:在构造函数中定义,例如 LLMChain(callbacks=[handler], tags=['a-tag']) ,它将被用于对该对象的所有调用,并且将只针对该对象,例如,如果你向 LLMChain 构造函数传递一个 handler ,它将不会被附属于该链的 Model 使用。 143 | 144 | `请求回调`:定义在用于发出请求的 call() / run() / apply() 方法中,例如 chain.call(inputs, callbacks=[handler]) ,它将仅用于该特定请求,以及它包含的所有子请求(例如,对 LLMChain 的调用会触发对 Model 的调用,该 Model 使用 call() 方法中传递的相同 handler)。 145 | 146 | verbose 参数在整个 API 的大多数对象(链、模型、工具、代理等)上都可以作为构造参数使用,例如 LLMChain(verbose=True),它相当于将 ConsoleCallbackHandler 传递给该对象和所有子对象的 callbacks 参数。这对调试很有用,因为它将把所有事件记录到控制台。 147 | 148 | #### 你想在什么时候使用这些东西呢? 149 | 150 | **构造函数回调对诸如日志、监控等用例最有用,这些用例不是针对单个请求,而是针对整个链**。例如,如果你想记录所有向 LLMChain 发出的请求,你可以向构造函数传递一个处理程序。 151 | 152 | **请求回调对流媒体等用例最有用**,你想把单个请求的输出流向特定的 websocket 连接,或其他类似用例。例如,如果你想把单个请求的输出流到一个 websocket ,你会把一个处理程序传递给 call() 方法. 153 | 154 | 155 | -------------------------------------------------------------------------------- /docs/C2/1. 基本概念.md: -------------------------------------------------------------------------------- 1 | 2 | # 一、基本概念 3 | 4 | ## 1. Prompt 5 | 6 | Prompt 最初是 NLP(自然语言处理)研究者为下游任务设计出来的一种任务专属的输入模板,类似于一种任务(例如:分类,聚类等)会对应一种 Prompt。在 ChatGPT 推出并获得大量应用之后,Prompt 开始被推广为给大模型的所有输入。即,我们每一次访问大模型的输入为一个 Prompt,而大模型给我们的返回结果则被称为 Completion。 7 | 8 | 例如,在下面示例中,我们给 ChatGPT 的提问 “NLP 中的 Prompt 指什么”是我们的提问,其实也就是我们此次的 Prompt;而 ChatGPT 的返回结果就是此次的 Completion。也就是对于 ChatGPT 模型,该 Prompt 对应的 Completion 是下图的展示。 9 | 10 | ![ChatGPT Prompt Examples](../figures/prompt_example.png) 11 | 12 | 后续我们都将会使用 Prompt 替代给 LLM 的输入,使用 Completion 替代 LLM 的输出。同时,我们会结合具体案例,介绍如何设计 Prompt 能够充分发挥 LLM 的能力。 13 | 14 | ## 2. Temprature 15 | 16 | LLM 生成是具有随机性的,在模型的顶层通过选取不同预测概率的预测结果来生成最后的结果。我们一般可以通过控制 Temprature 参数来控制 LLM 生成结果的随机性与创造性。 17 | 18 | Temprature 一般取值在 0~1 之间,当取值较低接近0时,预测的随机性会较低,产生更保守、可预测的文本,不太可能生成意想不到或不寻常的词。当取值较高接近1时,预测的随机性会较高,所有词被选择的可能性更大,会产生更有创意、多样化的文本,更有可能生成不寻常或意想不到的词。 19 | 20 | 例如,当我们使用 ChatGPT 要求其为我们想一个关于跨语言模型的硕士毕业论文选题,当我们将 temprature 设置为0时,模型回复为: 21 | 22 | 题目:基于跨语言模型的机器翻译性能优化研究 23 | 24 | 摘要:随着全球化的发展,跨语言交流的需求日益增长。机器翻译作为一种自动化翻译技术,为跨语言交流提供了便利。然而,由于语言之间的差异性,机器翻译系统在不同语言对之间的性能存在差异。本论文旨在通过研究跨语言模型,探索如何优化机器翻译的性能,提高翻译质量和准确性。 25 | 26 | 关键词:跨语言模型,机器翻译,性能优化,翻译质量,准确性 27 | 28 | 1. 引言 29 | 1.1 研究背景和意义 30 | 1.2 国内外研究现状 31 | 1.3 研究目标和内容 32 | 33 | 2. 跨语言模型的原理和方法 34 | 2.1 传统机器翻译方法 35 | 2.2 跨语言模型的基本原理 36 | 2.3 跨语言模型的常用方法和技术 37 | 38 | 3. 跨语言模型在机器翻译中的应用 39 | 3.1 跨语言模型在机器翻译中的优势和挑战 40 | 3.2 跨语言模型在不同语言对上的性能表现比较 41 | 3.3 跨语言模型在特定领域机器翻译中的应用案例分析 42 | 43 | 4. 跨语言模型的性能优化方法 44 | 4.1 数据预处理和特征选择 45 | 4.2 模型参数调优和训练策略 46 | 4.3 跨语言模型与其他技术的结合应用 47 | 48 | 5. 实验设计与结果分析 49 | 5.1 实验设计和数据集介绍 50 | 5.2 实验结果分析和对比 51 | 5.3 实验结果的可行性和可靠性验证 52 | 53 | 6. 结论与展望 54 | 6.1 研究工作总结 55 | 6.2 存在的问题和不足 56 | 6.3 进一步研究方向和展望 57 | 58 | 参考文献 59 | 60 | 注:以上仅为一个选题示例,具体选题应根据个人兴趣和研究背景进行调整和修改。 61 | 62 | 当我们将 Temprature 设置为1时,模型回复为: 63 | 64 | 以下是关于跨语言模型的几个硕士毕业论文选题建议: 65 | 66 | 1. 跨语言文本分类模型的比较和优化——通过比较不同跨语言模型的性能,分析其在不同语言之间的适应性和准确性,并尝试优化现有模型,提高跨语言文本分类的效果。 67 | 68 | 2. 基于跨语言模型的机器翻译性能分析——通过比较不同跨语言模型在机器翻译任务中的表现,研究不同语言之间的短板和优势,并探讨如何针对性地改进跨语言机器翻译的性能。 69 | 70 | 3. 跨语言情感分析模型的构建与应用——使用跨语言模型构建情感分析模型,通过比较模型在不同语言上的准确性和一致性,分析不同语言中情感表达的差异,并探索在多语言场景下的情感分析应用。 71 | 72 | 4. 多任务学习下的跨语言模型训练——探索多任务学习下跨语言模型的训练方法和效果,通过同时训练多个任务来提高跨语言模型的泛化能力和性能,并验证多任务学习对跨语言模型的影响。 73 | 74 | 5. 跨语言问答系统的构建与评估——构建跨语言问答系统,通过跨语言模型实现问题的自动解析和答案的生成,并评估系统在多语言环境下的效果和可用性。 75 | 76 | 6. 基于预训练的跨语言模型的应用于语音识别——将预训练的跨语言模型应用于语音识别任务中,研究其对语音识别准确性和多语种适应性的影响,并比较不同模型对多语种语音数据的处理能力。 77 | 78 | 选择适合自己兴趣和研究方向的选题,并与导师进行深入讨论和确认。 79 | 80 | 对于不同的问题与应用场景,我们可能需要设置不同的 Temprature。例如,在本教程搭建的个人知识库助手项目中,我们一般将 Temprature 设置为0,从而保证助手对知识库内容的稳定使用,规避错误内容、模型幻觉;在产品智能客服、科研论文写作等场景中,我们同样更需要稳定性而不是创造性;但在个性化 AI、创意营销文案生成等场景中,我们就更需要创意性,从而更倾向于将 Temprature 设置为较高的值。 81 | 82 | ## 3. System Prompt 83 | 84 | System Prompt 是随着 ChatGPT API 开放并逐步得到大量使用的一个新兴概念,事实上,它并不在大模型本身训练中得到体现,而是大模型服务方为提升用户体验所设置的一种策略。 85 | 86 | 具体来说,在使用 ChatGPT API 时,你可以设置两种 Prompt:一种是 System Prompt,该种 Prompt 内容会在整个会话过程中持久地影响模型的回复,且相比于普通 Prompt 具有更高的重要性;另一种是 User Prompt,这更偏向于咱们平时的 Prompt,即需要模型做出回复的输入。 87 | 88 | 我们一般设置 System Prompt 来对模型进行一些初始化设定,例如,我们可以在 System Prompt 中给模型设定我们希望它具备的人设如一个个人知识库助手等。System Prompt 一般在一个会话中仅有一个。在通过 System Prompt 设定好模型的人设或是初始设置后,我们可以通过 User Prompt 给出模型需要遵循的指令。例如,当我们需要一个幽默风趣的个人知识库助手,并向这个助手提问我今天有什么事时,可以如下地构造 Prompt: 89 | 90 | ```json 91 | { 92 | "system prompt":"你是一个幽默风趣的个人知识库助手,可以根据给定的知识库内容回答用户的提问,注意,你的回答风格应是幽默风趣的", 93 | "user prompt":"我今天有什么事务?" 94 | } 95 | ``` 96 | 97 | 通过如上 Prompt 的构造,我们可以让模型以幽默风趣的风格回答用户提出的问题。注意,如果有多个用户问题,那么我们只需要添加对应数量的 User Prompt 即可,System Prompt 仅需构造一个。 -------------------------------------------------------------------------------- /docs/C2/3. 调用百度文心.md: -------------------------------------------------------------------------------- 1 | # 三、调用百度文心 2 | 3 | ## 1. 文心一言 4 | 5 | 文心一言,由百度于2023年3月27日推出的中文大模型,是目前国内大语言模型的代表产品。受限于中文语料质量差异及国内计算资源、计算技术瓶颈,文心一言在整体性能上距离 ChatGPT 仍有一定差异,但在中文语境下已展现出了较为优越的性能。文心一言所考虑的落地场景包括多模态生成、文学创作等多种商业场景,其目标是在中文语境下赶超 ChatGPT。当然,要真正战胜 ChatGPT,百度还有很长的路要走;但在生成式 AI 监管较为严格的国内,作为第一批被允许向公众开放的生成式 AI 应用,文心一言相对无法被公开使用的 ChatGPT 还是具备一定商业上的优势。 6 | 7 | 百度同样提供了文心一言的 API 接口,其于推出大模型的同时推出了文心千帆企业级大语言模型服务平台,包括了百度整套大语言模型开发工作链。对于不具备大模型实际落地能力的中小企业或传统企业,考虑文心千帆是一个可行的选择。当然,本教程仅包括通过文心千帆平台调用文心一言 API,对于其他企业级服务不予讨论。不过,值得额外注意的事,国内大模型厂商对于 API 的服务相对疏忽,文心一言 API 的实际性能与其 Web 应用所展现出来的能力还存在一定差异。 8 | 9 | 在本章节中,我们同样将讲述两种通过 Python 代码调用百度文心一言大模型的方法:直接调用百度文心原生接口;使用 LangChain 调用百度文心接口。 10 | 11 | ## 2. 获取文心一言调用秘钥 12 | 13 | 同样,要调用文心一言 API,需要先获取文心一言调用秘钥,在代码中需要配置自己的秘钥才能实现对模型的调用。 14 | 15 | 百度文心有两层秘钥认证,第一层是拥有调用权限的账户可以从账户中获取的 API_Key 和 Secret_Key,每一个账户可以创建若干个应用,每个应用会对应一个 API_Key 和 Secret_Key。 16 | 17 | 在获取完成 API_Key 和 Secret_Key 后,还需要基于这两个 Key 去获取 access_token 值。access_token 是第二层认证,基于 access_token 即可调用百度文心大模型,而 access_token 是可以控制基于时间或流量过期的。通过上述两层秘钥认证,可以进一步提高企业服务的安全性。 18 | 19 | 当然,在本教程中,我们并不需要将两层秘钥分离。我们将在该部分简述如何获取 API_Key、Secret_Key 以及如何基于 Key 获取 access_token 值,后续我们将直接通过 access_token 来调用文心大模型。 20 | 21 | ![](../figures/baidu_qianfan_1.png) 22 | 23 | 首先我们需要进入[文心千帆服务平台](https://console.bce.baidu.com/qianfan/overview),点击上述应用接入按钮,创建一个调用文心大模型的应用。注意,你需要首先有一个经过实名认证的百度账号。 24 | 25 | ![](../figures/baidu_qianfan_2.png) 26 | 27 | 接着点击“去创建”按钮,进入应用创建界面: 28 | 29 | ![](../figures/baidu_qianfan_3.png) 30 | 31 | 简单输入基本信息,选择默认配置,创建应用即可。 32 | 33 | ![](../figures/baidu_qianfan_4.png) 34 | 35 | 创建完成后,我们可以在控制台看到创建的应用的 `AppID`、`API Key`、`Secret Key`。使用这里的 `API Key` 和 `Secret Key` 即可进行 access_token 的获取。 36 | 37 | access_token 需要通过代码 post 访问指定网址得到: 38 | 39 | 40 | ```python 41 | import requests 42 | import json 43 | 44 | def get_access_token(): 45 | """ 46 | 使用 API Key,Secret Key 获取access_token,替换下列示例中的应用API Key、应用Secret Key 47 | """ 48 | # 指定网址 49 | url = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={api_key}&client_secret={secret_key}" 50 | # 设置 POST 访问 51 | payload = json.dumps("") 52 | headers = { 53 | 'Content-Type': 'application/json', 54 | 'Accept': 'application/json' 55 | } 56 | # 通过 POST 访问获取账户对应的 access_token 57 | response = requests.request("POST", url, headers=headers, data=payload) 58 | return response.json().get("access_token") 59 | ``` 60 | 61 | 通过上述代码,即可获取到账户对应的 access_token,后续使用 access_token 即可调用百度文心大模型。 62 | 63 | ## 3. 调用百度文心原生接口 64 | 65 | 在完成 access_token 的获取后,可以同样通过 POST 访问来调用百度文心原生接口: 66 | 67 | 68 | ```python 69 | def get_wenxin(prompt): 70 | # 调用接口 71 | url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token={access_token}" 72 | # 配置 POST 参数 73 | payload = json.dumps({ 74 | "messages": [ 75 | { 76 | "role": "user",# user prompt 77 | "content": "{}".format(prompt)# 输入的 prompt 78 | } 79 | ] 80 | }) 81 | headers = { 82 | 'Content-Type': 'application/json' 83 | } 84 | # 发起请求 85 | response = requests.request("POST", url, headers=headers, data=payload) 86 | # 返回的是一个 Json 字符串 87 | js = json.loads(response.text) 88 | print(js["result"]) 89 | 90 | ``` 91 | 92 | 百度文心的 Prompt 格式同 OpenAI 的 Prompt 格式相似,但文心并没有提供 system prompt 级别的配置,仅支持 user、assistant 两个级别,可以在传入参数的 message 中配置。我们此处仅使用 user prompt 来实现调用。 93 | 94 | 同时,百度文心返回的数据也是一个 Json 字符串,我们可以调用其中的 result 属性来获取返回数据。 95 | 96 | 97 | ```python 98 | get_wenxin("你好") 99 | ``` 100 | 101 | 您好!我是百度研发的知识增强大语言模型,中文名是文心一言,英文名是ERNIE Bot。我能够与人对话互动,回答问题,协助创作,高效便捷地帮助人们获取信息、知识和灵感。 102 | 103 | 104 | 百度千帆提供了多种模型接口供调用,此处我们主要使用 `ERNIE-Bot-turbo` 模型的 chat 接口,也就是常说的百度文心大模型。此处简要介绍文心大模型接口的常用参数: 105 | 106 | · messages,即调用的 Prompt。文心的 messages 配置与 ChatGPT 有一定区别,其不支持 max_token 参数,由模型自行控制最大 token 数,content 总长度不能超过11200字符,否则模型就会自行对前文依次遗忘。文心的 messages 有以下几点要求:① 一个成员为单轮对话,多个成员为多轮对话;② 最后一个 message 为当前对话,前面的 message 为历史对话;③ 必须为奇数个对象,message 中的 role 必须依次是 user、assistant。 107 | 108 | · stream,是否使用流式传输。 109 | 110 | · temperature:温度系数,默认0.95,文心的 temperature 参数要求范围在0~1之间,不能设置为0。 111 | 112 | 我们同样封装一个调用百度文心大模型的函数供之后使用: 113 | 114 | 115 | ```python 116 | # 一个封装 Wenxin 接口的函数,参数为 Prompt,返回对应结果 117 | def get_completion_weixin(prompt, temperature = 0.1, access_token = ""): 118 | ''' 119 | prompt: 对应的提示词 120 | temperature:温度系数 121 | access_token:已获取到的秘钥 122 | ''' 123 | url = f"https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token={access_token}" 124 | # 配置 POST 参数 125 | payload = json.dumps({ 126 | "messages": [ 127 | { 128 | "role": "user",# user prompt 129 | "content": "{}".format(prompt)# 输入的 prompt 130 | } 131 | ], 132 | "temperature" : temperature 133 | }) 134 | headers = { 135 | 'Content-Type': 'application/json' 136 | } 137 | # 发起请求 138 | response = requests.request("POST", url, headers=headers, data=payload) 139 | # 返回的是一个 Json 字符串 140 | js = json.loads(response.text) 141 | # print(js) 142 | return js["result"] 143 | 144 | ``` 145 | 146 | 147 | ```python 148 | prompt = "你好" 149 | access_token = "xxx" 150 | get_completion_weixin(prompt, access_token=access_token) 151 | ``` 152 | 153 | 154 | 155 | 156 | '您好!我是百度研发的知识增强大语言模型,中文名是文心一言,英文名是ERNIE Bot。我能够与人对话互动,回答问题,协助创作,高效便捷地帮助人们获取信息、知识和灵感。' 157 | 158 | 159 | 160 | ## 4. 使用 LangChain 调用百度文心 161 | 162 | 我们同样可以通过 LangChain 框架来调用百度文心大模型,以将文心模型接入到我们的应用框架中。 163 | 164 | 但是,原生的 LangChain 是不支持文心调用的,我们需要自定义一个支持文心模型调用的 LLM。在《附一 LangChain自定义LLM》中,我们简述了如何自定义 LLM。 165 | 166 | 此处,我们可以直接调用已自定义好的 Wenxin_LLM。 167 | 168 | 169 | ```python 170 | from wenxin_llm import Wenxin_LLM 171 | ``` 172 | 173 | 我们希望像调用 ChatGPT 那样直接将秘钥存储在 .env 文件中,并将其加载到环境变量,从而隐藏秘钥的具体细节,保证安全性。因此,我们需要在 .env 文件中配置 `wenxin_api_key` 和 `wenxin_secret_key`,并使用以下代码加载: 174 | 175 | 176 | ```python 177 | from dotenv import find_dotenv, load_dotenv 178 | import os 179 | 180 | # 读取本地/项目的环境变量。 181 | 182 | # find_dotenv()寻找并定位.env文件的路径 183 | # load_dotenv()读取该.env文件,并将其中的环境变量加载到当前的运行环境中 184 | # 如果你设置的是全局的环境变量,这行代码则没有任何作用。 185 | _ = load_dotenv(find_dotenv()) 186 | 187 | # 获取环境变量 OPENAI_API_KEY 188 | wenxin_api_key = os.environ["wenxin_api_key"] 189 | wenxin_secret_key = os.environ["wenxin_secret_key"] 190 | ``` 191 | 192 | 193 | ```python 194 | llm = Wenxin_LLM(api_key=wenxin_api_key, secret_key=wenxin_secret_key) 195 | ``` 196 | 197 | 198 | ```python 199 | llm("你好") 200 | ``` 201 | 202 | 203 | 204 | 205 | '您好!我是百度研发的知识增强大语言模型,中文名是文心一言,英文名是ERNIE Bot。我能够与人对话互动,回答问题,协助创作,高效便捷地帮助人们获取信息、知识和灵感。' 206 | 207 | 208 | 209 | 从而我们可以将文心大模型加入到 LangChain 架构中,实现在应用中对文心大模型的调用。 210 | -------------------------------------------------------------------------------- /docs/C2/4. 调用讯飞星火.md: -------------------------------------------------------------------------------- 1 | # 四、调用讯飞星火 2 | 3 | ## 1. 讯飞星火认知大模型 4 | 5 | 讯飞星火认知大模型,由科大讯飞于2023年5月推出的中文大模型,也是国内大模型的代表产品之一。同样,受限于中文语境与算力资源,星火在使用体验上与 ChatGPT 还存在差异,但是,作为与文心不分伯仲的国内中文大模型,仍然值得期待与尝试。相较于存在显著资源、技术优势的百度,科大讯飞想要杀出重围,成为国内大模型的佼佼者,需要充分利用相对优势,至少目前来看,星火并未掉队。同时,不知道是否因为讯飞 API 还没有全面开放,讯飞 API 的测试使用效果比文心更好,值得期待。 6 | 7 | 目前,讯飞星火大模型 API 已进入 $\beta$ 测试阶段,每一个讯飞账户都可以申请若干 token 的试用。但是,相对于文心与 GPT 几乎完全一致的 API 调用方式,星火 API 需要使用 WebSocket 来进行调用,对企业友好,但对初学者、新手开发者来说调用难度较大。本章节将指导开发者如何将星火 API 封装为可直接通过 request 调用的 API 接口从而和其他大模型保持一致,也将介绍如何将其封装成个性化 LLM 嵌入 LangChain 使用。 8 | 9 | ## 2. 申请调用权限 10 | 11 | 相对于文心复杂的申请流程,讯飞的权限申请显得简单易操作得多: 12 | 13 | 首先进入到[星火认知大模型首页](https://xinghuo.xfyun.cn/sparkapi),点击“免费试用”: 14 | 15 | ![](../figures/spark_1.png) 16 | 17 | 如果是没有领取过免费试用包的用户,可以领取到 100000 token 的试用量;如果已领取过,就会自动跳转到下方购买产品的页面。完成领取后,点击上文中的“服务管理”即可进入控制台: 18 | 19 | ![](../figures/spark_2.png) 20 | 21 | 在该界面,我们就可以看到我们获取到的 `APPID`、`APISecret` 和 `APIKey` 了。 22 | 23 | ## 3. 调用原生星火 API 24 | 25 | 星火 API 需要通过 WebSocket 进行连接,相对来说配置较为复杂,讯飞给出了配置示例 SparkApi.py 和连接示例 test.py,此处我们仅讲解 test.py 里的调用逻辑,配置示例代码直接使用即可。 26 | 27 | 注意,需要在环境中安装配置示例中的所需第三方库。 28 | 29 | 首先我们需要配置秘钥信息: 30 | 31 | 32 | ```python 33 | import SparkApi 34 | #以下密钥信息从控制台获取 35 | appid = "" #填写控制台中获取的 APPID 信息 36 | api_secret = "" #填写控制台中获取的 APISecret 信息 37 | api_key ="" #填写控制台中获取的 APIKey 信息 38 | 39 | #用于配置大模型版本,默认“general/generalv2” 40 | domain = "general" # v1.5版本 41 | # domain = "generalv2" # v2.0版本 42 | 43 | #云端环境的服务地址 44 | Spark_url = "ws://spark-api.xf-yun.com/v1.1/chat" # v1.5环境的地址 45 | # Spark_url = "ws://spark-api.xf-yun.com/v2.1/chat" # v2.0环境的地址 46 | ``` 47 | 48 | 星火的调用传参和文心类似,也需要传入一个列表,列表中包括 role 和 prompt,我们首先定义一个从用户输入 prompt 生成传入参数的函数: 49 | 50 | 51 | ```python 52 | def getText(role, content, text = []): 53 | # role 是指定角色,content 是 prompt 内容 54 | jsoncon = {} 55 | jsoncon["role"] = role 56 | jsoncon["content"] = content 57 | text.append(jsoncon) 58 | return text 59 | ``` 60 | 61 | 接着,我们将一个用户输入 prompt 封装为这样一个传入参数列表: 62 | 63 | 64 | ```python 65 | question = getText("user", "你好") 66 | question 67 | ``` 68 | 69 | 70 | 71 | 72 | [{'role': 'user', 'content': '你好'}] 73 | 74 | 75 | 76 | 然后再调用 SparkApi.py 中封装的 main 函数即可: 77 | 78 | 79 | ```python 80 | response = SparkApi.main(appid,api_key,api_secret,Spark_url,domain,question) 81 | response 82 | ``` 83 | 84 | 你好!很高兴为您提供帮助。请问有什么问题我可以帮您解答吗? 85 | 86 | ## 4. 统一 API 调用方式 87 | 88 | 由于星火使用了 WebSocket 连接,不能直接使用 request 来进行访问,同其他大模型 API 访问方式具有一定差异。我们可以通过 FastAPI 将星火 API 封装成本地 API,从而实现统一的模型调用方式。我们在《附2 将大模型 API 封装成本地 API》中讲解了如何实现本地 API 的封装,此处仅讲解如何启动并调用本地 API。 89 | 90 | 在我们完成本地 API 的封装后(spark_api.py),我们可以通过 uvicorn 命令启动: 91 | 92 | 93 | ```python 94 | ! uvicorn spark_api:app 95 | ``` 96 | 97 | 启动之后,默认会在本地 8000 端口开启 API 服务。 98 | 99 | 启动 API 之后,我们可以向本地 8000 端口发起 Request 请求来访问 API: 100 | 101 | 102 | ```python 103 | import requests 104 | 105 | api_url = "http://127.0.0.1:8000/spark" 106 | headers = {"Content-Type": "application/json"} 107 | data = { 108 | "prompt" : "你好", 109 | "temperature" : 0.2, 110 | "max_tokens" : 3096} 111 | 112 | response = requests.post(api_url, headers=headers, json=data) 113 | response.text 114 | ``` 115 | 116 | 117 | 118 | 119 | '"你好!有什么我可以帮助你的吗?"' 120 | 121 | 122 | 123 | 同样,我们可以用一个函数来封装 requests 访问的细节: 124 | 125 | 126 | ```python 127 | def get_completion_spark(prompt, temperature = 0.1, max_tokens = 4096): 128 | 129 | api_url = "http://127.0.0.1:8000/spark" 130 | headers = {"Content-Type": "application/json"} 131 | data = { 132 | "prompt" : prompt, 133 | "temperature" : temperature, 134 | "max_tokens" : max_tokens} 135 | 136 | response = requests.post(api_url, headers=headers, json=data) 137 | return response.text 138 | ``` 139 | 140 | 141 | ```python 142 | get_completion_spark("你好") 143 | ``` 144 | 145 | 146 | 147 | 148 | '"你好!有什么我可以帮助你的吗?"' 149 | 150 | 151 | 152 | 星火 API 同样可以制作成自定义 LLM 并接入 LangChain,制作方式同文心大模型,此处就不再赘述,如有需要可自行尝试。 153 | -------------------------------------------------------------------------------- /docs/C2/5. 调用智谱 AI(ChatGLM).md: -------------------------------------------------------------------------------- 1 | # 五、调用智谱 AI 2 | 3 | 4 | ## 1. ChatGLM 大模型 5 | 6 | 智谱 AI 是由清华大学计算机系技术成果转化而来的公司,致力于打造新一代认知智能通用模型。公司合作研发了双语千亿级超大规模预训练模型 GLM-130B,并构建了高精度通用知识图谱,形成数据与知识双轮驱动的认知引擎,基于此模型打造了 ChatGLM(chatglm.cn)。 7 | 8 | ChatGLM 系列模型,包括 ChatGLM-130B 和 ChatGLM-6B 模型,支持相对复杂的自然语言指令,并且能够解决困难的推理类问题。其中,ChatGLM-6B 模型吸引了全球超过 160 万人下载安装,该模型在 Hugging Face (HF) 全球大模型下载榜中连续 12 天位居第一名,在国内外的开源社区中产生了较大的影响。 9 | 10 | 11 | 12 | 本章节将指导开发者如何将智谱 AI API 的使用方式,也将介绍如何将其封装成个性化 LLM 嵌入 LangChain 使用。 13 | 14 | ## 2. 申请调用权限 15 | 16 | 首先进入到[智谱AI开放平台](https://open.bigmodel.cn/overview),点击“开始使用”或者“开发者工具台”进行注册: 17 | 18 | ![](../figures/zhipuai_home.png) 19 | 20 | 如果是没有领取过免费试用包的用户,可以领取到 18 元的 token 的试用量;如下图右边绿色框所示。智谱 AI 提供了三种不同的模型 API,ChatGLM-Pro, ChatGLM-Std, ChatGLM-Lite 三种不同的模型分别适用于不同的场景,可以点击蓝色框中的立即体验直接体验。对于需要使用 API key 来搭建应用的话,需要点击右边红框中的查看 API key,就会进入到我们个人的 API 管理列表中。 21 | 22 | ![智谱 AI 控制台](../figures/zhipuai_overview.png) 23 | 24 | ![智谱 AI token 消费](../figures/zhipuai_pay.png) 25 | 26 | 在该界面,我们就可以看到我们获取到的 API 所对应的应用名字和 `API key` 了。 27 | 28 | 29 | 我们可以点击 `添加新的 API key` 并输入对应的名字即可生成新的 API key。 30 | 31 | ![智谱 AI api 管理](../figures/zhipuai_api.png) 32 | 33 | ## 3. 调用智谱 AI API 34 | 35 | 智谱 AI 提供了 SDK 和原生 HTTP 来实现模型 API 的调用,建议使用 SDK 进行调用以获得更好的编程体验。 36 | 37 | 注意,需要在环境中安装配置示例中的所需第三方库。 38 | 39 | 首先我们需要配置秘钥信息: 40 | 41 | 42 | ```python 43 | !pip install zhipuai 44 | ``` 45 | 46 | 47 | ```python 48 | import zhipuai 49 | zhipuai.api_key = "your api key" #填写控制台中获取的 APIKey 信息 50 | 51 | model = "chatglm_std" #用于配置大模型版本 52 | ``` 53 | 54 | 智谱的调用传参和其他类似,也需要传入一个列表,列表中包括 role 和 prompt,我们首先定义一个从用户输入 prompt 生成传入参数的函数: 55 | 56 | 57 | ```python 58 | def getText(role, content, text = []): 59 | # role 是指定角色,content 是 prompt 内容 60 | jsoncon = {} 61 | jsoncon["role"] = role 62 | jsoncon["content"] = content 63 | text.append(jsoncon) 64 | return text 65 | ``` 66 | 67 | 接着,我们将一个用户输入 prompt 封装为这样一个传入参数列表: 68 | 69 | 70 | ```python 71 | question = getText("user", "你好") 72 | question 73 | ``` 74 | 75 | 76 | 77 | 78 | [{'role': 'user', 'content': '你好'}] 79 | 80 | 81 | 82 | 然后再调用 zhipuai SDK 中封装的 invoke 函数即可: 83 | 84 | 85 | ```python 86 | # 请求模型 87 | response = zhipuai.model_api.invoke( 88 | model=model, 89 | prompt=question 90 | ) 91 | print(response) 92 | ``` 93 | 94 | {'code': 200, 'msg': '操作成功', 'data': {'request_id': '8023318729410566227', 'task_id': '8023318729410566227', 'task_status': 'SUCCESS', 'choices': [{'role': 'assistant', 'content': '" 你好👋!我是人工智能助手 智谱清言,可以叫我小智🤖,很高兴见到你,欢迎问我任何问题。"'}], 'usage': {'prompt_tokens': 2, 'completion_tokens': 28, 'total_tokens': 30}}, 'success': True} 95 | 96 | 97 | 这里对传入 zhipuai 的参数进行简单介绍: 98 | 99 | - `prompt (list)`: 调用对话模型时,将当前对话信息列表作为提示输入给模型; 按照 {"role": "user", "content": "你好"} 的键值对形式进行传参; 总长度超过模型最长输入限制后会自动截断,需按时间由旧到新排序。 100 | 101 | - `temperature (float)`: 采样温度,控制输出的随机性,必须为正数取值范围是:(0.0,1.0],不能等于 0,默认值为 0.95 值越大,会使输出更随机,更具创造性;值越小,输出会更加稳定或确定。 102 | 103 | - `top_p (float)`: 用温度取样的另一种方法,称为核取样。取值范围是:(0.0, 1.0) 开区间,不能等于 0 或 1,默认值为 0.7。模型考虑具有 top_p 概率质量 tokens 的结果。例如:0.1 意味着模型解码器只考虑从前 10% 的概率的候选集中取 tokens。 104 | 105 | - `request_id (string)`: 由用户端传参,需保证唯一性;用于区分每次请求的唯一标识,用户端不传时平台会默认生成 106 | 107 | - `return_type (string)`: 用于控制每次返回内容的类型,空或者没有此字段时默认按照 json_string 返回。`json_string` 返回标准的 JSON 字符串。`text` 返回原始的文本内容 108 | 109 | - **建议您根据应用场景调整 top_p 或 temperature 参数,但不要同时调整两个参数** 110 | 111 | 112 | ## 4. 使用 LangChain 调用智谱 AI 113 | 114 | 我们同样可以通过 LangChain 框架来调用智谱 AI 大模型,以将其接入到我们的应用框架中。 115 | 116 | 同文心大模型类似,原生的 LangChain 是不支持智谱 AI 调用的,我们需要自定义一个 LLM。 117 | 118 | 此处,我们可以直接调用已自定义好的 ZhipuAILLM 119 | 120 | 121 | ```python 122 | from zhipuai_llm import ZhipuAILLM 123 | ``` 124 | 125 | 126 | ```python 127 | zhipuai_model = ZhipuAILLM(model="chatglm_std", temperature=0, zhipuai_api_key=zhipuai.api_key) 128 | ``` 129 | 130 | 131 | ```python 132 | zhipuai_model.generate(['你好']) 133 | ``` 134 | 135 | 136 | 137 | 138 | LLMResult(generations=[[Generation(text='" 你好👋!我是人工智能助手 智谱清言,可以叫我小智🤖,很高兴见到你,欢迎问我任何问题。"', generation_info=None)]], llm_output=None, run=[RunInfo(run_id=UUID('36840571-ce83-4bcb-8095-a222d59f32a4'))]) 139 | 140 | 141 | -------------------------------------------------------------------------------- /docs/C2/6. 调用智谱 AI(ChatGLM)生成 embedding.md: -------------------------------------------------------------------------------- 1 | # 六、调用智谱 AI 生成 embedding 2 | 3 | 4 | ## 1. 调用智谱 AI Embedding API 5 | 6 | 智谱 AI 及ChatGLM 在上一章已经进行了简单介绍,本章将介绍如何通过其获得文本的 embedding 的,以及将其封装成个性化 embedding 嵌入 LangChain 使用。 7 | 8 | 9 | ```python 10 | import zhipuai 11 | zhipuai.api_key = "your api key" #填写控制台中获取的 APIKey 信息 12 | 13 | model = "text_embedding" #选择调用生成 embedding 的模型 14 | ``` 15 | 16 | 自定义要生产 embedding 的文本 17 | 18 | 19 | ```python 20 | text = "要生成 embedding 的输入文本,字符串形式。每个输入不得超过模型的最大输入tokens数量512" 21 | ``` 22 | 23 | 调用远程 API 24 | 25 | 26 | ```python 27 | response = zhipuai.model_api.invoke( 28 | model=model, 29 | prompt=text 30 | ) 31 | ``` 32 | 33 | 官方的 SDK 返回的结果是字典的格式,这里我们可以直接传入键获得值。 34 | 35 | 我们通过查看 `code` 是否 == 200 来判断请求是否成功 36 | 37 | 38 | ```python 39 | print(response['code']) 40 | ``` 41 | 42 | 200 43 | 44 | 45 | 返回的 embedding, token 等内容被存放在 `data` 中。我们可以查看生产 embedding 的长度 46 | 47 | 48 | ```python 49 | print(f"生成的 embedding 长度为: {len(response['data']['embedding'])}") 50 | ``` 51 | 52 | 生成的 embedding 长度为: 1024 53 | 54 | 55 | 对于每次模型的调用来说,都是要消耗 token 的(花钱),token 的消耗都存放在 `data` 的 `usage` 中。 56 | 57 | 一般情况下 ChatGLM 模型中 token 和字数的换算比例约为 1:1.8,但因为不同模型的分词不同,所以换算比例也存在差异,每一次实际处理 token 数量以模型返回为准。 58 | 59 | 60 | 61 | 我们可以查看输入的 tokens 62 | 63 | 64 | ```python 65 | print(f"用户输入的 tokens 数量为: {response['data']['usage']['prompt_tokens']}") 66 | ``` 67 | 68 | 用户输入的 tokens 数量为: 28 69 | 70 | 71 | 72 | ```python 73 | print(f"用户输入的文本长度为: {len(text)}") 74 | ``` 75 | 76 | 用户输入的文本长度为: 52 77 | 78 | 79 | 80 | ```python 81 | print(f"本次 token 和字数的换算比例为: {response['data']['usage']['prompt_tokens']/len(text)}, 和理论值 1:1.8 = {1/1.8} 接近") 82 | ``` 83 | 84 | 本次 token 和字数的换算比例为: 0.5384615384615384, 和理论值 1:1.8 = 0.5555555555555556 接近 85 | 86 | 87 | 因为模型其实没有生成新的文本,只是获取到输入的 embedding,所以 token 数为0 88 | 89 | 90 | ```python 91 | print(f"模型输出的 tokens 数量为: {response['data']['usage']['completion_tokens']}") 92 | ``` 93 | 94 | 模型输出的 tokens 数量为: 0 95 | 96 | 97 | 98 | ```python 99 | print(f"总 tokens 数量为: {response['data']['usage']['total_tokens']}") 100 | ``` 101 | 102 | 总 tokens 数量为: 28 103 | 104 | 105 | ## 2. 使用 LangChain 调用智谱 AI Embedding 106 | 107 | 我们同样可以通过 LangChain 框架来调用智谱 AI 大模型,以将其接入到我们的应用框架中。 108 | 109 | 原生的 LangChain 是不支持智谱 AI Embedding 调用的,我们需要自定义一个 Embedding。 110 | 111 | 此处,我们可以直接调用已自定义好的 ZhipuAILLM 112 | 113 | 114 | ```python 115 | import zhipuai 116 | ``` 117 | 118 | 119 | ```python 120 | from zhipuai_embedding import ZhipuAIEmbeddings 121 | ``` 122 | 123 | 124 | ```python 125 | zhipuai.api_key = "99ee3e4eb4477848c7a44c0e154a9018.3a7bL4l15TkF3wPi" 126 | 127 | ``` 128 | 129 | 130 | ```python 131 | zhipuai_embeddings = ZhipuAIEmbeddings(zhipuai_api_key=zhipuai.api_key) 132 | ``` 133 | 134 | 我们可以生成 query 的 embedding。 135 | 136 | 137 | ```python 138 | query_embedding = zhipuai_embeddings.embed_query('你好') 139 | 140 | print(query_embedding[:10]) 141 | ``` 142 | 143 | [-0.13970163464546204, 0.04416792839765549, 0.020967043936252594, -0.19684536755084991, 0.08451296389102936, -0.0685092955827713, -0.05186789482831955, 0.11296232044696808, 0.12375720590353012, 0.1507660448551178] 144 | 145 | 146 | 我们也可以生成 doc_list 的 embedding。 147 | 148 | 149 | ```python 150 | doc_list = [ 151 | '你好', 152 | '什么是机器学习', 153 | '什么是深度学习', 154 | '什么是大模型' 155 | ] 156 | 157 | doc_embeddings = zhipuai_embeddings.embed_documents(doc_list) 158 | ``` 159 | 160 | 161 | ```python 162 | print('\n'.join([f'{doc} 的 embedding 为 {doc_embedding[:10]}...\n' for doc, doc_embedding in zip(doc_list, doc_embeddings)])) 163 | ``` 164 | 165 | 你好 的 embedding 为 [-0.13970163464546204, 0.04416792839765549, 0.020967043936252594, -0.19684536755084991, 0.08451296389102936, -0.0685092955827713, -0.05186789482831955, 0.11296232044696808, 0.12375720590353012, 0.1507660448551178]... 166 | 167 | 什么是机器学习 的 embedding 为 [-0.04628180339932442, -0.09553179144859314, 0.010844158940017223, -0.1201983317732811, 0.16935010254383087, -0.15349552035331726, 0.17940732836723328, 0.1256963312625885, 0.09910263121128082, 0.1022590845823288]... 168 | 169 | 什么是深度学习 的 embedding 为 [-0.09552870690822601, -0.03116282820701599, 0.11060678958892822, 0.08925414085388184, 0.06898286193609238, -0.07559530436992645, 0.2021033763885498, -0.04418506473302841, 0.10697835683822632, -0.0666293203830719]... 170 | 171 | 什么是大模型 的 embedding 为 [0.10551410913467407, 0.1735556423664093, -0.24402201175689697, 0.02649446204304695, 0.09757085889577866, 0.030247822403907776, 0.4318920969963074, 0.06334380805492401, -0.02869655191898346, -0.1011139303445816]... 172 | 173 | 174 | -------------------------------------------------------------------------------- /docs/C2/7. 总结.md: -------------------------------------------------------------------------------- 1 | # 七、总结 2 | 3 | 在本章中,我们简要介绍了四种常用大模型 API 的调用方式:ChatGPT、百度文心、讯飞星火、智谱 AI。四种模型 API 都具有不同的调用要求,我们分别进行了介绍并对其原生接口进行了封装,方便用户直接调用使用;同时,我们也简要介绍了如何将大模型 API 封装到 LangChain 的自定义 LLM 中,如何将大模型 API 封装成统一方式调用的本地 API,以及如何将大模型 Embedding API 封装到 LangChain 的自定义 LLM 中。我们分别以百度文心、讯飞星火、智谱 AI作为示例介绍了调用方式,欢迎读者们自行实践尝试将更多的模型进行统一封装。 4 | 5 | 学习完本章,你应该掌握了常用大模型的基本调用方式,那么接下来,你就可以开始着手基于大模型打造自己的应用啦! -------------------------------------------------------------------------------- /docs/C2/附1.LangChain自定义 LLM.md: -------------------------------------------------------------------------------- 1 | # 附一 基于 LangChain 自定义 LLM 2 | 3 | LangChain 为基于 LLM 开发自定义应用提供了高效的开发框架,便于开发者迅速地激发 LLM 的强大能力,搭建 LLM 应用。LangChain 也同样支持多种大模型,内置了 OpenAI、LLAMA 等大模型的调用接口。但是,LangChain 并没有内置所有大模型,它通过允许用户自定义 LLM 类型,来提供强大的可扩展性。 4 | 5 | 在本部分,我们以百度文心大模型为例,讲述如何基于 LangChain 自定义 LLM,让我们基于 LangChain 搭建的应用能够支持百度文心、讯飞星火等国内大模型。 6 | 7 | 本部分涉及相对更多 LangChain、大模型调用的技术细节,有精力同学可以学习部署,如无精力可以直接使用后续代码来支持调用。 8 | 9 | 要实现自定义 LLM,需要定义一个自定义类继承自 LangChain 的 LLM 基类,然后定义两个函数:① _call 方法,其接受一个字符串,并返回一个字符串,即模型的核心调用;② _identifying_params 方法,用于打印 LLM 信息。 10 | 11 | 首先我们导入所需的第三方库: 12 | 13 | 14 | ```python 15 | import json 16 | import time 17 | from typing import Any, List, Mapping, Optional, Dict, Union, Tuple 18 | import requests 19 | from langchain.callbacks.manager import CallbackManagerForLLMRun 20 | from langchain.llms.base import LLM 21 | from langchain.utils import get_from_dict_or_env 22 | from pydantic import Field, model_validator 23 | ``` 24 | 25 | 由于百度文心使用双重秘钥进行认证,用户需要先基于 API_Key 与 Secret_Key 来获取 access_token,再使用 access_token 来实现对模型的调用(详见《3. 调用百度文心》),因此我们需要先定义一个 get_access_token 方法来获取 access_token: 26 | 27 | 28 | ```python 29 | def get_access_token(api_key : str, secret_key : str): 30 | """ 31 | 使用 API Key,Secret Key 获取access_token,替换下列示例中的应用API Key、应用Secret Key 32 | """ 33 | # 指定网址 34 | url = f"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={api_key}&client_secret={secret_key}" 35 | # 设置 POST 访问 36 | payload = json.dumps("") 37 | headers = { 38 | 'Content-Type': 'application/json', 39 | 'Accept': 'application/json' 40 | } 41 | # 通过 POST 访问获取账户对应的 access_token 42 | response = requests.request("POST", url, headers=headers, data=payload) 43 | return response.json().get("access_token") 44 | ``` 45 | 46 | 接着我们定义一个继承自 LLM 类的自定义 LLM 类: 47 | 48 | 49 | ```python 50 | # 继承自 langchain.llms.base.LLM 51 | class Wenxin_LLM(LLM): 52 | # 原生接口地址 53 | url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant" 54 | # 默认选用 ERNIE-Bot-turbo 模型,即目前一般所说的百度文心大模型 55 | model_name: str = Field(default="ERNIE-Bot-turbo", alias="model") 56 | # 访问时延上限 57 | request_timeout: Optional[Union[float, Tuple[float, float]]] = None 58 | # 温度系数 59 | temperature: float = 0.1 60 | # API_Key 61 | api_key: str = None 62 | # Secret_Key 63 | secret_key : str = None 64 | # access_token 65 | access_token: str = None 66 | # 必备的可选参数 67 | model_kwargs: Dict[str, Any] = Field(default_factory=dict) 68 | 69 | ``` 70 | 71 | 上述初始化涵盖了我们平时常用的参数,也可以根据实际需求与文心的 API 加入更多的参数。 72 | 73 | 接下来我们实现一个初始化方法 init_access_token,当模型的 access_token 为空时调用: 74 | 75 | 76 | ```python 77 | def init_access_token(self): 78 | if self.api_key != None and self.secret_key != None: 79 | # 两个 Key 均非空才可以获取 access_token 80 | try: 81 | self.access_token = get_access_token(self.api_key, self.secret_key) 82 | except Exception as e: 83 | print(e) 84 | print("获取 access_token 失败,请检查 Key") 85 | else: 86 | print("API_Key 或 Secret_Key 为空,请检查 Key") 87 | ``` 88 | 89 | 接下来我们实现核心的方法——调用模型 API: 90 | 91 | 92 | ```python 93 | def _call(self, prompt : str, stop: Optional[List[str]] = None, 94 | run_manager: Optional[CallbackManagerForLLMRun] = None, 95 | **kwargs: Any): 96 | # 除 prompt 参数外,其他参数并没有被用到,但当我们通过 LangChain 调用时会传入这些参数,因此必须设置 97 | # 如果 access_token 为空,初始化 access_token 98 | if self.access_token == None: 99 | self.init_access_token() 100 | # API 调用 url 101 | url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token={}".format(self.access_token) 102 | # 配置 POST 参数 103 | payload = json.dumps({ 104 | "messages": [ 105 | { 106 | "role": "user",# user prompt 107 | "content": "{}".format(prompt)# 输入的 prompt 108 | } 109 | ], 110 | 'temperature' : self.temperature 111 | }) 112 | headers = { 113 | 'Content-Type': 'application/json' 114 | } 115 | # 发起请求 116 | response = requests.request("POST", url, headers=headers, data=payload, timeout=self.request_timeout) 117 | if response.status_code == 200: 118 | # 返回的是一个 Json 字符串 119 | js = json.loads(response.text) 120 | return js["result"] 121 | else: 122 | return "请求失败" 123 | ``` 124 | 125 | 然后我们还需要定义一下模型的描述方法: 126 | 127 | 128 | ```python 129 | # 首先定义一个返回默认参数的方法 130 | @property 131 | def _default_params(self) -> Dict[str, Any]: 132 | """获取调用Ennie API的默认参数。""" 133 | normal_params = { 134 | "temperature": self.temperature, 135 | "request_timeout": self.request_timeout, 136 | } 137 | return {**normal_params} 138 | 139 | 140 | @property 141 | def _identifying_params(self) -> Mapping[str, Any]: 142 | """Get the identifying parameters.""" 143 | return {**{"model_name": self.model_name}, **self._default_params} 144 | ``` 145 | 146 | 通过上述步骤,我们就可以基于 LangChain 定义百度文心的调用方式了。我们将此代码封装在 wenxin_llm.py 文件中,将在讲述如何调用百度文心的 Notebook 中直接使用该 LLM。 147 | -------------------------------------------------------------------------------- /docs/C2/附2.将大模型 API 封装成本地 API.md: -------------------------------------------------------------------------------- 1 | ## 附2 将大模型 API 封装成本地 API 2 | 3 | 目前,大模型正方兴未艾,各领域、厂家、架构的大模型层出不穷,有支持本地微调、部署的开源大模型,也有提供 Web 及 API 服务的通用大模型。不同的大模型往往有着不同的调用方式及参数,例如,讯飞星火认知大模型需要使用 websocket 连接来调用,同直接使用 request 调用的百度文心、ChatGPT 等存在显著差异。对于不同调用方式的模型,如果不能统一调用,就需要在程序代码中增加很多复杂的业务逻辑、调用细节,增加了程序开发的工作量,也增加了出现 Bug 的概率。 4 | 5 | 我们可以使用 FastAPI,对不同的大模型 API 再进行一层封装,将其映射到本地接口上,从而通过统一的方式来调用本地接口实现不同大模型的调用。通过这样的手段,可以极大程度减少对于模型调用的工作量和复杂度。 6 | 7 | 在本章中,我们以讯飞星火大模型 API 为例,讲解如何将通用大模型 API 封装成本地 API,从而实现同一方式的 API 调用。 8 | 9 | 要实现本地 API 封装,我们首先需要安装 fastapi 第三方库: 10 | 11 | 12 | ```python 13 | ! pip install fastapi 14 | ``` 15 | 16 | 接下来导入第三方库,并创建一个 API 对象: 17 | 18 | 19 | ```python 20 | from fastapi import FastAPI 21 | from pydantic import BaseModel 22 | import os 23 | 24 | app = FastAPI() # 创建 api 对象 25 | ``` 26 | 27 | 本地 API 一般通过 POST 方式进行访问,即参数会附加在 POST 请求中,我们需要定义一个数据模型来接收 POST 请求中的数据: 28 | 29 | 30 | ```python 31 | # 定义一个数据模型,用于接收POST请求中的数据 32 | class Item(BaseModel): 33 | prompt : str # 用户 prompt 34 | temperature : float # 温度系数 35 | max_tokens : int # token 上限 36 | if_list : bool = False # 是否多轮对话 37 | 38 | ``` 39 | 40 | 在上面的数据模型中,我们定义了几个常用参数: 41 | 42 | · prompt:即用户输入的 Prompt。我们默认为单轮对话调用,因此 prompt 默认为一句输入;如果将 if_list 设置为 True,那么就是多轮对话调用,prompt 应为一个已构造好(即有标准 role、content 格式)的列表字符串 43 | 44 | · temperature:温度系数 45 | 46 | · max_tokens:回答的最大 token 上限 47 | 48 | · if_list:是否多轮对话,默认为 False 49 | 50 | 接下来我们就可以创建一个 POST 请求的 API 端点: 51 | 52 | 53 | ```python 54 | @app.post("/spark/") 55 | async def get_spark_response(item: Item): 56 | # 实现星火大模型调用的 API 端点 57 | response = get_spark(item) 58 | return response 59 | ``` 60 | 61 | 在上述代码中,我们创建了一个 POST 请求的端点,后续我们每一次请求都会通过这个端点。我们将另外定义一个函数来实现对星火 API 的调用: 62 | 63 | 64 | ```python 65 | import SparkApiSelf 66 | 67 | # 首先定义一个构造参数函数 68 | def getText(role, content, text = []): 69 | # role 是指定角色,content 是 prompt 内容 70 | jsoncon = {} 71 | jsoncon["role"] = role 72 | jsoncon["content"] = content 73 | text.append(jsoncon) 74 | return text 75 | 76 | def get_spark(item): 77 | # 配置 spark 秘钥 78 | #以下密钥信息从控制台获取 79 | appid = "9f922c84" #填写控制台中获取的 APPID 信息 80 | api_secret = "YjU0ODk4MWQ4NTgyNDU5MzNiNWQzZmZm" #填写控制台中获取的 APISecret 信息 81 | api_key ="5d4e6e41f6453936ccc34dd524904324" #填写控制台中获取的 APIKey 信息 82 | domain = "generalv2" # v2.0版本 83 | Spark_url = "ws://spark-api.xf-yun.com/v2.1/chat" # v2.0环境的地址 84 | 85 | # 构造请求参数 86 | if item.if_list: 87 | prompt = item.prompt 88 | else: 89 | prompt = getText("user", item.prompt) 90 | 91 | response = SparkApiSelf.main(appid,api_key,api_secret,Spark_url,domain,prompt, item.temperature, item.max_tokens) 92 | return response 93 | ``` 94 | 95 | 注意,由于星火给出的示例 SparkApi 中将 temperature、max_tokens 都进行了封装,我们需要对示例代码进行改写,暴露出这两个参数接口,我们实现了一个新的文件 SparkApiSelf,对其中的改动如下: 96 | 97 | 首先,我们对参数类中新增了 temperature、max_tokens 两个属性: 98 | 99 | 100 | ```python 101 | class Ws_Param(object): 102 | # 初始化 103 | def __init__(self, APPID, APIKey, APISecret, Spark_url): 104 | self.APPID = APPID 105 | self.APIKey = APIKey 106 | self.APISecret = APISecret 107 | self.host = urlparse(Spark_url).netloc 108 | self.path = urlparse(Spark_url).path 109 | self.Spark_url = Spark_url 110 | # 自定义 111 | self.temperature = 0 112 | self.max_tokens = 2048 113 | ``` 114 | 115 | 然后在生成请求参数的函数中,增加这两个参数并在构造请求数据时加入参数: 116 | 117 | 118 | ```python 119 | def gen_params(appid, domain,question, temperature, max_tokens): 120 | """ 121 | 通过appid和用户的提问来生成请参数 122 | """ 123 | data = { 124 | "header": { 125 | "app_id": appid, 126 | "uid": "1234" 127 | }, 128 | "parameter": { 129 | "chat": { 130 | "domain": domain, 131 | "random_threshold": 0.5, 132 | "max_tokens": max_tokens, 133 | "temperature" : temperature, 134 | "auditing": "default" 135 | } 136 | }, 137 | "payload": { 138 | "message": { 139 | "text": question 140 | } 141 | } 142 | } 143 | return data 144 | ``` 145 | 146 | 再在 run 函数中调用生成参数时加入这两个参数: 147 | 148 | 149 | ```python 150 | def run(ws, *args): 151 | data = json.dumps(gen_params(appid=ws.appid, domain= ws.domain,question=ws.question, temperature = ws.temperature, max_tokens = ws.max_tokens)) 152 | ws.send(data) 153 | ``` 154 | 155 | 最后,由于 WebSocket 是直接打印到终端,但我们需要将最后的结果返回给用户,我们需要修改 main 函数,使用一个队列来装填星火流式输出产生的结果,并最终集成返回给用户: 156 | 157 | 158 | ```python 159 | def main(appid, api_key, api_secret, Spark_url,domain, question, temperature, max_tokens): 160 | # print("星火:") 161 | output_queue = queue.Queue() 162 | def on_message(ws, message): 163 | data = json.loads(message) 164 | code = data['header']['code'] 165 | if code != 0: 166 | print(f'请求错误: {code}, {data}') 167 | ws.close() 168 | else: 169 | choices = data["payload"]["choices"] 170 | status = choices["status"] 171 | content = choices["text"][0]["content"] 172 | # print(content, end='') 173 | # 将输出值放入队列 174 | output_queue.put(content) 175 | if status == 2: 176 | ws.close() 177 | 178 | wsParam = Ws_Param(appid, api_key, api_secret, Spark_url) 179 | websocket.enableTrace(False) 180 | wsUrl = wsParam.create_url() 181 | ws = websocket.WebSocketApp(wsUrl, on_message=on_message, on_error=on_error, on_close=on_close, on_open=on_open) 182 | ws.appid = appid 183 | ws.question = question 184 | ws.domain = domain 185 | ws.temperature = temperature 186 | ws.max_tokens = max_tokens 187 | ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) 188 | return ''.join([output_queue.get() for _ in range(output_queue.qsize())]) 189 | ``` 190 | 191 | 完成上述步骤之后,我们的 API 封装就大致完成了。接下来,将上述代码放在一个文件中,再通过 uvicorn 启动 API 即可实现访问,整体代码参见《SparkApiSelf.py》。后续操作参见《4. 调用讯飞星火》。 192 | -------------------------------------------------------------------------------- /docs/C2/附3.LangChain 自定义 LLM embedding.md: -------------------------------------------------------------------------------- 1 | # 附三 基于 LangChain 自定义 Embeddings 2 | 3 | LangChain 为基于 LLM 开发自定义应用提供了高效的开发框架,便于开发者迅速地激发 LLM 的强大能力,搭建 LLM 应用。LangChain 也同样支持多种大模型的 Embeddings,内置了 OpenAI、LLAMA 等大模型 Embeddings 的调用接口。但是,LangChain 并没有内置所有大模型,它通过允许用户自定义 Embeddings 类型,来提供强大的可扩展性。 4 | 5 | 在本部分,我们以智谱 AI 为例,讲述如何基于 LangChain 自定义 Embeddings,让我们基于 LangChain 搭建的应用能够支持百度文心、智谱 AI 等国内大模型生成的 Embeddings(讯飞星火目前还不支持)。 6 | 7 | 本部分涉及相对更多 LangChain、大模型调用的技术细节,有精力同学可以学习部署,如无精力可以直接使用后续代码来支持调用。 8 | 9 | 要实现自定义 Embeddings,需要定义一个自定义类继承自 LangChain 的 Embeddings 基类,然后定义三个函数:① _embed 方法,其接受一个字符串,并返回一个存放 Embeddings 的 List[float],即模型的核心调用;② embed_query 方法,用于对单个字符串(query)进行 embedding。③ embed_documents 方法,用于对字符串列表(documents)进行 embedding。 10 | 11 | 首先我们导入所需的第三方库: 12 | 13 | 14 | ```python 15 | from __future__ import annotations 16 | 17 | import logging 18 | from typing import Any, Dict, List, Optional 19 | 20 | from langchain.embeddings.base import Embeddings 21 | from langchain.pydantic_v1 import BaseModel, root_validator 22 | from langchain.utils import get_from_dict_or_env 23 | ``` 24 | 25 | 这里我们定义一个继承自 Embeddings 类的自定义 Embeddings 类: 26 | 27 | 28 | ```python 29 | class ZhipuAIEmbeddings(BaseModel, Embeddings): 30 | """`Zhipuai Embeddings` embedding models.""" 31 | 32 | zhipuai_api_key: Optional[str] = None 33 | """Zhipuai application apikey""" 34 | ``` 35 | 36 | 在 Python 中,root_validator 是 Pydantic 模块中一个用于自定义数据校验的装饰器函数。root_validator 用于在校验整个数据模型之前对整个数据模型进行自定义校验,以确保所有的数据都符合所期望的数据结构。 37 | 38 | root_validator 接收一个函数作为参数,该函数包含需要校验的逻辑。函数应该返回一个字典,其中包含经过校验的数据。如果校验失败,则抛出一个 ValueError 异常。 39 | 40 | 装饰器 root_validator 确保导入了相关的包和并配置了相关的 API_Key 41 | 这里取巧,在确保导入 zhipuai model 后直接将`zhipuai.model_api`绑定到 cliet 上,减少和其他 Embeddings 类的差异。 42 | 43 | 44 | `values["client"] = zhipuai.model_api` 45 | 46 | 47 | ```python 48 | @root_validator() 49 | def validate_environment(cls, values: Dict) -> Dict: 50 | """ 51 | 验证环境变量或配置文件中的zhipuai_api_key是否可用。 52 | 53 | Args: 54 | 55 | values (Dict): 包含配置信息的字典,必须包含 zhipuai_api_key 的字段 56 | Returns: 57 | 58 | values (Dict): 包含配置信息的字典。如果环境变量或配置文件中未提供 zhipuai_api_key,则将返回原始值;否则将返回包含 zhipuai_api_key 的值。 59 | Raises: 60 | 61 | ValueError: zhipuai package not found, please install it with `pip install 62 | zhipuai` 63 | """ 64 | values["zhipuai_api_key"] = get_from_dict_or_env( 65 | values, 66 | "zhipuai_api_key", 67 | "ZHIPUAI_API_KEY", 68 | ) 69 | 70 | try: 71 | import zhipuai 72 | zhipuai.api_key = values["zhipuai_api_key"] 73 | values["client"] = zhipuai.model_api 74 | 75 | except ImportError: 76 | raise ValueError( 77 | "Zhipuai package not found, please install it with " 78 | "`pip install zhipuai`" 79 | ) 80 | return values 81 | 82 | ``` 83 | 84 | 接下来我们重写 `_embed` 方法,调用远程 API 并解析 embedding 结果。 85 | 86 | 87 | ```python 88 | def _embed(self, texts: str) -> List[float]: 89 | """ 90 | 生成输入文本的 embedding。 91 | 92 | Args: 93 | texts (str): 要生成 embedding 的文本。 94 | 95 | Return: 96 | embeddings (List[float]): 输入文本的 embedding,一个浮点数值列表。 97 | """ 98 | try: 99 | resp = self.client.invoke( 100 | model="text_embedding", 101 | prompt=texts 102 | ) 103 | except Exception as e: 104 | raise ValueError(f"Error raised by inference endpoint: {e}") 105 | 106 | if resp["code"] != 200: 107 | raise ValueError( 108 | "Error raised by inference API HTTP code: %s, %s" 109 | % (resp["code"], resp["msg"]) 110 | ) 111 | embeddings = resp["data"]["embedding"] 112 | return embeddings 113 | ``` 114 | 115 | 重写 embed_documents 方法,因为这里 `_embed` 已经定义好了,可以直接传入文本并返回结果即可。 116 | 117 | 118 | ```python 119 | def embed_documents(self, texts: List[str]) -> List[List[float]]: 120 | """ 121 | 生成输入文本列表的 embedding。 122 | Args: 123 | texts (List[str]): 要生成 embedding 的文本列表. 124 | 125 | Returns: 126 | List[List[float]]: 输入列表中每个文档的 embedding 列表。每个 embedding 都表示为一个浮点值列表。 127 | """ 128 | return [self._embed(text) for text in texts] 129 | ``` 130 | 131 | `embed_query` 是对单个文本计算 embedding 的方法,因为我们已经定义好对文档列表计算 embedding 的方法`embed_documents` 了,这里可以直接将单个文本组装成 list 的形式传给 `embed_documents`。 132 | 133 | 134 | ```python 135 | def embed_query(self, text: str) -> List[float]: 136 | """ 137 | 生成输入文本的 embedding。 138 | 139 | Args: 140 | text (str): 要生成 embedding 的文本。 141 | 142 | Return: 143 | List [float]: 输入文本的 embedding,一个浮点数值列表。 144 | """ 145 | resp = self.embed_documents([text]) 146 | return resp[0] 147 | ``` 148 | 149 | 可能大家会好奇,为什么要先定义`embed_documents`再用 `embed_query` 调用呢,不返过来呢,其实也是可以的,`embed_query` 单独请求也是可以的。 150 | 151 | 对于 `embed_documents` 可以加入一些内容处理后再请求 embedding,比如如果文档特别长,我们可以考虑对文档分段,防止超过最大 token 限制,这些都是可以的,靠大家发挥自己的主观能动性完善啦,这里只是给出一个简单的 demo。 152 | 153 | 目前只是实现了同步调用方式,后续优化中大家可以按需完善异步调用的方式,这里因为智谱官方不支持就没有实现。 154 | 155 | 通过上述步骤,我们就可以基于 LangChain 定义智谱 AI 生成 embedding 的调用方式了。我们将此代码封装在 zhipuai_embedding.py 文件中。 156 | -------------------------------------------------------------------------------- /docs/C3/1. 大模型开发流程.md: -------------------------------------------------------------------------------- 1 | # 一、大模型开发整体流程 2 | 3 | ## 1. 何为大模型开发 4 | 5 | 我们将开发以大语言模型为功能核心、通过大语言模型的强大理解能力和生成能力、结合特殊的数据或业务逻辑来提供独特功能的应用称为大模型开发。开发大模型相关应用,其技术核心点虽然在大语言模型上,但一般通过调用 API 或开源模型来实现核心的理解与生成,通过 Prompt Enginnering 来实现大语言模型的控制,因此,虽然大模型是深度学习领域的集大成之作,大模型开发却更多是一个工程问题。 6 | 7 | 在大模型开发中,我们一般不会去大幅度改动模型,而是将大模型作为一个调用工具,通过 Prompt Engineering、数据工程、业务逻辑分解等手段来充分发挥大模型能力,适配应用任务,而不会将精力聚焦在优化模型本身上。这因此,作为大模型开发的初学者,我们并不需要深研大模型内部原理,而更需要掌握使用大模型的实践技巧。 8 | 9 | ![](../figures/LLM_developing.png) 10 |
大模型开发要素
11 |

12 | 13 | 同时,以调用、发挥大模型为核心的大模型开发与传统的 AI 开发在整体思路上有着较大的不同。大语言模型的两个核心能力:指令理解与文本生成提供了复杂业务逻辑的简单平替方案。在传统的 AI 开发中,我们首先需要将非常复杂的业务逻辑依次拆解,对于每一个子业务构造训练数据与验证数据,对于每一个子业务训练优化模型,最后形成完整的模型链路来解决整个业务逻辑。然而,在大模型开发中,我们将尝试用 Prompt Engineering 来替代子模型的训练调优,通过 Prompt 链路组合来实现业务逻辑,用一个通用大模型 + 若干业务 Prompt 来解决任务,从而将传统的模型训练调优转变成了更简单、轻松、低成本的 Prompt 设计调优。 14 | 15 | 同时,在评估思路上,大模型开发与传统 AI 开发也有了质的差异。传统 AI 开发需要首先构造训练集、测试集、验证集,通过在训练集上训练模型、在测试集上调优模型、在验证集上最终验证模型效果来实现性能的评估。然而,大模型开发更敏捷、灵活,我们一般不会在初期显式地确定训练集、验证集,由于不再需要训练子模型,我们不再构造训练集,而是直接从实际业务需求出发构造小批量验证集,设计合理 Prompt 来满足验证集效果。然后,我们将不断从业务逻辑中收集当下 Prompt 的 Bad Case,并将 Bad Case 加入到验证集中,针对性优化 Prompt,最后实现较好的泛化效果。 16 | 17 | ![](../figures/AI_eval.png) 18 | 19 |
传统 AI 评估
20 |

21 | 22 | ![](../figures/LLM_eval.png) 23 | 24 |

LLM 评估
25 |

26 | 27 | 在本章中,我们将简述大模型开发的一般流程,并结合项目实际需求,逐步分析完成项目开发的工作和步骤。 28 | 29 | ## 2. 大模型开发的整体流程 30 | 31 | 结合上述分析,我们一般可以将大模型开发分解为以下几个流程: 32 | 33 | ![](../figures/LLM_developing_whole.png) 34 | 35 | 1. 确定目标。在进行开发前,我们首先需要确定开发的目标,即要开发的应用的应用场景、目标人群、核心价值。对于个体开发者或小型开发团队而言,一般应先设定最小化目标,从构建一个 mvp(最小可行性产品)开始,逐步进行完善和优化。 36 | 37 | 2. 设计功能。在确定开发目标后,需要设计本应用所要提供的功能,以及每一个功能的大体实现逻辑。虽然我们通过使用大模型来简化了业务逻辑的拆解,但是越清晰、深入的业务逻辑理解往往也能带来更好的 Prompt 效果。同样,对于个体开发者或小型开发团队来说,首先要确定应用的核心功能,然后延展设计核心功能的上下游功能;例如,我们想打造一款个人知识库助手,那么核心功能就是结合个人知识库内容进行问题的回答,那么其上游功能的用户上传知识库、下游功能的用户手动纠正模型回答就是我们也必须要设计实现的子功能。 38 | 39 | 3. 搭建整体架构。目前,绝大部分大模型应用都是采用的特定数据库+ Prompt + 通用大模型的架构。我们需要针对我们所设计的功能,搭建项目的整体架构,实现从用户输入到应用输出的全流程贯通。一般来说,我们推荐基于 LangChain 框架进行开发。LangChain 提供了 Chain、Tool 等架构的实现,我们可以基于 LangChain 进行个性化定制,实现从用户输入到数据库再到大模型最后输出的整体架构连接。 40 | 41 | 4. 搭建数据库。个性化大模型应用需要有个性化数据库进行支撑。由于大模型应用需要进行向量语义检索,一般使用诸如 chroma 的向量数据库。在该步骤中,我们需要收集数据并进行预处理,再向量化存储到数据库中。数据预处理一般包括从多种格式向纯文本的转化,例如 pdf、markdown、html、音视频等,以及对错误数据、异常数据、脏数据进行清洗。完成预处理后,需要进行切片、向量化构建出个性化数据库。 42 | 43 | 5. Prompt Engineering。优质的 Prompt 对大模型能力具有极大影响,我们需要逐步迭代构建优质的 Prompt Engineering 来提升应用性能。在该步中,我们首先应该明确 Prompt 设计的一般原则及技巧,构建出一个来源于实际业务的小型验证集,基于小型验证集设计满足基本要求、具备基本能力的 Prompt。 44 | 45 | 6. 验证迭代。验证迭代在大模型开发中是极其重要的一步,一般指通过不断发现 Bad Case 并针对性改进 Prompt Engineering 来提升系统效果、应对边界情况。在完成上一步的初始化 Prompt 设计后,我们应该进行实际业务测试,探讨边界情况,找到 Bad Case,并针对性分析 Prompt 存在的问题,从而不断迭代优化,直到达到一个较为稳定、可以基本实现目标的 Prompt 版本。 46 | 47 | 7. 前后端搭建。完成 Prompt Engineering 及其迭代优化之后,我们就完成了应用的核心功能,可以充分发挥大语言模型的强大能力。接下来我们需要搭建前后端,设计产品页面,让我们的应用能够上线成为产品。前后端开发是非常经典且成熟的领域,此处就不再赘述,我们将主要介绍两种快速开发 Demo 的框架:Gradio 和 Streamlit,可以帮助个体开发者迅速搭建可视化页面实现 Demo 上线。 48 | 49 | 8. 体验优化。在完成前后端搭建之后,应用就可以上线体验了。接下来就需要进行长期的用户体验跟踪,记录 Bad Case 与用户负反馈,再针对性进行优化即可。 -------------------------------------------------------------------------------- /docs/C3/2. 项目流程简析.md: -------------------------------------------------------------------------------- 1 | # 二、项目流程简析 2 | 3 | 以下我们将结合本实践项目与上文的整体流程介绍,简要分析本项目开发流程如下: 4 | 5 | ### 步骤一:项目规划与需求分析 6 | 7 | #### 1.**项目目标**:基于个人知识库的问答助手 8 | 9 | #### 2.**核心功能**: 10 | 11 | 1. 上传文档、创建知识库; 12 | 2. 选择知识库,检索用户提问的知识片段; 13 | 3. 提供知识片段与提问,获取大模型回答; 14 | 4. 流式回复; 15 | 5. 历史对话记录 16 | 17 | #### 3.**确定技术架构和工具** 18 | 19 | 1. LangChain框架 20 | 2. Chroma知识库 21 | 3. 大模型使用 GPT、Claude、科大讯飞的星火大模型、文心一言、Chat-GLM2等 22 | 4. 前后端使用 Gradio 和 Streamlit。 23 | 24 | ### 步骤二:数据准备与向量知识库构建 25 | 26 | 本项目实现原理如下图所示(图片来源),过程包括加载本地文档 -> 读取文本 -> 文本分割 -> 文本向量化 -> question向量化 -> 在文本向量中匹配出与问句向量最相似的 top k个 -> 匹配出的文本作为上下文和问题一起添加到 prompt中 -> 提交给 LLM生成回答。 27 | 28 | ![](../figures/flow_chart.png) 29 | 30 | #### 1. 收集和整理用户提供的文档。 31 | 32 | 用户常用文档格式有 pdf、txt、doc 等,首先使用工具读取文本,通常使用 langchain 的文档加载器模块可以方便的将用户提供的文档加载进来,也可以使用一些 python 比较成熟的包进行读取。 33 | 34 | 由于目前大模型使用 token 的限制,我们需要对读取的文本进行切分,将较长的文本切分为较小的文本,这时一段文本就是一个单位的知识。 35 | 36 | #### 2. 将文档词向量化 37 | 38 | 使用文本嵌入(Embeddings)对分割后的文档进行向量化,使语义相似的文本片段具有接近的向量表示。然后,存入向量数据库,这个流程正是创建索引(index)的过程。 39 | 40 | 向量数据库对各文档片段进行索引,支持快速检索。这样,当用户提出问题时,可以先将问题转换为向量,在数据库中快速找到语义最相关的文档片段。然后将这些文档片段与问题一起传递给语言模型,生成回答 41 | 42 | #### 3. 将向量化后的文档导入Chroma知识库,建立知识库索引。 43 | 44 | Langchain集成了超过30个不同的向量存储库。我们选择 Chroma 向量库是因为它轻量级且数据存储在内存中,这使得它非常容易启动和开始使用。 45 | 46 | 将用户知识库内容经过 embedding 存入向量知识库,然后用户每一次提问也会经过 embedding,利用向量相关性算法(例如余弦算法)找到最匹配的几个知识库片段,将这些知识库片段作为上下文,与用户问题一起作为 promt 提交给 LLM 回答。 47 | 48 | ### 步骤三:大模型集成与API连接 49 | 50 | 1. 集成GPT、Claude、星火、文心、GLM等大模型,配置API连接。 51 | 2. 编写代码,实现与大模型API的交互,以便获取问题答案。 52 | 53 | ### 步骤四:核心功能实现 54 | 55 | 1. 构建 Prompt Engineering,实现大模型回答功能,根据用户提问和知识库内容生成回答。 56 | 3. 实现流式回复,允许用户进行多轮对话。 57 | 4. 添加历史对话记录功能,保存用户与助手的交互历史。 58 | 59 | ### 步骤五:核心功能迭代优化 60 | 61 | 1. 进行验证评估,收集 Bad Case。 62 | 2. 根据 Bad Case 迭代优化核心功能实现。 63 | 64 | ### 步骤六:前端与用户交互界面开发 65 | 66 | 1. 使用Gradio和Streamlit搭建前端界面。 67 | 2. 实现用户上传文档、创建知识库的功能。 68 | 3. 设计用户界面,包括问题输入、知识库选择、历史记录展示等。 69 | 70 | ### 步骤七:部署测试与上线 71 | 72 | 1. 部署问答助手到服务器或云平台,确保可在互联网上访问。 73 | 2. 进行生产环境测试,确保系统稳定。 74 | 3. 上线并向用户发布。 75 | 76 | ### 步骤八:维护与持续改进 77 | 78 | 1. 监测系统性能和用户反馈,及时处理问题。 79 | 2. 定期更新知识库,添加新的文档和信息。 80 | 3. 收集用户需求,进行系统改进和功能扩展。 81 | 82 | 整个流程将确保项目从规划、开发、测试到上线和维护都能够顺利进行,为用户提供高质量的基于个人知识库的问答助手。 -------------------------------------------------------------------------------- /docs/C3/3. 项目架构简析.md: -------------------------------------------------------------------------------- 1 | # 三、项目架构简析 2 | 3 | ## 1. 整体架构 4 | 5 | 经过上文分析,本项目为搭建一个基于大模型的个人知识库助手,基于 LangChain 框架搭建,核心技术包括 LLM API 调用、向量数据库、检索问答链等。项目整体架构如下: 6 | 7 | ![](../figures/structure.jpg) 8 | 9 | 如上,本项目从底向上依次分为 LLM 层、数据层、数据库层、应用层与服务层。① LLM 层主要基于四种流行 LLM API 进行了 LLM 调用封装,支持用户以统一的入口、方式来访问不同的模型,支持随时进行模型的切换;② 数据层主要包括个人知识库的源数据以及 Embedding API,源数据经过 Embedding 处理可以被向量数据库使用;③ 数据库层主要为基于个人知识库源数据搭建的向量数据库,在本项目中我们选择了 Chroma;④ 应用层为核心功能的最顶层封装,我们基于 LangChain 提供的检索问答链基类进行了进一步封装,从而支持不同模型切换以及便捷实现基于数据库的检索问答;⑤ 最顶层为服务层,我们分别实现了 Gradio 搭建 Demo 与 FastAPI 组建 API 两种方式来支持本项目的服务访问。 10 | 11 | ## 2. 代码结构 12 | 13 | 本项目的完整代码存放于 project 目录下,实现了项目的全部功能及封装,代码结构如下: 14 | 15 | -project 16 | -readme.md 项目说明 17 | -llm LLM调用封装 18 | -self_llm.py 自定义 LLM 基类 19 | -wenxin_llm.py 自定义百度文心 LLM 20 | -spark_llm.py 自定义讯飞星火 LLM 21 | -zhipu_llm.py 自定义智谱 LLM 22 | -call_llm.py 将各个 LLM 的原生接口封装在一起 23 | -embedding embedding调用封装 24 | -zhipu_embedding.py 自定义智谱embedding 25 | -data 源数据路径 26 | -database 数据库层封装 27 | -create_db.py 处理源数据及初始化数据库封装 28 | -chain 应用层封装 29 | -qa_chain.py 封装检索问答链,返回一个检索问答链对象 30 | -chat_qa_chian.py:封装对话检索链,返回一个对话检索链对象 31 | -prompt_template.py 存放多个版本的 Template 32 | -serve 服务层封装 33 | -run_gradio.py 启动 Gradio 界面 34 | -api.py 封装 FastAPI 35 | -run_api.sh 启动 API 36 | 37 | ## 3. 项目逻辑 38 | 39 | 1. 用户:可以通过 run_gradio 或者 run_api 启动整个服务; 40 | 2. 服务层调用 qa_chain.py 或 chat_qa_chain 实例化对话检索链对象,实现全部核心功能; 41 | 3. 服务层和应用层都可以调用、切换 prompt_template.py 中的 prompt 模板来实现 prompt 的迭代; 42 | 4. 也可以直接调用 call_llm 中的 get_completion 函数来实现不使用数据库的 LLM; 43 | 5. 应用层调用已存在的数据库和 llm 中的自定义 LLM 来构建检索链; 44 | 6. 如果数据库不存在,应用层调用 create_db.py 创建数据库,该脚本可以使用 openai embedding 也可以使用 embedding.py 中的自定义 embedding 45 | 46 | ## 4. 各层简析 47 | 48 | ### 4.1 LLM 层 49 | 50 | LLM 层主要功能为将国内外四种知名 LLM API(OpenAI-ChatGPT、百度文心、讯飞星火、智谱GLM)进行封装,隐藏不同 API 的调用差异,实现在同一个对象或函数中通过不同的 model 参数来使用不同来源的 LLM。 51 | 52 | 在 LLM 层,我们首先构建了一个 Self_LLM 基类,基类定义了所有 API 的一些共同参数(如 API_Key,temperature 等);然后我们在该基类基础上继承实现了上述四种 LLM API 的自定义 LLM。同时,我们也将四种 LLM 的原生 API 封装在了统一的 get_completion 函数中。 53 | 54 | 在上一章,我们已详细介绍了每一种 LLM 的调用方式、封装方式,项目代码中的 LLM 层封装就是上一章讲解的代码实践。 55 | 56 | ### 4.2 数据层 57 | 58 | 数据层主要包括个人知识库的源数据(包括 pdf、txt、md 等)和 Embedding 对象。源数据需要经过 Embedding 处理才能进入向量数据库,我们在数据层自定义了智谱提供的 Embedding API 的封装,支持上层以统一方式调用智谱 Embedding 或 OpenAI Embedding。 59 | 60 | 在上一章,我们也已详细介绍了 Embdding API 的调用及封装方式。 61 | 62 | ### 4.3 数据库层 63 | 64 | 数据库层主要存放了向量数据库文件。同时,我们在该层实现了源数据处理、创建向量数据库的方法。 65 | 66 | 我们将在第四章详细介绍向量数据库、源数据处理方法以及构建向量数据库的具体实现。 67 | 68 | ### 4.4 应用层 69 | 70 | 应用层封装了整个项目的全部核心功能。我们基于 LangChain 提供的检索问答链,在 LLM 层、数据库层的基础上,实现了本项目检索问答链的封装。自定义的检索问答链除具备基本的检索问答功能外,也支持通过 model 参数来灵活切换使用的 LLM。我们实现了两个检索问答链,分别是有历史记录的 Chat_QA_Chain 和没有历史记录的 QA_Chain。 71 | 72 | 我们将在第五章讲解 Prompt 的构造与检索问答链的构建细节。 73 | 74 | ### 4.5 服务层 75 | 76 | 服务层主要是基于应用层的核心功能封装,实现了 Demo 的搭建或 API 的封装。在本项目中,我们分别实现了通过 Gradio 搭建前端界面与 FastAPI 进行封装,支持多样化的项目调用。 77 | 78 | 我们将在第六章详细介绍如何使用 Gradio 以及 FastAPI 来实现服务层的设计。 -------------------------------------------------------------------------------- /docs/C4/3. 构建项目数据库.md: -------------------------------------------------------------------------------- 1 | # 第三章 构建项目数据库 2 | 3 | 在前面两章我们具体介绍了我们的知识库选择,并介绍了如何加载、处理数据并构建、使用向量数据库。在本章中,我们结合之前讲解的内容,具体构建出本项目使用的数据库,之后我们的 Prompt Engineeering 及迭代优化、验证评估均会在该数据库基础上进行。 4 | 5 | 在这里,我们使用 OpenAI 的 Embedding 模型实现向量化,大家也可以根据前面的讲解选用不同的 Embedding 模型。 6 | 7 | 由于此处加载向量数据库需要一定时间运行,我们也提供了 py 脚本供大家使用。 8 | 9 | 10 | ```python 11 | # 首先实现基本配置 12 | from langchain.vectorstores import Chroma 13 | from langchain.document_loaders import PyMuPDFLoader 14 | from langchain.text_splitter import RecursiveCharacterTextSplitter 15 | from langchain.document_loaders import UnstructuredMarkdownLoader 16 | from langchain.document_loaders import UnstructuredFileLoader 17 | 18 | from langchain.embeddings.openai import OpenAIEmbeddings 19 | from langchain.embeddings.huggingface import HuggingFaceEmbeddings 20 | 21 | from langchain.llms import OpenAI 22 | from langchain.llms import HuggingFacePipeline 23 | 24 | # 使用前配置自己的 api 到环境变量中如 25 | import os 26 | import openai 27 | import sys 28 | 29 | from dotenv import load_dotenv, find_dotenv 30 | 31 | _ = load_dotenv(find_dotenv()) # read local .env fileopenai.api_key = os.environ['OPENAI_API_KEY'] 32 | openai.api_key = os.environ['OPENAI_API_KEY'] 33 | ``` 34 | 35 | 接下来逐个加载知识库里的文档: 36 | 37 | 38 | ```python 39 | #pdf 40 | # 加载 PDF 41 | loaders = [ 42 | PyMuPDFLoader("../knowledge_base/pumkin_book/pumpkin_book.pdf") # 机器学习, 43 | ] 44 | docs = [] 45 | for loader in loaders: 46 | docs.extend(loader.load()) 47 | ``` 48 | 49 | 50 | ```python 51 | #md 52 | folder_path = "../knowledge_base/prompt_engineering/" 53 | files = os.listdir(folder_path) 54 | loaders = [] 55 | for one_file in files: 56 | loader = UnstructuredMarkdownLoader(os.path.join(folder_path, one_file)) 57 | loaders.append(loader) 58 | for loader in loaders: 59 | docs.extend(loader.load()) 60 | ``` 61 | 62 | 63 | ```python 64 | #mp4-txt 65 | loaders = [ 66 | UnstructuredFileLoader("../knowledge_base/easy_rl/强化学习入门指南.txt") # 机器学习, 67 | ] 68 | for loader in loaders: 69 | docs.extend(loader.load()) 70 | ``` 71 | 72 | 然后对加载好的文档进行切片并向量化后存储到向量数据库中: 73 | 74 | 75 | ```python 76 | # 切分文档 77 | text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=150) 78 | split_docs = text_splitter.split_documents(docs) 79 | 80 | 81 | # 定义 Embeddings 82 | embedding = OpenAIEmbeddings() 83 | 84 | # 定义持久化路径 85 | persist_directory = '../knowledge_base/chroma' 86 | 87 | # 加载数据库 88 | vectordb = Chroma.from_documents( 89 | documents=split_docs, 90 | embedding=embedding, 91 | persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上 92 | ) 93 | ``` 94 | 95 | Using embedded DuckDB with persistence: data will be stored in: ../knowledge_base/chroma 96 | 97 | 98 | 最后将加载好的向量数据库持久化即可: 99 | 100 | 101 | ```python 102 | vectordb.persist() 103 | ``` 104 | -------------------------------------------------------------------------------- /docs/C5/3.添加历史对话的记忆功能.md: -------------------------------------------------------------------------------- 1 | # 添加历史对话的记忆功能 2 | 3 | 现在我们已经实现了通过上传本地知识文档,然后将他们保存到向量知识库,通过将查询问题与向量知识库的召回结果进行结合输入到 LLM 中,我们就得到了一个相比于直接让 LLM 回答要好得多的结果。在与语言模型交互时,你可能已经注意到一个关键问题 - **它们并不记得你之前的交流内容**。这在我们构建一些应用程序(如聊天机器人)的时候,带来了很大的挑战,使得对话似乎缺乏真正的连续性。这个问题该如何解决呢? 4 | 5 | 6 | ## 1. 记忆(Memory) 7 | 8 | 在本节中我们将介绍 LangChain 中的储存模块,即如何将先前的对话嵌入到语言模型中的,使其具有连续对话的能力。我们将使用 `ConversationBufferMemory` ,它保存聊天消息历史记录的列表,这些历史记录将在回答问题时与问题一起传递给聊天机器人,从而将它们添加到上下文中。 9 | 10 | 11 | ```python 12 | from langchain.memory import ConversationBufferMemory 13 | 14 | memory = ConversationBufferMemory( 15 | memory_key="chat_history", # 与 prompt 的输入变量保持一致。 16 | return_messages=True # 将以消息列表的形式返回聊天记录,而不是单个字符串 17 | ) 18 | ``` 19 | 20 | 关于更多的 Memory 的使用,包括保留指定对话轮数、保存指定 token 数量、保存历史对话的总结摘要等内容,请参考 langchain 的 Memory 部分的相关文档。 21 | 22 | ## 2. 对话检索链(ConversationalRetrievalChain) 23 | 24 | 对话检索链(ConversationalRetrievalChain)在检索 QA 链的基础上,增加了处理对话历史的能力。 25 | 26 | 它的工作流程是: 27 | 1. 将之前的对话与新问题合并生成一个完整的查询语句。 28 | 2. 在向量数据库中搜索该查询的相关文档。 29 | 3. 获取结果后,存储所有答案到对话记忆区。 30 | 4. 用户可在 UI 中查看完整的对话流程。 31 | 32 | ![](../figures/Modular_components.png) 33 | 34 | 这种链式方式将新问题放在之前对话的语境中进行检索,可以处理依赖历史信息的查询。并保留所有信 35 | 息在对话记忆中,方便追踪。 36 | 37 | 接下来让我们可以测试这个对话检索链的效果: 38 | 39 | 先加载一下上一节中的向量数据库和 LLM ! 40 | 41 | 42 | ```python 43 | from langchain.vectorstores import Chroma 44 | from langchain.embeddings.openai import OpenAIEmbeddings # 调用 OpenAI 的 Embeddings 模型 45 | import openai 46 | from dotenv import load_dotenv, find_dotenv 47 | import os 48 | 49 | _ = load_dotenv(find_dotenv()) # read local .env file 50 | openai.api_key = os.environ['OPENAI_API_KEY'] 51 | 52 | # 定义 Embeddings 53 | embedding = OpenAIEmbeddings() 54 | # 向量数据库持久化路径 55 | persist_directory = '../knowledge_base/chroma' 56 | # 加载数据库 57 | vectordb = Chroma( 58 | persist_directory=persist_directory, # 允许我们将persist_directory目录保存到磁盘上 59 | embedding_function=embedding 60 | ) 61 | 62 | # 创建LLM 63 | from langchain.chat_models import ChatOpenAI 64 | llm = ChatOpenAI(model_name = "gpt-3.5-turbo", temperature = 0 ) 65 | ``` 66 | 67 | 首先提出一个无历史对话的问题“这门课会学习 Python 吗?”,并查看回答。 68 | 69 | 70 | ```python 71 | from langchain.chains import ConversationalRetrievalChain 72 | 73 | retriever=vectordb.as_retriever() 74 | 75 | qa = ConversationalRetrievalChain.from_llm( 76 | llm, 77 | retriever=retriever, 78 | memory=memory 79 | ) 80 | question = "我可以学习到关于强化学习的知识吗?" 81 | result = qa({"question": question}) 82 | print(result['answer']) 83 | ``` 84 | 85 | 是的,根据提供的上下文,这门课程会教授关于强化学习的知识。 86 | 87 | 88 | 然后基于答案进行下一个问题“为什么这门课需要教这方面的知识?”: 89 | 90 | 91 | ```python 92 | question = "为什么这门课需要教这方面的知识?" 93 | result = qa({"question": question}) 94 | print(result['answer']) 95 | ``` 96 | 97 | 这门课需要教授关于强化学习的知识,是因为强化学习是一种用来学习如何做出一系列好的决策的方法。在人工智能领域,强化学习的应用非常广泛,可以用于控制机器人、实现自动驾驶、优化推荐系统等。学习强化学习可以帮助我们理解和应用这一领域的核心算法和方法,从而更好地解决实际问题。 98 | 99 | 100 | 可以看到,LLM 它准确地判断了这方面的知识,指代内容是强化学习的知识,也就 101 | 是我们成功地传递给了它历史信息。这种持续学习和关联前后问题的能力,可大大增强问答系统的连续 102 | 性和智能水平。 103 | 104 | 105 | -------------------------------------------------------------------------------- /docs/C6/1. 验证迭代的一般思路.md: -------------------------------------------------------------------------------- 1 | # 一、验证迭代的一般思路 2 | 3 | 根据前文所讲解的大模型开发流程,我们可以发现,以调用、发挥大模型为核心的大模型开发相较传统的 AI 开发更注重验证迭代。由于你可以快速构建出基于 LLM 的应用程序,在几分钟内定义一个 Prompt,并在几小时内得到反馈结果,那么停下来收集一千个测试样本就会显得极为繁琐。因为现在,你可以在没有任何训练样本的情况下得到结果。 4 | 5 | 因此,在使用LLM构建应用程序时,你可能会经历以下流程:首先,你会在一到三个样本的小样本中调整 Prompt ,尝试使其在这些样本上起效。随后,当你对系统进行进一步测试时,可能会遇到一些棘手的例子,这些例子无法通过 Prompt 或者算法解决。这就是使用 LLM 构建应用程序的开发者所面临的挑战。在这种情况下,你可以将这些额外的几个例子添加到你正在测试的集合中,有机地添加其他难以处理的例子。最终,你会将足够多的这些例子添加到你逐步扩大的开发集中,以至于手动运行每一个例子以测试 Prompt 变得有些不便。然后,你开始开发一些用于衡量这些小样本集性能的指标,例如平均准确度。这个过程的有趣之处在于,如果你觉得你的系统已经足够好了,你可以随时停止,不再进行改进。实际上,很多已经部署的应用程序就在第一步或第二步就停下来了,而且它们运行得非常好。 6 | 7 | ![](../figures/eval.png) 8 | 9 | 在上一章 Prompt Engineering 部分,我们已经讲解了如何在数个简单样例的基础上设计 Prompt Engineering,初步实现核心任务的启动。 10 | 11 | 在本章中,我们将逐个介绍接下来的几个步骤,并设计本项目验证迭代的过程,从而实现应用功能的优化。 12 | 13 | 我们将首先介绍如何找出 Bad Case 的一些思路提示,以及针对 Bad Case 针对性做出 Prompt 优化的一般思路。注意,在这一过程中,你仍然应该谨记我们在上一节中所讲述的 Prompt 设计原则与技巧,并时刻保证优化后的 Prompt 不会在原先表现良好的样例上出现失误。 14 | 15 | 接着,我们将简要介绍大模型开发评估的几种方法。对于有简单标准答案的任务来说,评估很容易得到实现;但大模型开发一般是需要实现复杂的生成任务,如何在没有简单答案甚至没有标准答案的情况下实现评估,能够准确地反映应用的效果,我们将简要介绍几种方法。 16 | 17 | 最后,随着我们不断寻找到 Bad Case 并做出针对性优化,我们可以将这些 Bad Case 逐步加入到验证集,从而形成一个有一定样例数的验证集。针对这种验证集,一个一个进行评估就是不切实际的了。我们需要一种自动评估方法,实现对该验证集上性能的整体评估。 18 | 19 | 验证迭代是构建以 LLM 为中心的应用程序所必不能少的重要步骤,通过不断寻找 Bad Case,针对性调整 Prompt 或优化应用框架,来推动应用达到我们目标中的性能与精度。接下来,我们将简要介绍大模型开发评估的几种方法,并概括性介绍从少数 Bad Case 针对性优化到整体自动化评估的一般思路。 -------------------------------------------------------------------------------- /docs/C7/2. fast api 进行前后端分离.md: -------------------------------------------------------------------------------- 1 | # Fast api 进行前后端分离 💬 2 | 3 | 目前我们已经完成了基本的可视化页面,并且可以实现对应的功能。 4 | 5 | 为了方便整个项目的管理,现有的项目通常采用前后端分离的方式搭建,前后端数据通过 json 的格式进行传输。 6 | 7 | 8 | FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,非常方便用于搭建我们的前后端分离的应用。 9 | 10 | 我们首先需要将我们用到的后端函数进行 FastAPI 的封装。封装 API 与前文中讲过将大模型 API 封装成本地 API 的方法类似,我们首先导入第三方库并创建一个 API 对象: 11 | 12 | 13 | ```python 14 | from fastapi import FastAPI 15 | from pydantic import BaseModel 16 | import os 17 | 18 | app = FastAPI() # 创建 api 对象 19 | ``` 20 | 21 | 本地 API 一般通过 POST 方式进行访问,即参数会附加在 POST 请求中,我们需要定义一个数据模型来接收 POST 请求中的数据: 22 | 23 | 24 | ```python 25 | # 定义一个数据模型,用于接收POST请求中的数据 26 | class Item(BaseModel): 27 | prompt : str # 用户 prompt 28 | model : str # 使用的模型 29 | temperature : float = 0.1# 温度系数 30 | if_history : bool = False # 是否使用历史对话功能 31 | # API_Key 32 | api_key: str = None 33 | # Secret_Key 34 | secret_key : str = None 35 | # access_token 36 | access_token: str = None 37 | # APPID 38 | appid : str = None 39 | # APISecret 40 | api_secret : str = None 41 | # 数据库路径 42 | db_path : str = "../database" 43 | # prompt template 44 | prompt_template : str = None 45 | # Template 变量 46 | input_variables : list = ["context","question"] 47 | # Embdding 48 | embedding : str = "openai" 49 | # Top K 50 | top_k : int = 5 51 | ``` 52 | 53 | 在上面的类中,我们定义了要调用我们已封装的 QA_chain 所需要传入的参数,对于非必须参数,我们都设置了默认参数来保证调用的简洁性,接下来我们就可以创建一个 POST 请求的 API 端点: 54 | 55 | 56 | ```python 57 | @app.post("/answer/") 58 | async def get_response(item: Item): 59 | 60 | # 首先确定需要调用的链 61 | if not item.if_history: 62 | # 调用 Chat 链 63 | chain = QA_chain_self(item.db_path, item.model, item.prompt_template, 64 | item.input_variables, item.temperature, item.api_key, 65 | item.secret_key, item.access_token, item.appid, item.api_secret, item.embedding) 66 | 67 | response = chain.answer(question = item.prompt, top_k = item.top_k, temperature = item.temperature) 68 | 69 | return response 70 | 71 | # 由于 API 存在即时性问题,不能支持历史链 72 | else: 73 | return "API 不支持历史链" 74 | ``` 75 | 76 | 上述端点的业务逻辑很简单,即调用我们已封装的 QA_chain_self 对象进行实例化与回答即可。通过这一个端点启动,我们便可通过访问本地 8000 端口来调用个人知识库助手的服务啦,我们只需要通过下列命令启动: 77 | 78 | 79 | ```python 80 | uvicorn app:app 81 | ``` 82 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # 动手学大模型应用开发 2 | 3 | ## 项目简介 4 | 5 | 本项目是一个面向小白开发者的大模型应用开发教程,旨在结合个人知识库助手项目,通过一个课程完成大模型开发的重点入门,主要内容包括: 6 | 7 | 1. 大模型简介,何为大模型、大模型特点是什么、LangChain 是什么,针对小白开发者的简单介绍; 8 | 2. 如何调用大模型 API,本节介绍了国内外知名大模型产品 API 的多种调用方式,包括调用原生 API、封装为 LangChain LLM、封装为 Fastapi 等调用方式,同时将包括百度文心、讯飞星火、智谱AI等多种大模型 API 进行了统一形式封装; 9 | 3. 大模型开发流程及架构,大模型应用开发的基本流程、一般思想和本项目的架构分析; 10 | 4. 数据库搭建,不同类型知识库文档的加载、处理,向量数据库的搭建; 11 | 5. Prompt 设计,如何设计 Prompt 来让大模型完成特定任务,Prompt Engineering 的原则和技巧有哪些; 12 | 6. 验证迭代,大模型开发如何实现验证迭代,一般的评估方法有什么; 13 | 7. 前后端开发,如何使用 Gradio、FastAPI 等框架快速开发大模型 Demo,展示应用能力。 14 | 15 | 16 | **目录结构说明:** 17 | 18 | notebook:教程源码,可运行的 Notebook,更新频率最高,更新速度最快。 19 | docs:在线阅读版本,基于 notebook 源码订正。 20 | figures:图片文件。 21 | project:个人知识库助手项目代码。 22 | 23 | ## 立项理由 24 | 25 | LLM 正逐步成为信息世界的新革命力量,其通过强大的自然语言理解、自然语言生成能力,为开发者提供了新的、更强大的应用开发选择。随着国内外井喷式的 LLM API 服务开放,如何基于 LLM API 快速、便捷地开发具备更强能力、集成 LLM 的应用,开始成为开发者的一项重要技能。 26 | 27 | 目前,关于 LLM 的介绍以及零散的 LLM 开发技能课程已有不少,但质量参差不齐,且没有很好地整合,开发者需要搜索大量教程并阅读大量相关性不强、必要性较低的内容,才能初步掌握大模型开发的必备技能,学习效率低,学习门槛也较高。 28 | 29 | 本项目从实践出发,结合最常见、通用的个人知识库助手项目,深入浅出逐步拆解 LLM 开发的一般流程、步骤,旨在帮助没有算法基础的小白通过一个课程完成大模型开发的基础入门。同时,我们也对项目本身做了清晰、全面的逐层规划及封装,实现了不同 LLM API 到项目的统一整合,帮助开发者能够自由、统一调用不同 LLM,充分降低学习门槛。 30 | 31 | ## 项目受众 32 | 33 | 所有具备基础 Python 能力,想要掌握 LLM 应用开发技能的开发者。 34 | 35 | 本项目对学习者的人工智能基础、算法基础没有任何要求,仅需要掌握基本 Python 语法、掌握初级 Python 开发技能即可。 36 | 37 | 本项目对本地硬件基本没有要求,不需要 GPU 环境,个人电脑及服务器均可用于学习。 38 | 39 | ## 项目亮点 40 | 41 | 1. 充分面向实践,动手学习大模型开发。相较于其他从理论入手、与实践代差较大的类似教程,本教程基于具有通用性的个人知识库助手项目打造,将普适的大模型开发理念融合在项目实践中,帮助学习者通过动手搭建个人项目来掌握大模型开发技能。 42 | 43 | 2. 从零开始,全面又简短的大模型教程。本项目针对个人知识库助手项目,对相关大模型开发理论、概念和基本技能进行了项目主导的重构,删去不需要理解的底层原理和算法细节,涵盖所有大模型开发的核心技能。教程整体时长在数小时之内,但学习完本教程,可以掌握基础大模型开发的所有核心技能。 44 | 45 | 3. 兼具统一性与拓展性。本项目对 GPT、百度文心、讯飞星火、智谱GLM 等国内外主要 LLM API 进行了统一封装,支持一键调用不同的 LLM,帮助开发者将更多的精力放在学习应用与模型本身的优化上,而不需要花时间在繁琐的调用细节上;同时,本教程拟上线 [奇想星球 | AIGC共创社区平台](https://1aigc.cn/),支持学习者自定义项目为本教程增加拓展内容,具备充分的拓展性。 46 | 47 | ## 项目规划 48 | 49 | ### 时间规划 50 | 51 | 2023.10.01~2023.10.22 完成初稿 52 | 2023.10.23~10.31 内测 53 | 2023.11.01 开放公测 54 | 2023.11.15 正式上线 55 | 56 | ### 示例 57 | 58 | 正在开发仓库:https://github.com/logan-zou/Tutorial_for_developing_LLM_application 59 | 60 | 61 | ### 内容大纲及对应负责人 62 | 63 | **目录:** 64 | 65 | 第一章 大模型简介 @徐虎 66 | 67 | 1. 什么是大模型 68 | 2. 大模型的能力、特点 69 | 3. 常见大模型 70 | 4. 什么是 LangChain 71 | 72 | 第二章 调用大模型 API @邹雨衡 73 | 74 | 1. 基本概念 75 | 2. 调用 ChatGPT 76 | 3. 调用百度文心 77 | 4. 调用讯飞星火 78 | 5. 调用智谱GLM 79 | 6. 总结 80 | 81 | 第三章 大模型开发流程及架构 @邹雨衡 82 | 83 | 1. 大模型一般开发流程简介 84 | 2. 个人知识库助手项目流程简析 85 | 86 | 第四章 数据库搭建 @高立业 87 | 88 | 1. 知识库文档处理 89 | 2. 向量数据库简介及使用 90 | 3. 构建项目数据库 91 | 92 | 第五章 Prompt 设计 @徐虎 93 | 94 | 1. Prompt 设计的原则及技巧 95 | 2. 基于问答助手的 Prompt 构建 96 | 3. 添加历史对话功能 97 | 98 | 第六章 验证迭代 @邹雨衡 99 | 100 | 1. 验证迭代的一般思路 101 | 2. 解决 Bad Case 102 | 3. 大模型评估方法 103 | 104 | 第七章 前后端搭建 @高立业 105 | 106 | 1. Gradio 简介与页面搭建 107 | 2. FastAPI 进行前后端分离 108 | 109 | 第八章 总结及拓展 @邹雨衡 110 | 111 | 112 | ## 项目负责人 113 | 114 | 邹雨衡 115 | 116 | 微信:Logan12120421 117 | 118 | Github主页:https://github.com/logan-zou 119 | 120 | -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | * [目录](README.md) 2 | * 第一章 大模型简介 3 | * [1. 概述](C1/1.%20什么是⼤模型.md) 4 | * [2. 大模型的能力、特点](C1/2.%20⼤模型的能⼒和特点.md) 5 | * [3. 常见大模型](C1/3.%20常⻅⼤模型.md) 6 | * [4. 什么是LangChain](C1/4.%20什么是%20LangChain.md) 7 | * 第二章 调用大模型API 8 | * [1. 基本概念](C2/1.%20基本概念.md) 9 | * [2. 调用ChatGPT](C2/2.%20调用ChatGPT.md) 10 | * [3. 调用百度文心](C2/3.%20调用百度文心.md) 11 | * [4. 调用讯飞星火](C2/4.%20调用讯飞星火.md) 12 | * [5. 调用智谱GLM](C2/5.%20调用智谱%20AI(ChatGLM).md) 13 | * [6. 调用智谱GLM Embedding](C2/6.%20调用智谱%20AI(ChatGLM)生成%20embedding.md) 14 | * [7. 总结](C2/7.%20总结.md) 15 | * [附1. LangChain自定义LLM](C2/附1.LangChain自定义%20LLM.md) 16 | * [附2. 将大模型API封装成本地API](C2/附2.将大模型%20API%20封装成本地%20API.md) 17 | * [附3. LangChain自定义Embedding](C2/附3.LangChain%20自定义%20LLM%20embedding.md) 18 | * 第三章 大模型开发流程及架构 19 | * [1. 大模型开发流程](C3/1.%20大模型开发流程.md) 20 | * [2. 项目流程简析](C3/2.%20项目流程简析.md) 21 | * [3. 项目架构简析](C3/3.%20项目架构简析.md) 22 | * 第四章 数据库搭建 23 | * [1. 知识库文档处理](C4/1.%20知识库文档处理.md) 24 | * [2. 向量数据库的介绍及使用](C4/2.%20向量数据库的介绍及使用.md) 25 | * [3. 构建项目数据库](C4/3.%20构建项目数据库.md) 26 | * 第五章 Prompt设计 27 | * [1. Prompt设计的原则和技巧](C5/1.Prompt%20设计的原则和技巧.md) 28 | * [2. 基于问答助手的Prompt构建](C5/2.基于问答助⼿的%20Prompt%20构建.md) 29 | * [3. 添加历史对话的记忆功能](C5/3.添加历史对话的记忆功能.md) 30 | * 第六章 验证迭代 31 | * [1. 验证迭代的一般思路](C6/1.%20验证迭代的一般思路.md) 32 | * [2. 解决Bad Case](C6/2.%20解决Bad%20Case.md) 33 | * [3. 大模型评估方法](C6/3.%20大模型评估方法.md) 34 | * 第七章 前后端搭建 35 | * [1. Gradio 搭建界面](C7/1.%20Gradio%20的介绍与前端界面的搭建.md) 36 | * [2. FastAPI 前后端分离](C7/2.%20fast%20api%20进行前后端分离.md) 37 | -------------------------------------------------------------------------------- /docs/figures/2023-10-02-12-57-39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/2023-10-02-12-57-39.png -------------------------------------------------------------------------------- /docs/figures/AI_eval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/AI_eval.png -------------------------------------------------------------------------------- /docs/figures/Agents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/Agents.png -------------------------------------------------------------------------------- /docs/figures/Bard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/Bard.png -------------------------------------------------------------------------------- /docs/figures/Claude.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/Claude.png -------------------------------------------------------------------------------- /docs/figures/GPT-series.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/GPT-series.png -------------------------------------------------------------------------------- /docs/figures/LLM_developing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/LLM_developing.png -------------------------------------------------------------------------------- /docs/figures/LLM_developing_whole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/LLM_developing_whole.png -------------------------------------------------------------------------------- /docs/figures/LLM_eval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/LLM_eval.png -------------------------------------------------------------------------------- /docs/figures/LLMs-0623-final.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/LLMs-0623-final.png -------------------------------------------------------------------------------- /docs/figures/Modular_components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/Modular_components.png -------------------------------------------------------------------------------- /docs/figures/Summary_of_Closed_Source_LLM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/Summary_of_Closed_Source_LLM.png -------------------------------------------------------------------------------- /docs/figures/Summary_of_Open_Source_LLM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/Summary_of_Open_Source_LLM.png -------------------------------------------------------------------------------- /docs/figures/baichuan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/baichuan.png -------------------------------------------------------------------------------- /docs/figures/baidu_qianfan_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/baidu_qianfan_1.png -------------------------------------------------------------------------------- /docs/figures/baidu_qianfan_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/baidu_qianfan_2.png -------------------------------------------------------------------------------- /docs/figures/baidu_qianfan_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/baidu_qianfan_3.png -------------------------------------------------------------------------------- /docs/figures/baidu_qianfan_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/baidu_qianfan_4.png -------------------------------------------------------------------------------- /docs/figures/chatglm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/chatglm.png -------------------------------------------------------------------------------- /docs/figures/data_collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/data_collection.png -------------------------------------------------------------------------------- /docs/figures/eval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/eval.png -------------------------------------------------------------------------------- /docs/figures/example-splitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/example-splitter.png -------------------------------------------------------------------------------- /docs/figures/flow_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/flow_chart.png -------------------------------------------------------------------------------- /docs/figures/langchain_model_input_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/langchain_model_input_output.png -------------------------------------------------------------------------------- /docs/figures/memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/memory.png -------------------------------------------------------------------------------- /docs/figures/openai-choose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/openai-choose.png -------------------------------------------------------------------------------- /docs/figures/openai-get-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/openai-get-key.png -------------------------------------------------------------------------------- /docs/figures/prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/prompt.png -------------------------------------------------------------------------------- /docs/figures/prompt_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/prompt_example.png -------------------------------------------------------------------------------- /docs/figures/recently_LLM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/recently_LLM.png -------------------------------------------------------------------------------- /docs/figures/spark_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/spark_1.png -------------------------------------------------------------------------------- /docs/figures/spark_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/spark_2.png -------------------------------------------------------------------------------- /docs/figures/structure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/structure.jpg -------------------------------------------------------------------------------- /docs/figures/types-of-splitters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/types-of-splitters.png -------------------------------------------------------------------------------- /docs/figures/zhipuai_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/zhipuai_api.png -------------------------------------------------------------------------------- /docs/figures/zhipuai_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/zhipuai_home.png -------------------------------------------------------------------------------- /docs/figures/zhipuai_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/zhipuai_overview.png -------------------------------------------------------------------------------- /docs/figures/zhipuai_pay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/zhipuai_pay.png -------------------------------------------------------------------------------- /docs/figures/文心一言.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/文心一言.PNG -------------------------------------------------------------------------------- /docs/figures/星火.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/星火.png -------------------------------------------------------------------------------- /docs/figures/通义千问.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/docs/figures/通义千问.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 动手学大模型应用开发 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 |

16 | 17 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /figures/2023-10-02-12-57-39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/2023-10-02-12-57-39.png -------------------------------------------------------------------------------- /figures/AI_eval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/AI_eval.png -------------------------------------------------------------------------------- /figures/Agents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/Agents.png -------------------------------------------------------------------------------- /figures/Bard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/Bard.png -------------------------------------------------------------------------------- /figures/Claude.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/Claude.png -------------------------------------------------------------------------------- /figures/GPT-series.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/GPT-series.png -------------------------------------------------------------------------------- /figures/LLM_developing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/LLM_developing.png -------------------------------------------------------------------------------- /figures/LLM_developing_whole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/LLM_developing_whole.png -------------------------------------------------------------------------------- /figures/LLM_eval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/LLM_eval.png -------------------------------------------------------------------------------- /figures/LLMs-0623-final.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/LLMs-0623-final.png -------------------------------------------------------------------------------- /figures/Modular_components.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/Modular_components.png -------------------------------------------------------------------------------- /figures/Summary_of_Closed_Source_LLM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/Summary_of_Closed_Source_LLM.png -------------------------------------------------------------------------------- /figures/Summary_of_Open_Source_LLM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/Summary_of_Open_Source_LLM.png -------------------------------------------------------------------------------- /figures/baichuan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/baichuan.png -------------------------------------------------------------------------------- /figures/baidu_qianfan_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/baidu_qianfan_1.png -------------------------------------------------------------------------------- /figures/baidu_qianfan_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/baidu_qianfan_2.png -------------------------------------------------------------------------------- /figures/baidu_qianfan_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/baidu_qianfan_3.png -------------------------------------------------------------------------------- /figures/baidu_qianfan_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/baidu_qianfan_4.png -------------------------------------------------------------------------------- /figures/chatglm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/chatglm.png -------------------------------------------------------------------------------- /figures/data_collection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/data_collection.png -------------------------------------------------------------------------------- /figures/eval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/eval.png -------------------------------------------------------------------------------- /figures/example-splitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/example-splitter.png -------------------------------------------------------------------------------- /figures/flow_chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/flow_chart.png -------------------------------------------------------------------------------- /figures/langchain_model_input_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/langchain_model_input_output.png -------------------------------------------------------------------------------- /figures/memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/memory.png -------------------------------------------------------------------------------- /figures/openai-choose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/openai-choose.png -------------------------------------------------------------------------------- /figures/openai-get-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/openai-get-key.png -------------------------------------------------------------------------------- /figures/prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/prompt.png -------------------------------------------------------------------------------- /figures/prompt_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/prompt_example.png -------------------------------------------------------------------------------- /figures/recently_LLM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/recently_LLM.png -------------------------------------------------------------------------------- /figures/spark_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/spark_1.png -------------------------------------------------------------------------------- /figures/spark_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/spark_2.png -------------------------------------------------------------------------------- /figures/structure.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/structure.jpg -------------------------------------------------------------------------------- /figures/types-of-splitters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/types-of-splitters.png -------------------------------------------------------------------------------- /figures/zhipuai_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/zhipuai_api.png -------------------------------------------------------------------------------- /figures/zhipuai_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/zhipuai_home.png -------------------------------------------------------------------------------- /figures/zhipuai_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/zhipuai_overview.png -------------------------------------------------------------------------------- /figures/zhipuai_pay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/zhipuai_pay.png -------------------------------------------------------------------------------- /figures/文心一言.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/文心一言.PNG -------------------------------------------------------------------------------- /figures/星火.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/星火.png -------------------------------------------------------------------------------- /figures/通义千问.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/figures/通义千问.png -------------------------------------------------------------------------------- /notebook/C1 大模型简介/1. 什么是⼤模型.md: -------------------------------------------------------------------------------- 1 | 2 | # 一. 什么是LLM(大语言模型)? 3 | 4 | ## 1. 发展历程 5 | 6 | 语言建模的研究始于`20世纪90年代`,最初采用了统计学习方法,通过前面的词汇来预测下一个词汇。然而,这种方法在理解复杂语言规则方面存在一定局限性。 7 | 8 | 随后,研究人员不断尝试改进,其中在`2003年`,深度学习先驱**Bengio**在他的经典论文《A Neural Probabilistic Language Model》中,首次将深度学习的思想融入到语言模型中,使用了更强大的**神经网络模型**,这相当于为计算机提供了更强大的"大脑"来理解语言。这种方法让模型可以更好地捕捉语言中的复杂关系,虽然这一步很重要,但仍有改进的空间。 9 | 10 | 大约在`2018年左右`,研究人员引入了**Transformer架构的神经网络模型**,通过大量文本数据训练这些模型,使它们能够通过阅读大量文本来深入理解语言规则和模式,就像让计算机阅读整个互联网一样。所以它对语言有了更深刻的理解。这种方法在很多任务上表现得非常好。 11 | 12 | 与此同时,研究人员发现,随着语言模型规模的扩大(增加模型大小或使用更多数据),模型展现出了一些惊人的能力,通常在各种任务中表现显著提升。这时我们进入了大语言模型(LLM)时代。 13 | 14 | ## 2. 大语言模型的概念 15 | 16 | **大语言模型(英文:Large Language Model,缩写LLM),也称大型语言模型,是一种人工智能模型,旨在理解和生成人类语言**。 17 | 18 | 通常,大语言模型 (LLM) 指包含**数百亿(或更多)参数的语言模型**,这些模型在大量的文本数据上进行训练,例如国外的有GPT-3 、GPT-4、PaLM 、Galactica 和 LLaMA 等,国内的有ChatGLM、文心一言、通义千问、讯飞星火等。 19 | 20 | 在这个阶段,计算机的“大脑”变得非常巨大,拥有数十亿甚至数千亿的参数。这就像是将计算机的大脑升级到了一个巨型超级计算机。这让计算机可以在各种任务上表现得非常出色,有时甚至比人类还要聪明。 21 | 22 | 为了探索性能的极限,许多研究人员开始训练越来越庞大的语言模型 ,例如拥有1750亿参数的 GPT-3 和5400亿参数的 PaLM 。尽管这些大型语言模型与小型语言模型(例如 BERT 的3.3亿参数和 GPT-2 的15亿参数)使用相似的架构和预训练任务,但它们展现出截然不同的能力,尤其在解决复杂任务时表现出了惊人的潜力,这被称为“**涌现能力**”。以 GPT-3 和 GPT-2 为例,GPT-3 可以通过学习上下文来解决少样本任务,而 GPT-2 在这方面表现较差。因此,研究界给这些庞大的语言模型起了个名字,称之为“大语言模型(LLM)”。而 LLM 的一个杰出应用就是 **ChatGPT** ,它是 GPT 系列 LLM 用于与人类对话式应用的大胆尝试,展现出了非常流畅和自然的表现。 23 | 24 | 25 | 26 | ### LLM的应用和影响 27 | 28 | LLM已经在许多领域产生了深远的影响。在**自然语言处理**领域,它可以帮助计算机更好地理解和生成文本,包括写文章、回答问题、翻译语言等。在**信息检索**领域,它可以改进搜索引擎,让我们更轻松地找到所需的信息。在**计算机视觉**领域,研究人员还在努力让计算机理解图像和文字,以改善多媒体交互。 29 | 30 | 最重要的是,LLM的出现让人们重新思考了**通用人工智能(AGI)**的可能性。AGI 是一种像人类一样思考和学习的人工智能。LLM 被认为是 AGI 的一种早期形式,这引发了对未来人工智能发展的许多思考和计划。 31 | 32 | 总之,LLM 是一种令人兴奋的技术,它让计算机更好地理解和使用语言,正在改变着我们与技术互动的方式,同时也引发了对未来人工智能的无限探索。希望这篇文章让你对LLM有了更清晰的认识! 33 | 34 | 35 | 36 | 【**参考内容**】: 37 | https://arxiv.org/abs/2303.18223 38 | -------------------------------------------------------------------------------- /notebook/C1 大模型简介/2. ⼤模型的能⼒、特点.md: -------------------------------------------------------------------------------- 1 | 2 | # 大模型的能力和特点 3 | 4 | 5 | ## 1. 大模型的能力 6 | 7 | ### 1.1 涌现能力(emergent abilities) 8 | 9 | 区分大语言模型(LLM)与以前的预训练语言模型(PLM)最显著的特征之一是它们的`涌现能力`。涌现能力指的是一种令人惊讶的能力,它在小型模型中不明显,但在大型模型中显著出现。可以类比到物理学中的相变现象,涌现能力的显现就像是模型性能随着规模增大而迅速提升,超过了随机水平,也就是我们常说的量变引起了质变。 10 | 11 | 具体来说,涌现能力可以定义为与某些复杂任务相关的能力,但我们更关注的是它们具备的通用能力,也就是能够应用于解决各种任务的能力。接下来,让我们简要介绍三个典型的LLM涌现能力: 12 | 13 | 1. **上下文学习**:上下文学习能力是由 GPT-3 首次引入的。这种能力允许语言模型在提供自然语言指令或多个任务示例的情况下,通过理解上下文并生成相应输出的方式来执行任务,而无需额外的训练或参数更新。 14 | 15 | 2. **指令遵循**:通过使用自然语言描述的多任务数据进行微调,也就是所谓的指令微调,LLM 被证明在同样使用指令形式化描述的未见过的任务上表现良好。这意味着LLM能够根据任务指令执行任务,而无需事先见过具体示例,这展示了其强大的泛化能力。 16 | 17 | 3. **逐步推理**:小型语言模型通常难以解决涉及多个推理步骤的复杂任务,例如数学问题。然而,LLM通过采用"思维链"推理策略,可以利用包含中间推理步骤的提示机制来解决这些任务,从而得出最终答案。据推测,这种能力可能是通过对代码的训练获得的。 18 | 19 | 这些涌现能力让LLM在处理各种任务时表现出色,使它们成为了解决复杂问题和应用于多领域的强大工具。 20 | 21 | ### 1.2 作为基座模型支持多元应用的能力 22 | 23 | 在2021年,斯坦福大学等多所高校的研究人员提出了基座模型(foundation model)的概念,这更清晰地描述了之前学界所称的预训练模型的作用。这是一种全新的AI技术范式,借助于海量无标注数据的训练,获得可以适用于大量下游任务的大模型(单模态或者多模态)。这样,多个应用可以只依赖于一个或少数几个大模型进行统一建设 24 | 25 | 大语言模型是这个新模式的典型例子,使用统一的大模型可以极大地提高研发效率,相比于分散的模型开发方式,这是一项本质上的进步。大型模型不仅可以缩短每个具体应用的开发周期,减少所需人力投入,也可以基于大模型的推理、常识和写作能力,获得更好的应用效果。因此,大模型可以成为AI应用开发的大一统基座模型,这是一个一举多得、全新的范式,值得大力推广 26 | 27 | 28 | ### 1.3 支持对话作为统一入口的能力 29 | 30 | 让大语言模型真正火爆的契机,是基于对话聊天的ChatGPT。事实上,业界很早就发现了用户对于对话交互的特殊偏好,陆奇在微软期间2016年就推进“对话即平台(conversation as a platform)”的战略。此外,苹果Siri、亚马逊Echo等基于语音对话的产品也非常受欢迎,反映出互联网用户对于聊天和对话这种交互模式的偏好。虽然之前的聊天机器人存在各种问题,但大型语言模型的出现再次让聊天机器人这种交互模式可以重新想像。用户愈发期待像钢铁侠中“贾维斯”一样的人工智能,无所不能、无所不知。这引发我们对于智能体(Agent)类型应用前景的思考,Auto-GPT、微软Jarvis等项目已经出现并受到关注,相信未来会涌现出很多类似的以对话形态让助手完成各种具体工作的项目 31 | 32 | ## 2.大模型的特点 33 | 34 | 大语言模型(LLM,Large Language Models)具有多种显著特点,这些特点使它们在自然语言处理和其他领域中引起了广泛的兴趣和研究。以下是大语言模型的一些主要特点: 35 | 36 | 1. **巨大的规模:** LLM通常具有巨大的参数规模,可以达到数十亿甚至数千亿个参数。这使得它们能够捕捉更多的语言知识和复杂的语法结构。 37 | 38 | 2. **预训练和微调:** LLM采用了预训练和微调的学习方法。它们首先在大规模文本数据上进行预训练(无标签数据),学会了通用的语言表示和知识,然后通过微调(有标签数据)适应特定任务,从而在各种NLP任务中表现出色。 39 | 40 | 3. **上下文感知:** LLM在处理文本时具有强大的上下文感知能力,能够理解和生成依赖于前文的文本内容。这使得它们在对话、文章生成和情境理解方面表现出色。 41 | 42 | 4. **多语言支持:** LLM可以用于多种语言,不仅限于英语。它们的多语言能力使得跨文化和跨语言的应用变得更加容易。 43 | 44 | 5. **多模态支持:** 一些LLM已经扩展到支持多模态数据,包括文本、图像和声音。这意味着它们可以理解和生成不同媒体类型的内容,实现更多样化的应用。 45 | 46 | 6. **涌现能力:** LLM表现出令人惊讶的涌现能力,即在大规模模型中出现但在小型模型中不明显的性能提升。这使得它们能够处理更复杂的任务和问题。 47 | 48 | 7. **多领域应用:** LLM已经被广泛应用于文本生成、自动翻译、信息检索、摘要生成、聊天机器人、虚拟助手等多个领域,对人们的日常生活和工作产生了深远的影响。 49 | 50 | 8. **伦理和风险问题:** 尽管LLM具有出色的能力,但它们也引发了伦理和风险问题,包括生成有害内容、隐私问题、认知偏差等。因此,研究和应用LLM需要谨慎。 51 | 52 | 总之,大语言模型是一种具有强大语言处理能力的技术,已经在多个领域展示了潜力。它们为自然语言理解和生成任务提供了强大的工具,同时也引发了对其伦理和风险问题的关注。这些特点使LLM成为了当今计算机科学和人工智能领域的重要研究和应用方向。 53 | 54 | 55 | 参考内容: 56 | https://arxiv.org/abs/2303.18223 57 | https://xueqiu.com/1389978604/248392718 -------------------------------------------------------------------------------- /notebook/C1 大模型简介/4. 什么是 LangChain.md: -------------------------------------------------------------------------------- 1 | # 什么是 LangChain 2 | 3 | ChatGPT 的巨大成功激发了越来越多的开发者兴趣,他们希望利用 OpenAI 提供的 API 或者私有化模型,来开发基于大型语言模型的应用程序。尽管大型语言模型的调用相对简单,但要创建完整的应用程序,仍然需要大量的定制开发工作,包括API集成、互动逻辑、数据存储等等。 4 | 5 | 为了解决这个问题,从2022年开始,许多机构和个人相继推出了多个开源项目,旨在**帮助开发者们快速构建基于大型语言模型的端到端应用程序或工作流程**。其中一个备受关注的项目就是LangChain框架。**LangChain框架是一个开源工具,充分利用了大型语言模型的强大能力,以便开发各种下游应用。它的目标是为各种大型语言模型应用提供通用接口,从而简化应用程序的开发流程**。具体来说,LangChain框架可以实现数据感知和环境互动,也就是说,它能够让语言模型与其他数据来源连接,并且允许语言模型与其所处的环境进行互动。 6 | 7 | 在接下来的部分中,我们将重点介绍 LangChain 的 6 种标准化、可扩展的接口并且可以外部集成的核心模块: 8 | 9 | - **模型输入/输出(Model I/O)**:与语言模型交互的接口 10 | - **数据连接(Data connection)**:与特定应用程序的数据进行交互的接口 11 | - **链(Chains)**:将组件组合实现端到端应用。 12 | - **记忆(Memory)**:用于链的多次运行之间持久化应用程序状态; 13 | - **代理(Agents)**:扩展模型的推理能力。用于复杂的应用的调用序列; 14 | - **回调(Callbacks)**:扩展模型的推理能力。用于复杂的应用的调用序列; 15 | 16 | ## 1. 模型输入/输出 17 | 18 | LangChain 中模型输入/输出模块是与各种大语言模型进行交互的基本组件,是大语言模型应用的核心元素。**模型 I/O 允许您管理 prompt(提示),通过通用接口调用语言模型以及从模型输出中提取信息**。该模块的基本流程如下图所示。 19 | 20 | ![](../../figures/langchain_model_input_output.png) 21 | 22 | 主要包含以下部分:`Prompts`、`Language Models`以及 `Output Parsers`。**用户原始输入与模型和示例进行组合,然后输入给大语言模型,再根据大语言模型的返回结果进行输出或者结构化处理**。 23 | 24 | ## 2. 数据连接 25 | 26 | 大语言模型(Large Language Model, LLM), 比如 ChatGPT , 可以回答许多不同的问题。**但是大语言模型的知识来源于其训练数据集,并没有用户的信息(比如用户的个人数据,公司的自有数据),也没有最新发生时事的信息(在大模型数据训练后发表的文章或者新闻)**。因此大模型能给出的答案比较受限。如果能够让大模型在训练数据集的基础上,利用我们自有数据中的信息来回答我们的问题,那便能够得到更有用的答案。 27 | 28 | 为了支持上述应用的构建,LangChain 数据连接(Data connection)模块通过以下方式提供组件来**加载、转换、存储和查询数据**:`Document loaders`、`Document transformers`、`Text embedding models`、`Vector stores` 以及 `Retrievers`。数据连接模块部分的基本框架如下图所示。 29 | 30 | ![](../../figures/data_collection.png) 31 | 32 | ## 3. 链(Chain) 33 | 34 | 虽然独立使用大型语言模型能够应对一些简单任务,但**对于更加复杂的需求,可能需要将多个大型语言模型进行链式组合,或与其他组件进行链式调用**。链允许将多个组件组合在一起,创建一个单一的、连贯的应用程序。例如,可以创建一个链,接受用户输入,使用 PromptTemplate 对其进行格式化,然后将格式化后的提示词传递给大语言模型。也可以通过将多个链组合在一起或将链与其他组件组合来构建更复杂的链。 35 | 36 | 大语言模型链(LLMChain)是一个简单但非常强大的链,也是后面我们将要介绍的许多链的基础。我们以它为例,进行介绍: 37 | 38 | ```python 39 | import warnings 40 | warnings.filterwarnings('ignore') 41 | 42 | from langchain.chat_models import ChatOpenAI 43 | from langchain.prompts import ChatPromptTemplate 44 | from langchain.chains import LLMChain 45 | 46 | # 这里我们将参数temperature设置为0.0,从而减少生成答案的随机性。 47 | # 如果你想要每次得到不一样的有新意的答案,可以尝试调整该参数。 48 | llm = ChatOpenAI(temperature=0.0) 49 | 50 | #初始化提示模版 51 | prompt = ChatPromptTemplate.from_template("描述制造{product}的一个公司的最佳名称是什么?") 52 | 53 | #将大语言模型(LLM)和提示(Prompt)组合成链 54 | chain = LLMChain(llm=llm, prompt=prompt) 55 | 56 | #运行大语言模型链 57 | product = "大号床单套装" 58 | chain.run(product) 59 | ``` 60 | 运行输出: 61 | >'"豪华床纺"' 62 | 63 | 除了上例中给出的 LLMChain,LangChain 中链还包含 RouterChain、SimpleSequentialChain、SequentialChain、TransformChain 等。 64 | 65 | - `RouterChain` 可以**根据输入数据的某些属性/特征值,选择调用不同的子链**(Subchain)。 66 | - `SimpleSequentialChain` 是最简单的序列链形式,其中每个步骤具有单一的输入/输出,**上一个步骤的输出是下一个步骤的输入**。 67 | - `SequentialChain` 是简单顺序链的更复杂形式,允许**多个输入/输出**。 68 | - `TransformChain` 可以引入**自定义转换函数,对输入进行处理后进行输出**。 69 | 70 | 以下是使用 SimpleSequentialChain 的代码示例: 71 | 72 | ```python 73 | from langchain.chains import SimpleSequentialChain 74 | llm = ChatOpenAI(temperature=0.9) 75 | 76 | #创建两个子链 77 | 78 | # 提示模板 1 :这个提示将接受产品并返回最佳名称来描述该公司 79 | first_prompt = ChatPromptTemplate.from_template( 80 | "描述制造{product}的一个公司的最好的名称是什么" 81 | ) 82 | chain_one = LLMChain(llm=llm, prompt=first_prompt) 83 | 84 | # 提示模板 2 :接受公司名称,然后输出该公司的长为20个单词的描述 85 | second_prompt = ChatPromptTemplate.from_template( 86 | "写一个20字的描述对于下面这个\ 87 | 公司:{company_name}的" 88 | ) 89 | chain_two = LLMChain(llm=llm, prompt=second_prompt) 90 | 91 | #构建简单顺序链 92 | #现在我们可以组合两个LLMChain,以便我们可以在一个步骤中创建公司名称和描述 93 | overall_simple_chain = SimpleSequentialChain(chains=[chain_one, chain_two], verbose=True) 94 | 95 | 96 | #运行简单顺序链 97 | product = "大号床单套装" 98 | overall_simple_chain.run(product) 99 | ``` 100 | 运行输出: 101 | 102 | 103 | > Entering new SimpleSequentialChain chain... 104 | 优床制造公司 105 | 优床制造公司是一家专注于生产高品质床具的公司。 106 | 107 | > Finished chain. 108 | 109 | 110 | '优床制造公司是一家专注于生产高品质床具的公司。' 111 | 112 | 113 | ## 4. 记忆(Meomory) 114 | 115 | 在 LangChain 中,记忆(Memory)指的是大语言模型(LLM)的短期记忆。为什么是短期记忆?那是因为LLM训练好之后 (获得了一些长期记忆),它的参数便不会因为用户的输入而发生改变。当用户与训练好的LLM进行对话时,LLM 会暂时记住用户的输入和它已经生成的输出,以便预测之后的输出,而模型输出完毕后,它便会“遗忘”之前用户的输入和它的输出。因此,之前的这些信息只能称作为 LLM 的短期记忆。 116 | 117 | 正如上面所说,在与语言模型交互时,你可能已经注意到一个关键问题:它们并不记忆你之前的交流内容,这在我们构建一些应用程序(如聊天机器人)的时候,带来了很大的挑战,使得对话似乎缺乏真正的连续性。因此,在本节中我们将介绍 LangChain 中的记忆模块,即如何将先前的对话嵌入到语言模型中的,使其具有连续对话的能力。 118 | 119 | ![](../../figures/memory.png) 120 | 121 | ## 5. 代理(Agents) 122 | 123 | **大型语言模型(LLMs)非常强大,但它们缺乏“最笨”的计算机程序可以轻松处理的特定能力**。LLM 对逻辑推理、计算和检索外部信息的能力较弱,这与最简单的计算机程序形成对比。例如,语言模型无法准确回答简单的计算问题,还有当询问最近发生的事件时,其回答也可能过时或错误,因为无法主动获取最新信息。这是由于当前语言模型仅依赖预训练数据,与外界“断开”。要克服这一缺陷, LangChain 框架提出了 “代理”( Agent ) 的解决方案。**代理作为语言模型的外部模块,可提供计算、逻辑、检索等功能的支持,使语言模型获得异常强大的推理和获取信息的超能力**。 124 | 125 | ![](../../figures/Agents.png) 126 | 127 | ## 6.回调(Callback) 128 | 129 | LangChain提供了一个**回调系统,允许您连接到LLM应用程序的各个阶段。这对于日志记录、监视、流式处理和其他任务非常有用**。 130 | 131 | **Callback 模块扮演着记录整个流程运行情况的角色,充当类似于日志的功能。在每个关键节点,它记录了相应的信息,以便跟踪整个应用的运行情况**。例如,在 Agent 模块中,它记录了调用 Tool 的次数以及每次调用的返回参数值。Callback 模块可以将收集到的信息直接输出到控制台,也可以输出到文件,甚至可以传输到第三方应用程序,就像一个独立的日志管理系统一样。通过这些日志,可以分析应用的运行情况,统计异常率,并识别运行中的瓶颈模块以进行优化。 132 | 133 | Callback 模块的具体实现包括两个主要功能,对应`CallbackHandler` 和 `CallbackManager` 的基类功能: 134 | 135 | - CallbackHandler 用于记录**每个应用场景(如 Agent、LLchain 或 Tool )的日志**,它是单个日志处理器,主要记录单个场景的完整日志信息。 136 | - 而CallbackManager则**封装和管理所有的 CallbackHandler** ,包括单个场景的处理器,也包括整个运行时链路的处理器。" 137 | 138 | #### 在哪里传入回调 ? 139 | 140 | 该参数可用于整个 API 中的大多数对象(链、模型、工具、代理等),位于两个不同位置:: 141 | 142 | `构造函数回调`:在构造函数中定义,例如 LLMChain(callbacks=[handler], tags=['a-tag']) ,它将被用于对该对象的所有调用,并且将只针对该对象,例如,如果你向 LLMChain 构造函数传递一个 handler ,它将不会被附属于该链的 Model 使用。 143 | 144 | `请求回调`:定义在用于发出请求的 call() / run() / apply() 方法中,例如 chain.call(inputs, callbacks=[handler]) ,它将仅用于该特定请求,以及它包含的所有子请求(例如,对 LLMChain 的调用会触发对 Model 的调用,该 Model 使用 call() 方法中传递的相同 handler)。 145 | 146 | verbose 参数在整个 API 的大多数对象(链、模型、工具、代理等)上都可以作为构造参数使用,例如 LLMChain(verbose=True),它相当于将 ConsoleCallbackHandler 传递给该对象和所有子对象的 callbacks 参数。这对调试很有用,因为它将把所有事件记录到控制台。 147 | 148 | #### 你想在什么时候使用这些东西呢? 149 | 150 | **构造函数回调对诸如日志、监控等用例最有用,这些用例不是针对单个请求,而是针对整个链**。例如,如果你想记录所有向 LLMChain 发出的请求,你可以向构造函数传递一个处理程序。 151 | 152 | **请求回调对流媒体等用例最有用**,你想把单个请求的输出流向特定的 websocket 连接,或其他类似用例。例如,如果你想把单个请求的输出流到一个 websocket ,你会把一个处理程序传递给 call() 方法. 153 | 154 | 155 | -------------------------------------------------------------------------------- /notebook/C2 调用大模型 API/.env: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY = "" 2 | wenxin_api_key = "" 3 | wenxin_secret_key = "" 4 | -------------------------------------------------------------------------------- /notebook/C2 调用大模型 API/1. 基本概念.md: -------------------------------------------------------------------------------- 1 | 2 | # 一、基本概念 3 | 4 | ## 1. Prompt 5 | 6 | Prompt 最初是 NLP(自然语言处理)研究者为下游任务设计出来的一种任务专属的输入模板,类似于一种任务(例如:分类,聚类等)会对应一种 Prompt。在 ChatGPT 推出并获得大量应用之后,Prompt 开始被推广为给大模型的所有输入。即,我们每一次访问大模型的输入为一个 Prompt,而大模型给我们的返回结果则被称为 Completion。 7 | 8 | 例如,在下面示例中,我们给 ChatGPT 的提问 “NLP 中的 Prompt 指什么”是我们的提问,其实也就是我们此次的 Prompt;而 ChatGPT 的返回结果就是此次的 Completion。也就是对于 ChatGPT 模型,该 Prompt 对应的 Completion 是下图的展示。 9 | 10 | ![ChatGPT Prompt Examples](../../figures/prompt_example.png) 11 | 12 | 后续我们都将会使用 Prompt 替代给 LLM 的输入,使用 Completion 替代 LLM 的输出。同时,我们会结合具体案例,介绍如何设计 Prompt 能够充分发挥 LLM 的能力。 13 | 14 | ## 2. Temprature 15 | 16 | LLM 生成是具有随机性的,在模型的顶层通过选取不同预测概率的预测结果来生成最后的结果。我们一般可以通过控制 Temprature 参数来控制 LLM 生成结果的随机性与创造性。 17 | 18 | Temprature 一般取值在 0~1 之间,当取值较低接近0时,预测的随机性会较低,产生更保守、可预测的文本,不太可能生成意想不到或不寻常的词。当取值较高接近1时,预测的随机性会较高,所有词被选择的可能性更大,会产生更有创意、多样化的文本,更有可能生成不寻常或意想不到的词。 19 | 20 | 例如,当我们使用 ChatGPT 要求其为我们想一个关于跨语言模型的硕士毕业论文选题,当我们将 temprature 设置为0时,模型回复为: 21 | 22 | 题目:基于跨语言模型的机器翻译性能优化研究 23 | 24 | 摘要:随着全球化的发展,跨语言交流的需求日益增长。机器翻译作为一种自动化翻译技术,为跨语言交流提供了便利。然而,由于语言之间的差异性,机器翻译系统在不同语言对之间的性能存在差异。本论文旨在通过研究跨语言模型,探索如何优化机器翻译的性能,提高翻译质量和准确性。 25 | 26 | 关键词:跨语言模型,机器翻译,性能优化,翻译质量,准确性 27 | 28 | 1. 引言 29 | 1.1 研究背景和意义 30 | 1.2 国内外研究现状 31 | 1.3 研究目标和内容 32 | 33 | 2. 跨语言模型的原理和方法 34 | 2.1 传统机器翻译方法 35 | 2.2 跨语言模型的基本原理 36 | 2.3 跨语言模型的常用方法和技术 37 | 38 | 3. 跨语言模型在机器翻译中的应用 39 | 3.1 跨语言模型在机器翻译中的优势和挑战 40 | 3.2 跨语言模型在不同语言对上的性能表现比较 41 | 3.3 跨语言模型在特定领域机器翻译中的应用案例分析 42 | 43 | 4. 跨语言模型的性能优化方法 44 | 4.1 数据预处理和特征选择 45 | 4.2 模型参数调优和训练策略 46 | 4.3 跨语言模型与其他技术的结合应用 47 | 48 | 5. 实验设计与结果分析 49 | 5.1 实验设计和数据集介绍 50 | 5.2 实验结果分析和对比 51 | 5.3 实验结果的可行性和可靠性验证 52 | 53 | 6. 结论与展望 54 | 6.1 研究工作总结 55 | 6.2 存在的问题和不足 56 | 6.3 进一步研究方向和展望 57 | 58 | 参考文献 59 | 60 | 注:以上仅为一个选题示例,具体选题应根据个人兴趣和研究背景进行调整和修改。 61 | 62 | 当我们将 Temprature 设置为1时,模型回复为: 63 | 64 | 以下是关于跨语言模型的几个硕士毕业论文选题建议: 65 | 66 | 1. 跨语言文本分类模型的比较和优化——通过比较不同跨语言模型的性能,分析其在不同语言之间的适应性和准确性,并尝试优化现有模型,提高跨语言文本分类的效果。 67 | 68 | 2. 基于跨语言模型的机器翻译性能分析——通过比较不同跨语言模型在机器翻译任务中的表现,研究不同语言之间的短板和优势,并探讨如何针对性地改进跨语言机器翻译的性能。 69 | 70 | 3. 跨语言情感分析模型的构建与应用——使用跨语言模型构建情感分析模型,通过比较模型在不同语言上的准确性和一致性,分析不同语言中情感表达的差异,并探索在多语言场景下的情感分析应用。 71 | 72 | 4. 多任务学习下的跨语言模型训练——探索多任务学习下跨语言模型的训练方法和效果,通过同时训练多个任务来提高跨语言模型的泛化能力和性能,并验证多任务学习对跨语言模型的影响。 73 | 74 | 5. 跨语言问答系统的构建与评估——构建跨语言问答系统,通过跨语言模型实现问题的自动解析和答案的生成,并评估系统在多语言环境下的效果和可用性。 75 | 76 | 6. 基于预训练的跨语言模型的应用于语音识别——将预训练的跨语言模型应用于语音识别任务中,研究其对语音识别准确性和多语种适应性的影响,并比较不同模型对多语种语音数据的处理能力。 77 | 78 | 选择适合自己兴趣和研究方向的选题,并与导师进行深入讨论和确认。 79 | 80 | 对于不同的问题与应用场景,我们可能需要设置不同的 Temprature。例如,在本教程搭建的个人知识库助手项目中,我们一般将 Temprature 设置为0,从而保证助手对知识库内容的稳定使用,规避错误内容、模型幻觉;在产品智能客服、科研论文写作等场景中,我们同样更需要稳定性而不是创造性;但在个性化 AI、创意营销文案生成等场景中,我们就更需要创意性,从而更倾向于将 Temprature 设置为较高的值。 81 | 82 | ## 3. System Prompt 83 | 84 | System Prompt 是随着 ChatGPT API 开放并逐步得到大量使用的一个新兴概念,事实上,它并不在大模型本身训练中得到体现,而是大模型服务方为提升用户体验所设置的一种策略。 85 | 86 | 具体来说,在使用 ChatGPT API 时,你可以设置两种 Prompt:一种是 System Prompt,该种 Prompt 内容会在整个会话过程中持久地影响模型的回复,且相比于普通 Prompt 具有更高的重要性;另一种是 User Prompt,这更偏向于咱们平时的 Prompt,即需要模型做出回复的输入。 87 | 88 | 我们一般设置 System Prompt 来对模型进行一些初始化设定,例如,我们可以在 System Prompt 中给模型设定我们希望它具备的人设如一个个人知识库助手等。System Prompt 一般在一个会话中仅有一个。在通过 System Prompt 设定好模型的人设或是初始设置后,我们可以通过 User Prompt 给出模型需要遵循的指令。例如,当我们需要一个幽默风趣的个人知识库助手,并向这个助手提问我今天有什么事时,可以如下地构造 Prompt: 89 | 90 | ```json 91 | { 92 | "system prompt":"你是一个幽默风趣的个人知识库助手,可以根据给定的知识库内容回答用户的提问,注意,你的回答风格应是幽默风趣的", 93 | "user prompt":"我今天有什么事务?" 94 | } 95 | ``` 96 | 97 | 通过如上 Prompt 的构造,我们可以让模型以幽默风趣的风格回答用户提出的问题。注意,如果有多个用户问题,那么我们只需要添加对应数量的 User Prompt 即可,System Prompt 仅需构造一个。 -------------------------------------------------------------------------------- /notebook/C2 调用大模型 API/7. 总结.md: -------------------------------------------------------------------------------- 1 | # 七、总结 2 | 3 | 在本章中,我们简要介绍了四种常用大模型 API 的调用方式:ChatGPT、百度文心、讯飞星火、智谱 AI。四种模型 API 都具有不同的调用要求,我们分别进行了介绍并对其原生接口进行了封装,方便用户直接调用使用;同时,我们也简要介绍了如何将大模型 API 封装到 LangChain 的自定义 LLM 中,如何将大模型 API 封装成统一方式调用的本地 API,以及如何将大模型 Embedding API 封装到 LangChain 的自定义 LLM 中。我们分别以百度文心、讯飞星火、智谱 AI作为示例介绍了调用方式,欢迎读者们自行实践尝试将更多的模型进行统一封装。 4 | 5 | 学习完本章,你应该掌握了常用大模型的基本调用方式,那么接下来,你就可以开始着手基于大模型打造自己的应用啦! -------------------------------------------------------------------------------- /notebook/C2 调用大模型 API/SparkApi.py: -------------------------------------------------------------------------------- 1 | import _thread as thread 2 | import base64 3 | import datetime 4 | import hashlib 5 | import hmac 6 | import json 7 | from urllib.parse import urlparse 8 | import ssl 9 | from datetime import datetime 10 | from time import mktime 11 | from urllib.parse import urlencode 12 | from wsgiref.handlers import format_date_time 13 | 14 | import websocket # 使用websocket_client 15 | answer = "" 16 | 17 | class Ws_Param(object): 18 | # 初始化 19 | def __init__(self, APPID, APIKey, APISecret, Spark_url): 20 | self.APPID = APPID 21 | self.APIKey = APIKey 22 | self.APISecret = APISecret 23 | self.host = urlparse(Spark_url).netloc 24 | self.path = urlparse(Spark_url).path 25 | self.Spark_url = Spark_url 26 | 27 | # 生成url 28 | def create_url(self): 29 | # 生成RFC1123格式的时间戳 30 | now = datetime.now() 31 | date = format_date_time(mktime(now.timetuple())) 32 | 33 | # 拼接字符串 34 | signature_origin = "host: " + self.host + "\n" 35 | signature_origin += "date: " + date + "\n" 36 | signature_origin += "GET " + self.path + " HTTP/1.1" 37 | 38 | # 进行hmac-sha256进行加密 39 | signature_sha = hmac.new(self.APISecret.encode('utf-8'), signature_origin.encode('utf-8'), 40 | digestmod=hashlib.sha256).digest() 41 | 42 | signature_sha_base64 = base64.b64encode(signature_sha).decode(encoding='utf-8') 43 | 44 | authorization_origin = f'api_key="{self.APIKey}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature_sha_base64}"' 45 | 46 | authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8') 47 | 48 | # 将请求的鉴权参数组合为字典 49 | v = { 50 | "authorization": authorization, 51 | "date": date, 52 | "host": self.host 53 | } 54 | # 拼接鉴权参数,生成url 55 | url = self.Spark_url + '?' + urlencode(v) 56 | # 此处打印出建立连接时候的url,参考本demo的时候可取消上方打印的注释,比对相同参数时生成的url与自己代码生成的url是否一致 57 | return url 58 | 59 | 60 | # 收到websocket错误的处理 61 | def on_error(ws, error): 62 | print("### error:", error) 63 | 64 | 65 | # 收到websocket关闭的处理 66 | def on_close(ws,one,two): 67 | print(" ") 68 | 69 | 70 | # 收到websocket连接建立的处理 71 | def on_open(ws): 72 | thread.start_new_thread(run, (ws,)) 73 | 74 | 75 | def run(ws, *args): 76 | data = json.dumps(gen_params(appid=ws.appid, domain= ws.domain,question=ws.question)) 77 | ws.send(data) 78 | 79 | 80 | # 收到websocket消息的处理 81 | def on_message(ws, message): 82 | # print(message) 83 | data = json.loads(message) 84 | code = data['header']['code'] 85 | if code != 0: 86 | print(f'请求错误: {code}, {data}') 87 | ws.close() 88 | else: 89 | choices = data["payload"]["choices"] 90 | status = choices["status"] 91 | content = choices["text"][0]["content"] 92 | print(content,end ="") 93 | global answer 94 | answer += content 95 | # print(1) 96 | if status == 2: 97 | ws.close() 98 | 99 | 100 | def gen_params(appid, domain,question): 101 | """ 102 | 通过appid和用户的提问来生成请参数 103 | """ 104 | data = { 105 | "header": { 106 | "app_id": appid, 107 | "uid": "1234" 108 | }, 109 | "parameter": { 110 | "chat": { 111 | "domain": domain, 112 | "random_threshold": 0.5, 113 | "max_tokens": 2048, 114 | "auditing": "default" 115 | } 116 | }, 117 | "payload": { 118 | "message": { 119 | "text": question 120 | } 121 | } 122 | } 123 | return data 124 | 125 | 126 | def main(appid, api_key, api_secret, Spark_url,domain, question): 127 | # print("星火:") 128 | wsParam = Ws_Param(appid, api_key, api_secret, Spark_url) 129 | websocket.enableTrace(False) 130 | wsUrl = wsParam.create_url() 131 | ws = websocket.WebSocketApp(wsUrl, on_message=on_message, on_error=on_error, on_close=on_close, on_open=on_open) 132 | ws.appid = appid 133 | ws.question = question 134 | ws.domain = domain 135 | ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) 136 | 137 | 138 | -------------------------------------------------------------------------------- /notebook/C2 调用大模型 API/SparkApiSelf.py: -------------------------------------------------------------------------------- 1 | import _thread as thread 2 | import base64 3 | import datetime 4 | import hashlib 5 | import hmac 6 | import json 7 | import queue 8 | from urllib.parse import urlparse 9 | import ssl 10 | from datetime import datetime 11 | from time import mktime 12 | from urllib.parse import urlencode 13 | from wsgiref.handlers import format_date_time 14 | 15 | import websocket # 使用websocket_client 16 | answer = "" 17 | 18 | class Ws_Param(object): 19 | # 初始化 20 | def __init__(self, APPID, APIKey, APISecret, Spark_url): 21 | self.APPID = APPID 22 | self.APIKey = APIKey 23 | self.APISecret = APISecret 24 | self.host = urlparse(Spark_url).netloc 25 | self.path = urlparse(Spark_url).path 26 | self.Spark_url = Spark_url 27 | # 自定义 28 | self.temperature = 0 29 | self.max_tokens = 2048 30 | 31 | # 生成url 32 | def create_url(self): 33 | # 生成RFC1123格式的时间戳 34 | now = datetime.now() 35 | date = format_date_time(mktime(now.timetuple())) 36 | 37 | # 拼接字符串 38 | signature_origin = "host: " + self.host + "\n" 39 | signature_origin += "date: " + date + "\n" 40 | signature_origin += "GET " + self.path + " HTTP/1.1" 41 | 42 | # 进行hmac-sha256进行加密 43 | signature_sha = hmac.new(self.APISecret.encode('utf-8'), signature_origin.encode('utf-8'), 44 | digestmod=hashlib.sha256).digest() 45 | 46 | signature_sha_base64 = base64.b64encode(signature_sha).decode(encoding='utf-8') 47 | 48 | authorization_origin = f'api_key="{self.APIKey}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature_sha_base64}"' 49 | 50 | authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8') 51 | 52 | # 将请求的鉴权参数组合为字典 53 | v = { 54 | "authorization": authorization, 55 | "date": date, 56 | "host": self.host 57 | } 58 | # 拼接鉴权参数,生成url 59 | url = self.Spark_url + '?' + urlencode(v) 60 | # 此处打印出建立连接时候的url,参考本demo的时候可取消上方打印的注释,比对相同参数时生成的url与自己代码生成的url是否一致 61 | return url 62 | 63 | 64 | # 收到websocket错误的处理 65 | def on_error(ws, error): 66 | print("### error:", error) 67 | 68 | 69 | # 收到websocket关闭的处理 70 | def on_close(ws,one,two): 71 | print(" ") 72 | 73 | 74 | # 收到websocket连接建立的处理 75 | def on_open(ws): 76 | thread.start_new_thread(run, (ws,)) 77 | 78 | 79 | def run(ws, *args): 80 | data = json.dumps(gen_params(appid=ws.appid, domain= ws.domain,question=ws.question, temperature = ws.temperature, max_tokens = ws.max_tokens)) 81 | ws.send(data) 82 | 83 | 84 | # 收到websocket消息的处理 85 | def on_message(ws, message): 86 | # print(message) 87 | data = json.loads(message) 88 | code = data['header']['code'] 89 | if code != 0: 90 | print(f'请求错误: {code}, {data}') 91 | ws.close() 92 | else: 93 | choices = data["payload"]["choices"] 94 | status = choices["status"] 95 | content = choices["text"][0]["content"] 96 | print(content,end ="") 97 | global answer 98 | answer += content 99 | # print(1) 100 | if status == 2: 101 | ws.close() 102 | 103 | 104 | def gen_params(appid, domain,question, temperature, max_tokens): 105 | """ 106 | 通过appid和用户的提问来生成请参数 107 | """ 108 | data = { 109 | "header": { 110 | "app_id": appid, 111 | "uid": "1234" 112 | }, 113 | "parameter": { 114 | "chat": { 115 | "domain": domain, 116 | "random_threshold": 0.5, 117 | "max_tokens": max_tokens, 118 | "temperature" : temperature, 119 | "auditing": "default" 120 | } 121 | }, 122 | "payload": { 123 | "message": { 124 | "text": question 125 | } 126 | } 127 | } 128 | return data 129 | 130 | 131 | def main(appid, api_key, api_secret, Spark_url,domain, question, temperature, max_tokens): 132 | # print("星火:") 133 | output_queue = queue.Queue() 134 | def on_message(ws, message): 135 | data = json.loads(message) 136 | code = data['header']['code'] 137 | if code != 0: 138 | print(f'请求错误: {code}, {data}') 139 | ws.close() 140 | else: 141 | choices = data["payload"]["choices"] 142 | status = choices["status"] 143 | content = choices["text"][0]["content"] 144 | # print(content, end='') 145 | # 将输出值放入队列 146 | output_queue.put(content) 147 | if status == 2: 148 | ws.close() 149 | 150 | wsParam = Ws_Param(appid, api_key, api_secret, Spark_url) 151 | websocket.enableTrace(False) 152 | wsUrl = wsParam.create_url() 153 | ws = websocket.WebSocketApp(wsUrl, on_message=on_message, on_error=on_error, on_close=on_close, on_open=on_open) 154 | ws.appid = appid 155 | ws.question = question 156 | ws.domain = domain 157 | ws.temperature = temperature 158 | ws.max_tokens = max_tokens 159 | ws.run_forever(sslopt={"cert_reqs": ssl.CERT_NONE}) 160 | return ''.join([output_queue.get() for _ in range(output_queue.qsize())]) 161 | 162 | 163 | -------------------------------------------------------------------------------- /notebook/C2 调用大模型 API/__pycache__/SparkApi.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/C2 调用大模型 API/__pycache__/SparkApi.cpython-39.pyc -------------------------------------------------------------------------------- /notebook/C2 调用大模型 API/__pycache__/SparkApiSelf.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/C2 调用大模型 API/__pycache__/SparkApiSelf.cpython-39.pyc -------------------------------------------------------------------------------- /notebook/C2 调用大模型 API/__pycache__/wenxin_llm.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/C2 调用大模型 API/__pycache__/wenxin_llm.cpython-39.pyc -------------------------------------------------------------------------------- /notebook/C2 调用大模型 API/spark_api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | ''' 4 | @File : spark_api.py 5 | @Time : 2023/09/24 11:00:46 6 | @Author : Logan Zou 7 | @Version : 1.0 8 | @Contact : loganzou0421@163.com 9 | @License : (C)Copyright 2017-2018, Liugroup-NLPR-CASIA 10 | @Desc : 将讯飞星火 API 封装成本地 API 11 | ''' 12 | 13 | from fastapi import FastAPI 14 | from pydantic import BaseModel 15 | import os 16 | import SparkApiSelf 17 | 18 | app = FastAPI() # 创建 api 对象 19 | 20 | # 定义一个数据模型,用于接收POST请求中的数据 21 | class Item(BaseModel): 22 | prompt : str # 用户 prompt 23 | temperature : float # 温度系数 24 | max_tokens : int # token 上限 25 | if_list : bool = False # 是否多轮对话 26 | 27 | @app.post("/spark/") 28 | async def get_spark_response(item: Item): 29 | # 实现星火大模型调用的 API 端点 30 | response = get_spark(item) 31 | print(response) 32 | return response 33 | 34 | 35 | # 首先定义一个构造参数函数 36 | def getText(role, content, text = []): 37 | # role 是指定角色,content 是 prompt 内容 38 | jsoncon = {} 39 | jsoncon["role"] = role 40 | jsoncon["content"] = content 41 | text.append(jsoncon) 42 | return text 43 | 44 | def get_spark(item): 45 | # 配置 spark 秘钥 46 | #以下密钥信息从控制台获取 47 | appid = "9f922c84" #填写控制台中获取的 APPID 信息 48 | api_secret = "YjU0ODk4MWQ4NTgyNDU5MzNiNWQzZmZm" #填写控制台中获取的 APISecret 信息 49 | api_key ="5d4e6e41f6453936ccc34dd524904324" #填写控制台中获取的 APIKey 信息 50 | domain = "generalv2" # v2.0版本 51 | Spark_url = "ws://spark-api.xf-yun.com/v2.1/chat" # v2.0环境的地址 52 | 53 | # 构造请求参数 54 | if item.if_list: 55 | prompt = item.prompt 56 | else: 57 | prompt = getText("user", item.prompt) 58 | 59 | response = SparkApiSelf.main(appid,api_key,api_secret,Spark_url,domain,prompt, item.temperature, item.max_tokens) 60 | return response -------------------------------------------------------------------------------- /notebook/C2 调用大模型 API/wenxin_llm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | ''' 4 | @File : wenxin_llm.py 5 | @Time : 2023/09/22 14:27:55 6 | @Author : Logan Zou 7 | @Version : 1.0 8 | @Contact : loganzou0421@163.com 9 | @License : (C)Copyright 2017-2018, Liugroup-NLPR-CASIA 10 | @Desc : 基于 LangChain 定义文心模型调用方式 11 | ''' 12 | 13 | import json 14 | import time 15 | from typing import Any, List, Mapping, Optional, Dict, Union, Tuple 16 | import requests 17 | from langchain.llms.base import LLM 18 | from langchain.utils import get_from_dict_or_env 19 | from pydantic import Field, root_validator 20 | from langchain.callbacks.manager import CallbackManagerForLLMRun 21 | 22 | def get_access_token(api_key : str, secret_key : str): 23 | """ 24 | 使用 API Key,Secret Key 获取access_token,替换下列示例中的应用API Key、应用Secret Key 25 | """ 26 | # 指定网址 27 | url = f"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={api_key}&client_secret={secret_key}" 28 | # 设置 POST 访问 29 | payload = json.dumps("") 30 | headers = { 31 | 'Content-Type': 'application/json', 32 | 'Accept': 'application/json' 33 | } 34 | # 通过 POST 访问获取账户对应的 access_token 35 | response = requests.request("POST", url, headers=headers, data=payload) 36 | return response.json().get("access_token") 37 | 38 | # 继承自 langchain.llms.base.LLM 39 | class Wenxin_LLM(LLM): 40 | # 原生接口地址 41 | url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant" 42 | # 默认选用 ERNIE-Bot-turbo 模型,即目前一般所说的百度文心大模型 43 | model_name: str = "ERNIE-Bot-turbo" 44 | # 访问时延上限 45 | request_timeout: float = None 46 | # 温度系数 47 | temperature: float = 0.1 48 | # API_Key 49 | api_key: str = None 50 | # Secret_Key 51 | secret_key : str = None 52 | # access_token 53 | access_token: str = None 54 | # 必备的可选参数 55 | model_kwargs: Dict[str, Any] = Field(default_factory=dict) 56 | 57 | def init_access_token(self): 58 | if self.api_key != None and self.secret_key != None: 59 | # 两个 Key 均非空才可以获取 access_token 60 | try: 61 | self.access_token = get_access_token(self.api_key, self.secret_key) 62 | except Exception as e: 63 | print(e) 64 | print("获取 access_token 失败,请检查 Key") 65 | else: 66 | print("API_Key 或 Secret_Key 为空,请检查 Key") 67 | 68 | def _call(self, prompt : str, stop: Optional[List[str]] = None, 69 | run_manager: Optional[CallbackManagerForLLMRun] = None, 70 | **kwargs: Any): 71 | # 如果 access_token 为空,初始化 access_token 72 | if self.access_token == None: 73 | self.init_access_token() 74 | # API 调用 url 75 | url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token={}".format(self.access_token) 76 | # 配置 POST 参数 77 | payload = json.dumps({ 78 | "messages": [ 79 | { 80 | "role": "user",# user prompt 81 | "content": "{}".format(prompt)# 输入的 prompt 82 | } 83 | ], 84 | 'temperature' : self.temperature 85 | }) 86 | headers = { 87 | 'Content-Type': 'application/json' 88 | } 89 | # 发起请求 90 | response = requests.request("POST", url, headers=headers, data=payload, timeout=self.request_timeout) 91 | if response.status_code == 200: 92 | # 返回的是一个 Json 字符串 93 | js = json.loads(response.text) 94 | return js["result"] 95 | else: 96 | return "请求失败" 97 | 98 | # 首先定义一个返回默认参数的方法 99 | @property 100 | def _default_params(self) -> Dict[str, Any]: 101 | """获取调用Ennie API的默认参数。""" 102 | normal_params = { 103 | "temperature": self.temperature, 104 | "request_timeout": self.request_timeout, 105 | } 106 | # print(type(self.model_kwargs)) 107 | return {**normal_params} 108 | 109 | @property 110 | def _llm_type(self) -> str: 111 | return "Wenxin" 112 | 113 | @property 114 | def _identifying_params(self) -> Mapping[str, Any]: 115 | """Get the identifying parameters.""" 116 | return {**{"model_name": self.model_name}, **self._default_params} 117 | -------------------------------------------------------------------------------- /notebook/C3 大模型开发流程及架构/1. 大模型开发流程.md: -------------------------------------------------------------------------------- 1 | # 一、大模型开发整体流程 2 | 3 | ## 1. 何为大模型开发 4 | 5 | 我们将开发以大语言模型为功能核心、通过大语言模型的强大理解能力和生成能力、结合特殊的数据或业务逻辑来提供独特功能的应用称为大模型开发。开发大模型相关应用,其技术核心点虽然在大语言模型上,但一般通过调用 API 或开源模型来实现核心的理解与生成,通过 Prompt Enginnering 来实现大语言模型的控制,因此,虽然大模型是深度学习领域的集大成之作,大模型开发却更多是一个工程问题。 6 | 7 | 在大模型开发中,我们一般不会去大幅度改动模型,而是将大模型作为一个调用工具,通过 Prompt Engineering、数据工程、业务逻辑分解等手段来充分发挥大模型能力,适配应用任务,而不会将精力聚焦在优化模型本身上。这因此,作为大模型开发的初学者,我们并不需要深研大模型内部原理,而更需要掌握使用大模型的实践技巧。 8 | 9 | ![](../../figures/LLM_developing.png) 10 |
大模型开发要素
11 |

12 | 13 | 同时,以调用、发挥大模型为核心的大模型开发与传统的 AI 开发在整体思路上有着较大的不同。大语言模型的两个核心能力:指令理解与文本生成提供了复杂业务逻辑的简单平替方案。在传统的 AI 开发中,我们首先需要将非常复杂的业务逻辑依次拆解,对于每一个子业务构造训练数据与验证数据,对于每一个子业务训练优化模型,最后形成完整的模型链路来解决整个业务逻辑。然而,在大模型开发中,我们将尝试用 Prompt Engineering 来替代子模型的训练调优,通过 Prompt 链路组合来实现业务逻辑,用一个通用大模型 + 若干业务 Prompt 来解决任务,从而将传统的模型训练调优转变成了更简单、轻松、低成本的 Prompt 设计调优。 14 | 15 | 同时,在评估思路上,大模型开发与传统 AI 开发也有了质的差异。传统 AI 开发需要首先构造训练集、测试集、验证集,通过在训练集上训练模型、在测试集上调优模型、在验证集上最终验证模型效果来实现性能的评估。然而,大模型开发更敏捷、灵活,我们一般不会在初期显式地确定训练集、验证集,由于不再需要训练子模型,我们不再构造训练集,而是直接从实际业务需求出发构造小批量验证集,设计合理 Prompt 来满足验证集效果。然后,我们将不断从业务逻辑中收集当下 Prompt 的 Bad Case,并将 Bad Case 加入到验证集中,针对性优化 Prompt,最后实现较好的泛化效果。 16 | 17 | ![](../../figures/AI_eval.png) 18 | 19 |
传统 AI 评估
20 |

21 | 22 | ![](../../figures/LLM_eval.png) 23 | 24 |

LLM 评估
25 |

26 | 27 | 在本章中,我们将简述大模型开发的一般流程,并结合项目实际需求,逐步分析完成项目开发的工作和步骤。 28 | 29 | ## 2. 大模型开发的整体流程 30 | 31 | 结合上述分析,我们一般可以将大模型开发分解为以下几个流程: 32 | 33 | ![](../../figures/LLM_developing_whole.png) 34 | 35 | 1. 确定目标。在进行开发前,我们首先需要确定开发的目标,即要开发的应用的应用场景、目标人群、核心价值。对于个体开发者或小型开发团队而言,一般应先设定最小化目标,从构建一个 mvp(最小可行性产品)开始,逐步进行完善和优化。 36 | 37 | 2. 设计功能。在确定开发目标后,需要设计本应用所要提供的功能,以及每一个功能的大体实现逻辑。虽然我们通过使用大模型来简化了业务逻辑的拆解,但是越清晰、深入的业务逻辑理解往往也能带来更好的 Prompt 效果。同样,对于个体开发者或小型开发团队来说,首先要确定应用的核心功能,然后延展设计核心功能的上下游功能;例如,我们想打造一款个人知识库助手,那么核心功能就是结合个人知识库内容进行问题的回答,那么其上游功能的用户上传知识库、下游功能的用户手动纠正模型回答就是我们也必须要设计实现的子功能。 38 | 39 | 3. 搭建整体架构。目前,绝大部分大模型应用都是采用的特定数据库+ Prompt + 通用大模型的架构。我们需要针对我们所设计的功能,搭建项目的整体架构,实现从用户输入到应用输出的全流程贯通。一般来说,我们推荐基于 LangChain 框架进行开发。LangChain 提供了 Chain、Tool 等架构的实现,我们可以基于 LangChain 进行个性化定制,实现从用户输入到数据库再到大模型最后输出的整体架构连接。 40 | 41 | 4. 搭建数据库。个性化大模型应用需要有个性化数据库进行支撑。由于大模型应用需要进行向量语义检索,一般使用诸如 chroma 的向量数据库。在该步骤中,我们需要收集数据并进行预处理,再向量化存储到数据库中。数据预处理一般包括从多种格式向纯文本的转化,例如 pdf、markdown、html、音视频等,以及对错误数据、异常数据、脏数据进行清洗。完成预处理后,需要进行切片、向量化构建出个性化数据库。 42 | 43 | 5. Prompt Engineering。优质的 Prompt 对大模型能力具有极大影响,我们需要逐步迭代构建优质的 Prompt Engineering 来提升应用性能。在该步中,我们首先应该明确 Prompt 设计的一般原则及技巧,构建出一个来源于实际业务的小型验证集,基于小型验证集设计满足基本要求、具备基本能力的 Prompt。 44 | 45 | 6. 验证迭代。验证迭代在大模型开发中是极其重要的一步,一般指通过不断发现 Bad Case 并针对性改进 Prompt Engineering 来提升系统效果、应对边界情况。在完成上一步的初始化 Prompt 设计后,我们应该进行实际业务测试,探讨边界情况,找到 Bad Case,并针对性分析 Prompt 存在的问题,从而不断迭代优化,直到达到一个较为稳定、可以基本实现目标的 Prompt 版本。 46 | 47 | 7. 前后端搭建。完成 Prompt Engineering 及其迭代优化之后,我们就完成了应用的核心功能,可以充分发挥大语言模型的强大能力。接下来我们需要搭建前后端,设计产品页面,让我们的应用能够上线成为产品。前后端开发是非常经典且成熟的领域,此处就不再赘述,我们将主要介绍两种快速开发 Demo 的框架:Gradio 和 Streamlit,可以帮助个体开发者迅速搭建可视化页面实现 Demo 上线。 48 | 49 | 8. 体验优化。在完成前后端搭建之后,应用就可以上线体验了。接下来就需要进行长期的用户体验跟踪,记录 Bad Case 与用户负反馈,再针对性进行优化即可。 -------------------------------------------------------------------------------- /notebook/C3 大模型开发流程及架构/2. 项目流程简析.md: -------------------------------------------------------------------------------- 1 | # 二、项目流程简析 2 | 3 | 以下我们将结合本实践项目与上文的整体流程介绍,简要分析本项目开发流程如下: 4 | 5 | ### 步骤一:项目规划与需求分析 6 | 7 | #### 1.**项目目标**:基于个人知识库的问答助手 8 | 9 | #### 2.**核心功能**: 10 | 11 | 1. 上传文档、创建知识库; 12 | 2. 选择知识库,检索用户提问的知识片段; 13 | 3. 提供知识片段与提问,获取大模型回答; 14 | 4. 流式回复; 15 | 5. 历史对话记录 16 | 17 | #### 3.**确定技术架构和工具** 18 | 19 | 1. LangChain框架 20 | 2. Chroma知识库 21 | 3. 大模型使用 GPT、Claude、科大讯飞的星火大模型、文心一言、Chat-GLM2等 22 | 4. 前后端使用 Gradio 和 Streamlit。 23 | 24 | ### 步骤二:数据准备与向量知识库构建 25 | 26 | 本项目实现原理如下图所示(图片来源),过程包括加载本地文档 -> 读取文本 -> 文本分割 -> 文本向量化 -> question向量化 -> 在文本向量中匹配出与问句向量最相似的 top k个 -> 匹配出的文本作为上下文和问题一起添加到 prompt中 -> 提交给 LLM生成回答。 27 | 28 | ![](../../figures/flow_chart.png) 29 | 30 | #### 1. 收集和整理用户提供的文档。 31 | 32 | 用户常用文档格式有 pdf、txt、doc 等,首先使用工具读取文本,通常使用 langchain 的文档加载器模块可以方便的将用户提供的文档加载进来,也可以使用一些 python 比较成熟的包进行读取。 33 | 34 | 由于目前大模型使用 token 的限制,我们需要对读取的文本进行切分,将较长的文本切分为较小的文本,这时一段文本就是一个单位的知识。 35 | 36 | #### 2. 将文档词向量化 37 | 38 | 使用文本嵌入(Embeddings)对分割后的文档进行向量化,使语义相似的文本片段具有接近的向量表示。然后,存入向量数据库,这个流程正是创建索引(index)的过程。 39 | 40 | 向量数据库对各文档片段进行索引,支持快速检索。这样,当用户提出问题时,可以先将问题转换为向量,在数据库中快速找到语义最相关的文档片段。然后将这些文档片段与问题一起传递给语言模型,生成回答 41 | 42 | #### 3. 将向量化后的文档导入Chroma知识库,建立知识库索引。 43 | 44 | Langchain集成了超过30个不同的向量存储库。我们选择 Chroma 向量库是因为它轻量级且数据存储在内存中,这使得它非常容易启动和开始使用。 45 | 46 | 将用户知识库内容经过 embedding 存入向量知识库,然后用户每一次提问也会经过 embedding,利用向量相关性算法(例如余弦算法)找到最匹配的几个知识库片段,将这些知识库片段作为上下文,与用户问题一起作为 promt 提交给 LLM 回答。 47 | 48 | ### 步骤三:大模型集成与API连接 49 | 50 | 1. 集成GPT、Claude、星火、文心、GLM等大模型,配置API连接。 51 | 2. 编写代码,实现与大模型API的交互,以便获取问题答案。 52 | 53 | ### 步骤四:核心功能实现 54 | 55 | 1. 构建 Prompt Engineering,实现大模型回答功能,根据用户提问和知识库内容生成回答。 56 | 3. 实现流式回复,允许用户进行多轮对话。 57 | 4. 添加历史对话记录功能,保存用户与助手的交互历史。 58 | 59 | ### 步骤五:核心功能迭代优化 60 | 61 | 1. 进行验证评估,收集 Bad Case。 62 | 2. 根据 Bad Case 迭代优化核心功能实现。 63 | 64 | ### 步骤六:前端与用户交互界面开发 65 | 66 | 1. 使用Gradio和Streamlit搭建前端界面。 67 | 2. 实现用户上传文档、创建知识库的功能。 68 | 3. 设计用户界面,包括问题输入、知识库选择、历史记录展示等。 69 | 70 | ### 步骤七:部署测试与上线 71 | 72 | 1. 部署问答助手到服务器或云平台,确保可在互联网上访问。 73 | 2. 进行生产环境测试,确保系统稳定。 74 | 3. 上线并向用户发布。 75 | 76 | ### 步骤八:维护与持续改进 77 | 78 | 1. 监测系统性能和用户反馈,及时处理问题。 79 | 2. 定期更新知识库,添加新的文档和信息。 80 | 3. 收集用户需求,进行系统改进和功能扩展。 81 | 82 | 整个流程将确保项目从规划、开发、测试到上线和维护都能够顺利进行,为用户提供高质量的基于个人知识库的问答助手。 -------------------------------------------------------------------------------- /notebook/C3 大模型开发流程及架构/3. 项目架构简析.md: -------------------------------------------------------------------------------- 1 | # 三、项目架构简析 2 | 3 | ## 1. 整体架构 4 | 5 | 经过上文分析,本项目为搭建一个基于大模型的个人知识库助手,基于 LangChain 框架搭建,核心技术包括 LLM API 调用、向量数据库、检索问答链等。项目整体架构如下: 6 | 7 | ![](../../figures/structure.jpg) 8 | 9 | 如上,本项目从底向上依次分为 LLM 层、数据层、数据库层、应用层与服务层。① LLM 层主要基于四种流行 LLM API 进行了 LLM 调用封装,支持用户以统一的入口、方式来访问不同的模型,支持随时进行模型的切换;② 数据层主要包括个人知识库的源数据以及 Embedding API,源数据经过 Embedding 处理可以被向量数据库使用;③ 数据库层主要为基于个人知识库源数据搭建的向量数据库,在本项目中我们选择了 Chroma;④ 应用层为核心功能的最顶层封装,我们基于 LangChain 提供的检索问答链基类进行了进一步封装,从而支持不同模型切换以及便捷实现基于数据库的检索问答;⑤ 最顶层为服务层,我们分别实现了 Gradio 搭建 Demo 与 FastAPI 组建 API 两种方式来支持本项目的服务访问。 10 | 11 | ## 2. 代码结构 12 | 13 | 本项目的完整代码存放于 project 目录下,实现了项目的全部功能及封装,代码结构如下: 14 | 15 | -project 16 | -readme.md 项目说明 17 | -llm LLM调用封装 18 | -self_llm.py 自定义 LLM 基类 19 | -wenxin_llm.py 自定义百度文心 LLM 20 | -spark_llm.py 自定义讯飞星火 LLM 21 | -zhipu_llm.py 自定义智谱 LLM 22 | -call_llm.py 将各个 LLM 的原生接口封装在一起 23 | -embedding embedding调用封装 24 | -zhipu_embedding.py 自定义智谱embedding 25 | -data 源数据路径 26 | -database 数据库层封装 27 | -create_db.py 处理源数据及初始化数据库封装 28 | -chain 应用层封装 29 | -qa_chain.py 封装检索问答链,返回一个检索问答链对象 30 | -chat_qa_chian.py:封装对话检索链,返回一个对话检索链对象 31 | -prompt_template.py 存放多个版本的 Template 32 | -serve 服务层封装 33 | -run_gradio.py 启动 Gradio 界面 34 | -api.py 封装 FastAPI 35 | -run_api.sh 启动 API 36 | 37 | ## 3. 项目逻辑 38 | 39 | 1. 用户:可以通过 run_gradio 或者 run_api 启动整个服务; 40 | 2. 服务层调用 qa_chain.py 或 chat_qa_chain 实例化对话检索链对象,实现全部核心功能; 41 | 3. 服务层和应用层都可以调用、切换 prompt_template.py 中的 prompt 模板来实现 prompt 的迭代; 42 | 4. 也可以直接调用 call_llm 中的 get_completion 函数来实现不使用数据库的 LLM; 43 | 5. 应用层调用已存在的数据库和 llm 中的自定义 LLM 来构建检索链; 44 | 6. 如果数据库不存在,应用层调用 create_db.py 创建数据库,该脚本可以使用 openai embedding 也可以使用 embedding.py 中的自定义 embedding 45 | 46 | ## 4. 各层简析 47 | 48 | ### 4.1 LLM 层 49 | 50 | LLM 层主要功能为将国内外四种知名 LLM API(OpenAI-ChatGPT、百度文心、讯飞星火、智谱GLM)进行封装,隐藏不同 API 的调用差异,实现在同一个对象或函数中通过不同的 model 参数来使用不同来源的 LLM。 51 | 52 | 在 LLM 层,我们首先构建了一个 Self_LLM 基类,基类定义了所有 API 的一些共同参数(如 API_Key,temperature 等);然后我们在该基类基础上继承实现了上述四种 LLM API 的自定义 LLM。同时,我们也将四种 LLM 的原生 API 封装在了统一的 get_completion 函数中。 53 | 54 | 在上一章,我们已详细介绍了每一种 LLM 的调用方式、封装方式,项目代码中的 LLM 层封装就是上一章讲解的代码实践。 55 | 56 | ### 4.2 数据层 57 | 58 | 数据层主要包括个人知识库的源数据(包括 pdf、txt、md 等)和 Embedding 对象。源数据需要经过 Embedding 处理才能进入向量数据库,我们在数据层自定义了智谱提供的 Embedding API 的封装,支持上层以统一方式调用智谱 Embedding 或 OpenAI Embedding。 59 | 60 | 在上一章,我们也已详细介绍了 Embdding API 的调用及封装方式。 61 | 62 | ### 4.3 数据库层 63 | 64 | 数据库层主要存放了向量数据库文件。同时,我们在该层实现了源数据处理、创建向量数据库的方法。 65 | 66 | 我们将在第四章详细介绍向量数据库、源数据处理方法以及构建向量数据库的具体实现。 67 | 68 | ### 4.4 应用层 69 | 70 | 应用层封装了整个项目的全部核心功能。我们基于 LangChain 提供的检索问答链,在 LLM 层、数据库层的基础上,实现了本项目检索问答链的封装。自定义的检索问答链除具备基本的检索问答功能外,也支持通过 model 参数来灵活切换使用的 LLM。我们实现了两个检索问答链,分别是有历史记录的 Chat_QA_Chain 和没有历史记录的 QA_Chain。 71 | 72 | 我们将在第五章讲解 Prompt 的构造与检索问答链的构建细节。 73 | 74 | ### 4.5 服务层 75 | 76 | 服务层主要是基于应用层的核心功能封装,实现了 Demo 的搭建或 API 的封装。在本项目中,我们分别实现了通过 Gradio 搭建前端界面与 FastAPI 进行封装,支持多样化的项目调用。 77 | 78 | 我们将在第六章详细介绍如何使用 Gradio 以及 FastAPI 来实现服务层的设计。 -------------------------------------------------------------------------------- /notebook/C4 数据库搭建/.env: -------------------------------------------------------------------------------- 1 | OPENAI_API_KEY = "" 2 | wenxin_api_key = "" 3 | wenxin_secret_key = "" 4 | -------------------------------------------------------------------------------- /notebook/C4 数据库搭建/.ipynb_checkpoints/3. 构建项目数据库-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 第三章 构建项目数据库" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "在前面两章我们具体介绍了我们的知识库选择,并介绍了如何加载、处理数据并构建、使用向量数据库。在本章中,我们结合之前讲解的内容,具体构建出本项目使用的数据库,之后我们的 Prompt Engineeering 及迭代优化、验证评估均会在该数据库基础上进行。\n", 15 | "\n", 16 | "在这里,我们使用 OpenAI 的 Embedding 模型实现向量化,大家也可以根据前面的讲解选用不同的 Embedding 模型。\n", 17 | "\n", 18 | "由于此处加载向量数据库需要一定时间运行,我们也提供了 py 脚本供大家使用。" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 6, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "# 首先实现基本配置\n", 28 | "from langchain.vectorstores import Chroma\n", 29 | "from langchain.document_loaders import PyMuPDFLoader\n", 30 | "from langchain.text_splitter import RecursiveCharacterTextSplitter\n", 31 | "from langchain.document_loaders import UnstructuredMarkdownLoader\n", 32 | "from langchain.document_loaders import UnstructuredFileLoader\n", 33 | "\n", 34 | "from langchain.embeddings.openai import OpenAIEmbeddings\n", 35 | "from langchain.embeddings.huggingface import HuggingFaceEmbeddings\n", 36 | "\n", 37 | "from langchain.llms import OpenAI\n", 38 | "from langchain.llms import HuggingFacePipeline\n", 39 | "\n", 40 | "# 使用前配置自己的 api 到环境变量中如\n", 41 | "import os\n", 42 | "import openai\n", 43 | "import sys\n", 44 | "\n", 45 | "from dotenv import load_dotenv, find_dotenv\n", 46 | "\n", 47 | "_ = load_dotenv(find_dotenv()) # read local .env fileopenai.api_key = os.environ['OPENAI_API_KEY']\n", 48 | "openai.api_key = os.environ['OPENAI_API_KEY']" 49 | ] 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "metadata": {}, 54 | "source": [ 55 | "接下来逐个加载知识库里的文档:" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 2, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "#pdf\n", 65 | "# 加载 PDF\n", 66 | "loaders = [\n", 67 | " PyMuPDFLoader(\"../knowledge_base/pumkin_book/pumpkin_book.pdf\") # 机器学习,\n", 68 | "]\n", 69 | "docs = []\n", 70 | "for loader in loaders:\n", 71 | " docs.extend(loader.load())" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 5, 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [ 80 | "#md\n", 81 | "folder_path = \"../knowledge_base/prompt_engineering/\"\n", 82 | "files = os.listdir(folder_path)\n", 83 | "loaders = []\n", 84 | "for one_file in files:\n", 85 | " loader = UnstructuredMarkdownLoader(os.path.join(folder_path, one_file))\n", 86 | " loaders.append(loader)\n", 87 | "for loader in loaders:\n", 88 | " docs.extend(loader.load())" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 7, 94 | "metadata": {}, 95 | "outputs": [], 96 | "source": [ 97 | "#mp4-txt\n", 98 | "loaders = [\n", 99 | " UnstructuredFileLoader(\"../knowledge_base/easy_rl/强化学习入门指南.txt\") # 机器学习,\n", 100 | "]\n", 101 | "for loader in loaders:\n", 102 | " docs.extend(loader.load())" 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": {}, 108 | "source": [ 109 | "然后对加载好的文档进行切片并向量化后存储到向量数据库中:" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": 13, 115 | "metadata": {}, 116 | "outputs": [ 117 | { 118 | "name": "stderr", 119 | "output_type": "stream", 120 | "text": [ 121 | "Using embedded DuckDB with persistence: data will be stored in: ../knowledge_base/chroma\n" 122 | ] 123 | } 124 | ], 125 | "source": [ 126 | "# 切分文档\n", 127 | "text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=150)\n", 128 | "split_docs = text_splitter.split_documents(docs)\n", 129 | "\n", 130 | "\n", 131 | "# 定义 Embeddings\n", 132 | "embedding = OpenAIEmbeddings() \n", 133 | "\n", 134 | "# 定义持久化路径\n", 135 | "persist_directory = '../knowledge_base/chroma'\n", 136 | "\n", 137 | "# 加载数据库\n", 138 | "vectordb = Chroma.from_documents(\n", 139 | " documents=split_docs,\n", 140 | " embedding=embedding,\n", 141 | " persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上\n", 142 | ")" 143 | ] 144 | }, 145 | { 146 | "cell_type": "markdown", 147 | "metadata": {}, 148 | "source": [ 149 | "最后将加载好的向量数据库持久化即可:" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": null, 155 | "metadata": {}, 156 | "outputs": [], 157 | "source": [ 158 | "vectordb.persist()" 159 | ] 160 | } 161 | ], 162 | "metadata": { 163 | "kernelspec": { 164 | "display_name": "langchain", 165 | "language": "python", 166 | "name": "python3" 167 | }, 168 | "language_info": { 169 | "codemirror_mode": { 170 | "name": "ipython", 171 | "version": 3 172 | }, 173 | "file_extension": ".py", 174 | "mimetype": "text/x-python", 175 | "name": "python", 176 | "nbconvert_exporter": "python", 177 | "pygments_lexer": "ipython3", 178 | "version": "3.10.12" 179 | }, 180 | "orig_nbformat": 4 181 | }, 182 | "nbformat": 4, 183 | "nbformat_minor": 2 184 | } 185 | -------------------------------------------------------------------------------- /notebook/C4 数据库搭建/3. 构建项目数据库.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 第三章 构建项目数据库" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "在前面两章我们具体介绍了我们的知识库选择,并介绍了如何加载、处理数据并构建、使用向量数据库。在本章中,我们结合之前讲解的内容,具体构建出本项目使用的数据库,之后我们的 Prompt Engineeering 及迭代优化、验证评估均会在该数据库基础上进行。\n", 15 | "\n", 16 | "在这里,我们使用 OpenAI 的 Embedding 模型实现向量化,大家也可以根据前面的讲解选用不同的 Embedding 模型。\n", 17 | "\n", 18 | "由于此处加载向量数据库需要一定时间运行,我们也提供了 py 脚本供大家使用。" 19 | ] 20 | }, 21 | { 22 | "cell_type": "code", 23 | "execution_count": 6, 24 | "metadata": {}, 25 | "outputs": [], 26 | "source": [ 27 | "# 首先实现基本配置\n", 28 | "from langchain.vectorstores import Chroma\n", 29 | "from langchain.document_loaders import PyMuPDFLoader\n", 30 | "from langchain.text_splitter import RecursiveCharacterTextSplitter\n", 31 | "from langchain.document_loaders import UnstructuredMarkdownLoader\n", 32 | "from langchain.document_loaders import UnstructuredFileLoader\n", 33 | "\n", 34 | "from langchain.embeddings.openai import OpenAIEmbeddings\n", 35 | "from langchain.embeddings.huggingface import HuggingFaceEmbeddings\n", 36 | "\n", 37 | "from langchain.llms import OpenAI\n", 38 | "from langchain.llms import HuggingFacePipeline\n", 39 | "\n", 40 | "# 使用前配置自己的 api 到环境变量中如\n", 41 | "import os\n", 42 | "import openai\n", 43 | "import sys\n", 44 | "\n", 45 | "from dotenv import load_dotenv, find_dotenv\n", 46 | "\n", 47 | "_ = load_dotenv(find_dotenv()) # read local .env fileopenai.api_key = os.environ['OPENAI_API_KEY']\n", 48 | "openai.api_key = os.environ['OPENAI_API_KEY']" 49 | ] 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "metadata": {}, 54 | "source": [ 55 | "接下来逐个加载知识库里的文档:" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 2, 61 | "metadata": {}, 62 | "outputs": [], 63 | "source": [ 64 | "#pdf\n", 65 | "# 加载 PDF\n", 66 | "loaders = [\n", 67 | " PyMuPDFLoader(\"../knowledge_base/pumkin_book/pumpkin_book.pdf\") # 机器学习,\n", 68 | "]\n", 69 | "docs = []\n", 70 | "for loader in loaders:\n", 71 | " docs.extend(loader.load())" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": 5, 77 | "metadata": {}, 78 | "outputs": [], 79 | "source": [ 80 | "#md\n", 81 | "folder_path = \"../knowledge_base/prompt_engineering/\"\n", 82 | "files = os.listdir(folder_path)\n", 83 | "loaders = []\n", 84 | "for one_file in files:\n", 85 | " loader = UnstructuredMarkdownLoader(os.path.join(folder_path, one_file))\n", 86 | " loaders.append(loader)\n", 87 | "for loader in loaders:\n", 88 | " docs.extend(loader.load())" 89 | ] 90 | }, 91 | { 92 | "cell_type": "code", 93 | "execution_count": 7, 94 | "metadata": {}, 95 | "outputs": [], 96 | "source": [ 97 | "#mp4-txt\n", 98 | "loaders = [\n", 99 | " UnstructuredFileLoader(\"../knowledge_base/easy_rl/强化学习入门指南.txt\") # 机器学习,\n", 100 | "]\n", 101 | "for loader in loaders:\n", 102 | " docs.extend(loader.load())" 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": {}, 108 | "source": [ 109 | "然后对加载好的文档进行切片并向量化后存储到向量数据库中:" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": 13, 115 | "metadata": {}, 116 | "outputs": [ 117 | { 118 | "name": "stderr", 119 | "output_type": "stream", 120 | "text": [ 121 | "Using embedded DuckDB with persistence: data will be stored in: ../knowledge_base/chroma\n" 122 | ] 123 | } 124 | ], 125 | "source": [ 126 | "# 切分文档\n", 127 | "text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=150)\n", 128 | "split_docs = text_splitter.split_documents(docs)\n", 129 | "\n", 130 | "\n", 131 | "# 定义 Embeddings\n", 132 | "embedding = OpenAIEmbeddings() \n", 133 | "\n", 134 | "# 定义持久化路径\n", 135 | "persist_directory = '../knowledge_base/chroma'\n", 136 | "\n", 137 | "# 加载数据库\n", 138 | "vectordb = Chroma.from_documents(\n", 139 | " documents=split_docs,\n", 140 | " embedding=embedding,\n", 141 | " persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上\n", 142 | ")" 143 | ] 144 | }, 145 | { 146 | "cell_type": "markdown", 147 | "metadata": {}, 148 | "source": [ 149 | "最后将加载好的向量数据库持久化即可:" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": null, 155 | "metadata": {}, 156 | "outputs": [], 157 | "source": [ 158 | "vectordb.persist()" 159 | ] 160 | } 161 | ], 162 | "metadata": { 163 | "kernelspec": { 164 | "display_name": "Python 3 (ipykernel)", 165 | "language": "python", 166 | "name": "python3" 167 | }, 168 | "language_info": { 169 | "codemirror_mode": { 170 | "name": "ipython", 171 | "version": 3 172 | }, 173 | "file_extension": ".py", 174 | "mimetype": "text/x-python", 175 | "name": "python", 176 | "nbconvert_exporter": "python", 177 | "pygments_lexer": "ipython3", 178 | "version": "3.8.10" 179 | } 180 | }, 181 | "nbformat": 4, 182 | "nbformat_minor": 4 183 | } 184 | -------------------------------------------------------------------------------- /notebook/C4 数据库搭建/__pycache__/zhipuai_embedding.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/C4 数据库搭建/__pycache__/zhipuai_embedding.cpython-310.pyc -------------------------------------------------------------------------------- /notebook/C4 数据库搭建/create_db.py: -------------------------------------------------------------------------------- 1 | # 首先实现基本配置 2 | from langchain.vectorstores import Chroma 3 | from langchain.document_loaders import PyMuPDFLoader 4 | from langchain.text_splitter import RecursiveCharacterTextSplitter 5 | from langchain.document_loaders import UnstructuredMarkdownLoader 6 | from langchain.document_loaders import UnstructuredFileLoader 7 | 8 | from langchain.embeddings.openai import OpenAIEmbeddings 9 | from langchain.embeddings.huggingface import HuggingFaceEmbeddings 10 | 11 | from langchain.llms import OpenAI 12 | from langchain.llms import HuggingFacePipeline 13 | 14 | # 使用前配置自己的 api 到环境变量中如 15 | import os 16 | import openai 17 | import sys 18 | 19 | from dotenv import load_dotenv, find_dotenv 20 | 21 | _ = load_dotenv(find_dotenv()) # read local .env fileopenai.api_key = os.environ['OPENAI_API_KEY'] 22 | openai.api_key = os.environ['OPENAI_API_KEY'] 23 | 24 | #pdf 25 | # 加载 PDF 26 | loaders = [ 27 | PyMuPDFLoader("../knowledge_base/pumkin_book/pumpkin_book.pdf") # 机器学习, 28 | ] 29 | docs = [] 30 | for loader in loaders: 31 | docs.extend(loader.load()) 32 | 33 | #md 34 | folder_path = "../knowledge_base/prompt_engineering/" 35 | files = os.listdir(folder_path) 36 | loaders = [] 37 | for one_file in files: 38 | loader = UnstructuredMarkdownLoader(os.path.join(folder_path, one_file)) 39 | loaders.append(loader) 40 | for loader in loaders: 41 | docs.extend(loader.load()) 42 | 43 | #mp4-txt 44 | loaders = [ 45 | UnstructuredFileLoader("../knowledge_base/easy_rl/强化学习入门指南.txt") # 机器学习, 46 | ] 47 | for loader in loaders: 48 | docs.extend(loader.load()) 49 | 50 | # 切分文档 51 | text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=150) 52 | split_docs = text_splitter.split_documents(docs) 53 | 54 | 55 | # 定义 Embeddings 56 | embedding = OpenAIEmbeddings() 57 | 58 | # 定义持久化路径 59 | persist_directory = '../knowledge_base/chroma' 60 | 61 | # 加载数据库 62 | vectordb = Chroma.from_documents( 63 | documents=split_docs, 64 | embedding=embedding, 65 | persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上 66 | ) 67 | 68 | vectordb.persist() -------------------------------------------------------------------------------- /notebook/C4 数据库搭建/zhipuai_embedding.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import logging 4 | from typing import Any, Dict, List, Optional 5 | 6 | from langchain.embeddings.base import Embeddings 7 | from langchain.pydantic_v1 import BaseModel, root_validator 8 | from langchain.utils import get_from_dict_or_env 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | class ZhipuAIEmbeddings(BaseModel, Embeddings): 13 | """`Zhipuai Embeddings` embedding models.""" 14 | 15 | zhipuai_api_key: Optional[str] = None 16 | """Zhipuai application apikey""" 17 | 18 | @root_validator() 19 | def validate_environment(cls, values: Dict) -> Dict: 20 | """ 21 | Validate whether zhipuai_api_key in the environment variables or 22 | configuration file are available or not. 23 | 24 | Args: 25 | 26 | values: a dictionary containing configuration information, must include the 27 | fields of zhipuai_api_key 28 | Returns: 29 | 30 | a dictionary containing configuration information. If zhipuai_api_key 31 | are not provided in the environment variables or configuration 32 | file, the original values will be returned; otherwise, values containing 33 | zhipuai_api_key will be returned. 34 | Raises: 35 | 36 | ValueError: zhipuai package not found, please install it with `pip install 37 | zhipuai` 38 | """ 39 | values["zhipuai_api_key"] = get_from_dict_or_env( 40 | values, 41 | "zhipuai_api_key", 42 | "ZHIPUAI_API_KEY", 43 | ) 44 | 45 | try: 46 | import zhipuai 47 | zhipuai.api_key = values["zhipuai_api_key"] 48 | values["client"] = zhipuai.model_api 49 | 50 | except ImportError: 51 | raise ValueError( 52 | "Zhipuai package not found, please install it with " 53 | "`pip install zhipuai`" 54 | ) 55 | return values 56 | 57 | def _embed(self, texts: str) -> List[float]: 58 | # send request 59 | try: 60 | resp = self.client.invoke( 61 | model="text_embedding", 62 | prompt=texts 63 | ) 64 | except Exception as e: 65 | raise ValueError(f"Error raised by inference endpoint: {e}") 66 | 67 | if resp["code"] != 200: 68 | raise ValueError( 69 | "Error raised by inference API HTTP code: %s, %s" 70 | % (resp["code"], resp["msg"]) 71 | ) 72 | embeddings = resp["data"]["embedding"] 73 | return embeddings 74 | 75 | def embed_query(self, text: str) -> List[float]: 76 | """ 77 | Embedding a text. 78 | 79 | Args: 80 | 81 | Text (str): A text to be embedded. 82 | 83 | Return: 84 | 85 | List [float]: An embedding list of input text, which is a list of floating-point values. 86 | """ 87 | resp = self.embed_documents([text]) 88 | return resp[0] 89 | 90 | def embed_documents(self, texts: List[str]) -> List[List[float]]: 91 | """ 92 | Embeds a list of text documents. 93 | 94 | Args: 95 | texts (List[str]): A list of text documents to embed. 96 | 97 | Returns: 98 | List[List[float]]: A list of embeddings for each document in the input list. 99 | Each embedding is represented as a list of float values. 100 | """ 101 | return [self._embed(text) for text in texts] 102 | 103 | async def aembed_documents(self, texts: List[str]) -> List[List[float]]: 104 | """Asynchronous Embed search docs.""" 105 | raise NotImplementedError("Please use `embed_documents`. Official does not support asynchronous requests") 106 | 107 | async def aembed_query(self, text: str) -> List[float]: 108 | """Asynchronous Embed query text.""" 109 | raise NotImplementedError("Please use `aembed_query`. Official does not support asynchronous requests") 110 | -------------------------------------------------------------------------------- /notebook/C5 prompt设计/.ipynb_checkpoints/3.添加历史对话的记忆功能-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 添加历史对话的记忆功能" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "现在我们已经实现了通过上传本地知识文档,然后将他们保存到向量知识库,通过将查询问题与向量知识库的召回结果进行结合输入到 LLM 中,我们就得到了一个相比于直接让 LLM 回答要好得多的结果。在与语言模型交互时,你可能已经注意到一个关键问题 - **它们并不记得你之前的交流内容**。这在我们构建一些应用程序(如聊天机器人)的时候,带来了很大的挑战,使得对话似乎缺乏真正的连续性。这个问题该如何解决呢?\n" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## 1. 记忆(Memory)" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "在本节中我们将介绍 LangChain 中的储存模块,即如何将先前的对话嵌入到语言模型中的,使其具有连续对话的能力。我们将使用 `ConversationBufferMemory` ,它保存聊天消息历史记录的列表,这些历史记录将在回答问题时与问题一起传递给聊天机器人,从而将它们添加到上下文中。" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 3, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "from langchain.memory import ConversationBufferMemory\n", 38 | "\n", 39 | "memory = ConversationBufferMemory(\n", 40 | " memory_key=\"chat_history\", # 与 prompt 的输入变量保持一致。\n", 41 | " return_messages=True # 将以消息列表的形式返回聊天记录,而不是单个字符串\n", 42 | ")" 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "关于更多的 Memory 的使用,包括保留指定对话轮数、保存指定 token 数量、保存历史对话的总结摘要等内容,请参考 langchain 的 Memory 部分的相关文档。" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "## 2. 对话检索链(ConversationalRetrievalChain)" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "对话检索链(ConversationalRetrievalChain)在检索 QA 链的基础上,增加了处理对话历史的能力。\n", 64 | "\n", 65 | "它的工作流程是:\n", 66 | "1. 将之前的对话与新问题合并生成一个完整的查询语句。\n", 67 | "2. 在向量数据库中搜索该查询的相关文档。\n", 68 | "3. 获取结果后,存储所有答案到对话记忆区。\n", 69 | "4. 用户可在 UI 中查看完整的对话流程。" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": {}, 75 | "source": [ 76 | "![](../../figures/Modular_components.png)" 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "metadata": {}, 82 | "source": [ 83 | "这种链式方式将新问题放在之前对话的语境中进行检索,可以处理依赖历史信息的查询。并保留所有信\n", 84 | "息在对话记忆中,方便追踪。\n", 85 | "\n", 86 | "接下来让我们可以测试这个对话检索链的效果:" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "先加载一下上一节中的向量数据库和 LLM !" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 5, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | "from langchain.vectorstores import Chroma\n", 103 | "from langchain.embeddings.openai import OpenAIEmbeddings # 调用 OpenAI 的 Embeddings 模型\n", 104 | "import openai\n", 105 | "from dotenv import load_dotenv, find_dotenv\n", 106 | "import os\n", 107 | "\n", 108 | "_ = load_dotenv(find_dotenv()) # read local .env file\n", 109 | "openai.api_key = os.environ['OPENAI_API_KEY']\n", 110 | "\n", 111 | "# 定义 Embeddings\n", 112 | "embedding = OpenAIEmbeddings() \n", 113 | "# 向量数据库持久化路径\n", 114 | "persist_directory = '../knowledge_base/chroma'\n", 115 | "# 加载数据库\n", 116 | "vectordb = Chroma(\n", 117 | " persist_directory=persist_directory, # 允许我们将persist_directory目录保存到磁盘上\n", 118 | " embedding_function=embedding\n", 119 | ")\n", 120 | "\n", 121 | "# 创建LLM\n", 122 | "from langchain.chat_models import ChatOpenAI\n", 123 | "llm = ChatOpenAI(model_name = \"gpt-3.5-turbo\", temperature = 0 )" 124 | ] 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": {}, 129 | "source": [ 130 | "首先提出一个无历史对话的问题“这门课会学习 Python 吗?”,并查看回答。" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 7, 136 | "metadata": {}, 137 | "outputs": [ 138 | { 139 | "name": "stdout", 140 | "output_type": "stream", 141 | "text": [ 142 | "是的,根据提供的上下文,这门课程会教授关于强化学习的知识。\n" 143 | ] 144 | } 145 | ], 146 | "source": [ 147 | "from langchain.chains import ConversationalRetrievalChain\n", 148 | "\n", 149 | "retriever=vectordb.as_retriever()\n", 150 | "\n", 151 | "qa = ConversationalRetrievalChain.from_llm(\n", 152 | " llm,\n", 153 | " retriever=retriever,\n", 154 | " memory=memory\n", 155 | ")\n", 156 | "question = \"我可以学习到关于强化学习的知识吗?\"\n", 157 | "result = qa({\"question\": question})\n", 158 | "print(result['answer'])" 159 | ] 160 | }, 161 | { 162 | "cell_type": "markdown", 163 | "metadata": {}, 164 | "source": [ 165 | "然后基于答案进行下一个问题“为什么这门课需要教这方面的知识?”:" 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": 8, 171 | "metadata": {}, 172 | "outputs": [ 173 | { 174 | "name": "stdout", 175 | "output_type": "stream", 176 | "text": [ 177 | "这门课需要教授关于强化学习的知识,是因为强化学习是一种用来学习如何做出一系列好的决策的方法。在人工智能领域,强化学习的应用非常广泛,可以用于控制机器人、实现自动驾驶、优化推荐系统等。学习强化学习可以帮助我们理解和应用这一领域的核心算法和方法,从而更好地解决实际问题。\n" 178 | ] 179 | } 180 | ], 181 | "source": [ 182 | "question = \"为什么这门课需要教这方面的知识?\"\n", 183 | "result = qa({\"question\": question})\n", 184 | "print(result['answer'])" 185 | ] 186 | }, 187 | { 188 | "cell_type": "markdown", 189 | "metadata": {}, 190 | "source": [ 191 | "可以看到,LLM 它准确地判断了这方面的知识,指代内容是强化学习的知识,也就\n", 192 | "是我们成功地传递给了它历史信息。这种持续学习和关联前后问题的能力,可大大增强问答系统的连续\n", 193 | "性和智能水平。" 194 | ] 195 | }, 196 | { 197 | "cell_type": "markdown", 198 | "metadata": {}, 199 | "source": [] 200 | } 201 | ], 202 | "metadata": { 203 | "kernelspec": { 204 | "display_name": "xuhu", 205 | "language": "python", 206 | "name": "python3" 207 | }, 208 | "language_info": { 209 | "codemirror_mode": { 210 | "name": "ipython", 211 | "version": 3 212 | }, 213 | "file_extension": ".py", 214 | "mimetype": "text/x-python", 215 | "name": "python", 216 | "nbconvert_exporter": "python", 217 | "pygments_lexer": "ipython3", 218 | "version": "3.9.16" 219 | } 220 | }, 221 | "nbformat": 4, 222 | "nbformat_minor": 2 223 | } 224 | -------------------------------------------------------------------------------- /notebook/C5 prompt设计/3.添加历史对话的记忆功能.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# 添加历史对话的记忆功能" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "现在我们已经实现了通过上传本地知识文档,然后将他们保存到向量知识库,通过将查询问题与向量知识库的召回结果进行结合输入到 LLM 中,我们就得到了一个相比于直接让 LLM 回答要好得多的结果。在与语言模型交互时,你可能已经注意到一个关键问题 - **它们并不记得你之前的交流内容**。这在我们构建一些应用程序(如聊天机器人)的时候,带来了很大的挑战,使得对话似乎缺乏真正的连续性。这个问题该如何解决呢?\n" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## 1. 记忆(Memory)" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "在本节中我们将介绍 LangChain 中的储存模块,即如何将先前的对话嵌入到语言模型中的,使其具有连续对话的能力。我们将使用 `ConversationBufferMemory` ,它保存聊天消息历史记录的列表,这些历史记录将在回答问题时与问题一起传递给聊天机器人,从而将它们添加到上下文中。" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 3, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "from langchain.memory import ConversationBufferMemory\n", 38 | "\n", 39 | "memory = ConversationBufferMemory(\n", 40 | " memory_key=\"chat_history\", # 与 prompt 的输入变量保持一致。\n", 41 | " return_messages=True # 将以消息列表的形式返回聊天记录,而不是单个字符串\n", 42 | ")" 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "关于更多的 Memory 的使用,包括保留指定对话轮数、保存指定 token 数量、保存历史对话的总结摘要等内容,请参考 langchain 的 Memory 部分的相关文档。" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "## 2. 对话检索链(ConversationalRetrievalChain)" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "对话检索链(ConversationalRetrievalChain)在检索 QA 链的基础上,增加了处理对话历史的能力。\n", 64 | "\n", 65 | "它的工作流程是:\n", 66 | "1. 将之前的对话与新问题合并生成一个完整的查询语句。\n", 67 | "2. 在向量数据库中搜索该查询的相关文档。\n", 68 | "3. 获取结果后,存储所有答案到对话记忆区。\n", 69 | "4. 用户可在 UI 中查看完整的对话流程。" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": {}, 75 | "source": [ 76 | "![](../../figures/Modular_components.png)" 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "metadata": {}, 82 | "source": [ 83 | "这种链式方式将新问题放在之前对话的语境中进行检索,可以处理依赖历史信息的查询。并保留所有信\n", 84 | "息在对话记忆中,方便追踪。\n", 85 | "\n", 86 | "接下来让我们可以测试这个对话检索链的效果:" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "先加载一下上一节中的向量数据库和 LLM !" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 5, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | "from langchain.vectorstores import Chroma\n", 103 | "from langchain.embeddings.openai import OpenAIEmbeddings # 调用 OpenAI 的 Embeddings 模型\n", 104 | "import openai\n", 105 | "from dotenv import load_dotenv, find_dotenv\n", 106 | "import os\n", 107 | "\n", 108 | "_ = load_dotenv(find_dotenv()) # read local .env file\n", 109 | "openai.api_key = os.environ['OPENAI_API_KEY']\n", 110 | "\n", 111 | "# 定义 Embeddings\n", 112 | "embedding = OpenAIEmbeddings() \n", 113 | "# 向量数据库持久化路径\n", 114 | "persist_directory = '../knowledge_base/chroma'\n", 115 | "# 加载数据库\n", 116 | "vectordb = Chroma(\n", 117 | " persist_directory=persist_directory, # 允许我们将persist_directory目录保存到磁盘上\n", 118 | " embedding_function=embedding\n", 119 | ")\n", 120 | "\n", 121 | "# 创建LLM\n", 122 | "from langchain.chat_models import ChatOpenAI\n", 123 | "llm = ChatOpenAI(model_name = \"gpt-3.5-turbo\", temperature = 0 )" 124 | ] 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": {}, 129 | "source": [ 130 | "首先提出一个无历史对话的问题“这门课会学习 Python 吗?”,并查看回答。" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 7, 136 | "metadata": {}, 137 | "outputs": [ 138 | { 139 | "name": "stdout", 140 | "output_type": "stream", 141 | "text": [ 142 | "是的,根据提供的上下文,这门课程会教授关于强化学习的知识。\n" 143 | ] 144 | } 145 | ], 146 | "source": [ 147 | "from langchain.chains import ConversationalRetrievalChain\n", 148 | "\n", 149 | "retriever=vectordb.as_retriever()\n", 150 | "\n", 151 | "qa = ConversationalRetrievalChain.from_llm(\n", 152 | " llm,\n", 153 | " retriever=retriever,\n", 154 | " memory=memory\n", 155 | ")\n", 156 | "question = \"我可以学习到关于强化学习的知识吗?\"\n", 157 | "result = qa({\"question\": question})\n", 158 | "print(result['answer'])" 159 | ] 160 | }, 161 | { 162 | "cell_type": "markdown", 163 | "metadata": {}, 164 | "source": [ 165 | "然后基于答案进行下一个问题“为什么这门课需要教这方面的知识?”:" 166 | ] 167 | }, 168 | { 169 | "cell_type": "code", 170 | "execution_count": 8, 171 | "metadata": {}, 172 | "outputs": [ 173 | { 174 | "name": "stdout", 175 | "output_type": "stream", 176 | "text": [ 177 | "这门课需要教授关于强化学习的知识,是因为强化学习是一种用来学习如何做出一系列好的决策的方法。在人工智能领域,强化学习的应用非常广泛,可以用于控制机器人、实现自动驾驶、优化推荐系统等。学习强化学习可以帮助我们理解和应用这一领域的核心算法和方法,从而更好地解决实际问题。\n" 178 | ] 179 | } 180 | ], 181 | "source": [ 182 | "question = \"为什么这门课需要教这方面的知识?\"\n", 183 | "result = qa({\"question\": question})\n", 184 | "print(result['answer'])" 185 | ] 186 | }, 187 | { 188 | "cell_type": "markdown", 189 | "metadata": {}, 190 | "source": [ 191 | "可以看到,LLM 它准确地判断了这方面的知识,指代内容是强化学习的知识,也就\n", 192 | "是我们成功地传递给了它历史信息。这种持续学习和关联前后问题的能力,可大大增强问答系统的连续\n", 193 | "性和智能水平。" 194 | ] 195 | }, 196 | { 197 | "cell_type": "markdown", 198 | "metadata": {}, 199 | "source": [] 200 | } 201 | ], 202 | "metadata": { 203 | "kernelspec": { 204 | "display_name": "Python 3 (ipykernel)", 205 | "language": "python", 206 | "name": "python3" 207 | }, 208 | "language_info": { 209 | "codemirror_mode": { 210 | "name": "ipython", 211 | "version": 3 212 | }, 213 | "file_extension": ".py", 214 | "mimetype": "text/x-python", 215 | "name": "python", 216 | "nbconvert_exporter": "python", 217 | "pygments_lexer": "ipython3", 218 | "version": "3.8.10" 219 | } 220 | }, 221 | "nbformat": 4, 222 | "nbformat_minor": 4 223 | } 224 | -------------------------------------------------------------------------------- /notebook/C6 验证迭代/1. 验证迭代的一般思路.md: -------------------------------------------------------------------------------- 1 | # 一、验证迭代的一般思路 2 | 3 | 根据前文所讲解的大模型开发流程,我们可以发现,以调用、发挥大模型为核心的大模型开发相较传统的 AI 开发更注重验证迭代。由于你可以快速构建出基于 LLM 的应用程序,在几分钟内定义一个 Prompt,并在几小时内得到反馈结果,那么停下来收集一千个测试样本就会显得极为繁琐。因为现在,你可以在没有任何训练样本的情况下得到结果。 4 | 5 | 因此,在使用LLM构建应用程序时,你可能会经历以下流程:首先,你会在一到三个样本的小样本中调整 Prompt ,尝试使其在这些样本上起效。随后,当你对系统进行进一步测试时,可能会遇到一些棘手的例子,这些例子无法通过 Prompt 或者算法解决。这就是使用 LLM 构建应用程序的开发者所面临的挑战。在这种情况下,你可以将这些额外的几个例子添加到你正在测试的集合中,有机地添加其他难以处理的例子。最终,你会将足够多的这些例子添加到你逐步扩大的开发集中,以至于手动运行每一个例子以测试 Prompt 变得有些不便。然后,你开始开发一些用于衡量这些小样本集性能的指标,例如平均准确度。这个过程的有趣之处在于,如果你觉得你的系统已经足够好了,你可以随时停止,不再进行改进。实际上,很多已经部署的应用程序就在第一步或第二步就停下来了,而且它们运行得非常好。 6 | 7 | ![](../../figures/eval.png) 8 | 9 | 在上一章 Prompt Engineering 部分,我们已经讲解了如何在数个简单样例的基础上设计 Prompt Engineering,初步实现核心任务的启动。 10 | 11 | 在本章中,我们将逐个介绍接下来的几个步骤,并设计本项目验证迭代的过程,从而实现应用功能的优化。 12 | 13 | 我们将首先介绍如何找出 Bad Case 的一些思路提示,以及针对 Bad Case 针对性做出 Prompt 优化的一般思路。注意,在这一过程中,你仍然应该谨记我们在上一节中所讲述的 Prompt 设计原则与技巧,并时刻保证优化后的 Prompt 不会在原先表现良好的样例上出现失误。 14 | 15 | 接着,我们将简要介绍大模型开发评估的几种方法。对于有简单标准答案的任务来说,评估很容易得到实现;但大模型开发一般是需要实现复杂的生成任务,如何在没有简单答案甚至没有标准答案的情况下实现评估,能够准确地反映应用的效果,我们将简要介绍几种方法。 16 | 17 | 最后,随着我们不断寻找到 Bad Case 并做出针对性优化,我们可以将这些 Bad Case 逐步加入到验证集,从而形成一个有一定样例数的验证集。针对这种验证集,一个一个进行评估就是不切实际的了。我们需要一种自动评估方法,实现对该验证集上性能的整体评估。 18 | 19 | 验证迭代是构建以 LLM 为中心的应用程序所必不能少的重要步骤,通过不断寻找 Bad Case,针对性调整 Prompt 或优化应用框架,来推动应用达到我们目标中的性能与精度。接下来,我们将简要介绍大模型开发评估的几种方法,并概括性介绍从少数 Bad Case 针对性优化到整体自动化评估的一般思路。 -------------------------------------------------------------------------------- /notebook/C7 前后端搭建/.ipynb_checkpoints/2. fast api 进行前后端分离-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | {"cells":[{"cell_type":"markdown","id":"b7cf53b5","metadata":{"height":30},"source":["# Fast api 进行前后端分离 💬"]},{"cell_type":"markdown","id":"f8ce5955","metadata":{"height":30},"source":["目前我们已经完成了基本的可视化页面,并且可以实现对应的功能。"]},{"cell_type":"markdown","id":"32d2d01b","metadata":{},"source":["为了方便整个项目的管理,现有的项目通常采用前后端分离的方式搭建,前后端数据通过 json 的格式进行传输。\n"]},{"cell_type":"markdown","id":"e579ab22","metadata":{},"source":["FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,非常方便用于搭建我们的前后端分离的应用。"]},{"cell_type":"markdown","id":"bfda0137","metadata":{},"source":["我们首先需要将我们用到的后端函数进行 FastAPI 的封装。封装 API 与前文中讲过将大模型 API 封装成本地 API 的方法类似,我们首先导入第三方库并创建一个 API 对象:"]},{"cell_type":"code","execution_count":null,"id":"86e7d807","metadata":{},"outputs":[],"source":["from fastapi import FastAPI\n","from pydantic import BaseModel\n","import os\n","\n","app = FastAPI() # 创建 api 对象"]},{"cell_type":"markdown","id":"2adc8f8e","metadata":{},"source":["本地 API 一般通过 POST 方式进行访问,即参数会附加在 POST 请求中,我们需要定义一个数据模型来接收 POST 请求中的数据:"]},{"cell_type":"code","execution_count":null,"id":"495ff1d7","metadata":{},"outputs":[],"source":["# 定义一个数据模型,用于接收POST请求中的数据\n","class Item(BaseModel):\n"," prompt : str # 用户 prompt\n"," model : str # 使用的模型\n"," temperature : float = 0.1# 温度系数\n"," if_history : bool = False # 是否使用历史对话功能\n"," # API_Key\n"," api_key: str = None\n"," # Secret_Key\n"," secret_key : str = None\n"," # access_token\n"," access_token: str = None\n"," # APPID\n"," appid : str = None\n"," # APISecret\n"," api_secret : str = None\n"," # 数据库路径\n"," db_path : str = \"../database\"\n"," # prompt template\n"," prompt_template : str = None\n"," # Template 变量\n"," input_variables : list = [\"context\",\"question\"]\n"," # Embdding\n"," embedding : str = \"openai\"\n"," # Top K\n"," top_k : int = 5"]},{"cell_type":"markdown","id":"f8a2fd1a","metadata":{},"source":["在上面的类中,我们定义了要调用我们已封装的 QA_chain 所需要传入的参数,对于非必须参数,我们都设置了默认参数来保证调用的简洁性,接下来我们就可以创建一个 POST 请求的 API 端点:"]},{"cell_type":"code","execution_count":null,"id":"39ec91ae","metadata":{},"outputs":[],"source":["@app.post(\"/answer/\")\n","async def get_response(item: Item):\n","\n"," # 首先确定需要调用的链\n"," if not item.if_history:\n"," # 调用 Chat 链\n"," chain = QA_chain_self(item.db_path, item.model, item.prompt_template, \n"," item.input_variables, item.temperature, item.api_key,\n"," item.secret_key, item.access_token, item.appid, item.api_secret, item.embedding)\n"," \n"," response = chain.answer(question = item.prompt, top_k = item.top_k, temperature = item.temperature)\n"," \n"," return response\n"," \n"," # 由于 API 存在即时性问题,不能支持历史链\n"," else:\n"," return \"API 不支持历史链\""]},{"cell_type":"markdown","id":"e702e041","metadata":{},"source":["上述端点的业务逻辑很简单,即调用我们已封装的 QA_chain_self 对象进行实例化与回答即可。通过这一个端点启动,我们便可通过访问本地 8000 端口来调用个人知识库助手的服务啦,我们只需要通过下列命令启动: "]},{"cell_type":"code","execution_count":null,"id":"648f39a3","metadata":{},"outputs":[],"source":["uvicorn app:app "]}],"metadata":{"kernelspec":{"display_name":"Python 3.9.6 64-bit","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.9.6"},"vscode":{"interpreter":{"hash":"31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6"}}},"nbformat":4,"nbformat_minor":5} 2 | -------------------------------------------------------------------------------- /notebook/C7 前后端搭建/2. fast api 进行前后端分离.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "b7cf53b5", 6 | "metadata": { 7 | "height": 30 8 | }, 9 | "source": [ 10 | "# Fast api 进行前后端分离 💬" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "f8ce5955", 16 | "metadata": { 17 | "height": 30 18 | }, 19 | "source": [ 20 | "目前我们已经完成了基本的可视化页面,并且可以实现对应的功能。" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "id": "32d2d01b", 26 | "metadata": {}, 27 | "source": [ 28 | "为了方便整个项目的管理,现有的项目通常采用前后端分离的方式搭建,前后端数据通过 json 的格式进行传输。\n" 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "id": "e579ab22", 34 | "metadata": {}, 35 | "source": [ 36 | "FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,非常方便用于搭建我们的前后端分离的应用。" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "id": "bfda0137", 42 | "metadata": {}, 43 | "source": [ 44 | "我们首先需要将我们用到的后端函数进行 FastAPI 的封装。封装 API 与前文中讲过将大模型 API 封装成本地 API 的方法类似,我们首先导入第三方库并创建一个 API 对象:" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": null, 50 | "id": "86e7d807", 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "from fastapi import FastAPI\n", 55 | "from pydantic import BaseModel\n", 56 | "import os\n", 57 | "\n", 58 | "app = FastAPI() # 创建 api 对象" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "id": "2adc8f8e", 64 | "metadata": {}, 65 | "source": [ 66 | "本地 API 一般通过 POST 方式进行访问,即参数会附加在 POST 请求中,我们需要定义一个数据模型来接收 POST 请求中的数据:" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": null, 72 | "id": "495ff1d7", 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [ 76 | "# 定义一个数据模型,用于接收POST请求中的数据\n", 77 | "class Item(BaseModel):\n", 78 | " prompt : str # 用户 prompt\n", 79 | " model : str # 使用的模型\n", 80 | " temperature : float = 0.1# 温度系数\n", 81 | " if_history : bool = False # 是否使用历史对话功能\n", 82 | " # API_Key\n", 83 | " api_key: str = None\n", 84 | " # Secret_Key\n", 85 | " secret_key : str = None\n", 86 | " # access_token\n", 87 | " access_token: str = None\n", 88 | " # APPID\n", 89 | " appid : str = None\n", 90 | " # APISecret\n", 91 | " api_secret : str = None\n", 92 | " # 数据库路径\n", 93 | " db_path : str = \"../database\"\n", 94 | " # prompt template\n", 95 | " prompt_template : str = None\n", 96 | " # Template 变量\n", 97 | " input_variables : list = [\"context\",\"question\"]\n", 98 | " # Embdding\n", 99 | " embedding : str = \"openai\"\n", 100 | " # Top K\n", 101 | " top_k : int = 5" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "id": "f8a2fd1a", 107 | "metadata": {}, 108 | "source": [ 109 | "在上面的类中,我们定义了要调用我们已封装的 QA_chain 所需要传入的参数,对于非必须参数,我们都设置了默认参数来保证调用的简洁性,接下来我们就可以创建一个 POST 请求的 API 端点:" 110 | ] 111 | }, 112 | { 113 | "cell_type": "code", 114 | "execution_count": null, 115 | "id": "39ec91ae", 116 | "metadata": {}, 117 | "outputs": [], 118 | "source": [ 119 | "@app.post(\"/answer/\")\n", 120 | "async def get_response(item: Item):\n", 121 | "\n", 122 | " # 首先确定需要调用的链\n", 123 | " if not item.if_history:\n", 124 | " # 调用 Chat 链\n", 125 | " chain = QA_chain_self(item.db_path, item.model, item.prompt_template, \n", 126 | " item.input_variables, item.temperature, item.api_key,\n", 127 | " item.secret_key, item.access_token, item.appid, item.api_secret, item.embedding)\n", 128 | " \n", 129 | " response = chain.answer(question = item.prompt, top_k = item.top_k, temperature = item.temperature)\n", 130 | " \n", 131 | " return response\n", 132 | " \n", 133 | " # 由于 API 存在即时性问题,不能支持历史链\n", 134 | " else:\n", 135 | " return \"API 不支持历史链\"" 136 | ] 137 | }, 138 | { 139 | "cell_type": "markdown", 140 | "id": "e702e041", 141 | "metadata": {}, 142 | "source": [ 143 | "上述端点的业务逻辑很简单,即调用我们已封装的 QA_chain_self 对象进行实例化与回答即可。通过这一个端点启动,我们便可通过访问本地 8000 端口来调用个人知识库助手的服务啦,我们只需要通过下列命令启动: " 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": null, 149 | "id": "648f39a3", 150 | "metadata": {}, 151 | "outputs": [], 152 | "source": [ 153 | "uvicorn app:app " 154 | ] 155 | } 156 | ], 157 | "metadata": { 158 | "kernelspec": { 159 | "display_name": "Python 3 (ipykernel)", 160 | "language": "python", 161 | "name": "python3" 162 | }, 163 | "language_info": { 164 | "codemirror_mode": { 165 | "name": "ipython", 166 | "version": 3 167 | }, 168 | "file_extension": ".py", 169 | "mimetype": "text/x-python", 170 | "name": "python", 171 | "nbconvert_exporter": "python", 172 | "pygments_lexer": "ipython3", 173 | "version": "3.8.10" 174 | }, 175 | "vscode": { 176 | "interpreter": { 177 | "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" 178 | } 179 | } 180 | }, 181 | "nbformat": 4, 182 | "nbformat_minor": 5 183 | } 184 | -------------------------------------------------------------------------------- /notebook/knowledge_base/chroma/chroma-collections.parquet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/knowledge_base/chroma/chroma-collections.parquet -------------------------------------------------------------------------------- /notebook/knowledge_base/chroma/chroma-embeddings.parquet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/knowledge_base/chroma/chroma-embeddings.parquet -------------------------------------------------------------------------------- /notebook/knowledge_base/chroma/index/id_to_uuid_0a21ea39-d07d-45a7-80e3-a7e68cca4cb8.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/knowledge_base/chroma/index/id_to_uuid_0a21ea39-d07d-45a7-80e3-a7e68cca4cb8.pkl -------------------------------------------------------------------------------- /notebook/knowledge_base/chroma/index/id_to_uuid_1c24e063-9da4-403a-9153-f6b210c294d6.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/knowledge_base/chroma/index/id_to_uuid_1c24e063-9da4-403a-9153-f6b210c294d6.pkl -------------------------------------------------------------------------------- /notebook/knowledge_base/chroma/index/index_0a21ea39-d07d-45a7-80e3-a7e68cca4cb8.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/knowledge_base/chroma/index/index_0a21ea39-d07d-45a7-80e3-a7e68cca4cb8.bin -------------------------------------------------------------------------------- /notebook/knowledge_base/chroma/index/index_1c24e063-9da4-403a-9153-f6b210c294d6.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/knowledge_base/chroma/index/index_1c24e063-9da4-403a-9153-f6b210c294d6.bin -------------------------------------------------------------------------------- /notebook/knowledge_base/chroma/index/index_metadata_0a21ea39-d07d-45a7-80e3-a7e68cca4cb8.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/knowledge_base/chroma/index/index_metadata_0a21ea39-d07d-45a7-80e3-a7e68cca4cb8.pkl -------------------------------------------------------------------------------- /notebook/knowledge_base/chroma/index/index_metadata_1c24e063-9da4-403a-9153-f6b210c294d6.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/knowledge_base/chroma/index/index_metadata_1c24e063-9da4-403a-9153-f6b210c294d6.pkl -------------------------------------------------------------------------------- /notebook/knowledge_base/chroma/index/uuid_to_id_0a21ea39-d07d-45a7-80e3-a7e68cca4cb8.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/knowledge_base/chroma/index/uuid_to_id_0a21ea39-d07d-45a7-80e3-a7e68cca4cb8.pkl -------------------------------------------------------------------------------- /notebook/knowledge_base/chroma/index/uuid_to_id_1c24e063-9da4-403a-9153-f6b210c294d6.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/knowledge_base/chroma/index/uuid_to_id_1c24e063-9da4-403a-9153-f6b210c294d6.pkl -------------------------------------------------------------------------------- /notebook/knowledge_base/easy_rl/强化学习入门指南.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/knowledge_base/easy_rl/强化学习入门指南.mp4 -------------------------------------------------------------------------------- /notebook/knowledge_base/easy_rl/强化学习入门指南.txt: -------------------------------------------------------------------------------- 1 | B站的小伙伴们好 2 | 我是蘑菇书一语二语二强化学习教程的作者之一王奇 3 | 今天来有给大家带来一个强化学习的入门指南 4 | 本次入门指南基于蘑菇书一语二语二强化学习教程 5 | 本书的作者目前都是Dell会员成员 6 | 也都是数学在读 7 | 下面去介绍每个作者 8 | 我是王奇 9 | 目前就留于中国科研院大学 10 | 引用方向是深度学习、静态视觉以及数据挖掘 11 | 杨玉云目前就读于清华大学 12 | 他的引用方向为 13 | 时空数据挖掘、智能冲砍系统以及深度学习 14 | 张记目前就读于北京大学 15 | 他的引用方向为强化学习记忆人 16 | 接下来开始正式的分享 17 | 本次分享分为三部分 18 | 第一部分 19 | 为什么要学强化学习 20 | 第二部分 21 | 为什么要用本书来学 22 | 第三部分 23 | 这本书怎么学最高效 24 | 首先讲一下为什么要学强化学习 25 | 我们先聊一下强化学习的基本概念 26 | 强化学习用来学习如何做出一系列好的决策 27 | 而人工智能的基本挑战是 28 | 学习在不确定的情况下做出好的决策 29 | 这边我举个例子 30 | 比如你想让一个小孩学会走路 31 | 他就需要通过不断尝试来发现 32 | 怎么走比较好 33 | 怎么走比较快 34 | 强化学习的交互过程可以通过这张图来表示 35 | 强化学习由智能体和环境两部分组成 36 | 在强化学习过程中 37 | 智能体与环境一直在交互 38 | 智能体在环境中获取某个状态后 39 | 它会利用刚刚的状态输出一个动作 40 | 这个动作也被称为决策 41 | 然后这个动作会被环境中执行 42 | 环境会根据智能体采取的动作 43 | 来输出下一个状态 44 | 以及当前这个动作带来的奖励 45 | 整体它的目的呢 46 | 就是尽可能的多的 47 | 尽可能多的在环境中获取奖励 48 | 强化学习的应用非常广泛 49 | 比如说我们可以使用强化学习来玩游戏 50 | 玩游戏的话可以玩这种电子游戏 51 | 也可以玩这种围棋游戏 52 | 围棋游戏中比较出名的一个 53 | 强化学习的算法就是AlphaGo 54 | 此外我们可以使用强化学习 55 | 来控制机器人 56 | 以及来实现助力交通 57 | 另外还可以使用强化学习 58 | 来更好地给我们做推进 59 | 接下来就到第二部分 60 | 也就是为什么要使用本书来学习强化学习 61 | 这部分其实也是讲 62 | 这个蘑菇书它出版的一些故事 63 | 当时我在学习强化学习的时候 64 | 搜集了一些资料 65 | 然后我发现这些资料 66 | 都有点灰色难懂 67 | 并不是那么容易地上手 68 | 于是我开始到网上 69 | 搜索一些公开课来学习 70 | 首先我搜索到的是 71 | 李宏毅老师的一些公开课 72 | 很多人就是入门深度学习 73 | 和基学低门课 74 | 其实就是李宏毅老师的课 75 | 李宏毅老师的课 76 | 李宏毅老师的基础学习和深度学习公开课 77 | 在编上有很高的播放量 78 | 于是我搜索了李宏毅老师的强化学习课 79 | 这门课叫顺强化学习 80 | 这门课跟以往的李宏毅老师的 81 | 课人的风格都是一样的 82 | 就是非常的生动有趣 83 | 李宏毅老师经常会用 84 | 玩亚达利游戏的例子来讲强化学习 85 | 这样强化学你就变得通透易懂 86 | 然后就很多人都会 87 | 把这门课作为自己的强化学习入门课 88 | 这边我们念出了一些 89 | 就是观众的一些好评 90 | 比如说这边观众说 91 | 国内这个讲得最好了 92 | 然后李宏毅老师讲得真厉害 93 | 还有这个评论比较搞笑 94 | 这个视频每天晚上都有 95 | 几个到十几个人在看 96 | 因此我们可以发现 97 | 这门课还是非常受人欢迎的 98 | 后来我发现李宏毅老师的课 99 | 不是那么全面 100 | 他的课主要集中于讲解 101 | 迅速强化学算法 102 | 而忽略了全球强化学算法 103 | 以及一些比较前沿的强化学算法 104 | 因此我开始 105 | 到网上搜索其他的强化学公开课 106 | 当时是搜索到了 107 | 周博恩老师的强化学纲要 108 | 周博恩老师是 109 | 人文智能底层的一个顶尖学者 110 | 他在人文智能底层会议 111 | 亲爱发表了五十余篇学术论文 112 | 然后论文的作用量超过一万次 113 | 周博恩老师的这门强化学纲要课 114 | 就是理论严谨 115 | 然后内容丰富 116 | 全面的教训介绍了强化学领域 117 | 并有相关代码实践 118 | 在学习完 119 | 女红衣和周博恩老师两门强化学课以后 120 | 我发现还是有一点不足 121 | 就是代码的实践还偏少 122 | 于是我在网上搜索其他的强化学课 123 | 当时就搜索了李克强老师的一个 124 | 叫试验冠军代理丛林实践强化学习这门课 125 | 这门课有个特别突出的优点 126 | 就是实战性强 127 | 突兵课只能会使用单单的代码来讲解强化学习 128 | 这边也有很多好评 129 | 有了这三门课以后 130 | 我发现这三门课 131 | 通过这些公开课来进学的话 132 | 有些优点但也有缺点 133 | 优点的话就是这些课都是非常经典的一些公开课 134 | 然后他们这些课的这些老师 135 | 也都是人文领域的一些大流 136 | 然后他们的播放量非常高 137 | 就比较受欢迎 138 | 但是这些课呢也会存在一些问题 139 | 就用这些公开课来进学的课会存在一些问题 140 | 比如说它不便于实际的查询 141 | 然后对于一些重点的知识点它会缺乏一些讲解 142 | 此外这些知识点比较分散 143 | 就每个老师他讲的知识点各有侧重 144 | 此外就是视频的扩弱化比较严重 145 | 因此基于这三门公开课 146 | 就是我和杨亦远和江静 147 | 三个DDR成员 148 | 对这些三门课的内容进行整合补充优化 149 | 然后写出了这本教材叫 150 | Easy IR 强化域教程 151 | 这本教程当时是在 152 | 一开始是在Github上发布的 153 | 然后Github上呢当时发完以后 154 | 就是有很多好评 155 | 比如这边 156 | 比如说有人的同学就说 157 | 昨天非常棒 158 | 超越有帮助感谢博主 159 | 然后等等等等 160 | 然后目前这本书对应的那个Github仓库的 161 | start数已经达48k 162 | 然后 163 | 它的增长就是它的 164 | start数的一个增长曲线 165 | 也是曾经上升的一个态势 166 | 后来我们在DataWare举办了一次组队学习 167 | 然后组队学习的那个教材呢 168 | 就是以我们这本书的 169 | Github的那个在线版 170 | 作为一个教材 171 | 在组队学习结束以后 172 | 然后也是有很多的 173 | 来自世界各地的学习的小伙伴 174 | 给出好评 175 | 比如这边我就 176 | 列出了一个小伙伴的好评 177 | 然后因为在Github上有很多的读者 178 | 会通过issue来给我们反馈 179 | 比如说他们会觉得我们来的地方 180 | 翻译来电会有些问题 181 | 他们会直接列出来 182 | 然后我们也会给他们及时的反馈 183 | 然后对我们的教程进行优化 184 | 后来我们初入以后 185 | 有幸得到了七位强行学习领域 186 | 大开的亲笔推荐 187 | 比如说台湾大学的宁欧英老师 188 | 周伯伦老师以及李克强老师 189 | 还有比如清华的宁生梦老师 190 | 汪峥老师张伟老师 191 | 胡玉静老师等等 192 | 然后这边我们列出了 193 | 宁欧英老师的一个推荐语 194 | 因为我觉得宁欧英老师的 195 | 推荐语非常的有趣 196 | 比如他说 197 | 他当时看到我们这个 198 | 伊丽艾尔这本书的时候 199 | 他第一个想法是 200 | 这成员把强化学习的知识整理得真好 201 | 不仅有理论说明 202 | 还加上了诚实实力 203 | 同学们以后可以直接阅读这份教程 204 | 这样我以后上课 205 | 就不用再讲强化学习的部分了 206 | 可以发现宁欧英对我们 207 | 这本书还是挺认可的 208 | 然后再来讲一个问题 209 | 这本书为什么叫蘑菇书呢 210 | 难道是因为作者都是吃货 211 | 之前有一本西瓜书 212 | 还有一本南瓜书 213 | 然后作为一个吃货的话 214 | 还有一个传承一下叫蘑菇书 215 | 就吃完西瓜南瓜再来热蘑菇 216 | 但其实并不是 217 | 蘑菇书真的寓意是玛里奥 218 | 大家如果玩过超级玛里奥游戏 219 | 就知道玛里奥吃了蘑菇以后 220 | 会变得更加强大 221 | 然后我们也希望读者 222 | 在吃下这个蘑菇书以后 223 | 能够养有兴致的探索强化学习 224 | 然后像玛里奥那样越强大 225 | 然后进而在人工智能领域里面 226 | 获得一些奇葩收获 227 | 这边我们放出了一个小彩蛋 228 | 就是我们的作者之一杨亦远 229 | 跟宁欧英老师的一个意外接触 230 | 当时杨亦远在参加一个顶位的时候 231 | 发现宁欧英老师也在参会者名单里面 232 | 他给宁欧英老师发了封邮件 233 | 介绍了我们当时GitHub的开源教程 234 | 然后非常惊喜的就是 235 | 宁欧英老师很快地给出了回信 236 | 然后也是对我们这个教程给出了好评 237 | 这边列出了蘑菇书获得的一些荣誉 238 | 比如说人民邮件出版社的季度好书 239 | 然后日读期期间 240 | 当当计算机期中网的第一名 241 | 然后上市时间以后 242 | 获得的就是京东人工智能榜的第一名 243 | 全网的推文阅读量破十万 244 | 然后目前清华大学李淑木教授 245 | 小米NLP首位科学家王斌老师 246 | 以及百度高级研发工程师李克强老师 247 | 还有一些等20家的一个大咖公众号 248 | 以及微博大V社区他们进行的一个转发推荐 249 | 然后这个也被推荐到华为电影大学的一个保定图书馆 250 | 蘑菇书全书一共13章可以分两部分 251 | 第一部分他介绍了强学的基础知识 252 | 以及传统的强化学习算法 253 | 第二部分他介绍了 254 | 适用强化学习算法 255 | 以及常见问题的解决方法 256 | 咱们这本书还有一些突出的特点 257 | 比如第一点 258 | 我们会利用一些简单生动的例子来解释强化学概念 259 | 比如说我们可以用这个玩视频游戏 260 | 以及下围棋的例子 261 | 来对强化学的一些基本概念做出解释 262 | 然后还有一些其他特点 263 | 比如说我们会对专业的一些公式 264 | 进行详细的推导和分析 265 | 这边我们以这个比尔曼方程的 266 | 这个推导过程的例子 267 | 我们会一步一步的把这个推导过程念出来 268 | 不会跳步走 269 | 然后此外呢 270 | 我们还会对一些 271 | 可能大家比较难以理解的地方 272 | 我们会加入一些注解 273 | 通过这些注解 274 | 我们会让大家更容易理解一些相关的概念 275 | 此外本书配有对应的一个观念词 276 | 习题和面试题 277 | 当读者读完一章以后 278 | 大家可以通过观念词来快速的掌握重点 279 | 然后一个通过习题和面试题 280 | 来巩固对知识的理解 281 | 然后这个习题和面试题 282 | 也方便大家的一个程度补缺 283 | 然后最后呢 284 | 我们会有对应的代码实战 285 | 大家学完这个理论以后 286 | 还要通过动手来把这个代码进行 287 | 来把这个算法进行一个实践 288 | 就是大家把这个算法进行实践以后 289 | 大家才算对这个算法 290 | 有一个比较深入了解 291 | 接下来到最后一部分 292 | 叫这本书怎么学比较高效 293 | 第一个 294 | 当然你可以把这本书 295 | 作为三门公开课的一个必要教材 296 | 就是当你在看这三门课的时候 297 | 如果你发现有哪些概念不是很清楚的情况下 298 | 你是可以直接翻到 299 | 本书对应的知识点进行学习 300 | 当然本书也是完全图形于三门教材的 301 | 大家可以直接预读本书进行学习 302 | 本书在GitHub上面 303 | 配有对应的代码 304 | 这个代码也会适宜的更新 305 | 大家如果只是想很快的 306 | 把这个算法给应用上 307 | 大家可以直接去GitHub上 308 | 跑对应的代码 309 | 此外本书还有相关的一个刊物和修订 310 | 这些刊物和修订 311 | 也会根据大家的反馈的一些意见 312 | 进行一些适宜的更新 313 | 然后这边也要讲一下 314 | 本书它在GitHub有个叫PK版 315 | 然后它还有这种纸质书的版本叫纸质版 316 | 它们有什么区别呢 317 | 就GitHub的那种PK版本是本书的一个初稿 318 | 然后在本书的作者已经憋进来 319 | 不断的修改中 320 | 我们最后有了纸质版 321 | 大家看到我们 322 | 对这个PK版本里面有了大量的修订 323 | 所以说纸质书的一个质量 324 | 相对于PK版本是要高不少的 325 | 讲到这里大家可能会有疑问 326 | 可能是如果我目前我涉及的工作 327 | 不涉及到强化学习 328 | 那我还有必要学强化学习吗 329 | 对于这个问题我想用乔布斯的观点 330 | 叫黏生命的点 331 | 或者叫应用相连 332 | 这边就举一下乔布斯他本人的例子 333 | 乔布斯当时在大学学了一门书法课 334 | 这门课在很多人眼里都是没有用处的 335 | 而乔布斯他本人也是出于兴趣 336 | 才学这门课 337 | 他也没有对这门课抱有很大的期望 338 | 但是后来发现他这门课 339 | 在设计苹果电脑字体的时候 340 | 取到了极大作用 341 | 如果乔布斯当时没有学这门课的话 342 | 大家可能就看不到 343 | 苹果电脑中这些优美丰富赏意悦目的字体 344 | 而对强化学习来说 345 | 强化学习这种应用非常广泛的技术 346 | 即使现在可能跟你的工作没有很大关联 347 | 但说不定某一天 348 | 可能你的工作就要涉及到相关的 349 | 涉及到强化学习 350 | 这时候如果你在之前 351 | 对强化学习有一个基本了解 352 | 或者说入门的强化学习 353 | 这时候可能对你的工作 354 | 会起到一个意想不到的助理 355 | 最后我们念出了蘑菇书 356 | 在京东以及档案的一个购买的链接 357 | 以及对应的二维码 358 | 然后大家可以在这两个 359 | 可以在京东和档案上 360 | 购买对应的直述进行学习 361 | 然后我们念一下slogan 362 | 就是我们这本书的一个标语 363 | 标语叫EAR 364 | 像柴蘑菇一样轻松入门强化学习 365 | 然后这个标语 366 | 也代表了我们作者的编写这本书的一个目的 367 | 就想让大家学习强化学习的时候 368 | 更加轻松 369 | 不要像当时作者学习强化学习那样 370 | 有很多的困难 371 | 然后最后祝大家都能够轻松入门强化学习 372 | 然后学习强化学习的过程都很顺利 373 | -------------------------------------------------------------------------------- /notebook/knowledge_base/prompt_engineering/1. 简介 Introduction.md: -------------------------------------------------------------------------------- 1 | # 第一章 简介 2 | 3 | 欢迎来到**面向开发者的提示工程**部分,本部分内容基于**吴恩达老师的《Prompt Engineering for Developer》课程**进行编写。《Prompt Engineering for Developer》课程是由**吴恩达老师**与 OpenAI 技术团队成员 **Isa Fulford** 老师合作授课,Isa 老师曾开发过受欢迎的 ChatGPT 检索插件,并且在教授 LLM (Large Language Model, 大语言模型)技术在产品中的应用方面做出了很大贡献。她还参与编写了教授人们使用 Prompt 的 OpenAI cookbook。我们希望通过本模块的学习,与大家分享使用提示词开发 LLM 应用的最佳实践和技巧。 4 | 5 | 网络上有许多关于提示词(Prompt, 本教程中将保留该术语)设计的材料,例如《30 prompts everyone has to know》之类的文章,这些文章主要集中在 **ChatGPT 的 Web 界面上**,许多人在使用它执行特定的、通常是一次性的任务。但我们认为,对于开发人员,**大语言模型(LLM) 的更强大功能是能通过 API 接口调用,从而快速构建软件应用程序**。实际上,我们了解到 DeepLearning.AI 的姊妹公司 AI Fund 的团队一直在与许多初创公司合作,将这些技术应用于诸多应用程序上。很兴奋能看到 LLM API 能够让开发人员非常快速地构建应用程序。 6 | 7 | 在本模块,我们将与读者分享提升大语言模型应用效果的各种技巧和最佳实践。书中内容涵盖广泛,包括软件开发提示词设计、文本总结、推理、转换、扩展以及构建聊天机器人等语言模型典型应用场景。我们衷心希望该课程能激发读者的想象力,开发出更出色的语言模型应用。 8 | 9 | 随着 LLM 的发展,其大致可以分为两种类型,后续称为**基础 LLM** 和**指令微调(Instruction Tuned)LLM**。**基础LLM**是基于文本训练数据,训练出预测下一个单词能力的模型。其通常通过在互联网和其他来源的大量数据上训练,来确定紧接着出现的最可能的词。例如,如果你以“从前,有一只独角兽”作为 Prompt ,基础 LLM 可能会继续预测“她与独角兽朋友共同生活在一片神奇森林中”。但是,如果你以“法国的首都是什么”为 Prompt ,则基础 LLM 可能会根据互联网上的文章,将回答预测为“法国最大的城市是什么?法国的人口是多少?”,因为互联网上的文章很可能是有关法国国家的问答题目列表。 10 | 11 | 与基础语言模型不同,**指令微调 LLM** 通过专门的训练,可以更好地理解并遵循指令。举个例子,当询问“法国的首都是什么?”时,这类模型很可能直接回答“法国的首都是巴黎”。指令微调 LLM 的训练通常基于预训练语言模型,先在大规模文本数据上进行**预训练**,掌握语言的基本规律。在此基础上进行进一步的训练与**微调(finetune)**,输入是指令,输出是对这些指令的正确回复。有时还会采用**RLHF(reinforcement learning from human feedback,人类反馈强化学习)**技术,根据人类对模型输出的反馈进一步增强模型遵循指令的能力。通过这种受控的训练过程。指令微调 LLM 可以生成对指令高度敏感、更安全可靠的输出,较少无关和损害性内容。因此。许多实际应用已经转向使用这类大语言模型。 12 | 13 | 因此,本课程将重点介绍针对指令微调 LLM 的最佳实践,我们也建议您将其用于大多数使用场景。当您使用指令微调 LLM 时,您可以类比为向另一个人提供指令(假设他很聪明但不知道您任务的具体细节)。因此,当 LLM 无法正常工作时,有时是因为指令不够清晰。例如,如果您想问“请为我写一些关于阿兰·图灵( Alan Turing )的东西”,在此基础上清楚表明您希望文本专注于他的科学工作、个人生活、历史角色或其他方面可能会更有帮助。另外您还可以指定回答的语调, 来更加满足您的需求,可选项包括*专业记者写作*,或者*向朋友写的随笔*等。 14 | 15 | 如果你将 LLM 视为一名新毕业的大学生,要求他完成这个任务,你甚至可以提前指定他们应该阅读哪些文本片段来写关于阿兰·图灵的文本,这样能够帮助这位新毕业的大学生更好地完成这项任务。本书的下一章将详细阐释提示词设计的两个关键原则:**清晰明确**和**给予充足思考时间**。 16 | -------------------------------------------------------------------------------- /notebook/knowledge_base/prompt_engineering/9. 总结 Summary.md: -------------------------------------------------------------------------------- 1 | # 第九章 总结 2 | 3 | **恭喜您完成了本书第一单元内容的学习!** 4 | 5 | 总的来说,在第一部分中,我们学习并掌握了关于 Prompt 的两个核心原则: 6 | 7 | - 编写清晰具体的指令; 8 | - 如果适当的话,给模型一些思考时间。 9 | 10 | 您还学习了迭代式 Prompt 开发的方法,并了解了如何找到适合您应用程序的 Prompt 的过程是非常关键的。 11 | 12 | 我们还讨论了大型语言模型的许多功能,包括摘要、推断、转换和扩展。您也学习了如何搭建个性化的聊天机器人。在第一部分中,您的收获应该颇丰,希望通过第一部分学习能为您带来愉悦的体验。 13 | 14 | 我们期待您能灵感迸发,尝试创建自己的应用。请大胆尝试,并分享给我们您的想法。您可以从一个微型项目开始,或许它具备一定的实用性,或者仅仅是一项有趣的创新。请利用您在第一个项目中得到的经验,去创造更优秀的下一项目,以此类推。如果您已经有一个宏大的项目设想,那么,请毫不犹豫地去实现它。 15 | 16 | 最后,希望您在完成第一部分的过程中感到满足,感谢您的参与。我们热切期待着您的惊艳作品。接下来,我们将进入第二部分的学习! 17 | -------------------------------------------------------------------------------- /notebook/knowledge_base/pumkin_book/pumpkin_book.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/notebook/knowledge_base/pumkin_book/pumpkin_book.pdf -------------------------------------------------------------------------------- /notebook/readme.md: -------------------------------------------------------------------------------- 1 | 存放 Notebook 初稿 2 | -------------------------------------------------------------------------------- /project/database/__init__.py: -------------------------------------------------------------------------------- 1 | from .create_db import create_db -------------------------------------------------------------------------------- /project/database/create_db.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.append(os.path.dirname(os.path.dirname(__file__))) 4 | 5 | # 首先实现基本配置 6 | from langchain.vectorstores import Chroma 7 | from langchain.document_loaders import PyMuPDFLoader 8 | from langchain.text_splitter import RecursiveCharacterTextSplitter 9 | from langchain.document_loaders import UnstructuredMarkdownLoader 10 | from langchain.document_loaders import UnstructuredFileLoader 11 | 12 | from embedding.call_embedding import get_embedding 13 | import gradio as gr 14 | 15 | from dotenv import load_dotenv, find_dotenv 16 | import tempfile 17 | 18 | 19 | def file_loader(file, loaders): 20 | if isinstance(file, tempfile._TemporaryFileWrapper): 21 | file = file.name 22 | if not os.path.isfile(file): 23 | [file_loader(os.path.join(file, f), loaders) for f in os.listdir(file)] 24 | return 25 | file_type = file.split('.')[-1] 26 | if file_type == 'pdf': 27 | loaders.append(PyMuPDFLoader(file)) 28 | elif file_type == 'md': 29 | loaders.append(UnstructuredMarkdownLoader(file)) 30 | elif file_type == 'txt': 31 | loaders.append(UnstructuredFileLoader(file)) 32 | return 33 | 34 | def create_db(files, embeddings): 35 | """ 36 | 该函数用于加载 PDF 文件,切分文档,生成文档的嵌入向量,创建向量数据库。 37 | 38 | 参数: 39 | file: 存放文件的路径。 40 | embeddings: 用于生产 Embedding 的模型 41 | 42 | 返回: 43 | vectordb: 创建的数据库。 44 | """ 45 | if type(files) == str: 46 | files = [files] 47 | if len(files) == 0: 48 | return "can't load empty file" 49 | if type(files) != list: 50 | files = [files] 51 | loaders = [] 52 | [file_loader(file, loaders) for file in files] 53 | docs = [] 54 | for loader in loaders: 55 | if loader is not None: 56 | docs.extend(loader.load()) 57 | [print(doc.metadata) for doc in docs] 58 | # 切分文档 59 | text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=150) 60 | split_docs = text_splitter.split_documents(docs[:10]) 61 | 62 | # 定义持久化路径 63 | persist_directory = '../knowledge_base/chroma' 64 | if type(embeddings) == str: 65 | embeddings = get_embedding(embeddings) 66 | 67 | # 加载数据库 68 | vectordb = Chroma.from_documents( 69 | documents=split_docs, 70 | embedding=embeddings, 71 | persist_directory=persist_directory # 允许我们将persist_directory目录保存到磁盘上 72 | ) 73 | vectordb.persist() 74 | 75 | def presit_knowledge_db(vectordb): 76 | """ 77 | 该函数用于持久化向量数据库。 78 | 79 | 参数: 80 | vectordb: 要持久化的向量数据库。 81 | """ 82 | vectordb.persist() 83 | 84 | def load_knowledge_db(path, embeddings): 85 | """ 86 | 该函数用于加载向量数据库。 87 | 88 | 参数: 89 | path: 要加载的向量数据库路径。 90 | embeddings: 向量数据库使用的 embedding 模型。 91 | 92 | 返回: 93 | vectordb: 加载的数据库。 94 | """ 95 | vectordb = Chroma.from_documents( 96 | embeddings=embeddings, 97 | persist_directory=path.name 98 | ) 99 | return vectordb 100 | 101 | if __name__ == "__main__": 102 | db_path = "../../knowledge_base" 103 | persist_directory = "../../vector_data_base" 104 | create_db(db_path, "zhipuai") -------------------------------------------------------------------------------- /project/embedding/__init__.py: -------------------------------------------------------------------------------- 1 | # from .zhipuai_embedding import ZhipuAIEmbeddings -------------------------------------------------------------------------------- /project/embedding/call_embedding.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.append(os.path.dirname(os.path.dirname(__file__))) 4 | 5 | from langchain.embeddings.openai import OpenAIEmbeddings 6 | from langchain.embeddings.huggingface import HuggingFaceEmbeddings 7 | from embedding.zhipuai_embedding import ZhipuAIEmbeddings 8 | 9 | def get_embedding(embedding : str): 10 | if embedding == "openai": 11 | embedding = OpenAIEmbeddings() 12 | elif embedding == "zhipuai": 13 | embedding = ZhipuAIEmbeddings() 14 | elif name == 'm3e': 15 | embedding = HuggingFaceEmbeddings(model_name="moka-ai/m3e-base") 16 | return embedding 17 | -------------------------------------------------------------------------------- /project/embedding/zhipuai_embedding.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import logging 4 | from typing import Any, Dict, List, Optional 5 | 6 | from langchain.embeddings.base import Embeddings 7 | from langchain.pydantic_v1 import BaseModel, root_validator 8 | from langchain.utils import get_from_dict_or_env 9 | 10 | logger = logging.getLogger(__name__) 11 | 12 | class ZhipuAIEmbeddings(BaseModel, Embeddings): 13 | """`Zhipuai Embeddings` embedding models.""" 14 | 15 | zhipuai_api_key: Optional[str] = None 16 | """Zhipuai application apikey""" 17 | 18 | @root_validator() 19 | def validate_environment(cls, values: Dict) -> Dict: 20 | """ 21 | Validate whether zhipuai_api_key in the environment variables or 22 | configuration file are available or not. 23 | 24 | Args: 25 | 26 | values: a dictionary containing configuration information, must include the 27 | fields of zhipuai_api_key 28 | Returns: 29 | 30 | a dictionary containing configuration information. If zhipuai_api_key 31 | are not provided in the environment variables or configuration 32 | file, the original values will be returned; otherwise, values containing 33 | zhipuai_api_key will be returned. 34 | Raises: 35 | 36 | ValueError: zhipuai package not found, please install it with `pip install 37 | zhipuai` 38 | """ 39 | values["zhipuai_api_key"] = get_from_dict_or_env( 40 | values, 41 | "zhipuai_api_key", 42 | "ZHIPUAI_API_KEY", 43 | ) 44 | 45 | try: 46 | import zhipuai 47 | zhipuai.api_key = values["zhipuai_api_key"] 48 | values["client"] = zhipuai.model_api 49 | 50 | except ImportError: 51 | raise ValueError( 52 | "Zhipuai package not found, please install it with " 53 | "`pip install zhipuai`" 54 | ) 55 | return values 56 | 57 | def _embed(self, texts: str) -> List[float]: 58 | # send request 59 | try: 60 | resp = self.client.invoke( 61 | model="text_embedding", 62 | prompt=texts 63 | ) 64 | except Exception as e: 65 | raise ValueError(f"Error raised by inference endpoint: {e}") 66 | 67 | if resp["code"] != 200: 68 | raise ValueError( 69 | "Error raised by inference API HTTP code: %s, %s" 70 | % (resp["code"], resp["msg"]) 71 | ) 72 | embeddings = resp["data"]["embedding"] 73 | return embeddings 74 | 75 | def embed_query(self, text: str) -> List[float]: 76 | """ 77 | Embedding a text. 78 | 79 | Args: 80 | 81 | Text (str): A text to be embedded. 82 | 83 | Return: 84 | 85 | List [float]: An embedding list of input text, which is a list of floating-point values. 86 | """ 87 | resp = self.embed_documents([text]) 88 | return resp[0] 89 | 90 | def embed_documents(self, texts: List[str]) -> List[List[float]]: 91 | """ 92 | Embeds a list of text documents. 93 | 94 | Args: 95 | texts (List[str]): A list of text documents to embed. 96 | 97 | Returns: 98 | List[List[float]]: A list of embeddings for each document in the input list. 99 | Each embedding is represented as a list of float values. 100 | """ 101 | return [self._embed(text) for text in texts] 102 | 103 | async def aembed_documents(self, texts: List[str]) -> List[List[float]]: 104 | """Asynchronous Embed search docs.""" 105 | raise NotImplementedError("Please use `embed_documents`. Official does not support asynchronous requests") 106 | 107 | async def aembed_query(self, text: str) -> List[float]: 108 | """Asynchronous Embed query text.""" 109 | raise NotImplementedError("Please use `aembed_query`. Official does not support asynchronous requests") 110 | -------------------------------------------------------------------------------- /project/llm/.env: -------------------------------------------------------------------------------- 1 | openai_api_key = "" 2 | wenxin_api_key = "" 3 | wenxin_secret_key = "" 4 | spark_appid = "" #填写控制台中获取的 APPID 信息 5 | spark_api_secret = "" #填写控制台中获取的 APISecret 信息 6 | spark_api_key ="" #填写控制台中获取的 APIKey 信息 7 | zhipu_api_key = "" 8 | -------------------------------------------------------------------------------- /project/llm/__pycache__/call_llm.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/project/llm/__pycache__/call_llm.cpython-310.pyc -------------------------------------------------------------------------------- /project/llm/__pycache__/self_llm.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/project/llm/__pycache__/self_llm.cpython-310.pyc -------------------------------------------------------------------------------- /project/llm/__pycache__/spark_llm.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/project/llm/__pycache__/spark_llm.cpython-310.pyc -------------------------------------------------------------------------------- /project/llm/__pycache__/wenxin_llm.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/project/llm/__pycache__/wenxin_llm.cpython-310.pyc -------------------------------------------------------------------------------- /project/llm/__pycache__/wenxin_llm_.cpython-310.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/logan-zou/Tutorial_for_developing_LLM_application/4a67a2c21a99fcee60c122fb4ef38c834476ee2f/project/llm/__pycache__/wenxin_llm_.cpython-310.pyc -------------------------------------------------------------------------------- /project/llm/self_llm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | ''' 4 | @File : self_llm.py 5 | @Time : 2023/10/16 18:48:08 6 | @Author : Logan Zou 7 | @Version : 1.0 8 | @Contact : loganzou0421@163.com 9 | @License : (C)Copyright 2017-2018, Liugroup-NLPR-CASIA 10 | @Desc : 在 LangChain LLM 基础上封装的项目类,统一了 GPT、文心、讯飞、智谱多种 API 调用 11 | ''' 12 | 13 | from langchain.llms.base import LLM 14 | from typing import Dict, Any, Mapping 15 | from pydantic import Field 16 | 17 | class Self_LLM(LLM): 18 | # 自定义 LLM 19 | # 继承自 langchain.llms.base.LLM 20 | # 原生接口地址 21 | url : str = None 22 | # 默认选用 GPT-3.5 模型,即目前一般所说的百度文心大模型 23 | model_name: str = "gpt-3.5-turbo" 24 | # 访问时延上限 25 | request_timeout: float = None 26 | # 温度系数 27 | temperature: float = 0.1 28 | # API_Key 29 | api_key: str = None 30 | # 必备的可选参数 31 | model_kwargs: Dict[str, Any] = Field(default_factory=dict) 32 | 33 | # 定义一个返回默认参数的方法 34 | @property 35 | def _default_params(self) -> Dict[str, Any]: 36 | """获取调用默认参数。""" 37 | normal_params = { 38 | "temperature": self.temperature, 39 | "request_timeout": self.request_timeout, 40 | } 41 | # print(type(self.model_kwargs)) 42 | return {**normal_params} 43 | 44 | @property 45 | def _identifying_params(self) -> Mapping[str, Any]: 46 | """Get the identifying parameters.""" 47 | return {**{"model_name": self.model_name}, **self._default_params} -------------------------------------------------------------------------------- /project/llm/wenxin_llm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | ''' 4 | @File : wenxin_llm.py 5 | @Time : 2023/10/16 18:53:26 6 | @Author : Logan Zou 7 | @Version : 1.0 8 | @Contact : loganzou0421@163.com 9 | @License : (C)Copyright 2017-2018, Liugroup-NLPR-CASIA 10 | @Desc : 基于百度文心大模型自定义 LLM 类 11 | ''' 12 | 13 | from langchain.llms.base import LLM 14 | from typing import Any, List, Mapping, Optional, Dict, Union, Tuple 15 | from pydantic import Field 16 | from self_llm import Self_LLM 17 | import json 18 | import requests 19 | from langchain.callbacks.manager import CallbackManagerForLLMRun 20 | 21 | # 调用文心 API 的工具函数 22 | def get_access_token(api_key : str, secret_key : str): 23 | """ 24 | 使用 API Key,Secret Key 获取access_token,替换下列示例中的应用API Key、应用Secret Key 25 | """ 26 | # 指定网址 27 | url = f"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={api_key}&client_secret={secret_key}" 28 | # 设置 POST 访问 29 | payload = json.dumps("") 30 | headers = { 31 | 'Content-Type': 'application/json', 32 | 'Accept': 'application/json' 33 | } 34 | # 通过 POST 访问获取账户对应的 access_token 35 | response = requests.request("POST", url, headers=headers, data=payload) 36 | return response.json().get("access_token") 37 | 38 | class Wenxin_LLM(Self_LLM): 39 | # 文心大模型的自定义 LLM 40 | # URL 41 | url : str = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token={}" 42 | # Secret_Key 43 | secret_key : str = None 44 | # access_token 45 | access_token: str = None 46 | 47 | def init_access_token(self): 48 | if self.api_key != None and self.secret_key != None: 49 | # 两个 Key 均非空才可以获取 access_token 50 | try: 51 | self.access_token = get_access_token(self.api_key, self.secret_key) 52 | except Exception as e: 53 | print(e) 54 | print("获取 access_token 失败,请检查 Key") 55 | else: 56 | print("API_Key 或 Secret_Key 为空,请检查 Key") 57 | 58 | def _call(self, prompt : str, stop: Optional[List[str]] = None, 59 | run_manager: Optional[CallbackManagerForLLMRun] = None, 60 | **kwargs: Any): 61 | # 如果 access_token 为空,初始化 access_token 62 | if self.access_token == None: 63 | self.init_access_token() 64 | # API 调用 url 65 | url = self.url.format(self.access_token) 66 | # 配置 POST 参数 67 | payload = json.dumps({ 68 | "messages": [ 69 | { 70 | "role": "user",# user prompt 71 | "content": "{}".format(prompt)# 输入的 prompt 72 | } 73 | ], 74 | 'temperature' : self.temperature 75 | }) 76 | headers = { 77 | 'Content-Type': 'application/json' 78 | } 79 | # 发起请求 80 | response = requests.request("POST", url, headers=headers, data=payload, timeout=self.request_timeout) 81 | if response.status_code == 200: 82 | # 返回的是一个 Json 字符串 83 | js = json.loads(response.text) 84 | return js["result"] 85 | else: 86 | return "请求失败" 87 | 88 | @property 89 | def _llm_type(self) -> str: 90 | return "Wenxin" 91 | -------------------------------------------------------------------------------- /project/qa_chain/Chat_QA_chain_self.py: -------------------------------------------------------------------------------- 1 | from langchain.prompts import PromptTemplate 2 | from langchain.chains import RetrievalQA 3 | from langchain.vectorstores import Chroma 4 | from langchain.chains import ConversationalRetrievalChain 5 | from langchain.memory import ConversationBufferMemory 6 | from langchain.chat_models import ChatOpenAI 7 | 8 | import model_to_llm 9 | import get_vectordb 10 | 11 | 12 | class Chat_QA_chain_self: 13 | """" 14 | 带历史记录的问答链 15 | - model:调用的模型名称 16 | - temperature:温度系数,控制生成的随机性 17 | - top_k:返回检索的前k个相似文档 18 | - chat_history:历史记录,输入一个列表,默认是一个空列表 19 | - history_len:控制保留的最近 history_len 次对话 20 | - file_path:建库文件所在路径 21 | - persist_path:向量数据库持久化路径 22 | - appid:星火 23 | - api_key:所有模型都需要 24 | - api_secret:星火、百度文心 25 | - embeddings:使用的embedding模型 26 | """ 27 | def __init__(self,model:str, temperature:float=0.0, top_k:int=4, chat_history:list=[], history_len:int=0, file_path:str=None, persist_path:str=None, appid:str=None, api_key:str=None, api_secret:str=None, embedding = "openai"): 28 | self.model = model 29 | self.temperature = temperature 30 | self.top_k = top_k 31 | self.chat_history = chat_history 32 | self.history_len = history_len 33 | self.file_path = file_path 34 | self.persist_path = persist_path 35 | self.appid = appid 36 | self.api_key = api_key 37 | self.api_secret = api_secret 38 | self.embedding = embedding 39 | 40 | self.vectordb = get_vectordb(self.file_path, self.persist_path, self.api_key, self.embedding) 41 | self.llm = model_to_llm(self.model, self.temperature, self.appid, self.api_key, self.api_secret) 42 | 43 | self.memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) 44 | 45 | self.retriever = self.vectordb.as_retriever(search_type="similarity", 46 | search_kwargs={'k': self.top_k}) #默认similarity,k=4 47 | 48 | self.qa = ConversationalRetrievalChain.from_llm( 49 | llm = self.llm, 50 | retriever = self.retriever, 51 | memory = self.memory 52 | ) 53 | 54 | def clear_history(self): 55 | "清空历史记录" 56 | return self.chat_history.clear() 57 | 58 | 59 | def change_history_length(self): 60 | """ 61 | 保存指定对话轮次的历史记录 62 | 输入参数: 63 | - history_len :控制保留的最近 history_len 次对话 64 | - chat_history:当前的历史对话记录 65 | 输出:返回最近 history_len 次对话 66 | """ 67 | n = len(self.chat_history) 68 | return self.chat_history[n-self.history_len:n] 69 | 70 | 71 | def answer(self, question:str=None): 72 | """" 73 | 核心方法,调用问答链 74 | arguments: 75 | - question:用户提问 76 | """ 77 | if len(question) == 0: 78 | return "", self.chat_history 79 | 80 | result = self.qa({"question": question}) 81 | self.chat_history.append((question,result['answer'])) #更新历史记录 82 | 83 | return result['answer'],self.chat_history #返回本次回答和更新后的历史记录 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /project/qa_chain/QA_chain_self.py: -------------------------------------------------------------------------------- 1 | from langchain.prompts import PromptTemplate 2 | from langchain.chains import RetrievalQA 3 | from langchain.vectorstores import Chroma 4 | 5 | import model_to_llm 6 | import get_vectordb 7 | 8 | 9 | class QA_chain_self(): 10 | """" 11 | 不带历史记录的问答链 12 | - model:调用的模型名称 13 | - temperature:温度系数,控制生成的随机性 14 | - top_k:返回检索的前k个相似文档 15 | - file_path:建库文件所在路径 16 | - persist_path:向量数据库持久化路径 17 | - appid:星火需要输入 18 | - api_key:所有模型都需要 19 | - api_secret:星火、百度文心需要输入 20 | - embeddings:使用的embedding模型 21 | - template:可以自定义提示模板,没有输入则使用默认的提示模板default_template_rq 22 | """ 23 | 24 | #基于召回结果和 query 结合起来构建的 prompt使用的默认提示模版 25 | default_template_rq = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答 26 | 案。最多使用三句话。尽量使答案简明扼要。总是在回答的最后说“谢谢你的提问!”。 27 | {context} 28 | 问题: {question} 29 | 有用的回答:""" 30 | 31 | def __init__(self, model:str, temperature:float=0.0, top_k:int=4, file_path:str=None, persist_path:str=None, appid:str=None, api_key:str=None, api_secret:str=None, embedding = "openai", template=default_template_rq): 32 | self.model = model 33 | self.temperature = temperature 34 | self.top_k = top_k 35 | self.file_path = file_path 36 | self.persist_path = persist_path 37 | self.appid = appid 38 | self.api_key = api_key 39 | self.api_secret = api_secret 40 | self.embedding = embedding 41 | self.template = template 42 | 43 | 44 | self.vectordb = get_vectordb(self.file_path, self.persist_path, self.api_key, self.embedding) 45 | self.llm = model_to_llm(self.model, self.temperature, self.appid, self.api_key, self.api_secret) 46 | 47 | self.QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"], 48 | template=self.template) 49 | # 自定义 QA 链 50 | self.qa_chain = RetrievalQA.from_chain_type(llm=self.llm, 51 | retriever=self.vectordb.as_retriever(), 52 | return_source_documents=True, 53 | chain_type_kwargs={"prompt":self.QA_CHAIN_PROMPT}) 54 | 55 | #基于大模型的问答 prompt 使用的默认提示模版 56 | #default_template_llm = """请回答下列问题:{question}""" 57 | 58 | def answer(self, question:str=None, ): 59 | """" 60 | 核心方法,调用问答链 61 | arguments: 62 | - question:用户提问 63 | """ 64 | 65 | if len(question) == 0: 66 | return "" 67 | 68 | result = self.qa_chain({"query": question, "temperature": self.temperature, "top_k":self.top_k}) 69 | return result["result"] 70 | -------------------------------------------------------------------------------- /project/qa_chain/get_vectordb.py: -------------------------------------------------------------------------------- 1 | from langchain.embeddings.openai import OpenAIEmbeddings # 调用 OpenAI 的 Embeddings 模型 2 | import os 3 | from zhipuai_embedding import ZhipuAIEmbeddings 4 | 5 | from create_db import create_db,load_knowledge_db 6 | 7 | 8 | def get_vectordb(self, file_path:str=None, persist_path:str=None, api_key: str = None, embedding = "openai"): 9 | """ 10 | 返回向量数据库对象 11 | 输入参数: 12 | question: 13 | llm: 14 | vectordb:向量数据库(必要参数),一个对象 15 | template:提示模版(可选参数)可以自己设计一个提示模版,也有默认使用的 16 | embedding:可以使用zhipuai等embeddin,不输入该参数则默认使用 openai embedding,注意此时api_key不要输错 17 | """ 18 | if embedding == "openai": 19 | embedding = OpenAIEmbeddings() 20 | elif embedding == "zhipu": 21 | embedding = ZhipuAIEmbeddings() 22 | 23 | 24 | if os.path.exists(persist_path): #持久化目录存在 25 | contents = os.listdir(persist_path) 26 | if len(contents) == 0: #但是下面为空 27 | #print("目录为空") 28 | vectordb = create_db(file_path, embedding) 29 | #presit_knowledge_db(vectordb) 30 | vectordb = load_knowledge_db(persist_path, embedding) 31 | else: 32 | #print("目录不为空") 33 | vectordb = load_knowledge_db(persist_path, embedding) 34 | else: #目录不存在,从头开始创建向量数据库 35 | vectordb = create_db(file_path, embedding) 36 | #presit_knowledge_db(vectordb) 37 | vectordb = load_knowledge_db(persist_path, embedding) 38 | 39 | return vectordb -------------------------------------------------------------------------------- /project/qa_chain/model_to_llm.py: -------------------------------------------------------------------------------- 1 | from wenxin_llm import Wenxin_LLM 2 | from spark_llm import Spark_LLM 3 | from zhipuai_llm.py import ZhipuAILLM 4 | from langchain.chat_models import ChatOpenAI 5 | 6 | 7 | def model_to_llm(model:str=None, temperature:float=0.0, appid:str=None, api_key:str=None, api_secret:str=None): 8 | """ 9 | 星火:model,temperature,appid,api_key,api_secret 10 | 百度问心:model,temperature,api_key,api_secret 11 | 智谱:model,temperature,api_key 12 | OpenAI:model,temperature,api_key 13 | """ 14 | if model in ["gpt-3.5-turbo", "gpt-3.5-turbo-16k-0613", "gpt-3.5-turbo-0613", "gpt-4", "gpt-4-32k"]: 15 | llm = ChatOpenAI(model_name = model, temperature = temperature , openai_api_key = api_key) 16 | elif model in ["ERNIE-Bot", "ERNIE-Bot-4", "ERNIE-Bot-turbo"]: 17 | llm = Wenxin_LLM(model=model, temperature = temperature, api_key=api_key, secret_key=api_secret) 18 | elif model in ["Spark-1.5", "Spark-2.0"]: 19 | llm = Spark_LLM(model=model, temperature = temperature, appid=appid, api_secret=api_secret, api_key=api_key) 20 | elif model in ["chatglm_pro", "chatglm_std", "chatglm_lite"]: 21 | llm = ZhipuAILLM(model=model, api_key=api_key, temperature = temperature) 22 | else: 23 | return "不正确的模型" 24 | return llm -------------------------------------------------------------------------------- /project/readme.md: -------------------------------------------------------------------------------- 1 | 用于存放完整的项目代码 -------------------------------------------------------------------------------- /project/serve/api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- encoding: utf-8 -*- 3 | ''' 4 | @File : spark_api.py 5 | @Time : 2023/09/24 11:00:46 6 | @Author : Logan Zou 7 | @Version : 1.0 8 | @Contact : loganzou0421@163.com 9 | @License : (C)Copyright 2017-2018, Liugroup-NLPR-CASIA 10 | @Desc : 启动服务为本地 API 11 | ''' 12 | 13 | from fastapi import FastAPI 14 | from pydantic import BaseModel 15 | import os 16 | import sys 17 | # 导入功能模块目录 18 | sys.path.append("../") 19 | from qa_chain.QA_chain_self import QA_chain_self 20 | 21 | app = FastAPI() # 创建 api 对象 22 | 23 | template = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答 24 | 案。最多使用三句话。尽量使答案简明扼要。总是在回答的最后说“谢谢你的提问!”。 25 | {context} 26 | 问题: {question} 27 | 有用的回答:""" 28 | 29 | # 定义一个数据模型,用于接收POST请求中的数据 30 | class Item(BaseModel): 31 | prompt : str # 用户 prompt 32 | model : str # 使用的模型 33 | temperature : float = 0.1# 温度系数 34 | if_history : bool = False # 是否使用历史对话功能 35 | # API_Key 36 | api_key: str = None 37 | # Secret_Key 38 | secret_key : str = None 39 | # access_token 40 | access_token: str = None 41 | # APPID 42 | appid : str = None 43 | # APISecret 44 | api_secret : str = None 45 | # 数据库路径 46 | db_path : str = "../database" 47 | # prompt template 48 | prompt_template : str = template 49 | # Template 变量 50 | input_variables : list = ["context","question"] 51 | # Embdding 52 | embedding : str = "openai" 53 | # Top K 54 | top_k : int = 5 55 | 56 | @app.post("/answer/") 57 | async def get_response(item: Item): 58 | 59 | # 首先确定需要调用的链 60 | if not item.if_history: 61 | # 调用 Chat 链 62 | chain = QA_chain_self(item.db_path, item.model, item.prompt_template, 63 | item.input_variables, item.temperature, item.api_key, 64 | item.secret_key, item.access_token, item.appid, item.api_secret, item.embedding) 65 | 66 | response = chain.answer(question = item.prompt, top_k = item.top_k, temperature = item.temperature) 67 | 68 | return response 69 | 70 | # 由于 API 存在即时性问题,不能支持历史链 71 | else: 72 | return "API 不支持历史链" -------------------------------------------------------------------------------- /project/serve/run_api.sh: -------------------------------------------------------------------------------- 1 | ! uvicorn api:app --------------------------------------------------------------------------------