基础部分总结(1/3) | 豆包MarsCode AI刷题

160 阅读7分钟

前言

我个人理解,黄老师课程的基础部分主要讲了六大板块:Model、Prompt、chain、memory、agent、toolkit。这六大板块刚好可以分为三类,每一类内部有较强的关联性,三类自前向后功能逐渐复杂。

基础类:Model、Prompt;这两个是大模型最基本的部分,有模型,有提示词,就可以输出一个结果。其他的如memory、agent等都是基于多样功能的需求,对这二者进行扩展。

进阶类:chain、memory;这二者是对大模型调用的扩展。chain重在复杂功能的实现,每个链都是一个功能,通过chain可以将简单的输入提示词、输出结果进行扩展,完成多样化的功能。memory则是侧重内容的延续,以memory作为新输出的参考。

高级类:agent、toolkit;这两个本质上是讲了同一件事:外部工具的调用。如果只有前四者,哪怕玩出花来,也不可能无中生有,输出大模型所不知道的知识;而这两者就是通过对外部工具进行访问,来获取额外的信息作为参考,以丰富输出的内容。

为了方便理解和代码使用,我在总结的时候把各部分内部所涉及的内容单独提取出来,形成模板。各个模板组合,就能形成一个完整项目代码。

1. Model

1.1. Input

我理解的input,就是调用大模型的过程。以gpt为例,调用大模型可以直接通过官方渠道即openai库调用,也可以通过Langchain转一手调用。

方法一:使用openai库直接调用大模型

from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(  
  model="**调用的大模型**",
  messages=[
        {"role": "system", "content": "##模型角色扮演##"},
        {"role": "user", "content": "##提示内容##"},
    ],
  temperature=0.8,
  max_tokens=60
)
print(response.choices[0].message.content.strip())

方法二:通过Langchain调用大模型

from langchain_openai import ChatOpenAI
llm=ChatOpenAI(model="**调用的大模型**",temperature=0.7,max_tokens=300)
response=llm.invoke("##提示内容##")
print(response.content)

或者

from langchain_openai import ChatOpenAI
from langchain.schema import HumanMessage, SystemMessage
llm = ChatOpenAI(model="**调用的大模型**", temperature=0.7, max_tokens=300)
messages = [
    SystemMessage(content="##模型角色扮演##"),
    HumanMessage(content="##提示内容##"),
]
response = llm.invoke(messages)
print(response.content)

涉及到Langchain的大模型调用最好使用方法二,其作用获取一个名为llm的实例,并将提示词输入其中。至于提示词的构建方法、输入方式就属于其他部分的内容了。

1.2. Output

1)OutputParser(输出解析器)

输出解析器通过在提示词中限定输出结果的格式,结合输出解析函数.parse来实现对文本结果的解析与格式转换。

response_schemas内包含了输出格式要求,依据要求创建输出解析器output_parser。通过输出解析器获取格式指示format_instructions。格式指示本质是一段提示词,限定输出的格式,与response_schemas相对应。

# 导入结构化输出解析器和ResponseSchema
from langchain.output_parsers import StructuredOutputParser, ResponseSchema

# 定义我们想要接收的响应模式(description、reason可以替换为其他想要的内容)
response_schemas = [
    ResponseSchema(name="description", description="##描述文案##"),
    ResponseSchema(name="reason", description="##为什么要这样写这个文案##")
]

# 创建输出解析器
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)

# 获取格式指示
format_instructions = output_parser.get_format_instructions()

将格式指示format_instructions到提示词prompt上,方便解析。

# 导入LangChain中的提示模板
from langchain.prompts import PromptTemplate
# 创建原始提示模板
template = """##提示内容##
{format_instructions}"""

# 根据原始模板创建提示,同时在提示中加入输出解析器的说明
prompt = PromptTemplate.from_template(template, 
                partial_variables={"format_instructions": format_instructions}) 

调用大模型,具体步骤见Input。获取输出结果output。然后按下述步骤对输出结果进行解析。

  # 解析模型的输出
  parsed_output = output_parser.parse(output)

2)PydanticParser

Pydantic (JSON) 解析器可以将输出结果转化为json格式,方便输出数据的存储、使用和转化。

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

class TypeDescription(BaseModel):
    feature1: str = Field(description="##描述内容##")
    feature2: int = Field(description="##描述内容##")
  • 创建Pydantic解析器output_parser
from langchain.output_parsers import PydanticOutputParser
output_parser = PydanticOutputParser(pydantic_object=TypeDescription)
# 获取输出格式指示
format_instructions = output_parser.get_format_instructions()
  • 使用解析器解析模型llm的输出output,获得解析结果parsed_output
  parse_output = output_parser.parse(output)

3)OutputFixingParser(自动修复解析器)

