原文towardsdatascience.com/the-lesser-known-rising-application-of-llms-775834116477?sourcecollection_archive---------3-----------------------#2024-05-13https://medium.com/vianney.mixtur_39698?sourcepost_page---byline--775834116477--------------------------------https://towardsdatascience.com/?sourcepost_page---byline--775834116477-------------------------------- Vianney Mixtur·发表于Towards Data Science ·8 分钟阅读·2024 年 5 月 13 日–概述大语言模型LLMs通常被称为生成型人工智能GenAI因为它们确实具有生成文本的能力。LLM 的第一个流行应用是聊天机器人其中 ChatGPT 走在前列。随后我们将其应用范围扩展到其他任务如语义搜索和检索增强生成RAG。今天我想谈谈 LLM 的一个崛起应用即结构化无结构数据我将通过将原始文本结构化为 JSON 数据来展示一个例子。使用 LLM大语言模型进行数据结构化和提取是一个非常有前景的应用具有很大的潜力。以下是原因提高准确性LLM 能够理解人类语言的细微差别。这使得它们能够比传统的基于规则的系统更准确地从杂乱、无结构的文本中识别关键信息。自动化潜力从无结构数据中提取信息可能是一项耗时且劳动密集的任务。LLM 可以自动化这个过程从而释放人力资源用于其他任务并加速对更大数据集的分析。适应性和学习能力LLM 则可以持续进行微调并适应处理新的数据源和信息类型。随着它们接触到更多的无结构数据它们能够学习并提高识别模式和提取相关信息的能力。业务成果大量宝贵信息存在于诸如电子邮件、客户评论、社交媒体对话和内部文档等非结构化文本数据源中。然而这些数据通常难以分析。大语言模型LLM可以通过将非结构化数据转换为结构化格式解锁这些隐藏的潜力。这使得企业能够利用强大的分析工具来识别趋势并获取洞察。实质上通过使用 LLM 将非结构化数据进行结构化企业可以将一种负担不可用的数据转变为一种资产有价值的洞察从而推动更好的决策并提升整体业务成果。一个例子最近我在为个人项目寻找开源食谱数据集时除了这个 GitHub 仓库外什么也没找到该仓库包含了在publicdomainrecipes.com上显示的食谱。https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/04ad1e467b2d1359d7502b35c19f079e.png照片由Jeff Sheldon拍摄来自Unsplash不幸的是我需要一个更具可操作性的数据集即更接近表格数据或NoSQL 文档的东西。这就是我开始考虑找到一种方法将原始数据转换成更适合我需求的东西而不需要花费数小时、数天甚至数周手动完成的原因。让我展示一下我如何利用大语言模型的强大能力来自动化将原始文本转换为结构化文档的过程。数据集原始数据集是一个 markdown 文件的集合每个文件代表一个食谱。一个描述如何制作法式可丽饼的食谱的 markdown 文件示例。如你所见这并非完全无结构文件顶部有一些漂亮的表格元数据接下来有 4 个不同的部分一个介绍食材列表步骤一些提示。基于这个观察Sebastian Bahr开发了一个解析器将 markdown 文件转换为 JSON 格式在这里。解析器的输出已经变得更具可操作性此外Sebastian 利用它构建了一个食谱推荐聊天机器人。然而仍然存在一些缺点。食材和步骤的键包含了原始文本这些文本可以做得更有结构。按原样某些有用的信息被隐藏了。例如食材的数量每个步骤的准备或烹饪时间。代码在本文的剩余部分我将展示我采取的步骤以便得到像下面这样的 JSON 文档。{name:Crêpes,serving_size:4,ingredients:[{id:1,name:white flour,quantity:300.0,unit:g},{id:2,name:eggs,quantity:3.0,unit:unit},{id:3,name:milk,quantity:60.0,unit:cl},{id:4,name:beer,quantity:20.0,unit:cl},{id:5,name:butter,quantity:30.0,unit:g}],steps:[{number:1,description:Mix flour, eggs, and melted butter in a bowl.,preparation_time:null,cooking_time:null,used_ingredients:[1,2,5]},{number:2,description:Slowly add milk and beer until the dough becomes fluid enough.,preparation_time:5,cooking_time:null,used_ingredients:[3,4]},{number:3,description:Let the dough rest for one hour.,preparation_time:60,cooking_time:null,used_ingredients:[]},{number:4,description:Cook the crêpe in a flat pan, one ladle at a time.,preparation_time:10,cooking_time:null,used_ingredients:[]}]}复现教程的代码在 GitHub这里。我依赖了两个强大的库——用于与 LLM 提供商通信的[langchain](https://www.langchain.com/)以及用于格式化 LLM 输出的[pydantic](https://docs.pydantic.dev/latest/)。首先我定义了食谱的两个主要组成部分——Ingredient类和Step类。在每个类中我定义了相关的属性并提供了字段描述和示例。然后这些内容通过langchain传递给 LLM从而获得更好的结果。schemas.pyfrompydanticimportBaseModel,Field,field_validatorclassIngredient(BaseModel):Ingredient schemaid:intField(descriptionRandomly generated unique identifier of the ingredient,examples[1,2,3,4,5,6],)name:strField(descriptionThe name of the ingredient,examples[flour,sugar,salt])quantity:float|NoneField(None,descriptionThe quantity of the ingredient,examples[200,4,0.5,1,1,1],)unit:str|NoneField(None,descriptionThe unit in which the quantity is specified,examples[ml,unit,l,unit,teaspoon,tablespoon],)field_validator(quantity,modebefore)defparse_quantity(cls,value:float|int|str|None):Converts the quantity to a float if it is not already oneifisinstance(value,str):try:valuefloat(value)exceptValueError:try:valueeval(value)exceptExceptionase:print(e)passreturnvalueclassStep(BaseModel):number:int|NoneField(None,descriptionThe position of the step in the recipe,examples[1,2,3,4,5,6],)description:strField(descriptionThe action that needs to be performed during that step,examples[Preheat the oven to 180°C,Mix the flour and sugar in a bowl,Add the eggs and mix well,Pour the batter into a greased cake tin,Bake for 30 minutes,Let the cake cool down before serving,],)preparation_time:int|NoneField(None,descriptionThe preparation time mentioned in the step description if any.,examples[5,10,15,20,25,30],)cooking_time:int|NoneField(None,descriptionThe cooking time mentioned in the step description if any.,examples[5,10,15,20,25,30],)used_ingredients:list[int]Field([],descriptionThe list of ingredient ids used in the step,examples[[1,2],[3,4],[5,6],[7,8],[9,10],[11,12]],)classRecipe(BaseModel):Recipe schemaname:strField(descriptionThe name of the recipe,examples[Chocolate Cake,Apple Pie,Pasta Carbonara,Pumpkin Soup,Chili con Carne,],)serving_size:int|NoneField(None,descriptionThe number of servings the recipe makes,examples[1,2,4,6,8,10],)ingredients:list[Ingredient][]steps:list[Step][]total_preparation_time:int|NoneField(None,descriptionThe total preparation time for the recipe,examples[5,10,15,20,25,30],)total_cooking_time:int|NoneField(None,descriptionThe total cooking time for the recipe,examples[5,10,15,20,25,30],)comments:list[str][]技术细节这里需要注意不要使用过于严格的模型否则 LLM 输出的 JSON 会失败 Pydantic 验证。一个好的方法是提供一些灵活性比如根据目标输出类型提供默认值如None或空列表[]。注意Ingredient类中quantity属性上的field_validator它帮助引擎解析数量。最初没有这个但通过一些实验我发现 LLM 经常将数量作为字符串提供例如1/3或1/2。used_ingredients用于正式地将食材与食谱的相关步骤联系起来。输出模型一旦定义后续过程就相对顺利。在prompt.py文件中我定义了一个create_prompt函数用于轻松生成提示语。每个食谱都会生成一个“新”的提示语。所有提示语有相同的基础但食谱本身作为变量传递给基础提示语以创建一个新的提示。 prompt.py The import statements and the create_prompt function have not been included in this snippet. # Note : Extra spaces have been included here for readability.DEFAULT_BASE_PROMPT What are the ingredients and their associated quantities as well as the steps to make the recipe described by the following {ingredients} and {steps} provided as raw text ? In particular, please provide the following information: - The name of the recipe - The serving size - The ingredients and their associated quantities - The steps to make the recipe and in particular, the duration of each step - The total duration of the recipe broken down into preparation, cooking and waiting time. The totals must be consistent with the sum of the durations of the steps. - Any additional comments {format_instructions} Make sure to provide a valid and well-formatted JSON. 与 LLM 逻辑的通信是在core.py文件的run函数中定义的我这里为了简洁没有展示。最后我将所有这些组件结合在我的demo.ipynb笔记本中以下是其内容。# demo.ipynbimportosfrompathlibimportPathimportpandasaspdfromlangchain.output_parsersimportPydanticOutputParserfromlangchain_mistralai.chat_modelsimportChatMistralAIfromdotenvimportload_dotenvfromcoreimportrunfrompromptimportDEFAULT_BASE_PROMPT,create_promptfromschemasimportRecipe# End of first cell# Setup environmentload_dotenv()MISTRAL_API_KEYos.getenv(MISTRAL_API_KEY)#1# End of second cell# Load the datapath_to_dataPath(os.getcwd())/data/input#2dfpd.read_json(data/input/recipes_v1.json)df.head()# End of third cell# Preparing the components of the systemllmChatMistralAI(api_keyMISTRAL_API_KEY,model_nameopen-mixtral-8x7b)parserPydanticOutputParser(pydantic_objectRecipe)promptcreate_prompt(DEFAULT_BASE_PROMPT,parser,df[ingredients][0],df[direction][0])#prompt# End of fourth cell# Combining the componentsexampleawaitrun(llm,prompt,parser)#example# End of fifth cell我使用了MistralAI作为 LLM 提供商采用他们的open-mixtral-8x7b模型这是一个非常好的开源替代方案相较于OpenAI。langchain让你可以轻松切换提供商只要你在提供商平台上创建了账户。如果你试图复现这些结果(#1) — 确保你在.env文件中或在操作系统环境中有MISTRAL_API_KEY。(#2) — 请小心数据的路径。如果你克隆了我的仓库这将不是问题。在整个数据集上运行代码的费用不到 2€。通过此代码生成的结构化数据集可以在我的仓库中这里找到。我对结果很满意但仍然可以尝试对提示语、字段描述或所使用的模型进行迭代以进一步改进它们。我可能会尝试 MistralAI 的最新模型open-mixtral-8x22b或者通过简单地修改 2 到 3 行代码借助langchain尝试另一个 LLM 提供商。当我准备好时我可以回到我的原始项目。如果你想知道它是什么敬请关注。同时如果你有任何想法欢迎在评论中告诉我你会如何利用最终的数据集结论大型语言模型LLMs为结构化非结构化数据提供了强大的工具。它们理解和解释人类语言细微差别的能力、自动化繁琐任务的能力以及适应不断变化的数据的能力使它们成为数据分析中无价的资源。通过发掘非结构化文本数据中的潜在价值企业可以将这些数据转化为有价值的洞察推动更好的决策和商业成果。提供的例子——将原始食谱数据转化为结构化格式——只是 LLMs 所能提供的无数可能性中的一个。随着我们继续探索和开发这些模型未来我们可以预见到更多创新应用的出现。充分发挥 LLMs 潜力的旅程才刚刚开始未来的道路充满了激动人心的前景。