Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Redis

Persisting Chat History: LangChain และ Upstash Redis

LangChain มี Interface เรียบง่ายสำหรับการสนทนาระหว่างมนุษย์และ AI สามารถตั้งค่าใช้ BufferMemory เก็บประวัติใน Memory ได้ ซึ่งเพียงพอสำหรับบาง Use Cases แต่อาจต้องการ Persistence ระยะยาว สลับไปใช้ Upstash Redis ได้ง่ายเช่นกัน

LangChain มี Redis Integrations หลายตัว ได้แก่ ioredis, node-redis และ Upstash Redis เนื่องจาก Upstash Redis Client ทำงานผ่าน REST จึงสร้าง Edge-ready Apps Deploy ได้บน Vercel, Cloudflare Workers หรือ Serverless อื่นๆ เราจะสร้าง Chat App เรียบง่ายกับ Memory ที่ Persist ข้าม Session

ซอร์สโค้ดเต็มได้ที่นี่

Prerequisites - เงื่อนไขก่อนเริ่ม

  • Upstash Redis Database
  • OpenAI API Key

Getting Started - เริ่มต้น

Creating the Project - สร้างโปรเจกต์

สร้าง Next.js App พื้นฐานพร้อม Vercel AI SDK สาธิต LangChain กับ Upstash Redis:

npx create-next-app@latest

เลือก Options ตามปกติ สำหรับ Demo ให้ Enable TypeScript และ app Directory

Installing Dependencies - ติดตั้ง Dependencies

npm install ai langchain openai @upstash/redis

Vercel AI SDK ช่วย Streaming Responses จาก OpenAI ไป Frontend Next.js เราต้องใช้ @upstash/redis สร้าง Redis Client เท่านั้น LangChain จัดการส่วนอื่น

Setting Environment Variables - ตั้งค่า Environment Variables

Env Variables ต่อไปจาก Prerequisites ใส่ใน .env Root Project (ชื่อต้องตรงตามนี้ ไม่งั้นอ่าน Auto ไม่ได้):

UPSTASH_REDIS_REST_URL="https://********.upstash.io"
UPSTASH_REDIS_REST_TOKEN="********"
OPENAI_API_KEY="sk-********"

Creating a Basic Chat Client - สร้าง Chat Client พื้นฐาน

Next.js สร้างไฟล์เยอะ เราทำงานแค่ไฟล์ใน app Directory ลบของใน public และ app ทิ้งได้

สร้าง app/layout.tsx 基礎:

import type { PropsWithChildren } from "react";
export default function RootLayout({ children }: PropsWithChildren) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

สร้าง Form พร้อม Input รับข้อความใน app/page.tsx:

export default function Home() {
  return (
    <main>
      <form>
        <input placeholder="Enter a message..." />
        <button type="submit">Send</button>
      </form>
    </main>
  );
}

Persisting Chat History: LangChain และ Upstash Redis

Vercel AI SDK มี Hook useChat สร้าง Chat UI ง่าย จัดการ Streaming และ State Input ใช้ Hook ต้องเพิ่ม "use client" ด้านบน Destructure Properties:

  • messages - Array ข้อความที่ส่งและรับ
  • input - ค่า Input Field ปัจจุบัน
  • handleInputChange - Function Update Input
  • handleSubmit - Function ส่งข้อความไป Endpoint
"use client";
import { useChat } from "ai/react";
export default function Home() {
  const { messages, input, handleInputChange, handleSubmit } = useChat();
  return (
    <main>
      <form onSubmit={handleSubmit}>
        <input value={input} onChange={handleInputChange} placeholder="Enter a message..." />
        <button type="submit">Send</button>
      </form>
    </main>
  );
}

useChat Append input ไป messages เมื่อ handleSubmit เรียก Trigger Re-render ไม่ต้องจัดการ UI เอง Clear Input และ Trigger API Call ไป Endpoint Default /api/chat

Render messages เหนือ Form:

<main>
  <section>
    {messages.map((message) => (
      <p key={message.id}>{message.content}</p>
    ))}
  </section>
  {/* snip */}
</main>

Creating the API Endpoint - สร้าง API Endpoint

สร้าง app/api/chat/route.ts Next.js ใช้ File-based Routing สำหรับ API และ Pages โฟลเดอร์ตรงกับ Default Endpoint /api/chat

ใช้ Upstash Redis Endpoint Edge-Compatible ระบุ export const runtime = "edge" ดึง messages จาก useChat ส่ง Latest Message ให้ LangChain:

import { type NextRequest } from "next/server";
import { LangChainStream, StreamingTextResponse } from "ai";
export const runtime = "edge";
export async function POST(req: NextRequest) {
  const { messages } = await req.json();
  const { stream, handlers } = LangChainStream();
  const latestMessage = messages[messages.length - 1];
  return new StreamingTextResponse(stream);
}

LangChainStream Return Properties:

  • stream - ReadableStream ผลลัพธ์ LangChain Process
  • handlers - Object Callback Functions ส่งให้ LangChain

Import Classes เพิ่มเติม:

import { Redis } from "@upstash/redis";
import { ConversationChain } from "langchain/chains";
import { ChatOpenAI } from "langchain/chat_models/openai";
import { BufferMemory } from "langchain/memory";
import { UpstashRedisChatMessageHistory } from "langchain/stores/message/upstash_redis";

สร้าง Redis Client ตั้งค่า Memory สำหรับ Chain ใช้ ConversationChain สนทนาระหว่าง Human และ AI ส่ง BaseMemory Custom Implementation เก็บ/ดึงข้อความ ใช้ BufferMemory กับ UpstashRedisChatMessageHistory เก็บใน Upstash Redis:

// snip
const latestMessage = messages[messages.length - 1];
const memory = new BufferMemory({
  chatHistory: new UpstashRedisChatMessageHistory({
    sessionId: new Date().toLocaleDateString(),
    client: Redis.fromEnv(),
  }),
});
const model = new ChatOpenAI({
  modelName: "gpt-3.5-turbo",
  streaming: true,
});
const chain = new ConversationChain({ llm: model, memory });
// snip

สร้าง Redis Client ด้วย Class Redis จาก @upstash/redis มี Method โหลด Env Auto เหมือน ChatOpenAI ตั้งชื่อ Env ถูกต้องไม่ต้องส่ง Arguments เพิ่ม

sessionId ใช้ Date ปัจจุบันสำหรับ Demo แอปจริงควรใช้ User ID หรือ Unique Identifier ป้องกัน Share Messages ระหว่าง User UpstashRedisChatMessageHistory มี Options อื่นๆ เช่น sessionTTL ตั้งอายุ Cache

สำคัญ: Enable streaming บน Model เพื่อใช้ handlers Pipe ผลลัพธ์ไป stream เรียก Chain ส่ง Latest Message และ handlers:

// snip
const chain = new ConversationChain({ llm: model, memory });
chain.call({
  input: latestMessage.content,
  callbacks: [handlers],
});
return new StreamingTextResponse(stream);
// snip

latestMessage เป็น Prompt ให้ LLM ส่ง handlers Pipe ผลลัพธ์ไป stream

Conclusion - สรุป

เสร็จแล้ว! รัน npm run dev เริ่มสนทนากับ AI Response จะ Stream กลับ Client อัตโนมัติ ประวัติสนทนาจะเก็บใน Upstash Redis

Persisting Chat History: LangChain และ Upstash Redis

Persisting Chat History: LangChain และ Upstash Redis