一、 runnable接口函数
invoke:将单个输入转换为输出
batch:将多个输入转换为输出
stream:流式输出
二、runnable组件
2.1 组件种类
2.2 runnable组件的动态参数绑定
动态绑定:在运行时确定参数与函数的映射关系,而不是在编写代码时固定
1、将函数附加到模型上
#符合openai functions规范的函数声明:json schema格式
functions=[
{
"name": "solver",
"description": "Formulates and solves an equation",
"parameters": {
"type": "object",
"properties": {
"equation": {
"type": "string",
"description": "The algebraic expression of the equation",
},
"solution": {
"type": "string",
"description": "The solution to the equation",
},
},
"required": ["equation", "solution"],
},
},
{
"name": "birth_finder",
"description": "Finds the birth city and the birth date of the person",
"parameters": {
"type": "object",
"properties": {
"city":{
"type":"string",
"description":"the birth place of the person",
},
"date":{
"type":"string",
"description":"the birth date of the person"
}
},
"required": ["city","date"],
},
},
]
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"Please provide the birth city and the birth date of the following person:",
),
("human", "{person}"),
]
)
model = ChatOpenAI(model="gpt-4", temperature=0,api_key="",base_url="").bind(
function_call="auto", functions=functions
)
runnable = {"person": RunnablePassthrough()} | prompt | model
output = runnable.invoke("Barack Obama")
print(output)
functions
参数提供了一个函数列表,其中每个函数都有一个名称和参数描述。这个列表告诉模型有哪些函数可以调用,以及每个函数需要什么参数。
function_call
参数指定了在生成文本的过程中应该调用哪个函数。它是一个包含函数名称的字典,模型会根据这个名称来选择要调用的函数。而auto则模型会根据自己的生成自动选择要调用的函数解释:为什么传递的参数是person,但函数需要的参数是city和date:
birth_finder
函数的作用是接收已经生成或解析出的city
和date
参数,然后根据这些参数执行某种处理,或者只是按照特定的格式返回结果。它并不会主动解析或生成这些信息,而是依赖于模型在之前的步骤中已经生成的内容
三、runnable对象类型
runnable对象类型,指明了runnable组件之间的数据流动方式
3.1 RunnableLambda
参数:
func
- 描述: 这是传递给
RunnableLambda
的函数或 lambda 表达式。它定义了如何处理传入的数据
sequence = RunnableLambda(lambda x: x + 1) | {
'mul_2': RunnableLambda(lambda x: x * 2),
'mul_5': RunnableLambda(lambda x: x * 5)
}
print(sequence.invoke(1))
#{'mul_2': 4, 'mul_5': 10}
sequence2 = RunnableLambda(lambda x: x + 1) | RunnableLambda(lambda x: x * 2)|RunnableLambda(lambda x: {"outcome":x * 5})
print(sequence2.invoke(1))
#{'outcome': 20}
3.2 RunnablePassthrough
数据流动方式:直接传递
不传输全部数据:itemgetter:传递字典中的某一个键值
3.3 RunnableSequence
数据流动方式:按顺序链式处理
说明:在
RunnableSequence
中,数据按顺序从第一个runnable
组件流向第二个,依此类推创建方式:
显示创建:RunnableSequence(step1, step2),其中step1、step2应该为a Runnable, callable or dict
隐式创建:用|串联
3.4 RunnableMap (RunnableParallel,同名)
用词典嵌入sequence即相当于构建了runnableparallel,没什么特别的,就是使用相同参数填充value罢了
3.4.1 书写格式
RunnableParallel({"key1":value1, "key2":value2})
- 字典的每个属性(key1与key2)都接受相同的输入参数
- 而后使用这些参数并行调用value1、value2,返回值用于填充map对象
- 将填充完数据的字典对象传递给sequence中的下一个runnable对象
3.4.2 用法
1.并行调用runnable对象或函数
# 并行处理runnable对象
model= ChatOpenAI(model="gpt-4", temperature=0,api_key="",base_url="")
joke_chain = ChatPromptTemplate.from_template("tell me a joke about {topic}") | model
poem_chain = (
ChatPromptTemplate.from_template("write a 2-line poem about {topic}") | model
)
map_chain = RunnableParallel({"joke":joke_chain, "poem":poem_chain})
print(map_chain.invoke({"topic": "bear"}))
#并行处理函数
def task1(x):
# 执行一些操作
return x+1
def task2(x):
# 执行一些操作
return x+2
# 创建 RunnableParallel 实例
parallel_executor = RunnableParallel({"1":task1,"2":task2})
print(parallel_executor.invoke(3))
2. 自动实现runnable对象间的输入——输出格式转换
vectorstore = FAISS.from_texts(
["harrison worked at kensho"], embedding=OpenAIEmbeddings()
)
# 定义了一个检索器 retriever,可以从文本中检索上下文
retriever = vectorstore.as_retriever()
# template 定义了一个带占位符的prompt模板,所以prompt组件需要一个包含context和question键的字典作为输入。
template = """Answer the question based only on the following context:
{context}
Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
retrieval_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| model
| StrOutputParser()
)
retrieval_chain.invoke("where did harrison work?")
说明:
prompt组件需要一个包含"context"和"question"键的字典作为输入。
用户只输入了一个问题字符串。
于是使用了一个RunnableMap,组装context与question得到prompt组件需要的输入格式
3. 构建复杂链
prompt1 = ChatPromptTemplate.from_template('what is the city {person} is from?only respond with city name.')
prompt2 = ChatPromptTemplate.from_template('What country is the city {city} in? Respond in {language}.')
combinedChain={"city":itemgetter("person")|prompt1|model|StrOutputParser(),"language":itemgetter("language")}|prompt2|model|StrOutputParser()
result=combinedChain.invoke({"person":"chairman Mao","language":"chinese"})
print(result)
即询问毛主席来自哪个城市——>这座城市属于哪个国家,用中文回答