跳至主要内容

完整的 Databricks Dolly 应用构建教程

学习使用 Databricks Dolly 大语言模型(LLM)的高级功能来构建应用。

使用 AI 探索

手动处理数据会拖慢产出并延误项目进度。因此,数据工程师和分析师总在寻找更快、更便宜的 LLM 来应对日常任务。

Dolly 是 Databricks 推出的开源 AI 模型,可帮助分析师、工程师及其他专业人士在各行各业更高效地开展工作。由于其开源,任何人都可以使用其训练代码,按需构建更优、更定制化的 LLM。

接下来,通过我们的 Databricks Dolly 教程进一步了解它。

为什么选择 Databricks Dolly?

让 Databricks Dolly 成为其他工具绝佳替代方案的,是其为不同规模企业打造定制解决方案的方法论。它将 LLM 从专属且高成本的技术,转变为每家公司都能拥有并定制的多功能工具。

来源:Databricks

Dolly 的优势

Dolly 能为您带来以下帮助:

  • 可定制:可根据您组织的需求定制 LLM,更易管理工作流。
  • 高性价比:以低成本、高效率构建定制的指令跟随模型。
  • 敏捷:助力企业优化数据工作流、自动化复杂流程,并更高效地产生洞见。
  • 可及性强:让先进 AI 更易获取、更易适配业务场景,从而提升运营效率。
  • 安全:为构建 AI 应用提供可行方案,避免常见的依赖 API 工具所引发的数据安全或合规问题。

想进一步了解大型语言模型的能力?请学习这门LLM 概念课程。

Databricks Dolly 快速上手

下面看看如何更好地将 Dolly 用于您的场景。

Databricks Dolly 功能概览

Dolly 在专门的 databricks-dolly-15k 数据集上进行微调,以解锁与更大模型(如 GPT)相似的功能。因此,您可以创建定制 LLM 来头脑风暴、生成文本,并按指令执行特定任务。

在 Databricks Dolly 上搭建环境

按照以下步骤为生成回复搭建 Databricks Dolly 环境。

如果您的机器配备 A100 GPU,可结合 transformers 库使用此模型。

步骤 1:在 Databricks 笔记本中运行以下代码,安装 transformers 和 accelerate 库:

%pip install "accelerate>=0.16.0,<1" "transformers[torch]>=4.28.1,<5" "torch>=1.13.1,<2"

步骤 2:接着从 transformers 库中导入 pipeline:

from transformers import pipeline
import torch
instruct_pipeline = pipeline(model="databricks/dolly-v2-12b", torch_dtype=torch.bfloat16, trust_remote_code=True, device_map="auto")

步骤 3:然后,您可以从该流水线生成回复:

instruct_pipeline("Explain to me the difference between nuclear fission and fusion.")

使用 Databricks Dolly LLM

Dolly 的基础操作

以下是可用 Dolly 执行的一些基础操作:

文本生成

  • 写作者与内容创作者可就任意主题生成草稿、提纲或完整稿件,从而节省写作过程中的时间与精力。
  • 企业与营销人员可创建吸引人的文案、产品描述或营销活动内容。

原始模型结果与 Dolly 微调结果的差异。[来源:Databricks]

头脑风暴

  • 创业者和业务负责人可以探索潜在的新产品、服务或商业模式。
  • 作家、艺术家和设计师可借助 Dolly 获取灵感与独特创意,推动其创意项目。
  • 您甚至可以在个人场景中进行头脑风暴,以规划活动或应对日常挑战。

原始模型结果与 Dolly 微调结果的差异。[来源:Databricks]

开放式问答

  • 学生可以就复杂主题提问并获得深入讲解。
  • 专业人士和研究人员可以请求特定主题的背景信息。

使用 Dolly 进行开放式问答的示例。[来源:Databricks]

进阶技巧

Dolly 并不限于基础操作;您还可以应用多种进阶技巧:

基于自定义数据进行微调

您可以将更大的预训练语言模型作为基础,对个性化 LLM 进行微调。这将提升其指令跟随能力,使其能够执行更契合您需求的任务。

策划特定领域的指令数据

如需让 LLM 专注某些行业,可在标准指令数据之外,补充面向目标领域(医疗、金融、工程等)的自定义提示。

通过在包含该领域术语、格式与知识的特定数据集上进行微调,模型能够提供贴合该领域语言与规范的准确、相关输出。

