惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
L
LangChain Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
罗磊的独立博客
J
Java Code Geeks
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 叶小钗
小众软件
小众软件
博客园 - Franky
D
Docker
Google DeepMind News
Google DeepMind News
Microsoft Azure Blog
Microsoft Azure Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
U
Unit 42
宝玉的分享
宝玉的分享
C
Check Point Blog
B
Blog
V
V2EX
博客园 - 三生石上(FineUI控件)
MyScale Blog
MyScale Blog
The Cloudflare Blog
博客园 - 聂微东
博客园_首页
Engineering at Meta
Engineering at Meta

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
CRAG Implementation using TS
Tej Hagargi · 2026-05-16 · via DEV Community

import {
StateGraph,
Annotation,
MessagesAnnotation,
END,
} from "@langchain/langgraph";
import { ChatOpenAI } from "@langchain/openai";
import { HumanMessage, SystemMessage } from "@langchain/core/messages";
import { PineconeStore } from "@langchain/pinecone";
import { embeddings } from "./embeddings";
import { promptTemplate } from "./ragPrompt";

const model = new ChatOpenAI({
modelName: "gpt-4",
temperature: 0,
openAIApiKey: process.env.OPENAI_API_KEY,
});

let vectorStore: PineconeStore | null = null;

async function getVectorStore() {
console.log("[CRAG] getVectorStore called, cached:", !!vectorStore);
if (!vectorStore) {
const { pineconeIndex } = await import("./pinecone");
vectorStore = await PineconeStore.fromExistingIndex(embeddings, {
pineconeIndex,
});
console.log("[CRAG] vectorStore initialized");
}
return vectorStore;
}

const CRAGState = Annotation.Root({
...MessagesAnnotation.spec,
question: Annotation({ reducer: (, b) => b, default: () => "" }),
namespace: Annotation({ reducer: (
, b) => b, default: () => "" }),
documents: Annotation({ reducer: (, b) => b, default: () => [] }),
retrievalGrade: Annotation({
reducer: (
, b) => b,
default: () => "",
}),
rewrittenQuestion: Annotation({
reducer: (, b) => b,
default: () => "",
}),
answer: Annotation({ reducer: (
, b) => b, default: () => "" }),
retryCount: Annotation({ reducer: (_, b) => b, default: () => 0 }),
});

async function retrieve(state: typeof CRAGState.State) {
console.log("[CRAG] retrieve node started");
const store = await getVectorStore();
const query = state.rewrittenQuestion || state.question;
console.log("[CRAG] retrieve query:", query, "namespace:", state.namespace);
const results = await store.similaritySearch(query, 5, {
namespace: state.namespace,
});
const docs = results.map((doc) => doc.pageContent);
console.log("[CRAG] retrieve got", docs.length, "docs");
return { documents: docs };
}

async function gradeDocuments(state: typeof CRAGState.State) {
console.log("[CRAG] LLM grading retrieval...");

const context = state.documents.join("\n\n");

const response = await model.invoke([
new SystemMessage(`
You are a retrieval evaluator.

Determine whether the retrieved documents
are relevant enough to answer the user's question.

Reply ONLY with:

  • good
  • bad
    `),

    new HumanMessage(`
    Question:
    ${state.question}

Retrieved Documents:
${context}
`),
]);

const grade =
typeof response.content === "string"
? response.content.toLowerCase().trim()
: "bad";

console.log("[CRAG] LLM grade:", grade);

return {
retrievalGrade: grade,
};
}

async function rewriteQuery(state: typeof CRAGState.State) {
console.log("[CRAG] rewriteQuery node started");
const response = await model.invoke([
new SystemMessage("Rewrite the user's query to improve vector retrieval."),
new HumanMessage(state.question),
]);
const rewritten =
typeof response.content === "string" ? response.content : state.question;
console.log("[CRAG] rewriteQuery new query:", rewritten);
return { rewrittenQuestion: rewritten, retryCount: state.retryCount + 1 };
}

async function generateAnswer(state: typeof CRAGState.State) {
console.log("[CRAG] generateAnswer node started");
const combinedContext = state.documents.join("\n\n");
const formattedPrompt = await promptTemplate.format({
context: combinedContext,
});
const response = await model.invoke([
new SystemMessage(formattedPrompt),
new HumanMessage(state.question),
]);
const answer = typeof response.content === "string" ? response.content : "";
console.log("[CRAG] generateAnswer produced answer length:", answer.length);
return { answer, messages: [response] };
}

function shouldRetry(state: typeof CRAGState.State) {
console.log(
"[CRAG] shouldRetry grade:",
state.retrievalGrade,
"retryCount:",
state.retryCount,
);
if (state.retryCount >= 2) return "generate";
if (state.retrievalGrade === "bad") return "rewrite_query";
return "generate";
}

console.log("[CRAG] Graph compiled");
export const cragGraph = new StateGraph(CRAGState)
.addNode("retrieve", retrieve)
.addNode("grade_documents", gradeDocuments)
.addNode("rewrite_query", rewriteQuery)
.addNode("generate", generateAnswer)
.addEdge("start", "retrieve")
.addEdge("retrieve", "grade_documents")
.addConditionalEdges("grade_documents", shouldRetry, {
rewrite_query: "rewrite_query",
generate: "generate",
})
.addEdge("rewrite_query", "retrieve")
.addEdge("generate", END)
.compile();