- 人工智能
- 大模型
- 预训练
- 微调
- LoRA
- RLHF
- 强化学习
- 分布式训练
【免费下载链接】PaddleNLP
Easy-to-use and powerful LLM and SLM library with awesome model zoo.
导读
本文基于 PaddleNLP 仓库slm/pipelines子项目中的端到端问答示例,系统讲解如何用预置的召回模型(Retriever)、排序模型(Ranker)与阅读理解模型(Reader)快速搭建一套针对自有业务数据的智能问答系统,并串联 ElasticSearch ANN 服务、REST API 模型服务与 Streamlit WebUI,最终交付可交互的 Web 可视化问答应用。读完本文,你将掌握端到端问答系统的完整搭建流程、offline_ann.py建库命令与dense_qa.yaml流水线配置的精读方法,以及将自定义模型接入系统的具体路径。
1. 场景概述:为什么需要一套问答系统
问答系统是信息检索系统的一种高级形式:系统理解用户输入的问题,然后从知识库中检索、定位并直接反馈答案。其典型价值场景包括:
- 生活场景中的复杂规则:例如"火车提前多久可以免费退票?""在北京工作几年可以办理居住证?",答案往往散落在冗长的规章制度中。
- 企业内部政策咨询:例如"商业保险理赔需要什么材料?""打车报销的具体流程是什么?",传统做法需要员工逐一阅读政策文件或咨询相关工作人员,费时费力。
针对这类常见业务,基于检索增强的问答系统可以把政策文档、规则条款整理成知识库,用户提问时系统自动从知识库中找到答案,在提升用户体验的同时降低客服人员的工作负荷与企业运营成本。
2. 产品功能与系统特色
本项目(位于slm/pipelines)提供了低成本搭建端到端问答系统的能力:用户只需准备好自己的业务数据,即可使用预置的问答系统模型(召回模型、排序模型、阅读理解模型)快速搭建针对自身业务数据的问答系统,并提供基于 Streamlit 的 Web 可视化服务。
2.1 系统特色
- 端到端:提供包括数据建库、模型服务部署、WebUI 可视化在内的一整套端到端问答系统能力;支持对 Txt、Word、PDF、Image 多源数据进行解析、识别并写入 ANN 数据库。
- 效果好:依托 ERNIE 语义理解技术与 RocketQA 开放域问答技术,预置了成熟的深度学习模型。其中召回与排序模型来自 RocketQA 系列(如
rocketqa-zh-nano-*、rocketqa-zh-dureader-*),阅读理解模型为ernie-gram-zh-finetuned-dureader-robust(基于 ERNIE-Gram 在 DuReader Robust 数据集上微调)。
3. 系统架构:检索-排序-阅读三段式流水线
从源码结构看,问答系统的核心是一条"召回 → 排序 → 阅读"的串行流水线。在 standard_pipelines.py 中,ExtractiveQAPipeline通过Pipeline依次注册三个节点:
self.pipeline.add_node(component=retriever, name="Retriever", inputs=["Query"]) self.pipeline.add_node(component=ranker, name="Ranker", inputs=["Retriever"]) self.pipeline.add_node(component=reader, name="Reader", inputs=["Ranker"])三个核心组件的职责与底层实现如下:
| 组件 | 类型 | 模型角色 | 源码位置 |
|---|---|---|---|
DensePassageRetriever | 双塔(bi-encoder) | 分别编码 Query 与 Passage,在 ANN 索引中做向量召回 | retriever/dense.py |
ErnieRanker | 交互式(cross-encoder) | 对召回结果做精细相关性重排 | ranker/ernie_ranker.py |
ErnieReader | 抽取式阅读理解 | 从重排后的候选文档中抽取答案片段 | reader/ernie_dureader.py |
DensePassageRetriever使用一对编码器(Query 编码器与 Passage 编码器)将问题与候选段落映射到同一向量空间,用向量相似度完成粗召回,支持max_seq_len_query、max_seq_len_passage、batch_size、embed_title、top_k等关键参数(见 dense.py)。ErnieRanker内部通过 PaddleNLPTaskflow("text_similarity", model=model_name_or_path)加载 Cross-Encoder 模型,对 "问题-文档" 组合打分排序,弥补"召回召回率高但排序不准"的短板。ErnieReader基于 ERNIE 3.0 系抽取式问答模型,从候选文档中预测答案起止位置,并提供context_window_size、return_no_answer、no_ans_boost、top_k等推理控制参数。
4. 运行环境与安装说明
示例的运行环境要求如下(文档实验环境,用户也可在自己的 GPU 硬件上复现):
a. 软件环境
- Python >= 3.7.3
- paddlenlp >= 2.2.1
- paddlepaddle-gpu >= 2.3
- CUDA Version: 10.2
- NVIDIA Driver Version: 440.64.00
- Ubuntu 16.04.6 LTS (Docker)
b. 硬件环境
- NVIDIA Tesla V100 16GB x4 卡
- Intel(R) Xeon(R) Gold 6148 CPU @ 2.40GHz
c. 依赖安装
首先安装 PaddlePaddle(依据官方安装文档选择对应 CUDA 版本的安装方式),然后安装paddle-pipelines依赖:
# pip 一键安装 pip install --upgrade paddle-pipelines -i https://pypi.tuna.tsinghua.edu.cn/simple # 或者源码进行安装最新版本 cd ${HOME}/PaddleNLP/pipelines/ pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple python setup.py install下载源码:
git clone https://gitcode.com/gh_mirrors/pa/PaddleNLP.git cd PaddleNLP/pipelines注意:以下所有流程都只需要在pipelines根目录下进行,不需要跳转目录。若在 Windows 环境下搭建,请参考 Install_windows.md,其中建议使用 Anaconda Powershell Prompt(由于环境变量设置不兼容的原因,暂不支持 cmd 执行),并额外需要先通过源码安装htbuilder包(git clone后执行python setup install,可规避 Windows 默认 gbk 编码导致的UnicodeDecodeError)。
5. 快速开始:城市百科知识问答系统一键体验
5.1 数据说明
示例知识库数据为爬取的百度百科国内重点城市介绍文档,将文档中的非结构化文本抽取后按段落切分作为问答知识库数据:共 365 个城市的百科介绍文档,切分后 1318 个段落。
5.2 一键运行示例脚本
仓库预置了城市百科问答系统的代码示例,可通过dense_qa_example.py快速体验(建议 GPU 环境,CPU 也可运行但耗时较长):
# 建议在 GPU 环境下运行本示例,运行速度较快 # 设置 1 个空闲的 GPU 卡,此处假设 0 卡为空闲 GPU export CUDA_VISIBLE_DEVICES=0 python examples/question-answering/dense_qa_example.py --device gpu # 如果只有 CPU 机器,可以通过 --device 参数指定 cpu 即可, 运行耗时较长 unset CUDA_VISIBLE_DEVICES python examples/question-answering/dense_qa_example.py --device cpudense_qa_example.py支持的命令行参数(见 dense_qa_example.py):
| 参数 | 默认值 | 说明 |
|---|---|---|
--device | gpu | 运行设备,可选cpu/gpu |
--index_name | faiss_index | FAISS ANN 索引名称 |
--max_seq_len_query | 64 | 查询文本分词后的最大长度 |
--max_seq_len_passage | 256 | 段落文本分词后的最大长度 |
--retriever_batch_size | 16 | 构建 ANN 索引时召回模型抽取段落向量的批大小 |
脚本内部会从对象存储自动下载百科数据(baike.zip)、切分段落、写入 FAISS 文档库并更新向量索引;随后加载rocketqa-zh-dureader-cross-encoder排序模型与ernie-gram-zh-finetuned-dureader-robust阅读理解模型,构建ExtractiveQAPipeline,以{"Retriever": {"top_k": 50}, "Ranker": {"top_k": 1}, "Reader": {"top_k": 1}}的参数依次回答"北京市有多少个行政区?""上海常住人口有多少?""广州市总面积多大?""河北省的省会在哪里?""安徽省的简称是什么?"等示例问题。三个组件的预置模型详细介绍请参考 API.md。
6. 构建 Web 可视化问答系统
整个 Web 可视化问答系统包含3 大组件:
- 基于 ElasticSearch 的 ANN 服务(向量检索库)
- 基于 REST API 的模型服务(召回 + 排序 + 阅读推理)
- 基于 Streamlit 的 WebUI(人机交互界面)
以下依次搭建这 3 个服务并串联成完整的可视化问答系统。
6.1 启动 ANN 服务(ElasticSearch)
- 下载并解压 ElasticSearch 8.3.2(参考官方文档)。
- 修改 ElasticSearch 安装目录下
config/elasticsearch.yml的配置,关闭安全认证:
xpack.security.enabled: false- 启动 ES 服务:
./bin/elasticsearch- 检查 ES 服务是否启动成功:
curl http://localhost:9200/_aliases?pretty=true备注:ES 服务默认开启端口为 9200。如果以 root 用户启动报错java.lang.RuntimeException: can not run elasticsearch as root,可参考 FAQ.md 中的做法:新建非 root 用户并授予 ES 安装目录权限后以该用户启动。
6.2 文档数据写入 ANN 索引库
使用utils/offline_ann.py将百科城市数据写入 ES 建立 ANN 索引库:
python utils/offline_ann.py --index_name baike_cities \ --doc_dir data/baike \ --delete_index \ --query_embedding_model rocketqa-zh-nano-query-encoder \ --passage_embedding_model rocketqa-zh-nano-para-encoder \ --embedding_dim 312参数含义说明(完整参数见 offline_ann.py):
| 参数 | 默认值 | 说明 |
|---|---|---|
index_name | baike_cities | ANN 索引的名称 |
doc_dir | data/baike/ | txt 文本数据的路径 |
host | 127.0.0.1 | ElasticSearch 的 IP 地址 |
port | 9200 | ElasticSearch 的端口号 |
delete_index | false | 是否删除现有的索引和数据(清空 ES 数据),默认 false |
search_engine | elastic | ANN 检索引擎类型,可选elastic/milvus/bes(Baidu ElasticSearch) |
embedding_dim | 768 | 索引的向量维度,需与模型输出维度一致(nano 系列为 312) |
username/password | 空 | ANN 检索引擎的用户名与密码(如 BES) |
query_embedding_model | rocketqa-zh-base-query-encoder | 查询侧编码模型 |
passage_embedding_model | rocketqa-zh-base-para-encoder | 段落侧编码模型 |
device | gpu | 运行设备,可选cpu/gpu |
embed_title | False | 是否将标题拼接进 embedding |
split_answers | False | 是否将行切分为问题与答案 |
此外脚本还提供params_path(加载本地 checkpoint)、use_splitter(是否使用更精细的切分器,配合chunk_size、chunk_overlap、separator、language、pooling_mode等参数)、es_chunk_size/es_thread_count/es_queue_size(ES 批量写入调优)等高级选项。当doc_dir为脚本内置的数据键(如data/baike、data/dureader_dev、data/insurance)时,脚本会自动下载对应数据压缩包。
运行成功后会输出类似日志(段落数量应与建库数据一致):
INFO - pipelines.utils.logger - Logged parameters: {'processor': 'TextSimilarityProcessor', 'tokenizer': 'NoneType', 'max_seq_len': '0', 'dev_split': '0.1'} INFO - pipelines.document_stores.elasticsearch - Updating embeddings for all 1318 docs ... Updating embeddings: 10000 Docs [00:16, 617.76 Docs/s]使用如下命令查看插入结果:
curl -XGET http://localhost:9200/baike_cities/_count运行结束后会有如下输出:
{"count":1318,"_shards":{"total":1,"successful":1,"skipped":0,"failed":0}}6.3 启动 REST API 模型服务
注意:dense_qa.yaml中配置的检索模型需要与前面使用offline_ann.py建库时使用的检索模型一致(包括模型名与向量维度),否则会出现向量维度不匹配、召回失效的问题。
# 指定智能问答系统的Yaml配置文件 export PIPELINE_YAML_PATH=rest_api/pipeline/dense_qa.yaml # 使用端口号 8891 启动模型服务 python rest_api/application.py 8891Linux 用户推荐采用 Shell 脚本一键启动:
sh examples/question-answering/run_qa_server.sh(run_qa_server.sh内部即设置CUDA_VISIBLE_DEVICES=0、PIPELINE_YAML_PATH=rest_api/pipeline/dense_qa.yaml后执行python rest_api/application.py 8891,见 run_qa_server.sh。)
rest_api/application.py基于 FastAPI 构建,注册了 search(检索)、feedback(反馈)、file-upload(文件上传)、document(文档管理)四类路由(见 router.py),并默认开启 CORS 允许浏览器跨域访问。
启动后可用 curl 验证服务:
curl -X POST -k http://localhost:8891/query -H 'Content-Type: application/json' -d '{"query": "北京市有多少个行政区?","params": {"Retriever": {"top_k": 5}, "Ranker":{"top_k": 5}}}'更多 API 接口文档及调用方式可通过http://127.0.0.1:8891/docs(FastAPI 自动生成的 OpenAPI 文档)查看。
dense_qa.yaml 流水线配置精读
服务启动前会读取 dense_qa.yaml,该文件定义了整套流水线的组件与连接关系:
version: '1.1.0' components: # define all the building-blocks for Pipeline - name: DocumentStore type: ElasticsearchDocumentStore params: host: localhost index: baike_cities embedding_dim: 312 port: 9200 - name: Retriever type: DensePassageRetriever params: document_store: DocumentStore # params can reference other components defined in the YAML top_k: 10 query_embedding_model: rocketqa-zh-nano-query-encoder passage_embedding_model: rocketqa-zh-nano-query-encoder embed_title: False - name: Ranker type: ErnieRanker params: model_name_or_path: rocketqa-zh-dureader-cross-encoder top_k: 5 - name: Reader type: ErnieReader params: model_name_or_path: ernie-gram-zh-finetuned-dureader-robust context_window_size: 1000 return_no_answer: true top_k: 5 - name: TextFileConverter type: TextConverter - name: ImageFileConverter type: ImageToTextConverter - name: PDFFileConverter type: PDFToTextConverter - name: DocxFileConverter type: DocxToTextConverter - name: Preprocessor type: PreProcessor params: split_by: word split_length: 1000 - name: FileTypeClassifier type: FileTypeClassifier pipelines: - name: query # a sample extractive-qa Pipeline type: Query nodes: - name: Retriever inputs: [Query] - name: Ranker inputs: [Retriever] - name: Reader inputs: [Ranker] - name: indexing type: Indexing nodes: - name: FileTypeClassifier inputs: [File] # ...各文件转换器按类型分派,经 Preprocessor 切分后由 Retriever 生成向量并写入 DocumentStore关键配置解读:
DocumentStore:指定 ES 连接地址(host: localhost、port: 9200)、索引名(index: baike_cities)与向量维度(embedding_dim: 312,与rocketqa-zh-nano-*模型输出维度一致);若要支撑更大规模文档,YAML 注释中还提示可考虑MilvusDocumentStore或WeaviateDocumentStore。Retriever:top_k: 10控制每路召回的候选文档数;passage_embedding_model与query_embedding_model在此示例中同为 nano 系列编码器。Ranker:rocketqa-zh-dureader-cross-encoder,top_k: 5控制重排后送入 Reader 的文档数。Reader:context_window_size: 1000控制答案上下文显示窗口,return_no_answer: true允许在找不到答案时返回"无答案"预测。indexing流水线:FileTypeClassifier按文件类型分派到TextConverter/PDFToTextConverter/DocxToTextConverter/ImageToTextConverter,经PreProcessor(按词切分、每块 1000 词)切分后由Retriever生成向量并写入DocumentStore,这正是 WebUI 前端上传文件建索引的底层链路。
6.4 启动 WebUI(Streamlit)
pip install streamlit==1.11.1 # 配置模型服务地址 export API_ENDPOINT=http://127.0.0.1:8891 # 在指定端口 8502 启动 WebUI python -m streamlit run ui/webapp_question_answering.py --server.port 8502Linux 用户推荐采用 Shell 脚本启动:
sh examples/question-answering/run_qa_web.sh(run_qa_web.sh内部会unset http_proxy && unset https_proxy,设置API_ENDPOINT=http://127.0.0.1:8891后以 8502 端口启动 WebUI,见 run_qa_web.sh。)
WebUI 前端(webapp_question_answering.py)支持通过环境变量定制默认问题、答案、召回与重排数量:DEFAULT_QUESTION_AT_STARTUP(默认"中国的首都在哪里?")、DEFAULT_ANSWER_AT_STARTUP(默认"北京")、DEFAULT_DOCS_FROM_RETRIEVER(默认 50)、DEFAULT_DOCS_FROM_RANKER(默认 1)、DEFAULT_NUMBER_OF_ANSWERS(默认 1)。
到这里,打开浏览器访问http://127.0.0.1:8502即可体验城市百科知识问答系统服务。
6.5 数据更新
数据更新有两种方式:
- 命令行更新:继续使用
utils/offline_ann.py对新的文档目录建库(配合--delete_index可先清空旧索引)。 - 前端界面上传:WebUI 支持上传 txt、pdf、image、word 格式文件并自动建索引。以 txt 为例,每段文本需要使用空行隔开,程序会根据空行进行分段建立索引。示例数据(demo.txt)格式如下:
兴证策略认为,最恐慌的时候已经过去,未来一个月市场迎来阶段性修复窗口。 从海外市场表现看, 对俄乌冲突的恐慌情绪已显著释放, 海外权益市场也从单边下跌转入双向波动。 长期,继续聚焦科技创新的五大方向。1)新能源(新能源汽车、光伏、风电、特高压等),2)新一代信息通信技术(人工智能、大数据、云计算、5G等),3)高端制造(智能数控机床、机器人、先进轨交装备等),4)生物医药(创新药、CXO、医疗器械和诊断设备等),5)军工(导弹设备、军工电子元器件、空间站、航天飞机等)。前端上传建索引的流程由dense_qa.yaml中的indexing流水线驱动:文件先经FileTypeClassifier按类型分派给对应的文件转换器,再经PreProcessor切分,最后由Retriever计算向量并写入DocumentStore。
7. 预置模型一览与自定义模型接入
7.1 预置模型
Pipelines 的预置模型详细介绍见 API.md,要点如下:
- DensePassageRetriever(双塔检索模型):中文侧提供
rocketqa-zh-base-query-encoder(12 层、768 hidden、118M 参数)、rocketqa-zh-medium-query-encoder(6 层、768 hidden、75M)、rocketqa-zh-mini-query-encoder(6 层、384 hidden、27M)、rocketqa-zh-micro-query-encoder(4 层、384 hidden、23M)、rocketqa-zh-nano-query-encoder(4 层、312 hidden、18M),均基于 DuReader retrieval 文本训练;英文侧提供rocketqav2-en-marco-query-encoder、ernie-search-base-dual-encoder-marco-en(基于 MSMARCO 训练)。 - ErnieRanker(Cross-Encoder 排序模型):中文侧为
rocketqa-base/medium/mini/micro/nano-cross-encoder系列,英文侧为rocketqav2-en-marco-cross-encoder、ernie-search-large-cross-encoder-marco-en。 - ErnieReader(抽取式阅读理解模型):预置
ernie-gram-zh-finetuned-dureader-robust(12 层、768 hidden、118M 参数,基于 DuReader Robust 文本训练)。
7.2 训练并接入自定义模型
- 召回与排序模型训练:可参考 neural_search 应用目录(
slm/applications/neural_search下的recall/与ranking/子目录)中的训练流程;召回和排序模型的接入流程与语义检索(Neural Search)的接入流程一致。 - 答案抽取模型训练:参考 machine_reading_comprehension/DuReader-robust 示例(
slm/examples/machine_reading_comprehension/DuReader-robust)中的训练教程。 - 接入方式:召回与排序模型在
dense_qa.yaml(或DensePassageRetriever/ErnieRanker构造参数)中把模型名称替换为自己的模型即可;阅读理解模型只需在加载模型(ErnieReader的model_name_or_path)时,把模型名称换成您训练好的模型路径即可。DensePassageRetriever也支持传入本地模型目录(query_embedding_model="model_directory/question-encoder")以及通过params_path指定 checkpoint。
8. FAQ 与常见问题排查
安装或运行过程中遇到问题,可查阅 FAQ.md,以下是常见问题摘要:
Windows 下 pip 安装
htbuilder报UnicodeDecodeError: 'gbk' codec can't decode byte...:是 Windows 默认 gbk 编码导致,可通过源码安装(git clone后python setup install)解决。终端输出乱码:设置操作系统默认编码为中文 UTF-8:
export LANG=zh_CN.UTF-8Linux 上以 root 启动 elasticsearch 报
can not run elasticsearch as root:ES 需在非 root 环境下运行,可新建用户并授权:adduser est chown est:est -R ${HOME}/elasticsearch-8.3.2/ cd ${HOME}/elasticsearch-8.3.2/ su est ./bin/elasticsearch
9. 参考资料与致谢
本文内容围绕以下基础研究工作展开:ERNIE 3.0 大规模知识增强预训练模型(用于语言理解与生成)、RocketQA 开放域稠密检索问答训练方法(用于召回与排序模型)、以及 DuReader_robust 中文机器阅读理解数据集(用于鲁棒性评估与阅读模型微调)。
在框架设计上,本项目借鉴了 Deepset.ai Haystack 优秀的框架设计(如组件化流水线、文档存储抽象等),在此对 Haystack 作者及其开源社区表示感谢。
- 人工智能
- 大模型
- 预训练
- 微调
- LoRA
- RLHF
- 强化学习
- 分布式训练
【免费下载链接】PaddleNLP
Easy-to-use and powerful LLM and SLM library with awesome model zoo.
相关推荐
Windows 环境下使用 PaddleNLP Pipelines 搭建端到端城市百科智能问答系统
Windows 环境下使用 PaddleNLP Pipelines 搭建端到端城市百科智能问答系统 本文基于 PaddleNLP 仓库中 Windows 安装指
人工智能大模型预训练微调LoRARLHF强化学习分布式训练模型推理服务推理引擎模型量化模型压缩本地部署NLP如何用免费开源工具NoFences彻底告别杂乱Windows桌面:3分钟创建你的专属数字工作区
如何用免费开源工具NoFences彻底告别杂乱Windows桌面:3分钟创建你的专属数字工作区 还在为Windows桌面上堆积如山的图标感到头疼吗?每次找文件都
人工智能大模型预训练微调LoRARLHF强化学习分布式训练模型推理服务推理引擎模型量化模型压缩本地部署NLPPaddleNLP Pipelines 语义检索(Neural Search)系统实战:从 RocketQA 召回排序到 Web 可视化端到端部署
PaddleNLP Pipelines 语义检索(Neural Search)系统实战:从 RocketQA 召回排序到 Web 可视化端到端部署 导读 本文基
人工智能大模型预训练微调LoRARLHF强化学习分布式训练模型推理服务推理引擎模型量化模型压缩本地部署NLP
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考