大模型格式化輸出的本質——通過提示詞約束模型輸出 原創
“ 大模型的格式化輸出只能靠提示詞約束,沒有其它辦法;Langchain的輸出解析器只不過是封裝了格式化輸出,其本質還是通過提示詞來實現。”
在大模型應用開發中,格式化輸出是很重要的一個環節,因為沒有格式化輸出就不會有大模型的應用。
但是大模型的格式化輸出是怎么實現的呢?
今天我們就以Langchain框架為例,來講一下大模型的格式化輸出問題。
基于Langchain的格式化輸出
在前面的文章中有提到過Langchain輸出解析器的問題,其實輸出解析器的本質,就是把需要的返回值封裝成實體對象或JSON等對象,然后把對象的描述拼接到提示詞模板中,然后由大模型按照模板的格式要求進行數據輸出;之后,輸出解析器再把模型輸出的字符串轉換成需要的對象格式。
如下圖所示,其中parser就是一個輸出解析器,其可以是字符串解析器,json解析器,也可以是PydanticOutputParser對象解析器。

通過parser.get_format_instructions()就可以獲取到需要的輸出格式;如下所示,標識需要輸出的是一個對象;當然,生成式模型無法生成json或實體對象,只能生成字符串格式的數據,因此拿到大模型的輸出之后,需要把字符串轉換成json或實體對象。

所以,從這里可以看出大模型格式化輸出的本質,就是通過提示詞告訴模型我需要什么樣的格式,然后模型就可以根據要求生成對應的格式;而Langchain中的解析器的作用,一是提供一個默認的格式化輸出提示詞;二是把模型輸出的字符串解析成對應的數據格式。
當然,在Langchain中提供了多種不同的解析器,其使用場景也不一樣;但其中最重要的解析器,應該就是PydanticOutputParser了,原因就在于其格式化程度最強,并且可以使用類型驗證來保證模型輸出的準確性。
當然,由于模型自身不穩定的特性,其輸出并不是每一次都是按照要求生成的;因此,作為一個合格的輸出解析器必須要有異常處理,也就是當模型輸出錯誤格式的數據時,能夠拋出異常,或者進行處理然后重試等。
"""langchain 提示詞 格式化輸出 和 鏈"""
import os
from pydantic import BaseModel, Field
import config
from langchain_openai import ChatOpenAI
from langchain_core.prompts import
(
PromptTemplate,
ChatPromptTemplate
)
from langchain.prompts import
(
ChatPromptTemplate,
MessagesPlaceholder,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate
)
from langchain_core.output_parsers import StrOutputParser, JsonOutputParser, CommaSeparatedListOutputParser
from langchain.output_parsers import ResponseSchema, StructuredOutputParser, PydanticOutputParser
os.environ['OPENAI_API_KEY'] = config.AIModel.openai_api_key
os.environ['OPENAI_API_BASE'] = config.AIModel.openai_api_base
# prompt = PromptTemplate.from_template("你是一個智能助手 你能回答用戶問題")
prompt = ChatPromptTemplate.from_messages([
("system", "你是一個智能助手 能夠根據用戶的需求提取信息 并返回json格式的數據 以以下JSON格式返回:{format_instructions}"),
MessagesPlaceholder(variable_name="chat_history"),
("human", "用戶問題如下: {query}")
])
# prompt_value = prompt.invoke({"query": "你是誰?", "chat_history": []})
#
# print(f"prompt_value: {type(prompt_value)}, {prompt_value}")
# print(f"prompt: {type(prompt)}, {prompt}")
model = ChatOpenAI(model_name=config.AIModel.model, temperature=0.8, streaming=True, max_tokens=1024)
# parser = StructuredOutputParser.from_response_schemas(response_schemas)
# parser = StrOutputParser()
# parser = JsonOutputParser()
class Student(BaseModel):
stu_no: str = Field(descriptinotallow="學號")
name: str = Field(descriptinotallow="姓名")
parser = PydanticOutputParser(pydantic_object=Student)
print(f"parser: {parser}, {parser.get_format_instructions()}")
# prompt.partial_variables = {
# "format_instructions": parser.get_format_instructions()
# }
prompt = prompt.partial(
format_instructinotallow=parser.get_format_instructions()
)
chain = prompt | model | parser
inputs = {
"query": "張三是一名學生 他的學號是st132 ",
"chat_history": []
}
result = chain.invoke(inputs)
print(f"result: {result}")在Langchain中,輸出解析器設計的都是基于字典形式的輸出,所以輸出解析器無法直接輸出列表形式的數據;原因在于列表形式的數據格式靈活性沒有字典形式的數據格式靈活性高。
其次,可以通過封裝的形式來讓模型輸出列表形式的數據;以Student對象為例,如果想讓模型輸出一個學生對象列表,那么就可以再封裝一個對象的列表集合,通過這種方式來實現讓模型輸出列表形式的數據。
class StudentList(BaseModel):
student_list: List[Student] = Field(descriptinotallow="學生列表")?
本文轉載自??AI探索時代???? 作者:DFires

















