问题引入
现有llm只能对话,无法进行操作,查询相关data
如果要换一个llm,那就需要重新更新llm的代码
不能实现根据不同任务选择不同的llm
无法有记忆,不能查到最新的消息
langchain介绍
解耦合了,变成prompt,model,chain,agent,vector等多个模块
LangChain 提供了对向量数据库的支持,能够把超长的 txt、pdf 等通过大模型转换为 embedding 的形式,存到向量数据库中,然后利用数据库进行检索。这样就可以支持更多长度的输入,解放了 LLM 的优势。
基本模块介绍 最简单的运行模板
1 2 3 4 5 6 7 8 9 10 11 DASHSCOPE_API_KEY="" from langchain_community.llms import Tongyifrom langchain.chains import LLMChainfrom langchain.prompts import PromptTemplatellm=Tongyi(temperature=1 ,dashscope_api_key=DASHSCOPE_API_KEY) prompt =PromptTemplate.from_template("给我一个很土但是听起来很好养活的{animal}名字" ) prompt.format (animal="狗" ) chain = LLMChain(llm=llm, prompt=prompt) chain.run("老鹰" )
定义llm
定义prompt
定义chain,传入llm还有提示
之后使用run来预测
model 这是标准的llm模块,方便介入各种大模型,zhipu,chatgpt,qwen等
1 2 3 4 5 DASHSCOPE_API_KEY="" from langchain_community.llms import Tongyifrom langchain.chains import LLMChainfrom langchain.prompts import PromptTemplatellm=Tongyi(temperature=1 ,dashscope_api_key=DASHSCOPE_API_KEY)
1 2 from langchain.llms import OpenAIllm = OpenAI(openai_api_key="..." )
直接通过llm模块皆可以快速引入各种模型,具体参考官网的llm
自定义model 只需要继承llm类,实现_call方法,同时设置一个属性是静态,返回模型的名称。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class weijia (LLM ): @property def _llm_type (self ) -> str : return "weijia-ai" def _call (self, prompt:str , stop:Optional [List [str ]]=None , run_manager:Optional [CallbackManagerForLLMRun] = None ) -> str : pd = prompt.find("吗" ) if pd >=0 : return prompt[:pd]+"." return "哦。"
prompt 这是提示模块,就是输入的指令,可以分为的下面多个提示词。
为什么需要提示词
指令,扮演猫娘
案例学习,现在我要你计算1+2=?,我们知道1+1=2,然后。。,最后。。给定一个事例,按照这个事例来进行输出
提问,询问这个文档的主题是什么
1 2 prompt =PromptTemplate.from_template("给我一个很土但是听起来很好养活的{animal}名字" ) prompt.format (animal="狗" )
以模板的样子来进行设置提示词,animal就是可以传入的参数,
案例学习
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from langchain.prompts.few_shot import FewShotPromptTemplatefrom langchain.prompts.prompt import PromptTemplateexamples = [ { "question" :"你好吗?" , "answer" :"帅哥,我很好" }, { "question" :"今天周几?" , "answer" :"帅哥,今天是周一" }, { "question" :"今天天气怎么样?" , "answer" :"帅哥,今天天气很好" } ] example_prompt = PromptTemplate(input_variables=["question" ,"answer" ],template="Question:{question}\n{answer}" ) prompt = FewShotPromptTemplate(example_prompt=example_prompt,examples=examples,suffix="Question: {input}" ,input_variables=["input" ]) print (prompt.format (input ="我怎么这么丑?" ))
使用的是少样本学习,给定example,之后使用fewshot来实现填充,最后一个是末尾加入一个suffix,相当于提问
定义example,使用{}来包括,放入到一个大列表
之后调用普通模板,只需要传入上面的格式
最后是fewshot,传入example,传入链,最后是加入后缀,就是自己要提问的
与fintune区别:finetue是需要微调llm,fewshot不需要,直接是提示工程
聊天提示模板
思路就是把上轮的对话内容也加入到提示里面来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from langchain.prompts import ( ChatPromptTemplate, PromptTemplate, SystemMessagePromptTemplate, AIMessagePromptTemplate, HumanMessagePromptTemplate, ) from langchain.schema import ( AIMessage, HumanMessage, SystemMessage ) template="You are a helpful assistant that translates {input_language} to {output_language}." system_message_prompt = SystemMessagePromptTemplate.from_template(template) human_template="{text}" human_message_prompt = HumanMessagePromptTemplate.from_template(human_template) chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt]) chat_prompt.format_prompt(input_language="English" , output_language="French" , text="I love programming." ).to_messages()
路由提示
如何让llm判断是什么类型,然后进行选择哪一个提示。一个是取名字,一个是做数学题,我想让他帮忙进行取名字
使用路由提示,和网关作用差不多,gateway选择微服务。
那就需要两个提示,一个提示是gateway提示,还有一个是所有提示的聚合
1 2 3 4 5 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 54 55 56 57 58 naming_template="""你是一个非常有创意的起名字专家. \ 你非常擅长给新生儿们起好听的,富含寓意的名字. \ 用中文给出回答 \ 这里是问题: \ {input}""" math_template ="""You are a very good mathematician.You are great at answering math questions. You are so good because you are able to break down hard problems into their component parts, \ answer the component parts,and then put them together to answer the broader question. Here is a question: {input}""" prompt_infos = [ { "name" : "naming" , "description" : "给新生儿起名字" , "template" : naming_template }, { "name" : "math" , "description" : "解数学问题" , "template" : math_template } ] from langchain.prompts import PromptTemplatefrom langchain.chains import LLMChain, ConversationChainDASHSCOPE_API_KEY= from langchain_community.llms import Tongyillm=Tongyi(temperature=1 ,dashscope_api_key=DASHSCOPE_API_KEY) destination_chains = {} for p_info in prompt_infos: name = p_info["name" ] prompt_template = p_info["template" ] prompt = PromptTemplate(template=prompt_template,input_variable=["input" ]) chain =LLMChain(prompt=prompt,llm=llm) destination_chains[name] = chain default_chain = ConversationChain(llm=llm,output_key="text" ) from langchain.chains.router.llm_router import LLMRouterChain,RouterOutputParserfrom langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATEdestinations =[f"{p['name' ]} :{p['description' ]} " for p in prompt_infos] destination_str = "," .join(destinations) router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format (destinations=destination_str) router_prompt = PromptTemplate(template=router_template,input_variable=["input" ],output_parser=RouterOutputParser()) router_chain = LLMRouterChain.from_llm(llm,router_prompt) from langchain.chains.router import MultiPromptChainchain = MultiPromptChain(router_chain=router_chain,destination_chains=destination_chains,default_chain=default_chain,verbose=True ) print (chain.run("计算100的1/2次方" ))
定义所有的prompt,有dest,根据dest【name】来获取
定义router路由,根据描述来进行选择name,之后使用dest的name来进行获取
然后放入到运行的链chain = MultiPromptChain ( router_chain = router_chain , destination_chains = destination_chains , default_chain = default_chain , verbose = True)
数据连接
大模型只有语言知识,但是如果是要外接入数据,那就是需要进行读取数据,例如pdf等数据,这就是需要是用data connection来进行解码数据
例如pdf还有csv等数据。
最终输出的是doc模块
如果pdf页数太大,超过llm的token,这个时候还需要进去切词。这个就是分割器。可以参考MapReduce的操作
整体流程
输入pdf
进行分割
之后使用doc来进行embedding
最后存放到向量数据库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from langchain.document_loaders import PyPDFLoaderloader = PyPDFLoader("./se230522013.pdf" ) from langchain.text_splitter import RecursiveCharacterTextSplittertext_splitter = RecursiveCharacterTextSplitter( chunk_size=100 , chunk_overlap=20 , length_function=len ) pages =loader.load_and_split(text_splitter) from langchain_community.embeddings import ModelScopeEmbeddingsmodel_id = "damo/nlp_corom_sentence-embedding_english-base" embeddings = ModelScopeEmbeddings(model_id=model_id) from langchain.vectorstores import Chromadb = Chroma.from_documents(pages, embeddings) query = "Artificial Intelligence" docs = db.similarity_search(query, k=5 )
memory agent 之前的使用llmmath来进行解决数学题,学会调用工具