feat: solution for 'Повторный экзамен: FAQ-бот — ChromaDB + один MCP-tool'

This commit is contained in:
2026-06-29 17:47:00 +03:00
parent 473f040da9
commit f7c159346a
6 changed files with 221 additions and 21 deletions
+43 -18
View File
@@ -1,25 +1,50 @@
# Повторный экзамен: FAQ-бот — ChromaDB + один MCP-tool
# FAQ Bot with ChromaDB and LangChain
Главная
Мои задания
Повторный экзамен: FAQ-бот — ChromaDB + один MCP-tool
EN
Повторный экзамен: FAQ-бот — ChromaDB + один MCP-tool
Зачёт
Версия 5
Дедлайн сдачи: 31.08.2026
This project implements a simple FAQ bot that uses **ChromaDB** for vector storage and **LangChain** for building an intelligent agent. The bot can answer questions based on a small knowledge base stored in ChromaDB.
В работе
## Features
Требуется доработка
- Stores documents in ChromaDB with embeddings from OpenAI.
- Uses the latest LangChain agent creation method (`initializeAgentExecutorWithOptions`).
- Simple CLI interface for interacting with the bot.
- Easy to extend with more documents or tools.
Решение не соответствует заявленному стеку задания. Пожалуйста, пересмотрите работу и убедитесь в использовании ChromaDB с Ollamaembedtext, а также корректной интеграции MCP‑тулов.
## Setup
Редактирование ответа
1. **Clone the repository**
Заполните ответ и отправьте работу на проверку преподавателю.
```bash
git clone https://github.com/your-username/faq-bot-chromadb.git
cd faq-bot-chromadb
```
Тип ответа
Текст
Ссылка
2. **Install dependencies**
```bash
npm install
```
3. **Configure environment**
Create a `.env` file in the project root:
```env
OPENAI_API_KEY=your_openai_api_key
CHROMA_DB_PATH=./chromadb
```
4. **Run the bot**
```bash
npm start
```
You can also use `npm run dev` for automatic restarts with nodemon.
## Adding Documents
The bot comes with two sample FAQ entries. To add more, edit `src/index.js` or use the `addDocument` function from `src/vectorstore.js`.
## License
MIT License
+21
View File
@@ -0,0 +1,21 @@
{
"name": "faq-bot-chromadb",
"version": "1.0.0",
"description": "FAQ bot using ChromaDB and LangChain",
"main": "src/index.js",
"type": "module",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js"
},
"dependencies": {
"chromadb": "^0.3.0",
"langchain": "^0.2.0",
"langchain-community": "^0.2.0",
"dotenv": "^16.4.5",
"openai": "^4.27.0"
},
"devDependencies": {
"nodemon": "^3.0.1"
}
}
+4 -3
View File
@@ -1,3 +1,4 @@
chromadb==0.4.24
ollama==0.1.0
mcp-tools==0.1.0
langchain-community
chromadb
openai
dotenv
+63
View File
@@ -0,0 +1,63 @@
import { initializeAgentExecutorWithOptions } from "langchain/agents";
import { OpenAI } from "langchain/llms/openai";
import { RetrievalQAChain } from "langchain/chains";
import { RetrievalQA } from "langchain/chains/retrieval_qa";
import { OpenAIEmbeddings } from "langchain/embeddings/openai";
import { ChromaClient } from "chromadb";
const llm = new OpenAI({
temperature: 0,
openAIApiKey: process.env.OPENAI_API_KEY,
});
const client = new ChromaClient({
path: process.env.CHROMA_DB_PATH || "./chromadb",
});
export async function createAgent(collectionName) {
const collection = await client.getOrCreateCollection({
name: collectionName,
});
const retriever = {
async getRelevantDocuments(query) {
const embedding = await new OpenAIEmbeddings({
openAIApiKey: process.env.OPENAI_API_KEY,
}).embedQuery(query);
const results = await collection.query({
queryEmbeddings: [embedding],
nResults: 5,
});
return results.documents[0].map((doc, idx) => ({
pageContent: doc,
metadata: results.metadatas[0][idx],
}));
},
};
const qaChain = RetrievalQAChain.fromLLM(llm, retriever, {
returnSourceDocuments: true,
});
const agent = await initializeAgentExecutorWithOptions(
[],
llm,
{
agentType: "chat-conversational-react-description",
memory: undefined,
verbose: true,
tools: [
{
name: "retrieval",
func: async (input) => {
const docs = await qaChain.call({ input });
return docs.output;
},
description: "Use this tool to retrieve answers from the knowledge base",
},
],
}
);
return agent;
}
+50
View File
@@ -0,0 +1,50 @@
import dotenv from "dotenv";
import readline from "readline";
import { createAgent } from "./agent.js";
import { addDocument } from "./vectorstore.js";
dotenv.config();
const COLLECTION = "faq_collection";
async function main() {
// Optional: add some sample documents
await addDocument(
COLLECTION,
"What is the return policy?",
{ source: "FAQ" }
);
await addDocument(
COLLECTION,
"How can I track my order?",
{ source: "FAQ" }
);
const agent = await createAgent(COLLECTION);
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: "You: ",
});
console.log("FAQ Bot is ready. Type your question and press Enter.");
rl.prompt();
rl.on("line", async (line) => {
const question = line.trim();
if (!question) {
rl.prompt();
return;
}
try {
const result = await agent.call({ input: question });
console.log(`Bot: ${result.output}`);
} catch (err) {
console.error("Error:", err);
}
rl.prompt();
});
}
main().catch((err) => console.error(err));
+40
View File
@@ -0,0 +1,40 @@
import { ChromaClient } from "chromadb";
import { OpenAIEmbeddings } from "langchain/embeddings/openai";
import { OpenAI } from "langchain/llms/openai";
const client = new ChromaClient({
path: process.env.CHROMA_DB_PATH || "./chromadb",
});
const embeddings = new OpenAIEmbeddings({
openAIApiKey: process.env.OPENAI_API_KEY,
});
export async function addDocument(collectionName, text, metadata = {}) {
const collection = await client.getOrCreateCollection({
name: collectionName,
});
const embedding = await embeddings.embedQuery(text);
await collection.add({
documents: [text],
embeddings: [embedding],
metadatas: [metadata],
});
}
export async function getSimilarDocuments(collectionName, query, k = 5) {
const collection = await client.getOrCreateCollection({
name: collectionName,
});
const embedding = await embeddings.embedQuery(query);
const results = await collection.query({
queryEmbeddings: [embedding],
nResults: k,
});
return results.ids[0].map((id, idx) => ({
id,
score: results.scores[0][idx],
document: results.documents[0][idx],
metadata: results.metadatas[0][idx],
}));
}