AI方向“链(上&下)”之思考题 | 豆包MarsCode AI刷题

115 阅读10分钟

本文涵盖了四个关于使用 langchain的思考题。首先,通过使用 LLMChain 重构提示格式化和模型输出部分,实现了生成鲜花描述的功能。其次,进一步将 output_parser 整合到 LLMChain 中,简化了程序结构并提高了输出解析的精度。第三,选择了 TransformChain 链,通过定义转换函数和创建转换链,实现了对长文本的格式转换和裁剪,再通过 LLMChain 进行总结。最后,探讨了 verbose 参数的作用,展示了设置 verbose=Trueverbose=False 时输出结果的不同,并成功将 default_chainConversationChain 替换为 LLMChain,通过定义提示模板解决了模型调用的问题。这些改进和实践展示了 langchain 库在不同应用场景中的灵活性和强大功能。

一、链上思考题一

题目:

  1. 在第四课中(其实是第三课02_ModelIO_LoopCall.py),我们曾经用提示模板生成过一段鲜花的描述,代码如下:
for flower, price in zip(flowers, prices):
    # 根据提示准备模型的输入
    input = prompt.format(flower_name=flower, price=price)
    # 获取模型的输出
    output = model(input)    
    # 解析模型的输出
    parsed_output = output_parser.parse(output)

请你使用LLMChain重构提示的format和获取模型输出部分,完成相同的功能。提示:

    llm_chain = LLMChain(
        llm=model,
        prompt=prompt)

解答: 之前程序和现在程序最大的区别是:

(1)之前的程序(第三课02_ModelIO_LoopCall.py)使用的是model.invoke(input_prompt)。

  • 使用 model.invoke(input_prompt) 直接调用模型。
  • 手动格式化提示模板并传递给模型。
  • 输出解析需要手动处理。

(2)现在我们使用了model(llm=llm, prompt=prompt)。

  • 使用 LLMChain 统一管理提示模板和模型调用。
  • 自动处理提示模板的格式化。
  • 输出解析更为精细,假设输出是一个字典,包含 "text" 键。
# 设置OpenAI API密钥
import os

# 导入所需的库
from langchain import PromptTemplate, LLMChain
from langchain_openai import ChatOpenAI

# 假设 flowers 和 prices 是已知的列表
flowers = ["玫瑰", "百合", "郁金香"]
prices = [100, 150, 200]

# 创建模型实例
llm = ChatOpenAI(temperature=0, model=os.environ.get("LLM_MODELEND"))  # 根据实际情况选择模型

# 创建提示模板
template = """\
鲜花名称:{flower_name},价格:{price}。请描述这朵花的特点和适合的场合。
"""
prompt = PromptTemplate.from_template(template)

# 创建 LLMChain
llm_chain = LLMChain(llm=llm, prompt=prompt)

# 遍历 flowers 和 prices 列表,生成描述
for flower, price in zip(flowers, prices):
    # 准备模型的输入
    input = {"flower_name": flower, "price": price}
    # 获取模型的输出
    output = llm_chain(input)
    # 解析模型的输出
    parsed_output = output["text"].strip()  # 假设输出是一个字典,包含 "text" 键
    print(f"鲜花名称:{flower},价格:{price}。描述:{parsed_output}")

在上面这段程序中,首先定义鲜花和价格列表,然后使用 PromptTemplate 类创建一个提示模板,再使用 ChatOpenAI 类创建一个模型实例并构建链,最后遍历鲜花和价格列表调用模型生成输出。

二、链上思考题二

题目:

  1. 上一道题目中,我要求你把提示的format和获取模型输出部分整合到LLMChain中,其实你还可以更进一步,把output_parser也整合到LLMChain中,让程序结构进一步简化,请你尝试一下。

请你使用LLMChain重构提示的format和获取模型输出部分,完成相同的功能。提示:

      llm_chain = LLMChain(
        llm=model,
        prompt=prompt,
        output_parser=output_parser)

解答: 在思考题1基础上,对下面内容进行改进可实现题目中要求的内容:

(1)在提示模板中添加“{format_instructions}”内容: 通过在提示模板中添加 {format_instructions} 占位符,我们可以在运行时动态插入输出格式指示。这使得模型能够根据预定义的格式生成输出,从而确保输出的一致性和规范性。

