Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何在langchain中对大模型的输出进行格式化

如何在langchain中对大模型的输出进行格式化

原创
作者头像
程序那些事
发布于 2023-11-27 01:41:55
发布于 2023-11-27 01:41:55
2.1K00
代码可运行
举报
文章被收录于专栏:程序那些事程序那些事
运行总次数:0
代码可运行

简介

我们知道在大语言模型中, 不管模型的能力有多强大,他的输入和输出基本上都是文本格式的,文本格式的输入输出虽然对人来说非常的友好,但是如果我们想要进行一些结构化处理的话还是会有一点点的不方便。

不用担心,langchain已经为我们想到了这个问题,并且提出了完满的解决方案。

langchain中的output parsers

langchain中所有的output parsers都是继承自BaseOutputParser。这个基础类提供了对LLM大模型输出的格式化方法,是一个优秀的工具类。

我们先来看下他的实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class BaseOutputParser(BaseModel, ABC, Generic[T]):

    @abstractmethod
    def parse(self, text: str) -> T:
        """Parse the output of an LLM call.

        A method which takes in a string (assumed output of a language model )
        and parses it into some structure.

        Args:
            text: output of language model

        Returns:
            structured output
        """

    def parse_with_prompt(self, completion: str, prompt: PromptValue) -> Any:
        """Optional method to parse the output of an LLM call with a prompt.

        The prompt is largely provided in the event the OutputParser wants
        to retry or fix the output in some way, and needs information from
        the prompt to do so.

        Args:
            completion: output of language model
            prompt: prompt value

        Returns:
            structured output
        """
        return self.parse(completion)

    def get_format_instructions(self) -> str:
        """Instructions on how the LLM output should be formatted."""
        raise NotImplementedError

    @property
    def _type(self) -> str:
        """Return the type key."""
        raise NotImplementedError(
            f"_type property is not implemented in class {self.__class__.__name__}."
            " This is required for serialization."
        )

    def dict(self, **kwargs: Any) -> Dict:
        """Return dictionary representation of output parser."""
        output_parser_dict = super().dict()
        output_parser_dict["_type"] = self._type
        return output_parser_dict

BaseOutputParser 是一个基础的类,可能被其他特定的输出解析器继承,以实现特定语言模型的输出解析。

这个类使用了Python的ABC模块,表明它是一个抽象基类(Abstract Base Class),不能被直接实例化,而是需要子类继承并实现抽象方法。

Generic[T] 表示这个类是一个泛型类,其中T 是一个类型变量,它表示解析后的输出数据的类型。

@abstractmethod 装饰器标记了 parse 方法,说明它是一个抽象方法,必须在子类中实现。parse 方法接受一个字符串参数 text,通常是语言模型的输出文本,然后将其解析成特定的数据结构,并返回。

parse_with_prompt 方法也是一个抽象方法,接受两个参数,completion 是语言模型的输出,prompt 是与输出相关的提示信息。这个方法是可选的,可以用于在需要时解析输出,可能根据提示信息来调整输出。

get_format_instructions 方法返回关于如何格式化语言模型输出的说明。这个方法可以用于提供解析后数据的格式化信息。

_type 是一个属性,可能用于标识这个解析器的类型,用于后续的序列化或其他操作。

dict 方法返回一个包含输出解析器信息的字典,这个字典可以用于序列化或其他操作。

其中子类必须要实现的方法就是parse。其他的都做为辅助作用。

langchain中有哪些Output Parser

那么langchain中有哪些Output Parser的具体实现呢?具体对应我们应用中的什么场景呢?

接下来我们将会一一道来。

List parser

ListOutputParser的作用就是把LLM的输出转成一个list。ListOutputParser也是一个基类,我们具体使用的是他的子类:CommaSeparatedListOutputParser。

看一下他的parse方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    def parse(self, text: str) -> List[str]:
        """Parse the output of an LLM call."""
        return text.strip().split(", ")