引入动态数据输入

您可以训练模型接入图像、视频、音频等动态输入。这样,它就能突破纯文本理解的限制,同时从多条数据流中汲取洞见并生成内容。

使用 Databricks Dolly 构建应用

原版 Dolly 提供了基础操作能力,您可以在此模型基础上进行调整,以构建如聊天机器人等应用。

创建聊天机器人

您可以分两部分使用 Databricks Dolly 来创建定制化聊天机器人。

数据准备与向量数据库创建

要创建聊天机器人,首先需要设置 Databricks 的向量数据库(Chroma),并使用 Databricks Lakehouse、Delta Lake 和 Delta Live Tables 来采集与导入数据。

首先,安装所需的库。

%pip install -U chromadb==0.3.22 langchain==0.0.164 transformers==4.29.0 accelerate==0.19.0

在 Databricks 笔记本中运行以下命令。

%run ./_resources/00-init $catalog=hive_metastore $db=dbdemos_llm

假设您正在构建一款园艺聊天机器人。

注意:如您希望亲自尝试该演示,请确保在 Databricks 笔记本中设置好 db demos。

1. 由于我们使用的是来自 dbdemos 的园艺示例数据集,使用“sh”命令提取该数据集。

%sh
#To keep it simple, we'll download and extract the dataset using standard bash commands 
#Install 7zip to extract the file
apt-get install -y p7zip-full

rm -r /tmp/gardening
mkdir -p /tmp/gardening
cd /tmp/gardening
#Download & extract the gardening archive
curl -L https://archive.org/download/stackexchange/gardening.stackexchange.com.7z -o gardening.7z
7z x gardening.7z 
#Move the dataset to our main bucket
mkdir -p /dbfs/dbdemos/product/llm/gardening/raw
cp -f Posts.xml /dbfs/dbdemos/product/llm/gardening/raw

2. 现在,您可以查看数据集信息。

%fs ls /dbdemos/product/llm/gardening/raw

清洗并准备问答:

1. 查看原始数据集。

gardening_raw_path = demo_path+"/gardening/raw"

print(f"loading raw xml dataset under {gardening_raw_path}")

raw_gardening = spark.read.format("xml").option("rowTag", "row").load(f"{gardening_raw_path}/Posts.xml")
display(raw_gardening)

2. 下方代码将 HTML 格式字符串转为文本,并使用 BeautifulSoup 解析 HTML 并抽取文本。

from bs4 import BeautifulSoup

#UDF to transform html content as text

@pandas_udf("string")
def html_to_text(html):
  return html.apply(lambda x: BeautifulSoup(x).get_text())

gardening_df =(raw_gardening
                  .filter("_Score >= 5") # keep only good answer/question
                  .filter(length("_Body") <= 1000) #remove too long questions
                  .withColumn("body", html_to_text("_Body")) 

#Convert html to text

                  .withColumnsRenamed({"_Id": "id", "_ParentId": "parent_id"})
                  .select("id", "body", "parent_id"))

# Save 'raw' content for later loading of questions

gardening_df.write.mode("overwrite").saveAsTable(f"gardening_dataset")
display(spark.table("gardening_dataset"))

3. 现在,将问题与答案配对。

gardening_df = spark.table("gardening_dataset")

# Self-join to assemble questions and answers

qa_df = gardening_df.alias("a").filter("parent_id IS NULL") \
         .join(gardening_df.alias("b"), on=[col("a.id") == col("b.parent_id")]) \
         .select("b.id", "a.body", "b.body") \
         .toDF("answer_id", "question", "answer")
        
# Prepare the training dataset: question following with the best answers.

docs_df = qa_df.select(col("answer_id"), F.concat(col("question"), F.lit("\n\n"), col("answer"))).toDF("source", "text")
display(docs_df)

将文档转换为向量表示:

from langchain.embeddings import HuggingFaceEmbeddings
 
# Download model from Hugging face

hf_embed = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")

将文档索引到 Databricks 向量数据库以提升检索效果:

dbutils.widgets.dropdown("reset_vector_database", "false", ["false", "true"], "Recompute embeddings for chromadb")
gardening_vector_db_path = demo_path+"/vector_db"
 
# Don't recompute the embeddings if they're already available

compute_embeddings = dbutils.widgets.get("reset_vector_database") == "true" or is_folder_empty(gardening_vector_db_path)
 
