跳到主要内容
Open In ColabOpen on GitHub

如何向链的状态添加值

另一种在链的步骤中传递数据的方式是保持链状态的当前值不变,同时在给定键下分配新值。 RunnablePassthrough.assign() 静态方法接收一个输入值,并添加传递给 assign 函数的额外参数。

这在 LangChain 表达式语言(LangChain Expression Language)中很常见,可以累加创建字典,作为后续步骤的输入。

这是一个示例

%pip install --upgrade --quiet langchain langchain-openai

import os
from getpass import getpass

if "OPENAI_API_KEY" not in os.environ:
os.environ["OPENAI_API_KEY"] = getpass()
from langchain_core.runnables import RunnableParallel, RunnablePassthrough

runnable = RunnableParallel(
extra=RunnablePassthrough.assign(mult=lambda x: x["num"] * 3),
modified=lambda x: x["num"] + 1,
)

runnable.invoke({"num": 1})
{'extra': {'num': 1, 'mult': 3}, 'modified': 2}

让我们来详细说明这里发生的情况。

  • 链的输入是 {"num": 1}。这被传递给 RunnableParallel,它会用这个输入并行调用传递给它的可运行对象。
  • extra 键下的值被调用。RunnablePassthrough.assign() 保留输入字典({"num": 1})中的原始键,并分配一个名为 mult 的新键。该值为 lambda x: x["num"] * 3),即 3。因此,结果是 {"num": 1, "mult": 3}
  • {"num": 1, "mult": 3} 被返回到 RunnableParallel 调用,并被设置为 extra 键的值。
  • 同时,modified 键被调用。结果是 2,因为 lambda 从其输入中提取一个名为 "num" 的键并加一。

因此,结果是 {'extra': {'num': 1, 'mult': 3}, 'modified': 2}

流式传输

此方法的一个便捷功能是它允许值一经可用即传递。为了展示这一点,我们将使用 RunnablePassthrough.assign() 在检索链中立即返回源文档。

from langchain_community.vectorstores import FAISS
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI, OpenAIEmbeddings

vectorstore = FAISS.from_texts(
["harrison worked at kensho"], embedding=OpenAIEmbeddings()
)
retriever = vectorstore.as_retriever()
template = """Answer the question based only on the following context:
{context}

Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)
model = ChatOpenAI()

generation_chain = prompt | model | StrOutputParser()

retrieval_chain = {
"context": retriever,
"question": RunnablePassthrough(),
} | RunnablePassthrough.assign(output=generation_chain)

stream = retrieval_chain.stream("where did harrison work?")

for chunk in stream:
print(chunk)
{'question': 'where did harrison work?'}
{'context': [Document(page_content='harrison worked at kensho')]}
{'output': ''}
{'output': 'H'}
{'output': 'arrison'}
{'output': ' worked'}
{'output': ' at'}
{'output': ' Kens'}
{'output': 'ho'}
{'output': '.'}
{'output': ''}

我们可以看到第一个块包含原始的 "question",因为它立即可用。第二个块包含 "context",因为检索器后完成。最后,generation_chain 的输出一经可用就以块的形式流式传输。

下一步

现在你已经学会了如何在链中传递数据,以帮助格式化流经链的数据。

要了解更多信息,请参阅本节中关于可运行对象的其他操作指南。