Tìm hiểu Embedding là gì và cách sử dụng chúng trong ứng dụng AI với TypeScript, PostgreSQL và pgvector. Giải thích các khái niệm phức tạp một cách đơn giản, hài hước và dễ hiểu.
Hướng dẫn chi tiết xây dựng pipeline tự động hóa xử lý PDF, tạo embeddings với OpenAI và lưu trữ vào Zilliz Cloud, sử dụng AWS Lambda và CircleCI cho CI/CD.
Timescale công bố benchmark ấn tượng: Postgres với pgvector và pgvectorscale vượt trội Qdrant trong tìm kiếm vector trên 50 triệu embeddings, chứng minh khả năng xử lý AI mạnh mẽ mà không cần database chuyên biệt.
Thật lòng mà nói – ai trong chúng ta mà chẳng từng trải qua cảm giác đó, đúng không? Bạn đang cố gắng tìm một cái meme cực phẩm để diễn tả nỗi sợ hãi tột độ với sáng thứ Hai cà phê chưa pha, nhưng dù có gõ đủ kiểu từ khóa thì cũng chỉ toàn ra ảnh mèo không liên quan. Nào, xin giới thiệu 'tìm kiếm ngữ nghĩa' (semantic search) – công nghệ cuối cùng đã hiểu được những truy vấn tìm kiếm 'hỗn loạn' của bạn! Trong bài viết này, tôi sẽ bật mí cách tôi đã xây dựng một công cụ tìm kiếm meme mà nó thực sự 'bắt được sóng' câu chuyện, sử dụng chút 'phép thuật' công nghệ xịn sò (và những công cụ đỉnh cao của Upstash nữa đó!). Upstash không chỉ cung cấp một cơ sở dữ liệu vector (vector database) siêu xịn, cho phép bạn tìm kiếm sự tương đồng giữa các vector một cách cực kỳ linh hoạt và mở rộng. Nó còn có cả tính năng lọc metadata và các mô hình nhúng (embedding models) tích hợp sẵn, tiện lợi hết sức! Chưa hết, Upstash Redis còn là một 'phù thủy' trong việc lưu cache và giới hạn tốc độ truy cập (rate limiting), biến nó thành nền tảng lý tưởng cho các ứng dụng được hỗ trợ bởi AI hiện đại. Trong bài viết này, tôi sẽ cùng bạn khám phá hành trình chúng ta đã tạo ra một công cụ tìm kiếm meme ngữ nghĩa sử dụng Upstash Vector và Redis. Bạn sẽ thấy rõ những công cụ mạnh mẽ này có thể giúp chúng ta xây dựng trải nghiệm tìm kiếm hiệu quả và thân thiện với người dùng đến thế nào! Bạn có thể tự mình 'mò' mã nguồn của dự án trên <a href="https://github.com/akifitu/ai-meme-search-engine">GitHub</a> hoặc triển khai thẳng lên tài khoản Vercel của riêng bạn. <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/meme_search_problem.png' alt='Tìm kiếm meme truyền thống thất bại'> <b>Khi từ khóa 'bất lực': Nỗi niềm tìm kiếm meme</b> Tìm kiếm bằng từ khóa truyền thống sẽ 'ngon ơ' khi bạn biết chính xác mình muốn gì. Ví dụ: gõ 'Mèo cáu kỉnh' (Grumpy Cat) là ra ngay ảnh mèo cáu kỉnh. Dễ ợt! Nhưng meme thì lại sống trong một thế giới 'kỳ cục' giữa nghĩa đen và bối cảnh văn hóa. Thử tìm kiếm 'cảm giác khi WiFi chết giữa cuộc gọi Zoom' xem, bạn sẽ nhanh chóng thấy giới hạn của việc chỉ dựa vào từ khóa thôi là không đủ. Đó chính là lúc tìm kiếm ngữ nghĩa tỏa sáng! Nó giống như việc bạn có một người bạn cực kỳ am hiểu 'văn hóa meme'. Bạn chỉ cần nói 'Tao cần cái gì đó cho cảm giác trưởng thành khó quá', và họ sẽ đưa cho bạn 10 biến thể của meme 'Chó này vẫn ổn' (This is Fine) mà không cần chớp mắt. Và đó chính xác là thứ chúng ta đang xây dựng ở đây đó! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/semantic_search_brain.png' alt='Tìm kiếm ngữ nghĩa hiểu bối cảnh'> <b>Bộ công cụ công nghệ: Vì sao lại chọn những cái tên này?</b> <ul><li><b>Next.js 15:</b> Vì ai mà muốn 'đau đầu' với những thiết lập phức tạp chứ? Tích hợp API routes siêu tốc + sự 'ngon lành' của React = lập trình viên hạnh phúc.</li><li><b>Upstash Vector:</b> Giống như một bộ não biết ghi nhớ mối quan hệ giữa các khái niệm (nhưng rẻ hơn não thật nhiều!).</li><li><b>Upstash Redis:</b> 'Con dao Thụy Sĩ' trong thế giới database – xử lý mượt mà việc lưu cache và ngăn người dùng 'spam' API của chúng ta.</li><li><b>LLM API:</b> Để tạo metadata (siêu dữ liệu) cho các hình ảnh meme. Có rất nhiều mô hình LLM khác nhau để bạn lựa chọn đó nha.</li><li><b>OpenAI Embeddings:</b> Không bắt buộc, bạn có thể dùng các mô hình AI khác (như của Hugging Face) nếu thích.</li><li><b>Vercel Blob:</b> Nơi 'cất giữ' tất cả những meme 'nóng hổi' mà không cần phải 'bơi' trong mớ cấu hình S3 phức tạp.</li></ul> <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/llm_metadata_generation.png' alt='LLM tạo metadata cho hình ảnh'> <b>Tạo metadata cho ảnh meme</b> Trước khi tạo vector nhúng (embedding vectors) cho các ảnh meme trong tập dữ liệu, chúng ta cần tạo metadata đầy đủ cho từng ảnh. Để làm được điều này, tôi đã tận dụng API LLM của OpenAI để tự động gắn nhãn cho tất cả ảnh với 9 thông số chính: đường dẫn (path - được lưu trữ trên Vercel), tiêu đề (title), mô tả (description), thẻ (tags), ngữ cảnh meme (memeContext), độ hài hước (humor), định dạng (format), nội dung văn bản (textContent), nhân vật (person) và đối tượng (objects). Thử thách ở đây là phải nắm bắt được cả nội dung hình ảnh lẫn văn bản được nhúng trong meme. Dưới đây là một ví dụ về việc gắn thẻ metadata: <code>{"path":"https://kqznk1deju1f3qri.public.blob.vercel-storage.com/another_%20Bugs%20Bunny_s%20_No_-D6ht580Nj0I8mri3hYLVIHnRx4DNIB.jpg","metadata":{"title":"Meme Bugs Bunny 'Không' với biểu cảm thách thức","description":"Meme này có hình Bugs Bunny, một nhân vật hoạt hình kinh điển từ series Looney Tunes, với biểu cảm thách thức. Bức ảnh là cận cảnh khuôn mặt Bugs Bunny, cho thấy anh ta với đôi mắt lim dim và miệng hơi mở, truyền tải sự thờ ơ hoặc từ chối. Từ 'không' được hiển thị bằng chữ trắng đậm, nhấn mạnh thái độ bác bỏ của anh ta. Meme này thường được dùng để thể hiện sự từ chối dứt khoát một cách hài hước. Phong cách hoạt hình giữa thế kỷ 20 làm tăng thêm sự hoài niệm.","tags":["Bugs Bunny","Looney Tunes","hoạt hình","meme","không","từ chối","thách thức","hài hước","hoạt họa","kinh điển","hoài niệm","biểu cảm","bác bỏ","khước từ","chữ đậm"],"memeContext":"Một khung hình từ Looney Tunes được tái sử dụng để truyền tải sự từ chối hài hước trong các cuộc trò chuyện trực tuyến, tận dụng tính cách hóm hỉnh của Bugs Bunny.","humor":"Sự từ chối phóng đại bằng một nhân vật được yêu mến, với sự đơn giản làm tăng hiệu ứng hài hước.","format":"Meme Bugs Bunny 'Không'","textContent":"không","person":"Bugs Bunny, nhân vật hoạt hình","objects":"Bugs Bunny, chữ 'không'"}}</code> LLM đã phân tích cả yếu tố hình ảnh (ví dụ: biểu cảm nhân vật, vị trí văn bản) và bối cảnh văn hóa (ví dụ: sức hấp dẫn hoài cổ của Bugs Bunny) để tạo ra metadata phong phú, thân thiện với tìm kiếm. <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/embedding_vectors.png' alt='Mô tả vector nhúng'> <b>Chuẩn bị các vector nhúng (Embeddings)</b> Đối với công cụ tìm kiếm meme của chúng ta, chúng tôi tự tạo các vector nhúng bằng mô hình <code>text-embedding-3-small</code> của OpenAI. Nhưng tôi khuyến khích bạn thử các mô hình nhúng khác để xem sự đa dạng nhé! Mỗi meme được đại diện bằng cách nhúng tiêu đề và mô tả của nó: <code>export const generateEmbedding = async (value: string): Promise<number[]> => { const input = value.replaceAll("\n", " "); const { embedding } = await embed({ model: embeddingModel, value: input, }); return embedding;};</code> <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://dev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ihm4e1fb3a9cxj8rsvj.png' alt='Thiết lập cơ sở dữ liệu vector với Upstash'> <b>Đánh chỉ mục các Vector</b> Đối với công cụ tìm kiếm meme, chúng tôi đã tạo một cấu trúc chỉ mục đơn giản, nơi mỗi meme được đại diện bởi: <ul><li>Một vector nhúng của tiêu đề và mô tả của nó.</li><li>Metadata bao gồm tiêu đề, mô tả và đường dẫn hình ảnh.</li><li>Một ID duy nhất để truy xuất.</li></ul> Quá trình đánh chỉ mục thực tế được xử lý thông qua API của Upstash Vector: <code>// Khởi tạo client Upstash Vector với chỉ mục meme export const memesIndex = new Index({ url: process.env.UPSTASH_VECTOR_URL!, token: process.env.UPSTASH_VECTOR_TOKEN!,});</code> Không giống như các dự án lớn hơn có thể yêu cầu xử lý hàng loạt, cơ sở dữ liệu meme của chúng ta đủ nhỏ để được đánh chỉ mục hiệu quả mà không cần tối ưu hóa đặc biệt. Sự đơn giản của API Upstash Vector đã làm cho quá trình này trở nên cực kỳ dễ dàng. <b>Xây dựng Công cụ Tìm kiếm Meme</b> Chức năng tìm kiếm kết hợp cả tìm kiếm tương đồng vector và đối sánh văn bản trực tiếp (và loại bỏ nếu có trùng lặp): <code>// Đối với các truy vấn dài, thực hiện cả tìm kiếm trực tiếp và ngữ nghĩa const directMatches = await findMemesByQuery(query);const semanticMatches = await findSimilarMemes(query);// Kết hợp các kết quả, loại bỏ trùng lặp const allMatches = uniqueItemsByTitle([...directMatches, ...semanticMatches]);</code> Tìm kiếm vector tìm thấy nội dung có ý nghĩa tương tự: <code>export const findSimilarMemes = async (description: string): Promise<Meme[]> => { const embedding = await generateEmbedding(description); const results = await memesIndex.query({ vector: embedding, includeMetadata: true, topK: 60, includeVectors: false, }); return results.map((result: any) => ({ id: String(result.id), title: result.metadata?.title
Chào bạn, bạn có bao giờ tò mò làm thế nào để quản lý cơ sở dữ liệu vector một cách “siêu mượt” và tự động hóa toàn bộ quá trình tạo embeddings cho các ứng dụng AI không? Trong thời đại AI bùng nổ như hiện nay, việc tìm kiếm sự tương đồng, đề xuất thông minh hay truy xuất dữ liệu quy mô lớn đều phụ thuộc rất nhiều vào các vector database. Nhưng khi dữ liệu cứ “phình to” không ngừng, việc cập nhật embeddings mới thủ công chẳng khác nào “mò kim đáy bể”, vừa tốn thời gian lại dễ mắc lỗi. Đó là lúc chúng ta cần đến sự “phù phép” của tự động hóa! Trong bài viết này, tôi sẽ cùng bạn khám phá một “bí kíp” xây dựng quy trình tự động hoàn toàn để xử lý và cập nhật vector database, sử dụng bộ ba quyền lực: AWS Lambda, Docker và CircleCI. Chúng ta sẽ cùng nhau biến những file PDF khô khan thành embeddings “thông minh” bằng OpenAI, rồi lưu trữ chúng gọn gàng trong Zilliz Cloud – một cơ sở dữ liệu vector được quản lý cực kỳ tiện lợi. Đồng thời, chúng ta cũng sẽ “dựng nhà” trên AWS (với S3, ECR, Lambda) và triển khai một đường ống CI/CD “siêu tốc” bằng CircleCI để mọi thứ diễn ra tự động như một phép màu. Bạn sẽ học được gì sau chuyến hành trình này? Cách quản lý vector database và tự động hóa việc tạo embeddings. Xây dựng một hàm AWS Lambda để xử lý và cập nhật embeddings. “Đóng gói” hàm Lambda bằng Docker để chạy hiệu quả. Thiết lập CircleCI để tự động hóa kiểm thử và triển khai. Áp dụng các mẹo hay về vai trò IAM và bảo mật trên AWS. Sau khi đọc xong bài hướng dẫn này, bạn sẽ có trong tay một quy trình làm việc tự động hoàn chỉnh để xử lý và cập nhật vector embeddings một cách trơn tru, không cần động tay động chân! Bài viết này giả định bạn đã có chút “làm quen” với Python, AWS và Docker nhé. Bạn có thể xem toàn bộ mã nguồn trên GitHub nếu tò mò, nhưng tôi sẽ dẫn bạn đi từng bước một, không bỏ sót chi tiết nào đâu! https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/example_pipeline_diagram.png Trước khi bắt đầu: Chuẩn bị hành trang Để chuyến hành trình của chúng ta diễn ra suôn sẻ, bạn cần chuẩn bị một vài thứ nhỏ xinh sau đây: 1. **Tài khoản AWS:** Nếu chưa có, hãy đăng ký ngay một tài khoản AWS. Chúng ta sẽ cần đến AWS Lambda và Elastic Container Registry (ECR) để triển khai ứng dụng của mình đó. 2. **AWS CLI:** Đảm bảo bạn đã cài đặt và cấu hình AWS Command Line Interface (CLI) với các thông tin đăng nhập của mình. Nếu chưa, hãy tìm hướng dẫn cài đặt AWS CLI nhé. 3. **Kiến thức cơ bản về LangChain hoặc Vector Databases:** Việc hiểu biết những điều căn bản về LangChain và Vector Databases sẽ giúp bạn dễ dàng hình dung kiến trúc của quy trình này hơn. 4. **Làm quen với AWS Lambda và Docker:** Bạn nên biết những khái niệm cơ bản về AWS Lambda và Docker, vì chúng ta sẽ dùng chúng để “đóng gói” và triển khai ứng dụng. 5. **Tài khoản GitHub và CircleCI:** Hãy tạo tài khoản trên GitHub để quản lý mã nguồn và CircleCI để tự động hóa quy trình CI/CD “thần thánh” của chúng ta. 6. **OpenAI API Key:** Để “triệu hồi” các mô hình GPT của OpenAI, bạn sẽ cần một API key. Đăng ký một chiếc key trên website của OpenAI nhé. 7. **Tài khoản Zilliz Cloud:** Đăng ký một tài khoản Zilliz Cloud để “làm chủ” cơ sở dữ liệu vector của bạn. Bạn sẽ có một cụm miễn phí, cung cấp URI endpoint và Token để giao tiếp với nó. Sau khi đã “tích kê” đủ hết các thứ này, bạn đã sẵn sàng để cùng tôi thiết lập quy trình tự động rồi đó! https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/checklist_prerequisites.png Thiết lập cấu trúc dự án: Ngôi nhà của mã nguồn Trước khi “xắn tay áo” vào code, chúng ta cần xây dựng một “ngôi nhà” gọn gàng cho dự án của mình. Một cấu trúc dự án tốt sẽ giúp việc phát triển, kiểm thử và triển khai trở nên mượt mà hơn rất nhiều, đặc biệt là khi chúng ta làm việc với các dịch vụ đám mây và tự động hóa CI/CD. **Tổ chức dự án và các thành phần chính:** Dự án của bạn sẽ trông giống như một “gia đình” với các thành viên sau đây: * `.circleci/`: Nơi chứa “kịch bản” tự động hóa của CircleCI (config.yml). * `data/`: Thư mục chứa các file dữ liệu đầu vào, ví dụ như file PDF của chúng ta. * `src/`: Đây là “trái tim” của dự án, chứa các mã nguồn chính như `create_collection.py`, `drop_collection.py`, `insert_documents.py`. * `aws_lambda/`: Nơi ở của “bộ não” hệ thống – hàm Lambda `lambda_function.py`. * `scripts/`: Chứa các “người thực hiện kịch bản” là các shell script giúp tự động hóa các tác vụ AWS (`build_deploy.sh`, `create_roles.sh`, `create_image.sh`, `create_lambda.sh`). * `tests/`: “Đội ngũ kiểm định chất lượng” của chúng ta, với các file kiểm thử `test_collection_exists.py`, `test_lambda_function.py`, `test_collection_mock.py`. * `Dockerfile`: “Công thức đóng gói” hàm Lambda vào Docker container. * `pyproject.toml`: “Danh sách mua sắm” các thư viện cần dùng. https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/project_structure_diagram.png **Cài đặt các thư viện với UV Package Manager:** Đầu tiên, hãy “chép” toàn bộ mã nguồn về máy tính của bạn bằng cách clone repository: `git clone https://github.com/benitomartin/embeddings-aws-circlecicd embeddings-aws-circleci` *Lưu ý nhỏ:* Repository này đã có sẵn tất cả các đoạn mã mà chúng ta sẽ nhắc đến trong bài. Bạn không cần phải “khổ công” tạo lại từ đầu đâu nhé! Cứ theo dõi và so sánh là được. Và tất nhiên, bạn hoàn toàn có thể tùy chỉnh cấu trúc này cho phù hợp với dự án “cưng” của mình. Tiếp theo, chúng ta sẽ cài đặt tất cả các thư viện cần thiết bằng UV Package Manager. Nếu bạn chưa có UV, hãy xem hướng dẫn cài đặt của nó nhé: `uv sync --all-extras` `source .venv/bin/activate` Hai câu lệnh này sẽ giúp bạn cài đặt tất cả các “nguyên liệu” (dependencies) đã liệt kê trong file `pyproject.toml` và “kích hoạt” môi trường ảo của dự án. Đơn giản phải không? https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/uv_install.png Cấu hình môi trường: Sổ tay bí mật Hãy tạo một file `.env` ở thư mục gốc của dự án và thêm các biến môi trường sau vào đó. Hãy coi đây là “sổ tay bí mật” chứa các thông tin nhạy cảm của bạn, tuyệt đối không được chia sẻ lung tung nhé! `ZILLIZ_CLOUD_URI=your-zilliz-uri` `ZILLIZ_TOKEN=your-zilliz-token` `COLLECTION_NAME=your-collection-name` `PDF_BUCKET_NAME=your-bucket-name` `OPENAI_API_KEY=your-openai-key` `AWS_REGION=your-aws-region` `AWS_ACCESS_KEY_ID=your-access-key` `AWS_SECRET_ACCESS_KEY=your-secret-key` `AWS_ACCOUNT_ID=your-account-id` `LAMBDA_ECR_REPOSITORY_NAME=your-ecr-repo-name` `LAMBDA_IMAGE_NAME=your-image-name` `LAMBDA_FUNCTION_NAME=your-lambda-name` `ROLE_NAME=your-role-name` `ROLE_POLICY_NAME=your-policy-name` Hãy nhớ thay thế các giá trị `your-something` bằng thông tin thật của bạn nhé. Đây là “chìa khóa” để các dịch vụ của chúng ta có thể liên lạc với nhau! https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/env_file_security.png Thiết lập cơ sở dữ liệu vector: Kho lưu trữ “siêu trí nhớ” Để lưu trữ và truy xuất các embeddings một cách hiệu quả, chúng ta cần thiết lập một cơ sở dữ liệu vector. Phần này sẽ hướng dẫn bạn cấu hình Zilliz Cloud (Milvus), định nghĩa schema và tối ưu hóa cơ sở dữ liệu cho việc tìm kiếm vector nhanh chóng. **Thiết lập Collection trên Zilliz Cloud:** Zilliz Cloud là phiên bản Milvus được quản lý, một cơ sở dữ liệu vector hiệu suất cao. Chúng ta sẽ tạo một “collection” (tạm hiểu là một ngăn kéo chứa dữ liệu) để lưu trữ văn bản đã trích xuất và các embeddings vector tương ứng. Để tạo collection, bạn cần làm theo các bước sau: 1. Đăng ký và tạo một Cluster miễn phí trong Zilliz Cloud. 2. Lấy thông tin kết nối: * **URI:** Tìm thấy trong cài đặt cluster (public endpoint). * **Token:** Cần cho việc xác thực. 3. Đặt các biến môi trường vào file `.env` của bạn và cung cấp một tên cho collection: `ZILLIZ_CLOUD_URI=your-zilliz-uri` `ZILLIZ_TOKEN=your-zilliz-token` `COLLECTION_NAME=your-collection-name` https://truyentranh.letranglan.top/api/v1/proxy?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fga1zq0ki32z7plrjkzk0.png **Tạo Collection:** Khi đã có thông tin kết nối, bạn có thể tạo một collection trong Zilliz Cloud. Collection này sẽ lưu trữ văn bản đã trích xuất và các embeddings vector tương ứng. Trong thư mục `src`, bạn có thể tạo một script tên là `create_collection.py` với vài hàm để định nghĩa schema và tạo collection: * `create_schema`: Định nghĩa schema, bao gồm: * `id`: Khóa chính tự động tạo (INT64). * `pdf_text`: Văn bản được trích xuất, lưu dưới dạng VARCHAR. * `my_vector`: Embeddings vector, lưu dưới dạng FLOAT_VECTOR (chiều mặc định: 1536). * `create_collection`: Tạo collection trong Zilliz Cloud với schema đã định nghĩa. Nó tối ưu hóa việc tìm kiếm vector bằng cách thiết lập AUTOINDEX với độ tương đồng COSINE, đảm bảo truy xuất hiệu quả. ```python import os from typing import Optional from pymilvus import DataType, MilvusClient def create_schema(dimension: int = 1536) -> MilvusClient.create_schema: """Define the schema for the Milvus collection.""" schema = MilvusClient.create_schema( auto_id=True, enable_dynamic_field=True, ) schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True) schema.add_field(field_name="pdf_text", datatype=DataType.VARCHAR, max_length=65535) schema.add_field(field_name="my_vector", datatype=DataType.FLOAT_VECTOR, dim=dimension) return schema def create_collection( collection_name: Optional[str] = None, uri: Optional[str] = None, token: Optional[str] = None, dimension: int = 1536, ) -> None: """Create a new Milvus collection with the specified parameters. Args: collection_name (str, optional): Name of the collection. Defaults to env var COLLECTION_NAME. uri (str, optional): Zilliz Cloud URI. Defaults to env var ZILLIZ_CLOUD_URI. token (str, optional): Zilliz token. Defaults to env var ZILLIZ_TOKEN. dimension (int, optional): Vector dimension. Defaults to 1536. """ # Use environment variables as fallback collection_name = collection_name or os.getenv("COLLECTION_NAME") uri = uri or os.getenv("ZILLIZ_CLOUD_URI") token = token or os.getenv("ZILLIZ_TOKEN") if not all([collection_name, uri, token]): raise ValueError("Missing required parameters: collection_name, uri, or token") # Connect to Zilliz Cloud (Milvus) client = MilvusClient(uri=uri, token=token) # Create schema schema = create_schema(dimension) # Prepare index parameters index_params = client.prepare_index_params() index_params.add_index(field_name="my_vector", index_type="AUTOINDEX", metric_type="COSINE") # Create collection client.create_collection(collection_name=collection_name, schema=schema, index_params=index_params) if __name__ == "__main__": # Create collection print("Creating collection...") create_collection() print("Collection created successfully.") ``` Khi cụm Zilliz Cloud của bạn đã sẵn sàng và `.env` đã được cấu hình, hãy chạy lệnh sau: `uv run src/create_collection.py` Lệnh này sẽ tạo một collection trong cụm Zilliz Cloud của bạn. Trong trường hợp bạn muốn “dọn dẹp” collection này, bạn có thể tạo một script `drop_collection.py` trong thư mục `src` để xóa collection và sau đó tạo lại bằng script trước đó. ```python import os from typing import Optional from pymilvus import MilvusClient def drop_collection( collection_name: Optional[str] = None, uri: Optional[str] = None, token: Optional[str] = None, ) -> None: """Drop a Milvus collection. Args: collection_name (str, optional): Name of the collection. Defaults to env var COLLECTION_NAME. uri (str, optional): Zilliz Cloud URI. Defaults to env var ZILLIZ_CLOUD_URI. token (str, optional): Zilliz token. Defaults to env var ZILLIZ_TOKEN. """ # Use environment variables as fallback collection_name = collection_name or os.getenv("COLLECTION_NAME") uri = uri or os.getenv("ZILLIZ_CLOUD_URI") token = token or os.getenv("ZILLIZ_TOKEN") if not all([collection_name, uri, token]): raise ValueError("Missing required parameters: collection_name, uri, or token") # Connect to Zilliz Cloud (Milvus) client = MilvusClient(uri=uri, token=token) # Drop the collection client.drop_collection(collection_name=collection_name) if __name__ == "__main__": # Drop collection print("Dropping collection...") drop_collection() print("Collection dropped successfully.") ``` Để xóa collection, hãy chạy: `uv run src/drop_collection.py` https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/milvus_collection_management.png Triển khai quy trình xử lý PDF: Biến PDF thành “ngôn ngữ” AI Để lưu trữ và tìm kiếm văn bản hiệu quả, chúng ta cần xử lý các file PDF, trích xuất văn bản, chuyển đổi chúng thành embeddings, và lưu trữ vào Zilliz Cloud để truy xuất nhanh chóng. Đảm bảo bạn đã đặt biến môi trường `OPENAI_API_KEY` trong file `.env` của mình nhé. Sau đó, tạo một script `insert_documents.py` trong thư mục `src`. Script này sẽ là “phiên dịch viên” chính của chúng ta, thực hiện các công việc sau: * **Tải văn bản từ PDF:** Sử dụng `PyPDFLoader` từ LangChain để lấy đối tượng `Document`. * **Chia nhỏ văn bản:** Chia văn bản thành các “đoạn” nhỏ dễ quản lý bằng `CharacterTextSplitter` để đảm bảo embeddings chính xác. * **Tạo embeddings:** Sử dụng OpenAI để tạo các embeddings vector. * **Lưu trữ vào Zilliz Cloud:** Lưu văn bản và embeddings vào Zilliz Cloud bằng `MilvusClient` để tìm kiếm sự tương đồng hiệu quả. ```python import os from typing import Optional from langchain_community.document_loaders import PyPDFLoader from langchain_openai import OpenAIEmbeddings from langchain_text_splitters import CharacterTextSplitter from pymilvus import MilvusClient def process_pdf(pdf_path: str, chunk_size: int = 512, chunk_overlap: int = 100) -> list[dict]: """Process a PDF file and generate embeddings for its content.""" if not os.path.exists(pdf_path): raise FileNotFoundError(f"PDF file not found at {pdf_path}") # Load and process PDF loader = PyPDFLoader(pdf_path) documents = loader.load() # Split text text_splitter = CharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap) chunks = text_splitter.split_documents(documents) # Generate embeddings openai_embeddings = OpenAIEmbeddings() # Prepare data for insertion data = [] for chunk in chunks: text = chunk.page_content embedding = openai_embeddings.embed_documents([text])[0] data.append({"pdf_text": text, "my_vector": embedding}) return data def insert_documents( pdf_path: str, collection_name: Optional[str] = None, uri: Optional[str] = None, token: Optional[str] = None, chunk_size: int = 512, chunk_overlap: int = 100, ) -> None: """Insert documents from a PDF file into a Milvus collection.""" # Use environment variables as fallback collection_name = collection_name or os.getenv("COLLECTION_NAME") uri = uri or os.getenv("ZILLIZ_CLOUD_URI") token = token or os.getenv("ZILLIZ_TOKEN") if not all([collection_name, uri, token]): raise ValueError("Missing required parameters: collection_name, uri, or token") # Connect to Zilliz Cloud (Milvus) client = MilvusClient(uri=uri, token=token) # Process PDF and get data data = process_pdf(pdf_path, chunk_size, chunk_overlap) # Insert data client.insert(collection_name, data) # Verify collection load state load_state = client.get_load_state(collection_name=collection_name) print(f"Collection load state: {load_state}") if __name__ == "__main__": # Insert documents print("Inserting documents...") insert_documents("data/1706.03762v7.pdf") print("Documents inserted successfully.") ``` Để chạy script này, bạn hãy dùng lệnh sau. Bạn có thể tìm thấy một file PDF mẫu trong thư mục `data` nhưng cứ thoải mái dùng file của riêng bạn nhé: `uv run src/insert_documents.py` Script này sẽ “xử lý” file PDF của bạn, tạo embeddings và lưu chúng vào collection trong cụm Zilliz Cloud của bạn. Tuyệt vời phải không nào? https://truyentranh.letranglan.top/api/v1/proxy?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzskssf09tmbz92ziffx2.png Tạo vai trò và chính sách IAM: Bộ phận an ninh của AWS Giờ đây chúng ta đã có một quy trình hoạt động, bước tiếp theo là thiết lập AWS Lambda để kích hoạt quy trình này mỗi khi có một file PDF mới được tải lên một S3 bucket. Để triển khai các hàm AWS Lambda, bạn cần tạo các vai trò (IAM roles) và quyền (permissions) cụ thể trước tiên. Bạn có thể tạo script `create_roles.sh` dưới thư mục `scripts`. Script này tự động hóa quá trình tạo một vai trò IAM với chính sách `AWSLambdaExecute` cần thiết để AWS Lambda thực thi hàm và truy cập S3. Trước khi chạy script, hãy đảm bảo bạn đã đặt các biến môi trường `ROLE_NAME` và `AWS_REGION` trong file `.env` của mình. AWS Lambda sẽ đảm nhận vai trò này khi thực thi hàm, cho phép nó truy cập S3 bucket, như được định nghĩa trong chính sách `AWSLambdaExecute`. Nó cũng sẽ có quyền truy cập CloudWatch Logs cho mục đích ghi nhật ký, giúp bạn giám sát và gỡ lỗi hàm. ```bash #!/bin/bash # Exit immediately if a command exits with a non-zero status set -e # Load environment variables from .env file set -o allexport source .env set +o allexport echo "Environment variables loaded." # Check IAM role... echo "Checking IAM role..." # Check if the role exists if ! aws iam get-role --role-name ${ROLE_NAME} --region ${AWS_REGION} 2>/dev/null; then echo "Creating new IAM role for Lambda with S3 access..." # Fix: Remove space after = and use proper JSON formatting ASSUME_ROLE_POLICY='{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" }] }' # Create the IAM role aws iam create-role \ --role-name ${ROLE_NAME} \ --assume-role-policy-document "${ASSUME_ROLE_POLICY}" \ --region ${AWS_REGION} # Add Lambda execution policy. Provides Put, Get access to S3 and full access to CloudWatch Logs. aws iam attach-role-policy \ --role-name ${ROLE_NAME} \ --policy-arn arn:aws:iam::aws:policy/AWSLambdaExecute \ --region ${AWS_REGION} echo "IAM role created and policy attached." # Wait for role to propagate echo "Waiting for role to propagate..." sleep 20 else echo "IAM role ${ROLE_NAME} already exists. Skipping role creation." fi ``` Để thực thi script này, bạn hãy dùng lệnh sau: `uv run scripts/create_roles.sh` https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/iam_roles_permissions.png Xây dựng hàm AWS Lambda: Bộ não của hệ thống Hàm AWS Lambda là thành phần cốt lõi tự động hóa toàn bộ quá trình xử lý tải lên PDF, tạo embeddings và lưu trữ chúng trong Zilliz Cloud. Hàm này được kích hoạt bởi một sự kiện S3, xử lý PDF đã tải lên và lưu trữ dữ liệu kết quả vào collection Milvus của bạn. **Triển khai Lambda Handler:** Bây giờ bạn có thể tạo file `lambda_function.py` dưới đây và lưu nó vào thư mục `aws_lambda`. File này chứa phần triển khai của hàm AWS Lambda. Trong trường hợp này, hàm AWS Lambda được kích hoạt bởi một sự kiện S3 mỗi khi một file PDF mới được tải lên một S3 bucket. Nó xử lý sự kiện, trích xuất file, tạo embeddings và chèn dữ liệu vào collection Zilliz Cloud. ```python import json import os import boto3 from langchain_community.document_loaders import PyPDFLoader from langchain_openai import OpenAIEmbeddings from langchain_text_splitters import CharacterTextSplitter from pymilvus import MilvusClient # Global variables for reuse across invocations client = None openai_embeddings = None text_splitter = None def init_clients(): """Initialize global clients if not already initialized""" global client, openai_embeddings, text_splitter if client is None: print("Initializing Milvus client...") client = MilvusClient(uri=os.getenv("ZILLIZ_CLOUD_URI"), token=os.getenv("ZILLIZ_TOKEN")) if openai_embeddings is None: print("Initializing OpenAI embeddings...") openai_embeddings = OpenAIEmbeddings(openai_api_key=os.getenv("OPENAI_API_KEY")) if text_splitter is None: print("Initializing text splitter...") text_splitter = CharacterTextSplitter(chunk_size=512, chunk_overlap=100) def lambda_handler(event, context): try: print(f"Received event: {json.dumps(event)}") # Initialize clients init_clients() # Validate event structure if "Records" not in event or not event["Records"]: print("No records found in event") return {"statusCode": 400, "body": json.dumps("No records found in event")} # Get bucket and file info from S3 event record = event["Records"][0] bucket = record["s3"]["bucket"]["name"] key = record["s3"]["object"]["key"] print(f"Processing file {key} from bucket {bucket}") # Verify bucket expected_bucket = os.getenv("PDF_BUCKET_NAME") if bucket != expected_bucket: print(f"Invalid bucket. Expected {expected_bucket}, got {bucket}") return { "statusCode": 400, "body": json.dumps(f"Invalid bucket. Expected {expected_bucket}, got {bucket}"), } # Download PDF local_path = f"/tmp/{os.path.basename(key)}" print(f"Downloading file to {local_path}") s3 = boto3.client("s3") s3.download_file(bucket, key, local_path) # Process PDF print("Loading and splitting PDF...") documents = PyPDFLoader(local_path).load() chunks = text_splitter.split_documents(documents) print(f"Split PDF into {len(chunks)} chunks") # Prepare and insert data print("Generating embeddings and preparing data...") data = [ { "pdf_text": chunk.page_content, "my_vector": openai_embeddings.embed_documents([chunk.page_content])[0], } for chunk in chunks ] print(f"Inserting {len(data)} records into collection {os.getenv('COLLECTION_NAME')}") client.insert(os.getenv("COLLECTION_NAME"), data) # Cleanup os.remove(local_path) print("Processing completed successfully") return {"statusCode": 200, "body": json.dumps(f"Successfully processed {key}")} except Exception as e: print(f"Error processing document: {str(e)}") import traceback print(f"Traceback: {traceback.format_exc()}") return {"statusCode": 500, "body": json.dumps(str(e))} ``` Các tính năng chính của hàm Lambda: * **Xử lý sự kiện S3:** Hàm AWS Lambda được kích hoạt bởi một sự kiện S3 khi một file PDF mới được tải lên S3 bucket được chỉ định. * **Khởi tạo Client:** Hàm khởi tạo client Milvus để lưu trữ embeddings, client OpenAI embeddings và text splitter để chia nhỏ văn bản PDF. * **Xử lý văn bản:** Văn bản PDF được trích xuất bằng `PyPDFLoader`, sau đó được chia thành các đoạn nhỏ hơn để đảm bảo việc tạo embedding đúng cách. * **Tạo và lưu trữ Embeddings:** Các embeddings của OpenAI được tạo cho mỗi đoạn văn bản, và dữ liệu kết quả được chèn vào collection Milvus đã chỉ định trong Zilliz Cloud. * **Xử lý lỗi:** Hàm bao gồm xử lý lỗi để bắt và ghi lại bất kỳ ngoại lệ nào xảy ra trong quá trình xử lý PDF. https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/lambda_s3_flow.png Đóng gói AWS Lambda với Docker: Hộp thần kỳ Khi hàm AWS Lambda đã sẵn sàng, nó cần được “đóng gói” bằng Docker. Vì AWS Lambda hoạt động tốt hơn với `requirements.txt` thay vì `pyproject.toml`, bạn cần tạo một file `requirements.txt` từ file `pyproject.toml` của bạn ở thư mục gốc của dự án với các dependencies sau: * `langchain-community` * `langchain_milvus` * `boto3` * `langchain-openai` * `pypdf` `Dockerfile` dưới đây thiết lập môi trường cho hàm AWS Lambda, bao gồm các dependencies cần thiết và mã hàm. Bạn có thể lưu file này trong thư mục gốc của dự án. ```dockerfile FROM public.ecr.aws/lambda/python:3.12.2025.04.01.18 # Set the working directory to /var/task WORKDIR ${LAMBDA_TASK_ROOT} # Copy requirements first to leverage Docker cache COPY requirements.txt ./ # Install dependencies RUN pip install --no-cache-dir -r requirements.txt # Copy source code COPY aws_lambda/lambda_function.py ./lambda_function.py # Command to run the Lambda handler function CMD [ "lambda_function.lambda_handler" ] ``` Tương tự như việc tạo vai trò IAM, việc tạo repository ECR và Docker image có thể được tự động hóa bằng một shell script. Đảm bảo các biến môi trường tương ứng được đặt trong file `.env`. Lưu script dưới đây vào thư mục `scripts`. ```bash #!/bin/bash # Exit immediately if a command exits with a non-zero status set -e # Load environment variables from .env file set -o allexport source .env set +o allexport echo "Environment variables loaded." # Check if the ECR repository exists, create it if it does not if ! aws ecr describe-repositories --repository-names ${LAMBDA_ECR_REPOSITORY_NAME} --region ${AWS_REGION} 2>/dev/null; then echo "Repository ${LAMBDA_ECR_REPOSITORY_NAME} does not exist. Creating..." aws ecr create-repository --repository-name ${LAMBDA_ECR_REPOSITORY_NAME} --region ${AWS_REGION} echo "Repository ${LAMBDA_ECR_REPOSITORY_NAME} created." else echo "Repository ${LAMBDA_ECR_REPOSITORY_NAME} already exists." fi # Build Docker image # To make your image compatible with Lambda, you must use the --provenance=false option. echo "Building Docker image ${LAMBDA_IMAGE_NAME}..." docker buildx build --platform linux/amd64 --provenance=false -t ${LAMBDA_IMAGE_NAME}:latest . # Authenticate Docker to your Amazon ECR registry echo "Authenticating Docker to ECR..." aws ecr get-login-password --region ${AWS_REGION}
Chào các bạn! Tuần lễ ra mắt Timescale đang "nóng hừng hực" và chúng tôi mang đến những màn đối đầu cực kỳ gay cấn: Postgres đấu Qdrant với 50 triệu dữ liệu nhúng (embeddings)! Có một niềm tin rất phổ biến trong giới hạ tầng AI rằng, để đạt hiệu suất cao với các tác vụ xử lý vector, bạn cần phải "từ bỏ" các cơ sở dữ liệu đa năng. Logic nghe có vẻ hợp lý: Postgres siêu đỉnh cho các giao dịch truyền thống, nhưng khi cần tìm kiếm vector hiệu năng cao, thì phải tìm đến các "chuyên gia" như Qdrant. Nghe có lý không? À mà khoan, cái "logic" này có vẻ không đúng đâu nhé! Giống như lần chúng tôi từng so sánh pgvector với Pinecone, lần này cũng vậy thôi. Đúng như tinh thần của Launch Week, mọi thứ đều phải nhanh như chớp mà không phải đánh đổi bất cứ điều gì. Và trong trường hợp này, Postgres đã chứng minh điều đó! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/timescale_launch_week.png' alt='Timescale Launch Week'> Chúng tôi vừa tung ra một bài kiểm tra "khủng" thách thức ngay cái suy nghĩ "phải dùng DB chuyên biệt mới hiệu quả". Chúng tôi đã so sánh Postgres (cùng với pgvector và pgvectorscale) với Qdrant trên một bộ dữ liệu "siêu to khổng lồ": 50 triệu dữ liệu nhúng, mỗi dữ liệu có 768 chiều. Kết quả ư? Postgres không những "cầm cự" tốt mà còn thể hiện khả năng xử lý (throughput) và độ trễ (latency) vượt trội, ngay cả ở quy mô sản phẩm! Bài viết này sẽ tóm tắt những điểm chính, nhưng nó mới chỉ là khởi đầu thôi. Các bạn có thể đọc toàn bộ bài phân tích chi tiết về hiệu năng truy vấn, trải nghiệm của lập trình viên, và kinh nghiệm vận hành tại đây: https://www.timescale.com/blog/pgvector-vs-qdrant. Hãy cùng "mổ xẻ" xem chúng tôi đã tìm thấy gì và điều đó có ý nghĩa gì cho các đội ngũ đang xây dựng ứng dụng AI thực tế nhé! **Bài kiểm tra "đỉnh cao": Postgres vs. Qdrant trên 50 triệu dữ liệu nhúng** Chúng tôi đã cho Postgres và Qdrant "so găng" trên một sân chơi công bằng: - 50 triệu dữ liệu nhúng, mỗi cái "nặng" 768 chiều. - Dùng ANN-benchmarks, công cụ chuẩn của ngành để đánh giá hiệu năng. - Tập trung vào tìm kiếm lân cận gần đúng (ANN search), không lọc. - Tất cả các bài kiểm tra chạy trên phần cứng AWS giống hệt nhau. Kết quả chốt lại là gì? Postgres với pgvector và pgvectorscale thể hiện khả năng xử lý (throughput) cao hơn đáng kể, trong khi vẫn giữ được độ trễ dưới 100 ms. Qdrant có điểm mạnh ở độ trễ "đỉnh" (tail latencies) và tốc độ tạo index, nhưng Postgres lại "bứt tốc" ở những điểm quan trọng nhất cho các đội ngũ đang mở rộng quy mô lên sản xuất. <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fox73b5q8gbq353qnicwc.png' alt='Biểu đồ so sánh Throughput: Postgres vượt trội hơn Qdrant'> Để xem toàn bộ kết quả, bao gồm các chỉ số hiệu năng chi tiết, biểu đồ và cấu hình kiểm tra, đừng ngần ngại đọc bài viết đầy đủ tại https://www.timescale.com/blog/pgvector-vs-qdrant. **Tại sao điều này lại quan trọng? Hiệu năng AI mà không cần viết lại mã!** Những kết quả này không chỉ là mấy con số khô khan đâu nhé! Chúng có ý nghĩa thực sự về cách bạn xây dựng kiến trúc cho hệ thống AI của mình: - **Độ trễ "chuẩn production"**: Postgres cùng pgvectorscale mang lại độ trễ p99 dưới 100 ms – cực kỳ cần thiết cho các ứng dụng AI thời gian thực hoặc cần phản hồi nhanh. - **Khả năng xử lý đồng thời (Concurrency) cao hơn**: Postgres có throughput cao hơn đáng kể, nghĩa là bạn có thể hỗ trợ nhiều người dùng cùng lúc hơn mà không cần mở rộng quá mạnh mẽ. - **Đơn giản hơn**: Bạn không cần phải "vật lộn" để quản lý và tích hợp thêm một cơ sở dữ liệu vector chuyên biệt nào khác. - **Dễ vận hành**: Bạn vẫn tận dụng được sự ổn định, các công cụ và quy trình vận hành quen thuộc mà bạn đã có với Postgres. - **Phát triển ưu tiên SQL**: Bạn có thể lọc, join và tích hợp tìm kiếm vector một cách tự nhiên với dữ liệu quan hệ, mà không cần học các API hay ngôn ngữ truy vấn mới. Postgres với pgvector và pgvectorscale mang lại cho bạn hiệu năng của một cơ sở dữ liệu vector chuyên biệt mà không phải từ bỏ hệ sinh thái, công cụ và trải nghiệm tuyệt vời đã biến Postgres thành cơ sở dữ liệu phổ biến nhất thế giới. Bạn không cần phải chia nhỏ hệ thống của mình chỉ vì muốn tìm kiếm vector! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/simplified_ai_stack.png' alt='Kiến trúc AI đơn giản hơn với Postgres'> **Điều gì đã tạo nên sự khác biệt? Chính là Pgvectorscale và StreamingDiskANN!** Làm sao Postgres có thể "đối chọi" (và thậm chí vượt trội) các cơ sở dữ liệu vector "chuyên trị" được nhỉ? Câu trả lời nằm ở pgvectorscale (một phần của "gia đình" pgai), thứ đã triển khai chỉ mục StreamingDiskANN (một thuật toán ANN dựa trên ổ đĩa được xây dựng để mở rộng quy mô) cho pgvector. Khi kết hợp với Statistical Binary Quantization (SBQ), nó cân bằng việc sử dụng bộ nhớ và hiệu năng tốt hơn so với các triển khai HNSW (hierarchical navigable small world) truyền thống chạy trong bộ nhớ. Điều đó có nghĩa là: - Bạn có thể thực hiện tìm kiếm vector quy mô lớn trên phần cứng đám mây thông thường. - Bạn không cần phải "ngốn" bộ nhớ cực lớn hay dùng các node GPU đắt đỏ. - Hiệu năng vẫn ổn định ngay cả khi bộ dữ liệu của bạn tăng lên hàng chục hoặc hàng trăm triệu vector. Tất cả đều diễn ra... ngay bên trong Postgres! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/pgvectorscale_and_streamingdiskann.png' alt='pgvectorscale và StreamingDiskANN giúp Postgres mạnh mẽ hơn'> **Khi nào nên chọn Postgres, và khi nào thì không?** Nói rõ nhé: Qdrant là một hệ thống rất mạnh. Nó có tốc độ tạo index nhanh hơn và độ trễ "đỉnh" thấp hơn. Đây là một lựa chọn tốt nếu bạn chưa dùng Postgres, hoặc cho các trường hợp sử dụng cụ thể cần khả năng mở rộng (scale-out) tự nhiên và ngữ nghĩa vector được xây dựng chuyên biệt. Tuy nhiên, đối với nhiều đội ngũ – đặc biệt là những ai đã "đầu tư" vào Postgres – thì việc giới thiệu một cơ sở dữ liệu mới chỉ để hỗ trợ tìm kiếm vector là không cần thiết. Nếu bạn muốn độ chính xác (recall) cao, khả năng xử lý (throughput) cao, và tích hợp chặt chẽ với hệ thống hiện có, thì Postgres là quá đủ! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/database_decision.png' alt='Lựa chọn cơ sở dữ liệu vector'> **Muốn thử ngay không?** Pgvector và pgvectorscale đều là mã nguồn mở và có sẵn ngay hôm nay: - GitHub của pgvector: https://github.com/pgvector/pgvector - GitHub của pgvectorscale: https://github.com/timescale/pgvectorscale Hoặc để tiết kiệm thời gian, bạn có thể tạo tài khoản Timescale Cloud miễn phí để trải nghiệm cả hai: https://timescale.com/signup. Tìm kiếm vector trong Postgres không phải là một "mánh khóe" hay một giải pháp "tạm bợ" đâu. Nó nhanh, nó có thể mở rộng (scale) và nó hoạt động thật sự! Nếu bạn đang xây dựng các ứng dụng AI vào năm 2025, bạn không cần phải "hy sinh" cơ sở dữ liệu yêu thích của mình để chạy nhanh hơn đâu nhé! **Tiếp theo tại Timescale Launch Week** Sắp tới, chúng tôi sẽ đưa Postgres đi xa hơn nữa: Tìm hiểu cách truyền dữ liệu S3 bên ngoài vào Postgres với livesync cho S3 và làm việc trực tiếp với dữ liệu S3 bằng pgai Vectorizer. Hai cách mạnh mẽ để tích hợp liền mạch dữ liệu bên ngoài từ S3 trực tiếp vào quy trình làm việc Postgres của bạn! <img src='https://truyentranh.letranglan.top/api/v1/proxy?url=https://i.imgur.com/timescale_future_plans.png' alt='Tương lai của Postgres với Timescale'>
Khám phá Vecstore, API tìm kiếm AI giúp ứng dụng của bạn hiểu ý nghĩa và ngữ cảnh, không chỉ từ khóa. Tích hợp dễ dàng tính năng tìm kiếm văn bản/hình ảnh thông minh và kiểm duyệt nội dung chi tiết (NSFW detection) chỉ trong vài phút, không cần GPU hay hạ tầng phức tạp.
Timescale công bố benchmark đầy bất ngờ: Postgres (kết hợp pgvector & pgvectorscale) chứng minh khả năng vượt trội Qdrant về thông lượng trên 50 triệu vector embeddings. Khám phá cách Postgres giúp bạn xây dựng ứng dụng AI hiệu suất cao mà không cần từ bỏ cơ sở dữ liệu quen thuộc.
Khám phá hướng dẫn toàn diện về Agentic RAG: Xây dựng ứng dụng AI mạnh mẽ với PostgreSQL, pgvector và pgai. Giải quyết các thách thức thực tế và tối ưu hiệu suất.
Học cách triển khai tìm kiếm vector thông minh trong MongoDB Atlas cục bộ bằng Ollama và bộ dữ liệu lời bài hát Eurovision, giúp tìm kiếm theo ý nghĩa thay vì từ khóa.
Timescale công bố kết quả thử nghiệm hiệu năng mới: Postgres với pgvector và pgvectorscale đã vượt trội Qdrant về tốc độ xử lý và độ trễ trên bộ dữ liệu 50 triệu vector nhúng, chứng minh rằng bạn không cần từ bỏ Postgres để xây dựng ứng dụng AI quy mô lớn.
Khám phá cách nâng cấp công cụ AI đa tác tử với 'vòng mục tiêu' thông minh, khả năng truy cập tệp tin (Ref Files) và tích hợp hệ thống RAG (Retrieval-Augmented Generation) cùng Qdrant, OpenAI embeddings. Bài viết đi sâu vào thiết kế persona linh hoạt, quy trình RAG chi tiết và trình diễn ứng dụng thực tế trong thẩm định bảo hiểm, lập kế hoạch chăm sóc, giúp AI trở nên 'thông minh' và 'trợ lý' đắc lực hơn bao giờ hết.
Hướng dẫn siêu tốc: Xây dựng chatbot RAG thông minh chỉ trong 10 phút với MongoDB Atlas Vector Search và thư viện mongodb-rag mới toanh. Tạm biệt "học vẹt", đón chào AI xịn sò!
Chào mừng bạn đến với series blog hấp dẫn hướng dẫn từng bước xây dựng trợ lý AI 'xịn sò' của riêng bạn. Khám phá cách kết hợp Node.js, LangChain, PGVector, Redis và nhiều công cụ AI tiên tiến khác để tạo ra một chatbot thông minh, có khả năng ghi nhớ và truy xuất thông tin mạnh mẽ. Dù bạn là developer chuyên nghiệp hay mới bắt đầu, series này sẽ trang bị cho bạn kiến thức và kỹ năng cần thiết để làm chủ công nghệ AI, biến ý tưởng thành hiện thực.