(2)在调用 LLMChain 模型中,多使用 output_parser 参数: 通过在 LLMChain 中使用 output_parser 参数,我们可以自定义输出格式。这使得模型的输出可以直接被解析为预定义的数据结构,而无需手动解析。

(3)利用apply方法运行链:apply 方法允许我们针对输入列表运行链,一次处理多个输入。这不仅提高了代码的效率,还简化了批量处理输入数据的逻辑。

# 导入所需的库
import os
from langchain_core.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain_openai import ChatOpenAI


# 创建提示模板
template = """\
鲜花名称:{flower_name},价格:{price}。请描述这朵花的特点和适合的场合。
{format_instructions}
"""

# 定义我们想要接收的数据格式
from pydantic.v1 import BaseModel, Field

class FlowerDescription(BaseModel):
    flower_name: str = Field(description="鲜花的名字")
    price: int = Field(description="鲜花的价格")
    feature: str = Field(description="鲜花的特点")
    occasion: str = Field(description="鲜花的适用场合")

# 创建输出解析器
from langchain.output_parsers import PydanticOutputParser

output_parser = PydanticOutputParser(pydantic_object=FlowerDescription)
# 获取输出格式指示
format_instructions = output_parser.get_format_instructions()
# 打印提示
# print("输出格式:", format_instructions)

# 创建提示
prompt = PromptTemplate.from_template(template, partial_variables={"format_instructions": format_instructions})

# 创建模型实例
llm = ChatOpenAI(temperature=0,model=os.environ.get("LLM_MODELEND"))  # 根据实际情况选择模型
# 创建 LLMChain
llm_chain = LLMChain(llm=llm, prompt=prompt, output_parser=output_parser)


# 输入数据列表
input_list = [
    {"flower_name": "玫瑰", "price": "100"},
    {"flower_name": "百合", "price": "150"},
    {"flower_name": "郁金香", "price": "200"}
]
# 获取模型的输出
output = llm_chain.apply(input_list)
print(output)

在上面这段程序中,首先导入了必要的库,并定义了鲜花和价格列表。接着,我们创建了一个包含 {flower_name}{price}{format_instructions} 占位符的提示模板。然后,使用 pydantic 定义了期望的输出数据格式 FlowerDescription,并创建了一个 PydanticOutputParser 输出解析器。

通过 output_parser.get_format_instructions() 获取输出格式指示,并将其传递给提示模板。接下来,我们创建了一个 PromptTemplate 实例,并使用 ChatOpenAI 创建了一个模型实例。随后,使用 LLMChain 将模型、提示模板和输出解析器关联起来,创建了一个链。最后,我们准备了一个包含多个输入数据的列表,并使用 llm_chain.apply(input_list) 方法批量处理这些输入数据,获取模型的输出并打印结果。

三、链上思考题三

题目:

  1. 选择一个LangChain中的链(我们没用到的类型),尝试使用它解决一个问题,并分享你的用例和代码。

解答: 使用转换链(TransformChain)能通过设置转换函数,对输入文本进行一系列的格式转换。例如,你可以用它接受一个很长的鲜花相关的文档,给文档分割成句子,仅保留前面N句,以满足LLM的令牌数量的限制,然后将其传递到LLMChain中以总结这些内容。

参考链接:blog.csdn.net/2301_818882…

from langchain.chains import TransformChain, LLMChain
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate
import os


with open("the_old_man_and_the_sea.txt") as f:
    novel_text = f.read()


# 定义一个转换函数,输入是一个字典,输出也是一个字典。
def transform_func(inputs: dict) -> dict:
    # 从输入字典中获取"text"键对应的文本。
    text = inputs["raw_text"]
    # 使用split方法将文本按照"\n\n"分隔为多个段落,并只取前三个,然后再使用"\n\n"将其连接起来。
    shortened_text = "\n\n".join(text.split("\n\n")[:3])
    # 返回裁剪后的文本,用"output_text"作为键。
    return {"output_text": shortened_text}


