LangChain构建大模型应用之RAG
RAG(Retrieval-augmented Generation 检索增强生成)是一种结合信息检索与生成模型的技术,通过动态整合外部知识库提升大模型输出的准确性和时效性。其核心思想是在生成答案前,先检索外部知识库中的相关信息作为上下文依据,从而突破传统生成模型的静态知识边界。
为什么我们要整合外部知识库呢?
首先,大模型训练通常需要耗费很多资源,几百万张贵的离谱的高性能GPU卡,巨量的电力,巨量的高质量训练数据–意味着大量的硬盘,每次训练大概要几周到一两个月,总之成本在百万美元到上亿美元,比如2023年,OpenAI的GPT-4模型和Google的Gemini Ultra模型的训练成本更是分别高达约7800万美元和近2亿美元!2024年年底的重大新闻是我国的国产大模型DeepSeek v3 的发布,DeepSeek v3 真正令人印象深刻的是训练成本。该模型在 2788000 个 H800 GPU 小时上进行训练,估计成本为 5576000 美元。facebook (现在名为Meta )的Llama 3.1 405B 训练了 30,840,000 个 GPU 小时——是 DeepSeek v3 所用时间的 11 倍,但基准测试结果略差。
大模型的知识库在训练的时候就已经固定了,而如果要更新知识库那就得重新训练模型,或者对大模型进行微调训练。如果遇到用户需要频繁更新知识库的场景,成本是无法接受的,于是就有了先检索知识库然后让大模型处理后输出的办法。
其次,LLM在自然语言处理任务中可能提供不准确或不充分答案的局限性。我们在使用大模型时候经常会遇到幻觉问题,在某些需求领域这些幻觉是无法接受的,比如在医院开药的时候,药名功效和用量是不能出错的
在一些细分的专业领域,大模型的训练数据是不足的,所以结合信息检索与文本生成:通过从庞大的外部知识库中检索相关信息,动态增强模型的生成能力,弥补LLM依赖静态训练数据的不足。
RAG还可以增强模型输出的准确性和信息完整性,减少生成错误答案的概率。
下面作者将根据吴恩达《LangChain for LLM Application Development》 视频课程来做一些课程笔记,这门课程非常不错,很适合那些有编程基础的读者学习大模型应用开发。由于代码里吴恩达用的是openAI 模型,收费高国内还不好用,langChain可以使用不同的模型,我将代码换成阿里巴巴的千问大模型,方便大家使用。
L1 ,model prompt parser.
第一节,模型,提示词和解析器
1.核心概念介绍
- 模型 model:指语言模型,是大语言模型应用的基础支撑。
- 提示词 prompt:即创建输入的风格,其决定传递给模型的信息内容和形式。
- 解析器 parser:负责将模型输出解析为结构化格式,便于后续处理。
模型与提示的应用实践
基础示例:利用大模型,通过自定义助手函数调用 千问大模型 qwen-plus,如询问 “一加一等于什么” 获取回答。
使用千问大模型需要在阿里官网开通appkey具体如何使用和配置千问大模型 参考如下链接
https://blog.csdn.net/roccreed/article/details/141927269
(linux 和macos 配置环境变量方式和上面不一样在这里插入代码片)
import os
from openai import OpenAIclient = OpenAI(# 若没有配置环境变量,请用百炼API Key将下行替换为:api_key="sk-xxx",api_key=os.getenv("DASHSCOPE_API_KEY"), base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
)
client
llm_model = "qwen-plus"def get_completion(prompt, model=llm_model):messages = [{"role": "user", "content": prompt}]response = client.chat.completions.create(model=model,messages=messages,temperature=0, )return response.choices[0].message.contentget_completion("What is 1+1?")
文本翻译案例:收到客户邮件时,使用大语言模型将用户的不规范的口语化的海盗式英语其翻译成平静而有礼貌的美式英语。先通过字符串构建翻译提示,后利用 LangChain 的 ChatOpenAI 和 ChatPromptTemplate 创建提示模板。设置温度参数(如设为 0 使输出更稳定),指定翻译样式和文本等输入变量,生成提示并传递给模型获取翻译结果。此方法可复用提示模板,处理不同语言客户邮件翻译,且修改提示能得到不同结果。
customer_email = """
Arrr, I be fuming that me blender lid \
flew off and splattered me kitchen walls \
with smoothie! And to make matters worse,\
the warranty don't cover the cost of \
cleaning up me kitchen. I need yer help \
right now, matey!
"""style = """American English \
in a calm and respectful tone
"""prompt = f"""Translate the text \
that is delimited by triple backticks
into a style that is {style}.
text: ```{customer_email}```
"""print(prompt)response = get_completion(prompt)
print(response)#下面是ChatPromptTemplate实现方式
from langchain_openai import ChatOpenAIchat = ChatOpenAI(openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",
# openai_api_key="sk-xxx", # app_keyopenai_api_key=os.getenv("DASHSCOPE_API_KEY"),model_name="qwen-plus", # 模型名称temperature=0.0
)template_string = """Translate the text \
that is delimited by triple backticks \
into a style that is {style}. \
Translated into {Language}
text: ```{text}```
"""customer_style = """American English \
in a calm and respectful tone
"""
customer_style = """American English \
in a calm and respectful tone
"""customer_email = """
Arrr, I be fuming that me blender lid \
flew off and splattered me kitchen walls \
with smoothie! And to make matters worse, \
the warranty don't cover the cost of \
cleaning up me kitchen. I need yer help \
right now, matey!
"""
customer_language = """french"""customer_messages = prompt_template.format_messages(style=customer_style,text=customer_email,Language = customer_language)print(customer_messages[0])customer_response = chat.invoke(customer_messages)
print(customer_response.content)
输出解析的应用实践
在复杂应用中,常要求模型按特定格式输出(如 JSON 格式)。常见的比如从产品评论提取信息为例,模型直接输出看似 JSON 格式的字符串,但实际是普通字符串,无法像字典一样提取值,因此需要输出解析,即由模型提取我们需要的内容以json输出,以方便我们的程序做存储和判断。
customer_review = """\
This leaf blower is pretty amazing. It has four settings:\
candle blower, gentle breeze, windy city, and tornado. \
It arrived in two days, just in time for my wife's \
anniversary present. \
I think my wife liked it so much she was speechless. \
So far I've been the only one using it, and I've been \
using it every other morning to clear the leaves on our lawn. \
It's slightly more expensive than the other leaf blowers \
out there, but I think it's worth it for the extra features.
"""review_template = """\
For the following text, extract the following information:gift: Was the item purchased as a gift for someone else? \
Answer True if yes, False if not or unknown.delivery_days: How many days did it take for the product \
to arrive? If this information is not found, output -1.price_value: Extract any sentences about the value or price,\
and output them as a comma separated Python list.Format the output as JSON with the following keys:
gift
delivery_days
price_valuetext: {text}
"""
from langchain.prompts import ChatPromptTemplateprompt_template = ChatPromptTemplate.from_template(review_template)
print(prompt_template)messages = prompt_template.format_messages(text=customer_review)
# chat = ChatOpenAI(temperature=0.0, model=llm_model)
chat = ChatOpenAI(openai_api_base="https://dashscope.aliyuncs.com/compatible-mode/v1",openai_api_key=os.getenv("DASHSCOPE_API_KEY"),model_name="qwen-plus", # 模型名称temperature=0.0
)
response = chat.invoke(messages)
print(response.content)type(response.content)
print(response.content)
#此处输出的是str类型
使用StructuredOutputParser实现,并输出字典类型
from langchain.output_parsers import ResponseSchema
from langchain.output_parsers import StructuredOutputParsergift_schema = ResponseSchema(name="gift",description="Was the item purchased\as a gift for someone else? \Answer True if yes,\False if not or unknown.")
delivery_days_schema = ResponseSchema(name="delivery_days",description="How many days\did it take for the product\to arrive? If this \information is not found,\output -1.")
price_value_schema = ResponseSchema(name="price_value",description="Extract any\sentences about the value or \price, and output them as a \comma separated Python list.")response_schemas = [gift_schema, delivery_days_schema,price_value_schema]output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
format_instructions = output_parser.get_format_instructions()
print(format_instructions)review_template_2 = """\
For the following text, extract the following information:gift: Was the item purchased as a gift for someone else? \
Answer True if yes, False if not or unknown.delivery_days: How many days did it take for the product\
to arrive? If this information is not found, output -1.price_value: Extract any sentences about the value or price,\
and output them as a comma separated Python list.text: {text}{format_instructions}
"""prompt = ChatPromptTemplate.from_template(template=review_template_2)messages = prompt.format_messages(text=customer_review, format_instructions=format_instructions)print(messages[0].content)response = chat.invoke(messages)
print(response.content)output_dict = output_parser.parse(response.content)
type(output_dict)
print(output_dict)output_dict.get('delivery_days')
output_dict.get('gift')
output_dict.get('price_value')