LangChain补充一:一些小且有用的点

一:LangChain 表达式语言LCEL(LangChain Expression Language)

chain:我们可以将包括大模型调用在内的一组操作组成“链条”,即所谓“调用链”

(一)概念

LangChain 提供的 LangChain Expression Language(LCEL) 让开发可以很方便地将多个组件连接成 AI 工作流(或者说是调用链)。如下是一个简单的工作流:
chain = prompt | chatmodel | outputparser
chain.invoke({"input":"What's your name?")
View Code
其中,通过由|管道操作符连接而成的 LangChain 表达式,我们方便地将三个组件 prompt chatmodel outparser 按顺序连接起来,这就形成了一个 AI 工作流。 invoke()则是实际运行这个工作流。
我们还可以组织较为复杂的 AI 工作流,如下所示,其中进行两次模型调用,并且示例中用的两个不同的模型。
chain = (
        prompt | chatmodel | outputparser |
        second_prompt | model2 | finalparser
        )
chain.invoke("input":"waht's AI?")
View Code

(二):通过LCEL实现多次调用模型

多次调用模型,分步来进行操作,从而利用模型的能力得到更符合期待的结果。
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from IPython.display import Markdown

llm = ChatOpenAI(
    model_name="gpt-4-1106-preview"    #创建聊天模型示例。这里采用 gpt-4-1106-preview 模型
)

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are world class technical documentation writer."),
    ("user", "{input}")
])    #创建第一次模型调用的提示语模板。其中系统提示语是“You are world class technical documentation writer.”(你是一个世界级的技术文档编写者。)

translate_prompt = ChatPromptTemplate.from_messages([
    ("system", "Translate to simplified Chinese."),
    ("user", "{input}")
])    #创建第二次模型调用的提示语模板。其中系统提示语是“Translate to simplified Chinese.”(翻译为简体中文。)

output_parser = StrOutputParser()    #StrOutputParser,它可将输出解析为易读的文本格式,将 AIMessage 转换成 string

chain = prompt | llm | output_parser \
        | {"input": RunnablePassthrough()} \
        | translate_prompt | llm | output_parser    #建立调用链。其中用 RunnablePassthrough() 将第一次模型的输出作为第二次的输入。

output = chain.invoke({"input": "what's generative ai?"})
View Code
注意:其中用 RunnablePassthrough() 将第一次模型的输出作为第二次的输入

二:结合LCEL实现对输出的处理

之前是第五期 LangChain学习调用模型获取返回结果之后,调用解析器进行解析,这里是通过LCEL链接输出处理步骤。链接调用链时,解析部分parser会注入指令到prompt中去
首先,我们用 Pydnatic 定义一个对象:
# 用 Pydantic 定义输出的 JSON 格式
from langchain_core.pydantic_v1 import BaseModel, Field

# Define your desired data structure.
class Joke(BaseModel):
    setup: str = Field(description="question to set up a joke")
    punchline: str = Field(description="answer to resolve the joke")
View Code
然后,我们调用模型,并指示模型输出 JSON 格式:
from langchain_core.output_parsers import JsonOutputParser
from langchain.prompts import ChatPromptTemplate

chatmodel = ChatOpenAI()

joke_query = "Tell me a joke."

# Set up a parser + inject instructions into the prompt template.
parser = JsonOutputParser(pydantic_object=Joke)

prompt_template = ChatPromptTemplate.from_messages(
    [
      ("system", "Answer the user query.\n{format_instructions}"),
      ("user", "{query}")
    ])

chain = prompt_template | chatmodel | parser

#print(parser.get_format_instructions())

chain.invoke(
    {"query": joke_query,
     "format_instructions": parser.get_format_instructions()
    })
View Code
其中get_format_instructions指示我们如何将llm的输出进行格式化,需要注入到prompt中

补充1:两种引入prompt模板的方式其实最后都是走到langchain_core.prompts,如果要使用第二个,需要使用pip install langchain安装