def main():
    # 使用上述转换函数创建一个TransformChain对象。
    # 定义输入变量为["text"],输出变量为["output_text"],并指定转换函数为transform_func。
    # 提供一个壳子 将函数处理能力 逃进来
    transform_chain = TransformChain(
        input_variables=["raw_text"], output_variables=["output_text"], transform=transform_func
    )

    # 通过chain转换后的文本数据 包括两个key raw_text输入结果 output_text输出结果
    transformed_novel = transform_chain(novel_text)
    print(transformed_novel)

    template = """总结下面文本:
    {output_text}
    总结:"""
    prompt = PromptTemplate(input_variables=["output_text"], template=template)
    llm_chain = LLMChain(llm=ChatOpenAI(model=os.environ.get("LLM_MODELEND")), prompt=prompt, verbose=True)

    few_output_text = transformed_novel['output_text'][:500]

    result = llm_chain(few_output_text)
    print(result)


if __name__ == "__main__":
    main()

在上面程序中,首先定义了一个转换函数 transform_func,该函数接受一个包含文本的字典,将文本按段落分割并保留前三个段落,然后将裁剪后的文本返回。接着,我们使用 TransformChain 创建了一个转换链,将输入文本转换为裁剪后的文本。然后,我们使用 LLMChain 创建了一个模型链,用于总结裁剪后的文本。最后,我们通过 transform_chain 转换输入文本,并将其结果传递给 llm_chain 进行总结,最终打印出总结结果。

四、链下思考题一

题目:

  1. 通过verbose=True这个选项的设定,在输出时显示了链的开始和结束日志,从而得到其相互调用流程。请你尝试把该选项设置为False,看一看输出结果有何不同。

解答:

(1)原始程序运行的部分结果如下(当verbose=True):

image.png 从上图可以发现,当verbose=True时候可以正常显示问题、调用的模型以及模型回答的结果。

(2)在原始程序基础上,当verbose=False的部分结果如下:

image.png 从上图可以发现,当verbose=False时,发现在(1)原始程序的基础上无法显示具体调用的模型是哪个,但是可以正常显示问题和模型回答的结果。

总结: 通过设置 verbose 参数,我们可以控制 LLMChain 是否显示详细的调用日志。当 verbose=True 时,程序会详细显示链的调用过程,这对于调试和理解链的工作流程非常有用。而当 verbose=False 时,程序仅显示最终的输出结果,适用于生产环境或不需要详细日志的场景。这种灵活性使得 langchain 库在不同的应用场景中都能发挥出色的表现。

五、链下思考题二

题目:

  1. 在这个例子中,我们使用了ConversationChain作为default_chain,这个Chain是LLMChain的子类,你能否把这个Chain替换为LLMChain?

解答:

(1)原始程序运行的部分结果如下(使用了ConversationChain作为default_chain,这个Chain是LLMChain的子类):

default_chain = ConversationChain(llm=llm, output_key="text", verbose=True)

image.png 从上图可以发现,当使用了ConversationChain作为default_chain时候可以正常显示问题、调用的模型以及模型回答的结果。

(2)在原始程序基础上,使用LLMChain作为default_chain的部分结果如下:

default_chain = LLMChain(llm=llm, output_key="text", verbose=True)

image.png 从上图发现,仅仅将“ConversationChain”修改为“LLMChain”是无法运行成功的。因为LLMChain中需要定义prompt才能运行成功,因此我们定义默认的提示模板,并将提示模板传入LLMChain模型中。对代码作如下修改,程序运行结果图如下:

default_prompt = PromptTemplate(
    template="请回答以下问题:\n{input}",
    input_variables=["input"]
)

default_chain = LLMChain(llm=llm, prompt=default_prompt,output_key="text", verbose=True)

image.png 从上图发现,当我们尝试将 default_chain 替换为 LLMChain 时,需要注意到 LLMChain 需要一个提示模板(PromptTemplate)才能正常工作。这是因为 LLMChain 不像 ConversationChain 那样内置了对话管理的功能。

六、总结

通过本次的学习,可以学习到调用LLMChain模型时可以使用的不同参数(llm参数——模型,prompt参数——提示模板,output_parser参数——自定义输出格式);也可以学到LangChain中的TransformChain链能通过设置转换函数,对输入文本进行一系列的格式转换;还可以学到对LLMChain模型中verbose=True参数的使用,当verbose=True时可以显示调用模型的详细信息;最后,还可以LLMChain模型是一定要有提示模板的。

如有错误,欢迎在评论区指出!