问题引入 
现有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来进行解决数学题,学会调用工具