Video hướng dẫn Phần 1 bấm vào đây
Xem Khóa Học và Lộ Trình Chi Tiết bấm vào đây
Video hướng dẫn Phần 2 bấm vào đây
- Giới thiệu
- Kiến trúc hệ thống
- Yêu cầu hệ thống
- Cài đặt và Triển khai
- Chi tiết các Component
- Tài liệu tham khảo
Dự án này là một ứng dụng chat tích hợp mô hình ngôn ngữ lớn (LLM) sử dụng:
- Frontend: Next.js 15+ với App Router
- Backend: FastAPI
- LLM: Ollama với mô hình Qwen
- Database: SQLite với SQLModel
graph LR
A[User Query] --> B[FastAPI Backend]
B --> C[Template Engine]
C --> D[LangChain Chain]
D --> E[Ollama LLM]
D --> F[(SQLite DB)]
subgraph Template Processing
C --> G[PromptTemplate]
G --> H[Table Info]
H --> I[Question]
end
subgraph LangChain Pipeline
D --> J[llm_chain]
J --> K[StrOutputParser]
end
subgraph Database Operations
F --> L[Store Chat]
F --> M[Execute SQL]
end
- Docker và Docker Compose
- Node.js 18+ (cho development)
- Python 3.11+ (cho development)
- Git
git clone <repository-url>cd<project-folder>.
├── docker-compose.yml
├── fastapi/
│ ├── Dockerfile
│ ├── app.py
│ ├── requirements.txt
│ └── ...
├── nextjs-app/
│ ├── Dockerfile
│ ├── package.json
│ └── ...
└── ollama/
├── Dockerfile
└── pull-qwen.sh
version: '3.8'services:
frontend:
build: ./nextjs-appports:
- "3000:3000"volumes:
- ./nextjs-app:/appdepends_on:
- backendbackend:
build: ./fastapiports:
- "8000:8000"volumes:
- ./fastapi:/appdepends_on:
- ollama-serverollama-server:
build: ./ollamavolumes:
- ollama_data:/root/.ollamadeploy:
resources:
reservations:
devices:
- driver: nvidiacount: 1capabilities: [gpu]volumes:
ollama_data:FastAPI backend xử lý các request từ frontend và tương tác với Ollama LLM. Code chính trong app.py:
importrequestsfromfastapiimportFastAPI, Response# Databasefromdbimport (
create_chat,
get_all_chats,
get_chat_by_id,
delete_chat,
DataChat,
path_db
@app.get('/ask')
defask(prompt :str):
# Langchainfromlangchain_ollamaimportOllamaLLM# Ollama modelfromlangchain_ollama.llmsimportBaseLLM# Lớp cơ sở của LLMfromlangchain.chains.llmimportLLMChain# xử lí chuỗi các LLMfromlangchain.chains.sql_database.queryimportcreate_sql_query_chain# tạo câu truy vấn cơ sở dữ liệu từ llmfromlangchain.promptsimportPromptTemplate# tạo câu truy vấn từ mẫufromlangchain_community.toolsimportQuerySQLDataBaseTool# công cụ truy vấn cơ sở dữ liệufromlangchain.sql_databaseimportSQLDatabase# cơ sở dữ liệufromlangchain_core.output_parsersimportStrOutputParser, PydanticOutputParser# xử lí kết quả trả về là kiểu dữ liệu chuỗifromlangchain_core.runnablesimportRunnablePassthrough# truyền đa dạng đối sốfromoperatorimportitemgetter# lấy giá trị từ dict# Cachefromlangchain.cacheimportInMemoryCachefromlangchain.globalsimportset_llm_cache#--------------------------------------------------llm=OllamaLLM(
# Utilityfromutilsimportget_sql_from_answer_llm
)
#test on dockerurl_docker="http://ollama-server:11434"#test on localurl_local="http://localhost:11434"model="qwen2.5-coder:0.5b"app=FastAPI()
llm=OllamaLLM(
base_url=url_local, model=model
)
@app.get('/')cache=InMemoryCache()
set_llm_cache(cache)
@app.get('/ask')template=PromptTemplate.from_template(
""" Từ các bảng cơ sở dữ đã có: {tables} Tạo câu truy vấn cơ sở dữ liệu từ câu hỏi sau: {question} Trả lời ở đây: """
)
# nếu câu hỏi không liên quan đến các bảng cơ sở dữ liệu đã có thì trả lời là "Không liên quan đến các bảng cơ sở dữ liệu đã có", và nếu câu hỏi gây nguy hiểm đến cơ sở dữ liệu thì trả lời là "Không thể trả lời câu hỏi này"llm_chain= (
template|llm|StrOutputParser()
)
db=SQLDatabase.from_uri(f"sqlite:///{path_db}")
app=FastAPI()
@app.get('/')defhome():
return {"hello" : "World"}
@app.get('/ask')defask(prompt :str):
# name of the service is ollama-server, is hostname by bridge to connect same network# res = requests.post('http://ollama-server:11434/api/generate', json={# "prompt": prompt,# "stream" : False,# "model" : "qwen2.5-coder:0.5b"# })res=llm_chain.invoke({
"tables": f'''{db.get_table_info(db.get_usable_table_names())}''',
"question": prompt
})
response=""ifisinstance(res, str):
response=reselse:
response=res.text# Store chat in databasechat=create_chat(message=prompt, response=response)
try:
data_db=db.run(get_sql_from_answer_llm(response))
exceptExceptionase:
data_db=str(e)
return {
"answer": response, "data_db": data_db
}Giải thích các thành phần chính:
- Sử dụng LangChain để tương tác với Ollama
- Cache LLM responses để tối ưu performance
- Xử lý SQL queries từ user input
- Error handling cho database operations
Ollama server chạy mô hình Qwen và expose API. Setup trong pull-qwen.sh:
./bin/ollama serve &
pid=$!
sleep 5
echo"Pulling qwen2.5-coder model"
ollama pull qwen2.5-coder:0.5b
wait$pidFrontend sử dụng Next.js 13+ với App Router và Tailwind CSS. Tham khảo cấu hình trong:
{
"name": "nextjs-app",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"react": "19.0.0-rc-66855b96-20241106",
"react-dom": "19.0.0-rc-66855b96-20241106",
"next": "15.0.3"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"postcss": "^8",
"tailwindcss": "^3.4.1"
}
}- FastAPI Documentation
- Next.js Documentation
- Ollama GitHub
- LangChain Documentation
- SQLModel Documentation
Vui lòng đọc CONTRIBUTING.md để biết thêm chi tiết về quy trình đóng góp code.
Dự án này được phân phối dưới giấy phép MIT. Xem file LICENSE để biết thêm chi tiết.

