was employed at Kensho.', additional_kwargs={}, example=False)conversational_qa_chain.invoke({    "question": "where did he work?",    "chat_history": [("Who wrote this notebook?", "Harrison")],})    AIMessage(content='Harrison worked at Kensho.', additional_kwargs={}, example=False)With Memory and returning source documents‚ÄãThis shows how to use memory with the above. For memory, we need to manage that outside at the memory. For returning the retrieved documents, we just need to pass them through all the way.from operator import itemgetterfrom langchain.memory import ConversationBufferMemorymemory = 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 objectloaded_memory = RunnablePassthrough.assign(    chat_history=RunnableLambda(memory.load_memory_variables) | itemgetter("history"),)# Now we calculate the standalone questionstandalone_question = {    "standalone_question": {        "question": lambda x: x["question"],        "chat_history": lambda x: _format_chat_history(x['chat_history'])    } | CONDENSE_QUESTION_PROMPT | ChatOpenAI(temperature=0) | StrOutputParser(),}# Now we retrieve the documentsretrieved_documents = {    "docs": itemgetter("standalone_question") | retriever,    "question": lambda x: x["standalone_question"]}# Now we construct the inputs for the final promptfinal_inputs = {    "context": lambda x: _combine_documents(x["docs"]),    "question": itemgetter("question")}# And finally, we do the part that returns the answersanswer = {    "answer": final_inputs | ANSWER_PROMPT | ChatOpenAI(),    "docs": itemgetter("docs"),}# And now we put it all together!final_chain = loaded_memory | standalone_question | retrieved_documents | answerinputs = {"question": "where did harrison work?"}result = final_chain.invoke(inputs)result    {'answer': AIMessage(content='Harrison was employed at Kensho.', additional_kwargs={}, example=False),
Let's look at adding in a retrieval step to a prompt and LLM, which adds up to a "retrieval-augmented generation" chain
Let's look at adding in a retrieval step to a prompt and LLM, which adds up to a "retrieval-augmented generation" chain ->: was employed at Kensho.', additional_kwargs={}, example=False)conversational_qa_chain.invoke({    "question": "where did he work?",    "chat_history": [("Who wrote this notebook?", "Harrison")],})    AIMessage(content='Harrison worked at Kensho.', additional_kwargs={}, example=False)With Memory and returning source documents‚ÄãThis shows how to use memory with the above. For memory, we need to manage that outside at the memory. For returning the retrieved documents, we just need to pass them through all the way.from operator import itemgetterfrom langchain.memory import ConversationBufferMemorymemory = 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 objectloaded_memory = RunnablePassthrough.assign(    chat_history=RunnableLambda(memory.load_memory_variables) | itemgetter("history"),)# Now we calculate the standalone questionstandalone_question = {    "standalone_question": {        "question": lambda x: x["question"],        "chat_history": lambda x: _format_chat_history(x['chat_history'])    } | CONDENSE_QUESTION_PROMPT | ChatOpenAI(temperature=0) | StrOutputParser(),}# Now we retrieve the documentsretrieved_documents = {    "docs": itemgetter("standalone_question") | retriever,    "question": lambda x: x["standalone_question"]}# Now we construct the inputs for the final promptfinal_inputs = {    "context": lambda x: _combine_documents(x["docs"]),    "question": itemgetter("question")}# And finally, we do the part that returns the answersanswer = {    "answer": final_inputs | ANSWER_PROMPT | ChatOpenAI(),    "docs": itemgetter("docs"),}# And now we put it all together!final_chain = loaded_memory | standalone_question | retrieved_documents | answerinputs = {"question": "where did harrison work?"}result = final_chain.invoke(inputs)result    {'answer': AIMessage(content='Harrison was employed at Kensho.', additional_kwargs={}, example=False),