安装依赖
pip install --upgrade --quiet langchain-core langchain-community langchain-openai
编辑代码
from operator import itemgetter from langchain_core.messages import AIMessage, HumanMessage, get_buffer_string from langchain_core.prompts import format_document from langchain_core.runnables import RunnableParallel, RunnablePassthrough, RunnableLambda from langchain_openai.chat_models import ChatOpenAI from langchain_openai import OpenAIEmbeddings from langchain.prompts.prompt import PromptTemplate from langchain.prompts.chat import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langchain_community.vectorstores import DocArrayInMemorySearch from langchain.memory import ConversationBufferMemory vectorstore = DocArrayInMemorySearch.from_texts( ["wuzikang worked at earth", "sam worked at home", "harrison worked at kensho"], embedding=OpenAIEmbeddings() ) retriever = vectorstore.as_retriever() _template = """Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question, in its original language. Chat History: {chat_history} Follow Up Input: {question} Standalone question:""" CONDENSE_QUESTION_PROMPT = PromptTemplate.from_template(_template) template = """Answer the question based only on the following context: {context} Question: {question} """ ANSWER_PROMPT = ChatPromptTemplate.from_template(template) DEFAULT_DOCUMENT_PROMPT = PromptTemplate.from_template(template="{page_content}") def _combine_documents( docs, document_prompt=DEFAULT_DOCUMENT_PROMPT, document_separator="\n\n" ): doc_strings = [format_document(doc, document_prompt) for doc in docs] return document_separator.join(doc_strings) _inputs = RunnableParallel( standalone_question=RunnablePassthrough.assign( chat_history=lambda x: get_buffer_string(x["chat_history"]) ) | CONDENSE_QUESTION_PROMPT | ChatOpenAI(temperature=0) | StrOutputParser(), ) memory = ConversationBufferMemory( return_messages=True, output_key="answer", input_key="question" ) # First we add a step to load memory # This adds a "memory" key to the input object loaded_memory = RunnablePassthrough.assign( chat_history=RunnableLambda(memory.load_memory_variables) | itemgetter("history"), ) # Now we calculate the standalone question standalone_question = { "standalone_question": { "question": lambda x: x["question"], "chat_history": lambda x: get_buffer_string(x["chat_history"]), } | CONDENSE_QUESTION_PROMPT | ChatOpenAI(temperature=0) | StrOutputParser(), } # Now we retrieve the documents retrieved_documents = { "docs": itemgetter("standalone_question") | retriever, "question": lambda x: x["standalone_question"], } # Now we construct the inputs for the final prompt final_inputs = { "context": lambda x: _combine_documents(x["docs"]), "question": itemgetter("question"), } # And finally, we do the part that returns the answers answer = { "answer": final_inputs | ANSWER_PROMPT | ChatOpenAI(), "docs": itemgetter("docs"), } # And now we put it all together! final_chain = loaded_memory | standalone_question | retrieved_documents | answer inputs = {"question": "where did sam work?"} result = final_chain.invoke(inputs) print(f"result1: {result}") # memory memory.save_context(inputs, {"answer": result["answer"].content}) memory.load_memory_variables({}) inputs = {"question": "but where did he really work?"} result2 = final_chain.invoke(inputs) print(f"result2: {result2}")
运行代码
➜ python3 test06.py /Users/wuzikang/Desktop/py/langchain_test/own_learn/env/lib/python3.12/site-packages/pydantic/_migration.py:283: UserWarning: `pydantic.error_wrappers:ValidationError` has been moved to `pydantic:ValidationError`. warnings.warn(f'`{import_path}` has been moved to `{new_location}`.') result1: {'answer': AIMessage(content='Sam worked at home.', response_metadata={'finish_reason': 'stop', 'logprobs': None}), 'docs': [Document(page_content='sam worked at home'), Document(page_content='wuzikang worked at earth'), Document(page_content='harrison worked at kensho')]} result2: {'answer': AIMessage(content='Sam actually worked at home.', response_metadata={'finish_reason': 'stop', 'logprobs': None}), 'docs': [Document(page_content='sam worked at home'), Document(page_content='wuzikang worked at earth'), Document(page_content='harrison worked at kensho')]}