Langchain核心模塊與實戰(二)
- Langchian向量數據庫檢索
- Langchian構建向量數據庫和檢索器
- 批量搜索返回與之相似度最高的第一個
- 檢索器和模型結合得到非籠統的答案
- LangChain構建代理
- 通過代理去調用
- Langchain構建RAG的對話應用
- 包含歷史記錄的對話生成
Langchian向量數據庫檢索
Langchian構建向量數據庫和檢索器
支持從向量數據庫和其他來源檢索數據,以便與LLM(大型語言模型)工作流程集成。它們對于應用程序來說非常重要,這些應用程序需要獲取數據以作為模型推理的一部分進行推理,就像檢索增強生成(RAG)的情況一樣需要安裝:pip install langchain-chroma
- 文檔
- 向量存儲
- 檢索器
import osfrom langchain_community.vectorstores import Chroma
from langchain_core.documents import Document
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.chat_message_histories import ChatMessageHistoryos.environ['LANGCHAIN_TRACING_V2'] = "true"
os.environ['LANGCHAIN_PROJECT'] ="LangchainDemo"
os.environ['LANGCHAIN_API_KEY'] = "xxx"# 準備測試數據,假設我們提供的文檔數據如下:
documents = [Document(page_content="狗是偉大的伴侶,以其忠誠和友好而聞名。",#源數據metadata={"source": "哺乳動物寵物文檔"},),Document(page_content="貓是獨立的寵物,通常喜歡自己的空間。",metadata={"source": "哺乳動物寵物文檔"},),Document(page_content="金魚是初學者的流行寵物,需要相對簡單的護理。",metadata={"source": "魚類寵物文檔"},),Document(page_content="鸚鵡是聰明的鳥類,能夠模仿人類的語言。",metadata={"source": "鳥類寵物文檔"},),Document(page_content="兔子是社交動物,需要足夠的空間跳躍。",metadata={"source": "哺乳動物寵物文檔"},),
]# 將文檔實例化成一個向量數據庫
vector_store = Chroma.from_documents(documents,embedding=OpenAIEmbeddings(openai_api_key="sk-xxx",openai_api_base='https://xiaoai.plus/v1',))#計算向量的相似度(query:需要查詢什么東西) 返回相似的分數,分數越低相似度越高
print(vector_store.similarity_search_with_score('咖啡貓'))
[(Document(metadata={'source': '哺乳動物寵物文檔'}, page_content='貓是獨立的寵物,通常喜歡自己的空間。'), 0.27787065505981445), (Document(metadata={'source': '哺乳動物寵物文檔'}, page_content='兔子是社交動物,需要足夠的空間跳躍。'), 0.4110114872455597), (Document(metadata={'source': '哺乳動物寵物文檔'}, page_content='狗是偉大的伴侶,以其忠誠和友好而聞名。'), 0.4139944612979889), (Document(metadata={'source': '魚類寵物文檔'}, page_content='金魚是初學者的流行寵物,需要相對簡單的護理。'), 0.43892139196395874)]
返回分數,分數越低距離值越低越相似
批量搜索返回與之相似度最高的第一個
import osfrom langchain_community.vectorstores import Chroma
from langchain_core.documents import Document
from langchain_core.runnables import RunnableLambda
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.chat_message_histories import ChatMessageHistoryos.environ['LANGCHAIN_TRACING_V2'] = "true"
os.environ['LANGCHAIN_PROJECT'] ="LangchainDemo"
os.environ['LANGCHAIN_API_KEY'] = "xx"# 準備測試數據,假設我們提供的文檔數據如下:
documents = [Document(page_content="狗是偉大的伴侶,以其忠誠和友好而聞名。",#源數據metadata={"source": "哺乳動物寵物文檔"},),Document(page_content="貓是獨立的寵物,通常喜歡自己的空間。",metadata={"source": "哺乳動物寵物文檔"},),Document(page_content="金魚是初學者的流行寵物,需要相對簡單的護理。",metadata={"source": "魚類寵物文檔"},),Document(page_content="鸚鵡是聰明的鳥類,能夠模仿人類的語言。",metadata={"source": "鳥類寵物文檔"},),Document(page_content="兔子是社交動物,需要足夠的空間跳躍。",metadata={"source": "哺乳動物寵物文檔"},),
]# 將文檔實例化成一個向量數據庫
vector_store = Chroma.from_documents(documents,embedding=OpenAIEmbeddings(openai_api_key="sk-xx",openai_api_base='https://xiaoai.plus/v1',))#計算向量的相似度(query:需要查詢什么東西) 返回相似的分數,分數越低相似度越高
# print(vector_store.similarity_search_with_score('咖啡貓'))# 檢索器(封裝到runnable對象中) bind(k=1)返回相似度最高的第一個
retriever = RunnableLambda(vector_store.similarity_search).bind(k=1)
print(retriever.batch(['咖啡貓', '鯊魚']))
檢索器和模型結合得到非籠統的答案
import osfrom langchain_community.vectorstores import Chroma
from langchain_core.documents import Document
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableLambda, RunnablePassthrough
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.chat_message_histories import ChatMessageHistoryos.environ['LANGCHAIN_TRACING_V2'] = "true"
os.environ['LANGCHAIN_PROJECT'] ="LangchainDemo"
os.environ['LANGCHAIN_API_KEY'] = "xx"# 1.創建模型
model = ChatOpenAI(model='gpt-4-turbo',api_key='sk-xx',base_url='https://xiaoai.plus/v1')# 準備測試數據,假設我們提供的文檔數據如下:
documents = [Document(page_content="狗是偉大的伴侶,以其忠誠和友好而聞名。",#源數據metadata={"source": "哺乳動物寵物文檔"},),Document(page_content="貓是獨立的寵物,通常喜歡自己的空間。",metadata={"source": "哺乳動物寵物文檔"},),Document(page_content="金魚是初學者的流行寵物,需要相對簡單的護理。",metadata={"source": "魚類寵物文檔"},),Document(page_content="鸚鵡是聰明的鳥類,能夠模仿人類的語言。",metadata={"source": "鳥類寵物文檔"},),Document(page_content="兔子是社交動物,需要足夠的空間跳躍。",metadata={"source": "哺乳動物寵物文檔"},),
]# 將文檔實例化成一個向量數據庫
vector_store = Chroma.from_documents(documents,embedding=OpenAIEmbeddings(openai_api_key="sk-xx",openai_api_base='https://xiaoai.plus/v1',))#計算向量的相似度(query:需要查詢什么東西) 返回相似的分數,分數越低相似度越高
# print(vector_store.similarity_search_with_score('咖啡貓'))# 檢索器(封裝到runnable對象中) bind(k=1)返回相似度最高的第一個
retriever = RunnableLambda(vector_store.similarity_search).bind(k=1)
# print(retriever.batch(['咖啡貓', '鯊魚']))# context 上下文放檢索器
message ="""
使用提供的上下文僅回答這個問題。
{question}
上下文:
{context}
"""
#元組,字符串,列表是sequence
prompt_temp = ChatPromptTemplate.from_messages([('human',message)])#RunnablePassthrough允許我們將用戶的問題之后再傳遞給prompt和model | 模板 | 模型
chain={'question':RunnablePassthrough(),'context':retriever} | prompt_temp | model
# 會結合上下文給出答案
resp = chain.invoke('請介紹一下貓')
print(resp)
輸出結果如下,此處的輸出就不再是一個籠統的結果了,而是結合上下文輸出的結果
content='貓是一種獨立的寵物,通常喜歡享有自己的空間。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 30, 'prompt_tokens': 88, 'total_tokens': 118, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'gpt-4-turbo', 'system_fingerprint': 'fp_5603ee5e2e', 'id': 'chatcmpl-NBI72cCvyl95lkf3JYErQmRa01R2X', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--86dc4e6a-33bc-414e-8c7f-6da9fb0af42f-0' usage_metadata={'input_tokens': 88, 'output_tokens': 30, 'total_tokens': 118, 'input_token_details': {}, 'output_token_details': {}}
LangChain構建代理
語言模型本身無法執行動作(如直接問大模型最近北京的天氣怎么樣),它們只能輸出文本。代理是使用大型語言模型(LLM)作為推理引擎來確定要執行的操作以及這些操作的輸入應該是什么。然后,這些操作的結果可以反饋到代理中,代理將決定是否需要更多的操作,或者是否可以結束。
pip install langgraph 用來創建代理的API
**
1、定義工具
2、創建代理**
沒有任何代理的情況下:
import osfrom langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.messages import HumanMessage
from langchain_openai import ChatOpenAI, OpenAIEmbeddingsos.environ['LANGCHAIN_TRACING_V2'] = "true"
os.environ['LANGCHAIN_PROJECT'] ="LangchainDemo"
os.environ['LANGCHAIN_API_KEY'] = "xxx"
os.environ["TAVILY_API_KEY"] = 'tvly-xx'
# 1.創建模型
model = ChatOpenAI(model='gpt-4-turbo',api_key='sk-xxx',base_url='https://xiaoai.plus/v1')# 沒有任何代理的情況下
# result = model.invoke([HumanMessage(content='北京天氣怎么樣?')])
# print(result)# LangChain內置了一個工具,可以輕松地使用Tavily搜索引擎作為工具。
search = TavilySearchResults(max_results=2) # max_results: 只返回兩個結果
# print(search.invoke('北京的天氣怎么樣?'))# 讓模型綁定工具
tools = [search]
model_with_tools = model.bind_tools(tools)# 模型可以自動推理:是否需要調用工具去完成用戶的答案
resp = model_with_tools.invoke([HumanMessage(content='中國的首都是哪個城市?')])print(f'Model_Result_Content: {resp.content}')
print(f'Tools_Result_Content: {resp.tool_calls}')resp2 = model_with_tools.invoke([HumanMessage(content='成都天氣怎么樣?')])print(f'Model_Result_Content: {resp2.content}')
print(f'Tools_Result_Content: {resp2.tool_calls}')
resp2得到一個搜索的指令,LLM會根據用戶問的問題判斷是否調工具,如果要調工具會得到一個調用工具的搜素指令
Model_Result_Content: 中國的首都是北京。
Tools_Result_Content: []
Model_Result_Content:
Tools_Result_Content: [{'name': 'tavily_search_results_json', 'args': {'query': '成都天氣狀況'}, 'id': 'chatcmpl-palFZnWMAbktsQdoCPTp42gIsaZIW', 'type': 'tool_call'}]
通過代理去調用
import osfrom langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.messages import HumanMessage
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langgraph.prebuilt import chat_agent_executoros.environ['LANGCHAIN_TRACING_V2'] = "true"
os.environ['LANGCHAIN_PROJECT'] ="LangchainDemo"
os.environ['LANGCHAIN_API_KEY'] = "xxx"
os.environ["TAVILY_API_KEY"] = 'tvly-xxx'
# 1.創建模型
model = ChatOpenAI(model='gpt-4-turbo',api_key='sk-xx',base_url='https://xiaoai.plus/v1')# 沒有任何代理的情況下
# result = model.invoke([HumanMessage(content='北京天氣怎么樣?')])
# print(result)# LangChain內置了一個工具,可以輕松地使用Tavily搜索引擎作為工具。
search = TavilySearchResults(max_results=2) # max_results: 只返回兩個結果
# print(search.invoke('北京的天氣怎么樣?'))# 讓模型綁定工具
tools = [search]
model_with_tools = model.bind_tools(tools)# 模型可以自動推理:是否需要調用工具去完成用戶的答案
# resp = model_with_tools.invoke([HumanMessage(content='中國的首都是哪個城市?')])
#
# print(f'Model_Result_Content: {resp.content}')
# print(f'Tools_Result_Content: {resp.tool_calls}')
#
# resp2 = model_with_tools.invoke([HumanMessage(content='成都天氣怎么樣?')])
#
# print(f'Model_Result_Content: {resp2.content}')
# print(f'Tools_Result_Content: {resp2.tool_calls}')# 創建代理,模型會自動調用工具
# 代理執行器
agent_executor = chat_agent_executor.create_tool_calling_executor(model,tools)resp = agent_executor.invoke({'messages': [HumanMessage(content='中國的首都是哪個城市?')]})
print(resp['messages'])resp2 = agent_executor.invoke({'messages': [HumanMessage(content='北京天氣怎么樣?')]})
print(resp2['messages'])print(resp2['messages'][2].content)
[HumanMessage(content='中國的首都是哪個城市?', additional_kwargs={}, response_metadata={}, id='efffa452-42cf-4197-a2b3-ef62b326e8ba'), AIMessage(content='中國的首都是北京。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 8, 'prompt_tokens': 92, 'total_tokens': 100, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'gpt-4-turbo', 'system_fingerprint': 'fp_5603ee5e2e', 'id': 'chatcmpl-wXponqYpA2fleDkK2GpdehWTQvxWM', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--7fcfa616-7b61-4ae3-a19c-bf000e262ab0-0', usage_metadata={'input_tokens': 92, 'output_tokens': 8, 'total_tokens': 100, 'input_token_details': {}, 'output_token_details': {}})]
[HumanMessage(content='北京天氣怎么樣?', additional_kwargs={}, response_metadata={}, id='9848deca-5ef9-4920-b02d-bfccc108992c'), AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'chatcmpl-W7E8k525XQPXUh90ZIjCeJTXzqTBQ', 'function': {'arguments': '{"query":"北京當前天氣"}', 'name': 'tavily_search_results_json'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 90, 'total_tokens': 112, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'gpt-4-turbo', 'system_fingerprint': 'fp_5603ee5e2e', 'id': 'chatcmpl-W7E8k525XQPXUh90ZIjCeJTXzqTBQ', 'service_tier': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run--06dc9a8b-5764-4fd9-bb43-c520204f2d9f-0', tool_calls=[{'name': 'tavily_search_results_json', 'args': {'query': '北京當前天氣'}, 'id': 'chatcmpl-W7E8k525XQPXUh90ZIjCeJTXzqTBQ', 'type': 'tool_call'}], usage_metadata={'input_tokens': 90, 'output_tokens': 22, 'total_tokens': 112, 'input_token_details': {}, 'output_token_details': {}}), ToolMessage(content='[{"title": "中國氣象局-天氣預報- 北京", "url": "https://weather.cma.cn/web/weather/54511", "content": "| 氣壓 | 1010.2hPa | 1009.9hPa | 1006.9hPa | 1004.4hPa | 1004.2hPa | 1004.9hPa | 1004hPa | 1004.2hPa |\\n| 濕度 | 71.7% | 66% | 62.4% | 60.2% | 59.4% | 65% | 84.4% | 96.6% |\\n| 云量 | 44.5% | 31.9% | 27.2% | 10.1% | 79.9% | 79.9% | 79.9% | 79.9% | [...] | 氣壓 | 1007.6hPa | 1007.7hPa | 1006.3hPa | 1005.7hPa | 1007.6hPa | 1009.3hPa | 1009.5hPa | 1009.3hPa |\\n| 濕度 | 68.9% | 59% | 55.5% | 58.8% | 49% | 76% | 82.3% | 91% |\\n| 云量 | 79.9% | 80% | 80% | 80% | 86.6% | 66.7% | 72.2% | 79.9% | [...] | 氣壓 | 1001.4hPa | 999.8hPa | 998.3hPa | 999.7hPa | 1001.2hPa | 1005.1hPa | 1009.1hPa | 1010.7hPa |\\n| 濕度 | 46.2% | 29.2% | 17% | 24.7% | 25.7% | 53.5% | 46.7% | 39.9% |\\n| 云量 | 41.2% | 10% | 10% | 10% | 4.6% | 4.6% | 4.5% | 4.4% |", "score": 0.7636429}, {"title": "北京-天氣預報 - 中央氣象臺", "url": "https://www.nmc.cn/publish/forecast/ABJ/beijing.html", "content": "土壤水分監測\\n 農業干旱綜合監測\\n 關鍵農時農事\\n 農業氣象周報\\n 農業氣象月報\\n 農業氣象專報\\n 生態氣象監測評估\\n 作物發育期監測\\n\\n 數值預報\\n\\n CMA全球天氣模式\\n CMA全球集合模式\\n CMA區域模式\\n CMA區域集合模式\\n CMA臺風模式\\n 海浪模式\\n\\n1. 當前位置:首頁\\n2. 北京市\\n3. 北京天氣預報\\n\\n省份:城市:\\n\\n09:50更新\\n\\n日出04:45\\n\\n 北京 \\n\\n30℃\\n\\n日落19:43\\n\\n 降水量 \\n\\n0mm\\n\\n西南風\\n\\n3級\\n\\n 相對濕度 \\n\\n43%\\n\\n 體感溫度 \\n\\n29.9℃\\n\\n空氣質量:良 \\n\\n舒適度:溫暖,較舒適\\n\\n 雷達圖 \\n\\nImage 4\\n\\n24小時預報7天預報10天預報11-30天預報\\n\\n 發布時間:06-12 08:00 \\n\\n 06/12 \\n\\n周四 \\n\\nImage 5\\n\\n 多云 \\n\\n 南風 \\n\\n 3~4級 \\n\\n 35℃ \\n\\n 23℃ \\n\\nImage 6", "score": 0.741169}]', name='tavily_search_results_json', id='2cc11dce-0bd7-4654-8def-fcf10e333a22', tool_call_id='chatcmpl-W7E8k525XQPXUh90ZIjCeJTXzqTBQ', artifact={'query': '北京當前天氣', 'follow_up_questions': None, 'answer': None, 'images': [], 'results': [{'url': 'https://weather.cma.cn/web/weather/54511', 'title': '中國氣象局-天氣預報- 北京', 'content': '| 氣壓 | 1010.2hPa | 1009.9hPa | 1006.9hPa | 1004.4hPa | 1004.2hPa | 1004.9hPa | 1004hPa | 1004.2hPa |\n| 濕度 | 71.7% | 66% | 62.4% | 60.2% | 59.4% | 65% | 84.4% | 96.6% |\n| 云量 | 44.5% | 31.9% | 27.2% | 10.1% | 79.9% | 79.9% | 79.9% | 79.9% | [...] | 氣壓 | 1007.6hPa | 1007.7hPa | 1006.3hPa | 1005.7hPa | 1007.6hPa | 1009.3hPa | 1009.5hPa | 1009.3hPa |\n| 濕度 | 68.9% | 59% | 55.5% | 58.8% | 49% | 76% | 82.3% | 91% |\n| 云量 | 79.9% | 80% | 80% | 80% | 86.6% | 66.7% | 72.2% | 79.9% | [...] | 氣壓 | 1001.4hPa | 999.8hPa | 998.3hPa | 999.7hPa | 1001.2hPa | 1005.1hPa | 1009.1hPa | 1010.7hPa |\n| 濕度 | 46.2% | 29.2% | 17% | 24.7% | 25.7% | 53.5% | 46.7% | 39.9% |\n| 云量 | 41.2% | 10% | 10% | 10% | 4.6% | 4.6% | 4.5% | 4.4% |', 'score': 0.7636429, 'raw_content': None}, {'url': 'https://www.nmc.cn/publish/forecast/ABJ/beijing.html', 'title': '北京-天氣預報 - 中央氣象臺', 'content': '土壤水分監測\n 農業干旱綜合監測\n 關鍵農時農事\n 農業氣象周報\n 農業氣象月報\n 農業氣象專報\n 生態氣象監測評估\n 作物發育期監測\n\n 數值預報\n\n CMA全球天氣模式\n CMA全球集合模式\n CMA區域模式\n CMA區域集合模式\n CMA臺風模式\n 海浪模式\n\n1. 當前位置:首頁\n2. 北京市\n3. 北京天氣預報\n\n省份:城市:\n\n09:50更新\n\n日出04:45\n\n 北京 \n\n30℃\n\n日落19:43\n\n 降水量 \n\n0mm\n\n西南風\n\n3級\n\n 相對濕度 \n\n43%\n\n 體感溫度 \n\n29.9℃\n\n空氣質量:良 \n\n舒適度:溫暖,較舒適\n\n 雷達圖 \n\nImage 4\n\n24小時預報7天預報10天預報11-30天預報\n\n 發布時間:06-12 08:00 \n\n 06/12 \n\n周四 \n\nImage 5\n\n 多云 \n\n 南風 \n\n 3~4級 \n\n 35℃ \n\n 23℃ \n\nImage 6', 'score': 0.741169, 'raw_content': None}], 'response_time': 0.85}), AIMessage(content='當前北京的天氣是晴朗,溫度大約為30℃,相對濕度約43%。西南風,3級風速。空氣質量為良,體感溫度約29.9℃,境況整體溫暖且較舒適。沒有降水。\n\n更多詳細天氣信息,您可以訪問[中國中央氣象臺提供的北京天氣預報](https://www.nmc.cn/publish/forecast/ABJ/beijing.html)。', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 141, 'prompt_tokens': 1172, 'total_tokens': 1313, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'gpt-4-turbo', 'system_fingerprint': 'fp_5603ee5e2e', 'id': 'chatcmpl-wikxZewxU0WqV8Bc66hx68DkE2xcM', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None}, id='run--a6c255f9-4b6b-48e5-b16d-e7a8e3864b6b-0', usage_metadata={'input_tokens': 1172, 'output_tokens': 141, 'total_tokens': 1313, 'input_token_details': {}, 'output_token_details': {}})]
[{"title": "中國氣象局-天氣預報- 北京", "url": "https://weather.cma.cn/web/weather/54511", "content": "| 氣壓 | 1010.2hPa | 1009.9hPa | 1006.9hPa | 1004.4hPa | 1004.2hPa | 1004.9hPa | 1004hPa | 1004.2hPa |\n| 濕度 | 71.7% | 66% | 62.4% | 60.2% | 59.4% | 65% | 84.4% | 96.6% |\n| 云量 | 44.5% | 31.9% | 27.2% | 10.1% | 79.9% | 79.9% | 79.9% | 79.9% | [...] | 氣壓 | 1007.6hPa | 1007.7hPa | 1006.3hPa | 1005.7hPa | 1007.6hPa | 1009.3hPa | 1009.5hPa | 1009.3hPa |\n| 濕度 | 68.9% | 59% | 55.5% | 58.8% | 49% | 76% | 82.3% | 91% |\n| 云量 | 79.9% | 80% | 80% | 80% | 86.6% | 66.7% | 72.2% | 79.9% | [...] | 氣壓 | 1001.4hPa | 999.8hPa | 998.3hPa | 999.7hPa | 1001.2hPa | 1005.1hPa | 1009.1hPa | 1010.7hPa |\n| 濕度 | 46.2% | 29.2% | 17% | 24.7% | 25.7% | 53.5% | 46.7% | 39.9% |\n| 云量 | 41.2% | 10% | 10% | 10% | 4.6% | 4.6% | 4.5% | 4.4% |", "score": 0.7636429}, {"title": "北京-天氣預報 - 中央氣象臺", "url": "https://www.nmc.cn/publish/forecast/ABJ/beijing.html", "content": "土壤水分監測\n 農業干旱綜合監測\n 關鍵農時農事\n 農業氣象周報\n 農業氣象月報\n 農業氣象專報\n 生態氣象監測評估\n 作物發育期監測\n\n 數值預報\n\n CMA全球天氣模式\n CMA全球集合模式\n CMA區域模式\n CMA區域集合模式\n CMA臺風模式\n 海浪模式\n\n1. 當前位置:首頁\n2. 北京市\n3. 北京天氣預報\n\n省份:城市:\n\n09:50更新\n\n日出04:45\n\n 北京 \n\n30℃\n\n日落19:43\n\n 降水量 \n\n0mm\n\n西南風\n\n3級\n\n 相對濕度 \n\n43%\n\n 體感溫度 \n\n29.9℃\n\n空氣質量:良 \n\n舒適度:溫暖,較舒適\n\n 雷達圖 \n\nImage 4\n\n24小時預報7天預報10天預報11-30天預報\n\n 發布時間:06-12 08:00 \n\n 06/12 \n\n周四 \n\nImage 5\n\n 多云 \n\n 南風 \n\n 3~4級 \n\n 35℃ \n\n 23℃ \n\nImage 6", "score": 0.741169}]Process finished with exit code 0
Langchain構建RAG的對話應用
本案例是:復雜的問答 (Q&A) 聊天機器人。應用程序可以回答有關特定源信息的問題。使用一種稱為檢索增強生成 (RAG) 的技術。
RAG是一種增強大型語言模型(LLM)知識的方法,它通過引入額外的數據來實現。
pip install langgraph 用來創建代理的API
實現思路:
加載:首先,我們需要加載數據。這是通過DocumentLoaders完成的。
分割: Text splitters將大型文檔分割成更小的塊。這對于索引數據和將其傳遞給模型很有用,因為大塊數據更難搜索,并且不適合模型的有限上下文窗口。
存儲:我們需要一個地方來存儲和索引我們的分割,以便以后可以搜索。這通常使用VectorStore和Embeddings模型完成。
檢索:給定用戶輸入,使用檢索器從存儲中檢索相關分割。
生成:ChatModel / LLM使用包括問題和檢索到的數據的提示生成答案。
大文本切割
# 2、大文本的切割 每個片段包含20個字符,允許四個字符重復
text = "hello world, how about you? thanks, I am fine. the machine learning class. So what I wanna do today is just spend a little time going over the logistics of the class, and then we'll start to talk a bit about machine learning"
splitter = RecursiveCharacterTextSplitter(chunk_size=20,chunk_overlap=4)
res = splitter.split_text(text)
for r in res:print(r,end='**\n')
import os
import bs4
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.chains.history_aware_retriever import create_history_aware_retriever
from langchain.chains.retrieval import create_retrieval_chain
from langchain_chroma import Chroma
from langchain_community.document_loaders import WebBaseLoader
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitteros.environ['LANGCHAIN_TRACING_V2'] = "true"
os.environ['LANGCHAIN_PROJECT'] ="LangchainDemo"
os.environ['LANGCHAIN_API_KEY'] = "xxx"
os.environ["TAVILY_API_KEY"] = 'tvly-xxx'
# 1.創建模型
model = ChatOpenAI(model='gpt-4-turbo',api_key='sk-xx',base_url='https://xiaoai.plus/v1')# 1、加載數據: 一篇博客內容數據
loader = WebBaseLoader(web_paths=['https://lilianweng.github.io/posts/2023-06-23-agent/'],bs_kwargs=dict(parse_only=bs4.SoupStrainer(class_=('post-header', 'post-title', 'post-content')))
)docs = loader.load()# print(len(docs))
# print(docs)# 2、大文本的切割
# text = "hello world, how about you? thanks, I am fine. the machine learning class. So what I wanna do today is just spend a little time going over the logistics of the class, and then we'll start to talk a bit about machine learning"
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)splits = splitter.split_documents(docs)# 2、存儲
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())# 3、檢索器
retriever = vectorstore.as_retriever()# 整合# 創建一個問題的模板
system_prompt = """You are an assistant for question-answering tasks.
Use the following pieces of retrieved context to answer
the question. If you don't know the answer, say that you
don't know. Use three sentences maximum and keep the answer concise.\n{context}
"""##
# {context} 這個占位符是由 LangChain 框架自動處理的。在 RAG (Retrieval-Augmented Generation) 應用中,這個占位符會被 LangChain 在運行時動態替換為實際檢索到的相關上下文內容。
#
# 具體來說,工作流程是這樣的:
#
# 當用戶提問時,LangChain 會先通過檢索器(Retriever)從知識庫中查找與問題相關的文檔片段
# 這些檢索到的文檔片段會被自動填充到 {context} 的位置
# 然后連同用戶的問題一起組成完整的提示詞(Prompt)發送給大模型
# 大模型基于這個包含上下文的提示詞生成最終回答
# 所以你不需要手動傳遞 {context} 的值,這是 LangChain RAG 鏈(RAG chain)的標準工作方式。框架會自動處理檢索和上下文注入的過程。
#
# 這種設計是 LangChain 的常見模式,它通過模板和鏈(Chain)的概念,將檢索、提示詞構建和生成等步驟自動化地串聯起來。
# #prompt = ChatPromptTemplate.from_messages( # 提問和回答的 歷史記錄 模板[("system", system_prompt),MessagesPlaceholder("chat_history"), #("human", "{input}"),]
)# 得到chain (創建的是多個文本的)提示模板
chain1 = create_stuff_documents_chain(model, prompt)chain2 = create_retrieval_chain(retriever, chain1)resp = chain2.invoke({'input': "What is Task Decomposition?"})print(resp['answer'])
包含歷史記錄的對話生成
import os
import bs4
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.chains.history_aware_retriever import create_history_aware_retriever
from langchain.chains.retrieval import create_retrieval_chain
from langchain_chroma import Chroma
from langchain_community.document_loaders import WebBaseLoader
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitteros.environ['LANGCHAIN_TRACING_V2'] = "true"
os.environ['LANGCHAIN_PROJECT'] ="LangchainDemo"
os.environ['LANGCHAIN_API_KEY'] = ""
os.environ["TAVILY_API_KEY"] = 'tvly-xxx'
# 1.創建模型
model = ChatOpenAI(model='gpt-4-turbo',api_key='sk-xx',base_url='https://xiaoai.plus/v1')# 1、加載數據: 一篇博客內容數據
loader = WebBaseLoader(web_paths=['https://lilianweng.github.io/posts/2023-06-23-agent/'],bs_kwargs=dict(parse_only=bs4.SoupStrainer(class_=('post-header', 'post-title', 'post-content')))
)docs = loader.load()# print(len(docs))
# print(docs)# 2、大文本的切割
# text = "hello world, how about you? thanks, I am fine. the machine learning class. So what I wanna do today is just spend a little time going over the logistics of the class, and then we'll start to talk a bit about machine learning"
splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)splits = splitter.split_documents(docs)# 2、存儲
vectorstore = Chroma.from_documents(documents=splits, embedding=OpenAIEmbeddings())# 3、檢索器
retriever = vectorstore.as_retriever()# 整合# 創建一個問題的模板
system_prompt = """You are an assistant for question-answering tasks.
Use the following pieces of retrieved context to answer
the question. If you don't know the answer, say that you
don't know. Use three sentences maximum and keep the answer concise.\n{context}
"""##
# {context} 這個占位符是由 LangChain 框架自動處理的。在 RAG (Retrieval-Augmented Generation) 應用中,這個占位符會被 LangChain 在運行時動態替換為實際檢索到的相關上下文內容。
#
# 具體來說,工作流程是這樣的:
#
# 當用戶提問時,LangChain 會先通過檢索器(Retriever)從知識庫中查找與問題相關的文檔片段
# 這些檢索到的文檔片段會被自動填充到 {context} 的位置
# 然后連同用戶的問題一起組成完整的提示詞(Prompt)發送給大模型
# 大模型基于這個包含上下文的提示詞生成最終回答
# 所以你不需要手動傳遞 {context} 的值,這是 LangChain RAG 鏈(RAG chain)的標準工作方式。框架會自動處理檢索和上下文注入的過程。
#
# 這種設計是 LangChain 的常見模式,它通過模板和鏈(Chain)的概念,將檢索、提示詞構建和生成等步驟自動化地串聯起來。
# #prompt = ChatPromptTemplate.from_messages( # 提問和回答的 歷史記錄 模板[("system", system_prompt),MessagesPlaceholder("chat_history"), #("human", "{input}"),]
)# 得到chain (創建的是多個文本的)提示模板
chain1 = create_stuff_documents_chain(model, prompt)# chain2 = create_retrieval_chain(retriever, chain1)# resp = chain2.invoke({'input': "What is Task Decomposition?"})
#
# print(resp['answer'])'''
注意:
一般情況下,我們構建的鏈(chain)直接使用輸入問答記錄來關聯上下文。但在此案例中,查詢檢索器也需要對話上下文才能被理解。解決辦法:
添加一個子鏈(chain),它采用最新用戶問題和聊天歷史,并在它引用歷史信息中的任何信息時重新表述問題。這可以被簡單地認為是構建一個新的“歷史感知”檢索器。
這個子鏈的目的:讓檢索過程融入了對話的上下文。
'''# 創建一個子鏈
# 子鏈的提示模板
contextualize_q_system_prompt = """Given a chat history and the latest user question
which might reference context in the chat history,
formulate a standalone question which can be understood
without the chat history. Do NOT answer the question,
just reformulate it if needed and otherwise return it as is."""retriever_history_temp = ChatPromptTemplate.from_messages([('system', contextualize_q_system_prompt),MessagesPlaceholder('chat_history'),("human", "{input}"),]
)# 創建一個子鏈
history_chain = create_history_aware_retriever(model, retriever, retriever_history_temp)# 保持問答的歷史記錄
store = {}class ChatMessageHistory:passdef get_session_history(session_id: str):if session_id not in store:store[session_id] = ChatMessageHistory()return store[session_id]# 創建父鏈chain: 把前兩個鏈整合
chain = create_retrieval_chain(history_chain, chain1)result_chain = RunnableWithMessageHistory(chain,get_session_history,input_messages_key='input',history_messages_key='chat_history',output_messages_key='answer'
)# 第一輪對話
resp1 = result_chain.invoke({'input': 'What is Task Decomposition?'},config={'configurable': {'session_id': 'zs123456'}}
)print(resp1['answer'])# 第二輪對話
resp2 = result_chain.invoke({'input': 'What are common ways of doing it?'},config={'configurable': {'session_id': 'ls123456'}}
)print(resp2['answer'])