paint-brush
AI cho Quản lý Tri thức: Lặp lại trên RAG với Kiến trúc QE-RAGtừ tác giả@shanglun
4,222 lượt đọc
4,222 lượt đọc

AI cho Quản lý Tri thức: Lặp lại trên RAG với Kiến trúc QE-RAG

từ tác giả Shanglun Wang27m2023/09/12
Read on Terminal Reader

dài quá đọc không nổi

Thế hệ tăng cường truy xuất, hay RAG, là một kiến trúc phổ biến để phát triển các ứng dụng LLM mạnh mẽ. Tuy nhiên, kiến trúc hiện tại có một số hạn chế thực sự. Chúng tôi hướng dẫn xây dựng ứng dụng RAG, sau đó xem cách chúng tôi có thể cải thiện ứng dụng đó bằng cách sử dụng kiến trúc mới có tên QE-RAG
featured image - AI cho Quản lý Tri thức: Lặp lại trên RAG với Kiến trúc QE-RAG
Shanglun Wang HackerNoon profile picture


Khi cuộc cách mạng LLM bắt đầu hình thành, sự cường điệu đã nhường chỗ cho sự phát triển thương mại. Khi làn sóng phấn khích ban đầu lắng xuống, AI tổng quát không còn được coi là một hộp đen toàn trí mà giống như một công cụ cấu thành, nếu cực kỳ mạnh mẽ, trong kho vũ khí của kỹ sư. Kết quả là, các doanh nhân và nhà công nghệ hiện có một bộ công cụ và kỹ thuật ngày càng hoàn thiện để phát triển các ứng dụng LLM.


Một trong những trường hợp sử dụng thú vị nhất của LLM là trong lĩnh vực quản lý kiến thức. Các LLM chuyên dụng, dựa trên công nghệ GPT của OpenAI hoặc các mô hình nguồn mở như LLaMa 2 và Flan-T5, đang được sử dụng theo những cách thông minh để quản lý số lượng lớn dữ liệu. Trong khi các tổ chức trước đây có bộ dữ liệu văn bản lớn phải dựa vào các kỹ thuật tìm kiếm văn bản như đối sánh mờ hoặc lập chỉ mục toàn văn bản thì giờ đây họ có quyền truy cập vào một hệ thống mạnh mẽ không chỉ tìm thấy thông tin mà còn tóm tắt thông tin theo cách hiệu quả về thời gian và thân thiện với người đọc. thời trang.


Trong trường hợp sử dụng này, kiến trúc thế hệ tăng cường truy xuất , hay RAG, đã nổi lên như một kiến trúc nổi bật với tính linh hoạt và hiệu suất rất lớn. Với kiến trúc này, các tổ chức có thể nhanh chóng lập chỉ mục nội dung công việc, thực hiện các truy vấn ngữ nghĩa trên đó và tạo ra các câu trả lời mang tính thông tin và thuyết phục cho các truy vấn do người dùng xác định dựa trên kho văn bản. Một số công ty và dịch vụ đã xuất hiện để hỗ trợ triển khai kiến trúc RAG, làm nổi bật sức mạnh bền bỉ của nó.


Mặc dù RAG có hiệu quả nhưng kiến trúc này cũng có một số hạn chế thực sự. Trong bài viết này, chúng ta sẽ khám phá kiến trúc RAG, xác định các hạn chế của nó và đề xuất một kiến trúc cải tiến để giải quyết những hạn chế này.


Giống như tất cả các bài viết khác, tôi đang tìm cách kết nối với các nhà công nghệ và những người đam mê AI khác. Nếu bạn có suy nghĩ về cách cải thiện kiến trúc này hoặc có ý tưởng về AI mà bạn muốn thảo luận, vui lòng liên hệ ! Bạn có thể tìm thấy tôi trên Github hoặc LinkedIn, các liên kết có trong hồ sơ của tôi cũng như ở cuối bài viết này.


Tổng quan về nội dung

  • Kiến trúc thế hệ tăng cường truy xuất (RAG)
  • Hạn chế của Kiến trúc RAG
  • Đề xuất QE-RAG hoặc RAG nâng cao câu hỏi
  • Phần kết luận


Kiến trúc thế hệ tăng cường truy xuất (RAG)

Với những cái tên như RAG, Flan và LLaMa, cộng đồng AI khó có thể sớm giành được giải thưởng cho những cái tên tương lai và phong cách. Tuy nhiên, kiến trúc RAG chắc chắn xứng đáng nhận được giải thưởng nhờ sự kết hợp của hai kỹ thuật cực kỳ mạnh mẽ được tạo ra nhờ sự phát triển của LLM - nhúng tài liệu theo ngữ cảnh và kỹ thuật nhanh chóng.


Đơn giản nhất, kiến trúc RAG là một hệ thống sử dụng tìm kiếm vectơ nhúng để tìm (các) phần của kho ngữ liệu phù hợp nhất với câu hỏi, chèn (các) phần đó vào lời nhắc và sau đó sử dụng kỹ thuật nhắc nhở để đảm bảo rằng câu trả lời dựa trên các đoạn trích được đưa ra trong lời nhắc. Nếu tất cả điều này nghe có vẻ hơi khó hiểu, vui lòng đọc tiếp vì tôi sẽ giải thích lần lượt từng thành phần. Tôi cũng sẽ bao gồm mã ví dụ để bạn có thể làm theo.


Mô hình nhúng

