如何向链的状态中添加值
前提条件
本指南假定您熟悉以下概念:
一种传递数据通过链步骤的替代方法是在给定键下分配新值的同时,保持链状态的当前值不变。RunnablePassthrough.assign()静态方法接收一个输入值,并将传递给
assign 函数的额外参数添加进去。
这在 LangChain 表达式语言 的常见模式中非常有用,即通过逐步创建字典来作为后续步骤的输入。
以下是一个示例:
import {
RunnableParallel,
RunnablePassthrough,
} from "@langchain/core/runnables";
const runnable = RunnableParallel.from({
extra: RunnablePassthrough.assign({
mult: (input: { num: number }) => input.num * 3,
modified: (input: { num: number }) => input.num + 1,
}),
});
await 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() 在检索链中立即返回源文档:
:::提示 请参阅安装集成包的一般说明部分。 :::
- npm
- yarn
- pnpm
npm i @langchain/openai @langchain/core
yarn add @langchain/openai @langchain/core
pnpm add @langchain/openai @langchain/core
import { StringOutputParser } from "@langchain/core/output_parsers";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import {
RunnablePassthrough,
RunnableSequence,
} from "@langchain/core/runnables";
import { ChatOpenAI, OpenAIEmbeddings } from "@langchain/openai";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
const vectorstore = await MemoryVectorStore.fromDocuments(
[{ pageContent: "harrison 在 kensho 工作过", metadata: {} }],
new OpenAIEmbeddings()
);
const retriever = vectorstore.asRetriever();
const template = `仅基于以下上下文回答问题:
{context}
问题: {question}
`;
const prompt = ChatPromptTemplate.fromTemplate(template);
const model = new ChatOpenAI({ model: "gpt-4o" });
const generationChain = prompt.pipe(model).pipe(new StringOutputParser());
const retrievalChain = RunnableSequence.from([
{
context: retriever.pipe((docs) => docs[0].pageContent),
question: new RunnablePassthrough(),
},
RunnablePassthrough.assign({ output: generationChain }),
]);
const stream = await retrievalChain.stream("harrison 在哪里工作过?");
for await (const chunk of stream) {
console.log(chunk);
}
{ question: "harrison 在哪里工作过?" }
{ context: "harrison 在 kensho 工作过" }
{ output: "" }
{ output: "H" }
{ output: "arrison" }
{ output: " 工作" }
{ output: " 在" }
{ output: " Kens" }
{ output: "ho" }
{ output: "." }
{ output: "" }
我们可以看到,第一个 chunk 包含原始的
"question",因为它立即可用。第二个 chunk 包含
"context",因为检索器在稍后完成。最后,generation_chain
的输出在可用时以 chunk 的形式流式传输。
下一步
现在您已经了解了如何通过链传递数据,以帮助格式化流经链的数据。
要了解更多信息,请参阅本节中有关可运行对象的其他指南。