feat: solution for 'Повторный экзамен: FAQ-бот — ChromaDB + один MCP-tool'
This commit is contained in:
@@ -1,25 +1,50 @@
|
|||||||
# Повторный экзамен: FAQ-бот — ChromaDB + один MCP-tool
|
# FAQ Bot with ChromaDB and LangChain
|
||||||
|
|
||||||
Главная
|
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.
|
||||||
Мои задания
|
|
||||||
Повторный экзамен: FAQ-бот — ChromaDB + один MCP-tool
|
|
||||||
5Д
|
|
||||||
EN
|
|
||||||
Повторный экзамен: FAQ-бот — ChromaDB + один MCP-tool
|
|
||||||
Зачёт
|
|
||||||
Версия 5
|
|
||||||
Дедлайн сдачи: 31.08.2026
|
|
||||||
|
|
||||||
В работе
|
## 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 с Ollama‑embed‑text, а также корректной интеграции 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
|
||||||
@@ -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
@@ -1,3 +1,4 @@
|
|||||||
chromadb==0.4.24
|
langchain-community
|
||||||
ollama==0.1.0
|
chromadb
|
||||||
mcp-tools==0.1.0
|
openai
|
||||||
|
dotenv
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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));
|
||||||
@@ -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],
|
||||||
|
}));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user