ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

如何用句子滑窗检索在命中句子的同时返回完整句窗口

如何用句子滑窗检索在命中句子的同时返回完整句窗口 如何用句子滑窗检索在命中句子的同时返回完整句窗口【免费下载链接】llm-cookbook面向开发者的 LLM 入门教程吴恩达大模型系列课程中文版项目地址: https://gitcode.com/GitHub_Trending/ll/llm-cookbook基于 LlamaIndex 做文档问答时向量检索的命中粒度是句子但单独一句往往缺少上下文LLM 难以据此生成完整回答。llm-cookbook 仓库的《选修-Building and Evaluating Advanced RAG Applications》第四章 notebook 给出的做法是用SentenceWindowNodeParser按句子建索引把每个句子前后相邻句子组成的“窗口”全文存进节点的window元数据查询时再用MetadataReplacementPostProcessor把命中节点的文本替换成窗口全文这样送给模型的上下文是完整句窗口而相似度匹配仍然以句子为单位。本文按该 notebook4.句子滑窗检索 Sentence window retrieval.ipynb走一遍完整流程示例文档是仓库自带的 data/人工智能.pdf语言模型为gpt-3.5-turbo。准备条件目录、依赖与 API Key所有相对路径data/、utils.py、requirements.txt都以章节目录 content/选修-Building and Evaluating Advanced RAG Applications 为基准在该目录下运行代码。安装依赖。依赖版本以同目录 requirements.txt 为准其中与本场景直接相关的是llama-index0.9.8、openai1.3.5、sentence-transformers2.2.2、python-dotenv1.0.1、nest-asyncio1.6.0做可选的 TruLens 评估还需要trulens-eval0.18.1。pip install -r requirements.txt准备 OpenAI Key。utils.py 里的get_openai_api_key()通过 python-dotenv 的find_dotenv()读取环境变量因此在工作目录下放一个.env文件...中填你自己的 KeyOPENAI_API_KEY你的 OpenAI API Key读取 Key 的入口代码与 notebook 一致import utils import openai openai.api_key utils.get_openai_api_key()用短文本先验证句子窗口如何切分建索引前先用 notebook 里的短文本例子确认SentenceWindowNodeParser的切分与窗口行为。window_size3表示窗口包含 3 句命中句加相邻句子window_metadata_keywindow指定窗口文本存放的元数据键original_text_metadata_keyoriginal_text是原文元数据的键名。from llama_index.node_parser import SentenceWindowNodeParser from llama_index import Document node_parser SentenceWindowNodeParser.from_defaults( window_size3, window_metadata_keywindow, original_text_metadata_keyoriginal_text, ) text 你好. 你怎么样? 我很好! nodes node_parser.get_nodes_from_documents([Document(texttext)]) print([x.text for x in nodes]) print(nodes[1].metadata[window])notebook 记录的输出示例[你好. , 你怎么样? , 我很好! ] 你好. 你怎么样? 我很好!即节点被切分成逐句的文本而每个节点的metadata[window]是覆盖命中句的完整窗口文本。再对四句文本text 你好. 吧台. 猫狗. 老鼠取首句的窗口notebook 记录的输出示例是你好. 吧台. 猫狗. 即边界处的窗口取到文档开头为止的 3 句。加载并合并文档准备中文标点用SimpleDirectoryReader读取 PDF再把各页文本连接成一个字符串、合并为单个Document实例整个文档集合作为一个索引对象处理from llama_index import SimpleDirectoryReader, Document documents SimpleDirectoryReader( input_files[data/人工智能.pdf] ).load_data() document Document(text\n\n.join([doc.text for doc in documents]))中文文档必须先做标点归一化这一步不能省略。notebook 中的说明是不处理会导致无法正确切分中文句子影响后续sentence_window的大小导致输入长度大于gpt-3.5-turbo的最大限制。英文文档可以跳过# 将中文标点符号替换成英文标点符号方便后续处理 document.text document.text.replace(。, . ) document.text document.text.replace(, ! ) document.text document.text.replace(, ? )构建句子滑窗索引notebook 把前面的操作合并成两个函数构建索引的build_sentence_window_index和创建查询引擎的get_sentence_window_query_engine。下面是与 notebook 一致的构建函数注意其中的持久化逻辑save_dir不存在时构建并落盘存在时直接load_index_from_storage加载避免重复构建索引目录是运行时由脚本生成的不在仓库内import os from llama_index import ServiceContext, VectorStoreIndex, StorageContext from llama_index.node_parser import SentenceWindowNodeParser from llama_index import load_index_from_storage def build_sentence_window_index( documents, llm, embed_modellocal:BAAI/bge-small-zh-v1.5, sentence_window_size3, save_dirsentence_index, ): # create the sentence window node parser w/ default settings node_parser SentenceWindowNodeParser.from_defaults( window_sizesentence_window_size, window_metadata_keywindow, original_text_metadata_keyoriginal_text, ) sentence_context ServiceContext.from_defaults( llmllm, embed_modelembed_model, node_parsernode_parser, ) if not os.path.exists(save_dir): sentence_index VectorStoreIndex.from_documents( documents, service_contextsentence_context ) sentence_index.storage_context.persist(persist_dirsave_dir) else: sentence_index load_index_from_storage( StorageContext.from_defaults(persist_dirsave_dir), service_contextsentence_context, ) return sentence_index语言模型用gpt-3.5-turbo、temperature0.1中文文档嵌入模型用local:BAAI/bge-small-zh-v1.5英文文档改用local:BAAI/bge-small-en-v1.5notebook 中配有对应的_en版本函数与data/eBook-How-to-Build-a-Career-in-AI.pdffrom llama_index.llms import OpenAI index build_sentence_window_index( [document], llmOpenAI(modelgpt-3.5-turbo, temperature0.1), save_dir./sentence_index, )把命中节点文本替换为完整窗口MetadataReplacementPostProcessor的作用是把节点文本替换为目标元数据键的内容这里目标键就是window。用短文本可以直观看到替换前后替换前节点文本是命中的单句替换后是覆盖该句的完整窗口文本。from llama_index.indices.postprocessor import MetadataReplacementPostProcessor from llama_index.schema import NodeWithScore from copy import deepcopy postproc MetadataReplacementPostProcessor(target_metadata_keywindow) text 你好. 吧台. 猫狗. 老鼠 nodes node_parser.get_nodes_from_documents([Document(texttext)]) scored_nodes [NodeWithScore(nodex, score1.0) for x in nodes] nodes_old [deepcopy(n) for n in nodes] replaced_nodes postproc.postprocess_nodes(scored_nodes) print(nodes_old[1].text) print(replaced_nodes[1].text)notebook 记录的输出示例吧台. 你好. 吧台. 猫狗. 老鼠这就是标题所说的效果检索命中的是句子本身进入后续生成环节的文本却是完整窗口。重排序筛出最相关的句子窗口替换会放大送入模型的上下文notebook 在查询引擎里还挂了一个SentenceTransformerRerank后处理器模型为BAAI/bge-reranker-basetop_n2表示重排后保留前 2 个节点。先用构造数据验证它的工作方式查询我想要只狗.初始分数是“这是只猫”0.6、“这是只狗”0.4from llama_index import QueryBundle from llama_index.schema import TextNode, NodeWithScore from llama_index.indices.postprocessor import SentenceTransformerRerank rerank SentenceTransformerRerank( top_n2, modelBAAI/bge-reranker-base ) query QueryBundle(我想要只狗.) scored_nodes [ NodeWithScore(nodeTextNode(text这是只猫), score0.6), NodeWithScore(nodeTextNode(text这是只狗), score0.4), ] reranked_nodes rerank.postprocess_nodes(scored_nodes, query_bundlequery) print([(x.text, x.score) for x in reranked_nodes])notebook 记录的输出示例[(这是只狗, 0.9660425), (这是只猫, 0.06396222)]即重排后“这是只狗”升到首位。组装查询引擎并验证结果get_sentence_window_query_engine把上面两个后处理器按顺序挂到查询引擎上similarity_top_k6表示先按相似度取 6 个句级节点再依次做窗口替换和重排序def get_sentence_window_query_engine( sentence_index, similarity_top_k6, rerank_top_n2 ): # define postprocessors postproc MetadataReplacementPostProcessor(target_metadata_keywindow) rerank SentenceTransformerRerank( top_nrerank_top_n, modelBAAI/bge-reranker-base ) sentence_window_engine sentence_index.as_query_engine( similarity_top_ksimilarity_top_k, node_postprocessors[postproc, rerank] ) return sentence_window_engine query_engine get_sentence_window_query_engine(index, similarity_top_k6)执行查询并用display_response查看结果window_response query_engine.query(在人工智能领域建功立业的关键是什么?) from llama_index.response.notebook_utils import display_response display_response(window_response)notebook 中记录的Final Response输出示例在人工智能领域建功立业的关键是系统能够正确解释外部数据从中学习并利用这些知识通过灵活适应实现特定目标和任务的能力。验证要点display_response会展示最终回答与检索节点再次运行时./sentence_index已存在索引直接从磁盘加载而不重建可作为索引持久化生效的判断依据。可选用 TruLens 对比窗口大小 1 与 3 的效果如果想知道窗口大小对检索质量的影响notebook 提供了 TruLens 对比流程依赖trulens-eval0.18.1和 utils.py 中的get_prebuilt_trulens_recorder后者封装了 Answer Relevance、Context Relevance、Groundedness 三项 Feedback。从 data/generated_questions.txt 读取评测问题eval_questions [] with open(data/generated_questions.txt, r) as file: for line in file: item line.strip() eval_questions.append(item)以窗口大小为 1 为例窗口 3 只需把sentence_window_size改为 3、save_dir改为sentence_index_3notebook 中即 3.2 节from trulens_eval import Tru from utils import get_prebuilt_trulens_recorder tru Tru() tru.reset_database() sentence_index_1 build_sentence_window_index( documents, llmOpenAI(modelgpt-3.5-turbo, temperature0.1), embed_modellocal:BAAI/bge-small-zh-v1.5, sentence_window_size1, save_dirsentence_index_1, ) sentence_window_engine_1 get_sentence_window_query_engine( sentence_index_1 ) tru_recorder_1 get_prebuilt_trulens_recorder( sentence_window_engine_1, app_idsentence window engine 1 ) def run_evals(eval_questions, tru_recorder, query_engine): for question in eval_questions: with tru_recorder as recording: response query_engine.query(question) run_evals(eval_questions, tru_recorder_1, sentence_window_engine_1)运行后取回记录records, feedback tru.get_records_and_feedback(app_ids[]) records.head()记录表的Answer Relevance、Context Relevance、Groundedness三列是示例输出notebook 中窗口 1 与窗口 3 两次运行各有记录用于对照比较数值随运行变化不作为固定成功条件。边界与已知现象中文文档必须先做标点归一化再建索引否则句子切分不正确、窗口大小失真且可能超出gpt-3.5-turbo的输入长度限制notebook 注释明确说明。英文文档跳过标点替换嵌入模型改用local:BAAI/bge-small-en-v1.5。sentence_index、sentence_index_1、sentence_index_3等目录名一旦选定就固定了窗口大小等构建参数不同配置要像 notebook 那样使用不同save_dir否则加载到的旧索引与预期配置不一致。notebook 中记录到批量跑 TruLens 评估时 OpenAI 请求曾触发 429 限流错误TPM 限制 60000客户端按 Retries remaining 自动重试评估阶段出现同类报错属文档中已记录的现象。同目录 utils.py 还提供了build_automerging_index与get_automerging_query_engine对应本章之后的自动合并检索见 readme.md 目录中的第 5 节需要更大粒度上下文时可以继续沿这条线看。【免费下载链接】llm-cookbook面向开发者的 LLM 入门教程吴恩达大模型系列课程中文版项目地址: https://gitcode.com/GitHub_Trending/ll/llm-cookbook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表