Đầu tiên và quan trọng nhất, một hệ thống RAG hiệu quả đòi hỏi một mô hình nhúng mạnh mẽ. Mô hình nhúng biến đổi một tài liệu văn bản tự nhiên thành một chuỗi số hoặc một “vectơ”, đại diện gần đúng cho nội dung ngữ nghĩa của tài liệu. Giả sử mô hình nhúng là mô hình tốt, bạn sẽ có thể so sánh các giá trị ngữ nghĩa của hai tài liệu khác nhau và xác định xem hai tài liệu đó có giống nhau về mặt ngữ nghĩa hay không bằng cách sử dụng số học vectơ.


Để thấy điều này hoạt động, hãy dán đoạn mã sau vào tệp Python và chạy nó:


 import openai from openai.embeddings_utils import cosine_similarity openai.api_key = [YOUR KEY] EMBEDDING_MODEL = "text-embedding-ada-002" def get_cos_sim(input_1, input_2): embeds = openai.Embedding.create(model=EMBEDDING_MODEL, input=[input_1, input_2]) return cosine_similarity(embeds['data'][0]['embedding'], embeds['data'][1]['embedding']) print(get_cos_sim('Driving a car', 'William Shakespeare')) print(get_cos_sim('Driving a car', 'Riding a horse'))



Đoạn mã trên tạo ra các phần nhúng cho các cụm từ “Lái xe”, “William Shakespeare” và “Cưỡi ngựa” trước khi so sánh chúng với nhau bằng thuật toán tương tự cosine. Chúng tôi hy vọng độ tương tự cosine sẽ cao hơn khi các cụm từ giống nhau về mặt ngữ nghĩa, vì vậy “Lái xe” và “Cưỡi ngựa” sẽ gần nhau hơn nhiều, trong khi “Lái xe” và “William Shakespeare” sẽ khác nhau.


Bạn sẽ thấy rằng, theo mô hình nhúng của OpenAI, ada-002, cụm từ “lái ô tô” giống 88% với cụm từ “cưỡi ngựa” và giống 76% với cụm từ “William Shakespeare”. Điều này có nghĩa là mô hình nhúng đang hoạt động như chúng ta mong đợi. Việc xác định sự tương đồng về ngữ nghĩa này là nền tảng của hệ thống RAG.


Ý tưởng về độ tương tự cosin đặc biệt mạnh mẽ khi bạn mở rộng nó để so sánh các tài liệu lớn hơn nhiều. Ví dụ: lấy đoạn độc thoại mạnh mẽ từ Macbeth của Shakespeare, “ Ngày mai, ngày mai và ngày mai ”:


 monologue = '''Tomorrow, and tomorrow, and tomorrow, Creeps in this petty pace from day to day, To the last syllable of recorded time; And all our yesterdays have lighted fools The way to dusty death. Out, out, brief candle! Life's but a walking shadow, a poor player, That struts and frets his hour upon the stage, And then is heard no more. It is a tale Told by an idiot, full of sound and fury, Signifying nothing.''' print(get_cos_sim(monologue, 'Riding a car')) print(get_cos_sim(monologue, 'The contemplation of mortality'))


Bạn sẽ thấy đoạn độc thoại chỉ giống 75% với ý tưởng “cưỡi xe” và 82% giống với ý tưởng “Suy ngẫm về cái chết”.


Nhưng chúng ta không chỉ phải so sánh đoạn độc thoại với ý tưởng, chúng ta còn có thể so sánh đoạn độc thoại với câu hỏi. Ví dụ:


 get_cos_sim('''Tomorrow, and tomorrow, and tomorrow, Creeps in this petty pace from day to day, To the last syllable of recorded time; And all our yesterdays have lighted fools The way to dusty death. Out, out, brief candle! Life's but a walking shadow, a poor player, That struts and frets his hour upon the stage, And then is heard no more. It is a tale Told by an idiot, full of sound and fury, Signifying nothing.''', 'Which Shakespearean monologue contemplates mortality?') get_cos_sim('''Full of vexation come I, with complaint Against my child, my daughter Hermia. Stand forth, Demetrius. My noble lord, This man hath my consent to marry her. Stand forth, Lysander. And my gracious Duke, This man hath bewitch'd the bosom of my child. Thou, thou, Lysander, thou hast given her rhymes, And interchanged love-tokens with my child: Thou hast by moonlight at her window sung With feigning voice verses of feigning love, And stol'n the impression of her fantasy With bracelets of thy hair, rings, gauds, conceits, Knacks, trifles, nosegays, sweetmeats (messengers Of strong prevailment in unharden'd youth): With cunning hast thou filch'd my daughter's heart, Turn'd her obedience, which is due to me, To stubborn harshness. And, my gracious Duke, Be it so she will not here, before your Grace, Consent to marry with Demetrius, I beg the ancient privilege of Athens: As she is mine, I may dispose of her; Which shall be either to this gentleman, Or to her death, according to our law Immediately provided in that case.''', 'Which Shakespearean monologue contemplates mortality?')



Bạn sẽ thấy rằng phần lồng ghép cho thấy đoạn độc thoại của Macbeth gần gũi hơn nhiều về mặt ngữ cảnh với câu hỏi “Đoạn độc thoại nào của Shakespearean suy ngẫm về cái chết?” hơn đoạn độc thoại của Egeus, đề cập đến cái chết nhưng không trực tiếp đề cập đến khái niệm về cái chết.


Tra cứu Vector

Bây giờ chúng ta đã có phần nhúng, làm cách nào để sử dụng nó trong hệ thống RAG của mình? Chà, giả sử chúng ta muốn cung cấp cho hệ thống RAG của mình kiến thức về tất cả các đoạn độc thoại của Shakespeare để nó có thể trả lời các câu hỏi về Shakespeare. Trong trường hợp này, chúng tôi sẽ tải xuống tất cả các đoạn độc thoại của Shakespeare và tạo phần nhúng cho chúng. Nếu bạn đang theo dõi, bạn có thể tạo phần nhúng như thế này:



 embedding = openai.Embedding.create(model=EMBEDDING_MODEL, input=[monologue])['data'][0]['embedding']