自动修复解析器可以修复输出json数据的格式错误。本质上是回用大模型纠错:如果调用原有解析器正确则不管,失败则将错误的输出重新传递给大模型,让大模型来检查、修改。

  • 创建一个PydanticParser,名为output_parser,方法见PydanticParser部分
  • 创建OutputFixingParser;该解析器能够纠正格式不正确的输出。
from langchain.output_parsers import OutputFixingParser
fix_parser = OutputFixingParser.from_llm(
    parser=output_parser,    ##
    llm="**调用的大模型**",
)
#修复解析结果
parse_result = fix_parser.parse(response)

4)RetryWithErrorOutputParser(重试解析器)

重试解析器可以帮助我们利用大模型的推理能力,根据原始提示找回相关信息。

  • 创建一个PydanticParser,名为output_parser,方法见PydanticParser部分
  • 创建RetryWithErrorOutputParser;它会尝试再次提问来得到一个正确的输出。
from langchain.output_parsers import RetryWithErrorOutputParser
retry_parser = RetryWithErrorOutputParser.from_llm(
    parser=output_parser, llm="**调用的大模型**"
)
#尝试重新获得输出
parse_result = retry_parser.parse_with_prompt(output, prompt)

2. Prompt

由于Prompt 部分涉及各种模板、提示词的转换,在此先统一下各个变量的定义,方便后续理解。

template:原始提示模板。

prompt_template:转换后的提示模板。

prompt:加入变量内容的提示词。

2.1. 提示模板的类型

langchain提示模板需要使用提示词模板都位于langchain.prompts.promt下,可以使用from langchain import xxx 直接导入,也可以使用from langchain.prompts import xxx,或者使用from langchain.prompts.prompt import xxx,三种方法导入都可以。第一种方法比较简洁,第二、三种方法可读性强且指明来源。

1)PromptTemplate(常规提示模板)

导入langchain提示模板类,构建外部模板。

form langchain import PromptTemplate
template = """
##提示内容与变量{variable}##
"""

然后有两种方法构建langchain的提示模板。

方法一:

prompt_template=PromptTemplate.from_template(template)
prompt=prompt_template.format(variable="##变量##"

方法二:

# 导入聊天消息类模板
prompt=PromptTemplate(
input_variables=["##变量1##", "##变量2##"]
template=template
)

2) ChatPromptTemplate(聊天提示模板)

想要聊天,就要有聊天对象。通过SystemMessagePromptTemplate构建AI聊天对象,再通过HumanMessagePromptTemplate构建人类聊天对象。彼此的沟通通过ChatPromptTemplate来实现。

导入聊天消息类模板

from langchain.prompts import (
    ChatPromptTemplate,
    SystemMessagePromptTemplate,
    HumanMessagePromptTemplate,
)

构建聊天模板。系统角色和人类角色有各自的提示词,通过对应的类方法转为langchain提示模板后,使用ChatPromptTemplate将他们组合到一起,再通过.format_prompt()方法将变量组合进去。

system_template = "##输入系统角色的聊天内容与变量{variable1}##"
system_prompt_template = SystemMessagePromptTemplate.from_template(system_template)

human_template = "##输入人类角色的聊天内容与变量{variable2}##"
human_prompt_template = HumanMessagePromptTemplate.from_template(human_template)

prompt_template = ChatPromptTemplate.from_messages(
    [system_prompt_template, human_prompt_template]
)

prompt = prompt_template.format_prompt(
    variable1="##变量1##", variable2="##变量2##"
).to_messages()

获取整合后的提示词,输入大模型中。后面调用大模型与Input部分一样。

3)FewShotPromptTemplate(少样本提示模板)

  • 少样本提示要有样本,即需要先创建一些示例sample
sample=[
	{"feature1":"示例A特征1","feature2":"示例A特征2",},
	{"feature1":"示例B特征1","feature2":"示例B特征2",},
]
  • 构建常规提示模板prompt_template,对特征进行描述。
prompt_template = PromptTemplate(
    input_variables=["feature1", "feature2"],
    template="##特征1{feature1}与特征2{feature2}的相关描述##",
)
  • 使用少样本提示模板FewShotPromptTemplate,将常规提示模板prompt_template与示例sample组合到一起。
from langchain.prompts.few_shot import FewShotPromptTemplate

few_shot_prompt = FewShotPromptTemplate(
		examples=samples,
    example_prompt=prompt_template,
    prefix='##通用要求##',    #提示前缀,对每个样例都适用,可不要。  
    suffix="##与sample结构类似的输入内容与变量{variable}##",    #提示后缀,对变量的要求
    input_variables=["variable"],
    )
    
prompt=few_shot_prompt.format(variable="##变量##"")

具体调用大模型输出见1.1.Input部分。

2.2. 思维连(COT)、思维树(TOT)

我理解的思维链、思维树,就是通过丰富提示词的内容,告诉大模型第一步、第二步、第三步该怎么做,让大模型按照步骤运行下去。这部分内容主要是在提示词内容的编写上,代码方面并没有太多模板化的构造。