如何构建 LLM 生成的 UI
本指南将介绍使用 LangChain.js 构建生成式 UI 的一些高级概念和代码片段。要查看生成式 UI 的完整代码,请单击此处访问我们官方的 LangChain Next.js 模板。
该示例实现了一个工具调用代理,该代理在将工具调用的中间输出流式传输到客户端时输出交互式 UI 元素。
我们引入了两个实用程序,它们包装了 AI SDK,以便在 Runnable 和工具调用中更容易地生成 React 元素:createRunnableUI
和 streamRunnableUI
。
streamRunnableUI
使用streamEvents
方法执行提供的 Runnable,并通过 React Server Components 流将每个stream
事件发送到客户端。createRunnableUI
包装了 AI SDK 中的createStreamableUI
函数,以正确地挂钩到 Runnable 事件流。
用法如下
"use server";
const tool = tool(
async (input, config) => {
const stream = await createRunnableUI(config);
stream.update(<div>Searching...</div>);
const result = await images(input);
stream.done(
<Images
images={result.images_results
.map((image) => image.thumbnail)
.slice(0, input.limit)}
/>
);
return `[Returned ${result.images_results.length} images]`;
},
{
name: "Images",
description: "A tool to search for images. input should be a search query.",
schema: z.object({
query: z.string().describe("The search query used to search for cats"),
limit: z.number().describe("The number of pictures shown to the user"),
}),
}
);
// add LLM, prompt, etc...
const tools = [tool];
export const agentExecutor = new AgentExecutor({
agent: createToolCallingAgent({ llm, tools, prompt }),
tools,
});
提示
从 langchain
版本 0.2.8
开始,createToolCallingAgent
函数现在支持 OpenAI 格式的工具。
async function agent(inputs: {
input: string;
chat_history: [role: string, content: string][];
}) {
"use server";
return streamRunnableUI(agentExecutor, {
input: inputs.input,
chat_history: inputs.chat_history.map(
([role, content]) => new ChatMessage(content, role)
),
});
}
export const EndpointsContext = exposeEndpoints({ agent });
为了确保所有客户端组件都包含在捆绑包中,我们需要将所有服务器操作包装在 exposeEndpoints
方法中。这些端点将通过 Context API 从客户端访问,如 useActions
钩子中所示。
"use client";
import type { EndpointsContext } from "./agent";
export default function Page() {
const actions = useActions<typeof EndpointsContext>();
const [node, setNode] = useState();
return (
<div>
{node}
<button
onClick={async () => {
setNode(await actions.agent({ input: "cats" }));
}}
>
Get images of cats
</button>
</div>
);
}