还有一个get_format_instructions:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    def get_format_instructions(self) -> str:
        return (
            "Your response should be a list of comma separated values, "
            "eg: `foo, bar, baz`"
        )

get_format_instructions是告诉LLM以什么样的格式进行数据的返回。

就是把LLM的输出用逗号进行分割。

下面是一个基本的使用例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
output_parser = CommaSeparatedListOutputParser()

format_instructions = output_parser.get_format_instructions()
prompt = PromptTemplate(
    template="列出几种{subject}.\n{format_instructions}",
    input_variables=["subject"],
    partial_variables={"format_instructions": format_instructions}
)

_input = prompt.format(subject="水果")
output = model(_input)
print(output)
print(output_parser.parse(output))

我们可以得到下面的输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Apple, Orange, Banana, Grape, Watermelon, Strawberry, Pineapple, Peach, Mango, Cherry
['Apple', 'Orange', 'Banana', 'Grape', 'Watermelon', 'Strawberry', 'Pineapple', 'Peach', 'Mango', 'Cherry']

看到这里,大家可能有疑问了, 为什么我们问的是中文,返回的却是因为呢?

这是因为output_parser.get_format_instructions就是用英文描述的,所以LLM会自然的用英文来回答。

别急,我们可以稍微修改下运行代码,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
output_parser = CommaSeparatedListOutputParser()

format_instructions = output_parser.get_format_instructions()
prompt = PromptTemplate(
    template="列出几种{subject}.\n{format_instructions}",
    input_variables=["subject"],
    partial_variables={"format_instructions": format_instructions + "用中文回答"}
)

_input = prompt.format(subject="水果")
output = model(_input)
print(output)
print(output_parser.parse(output))

我们在format_instructions之后,提示LLM需要用中文来回答问题。这样我们就可以得到下面的结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
苹果,橘子,香蕉,,葡萄,芒果,柠檬,['苹果,橘子,香蕉,梨,葡萄,芒果,柠檬,桃']

是不是很棒?

Datetime parser

DatetimeOutputParser用来将LLM的输出进行时间的格式化。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class DatetimeOutputParser(BaseOutputParser[datetime]):
    format: str = "%Y-%m-%dT%H:%M:%S.%fZ"

    def get_format_instructions(self) -> str:
        examples = comma_list(_generate_random_datetime_strings(self.format))
        return f"""Write a datetime string that matches the 
            following pattern: "{self.format}". Examples: {examples}"""

    def parse(self, response: str) -> datetime:
        try:
            return datetime.strptime(response.strip(), self.format)
        except ValueError as e:
            raise OutputParserException(
                f"Could not parse datetime string: {response}"
            ) from e

    @property
    def _type(self) -> str:
        return "datetime"

在get_format_instructions中,他告诉LLM返回的结果是一个日期的字符串。

然后在parse方法中对这个LLM的输出进行格式化,最后返回datetime。

我们看下具体的应用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
output_parser = DatetimeOutputParser()
template = """回答下面问题:
{question}
{format_instructions}"""
prompt = PromptTemplate.from_template(
    template,
    partial_variables={"format_instructions": output_parser.get_format_instructions()},
)
chain = LLMChain(prompt=prompt, llm=model)
output = chain.run("中华人民共和国是什么时候成立的?")
print(output)
print(output_parser.parse(output))
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1949-10-01T00:00:00.000000Z
1949-10-01 00:00:00

回答的还不错,给他点个赞。

Enum parser

如果你有枚举的类型,那么可以尝试使用EnumOutputParser.

EnumOutputParser的构造函数需要传入一个Enum,我们主要看下他的两个方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @property
    def _valid_values(self) -> List[str]:
        return [e.value for e in self.enum]

    def parse(self, response: str) -> Any:
        try:
            return self.enum(response.strip())
        except ValueError:
            raise OutputParserException(
                f"Response '{response}' is not one of the "
                f"expected values: {self._valid_values}"
            )

    def get_format_instructions(self) -> str:
        return f"Select one of the following options: {', '.join(self._valid_values)}"