Khi chúng tôi có các phần nhúng, chúng tôi sẽ muốn lưu trữ chúng theo cách cho phép chúng tôi truy vấn và so sánh chúng với phần nhúng mới. Thông thường, chúng tôi sẽ đặt chúng vào cái gọi là Cơ sở dữ liệu vectơ , là kho lưu trữ dữ liệu chuyên dụng cho phép so sánh nhanh hai vectơ. Tuy nhiên, trừ khi kho dữ liệu của bạn cực kỳ lớn, các phép so sánh bạo lực có thể chấp nhận được một cách đáng ngạc nhiên đối với hầu hết các trường hợp sử dụng thử nghiệm, phi sản xuất trong đó hiệu suất không quan trọng.


Cho dù bạn có chọn sử dụng cơ sở dữ liệu hay không, bạn sẽ muốn xây dựng một hệ thống có thể tìm thấy (các) mục trong kho dữ liệu phù hợp nhất với câu hỏi. Trong ví dụ của chúng tôi, chúng tôi sẽ muốn có khả năng tìm thấy đoạn độc thoại phù hợp nhất với câu hỏi của người dùng. Bạn có thể muốn làm một cái gì đó như:



 monologues_embeddings = [ ['Tomorrow, and tomorrow, and tomorrow...', [...]], # text in the left position, embedding in the right position ['Full of vexation come I...', [...]], … # More monologues and their embeddings as you see fit. ] def lookup_most_relevant(question): embed = openai.Embedding.create(model=EMBEDDING_MODEL, input=[question])['data'][0]['embedding'] top_monologue = sorted(monologues_embeddings, key=lambda x: cosine_similarity(embed, x[1]), reverse=True)[0] return top_monologue lookup_most_relevant(“How does Macbeth evaluate his life when he is confronted with his mortality?“)


Nếu chạy ví dụ này, bạn sẽ thấy đoạn độc thoại Macbeth được chọn, với độ tương tự khoảng 82% với câu hỏi.


Kỹ thuật nhanh chóng

Bước cuối cùng trong mô hình RAG là kỹ thuật nhanh chóng. Trong trường hợp của chúng tôi, nó không quá khó khăn. Bây giờ chúng ta đã có sẵn đoạn độc thoại, chúng ta có thể tạo lời nhắc bằng cách nhúng đoạn độc thoại vào truy vấn của mình, sau đó đặt câu hỏi:


 completion = openai.ChatCompletion.create( model="gpt-4", messages=[ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": """ Consider the following monologue: Tomorrow, and tomorrow, and tomorrow, Creeps in this petty pace from day to day, To the last syllable of recorded time; And all our yesterdays have lighted fools The way to dusty death. Out, out, brief candle! Life's but a walking shadow, a poor player, That struts and frets his hour upon the stage, And then is heard no more. It is a tale Told by an idiot, full of sound and fury, Signifying nothing. How does Macbeth evaluate his life when he is confronted with his mortality? """}, ] )


Bạn sẽ thấy một câu trả lời như:


 In the well-known "Tomorrow and tomorrow and tomorrow" monologue from Shakespeare's Macbeth, the titular character plunges into existential despair when confronted with his impending death. Macbeth evaluates his life as hollow, futile, and meaningless when facing his mortality. He sees it as a "walking shadow" and himself as a "poor player," highlighting his view of life as a fleeting, contrived performance with no lasting substance or impact. The "brief candle" is a metaphor for his own mortality, suggesting that life's flame can be extinguished suddenly and unceremoniously. By stating "It is a tale told by an idiot, full of sound and fury, signifying nothing," Macbeth is expressing his belief that life, despite all its noise and action, is ultimately empty, absurd, and void of meaning. Overall, Macbeth's examination of his life is profoundly pessimistic, revealing his deep despair and cynicism.


Tất nhiên, ví dụ cụ thể này không phải là minh chứng mạnh mẽ nhất về kiến trúc RAG, vì hầu hết các mô hình GPT đều đã biết về những đoạn độc thoại của Shakespeare và đã được đào tạo công khai về khối lượng lớn các phân tích của Shakespeare trên internet. Trên thực tế, nếu bạn hỏi GPT-4 câu hỏi chính xác này mà không nhúng đoạn độc thoại, bạn có thể sẽ nhận được câu trả lời rất hay, mặc dù nó có thể sẽ không đưa ra nhiều trích dẫn tham chiếu đến đoạn độc thoại. Tuy nhiên, cần phải rõ ràng rằng, trong môi trường thương mại, kỹ thuật này có thể được áp dụng chéo cho các bộ dữ liệu độc quyền hoặc bí mật mà các triển khai GPT hiện tại không thể truy cập được.


Trên thực tế, những độc giả đã quen với bài viết trước của tôi, Xây dựng Trình phân tích Tài liệu bằng ChatGPT, Google Cloud và Python , có thể nhận ra rằng phần cuối cùng của kỹ thuật này rất giống với kỹ thuật nhắc nhở mà tôi đã thực hiện trong bài viết đó. Mở rộng từ ý tưởng đó, chúng ta có thể dễ dàng tưởng tượng ra một hệ thống RAG được xây dựng dựa trên các ấn phẩm của chính phủ Nhật Bản (dữ liệu mẫu từ bài báo đó), cho phép người dùng tìm kiếm và đặt câu hỏi về chính sách kinh tế Nhật Bản. Hệ thống sẽ nhanh chóng truy xuất các tài liệu có liên quan nhất, tóm tắt chúng và đưa ra câu trả lời dựa trên kiến thức chuyên sâu về miền cụ thể mà các mô hình GPT cơ sở không có. Sức mạnh và sự đơn giản này chính là lý do tại sao kiến trúc RAG đang nhận được nhiều sự chú ý của các nhà phát triển LLM.


Bây giờ chúng ta đã xem qua kiến trúc RAG, hãy cùng khám phá một số thiếu sót của kiến trúc này.


Hạn chế của Kiến trúc RAG

Nhúng khả năng gỡ lỗi

Bởi vì nhiều hệ thống RAG dựa vào việc nhúng tài liệu và tìm kiếm vectơ để kết nối câu hỏi và các tài liệu liên quan nên toàn bộ hệ thống thường hoạt động tốt như mô hình nhúng được sử dụng. Mô hình nhúng OpenAI cực kỳ linh hoạt và có nhiều kỹ thuật để điều chỉnh cho phù hợp với các phần nhúng. LLaMa, đối thủ cạnh tranh mã nguồn mở của Meta với GPT, cung cấp các mô hình nhúng có thể tinh chỉnh. Tuy nhiên, có một khía cạnh hộp đen không thể tránh khỏi đối với mô hình Nhúng. Điều này có thể quản lý được phần nào khi so sánh các chuỗi văn bản ngắn khi so sánh các chuỗi ngắn với các tài liệu dài hơn nhiều. Trong ví dụ trước, chúng ta phải tin tưởng một chút rằng việc tra cứu nhúng có thể kết nối “tử vong” với đoạn độc thoại “ngày mai, ngày mai và ngày mai”. Điều này có thể khá khó chịu đối với khối lượng công việc đòi hỏi tính minh bạch và khả năng gỡ lỗi.

Quá tải bối cảnh

Một hạn chế khác của mô hình RAG là số lượng ngữ cảnh tương đối hạn chế có thể được chuyển đến nó. Vì mô hình nhúng yêu cầu ngữ cảnh ở cấp độ tài liệu để hoạt động tốt nên chúng ta cần cẩn thận khi chia nhỏ kho văn bản để nhúng. Đoạn độc thoại của Macbeth có thể có độ giống 82% với câu hỏi về tỷ lệ tử vong, nhưng con số đó giảm xuống còn 78% khi bạn so sánh câu hỏi với phần lồng ghép cho hai dòng đầu tiên của đoạn độc thoại, tức là “Ngày mai, ngày mai, và Ngày mai. Len lỏi trong nhịp sống nhỏ nhặt này từ ngày này sang ngày khác, Đến âm tiết cuối cùng của thời gian được ghi lại.”.


Do đó, ngữ cảnh được chuyển tới dấu nhắc RAG cần phải khá lớn. Hiện tại, các mô hình GPT có ngữ cảnh cao nhất vẫn bị giới hạn ở 16.000 mã thông báo, khá nhiều văn bản, nhưng khi bạn làm việc với các bản ghi phỏng vấn dài hoặc các bài viết có ngữ cảnh phong phú, bạn sẽ bị giới hạn về số lượng ngữ cảnh bạn có thể cung cấp trong dấu nhắc thế hệ cuối cùng.

Thuật ngữ mới

Hạn chế cuối cùng của mô hình RAG là không có khả năng hoạt động với các thuật ngữ mới. Những người làm việc trong các lĩnh vực cụ thể có xu hướng phát triển các thuật ngữ và cách diễn đạt riêng cho lĩnh vực đó. Khi các thuật ngữ này không có trong dữ liệu huấn luyện của mô hình nhúng thì quá trình tra cứu sẽ bị ảnh hưởng.


Ví dụ: mô hình nhúng ada-002 có thể không biết rằng “Ngôn ngữ lập trình Rust” có liên quan đến “LLVM”. Trên thực tế, nó trả về độ tương tự cosin tương đối thấp là 78%. Điều này có nghĩa là các tài liệu nói về LLVM có thể không thể hiện sự tương đồng nhiều trong truy vấn về Rust, mặc dù hai ý tưởng này có liên quan chặt chẽ với nhau trong đời thực.


Thông thường, vấn đề về thuật ngữ mới có thể được khắc phục bằng một số kỹ thuật nhanh chóng, nhưng trong bối cảnh tìm kiếm nhúng, điều đó tương đối khó thực hiện. Như đã đề cập trước đó, việc tinh chỉnh mô hình nhúng là có thể, nhưng việc dạy mô hình nhúng thuật ngữ mới trong mọi ngữ cảnh có thể dễ xảy ra lỗi và tốn thời gian.

Đề xuất QE-RAG hoặc RAG nâng cao câu hỏi

Với những hạn chế này, tôi muốn đề xuất một kiến trúc được sửa đổi cho phép triển khai một lớp hệ thống RAG mới giúp loại bỏ nhiều hạn chế được mô tả ở trên. Ý tưởng này dựa trên việc thực hiện tìm kiếm vectơ trên các câu hỏi thường gặp, ngoài kho văn bản và sử dụng LLM để xử lý trước kho văn bản trong ngữ cảnh của câu hỏi. Nếu quá trình đó có vẻ phức tạp, đừng lo lắng, chúng tôi sẽ xem xét chi tiết cách triển khai trong phần này cùng với các ví dụ về mã mà bạn có thể sử dụng để làm theo.


Một điều cần lưu ý là QE-RAG nên được chạy cùng với việc triển khai RAG vanilla để nó có thể quay trở lại triển khai khác nếu cần. Khi quá trình triển khai hoàn thiện, nó ngày càng cần ít dự phòng hơn, nhưng QE-RAG vẫn nhằm mục đích nâng cao thay vì thay thế kiến trúc RAG vanilla.


Kiến trúc

Các nét chung của kiến trúc QE-RAG như sau:

  1. Tạo cơ sở dữ liệu vectơ gồm các câu hỏi có thể hoặc có khả năng sẽ được hỏi về kho văn bản.
  2. Tiền xử lý và tóm tắt kho dữ liệu dựa trên các câu hỏi trong cơ sở dữ liệu vectơ.
  3. Khi có truy vấn của người dùng, hãy so sánh truy vấn của người dùng với các câu hỏi trong cơ sở dữ liệu vectơ.
  4. Nếu một câu hỏi trong cơ sở dữ liệu rất giống với truy vấn của người dùng, hãy truy xuất phiên bản của kho văn bản được tóm tắt để trả lời câu hỏi.
  5. Sử dụng kho văn bản tóm tắt để trả lời câu hỏi của người dùng.
  6. Nếu không có câu hỏi nào trong DB rất giống với truy vấn của người dùng, hãy quay lại triển khai RAG thông thường.


Chúng ta hãy lần lượt đi qua từng phần.


Nhúng câu hỏi

Kiến trúc bắt đầu, giống như RAG vani, với cơ sở dữ liệu nhúng và vectơ. Tuy nhiên, thay vì nhúng tài liệu, chúng tôi sẽ nhúng một loạt câu hỏi.

Để minh họa điều này, giả sử chúng ta đang cố gắng xây dựng một LLM là chuyên gia về Shakespeare. Chúng tôi có thể muốn nó trả lời các câu hỏi như:


 questions = [ "How does political power shape the way characters interact in Shakespeare's plays?", "How does Shakespeare use supernatural elements in his plays?", "How does Shakespeare explore the ideas of death and mortality in his plays?", "How does Shakespeare explore the idea of free will in his plays?" ]


Chúng tôi sẽ muốn tạo một phần nhúng cho chúng như vậy và lưu chúng hoặc sử dụng sau này:


 questions_embed = openai.Embedding.create(model=EMBEDDING_MODEL, input=questions)


Tiền xử lý và tóm tắt

Bây giờ chúng tôi đã có câu hỏi, chúng tôi sẽ muốn tải xuống và tóm tắt kho văn bản. Với ví dụ này, chúng tôi sẽ tải xuống phiên bản HTML của Macbeth và Hamlet:


 import openai import os import requests from bs4 import BeautifulSoup plays = { 'shakespeare_macbeth': 'https://www.gutenberg.org/cache/epub/1533/pg1533-images.html', 'shakespeare_hamlet': 'https://www.gutenberg.org/cache/epub/1524/pg1524-images.html', } if not os.path.exists('training_plays'): os.mkdir('training_plays') for name, url in plays.items(): print(name) file_path = os.path.join('training_plays', '%s.txt' % name) if not os.path.exists(file_path): res = requests.get(url) with open(file_path, 'w') as fp_write: fp_write.write(res.text)


Sau đó, chúng tôi xử lý các vở kịch thành các cảnh, sử dụng thẻ HTML làm hướng dẫn:


 with open(os.path.join('training_plays', 'shakespeare_hamlet.txt')) as fp_file: soup = BeautifulSoup(''.join(fp_file.readlines())) headers = soup.find_all('div', {'class': 'chapter'})[1:] scenes = [] for header in headers: cur_act = None cur_scene = None lines = [] for i in header.find_all('h2')[0].parent.find_all(): if i.name == 'h2': print(i.text) cur_act = i.text elif i.name == 'h3': print('\t', i.text.replace('\n', ' ')) if cur_scene is not None: scenes.append({ 'act': cur_act, 'scene': cur_scene, 'lines': lines }) lines = [] cur_scene = i.text elif (i.text != '' and not i.text.strip('\n').startswith('ACT') and not i.text.strip('\n').startswith('SCENE') ): lines.append(i.text)


Và đây là phần làm cho QE-RAG trở nên độc đáo, thay vì tạo phần nhúng cho các cảnh cụ thể, chúng tôi tạo bản tóm tắt cho chúng, nhắm mục tiêu đến từng câu hỏi:


 def summarize_for_question(text, question, location): completion = openai.ChatCompletion.create( model="gpt-3.5-turbo-16k", messages=[ {"role": "system", "content": "You are a literature assistant that provides helpful summaries."}, {"role": "user", "content": """Is the following excerpt from %s relevant to the following question? %s === %s === If so, summarize the sections that are relevant. Include references to specific passages that would be useful. If not, simply say: \"nothing is relevant\" without additional explanation""" % ( location, question, text )}, ] ) return completion


Chức năng này yêu cầu ChatGPT thực hiện 2 việc: 1) xác định xem đoạn văn có thực sự hữu ích để trả lời câu hỏi hay không và 2) tóm tắt các phần của cảnh có ích cho việc trả lời câu hỏi.


Nếu bạn thử chức năng này với một vài cảnh quan trọng từ Macbeth hoặc Hamlet, bạn sẽ thấy GPT3.5 khá giỏi trong việc xác định xem một cảnh có liên quan đến câu hỏi hay không và phần tóm tắt sẽ ngắn hơn chính cảnh đó một chút. Điều này giúp việc nhúng sau này ở bước kỹ thuật nhanh chóng trở nên dễ dàng hơn nhiều.


Bây giờ chúng ta có thể làm điều này cho tất cả các cảnh.


 for scene in scenes: scene_text = ''.join(scene['lines']) question_summaries = {} for question in questions: completion = summarize_for_question(''.join(scene['lines']), question, "Shakespeare's Hamlet") question_summaries[question] = completion.choices[0].message['content'] scene['question_summaries'] = question_summaries


Trong khối lượng công việc sản xuất, chúng tôi sẽ đưa các bản tóm tắt vào cơ sở dữ liệu, nhưng trong trường hợp của chúng tôi, chúng tôi sẽ chỉ ghi nó dưới dạng tệp JSON vào đĩa.


Tìm kiếm vectơ hai giai đoạn

Bây giờ, giả sử chúng ta nhận được một câu hỏi của người dùng như dưới đây:


 user_question = "How do Shakespearean characters deal with the concept of death?"


Giống như trong vanilla RAG, chúng tôi sẽ muốn tạo phần nhúng cho câu hỏi:


 uq_embed = openai.Embedding.create(model=EMBEDDING_MODEL, input=[user_question])['data'][0]['embedding']


Trong RAG thông thường, chúng tôi sẽ so sánh phần nhúng câu hỏi của người dùng với phần nhúng cho các cảnh trong Shakespeare, nhưng trong QE-RAG, chúng tôi so sánh với phần nhúng câu hỏi với các câu hỏi:


 print([cosine_similarity(uq_embed, q) for q in question_embed])


Chúng tôi thấy rằng tìm kiếm vectơ đã xác định (chính xác) câu hỏi 3 là câu hỏi phù hợp nhất. Bây giờ, chúng ta lấy dữ liệu tóm tắt cho câu hỏi 3:


 relevant_texts = [] for scene in hamlet + macbeth: # hamlet and macbeth are the scene lists from the above code if "NOTHING IS RELEVANT" not in scene['question_summaries'][questions[2]].upper() and \ "NOTHING IN THIS EXCERPT" not in scene['question_summaries'][questions[2]].upper() and \ 'NOTHING FROM THIS EXCERPT' not in scene['question_summaries'][questions[2]].upper() and \ "NOT DIRECTLY ADDRESSED" not in scene['question_summaries'][questions[2]].upper(): relevant_texts.append(scene['question_summaries'][questions[2]])


Xin lưu ý rằng vì tóm tắt GPT không mang tính xác định nên bạn có thể nhận được một số chuỗi khác nhau để chỉ ra rằng một cảnh không liên quan đến câu hỏi hiện tại. Điều quan trọng là chỉ đẩy những đoạn trích có liên quan vào danh sách tóm tắt có liên quan.


Ở giai đoạn này, chúng tôi có thể thực hiện tìm kiếm vectơ cấp hai để chỉ bao gồm các bản tóm tắt có liên quan nhất trong lời nhắc của mình, nhưng với kích thước của kho văn bản, chúng tôi chỉ cần sử dụng toàn bộ danh sách relevant_texts trong lời nhắc của mình.


Kỹ thuật nhanh chóng

Bây giờ chúng ta đã có tất cả các đoạn trích, chúng ta có thể xây dựng lời nhắc như sau:

 completion = openai.ChatCompletion.create( model="gpt-3.5-turbo-16k", messages=[ {"role": "system", "content": "You are a literature assistant that answers questions based on excerpts."}, {"role": "user", "content": """Consider the following passages: %s ==== Answer this question: %s Be detailed and complete in your analysis. Make references to specific passages where helpful. Answer only based on passages provided. """ % ( '\n===\n'.join(relevant_texts), user_question )}, ] )


Hãy để lệnh gọi API chạy và bạn sẽ thấy nội dung như bên dưới:


 Based on the passages provided, Shakespearean characters deal with the concept of death in various ways. In Hamlet, for example, the characters contemplate the nature of death and its implications. Hamlet himself reflects on the brevity of life and the corrupting influence of vices. He questions the purpose of existence and contemplates suicide as a release from the burdens of life. In the passage, Hamlet says, "To die, to sleep— / To sleep, perchance to dream. Ay, there's the rub, / For in that sleep of death what dreams may come" (Lines 65-67). This shows his contemplation of the afterlife and the uncertainty surrounding it. In Macbeth, characters are confronted with the consequences of their actions and the fragility of life. Lady Macbeth, for instance, experiences guilt and remorse for her involvement in the murder of King Duncan. She is haunted by visions of blood on her hands and expresses the desire to escape the consequences of her actions. In the passage, Lady Macbeth says, "Out, damned spot! Out, I say!" (Line 30). This demonstrates her struggle to cope with the guilt and the psychological toll it takes on her. Furthermore, both Macbeth and Lady Macbeth reflect on the inevitability and the consequences of their actions. In the passage, Macbeth laments the decay of life and the loss of purpose and meaning. He reflects on the transitory nature of existence and the insignificance of worldly achievements. Macbeth states, "Life's but a walking shadow, a poor player / That struts and frets his hour upon the stage" (Lines 217-218). This shows his acceptance of mortality and his realization that material possessions and power do not bring true fulfillment. In summary, Shakespearean characters deal with the concept of death in various ways. They contemplate the nature of life and the afterlife, struggle with guilt and remorse, and question the meaning and purpose of their existence. Shakespeare's exploration of death and mortality through his characters provides insight into the complexities of human nature and the universal human experience of confronting one's mortality.


Đây là một bản tóm tắt rất hay được rút ra từ nhiều phần khác nhau của Hamlet và Macbeth.

Để so sánh, tôi đã tạo phần nhúng cho toàn bộ cảnh và chạy tra cứu RAG thông thường bằng cách sử dụng cùng một lời nhắc, tìm N cảnh hàng đầu có liên quan nhất cho đến khi tôi đạt được 10.000 mã thông báo


 relevant_texts = [] for i in range(10): if len(encoding.encode('\n===\n'.join(relevant_texts))) > 10000: break relevant_texts.append(''.join(macbeth[sorted( [(idx, cosine_similarity(uq_embed, q)) for idx, q in enumerate(macbeth_embed)], key=lambda x: x[1], reverse=True )[i][0]]['lines'])) relevant_texts.append(''.join(hamlet[sorted( [(idx, cosine_similarity(uq_embed, q)) for idx, q in enumerate(hamlet_embed)], key=lambda x: x[1], reverse=True )[i][0]]['lines']))


Nếu bạn đưa thông tin này vào dấu nhắc, bạn sẽ thấy nội dung như bên dưới:


 Based on the provided passages, Shakespearean characters deal with the concept of death in various ways. In Hamlet, the characters reflect on death and mortality extensively. Hamlet himself contemplates suicide, expressing his desire to end his suffering and questioning the purpose of life. He says, "To be, or not to be: that is the question" (Hamlet, Act III, Scene I, Lines 56). This soliloquy reveals his struggle with the concept of death and his contemplation of the consequences of choosing either life or death. Additionally, in the same play, the appearance of the Ghost prompts discussions about death. The characters question the meaning and significance of encountering the dead, and Hamlet grapples with the idea of mortality in relation to his father's death. He reflects, "Oh God! a beast that wants discourse of reason / Would have mourn'd longer" (Hamlet, Act I, Scene II, Lines 152-153). This passage highlights Hamlet's grief and his pondering of the brevity of life and the transitory nature of existence. In Macbeth, the characters also confront death and its consequences. Macbeth, after killing King Duncan, reflects on the significance of the act and its implications. He says, "Will all great Neptune's ocean wash this blood Clean from my hand? No, this my hand will rather The multitudinous seas incarnadine" (Macbeth, Act II, Scene II, Lines 77-79). This passage showcases Macbeth's awareness of the guilt associated with murder and his realization that the blood on his hands cannot be cleansed. Lady Macbeth, on the other hand, shows a different perspective on death. She suppresses her guilt and tries to detach herself from the consequences of their actions. She states, "A little water clears us of this deed" (Macbeth, Act II, Scene II, Line 69). This passage reveals her denial and determination to move forward without remorse. In conclusion, Shakespearean characters deal with the concept of death in various ways. Some contemplate the meaning of life and question the purpose of existence, while others grapple with the guilt and consequences that come with taking a life. Shakespeare explores the complexities of death and mortality through his characters' introspection and their different responses to the inevitability of death.


Đây là một phân tích rất có sức thuyết phục nhưng không đề cập đến nhiều đoạn văn quan trọng nhất trong Hamlet và Macbeth. Như bạn có thể thấy, QE-RAG có lợi thế khác biệt là có thể nhúng ngữ cảnh phù hợp hơn hệ thống RAG tiêu chuẩn.


Tuy nhiên, ví dụ trên không chứng minh được ưu điểm khác của QE-RAG, đó là khả năng giúp nhà phát triển kiểm soát tốt hơn quá trình nhúng. Để xem QE-RAG đạt được điều này như thế nào, chúng ta hãy xem phần mở rộng của vấn đề này - xử lý thuật ngữ mới.


Mở rộng QE-RAG sang thuật ngữ mới

Nơi QE-RAG thực sự tỏa sáng là khi bạn giới thiệu một thuật ngữ mới. Ví dụ: giả sử bạn đang giới thiệu một khái niệm mới, chẳng hạn như từ tiếng Nhật “zetsubou”, là một thuật ngữ nằm giữa sự tuyệt vọng và tuyệt vọng, đặc biệt truyền tải sự đầu hàng trước hoàn cảnh của một người. Nó không thảm khốc ngay lập tức như khái niệm tuyệt vọng của người Anh, mà thiên về sự chấp nhận những điều khó chịu đang xảy ra.


Giả sử chúng ta muốn trả lời một câu hỏi như:


user_question = "How do Shakespearean characters cope with Zetsubou?"


Với vanilla RAG, chúng tôi sẽ thực hiện tìm kiếm nội dung nhúng, sau đó thêm phần giải thích ở bước kỹ thuật nhanh chóng cuối cùng:


 relevant_texts = [] for i in range(10): if len(encoding.encode('\n===\n'.join(relevant_texts))) > 10000: break relevant_texts.append(''.join(macbeth[sorted( [(idx, cosine_similarity(uq_embed, q)) for idx, q in enumerate(macbeth_embed)], key=lambda x: x[1], reverse=True )[i][0]]['lines'])) relevant_texts.append(''.join(hamlet[sorted( [(idx, cosine_similarity(uq_embed, q)) for idx, q in enumerate(hamlet_embed)], key=lambda x: x[1], reverse=True )[i][0]]['lines'])) completion = openai.ChatCompletion.create( model="gpt-3.5-turbo-16k", messages=[ {"role": "system", "content": "You are a literature assistant that answers questions based on excerpts."}, {"role": "user", "content": """Zetsubou is the concept of hopelessness and despair, combined with a surrender to whim of one's circumstances. Consider the following passages: %s ==== Answer this question: %s Be detailed and complete in your analysis. Make references to specific passages where helpful. Answer only based on passages provided. """ % ( '\n===\n'.join(relevant_texts), user_question )}, ] )


Kết quả là một câu trả lời được viết rất hay và có sức thuyết phục nhưng hơi quá căng, tập trung vào một vài cảnh trong Hamlet. Macbeth hoàn toàn không được đề cập trong câu trả lời này, vì không có cảnh nào vượt qua tìm kiếm nhúng. Khi xem xét các phần nhúng, có thể thấy rất rõ rằng ý nghĩa ngữ nghĩa của “zetsubou” đã không được nắm bắt một cách chính xác và do đó không thể lấy được các văn bản liên quan từ nó.


Trong QE-RAG, chúng tôi có thể đưa định nghĩa cho thuật ngữ mới ở giai đoạn tóm tắt, cải thiện đáng kể chất lượng văn bản mà hệ thống có thể truy cập:


 def summarize_for_question(text, question, location, context=''): completion = openai.ChatCompletion.create( model="gpt-3.5-turbo-16k", messages=[ {"role": "system", "content": "You are a literature assistant that provides helpful summaries."}, {"role": "user", "content": """%s Is the following excerpt from %s relevant to the following question? %s === %s === If so, summarize the sections that are relevant. Include references to specific passages that would be useful. If not, simply say: \"nothing is relevant\" without additional explanation""" % ( context, location, question, text )}, ] ) return completion questions = [ "How do characters deal with Zetsubou in Shakespearean plays?" ] summarize_for_question(''.join(scene['lines']), questions[0], "Shakespeare's Macbeth", "Zetsubou is the concept of hopelessness and despair, combined with a surrender to whim of one's circumstances." )


Sử dụng lời nhắc tóm tắt này với các đoạn văn và bạn sẽ thấy những bản tóm tắt cực kỳ chính xác và phù hợp với ngữ cảnh. Những tóm tắt này sau đó có thể được sử dụng trong QE-RAG tiếp theo.


Ngoài ra, việc nhúng câu hỏi sẽ cực kỳ giống nhau, bởi vì mặc dù ada-002 không biết ý nghĩa chính xác của “zetsubou”, sự hiện diện của từ này trong cả hai câu hỏi khiến cho việc nhúng câu hỏi trở nên cực kỳ giống nhau.


Do đó, sử dụng QE-RAG để trả lời câu hỏi ban đầu về Zetsubou, chúng ta nhận được câu trả lời sau:


 Based on the passages provided, Shakespearean characters cope with Zetsubou, or hopelessness and despair, in different ways. In "Macbeth," Lady Macbeth copes with Zetsubou through guilt and anguish. She is consumed by the guilt of her and her husband's actions, and this guilt manifests in her sleepwalking and attempts to wash her hands of imagined blood stains. This can be seen in her utterances of "Out, damned spot!" and her preoccupation with the blood on her hands. Lady Macbeth's coping mechanism is to face the consequences of her actions head-on, even if it means descending into madness. The Doctor and Gentlewoman observe her behavior and acknowledge that her condition requires divine intervention. In "Hamlet," the excerpt does not provide specific passages or examples of characters coping with Zetsubou. However, it does address Hamlet's inner turmoil and struggle to cope with his circumstances. Hamlet's state of mind, confusion, and madness are a reflection of despair. The characters in this scene are attempting to understand Hamlet's condition and find ways to deal with it, but the excerpt does not provide details on how they cope with Zetsubou. In "Macbeth," Macbeth himself copes with Zetsubou by surrendering to his dire circumstances. He becomes desensitized to fear and horror, indicating a kind of resignation to his grim circumstances. He acknowledges that there is no escape from his fate and chooses to face it head-on, even though he knows it will lead to his downfall. Macbeth's reaction to the news of his wife's death and his subsequent soliloquy reflect a deep despair and hopelessness. He sees life as meaningless, a "tale Told by an idiot, full of sound and fury, Signifying nothing." Macbeth's surrender to his circumstances and his belief in the futility of life demonstrate his coping mechanism for Zetsubou. In "Macbeth," Lady Macduff copes with Zetsubou by expressing her feelings of despair and hopelessness. She feels betrayed and abandoned by her husband, who has fled and left their family behind. She questions his actions and believes that they show a lack of love and wisdom. Lady Macduff experiences a sense of abandonment, which aligns with the concept of Zetsubou. She tries to make her son understand the severity of their circumstances, but he questions the definition of a traitor. Lady Macduff ultimately meets a tragic end, indicating that her coping mechanism for Zetsubou is not successful. In summary, Shakespearean characters cope with Zetsubou in different ways. Lady Macbeth copes through guilt and faces the consequences of her actions, even if it means descending into madness. Macbeth copes through surrendering to his dire circumstances and embracing his fate. Lady Macduff copes through expressing her feelings of despair and hopelessness but ultimately meets a tragic end. These characters' coping mechanisms reflect different responses to Zetsubou in Shakespearean plays


Đầu ra vẫn gặp một chút khó khăn với khái niệm này, nhưng rõ ràng là QE-RAG có khả năng tương tác tốt hơn với nội dung của câu hỏi và rút ra từ nhiều nguồn khác nhau.

Và cùng với đó, chúng tôi đã triển khai QE-RAG và chứng minh trường hợp sử dụng của nó!


Phần kết luận

Trong bài viết hôm nay, chúng tôi đã xem xét kiến trúc RAG ngày càng phổ biến và những hạn chế của nó. Sau đó, chúng tôi đã mở rộng kiến trúc RAG bằng kiến trúc mới có tên QE-RAG, nhằm sử dụng đầy đủ hơn khả năng của các mô hình ngôn ngữ lớn. Ngoài việc cải thiện độ chính xác và khả năng truy cập theo ngữ cảnh, QE-RAG cho phép toàn bộ hệ thống phát triển khi tương tác với người dùng và trở nên quen thuộc hơn với các loại câu hỏi đang được hỏi, cho phép các công ty phát triển tài sản trí tuệ độc đáo dựa trên nguồn mở hoặc LLM có sẵn trên thị trường .

Tất nhiên, là một ý tưởng thử nghiệm, QE-RAG không hoàn hảo. Nếu bạn có ý tưởng về cách cải thiện kiến trúc này hoặc chỉ đơn giản là muốn thảo luận về công nghệ LLM, vui lòng gửi cho tôi một dòng thông qua Github hoặc LinkedIn của tôi.