原理篇
LLM模型,学术意义上这个大体现在供给给模型的训练样本很大,对我们使用者来说我们可以认为他海纳百川,有容乃大。学的足够多, 博学。所以你要跟它对话,需要先告诉它你充当的角色是谁,也就是你要获得知识的来源。
LangChain可以标准化和抽象化整个大语言模型使用过程。
- 文本加载
- 从各种数据源中加载文本语料。
- 你关心的数据,可以是自己现成的也可以是第三方供给的。
- 文本转换(切割)
嵌入容器入口有大小限制,切割后的文档有重合,便于关联文档上下文。 - 文本词嵌入(数字向量化)
文本词数字向量化,多维化。 - 词嵌入向量的存储和检索
存入向量数据库返回检索器
W模型,是一种用于写作文的方法,它指的是根据Who(谁),What(什么),When(何时),Where(何地),Why(为什么),How(如何)等问题,来组织文章的内容和结构;W模型可以帮助我们清晰地回答文章的基本问题,使文章更有逻辑和条理。
在这个例子中,我们可以根据以下方式来分析Prompt架构中的W模型:
- Who:谁是文章的作者,谁是文章的读者,谁是文章的主角。在这个例子中,文章的作者是我们,文章的读者是预训练语言模型(LLM),文章的主角是文本分类任务。
- What:文章的主题是什么,文章的目的是什么,文章的内容是什么。在这个例子中,文章的主题是情感分析,文章的目的是指导LLM完成文本分类任务,文章的内容是一个cloze prompt,包括输入部分和输出部分。
- When:文章发生在什么时间,文章的时效性如何,文章的时序关系如何。在这个例子中,文章发生在当前,文章的时效性较高,文章的时序关系是先输入后输出。
- Where:文章发生在什么地点,文章的空间关系如何,文章的范围如何。在这个例子中,文章发生在计算机中,文章的空间关系是输入部分和输出部分之间用分隔符隔开,文章的范围是一句话。
- Why:文章的动机是什么,文章的意义是什么,文章的论点是什么。在这个例子中,文章的动机是利用LLM的泛化能力和迁移能力,减少对有监督数据的依赖,文章的意义是实现小样本学习的目标,文章的论点是根据输入部分的情感倾向,输出正确的类别。
- How:文章的方法是什么,文章的结构是什么,文章的技巧是什么。在这个例子中,文章的方法是使用cloze prompt,文章的结构是输入部分和输出部分,文章的技巧是使用特殊符号或标记来分隔输入部分和输出部分,以及使用变量或元数据来表示参数。
开发篇
上传一个pdf文档,将文档转换为向量化语料喂给OpenAILLM模型,同时向它提问问题,回答内容和文档强相关。
- PostMan中API验证
- 实现结果
-
python-dotenv
初始化各种环境变量
pip install -U python-dotenv touch .env
配置项 配置值 OPENAI_API_KEY 'sk-xx' OPENAI_API_BASE "https://xxx" request_timeout "10000" https_proxy "http://127.0.0.1:58309" http_proxy "http://127.0.0.1:58309" upload_path_prefix xxxx/ save_vector_prefix xxxx/ -
fastapi
快速构建Backend API接口,类似Java Servlet、Spring MVCpip install -U fastapi
-
streamlit
快速构建 Frontend UI ,提供UI和后端进行交互。
pip install -U streamlit
-
chromadb
本地化向量数据库pip install chromadb
-
构建后端服务
uvicorn backend_api:app --reload
-
构建前端
streamlit run frontend_face.py
项目结构
具体实现
-
backend_api
from fastapi import FastAPI, UploadFile, File, Form from fastapi.responses import JSONResponse from langchain_utils import * app = FastAPI() @app.post("/upload_query") async def upload_query(file: UploadFile = File(...), query: str = Form(...)): try: upload_file(file) res = query_with_index(query,file.filename) return JSONResponse(content={"message": res}) except Exception as e: return JSONResponse(status_code=500, content={"message": f"Error occurred: {e}"})
-
frontend_face
import streamlit as st import requests form = st.form(key='my_form') uploaded_file = form.file_uploader('参考文件', type=['pdf']) text = form.text_input('检索关键词') submit_button = form.form_submit_button('上传并检索') if submit_button: # assuming the server is running on localhost and port 8000 url = "http://127.0.0.1:8000/upload_query" if uploaded_file is not None: # convert to bytes bytes_data = uploaded_file.getvalue() files = {'file': (uploaded_file.name, uploaded_file.getvalue())} else: file = None data = {'query': text} response = requests.post(url, files=files, data=data) if response.ok: # 获取后端返回的结果 result = response.json() # 显示结果 # 使用 st.markdown 来渲染结果,并添加一些样式 st.markdown(f""" <p style="text-indent:2em">{result['message']}</p> """, unsafe_allow_html=True) else: st.write('在提交过程中出现了错误')
-
langchain_utils
# # # 1.从Http Multi File文件流加载文件到服务器,这一步在API已完成 # # 2.从服务器路径加载文件到向量数据库 import os.path import shutil from dotenv import load_dotenv from langchain.indexes import VectorstoreIndexCreator from langchain.indexes.vectorstore import VectorStoreIndexWrapper from langchain_community.document_loaders import PyPDFLoader from langchain_community.embeddings import OpenAIEmbeddings from langchain_community.vectorstores.chroma import Chroma load_dotenv() local_persist_path = os.getenv("save_vector_prefix") upload_path_prefix = os.getenv("upload_path_prefix") # 从网络IO上传文件存到服务器端 def upload_file(file): save_path = get_file_path(upload_path_prefix,file.filename) if not (os.path.exists(save_path)): with open(f"{save_path}", "wb") as buffer: shutil.copyfileobj(file.file, buffer) # 构建地址和文件的相对路径 def get_file_path(path_prefix,indexName): return os.path.join(path_prefix,indexName) # 加载服务端上传好的文件到Chroma本地向量数据库 def load_file_2_VectorStore(file): loader = PyPDFLoader(file_path=get_file_path(upload_path_prefix,file)) save_path = get_file_path(local_persist_path,file) # 存在加载保存的数据进Chroma内存向量数据库 if (os.path.exists(save_path)): vectorstore = Chroma( embedding_function= OpenAIEmbeddings(), persist_directory = save_path ) return VectorStoreIndexWrapper(vectorstore=vectorstore) # 不存在生成并返回同时保存到本地 else: return (VectorstoreIndexCreator(vectorstore_kwargs={"persist_directory":save_path}).from_loaders(loaders=[loader])) # 用生成的向量数据库加载数据到OpenAI生成知识库,用知识库检索问题的答案 def query_with_index(query,filename): return load_file_2_VectorStore(filename).query_with_sources(query,chain_type="map_reduce")
文献
Agent ReAct
- Action agents
ReAct: Synergizing Reasoning and Acting in Language Models – Google Research Blog
- Plan And Execute Agent