parse方法接收一个字符串 response,尝试将其解析为枚举类型的一个成员。如果解析成功,它会返回该枚举成员;如果解析失败,它会抛出一个 OutputParserException 异常,异常信息中包含了所有有效值的列表。

get_format_instructions告诉LLM需要从Enum的有效value中选择一个输出。这样parse才能接受到正确的输入值。

具体使用的例子可以参考前面两个parser的用法。篇幅起见,这里就不列了。

Pydantic (JSON) parser

JSON可能是我们在日常代码中最常用的数据结构了,这个数据结构很重要。

在langchain中,提供的JSON parser叫做:PydanticOutputParser。

既然要进行JSON转换,必须得先定义一个JSON的类型对象,然后告诉LLM将文本输出转换成JSON格式,最后调用parse方法把json字符串转换成JSON对象。

我们来看一个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Student(BaseModel):
    name: str = Field(description="学生的姓名")
    age: str = Field(description="学生的年龄")

student_query = "告诉我一个学生的信息"

parser = PydanticOutputParser(pydantic_object=Student)

prompt = PromptTemplate(
    template="回答下面问题.\n{format_instructions}\n{query}\n",
    input_variables=["query"],
    partial_variables={"format_instructions": parser.get_format_instructions()+"用中文回答"},
)

_input = prompt.format_prompt(query=student_query)

output = model(_input.to_string())
print(output)
print(parser.parse(output))

这里我们定义了一个Student的结构体,然后让LLM给我一个学生的信息,并用json的格式进行返回。

之后我们使用parser.parse来解析这个json,生成最后的Student信息。

我们可以得到下面的输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
示例输出:{"name": "张三", "age": "18"}
name='张三' age='18'

Structured output parser

虽然PydanticOutputParser非常强大, 但是有时候我们只是需要一些简单的结构输出,那么可以考虑StructuredOutputParser.

我们看一个具体的例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
response_schemas = [
    ResponseSchema(name="name", description="学生的姓名"),
    ResponseSchema(name="age", description="学生的年龄")
]
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)

format_instructions = output_parser.get_format_instructions()
prompt = PromptTemplate(
    template="回答下面问题.\n{format_instructions}\n{question}",
    input_variables=["question"],
    partial_variables={"format_instructions": format_instructions}
)

_input = prompt.format_prompt(question="给我一个女孩的名字?")
output = model(_input.to_string())
print(output)
print(output_parser.parse(output))

这个例子是上面的PydanticOutputParser的改写,但是更加简单。

我们可以得到下面的结果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 ` ` `json
{
	"name": "Jane",
	"age": "18"
}
 ` ` `
{'name': 'Jane', 'age': '18'}

output返回的是一个markdown格式的json字符串,然后通过output_parser.parse得到最后的json。

其他的一些parser

除了json,xml格式也是比较常用的格式,langchain中提供的XML parser叫做XMLOutputParser。

另外,如果我们在使用parser的过程中出现了格式问题,langchain还贴心的提供了一个OutputFixingParser。也就是说当第一个parser报错的时候,或者说不能解析LLM输出的时候,就会换成OutputFixingParser来尝试修正格式问题:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from langchain.output_parsers import OutputFixingParser

new_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())

new_parser.parse(misformatted)

如果错误不是因为格式引起的,那么langchain还提供了一个RetryOutputParser,来尝试重试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from langchain.output_parsers import RetryWithErrorOutputParser

retry_parser = RetryWithErrorOutputParser.from_llm(
    parser=parser, llm=OpenAI(temperature=0)
)

retry_parser.parse_with_prompt(bad_response, prompt_value)

这几个parser都非常有用,大家可以自行尝试。

总结

