12
LangChain:大语言模型应用框架
大模型开发/技术交流
- 文心大模型
- 开源大模型
2023.10.1710821看过
文心+LangChain的应用与实现
项目结构:
安装langchain
使用1: 爬取网页并输出格式化数据
from langchain.prompts import PromptTemplatefrom langchain.chains import LLMRequestsChain, LLMChainfrom LLM.ChatGLM import ChatGLMfrom LLM.YiYan import YiYan# llm = ChatGLM()llm = YiYan()template = """在 >>> 和 <<< 之间是网页的返回的HTML内容。网页是电影简介。请抽取参数请求的信息。>>> {requests_result} <<<请使用如下的JSON格式返回数据{{"电影名":"a","导演":"b","主演":"c","上映日期":"d","国家/地区":"e","类型":"f","时长":"g","剧情简介":"h""豆瓣评分":"i"}}Extracted:"""prompt = PromptTemplate(input_variables=["requests_result"],template=template)chain = LLMRequestsChain(llm_chain=LLMChain(llm=llm, prompt=prompt))inputs = {"url": "https://movie.douban.com/subject/1889243/"}response = chain(inputs)print(response['output'])
使用2: 构建本地知识库问答机器人
下载模型:text2vec-base-chinese 至/shareData/目录
将知识库本地文件都放在/work/langchain/data/目录中
import osfrom langchain.llms import TextGenfrom langchain import PromptTemplatefrom langchain.embeddings import HuggingFaceEmbeddingsfrom langchain.vectorstores import Chromafrom langchain.text_splitter import CharacterTextSplitterfrom langchain.document_loaders import DirectoryLoaderfrom langchain.chains import RetrievalQAfrom LLM.ChatGLM import ChatGLMfrom LLM.YiYan import YiYan# 加载文件夹中的所有.md类型的文件loader = DirectoryLoader('/work/langchain/data/', glob='**/*.md')# 将数据转成 document 对象,每个文件会作为一个 documentdocuments = loader.load()# 初始化加载器text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)# 切割加载的 documentsplit_docs = text_splitter.split_documents(documents)# 初始化 embeddings 对象embeddings = HuggingFaceEmbeddings(model_name='/shareData/text2vec-base-chinese')# 将 document 计算 embedding 向量信息并临时存入 Chroma 向量数据库,用于后续匹配查询# 持久化数据docsearch = Chroma.from_documents(split_docs, embeddings, persist_directory="/work/langchain/Chromadb")docsearch.persist()# 加载数据docsearch = Chroma(persist_directory="/work/langchain/Chromadb", embedding_function=embeddings)# 创建问答对象# llm = ChatGLM()llm = YiYan()prompt_template = """基于以下已知信息,简洁和专业的来回答用户的问题。如果无法从中得到答案,请说 "根据已知信息无法回答该问题" 或 "没有提供足够的相关信息",不允许在答案中添加编造成分,答案请使用代码。已知内容:{context}问题:{question}"""prompt = PromptTemplate(template=prompt_template, input_variables=["context", "question"])chain_type_kwargs = {"prompt": prompt}qa = RetrievalQA.from_chain_type(llm=llm, retriever=docsearch.as_retriever(), chain_type="stuff",chain_type_kwargs=chain_type_kwargs, return_source_documents=True)# 进行问答query = "mongodb和redis的区别是什么"res = qa({"query": query})answer, docs = res['result'], res['source_documents']print("\n\n> 问题:")print(query)print("\n> 回答:")print(answer)for document in docs:print("\n> " + document.metadata["source"] + ":")
过程分析:1)将本地文件进行向量化存入Chromadb(常用的向量数据库有:Chroma、Pinecone、FAISS、Qdrant,参考:vector stores),2)进行问答请求,本地返回与问题相似度较高的大量文本,调用大模型进行知识抽取问答,返回结果。
其中第一步耗时较长,实际应用中可以定时任务执行知识的向量化存储,这样就不用每次问答都重新进行向量化了,节约耗时。
像这样,在不进行模型增强、模型微调的情况下,采用本地知识库向量缓存检索是一种很好的知识补充方式。
使用3: 对超长pdf文本进行总结
from langchain.document_loaders import UnstructuredFileLoaderfrom langchain.chains.summarize import load_summarize_chainfrom langchain.text_splitter import RecursiveCharacterTextSplitterfrom LLM.ChatGLM import ChatGLMfrom LLM.YiYan import YiYan# 导入文本loader = UnstructuredFileLoader("/work/langchain/data/LLM_Survey_Chinese_V1.pdf")# 将文本转成 Document 对象document = loader.load()# 初始化文本分割器text_splitter = RecursiveCharacterTextSplitter(chunk_size = 2000,chunk_overlap = 0)# 切分文本split_documents = text_splitter.split_documents(document)print(f'documents:{len(split_documents)}')# documents:100# 加载 llm 模型# llm = ChatGLM()llm = YiYan()# 创建总结链chain = load_summarize_chain(llm, chain_type="map_reduce", verbose=True)# 执行总结链 只取了前10段res = chain.run(split_documents[:10])print(res)
模型部分LLM
文心 YiYan
from typing import List, Optionalfrom langchain.llms.base import LLMfrom langchain.llms.utils import enforce_stop_tokensimport requestsimport jsonWENXIN_AK = ""WENXIN_SK = ""def get_access_token():"""使用 API Key,Secret Key 获取access_token"""url = f"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={WENXIN_AK}&client_secret={WENXIN_SK}"payload = json.dumps("")headers = {'Content-Type': 'application/json'}response = requests.request("POST", url, headers=headers, data=payload)return response.json().get("access_token")class YiYan(LLM):temperature = 0.1 # 较高的数值会使输出更加随机,而较低的数值会使其更加集中和确定。默认0.95,范围 (0, 1.0]top_p = 0.8 # 影响输出文本的多样性,取值越大,生成文本的多样性越强。默认0.8,取值范围 [0, 1.0]penalty_score = 1 # 通过对已生成的token增加惩罚,减少重复生成的现象。值越大表示惩罚越大。默认1.0,取值范围:[1.0, 2.0]def __init__(self):super().__init__()@propertydef _llm_type(self) -> str:return "YiYan"def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token=" + get_access_token()data = {"messages": [{"role": "user", "content": prompt}],"temperature": self.temperature,"top_p": self.top_p,"penalty_score": self.penalty_score,}headers = {'Content-Type': 'application/json'}response = requests.request("POST", url, headers=headers, data=json.dumps(data))if response.status_code == 200:return response.json()['result']return "查询结果错误"if __name__ == '__main__':url = "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token=" + get_access_token()D = {"messages": [{"role": "user", "content": "早睡早起有啥好处"}]}data = requests.post(url, json=D, headers={"Content-Type": "application/json"})print(data.text)
开源模型 以ChatGLM举例
其他开源模型都是类似的。
Llama2、vicuna、chatglm2、codegeex2都是支持的。
from typing import List, Optionalfrom langchain.llms.base import LLMfrom langchain.llms.utils import enforce_stop_tokensimport requestsimport jsonURL = 'http://0.0.0.0:5000/api/v1/generate'class ChatGLM(LLM):max_new_tokens = 1000temperature = 0.1top_p = 1penalty_alpha = 0def __init__(self):super().__init__()@propertydef _llm_type(self) -> str:return "ChatGLM"def _call(self, prompt: str, stop: Optional[List[str]] = None) -> str:# headers中添加上content-type这个参数,指定为json格式headers = {'Content-Type': 'application/json'}data = {'prompt': prompt,'max_new_tokens': self.max_new_tokens,'temperature': self.temperature,'top_p': self.top_p,'penalty_alpha': self.penalty_alpha,}# 调用apiresponse = requests.post(URL, headers=headers, json=data)if response.status_code == 200:return response.json()['results'][0]['text']return "查询结果错误"if __name__ == '__main__':import requestsD = {"prompt": '累了怎么办'}data = requests.post(URL, json=D, headers={"Content-Type": "application/json"})print(data.text)
本文作者周洁,已获作者授权发布,如需转载请联系
评论