if compute_embeddings:
  print(f"creating folder {gardening_vector_db_path} under our blob storage (dbfs)")
  dbutils.fs.rm(gardening_vector_db_path, True)
  dbutils.fs.mkdirs(gardening_vector_db_path)

4. 现在,通过将数据集存入向量数据库来创建文档库。

from langchain.docstore.document import Document
from langchain.vectorstores import Chroma

# Import if you want to divide Chunk.
# from langchain.text_splitter import CharacterTextSplitter

all_texts = spark.table("gardening_training_dataset")
 
print(f"Saving document embeddings under /dbfs{gardening_vector_db_path}")
 
if compute_embeddings: 

  # Convert lines as langchain Documents.
  # If you want to index for shorter time periods, use the text_short field instead.

  documents = [Document(page_content=r["text"], metadata={"source": r["source"]}) for r in all_texts.collect()]
 
  # Long sentences may need to be split. But it's best to summarize as above.

  # text_splitter = CharacterTextSplitter(separator="\n", chunk_size=1000, chunk_overlap=100)

  # documents = text_splitter.split_documents(documents)
 
  # Initialize chromadb with sentence-transformers/all-mpnet-base-v2 model loaded from hugging face (hf_embed).

  db = Chroma.from_documents(collection_name="gardening_docs", documents=documents, embedding=hf_embed, persist_directory="/dbfs"+gardening_vector_db_path)
  db.similarity_search("dummy") # tickle it to persist metadata (?)
  db.persist()

这会将文档向量保存到 /dbfs/dbdemos/product/llm/vector_db

就这样——您的问答数据集已经准备就绪。

不过,完成后请重启 Python 内核以释放内存。

问答提示词工程

在此步骤中,您提出问题,系统从问答数据集中检索相似内容,然后将这些内容编排进提示词并发送给 Dolly,Dolly 生成答案并展示给用户。

操作如下:

  1. 从 Hugging Face 下载 2 个嵌入模型:
# Start here to load a previously-saved DB

from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import Chroma

if len(get_available_gpus()) == 0:

 Exception("Running dolly without GPU will be slow. We recommend you switch to a Single Node cluster with at least 1 GPU to properly run this demo.")
gardening_vector_db_path = "/dbfs"+demo_path+"/vector_db"
hf_embed = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")

db = Chroma(collection_name="gardening_docs", embedding_function=hf_embed, persist_directory=gardening_vector_db_path)

2. 现在,在问题之间执行相似度检索。

def get_similar_docs(question, similar_doc_count):
 return db.similarity_search(question, k=similar_doc_count)

# Let's test it with blackberries:

for doc in get_similar_docs("how to grow blackberry?", 2):
 print(doc.page_content)

3. 使用语言模型与提示词,通过 LangChain 构建一个能够回答问题的系统。

from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
import torch
from langchain import PromptTemplate
from langchain.llms import HuggingFacePipeline
from langchain.chains.question_answering import load_qa_chain
 
def build_qa_chain():
  torch.cuda.empty_cache()
  model_name = "databricks/dolly-v2-7b" # can use dolly-v2-3b or dolly-v2-7b for smaller models and faster inferences.
 
  # Increase max_new_tokens for a longer response
  # Other settings might give better results! Play around
  instruct_pipeline = pipeline(model=model_name, torch_dtype=torch.bfloat16, trust_remote_code=True, device_map="auto", 
                               return_full_text=True, max_new_tokens=256, top_p=0.95, top_k=50)
  # Note: if you use dolly 12B or smaller model but a GPU with less than 24GB RAM, use 8bit. This requires %pip install bitsandbytes
  # Defining our prompt content.
  # langchain will load our similar documents as {context}
  template = """Below is an instruction that describes a task. Write a response that appropriately completes the request.
 
  Instruction: 
  You are a gardener and your job is to help provide the best gardening answer. 
  Use only information in the following paragraphs to answer the question at the end. Explain the answer with reference to these paragraphs. If you don't know, say that you do not know.
 
  {context}
 
  Question: {question}
 
  Response:
  """
  prompt = PromptTemplate(input_variables=['context', 'question'], template=template)
 
  hf_pipe = HuggingFacePipeline(pipeline=instruct_pipeline)
  # Set verbose=True to see the full prompt:
  return load_qa_chain(llm=hf_pipe, chain_type="stuff", prompt=prompt, verbose=True)
