feat: solution for 'Агент с RAG-памятью'
CI / build (push) Has been cancelled

This commit is contained in:
2026-06-28 12:54:50 +03:00
parent a8a8111eca
commit a811a5c07d
7 changed files with 175 additions and 148 deletions
+23 -50
View File
@@ -1,57 +1,30 @@
# Agent with RAG Memory # Агент с RAG-памятью
This project demonstrates a simple LangChain agent that uses Retrieval-Augmented Generation (RAG) to answer questions based on a small set of documents. The implementation is written in TypeScript and follows the latest LangChain initialization patterns. Главная
Мои задания
Агент с RAG-памятью
EN
Агент с RAG-памятью
Зачёт
Версия 9
Дедлайн сдачи: 31.08.2026
## Features В работе
- **Updated Agent Initialization**: Uses `initializeAgentExecutorWithOptions` from LangChain. Требуется доработка
- **Custom Text Splitter**: Configured with a chunk size of 1000 characters and an overlap of 200 characters.
- **RAG Memory**: Embeddings are stored in a FAISS vector store and queried via a RetrievalQA chain.
- **Simple Test Harness**: Runs a sample query and prints the agent's response.
## Prerequisites Решение не соответствует ключевым требованиям задания: отсутствуют требуемые инструменты, некорректно реализован CLI и README содержит неверную информацию. Необходимо внести исправления.
- Node.js v18 or newer Редактирование ответа
- npm
## Setup Заполните ответ и отправьте работу на проверку преподавателю.
```bash Тип ответа
# Clone the repository Текст
git clone https://github.com/your-username/agent-rag-memory.git Ссылка
cd agent-rag-memory Файлы
Ссылка (URL)
# Install dependencies Прикреплённые файлы
npm install Загрузить файл
Отправить
# Create a .env file with your OpenAI API key
echo "OPENAI_API_KEY=your_api_key_here" > .env
```
## Running the Agent
```bash
npm start
```
You should see output similar to:
```
=== Agent Response ===
Paris
```
## Project Structure
```
agent-rag-memory/
├── src/
│ └── index.ts # Main implementation
├── package.json
├── tsconfig.json
└── README.md
```
## License
MIT License
+16 -18
View File
@@ -1,26 +1,24 @@
{ {
"name": "agent-rag-memory", "name": "rag-agent",
"version": "1.0.0", "version": "1.0.0",
"description": "A simple LangChain agent with RAG memory implemented in TypeScript", "description": "A simple RAG agent with memory using OpenAI and FAISS",
"main": "dist/index.js", "main": "src/index.js",
"type": "commonjs", "bin": {
"scripts": { "rag-agent": "./src/cli.js"
"build": "tsc", },
"start": "ts-node src/index.ts" "scripts": {
"start": "node src/cli.js"
}, },
"keywords": [
"langchain",
"rag",
"agent",
"typescript"
],
"author": "Your Name", "author": "Your Name",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/node": "^20.11.0", "@langchain/core": "^0.0.0",
"langchain": "^0.0.202", "@langchain/openai": "^0.0.0",
"openai": "^4.20.0", "@langchain/textsplitter": "^0.0.0",
"ts-node": "^10.9.1", "@langchain/vectorstores": "^0.0.0",
"typescript": "^5.3.3" "commander": "^10.0.0",
"dotenv": "^16.0.0",
"faiss-node": "^1.0.0",
"fs-extra": "^11.0.0"
} }
} }
+29 -11
View File
@@ -1,14 +1,32 @@
const { getChatCompletion } = require('./utils'); const { OpenAI } = require('@langchain/openai');
const retriever = require('./retriever'); const { RetrievalQAChain } = require('@langchain/chains');
const { initVectorStore } = require('./vectorStore');
require('dotenv').config();
async function ask(question) { class Agent {
const passages = await retriever.getRelevantPassages(question, 3); constructor() {
const context = passages.join('\n---\n'); this.llm = new OpenAI({
const prompt = `You are an assistant. Use the following context to answer the question.\n\nContext:\n${context}\n\nQuestion: ${question}\nAnswer:`; temperature: 0.7,
const answer = await getChatCompletion(prompt); openAIApiKey: process.env.OPENAI_API_KEY,
return answer; });
this.vectorStore = null;
this.chain = null;
} }
module.exports = { async init() {
ask, if (!this.vectorStore) {
}; this.vectorStore = await initVectorStore();
}
if (!this.chain) {
this.chain = RetrievalQAChain.fromLLM(this.llm, this.vectorStore.asRetriever());
}
}
async ask(question) {
await this.init();
const result = await this.chain.invoke({ question });
return result.output;
}
}
module.exports = new Agent();
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env node
require('dotenv').config();
const { program } = require('commander');
const { addDocumentFromFile, clearMemory, agent } = require('./tools');
program
.name('rag-agent')
.description('CLI for a RAG agent with OpenAI and FAISS')
.version('1.0.0');
program
.command('add <file>')
.description('Add a document to the vector store')
.action(async (file) => {
try {
await addDocumentFromFile(file);
} catch (err) {
console.error('Error adding document:', err.message);
}
});
program
.command('query <question...>')
.description('Ask a question to the agent')
.action(async (question) => {
try {
const answer = await agent.ask(question.join(' '));
console.log('Answer:', answer);
} catch (err) {
console.error('Error querying agent:', err.message);
}
});
program
.command('clear')
.description('Clear all stored memory')
.action(async () => {
try {
await clearMemory();
} catch (err) {
console.error('Error clearing memory:', err.message);
}
});
program.parseAsync(process.argv);
+1 -43
View File
@@ -1,43 +1 @@
const readline = require('readline'); module.exports = require('./agent');
const agent = require('./agent');
const retriever = require('./retriever');
async function init() {
// Load knowledge base from ./knowledge directory
await retriever.loadKnowledgeBase('./knowledge');
console.log('Knowledge base loaded.');
}
async function main() {
await init();
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: 'You> ',
});
rl.prompt();
rl.on('line', async (line) => {
const trimmed = line.trim();
if (trimmed.toLowerCase() === 'exit') {
rl.close();
process.exit(0);
}
try {
const answer = await agent.ask(trimmed);
console.log(`Assistant: ${answer}\n`);
} catch (err) {
console.error(`Error: ${err.message}\n`);
}
rl.prompt();
});
rl.on('close', () => {
console.log('Goodbye!');
process.exit(0);
});
}
main();
+29
View File
@@ -0,0 +1,29 @@
const fs = require('fs');
const { RecursiveCharacterTextSplitter } = require('@langchain/textsplitter');
const { addDocuments, clearVectorStore } = require('./vectorStore');
const agent = require('./agent');
async function addDocumentFromFile(filePath) {
if (!fs.existsSync(filePath)) {
throw new Error(`File not found: ${filePath}`);
}
const content = fs.readFileSync(filePath, 'utf-8');
const splitter = new RecursiveCharacterTextSplitter({
chunkSize: 1000,
chunkOverlap: 200,
});
const docs = await splitter.splitText(content);
await addDocuments(docs);
console.log(`Added ${docs.length} chunks from ${filePath}`);
}
async function clearMemory() {
await clearVectorStore();
console.log('Cleared vector store memory.');
}
module.exports = {
addDocumentFromFile,
clearMemory,
agent,
};
+32 -26
View File
@@ -1,33 +1,39 @@
class VectorStore { const { FAISS } = require('@langchain/vectorstores/faiss');
constructor() { const { OpenAIEmbeddings } = require('@langchain/openai');
this.documents = []; const fs = require('fs');
const path = require('path');
require('dotenv').config();
const VECTORSTORE_DIR = path.join(__dirname, '..', 'data', 'vectorstore');
async function initVectorStore() {
if (!fs.existsSync(VECTORSTORE_DIR)) {
fs.mkdirSync(VECTORSTORE_DIR, { recursive: true });
}
const embeddings = new OpenAIEmbeddings({
openAIApiKey: process.env.OPENAI_API_KEY,
});
const vectorStore = await FAISS.load(embeddings, VECTORSTORE_DIR);
return vectorStore;
} }
addDocument(id, embedding, text) { async function addDocuments(texts) {
this.documents.push({ id, embedding, text }); const embeddings = new OpenAIEmbeddings({
openAIApiKey: process.env.OPENAI_API_KEY,
});
const vectorStore = await FAISS.load(embeddings, VECTORSTORE_DIR);
await vectorStore.addDocuments(texts);
await vectorStore.save();
} }
cosineSimilarity(a, b) { async function clearVectorStore() {
let dot = 0; if (fs.existsSync(VECTORSTORE_DIR)) {
let normA = 0; fs.rmdirSync(VECTORSTORE_DIR, { recursive: true });
let normB = 0;
for (let i = 0; i < a.length; i++) {
dot += a[i] * b[i];
normA += a[i] * a[i];
normB += b[i] * b[i];
}
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
}
query(queryEmbedding, k) {
const sims = this.documents.map((doc) => ({
doc,
similarity: this.cosineSimilarity(queryEmbedding, doc.embedding),
}));
sims.sort((a, b) => b.similarity - a.similarity);
return sims.slice(0, k).map((s) => s.doc);
} }
} }
const store = new VectorStore(); module.exports = {
module.exports = store; initVectorStore,
addDocuments,
clearVectorStore,
};