Source code for langchain.chains.qa_with_sources.base
"""Question answering with sources over documents."""from__future__importannotationsimportinspectimportrefromabcimportABC,abstractmethodfromtypingimportAny,Dict,List,Optional,Tuplefromlangchain_core._apiimportdeprecatedfromlangchain_core.callbacksimport(AsyncCallbackManagerForChainRun,CallbackManagerForChainRun,)fromlangchain_core.documentsimportDocumentfromlangchain_core.language_modelsimportBaseLanguageModelfromlangchain_core.promptsimportBasePromptTemplatefrompydanticimportConfigDict,model_validatorfromlangchain.chainsimportReduceDocumentsChainfromlangchain.chains.baseimportChainfromlangchain.chains.combine_documents.baseimportBaseCombineDocumentsChainfromlangchain.chains.combine_documents.map_reduceimportMapReduceDocumentsChainfromlangchain.chains.combine_documents.stuffimportStuffDocumentsChainfromlangchain.chains.llmimportLLMChainfromlangchain.chains.qa_with_sources.loadingimportload_qa_with_sources_chainfromlangchain.chains.qa_with_sources.map_reduce_promptimport(COMBINE_PROMPT,EXAMPLE_PROMPT,QUESTION_PROMPT,)
[docs]@deprecated(since="0.2.13",removal="1.0",message=("This class is deprecated. Refer to this guide on retrieval and question ""answering with sources: ""https://python.langchain.com/docs/how_to/qa_sources/"),)classBaseQAWithSourcesChain(Chain,ABC):"""Question answering chain with sources over documents."""combine_documents_chain:BaseCombineDocumentsChain"""Chain to use to combine documents."""question_key:str="question"#: :meta private:input_docs_key:str="docs"#: :meta private:answer_key:str="answer"#: :meta private:sources_answer_key:str="sources"#: :meta private:return_source_documents:bool=False"""Return the source documents."""
[docs]@classmethoddeffrom_llm(cls,llm:BaseLanguageModel,document_prompt:BasePromptTemplate=EXAMPLE_PROMPT,question_prompt:BasePromptTemplate=QUESTION_PROMPT,combine_prompt:BasePromptTemplate=COMBINE_PROMPT,**kwargs:Any,)->BaseQAWithSourcesChain:"""Construct the chain from an LLM."""llm_question_chain=LLMChain(llm=llm,prompt=question_prompt)llm_combine_chain=LLMChain(llm=llm,prompt=combine_prompt)combine_results_chain=StuffDocumentsChain(llm_chain=llm_combine_chain,document_prompt=document_prompt,document_variable_name="summaries",)reduce_documents_chain=ReduceDocumentsChain(# type: ignore[misc]combine_documents_chain=combine_results_chain)combine_documents_chain=MapReduceDocumentsChain(llm_chain=llm_question_chain,reduce_documents_chain=reduce_documents_chain,document_variable_name="context",)returncls(combine_documents_chain=combine_documents_chain,**kwargs,)
[docs]@classmethoddeffrom_chain_type(cls,llm:BaseLanguageModel,chain_type:str="stuff",chain_type_kwargs:Optional[dict]=None,**kwargs:Any,)->BaseQAWithSourcesChain:"""Load chain from chain type."""_chain_kwargs=chain_type_kwargsor{}combine_documents_chain=load_qa_with_sources_chain(llm,chain_type=chain_type,**_chain_kwargs)returncls(combine_documents_chain=combine_documents_chain,**kwargs)
model_config=ConfigDict(arbitrary_types_allowed=True,extra="forbid",)@propertydefinput_keys(self)->List[str]:"""Expect input key. :meta private: """return[self.question_key]@propertydefoutput_keys(self)->List[str]:"""Return output key. :meta private: """_output_keys=[self.answer_key,self.sources_answer_key]ifself.return_source_documents:_output_keys=_output_keys+["source_documents"]return_output_keys@model_validator(mode="before")@classmethoddefvalidate_naming(cls,values:Dict)->Any:"""Fix backwards compatibility in naming."""if"combine_document_chain"invalues:values["combine_documents_chain"]=values.pop("combine_document_chain")returnvaluesdef_split_sources(self,answer:str)->Tuple[str,str]:"""Split sources from answer."""ifre.search(r"SOURCES?:",answer,re.IGNORECASE):answer,sources=re.split(r"SOURCES?:|QUESTION:\s",answer,flags=re.IGNORECASE)[:2]sources=re.split(r"\n",sources)[0].strip()else:sources=""returnanswer,sources@abstractmethoddef_get_docs(self,inputs:Dict[str,Any],*,run_manager:CallbackManagerForChainRun,)->List[Document]:"""Get docs to run questioning over."""def_call(self,inputs:Dict[str,Any],run_manager:Optional[CallbackManagerForChainRun]=None,)->Dict[str,str]:_run_manager=run_managerorCallbackManagerForChainRun.get_noop_manager()accepts_run_manager=("run_manager"ininspect.signature(self._get_docs).parameters)ifaccepts_run_manager:docs=self._get_docs(inputs,run_manager=_run_manager)else:docs=self._get_docs(inputs)# type: ignore[call-arg]answer=self.combine_documents_chain.run(input_documents=docs,callbacks=_run_manager.get_child(),**inputs)answer,sources=self._split_sources(answer)result:Dict[str,Any]={self.answer_key:answer,self.sources_answer_key:sources,}ifself.return_source_documents:result["source_documents"]=docsreturnresult@abstractmethodasyncdef_aget_docs(self,inputs:Dict[str,Any],*,run_manager:AsyncCallbackManagerForChainRun,)->List[Document]:"""Get docs to run questioning over."""asyncdef_acall(self,inputs:Dict[str,Any],run_manager:Optional[AsyncCallbackManagerForChainRun]=None,)->Dict[str,Any]:_run_manager=run_managerorAsyncCallbackManagerForChainRun.get_noop_manager()accepts_run_manager=("run_manager"ininspect.signature(self._aget_docs).parameters)ifaccepts_run_manager:docs=awaitself._aget_docs(inputs,run_manager=_run_manager)else:docs=awaitself._aget_docs(inputs)# type: ignore[call-arg]answer=awaitself.combine_documents_chain.arun(input_documents=docs,callbacks=_run_manager.get_child(),**inputs)answer,sources=self._split_sources(answer)result:Dict[str,Any]={self.answer_key:answer,self.sources_answer_key:sources,}ifself.return_source_documents:result["source_documents"]=docsreturnresult
[docs]@deprecated(since="0.2.13",removal="1.0",message=("This class is deprecated. Refer to this guide on retrieval and question ""answering with sources: ""https://python.langchain.com/docs/how_to/qa_sources/"),)classQAWithSourcesChain(BaseQAWithSourcesChain):"""Question answering with sources over documents."""input_docs_key:str="docs"#: :meta private:@propertydefinput_keys(self)->List[str]:"""Expect input key. :meta private: """return[self.input_docs_key,self.question_key]def_get_docs(self,inputs:Dict[str,Any],*,run_manager:CallbackManagerForChainRun,)->List[Document]:"""Get docs to run questioning over."""returninputs.pop(self.input_docs_key)asyncdef_aget_docs(self,inputs:Dict[str,Any],*,run_manager:AsyncCallbackManagerForChainRun,)->List[Document]:"""Get docs to run questioning over."""returninputs.pop(self.input_docs_key)@propertydef_chain_type(self)->str:return"qa_with_sources_chain"