ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

如何用 LCEL 串联 prompt、模型与 JsonOutputFunctionsParser 实现结构化标记与提取

如何用 LCEL 串联 prompt、模型与 JsonOutputFunctionsParser 实现结构化标记与提取 如何用 LCEL 串联 prompt、模型与 JsonOutputFunctionsParser 实现结构化标记与提取【免费下载链接】llm-cookbook面向开发者的 LLM 入门教程吴恩达大模型系列课程中文版项目地址: https://gitcode.com/GitHub_Trending/ll/llm-cookbook当你让大模型给一段文本打情感标签或从一句话里提取几个人名时模型默认返回的是AIMessage——真正的结构化参数藏在additional_kwargs.function_call.arguments里是一段 JSON 字符串不能直接当数据用。llm-cookbook 项目吴恩达大模型系列课程中文版选修课程《Functions、Tools 和 Agents with LangChain》的 5. 标记和提取 Tagging and Extraction.ipynb 解决的就是这个问题用 LCEL 管道语法把ChatPromptTemplate提示、绑定了函数描述的ChatOpenAI模型和JsonOutputFunctionsParser输出解析器串成一条链invoke之后直接得到可用的 dict。本文按该 notebook 逐步完成结构化标记Tagging与结构化提取Extraction两条链。准备条件安装依赖与配置 API Key先安装依赖。本课程 LCEL 章节 3. LangChain表达式语言 LCEL.ipynb 开头给出了这四条安装命令其中openai固定为0.28pip install langchain pip install openai0.28 pip install langchain[docarray] pip install tiktoken再按 设置OpenAI_API_KEY.ipynb 配置 API Key安装python-dotenv和openai在 notebook 所在目录创建.env文件写入下行内容并把your_api_key替换为你自己的 API KeyOPENAI_API_KEYyour_api_key代码中加载环境变量并赋给 openaiimport os import openai from dotenv import load_dotenv, find_dotenv _ load_dotenv(find_dotenv()) openai.api_key os.environ[OPENAI_API_KEY]第一步用 Pydantic 类定义函数描述notebook 中结构化输出先被定义成继承 PydanticBaseModel的类因此具备严格的数据类型校验功能。标记场景定义两个字段sentiment情感标签正面/负面/中立和language语言采用 ISO 639-1 代码from typing import List from pydantic import BaseModel, Field from langchain.utils.openai_functions import convert_pydantic_to_openai_function class Tagging(BaseModel): 用特定信息标记这段文本。 # 文本的情绪标签可选值为pos正面、neg负面或neutral中立 sentiment: str Field(description文本的情绪请从“正面”、“负面”或“中立”中选择) # 文本的语言标签应为ISO 639-1标准代码 language: str Field(description文本语言(应采用ISO 639-1代码))convert_pydantic_to_openai_function(Tagging)把类转换成 OpenAI 能识别的函数描述对象notebook 记录的文档示例输出为{name: Tagging, description: 用特定信息标记这段文本。, parameters: {title: Tagging, description: 用特定信息标记这段文本。, type: object, properties: {sentiment: {title: Sentiment, description: 文本的情绪请从“正面”、“负面”或“中立”中选择, type: string}, language: {title: Language, description: 文本语言(应采用ISO 639-1代码), type: string}}, required: [sentiment, language]}}注意name就是类名后面function_call要引用它。更一般的提取场景定义两个嵌套类Personname必填age可选和Information一个Person列表from typing import Optional class Person(BaseModel): 个人信息 name: str Field(description人的名字) # 人的名字 age: Optional[int] Field(description人的年龄) # 人的年龄可选字段 class Information(BaseModel): 要提取的信息 people: List[Person] Field(description关于人的信息列表) # 关于人的信息列表第二步用 bind 把函数描述绑定到模型创建温度为 0 的ChatOpenAI模型把转换后的函数放进列表用bind绑定到模型上function_call指定函数调用的名称让模型按这个函数描述返回参数from langchain.prompts import ChatPromptTemplate from langchain.chat_models import ChatOpenAI # 创建一个温度为0的ChatOpenAI模型实例 model ChatOpenAI(temperature0) # 应用 Tagging tagging_functions [convert_pydantic_to_openai_function(Tagging)] # 将模型与函数绑定并指定函数调用的名称 model_with_functions model.bind( functionstagging_functions, function_call{name: Tagging} )同时创建 prompt。system消息约束模型行为{input}占位符等待调用时传入的文本# 使用ChatPromptTemplate的from_messages方法创建聊天提示模板 prompt ChatPromptTemplate.from_messages([ (system, 仔细思考然后按指示标记文本), (user, {input}) ])第三步只串 prompt 和模型先看原始输出用 LCEL 管道语法先把链建起来还不接解析器# 创建一个标签链结合提示模板和模型 tagging_chain prompt | model_with_functions # 调用标签链并传入输入文本 tagging_chain.invoke({input: 我爱langchain})notebook 记录的文档示例输出AIMessage(content, additional_kwargs{function_call: {name: Tagging, arguments: {\n sentiment: 正面,\n language: zh\n}}}, exampleFalse)这就是标题里要解决的问题content是空的结构化结果以 JSON 字符串的形式放在arguments里没法直接取出sentiment字段。换一条输入我想要问的不是这些问题再调用输出仍是同样格式的AIMessage文档示例中 sentiment 为中立。要拿到可用的 dict需要在管道末端挂上解析器。第四步挂上 JsonOutputFunctionsParser直接拿到 dictJsonOutputFunctionsParser位于langchain.output_parsers.openai_functions模块把它接进管道即可# 从langchain.output_parsers.openai_functions模块导入JsonOutputFunctionsParser from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser # 创建一个新的标签链结合提示模板、模型和JsonOutputFunctionsParser解析器 tagging_chain prompt | model_with_functions | JsonOutputFunctionsParser() # 调用标签链并传入输入文本 tagging_chain.invoke({input: 我爱langchain})notebook 记录的文档示例输出直接就是 dict{sentiment: 正面, language: zh}第五步用同一条管道做多条信息的 Extractionnotebook 对两种任务的说法是提取Extraction类似于标记Tagging但用于提取多条信息当给定一个输入 JSON 模式时LLM 会查找并填充该模式的参数而且该能力并不局限于 function 模式可以用于一般用途的提取。组链方式与标记完全一致bind、管道、解析。# 创建提取功能列表并将提取功能绑定到模型上 extraction_functions [convert_pydantic_to_openai_function(Information)] extraction_model model.bind(functionsextraction_functions, function_call{name: Information}) # 使用ChatPromptTemplate创建提示模板 prompt ChatPromptTemplate.from_messages([ (system, 提取相关信息如果没有明确提供不要猜测。可以提取部分信息), (human, {input}) ]) # 创建提取链结合提示模板和提取模型 extraction_chain prompt | extraction_model不接解析器时extraction_chain.invoke({input: 乔30岁他妈妈叫玛莎})的文档示例同样是AIMessagearguments为people列表的 JSON 字符串。挂上JsonOutputFunctionsParser()extraction_chain prompt | extraction_model | JsonOutputFunctionsParser() extraction_chain.invoke({input: 乔30岁他妈妈叫玛莎})文档示例输出{people: [{name: 乔, age: 30}, {name: 玛莎}]}玛莎的年龄没有出现在文本中所以没有被填上——这正是 system 提示如果没有明确提供不要猜测。可以提取部分信息的效果也对应age字段声明为Optional[int]。如果连外层的people键都不想要、直接要列表改用JsonKeyOutputFunctionsParser并指定键名from langchain.output_parsers.openai_functions import JsonKeyOutputFunctionsParser # 创建提取链指定关键字name来解析输出 extraction_chain prompt | extraction_model | JsonKeyOutputFunctionsParser(key_namepeople) extraction_chain.invoke({input: 乔30岁他妈妈叫玛莎})文档示例输出[{name: 乔, age: 30}, {name: 玛莎}]结果验证如何判断链按预期工作notebook 记录了每个阶段的输出运行后可以逐层对照这些文档示例判断链是否接对阶段文档示例输出形态prompt \| model_with_functions未接解析器AIMessagecontent为空additional_kwargs.function_call中含name与 JSON 字符串argumentsprompt \| model \| JsonOutputFunctionsParser()dict键与 Pydantic 字段一致如{sentiment: 正面, language: zh}prompt \| model \| JsonKeyOutputFunctionsParser(key_namepeople)直接是列表如[{name: 乔, age: 30}, {name: 玛莎}]另外notebook 用不相关输入hi调用提取链文档示例输出是空列表[]——即文本中没有可提取信息时返回空列表而不是编造内容。如果你的运行输出是上面表格的形态dict 键、列表元素与示例一致即可认为这条 LCEL 链按预期工作。结果出现不该提取的内容时改 system 提示的显式约束notebook 的应用案例演示了一次真实迭代。加载一篇长文章后论文提取链第一次运行只返回了文章本身的标题文档示例[{title: LLM Powered Autonomous Agents, author: Lilian Weng}]。notebook 的处理方式是把提示中的约束写得更明确——不要提取文章本身的名称、没有提到论文就返回空列表、不要编造或猜测任何额外信息template_chinese 一篇文章将转交给你。把这篇文章中提到的所有论文都摘录出来。 不要提取文章本身的名称。如果没有提到论文那很好——你不需要提取任何论文!只返回一个空列表。 不要编造或猜测任何额外的信息。只提取文本中的内容。 # 使用定制化提示模板创建聊天提示 prompt ChatPromptTemplate.from_messages([ (system, template_chinese), (human, {input}) ]) # 重新创建提取链 extraction_chain prompt | extraction_model | JsonKeyOutputFunctionsParser(key_namepapers)再次调用后文档示例返回了文章提到的多篇论文如ReAct (Yao et al. 2023)、Reflexion (Shinn Labash 2023)等 7 条。也就是说当结果混入不该提取的条目时notebook 给出的路径是修改 system 消息中的显式约束而不动管道结构。可选分支把同一条链用于长文章notebook 的应用案例一节把同样的链应用到一篇博客文章步骤为# 使用WebBaseLoader加载文档 from langchain.document_loaders import WebBaseLoader loader WebBaseLoader(https://lilianweng.github.io/posts/2023-06-23-agent/) documents loader.load() # 获取第一个文档 doc documents[0] # 获取页面内容的前10000个字符 page_content doc.page_content[:10000]该 URL 是 notebook 使用的地址需要网络可达。加载之后有两个用法提取文章概览。定义Overview类summary总结、language语言、keywords关键词绑定function_call{name: Overview}后组链prompt | tagging_model | JsonOutputFunctionsParser()文档示例输出为包含该文章 summary、language 与 keywords 的 dict。分块提取。用RecursiveCharacterTextSplitter(chunk_overlap0)切分全文文档示例将该文章切为 14 块用RunnableLambda把每块包装成{input: ...}后逐块过提取链最后把各块结果的列表扁平化from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.schema.runnable import RunnableLambda text_splitter RecursiveCharacterTextSplitter(chunk_overlap0) prep RunnableLambda( lambda x: [{input: doc} for doc in text_splitter.split_text(x)] ) def flatten(matrix): flat_list [] for row in matrix: flat_list row return flat_list # 多个短文本分别使用extraction_chain进行提取将结果的list通过flatten函数扁平化到一起 chain prep | extraction_chain.map() | flattenchain.invoke(doc.page_content)的文档示例输出是一个很长的{title: ..., author: ...}dict 列表覆盖文章提到的多篇论文。这一分支依赖前面分节的prompt与extraction_model复用即可。限制与下一步各示例中function_call的名称都用 Pydantic 类名Tagging、Information、Info、Overview与convert_pydantic_to_openai_function生成的函数描述中name一致文档示例中name: Tagging。LCEL 章节 notebook 的运行输出中带有弃用警告ChatOpenAI在 langchain-community 0.0.10 中被标记为 deprecated将在 0.2.0 中移除警告建议改用 langchain-openai 包pip install -U langchain-openai导入方式from langchain_openai import ChatOpenAI。本文代码保持课程 notebook 的原始导入写法。除invoke外LCEL 链还提供batch输入列表中并行调用与stream流式返回接口以及对应的异步方法ainvoke、abatch、astream见 LCEL 章节接口 Interface一节可用于批量标记多条文本或低延迟输出场景。【免费下载链接】llm-cookbook面向开发者的 LLM 入门教程吴恩达大模型系列课程中文版项目地址: https://gitcode.com/GitHub_Trending/ll/llm-cookbook创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表