AI大模型(七)Langchain核心模块与实战(二)
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'])