虽然langchain中的有些parser我们可以自行借助python语言的各种工具来实现。但是有一些parser实际上是要结合LLM一起来使用的,比如OutputFixingParser和RetryOutputParser。

所以大家还是尽可能的使用langchain提供的parser为好。毕竟轮子都给你造好了,还要啥自行车。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
LangChain+Ollama+DeepSeek AI 应用开发:LangChain 模型 IO 模块认知
Lang Chain 是在 LLM 爆发之后,最早有一定知名度的开源工具,其他生态大部分工具也都基于 Lang Chain 的架构方式,所以通过学习 Lang Chain 可以了解 大部分的 AI 应用工具,今天和小伙伴分享 Lang Chain 模块中的 模型 IO
山河已无恙
2025/03/13
6750
LangChain+Ollama+DeepSeek AI 应用开发:LangChain 模型 IO 模块认知
LangChain学习笔记——Model IO
LanChain基于为LangChain Model Application提供一下能力而设计:
windealli
2023/11/09
1.2K0
LangChain学习笔记——Model IO
【LangChain系列2】【Model I/O详解】
总结: LangChain是一个用于开发由LLM支持的应用程序的框架,通过提供标准化且丰富的模块抽象,构建LLM的输入输出规范,主要是利用其核心概念chains,可以灵活地链接整个应用开发流程。(即,其中的每个模块抽象,都是源于对大模型的深入理解和实践经验,由许多开发者提供出来的标准化流程和解决方案的抽象,再通过灵活的模块化组合,才得到了langchain)
Alice师傅的好宝宝
2025/01/03
2050
拥抱 AI 时代:LangChain 框架快速入门指南
使用 LangChain 通常需要与一个或多个模型提供商、数据存储、API等集成。对于这个例子,我们将使用OpenAI的模型API。
朝雾轻寒
2023/09/06
1.7K0
拥抱 AI 时代:LangChain 框架快速入门指南
AI大模型全栈工程师课程笔记 - LangChain
LangChain 也是面向LLM的开发框架SDK,有 python 和 js 版的 https://python.langchain.com/docs/get_started
Michael阿明
2023/12/21
1.6K0
AI大模型全栈工程师课程笔记 - LangChain
AI 大模型企业应用实战(10)-LLMs和Chat Models
来看两种不同类型的模型--LLM 和聊天模型。然后,它将介绍如何使用提示模板来格式化这些模型的输入,以及如何使用输出解析器来处理输出。
JavaEdge
2025/06/01
1140
AI大模型企业应用实战(10)-LLMs和Chat Models
聊天模型通常由 LLM 支持,但专门针对会话进行调整。提供者 API 使用与纯文本补全模型不同的接口。它们的输入不是单个字符串,而是聊天信息列表,输出则是一条人工智能信息。
JavaEdge
2024/08/15
1810
使用LangChain自定义大模型 | 完美调用第三方 API | 如OneAPI/硅基流动
安装 Python3.7.1 或更高版本并设置虚拟环境后,即可安装 OpenAI Python 库
比克AI
2024/11/20
2.2K0
使用LangChain自定义大模型 | 完美调用第三方 API | 如OneAPI/硅基流动
9个范例带你入门LangChain
前方干货预警:这可能是你心心念念想找的最好懂最具实操性的langchain教程。本文通过演示9个具有代表性的应用范例,带你零基础入门langchain。
lyhue1991
2023/09/05
7.4K0
9个范例带你入门LangChain
LLM远不仅仅是Chat Model——LangChain基本概念与使用示例
一图胜千言,LangChain已经成为当前LLM应用框架的事实标准,这篇文章就来对LangChain基本概念以及其具体使用场景做一个整理
Kevinello
2023/09/06
2.6K0
LLM远不仅仅是Chat Model——LangChain基本概念与使用示例
LangChain:打造自己的LLM应用
导读 随着LLM的技术发展,其在业务上的应用越来越关键,通过LangChain大大降低了LLM应用开发的门槛。本文通过介绍LangChain是什么,LangChain的核心组件以及LangChain在实际场景下的使用方式,希望帮助大家能快速上手LLM应用的开发。
京东技术
2023/11/05
2.1K0
LangChain:打造自己的LLM应用
轻松上手的LangChain学习说明书
如今各类AI模型层出不穷,百花齐放,大佬们开发的速度永远遥遥领先于学习者的学习速度。。为了解放生产力,不让应用层开发人员受限于各语言模型的生产部署中..LangChain横空出世界。
腾讯技术工程官方号
2024/03/22
3.4K0
轻松上手的LangChain学习说明书
LLM生态下爬虫程序的现状与未来
最近出现一批与LLM有关的新的爬虫框架,一类是为LLM提供内容抓取解析的,比如 Jina Reader 和 FireCrawl ,可以将抓取的网页解析为markdown这样的对LLM友好的内容,例如markdown,这类本质上还是传统的爬虫解决方案。还有一类是通过LLM+agent工作流方式来构建的下一代爬虫程序,比如Skyvern、 Scrapegraph-ai等。
JadePeng
2024/05/10
6690
LLM生态下爬虫程序的现状与未来
LangChain对象关系梳理
BaseModel是python中用于数据接口定义检查与设置管理的库(pydantic库)。pedantic在运行时强制执行类型提示,并在数据无效时提供友好的错误。参考:https://www.cnblogs.com/dyl0/articles/16896330.html
码之有理
2023/05/15
3K0
LangChain学习:models,prompts,parsers
learn from https://learn.deeplearning.ai/langchain/lesson/2/models,-prompts-and-parsers
Michael阿明
2023/07/21
4920
LangChain学习:models,prompts,parsers
【LangChain系列】第五节:大语言模型中的提示词,模型
本节我们将探索 LangChain 的内部工作原理,LangChain 是一个有用的 Python 库,可以简化使用 LLM 的过程。您将能够创建直观、可重用且可扩展的应用程序,这些应用程序可以改变您与 LLM 的交互方式。
Freedom123
2024/05/21
4920
软件测试/人工智能|探究 LangChain 核心模块:PromptsModelsParsers
LangChain 是一种新兴的语言处理平台,其核心模块之一即 PromptsModelsParsers。这一模块扮演着关键的角色,为 LangChain 的功能和性能提供了坚实的基础。在这篇文章中,我们将深入探讨 PromptsModelsParsers 模块的工作原理、功能和其对语言处理的重要性。
霍格沃兹测试开发Muller老师
2023/11/27
2100
AI 大模型企业应用实战(08)-LangChain用prompts模板调教LLM的输入输出
超越chatGPT:学习使用prompts模板来调教LLM的输入输出,打造自己版本的"贾维斯"
JavaEdge
2025/06/01
2280
AI 大模型企业应用实战(08)-LangChain用prompts模板调教LLM的输入输出
【LangChain系列4】【Chain模块详解】
总结: LangChain是一个用于开发由LLM支持的应用程序的框架,通过提供标准化且丰富的模块抽象,构建LLM的输入输出规范,主要是利用其核心概念chains,可以灵活地链接整个应用开发流程。(即,其中的每个模块抽象,都是源于对大模型的深入理解和实践经验,由许多开发者提供出来的标准化流程和解决方案的抽象,再通过灵活的模块化组合,才得到了langchain)
Alice师傅的好宝宝
2025/01/08
7200
【LLM】基于LLama2构建智能助理帮你阅读PDF文件
本文将演示如何利用 LLM 从 PDF 发票中提取数据。我将构建一个 FastAPI 服务器,该服务器将接受 PDF 文件并以 JSON 格式返回提取的数据。
Freedom123
2024/04/27
7960
推荐阅读
相关推荐
LangChain+Ollama+DeepSeek AI 应用开发:LangChain 模型 IO 模块认知
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验