如何将代理数据流式传输到客户端
本指南将引导您了解我们如何使用此目录中的 React Server Components 将代理数据流式传输到客户端。本文档中的代码取自此目录中的 page.tsx
和 action.ts
文件。要查看完整的、不间断的代码,请单击此处查看 actions 文件和此处查看 client 文件。
本指南假设您熟悉以下概念
设置
首先,安装必要的 LangChain 和 AI SDK 包
- npm
- Yarn
- pnpm
npm install langchain @langchain/core @langchain/community ai
yarn add langchain @langchain/core @langchain/community ai
pnpm add langchain @langchain/core @langchain/community ai
在本演示中,我们将使用 TavilySearchResults
工具,这需要 API 密钥。您可以从此处获取一个,或者您可以将其换成您选择的另一个工具,例如WikipediaQueryRun
,它不需要 API 密钥。
如果您选择使用 TavilySearchResults
,请按如下方式设置您的 API 密钥
export TAVILY_API_KEY=your_api_key
开始
第一步是创建一个新的 RSC 文件,并添加我们将用于运行代理的导入。在本演示中,我们将其命名为 action.ts
"use server";
import { ChatOpenAI } from "@langchain/openai";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { TavilySearchResults } from "@langchain/community/tools/tavily_search";
import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
import { pull } from "langchain/hub";
import { createStreamableValue } from "ai/rsc";
接下来,我们将定义一个 runAgent
函数。此函数接收一个 string
类型的输入,并包含我们代理的所有逻辑以及将数据流式传输回客户端的逻辑
export async function runAgent(input: string) {
"use server";
}
接下来,在我们的函数内部,我们将定义我们选择的聊天模型
const llm = new ChatOpenAI({
model: "gpt-4o-2024-05-13",
temperature: 0,
});
接下来,我们将使用 ai
包提供的 createStreamableValue
辅助函数来创建可流式传输的值
const stream = createStreamableValue();
这在我们稍后开始将数据流式传输回客户端时非常重要。
接下来,让我们定义包含代理逻辑的异步函数
(async () => {
const tools = [new TavilySearchResults({ maxResults: 1 })];
const prompt = await pull<ChatPromptTemplate>(
"hwchase17/openai-tools-agent",
);
const agent = createToolCallingAgent({
llm,
tools,
prompt,
});
const agentExecutor = new AgentExecutor({
agent,
tools,
});
截至 langchain
版本 0.2.8
,createToolCallingAgent
函数现在支持 OpenAI 格式的工具。
在这里您可以看到我们正在做几件事
首先,我们定义了我们的工具列表(在本例中我们只使用一个工具),并从 LangChain 提示中心拉取我们的提示。
之后,我们将我们的 LLM、工具和提示传递给 createToolCallingAgent
函数,该函数将构建并返回一个 runnable 代理。然后将其传递到 AgentExecutor
类,该类将处理我们代理的执行和流式传输。
最后,我们将调用 .streamEvents
并将我们的流式数据传递回我们上面定义的 stream
变量,
const streamingEvents = agentExecutor.streamEvents(
{ input },
{ version: "v2" },
);
for await (const item of streamingEvents) {
stream.update(JSON.parse(JSON.stringify(item, null, 2)));
}
stream.done();
})();
如上所示,我们正在做一些有点奇怪的事情,即字符串化和解析我们的数据。这是由于 RSC 流代码中的一个错误,但是如果您像我们上面那样进行字符串化和解析,您不应该遇到这种情况。
最后,在函数底部返回流值
return { streamData: stream.value };
一旦我们实现了我们的服务器操作,我们就可以在我们的客户端函数中添加几行代码来请求和流式传输此数据
首先,添加必要的导入
"use client";
import { useState } from "react";
import { readStreamableValue } from "ai/rsc";
import { runAgent } from "./action";
然后在我们的 Page
函数内部,调用 runAgent
函数非常简单
export default function Page() {
const [input, setInput] = useState("");
const [data, setData] = useState<StreamEvent[]>([]);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
const { streamData } = await runAgent(input);
for await (const item of readStreamableValue(streamData)) {
setData((prev) => [...prev, item]);
}
}
}
就这样!您已成功构建了一个将数据流式传输回客户端的代理。您现在可以运行您的应用程序并实时查看数据流。