提示工程在RAG中的应用:优化LlamaIndex工作流程
在处理大型语言模型(LLM)时,优化提示(prompt)是提升输出质量的关键。本文将介绍如何在LlamaIndex的RAG(检索增强生成)工作流程中应用各种提示技巧,帮助你自定义LlamaIndex管道。
前置知识
在深入学习这些提示技巧之前,你需要了解以下基础知识:
- Python编程:熟悉Python语言及其常用库。
- 自然语言处理(NLP):了解基本的NLP概念和技术。
- 大型语言模型(LLM):了解LLM的基本工作原理和常见应用。
安装与配置
首先,我们需要安装必要的库,并配置OpenAI API密钥。
%pip install llama-index-llms-openai
%pip install llama-index-readers-file pymupdf
!pip install llama-index
import os
import openai
os.environ["OPENAI_API_KEY"] = "sk-..."
openai.api_key = os.environ["OPENAI_API_KEY"]
设置
import logging
import sys
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))
from llama_index.core import VectorStoreIndex
from llama_index.core import PromptTemplate
from IPython.display import Markdown, display
加载数据
我们将从arXiv下载一篇论文并加载到向量存储中。
!mkdir data
!wget --user-agent "Mozilla" "https://arxiv.org/pdf/2307.09288.pdf" -O "data/llama2.pdf"
from pathlib import Path
from llama_index.readers.file import PyMuPDFReader
loader = PyMuPDFReader()
documents = loader.load(file_path="./data/llama2.pdf")
加载到向量存储
from llama_index.core import VectorStoreIndex
from llama_index.llms.openai import OpenAI
gpt35_llm = OpenAI(model="gpt-3.5-turbo")
gpt4_llm = OpenAI(model="gpt-4")
index = VectorStoreIndex.from_documents(documents)
设置查询引擎 / 检索器
query_str = "What are the potential risks associated with the use of Llama 2 as mentioned in the context?"
query_engine = index.as_query_engine(similarity_top_k=2, llm=gpt35_llm)
# 用于测试
vector_retriever = index.as_retriever(similarity_top_k=2)
response = query_engine.query(query_str)
print(str(response))
查看/自定义提示
首先,让我们看看查询引擎的提示,并了解如何自定义它。
查看提示
# 定义提示查看函数
def display_prompt_dict(prompts_dict):
for k, p in prompts_dict.items():
text_md = f"**Prompt Key**: {k}<br>" f"**Text:** <br>"
display(Markdown(text_md))
print(p.get_template())
display(Markdown("<br><br>"))
prompts_dict = query_engine.get_prompts()
display_prompt_dict(prompts_dict)
自定义提示
如果我们想做一些不同于标准问答提示的事情呢?让我们尝试使用LangchainHub中的RAG提示。
# 为此,你需要使用langchain对象
from langchain import hub
langchain_prompt = hub.pull("rlm/rag-prompt")
# 注意:提示中的模板变量与查询引擎中的合成器预期的变量不同
# 提示使用context和question,
# 我们期望context_str和query_str
# 这没有问题!让我们添加模板变量映射来映射变量。我们使用LangchainPromptTemplate来映射到LangChain提示。
from llama_index.core.prompts import LangchainPromptTemplate
lc_prompt_tmpl = LangchainPromptTemplate(
template=langchain_prompt,
template_var_mappings={"query_str": "question", "context_str": "context"},
)
query_engine.update_prompts(
{"response_synthesizer:text_qa_template": lc_prompt_tmpl}
)
prompts_dict = query_engine.get_prompts()
display_prompt_dict(prompts_dict)
尝试一下
让我们重新运行查询引擎。
response = query_engine.query(query_str)
print(str(response))
添加少量示例
让我们尝试在提示中添加少量示例,这些示例可以根据查询动态加载!
from llama_index.core.schema import TextNode
few_shot_nodes = []
for line in open("../llama2_qa_citation_events.jsonl", "r"):
few_shot_nodes.append(TextNode(text=line))
few_shot_index = VectorStoreIndex(few_shot_nodes)
few_shot_retriever = few_shot_index.as_retriever(similarity_top_k=2)
import json
def few_shot_examples_fn(**kwargs):
query_str = kwargs["query_str"]
retrieved_nodes = few_shot_retriever.retrieve(query_str)
# 遍历每个节点,获取json对象
result_strs = []
for n in retrieved_nodes:
raw_dict = json.loads(n.get_content())
query = raw_dict["query"]
response_dict = json.loads(raw_dict["response"])
result_str = f"""\
Query: {query}
Response: {response_dict}"""
result_strs.append(result_str)
return "\n\n".join(result_strs)
# 编写带有函数的提示模板
qa_prompt_tmpl_str = """\
Context information is below.
---------------------
{context_str}
---------------------
Given the context information and not prior knowledge, \
answer the query asking about citations over different topics.
Please provide your answer in the form of a structured JSON format containing \
a list of authors as the citations. Some examples are given below.
{few_shot_examples}
Query: {query_str}
Answer: \
"""
qa_prompt_tmpl = PromptTemplate(
qa_prompt_tmpl_str,
function_mappings={"few_shot_examples": few_shot_examples_fn},
)
citation_query_str = "Which citations are mentioned in the section on Safety RLHF?"
# 让我们看看带有少量示例函数的格式化提示是什么样子的。(为了简洁起见,我们填充了测试上下文)
print(
qa_prompt_tmpl.format(
query_str=citation_query_str, context_str="test_context"
)
)
query_engine.update_prompts(
{"response_synthesizer:text_qa_template": qa_prompt_tmpl}
)
display_prompt_dict(query_engine.get_prompts())
response = query_engine.query(citation_query_str)
print(str(response))
上下文转换 - PII示例
我们还可以在提示变量中动态添加上下文转换函数。在这个示例中,我们展示了如何在将context_str输入到上下文窗口之前处理它——具体来说,是屏蔽PII(个人身份信息),以缓解数据隐私/安全方面的担忧。
from llama_index.core.postprocessor import (
NERPIINodePostprocessor,
SentenceEmbeddingOptimizer,
)
from llama_index.core import QueryBundle
from llama_index.core.schema import NodeWithScore, TextNode
pii_processor = NERPIINodePostprocessor(llm=gpt4_llm)
def filter_pii_fn(**kwargs):
# 运行优化器
query_bundle = QueryBundle(query_str=kwargs["query_str"])
new_nodes = pii_processor.postprocess_nodes(
[NodeWithScore(node=TextNode(text=kwargs["context_str"]))],
query_bundle=query_bundle,
)
new_node = new_nodes[0]
return new_node.get_content()
qa_prompt_tmpl_str = (
"Context information is below.\n"
"---------------------\n"
"{context_str}\n"
"---------------------\n"
"Given the context information and not prior knowledge, "
"answer the query.\n"
"Query: {query_str}\n"
"Answer: "
)
qa_prompt_tmpl = PromptTemplate(
qa_prompt_tmpl_str, function_mappings={"context_str": filter_pii_fn}
)
query_engine.update_prompts(
{"response_synthesizer:text_qa_template": qa_prompt_tmpl}
)
# 查看提示
retrieved_nodes = vector_retriever.retrieve(query_str)
context_str = "\n\n".join([n.get_content() for n in retrieved_nodes])
print(qa_prompt_tmpl.format(query_str=query_str, context_str=context_str))
response = query_engine.query(query_str)
print(str(response))
总结
通过使用提示工程技巧,你可以在LlamaIndex的RAG工作流程中显著提升输出质量。无论是自定义提示、添加少量示例还是动态上下文转换,这些技巧都能帮助你更好地控制和优化LLM的输出。希望本文能为你提供有价值的参考,让你在实际应用中取得更好的效果。
参考文献:
扩展阅读:
希望这篇博客能为你带来启发和帮助,让我们在编程的世界里,更加高效地驾驭数据和信息!
3640

被折叠的 条评论
为什么被折叠?



