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 ConversationBufferMemoryvectorstore = 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 | answerinputs ={"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')]}
创建动态库:
编写源文件:
// sub.h 显式调用
#include <iostream>extern "C" int sub(int a, int b);// sub.cpp
#include "sub.h"int sub(int a, int b)
{return a - b;
}// quadrature.h 隐式调用
#include <iostream&…