from langchain_core.prompts import ChatPromptTemplate
from langchain.prompts import ChatPromptTemplate
View Code

补充2:目前的例子中我们对prompt提示语的输入参数都是在最后面invoke时填充进去的,还可以使用partial()逐步的填充提示语的输入参数

# 4. 创建模板
prompt_template = ChatPromptTemplate.from_messages(
    [
      ("system", "Answer the user query.\n{format_instructions}"),
      ("user", "{query}")
    ])

# 5. 在模板中部分填充输出要求
prompt_partial_filled = prompt_template.partial(
  format_instructions=parser.get_format_instructions()
)

# 6. 生成调用链
chain = prompt_partial_filled | chatmodel | parser

# 7. 调用模型
joke_query = "Tell me a joke."

chain.invoke({"query": joke_query})
View Code

三:将结果流式输出

  • 将模型设为流式输出;
  • 调用采用stream()而非invoke()
  • 从开始接收到输出时就逐一打印。
chatmodel = ChatOpenAI(
    streaming=True
)

prompt_template = ChatPromptTemplate.from_messages([
    ("system", "You are world class technical documentation writer."),
    ("user", "{query}")
])

output_parser = StrOutputParser()
chain = prompt_template | chatmodel | output_parser
response = chain.stream({"query": "what's generative ai?"})

for value in response:
print(value, end='', flush=True)    #end=''使得后续的输出会紧接着前面的输出;flush=True意味着每次print调用后,输出缓存都会被清空,确保value被直接显示。
View Code

四:使用OpenAI SDK调用其他兼容/非兼容模型

(一)模型完全兼容OpenAI SDK

采用更改 openai_api_base (alias base_url)和model_name来调用这些模型:
from langchain_openai import ChatOpenAI
api_key = userdata.get('deepseek')
base_url= 'https://api.deepseek.com/v1'
model_name='deepseek-chat'

chatmodel = ChatOpenAI(
     base_url=base_url,
     api_key=api_key,
     model_name=model_name)

chatmodel.invoke("what's generative ai?")
View Code

(二)模型没有完全兼容OpenAI SDK

需要有对应模型的SDK、API,调用对应模型的方法即可,以文心为例:
  1. 注册百度千帆账号,开启相关的模型服务,并充值。你需要获得 API KEY 与 API Secret。我们这里配置的是百度文心(ErnieBot)模型。
  2. 安装 Qianfan SDK:
 pip install qianfan
  1. 设置API key、secret
  2. 调用对应的SDK
from langchain_community.chat_models.baidu_qianfan_endpoint import QianfanChatEndpoint

chat = QianfanChatEndpoint(
    qianfan_ak = qf_api_key,
    qianfan_sk = qf_secrect_key,
)

chat([HumanMessage(content="hello there, who are you?")])
View Code

五:少样本模板的构建FewShotChatMessagePromptTemplate

大语言模型是“少样本学习者”(Few shot learner),它能够直接从我们在提示语中提供的样例中学习。除了手工模拟AIMessage和HumanMessage之外,还可以通过FewShotChatMessagePromptTemplate协助完成创建少样本。

1.创建少样本

from langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate
from langchain_openai import ChatOpenAI

examples = [
    {"input": "2+2", "output": "4"},
    {"input": "2+3", "output": "5"},
]

# This is a prompt template used to format each individual example.
example_prompt = ChatPromptTemplate.from_messages(
    [
        ("human", "{input}"),
        ("ai", "{output}"),
    ]
)
few_shot_prompt = FewShotChatMessagePromptTemplate(
    example_prompt=example_prompt,
    examples=examples,
)

print(few_shot_prompt.format())
View Code

2.添加少样本到message

final_prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "You are a wondrous wizard of math."),
        few_shot_prompt,
        ("human", "{input}"),
    ]
)

print(final_prompt.format(input="What's the square of a triangle?"))
 
View Code

 

posted @ 2024-07-17 20:35  山上有风景  阅读(75)  评论(0编辑  收藏  举报