# Building the chain will load Dolly and can take several minutes depending on the model size
qa_chain = build_qa_chain()

影响性能的关键设置包括:

  • “Max_new_tokens”:减小可获得更快、更精炼的输出。
  • “Num_beams”:使用束搜索时,束数越多,运行时间近似线性增长。

4. 就这样。现在可以定义一个用于简单问答的函数。

def answer_question(question):
 similar_docs = get_similar_docs(question, similar_doc_count=2)

 result = qa_chain({"input_documents": similar_docs, "question": question})
 result_html = f"<p><blockquote style=\"font-size:24\">{question}</blockquote></p>"
 result_html += f"<p><blockquote style=\"font-size:18px\">{result['output_text']}</blockquote></p>"
 result_html += "<p><hr/></p>"
 for d in result["input_documents"]:
   source_id = d.metadata["source"]
   result_html += f"<p><blockquote>{d.page_content}<br/>(Source: <a href=\"https://gardening.stackexchange.com/a/{source_id}\">{source_id}</a>)</blockquote></p>"
 displayHTML(result_html)

现在,您可以向它提出与园艺相关的问题。

answer_question("What is the best kind of soil to grow blueberries in?")

在此查看 dbdemo 的聊天机器人构建示例。

真实世界的应用场景

凭借其先进的 NLP 能力,基于 Dolly 构建的定制 LLM 可用于众多真实场景,以下是常见示例:

1. 为金融分析师自动汇总数据

Dolly 能处理大型数据集并生成精炼摘要,帮助分析师更快掌握关键洞见。

例如,一位金融研究人员需要快速了解历史股价趋势。Dolly 可以分析数据并提供清晰概览,节省宝贵时间。

2. 零售行业中的数据清洗与预处理

在零售公司,数据分析师常处理来自全国数千家门店的海量交易记录。然而,单店原始数据往往存在不一致、缺失值、重复条目及其他错误。

Dolly 能识别数据中的不一致、缺失值与潜在错误,帮助数据科学家基于清洁数据提取有意义的洞见并创建可视化。

3. 制药行业中紧跟最新研究

在制药公司,科学家需要持续跟进多学科的最新发表研究。然而,每周手动审阅数百篇论文十分耗时。

他们可以使用 Databricks Dolly LLM 来分析论文,并提取目标、方法、结果与结论等关键信息。它还能整合多页摘要,突出每篇论文中最重要的洞见。

挑战与局限

与其他前沿 LLM 技术一样,Dolly 也存在一些局限与挑战。以下是 Dolly 的三大主要缺点:

  • 可能产生幻觉或给出事实不准确的回答,因为其训练数据规模远小于 ChatGPT。
  • 针对您的需求进行微调与定制存在难度,往往需要一定的机器学习与 NLP 专业知识。
  • 在解决数学题、编程问题以及在回答中加入幽默感方面存在困难。

缓解 Dolly LLM 的不足

目前尚无被证实的技术可完全缓解 Dolly 的现有限制,但 Databricks 持续开展研究,致力于改进其现有 AI 模型。Dolly 目前已更新至第 2 版,未来几年我们可能会看到进一步的提升。

结论与后续步骤

Databricks Dolly 是可商用的开源 AI 模型。您可以利用其训练代码与数据集来创建满足自身需求的特定 LLM。

如果您已准备好在本教程基础上进阶并打磨现有技能,请从以下资源开始:

学习愉快!

常见问题

Dolly 2.0 对用户是否免费?

可以,您可以试用 Dolly 2.0 的基础操作。它以开源且可商用的许可证发布,免费使用。

Databricks Dolly LLM 是否使用从 ChatGPT 获取的数据进行训练?

不是。Databricks Dolly LLM 并非基于从 ChatGPT 获取的数据进行训练。Dolly 2.0 是在全新的人类生成指令数据集上独立微调完成的。

Dolly 与 ChatGPT 有何区别?

Dolly 是开源 AI 模型,而 ChatGPT 是闭源 AI 模型。这意味着 Dolly 的训练代码是公开的,而 ChatGPT 的则是私有的。Dolly 的训练参数规模更小(60 亿参数)而 ChatGPT 约为 1750 亿参数,因此 Dolly 的复杂度更低、潜在能力也可能较弱。

主题