💡 Ví dụ hoạt động đầy đủ có sẵn trên GitHub:
document-to-markdown-rag-chunks-java
Vấn đề tại bàn làm việc yêu cầu bồi thường: Tại sao việc nhập RAG lại gặp sự cố với các tệp thực
Một quy trình nhập RAG nội bộ là lớp phân tích tài liệu chuyển các tệp mà nhóm đã có thành văn bản có thể tìm kiếm, trích dẫn mà không cần gửi chúng cho bên thứ ba. Các hoạt động bảo hiểm cho thấy tại sao điều này quan trọng. Một nhân viên xử lý yêu cầu bồi thường hỏi trợ lý nội bộ “người định giá đã nói gì về thiệt hại do nước gây ra trên hợp đồng này?”, và câu trả lời nằm trong một email từ tháng Ba vừa rồi, bên trong một báo cáo PDF đính kèm, dưới tiêu đề “Findings”. Trợ lý chỉ có thể tìm được nếu quá trình nhập đọc được tệp đính kèm, giữ lại tiêu đề và nhớ email nào chứa báo cáo.
Hầu hết các công việc nhập sai một trong ba điều sau. Trình trích xuất văn bản thuần trả về phần thân email và bỏ qua tệp đính kèm. Bộ chia cố định 512 token cắt báo cáo ở giữa “Findings”. Và một trình phân tích được lưu trữ giải quyết cả hai, nhưng chỉ sau khi tệp yêu cầu bồi thường, với các chi tiết cá nhân và y tế, đã được tải lên máy chủ của người khác và bị tính phí theo trang.
Nhóm cần một giải pháp hẹp và cụ thể: đọc các tệp Word, PDF, EML và ZIP trong dịch vụ Java đã sở hữu dữ liệu, giữ cấu trúc của chúng dưới dạng Markdown, chia tách tại các tiêu đề của tác giả, và gắn nguồn và cha cho mỗi đoạn.
Market snapshot: các hướng dẫn năm 2026 về “phân tích tài liệu cho RAG” mà chúng tôi đã xem xét so sánh các trình phân tích Python mã nguồn mở với các API đám mây tính phí theo trang. Thư viện Java chạy trên phần cứng của bạn hầu như không xuất hiện trong cuộc trò chuyện đó.
Tại sao các quy trình RAG cần Markdown thay vì Văn bản thuần?
Markdown giữ lại các phần của tài liệu cho biết cho bộ truy xuất biết ý tưởng này kết thúc ở đâu và ý tưởng tiếp theo bắt đầu ở đâu. Các tiêu đề trở thành các dòng #, bảng vẫn giữ dạng hàng và cột, và danh sách giữ các mục của chúng. Bộ chia đoạn có thể tách dựa trên các tiêu đề đó, và một LLM đọc đoạn sẽ thấy cùng một dàn bài như con người. Văn bản thuần loại bỏ dàn bài này, chỉ để lại kích thước làm tín hiệu duy nhất để chia tách.
Tại sao các giải pháp chung không hoạt động ở đây
Các đội thường thử một trong ba cách trước khi xây dựng một lớp nhập đúng chuẩn:
- Trích xuất văn bản thuần cộng với bộ chia token: nhanh để thiết lập, nhưng các đoạn trộn lẫn các phần và mất tiêu đề mà bạn muốn trích dẫn.
- API phân tích đám mây: cấu trúc tốt, nhưng các tệp rời mạng và chi phí tăng lên với mỗi trang được lập chỉ mục lại.
- Trình phân tích tự xây dựng cho mỗi định dạng: một thư viện cho DOCX, một cho PDF, một trình phân tích MIME cho email và
java.util.zipcho các kho lưu, mỗi cái có các trường hợp góc riêng.
GroupDocs.Parser for Java bao phủ cả bốn định dạng này trong một lớp Parser duy nhất và chạy trong cùng tiến trình.
Giải pháp: GroupDocs.Parser trong quy trình nhập yêu cầu bồi thường
GroupDocs.Parser for Java đọc tài liệu và có thể trả về văn bản dưới dạng Markdown qua getFormattedText. Email và kho lưu được mở ra như các container, các mục của chúng mở thành các thể hiện Parser mới, vì vậy một PDF đính kèm trong email được xử lý giống như một PDF trên đĩa. Dự án mẫu gói các chức năng này trong sáu phương thức tĩnh và ghi kết quả dưới dạng JSON Lines, mà bất kỳ công việc nhúng nào hoặc kho vector nào cũng có thể tải. Không có khung RAG nào tham gia; định dạng đầu ra là điểm tích hợp.
Để theo dõi, bạn cần:
- JDK 11 trở lên cho
pom.xmlđược cung cấp (mã nguồn vẫn tuân theo tính năng Java 8) - GroupDocs.Parser for Java 26.10 (get a temporary licence)
- Một vài tệp DOCX, PDF, EML hoặc ZIP
pom.xml của dự án khai báo kho https://releases.groupdocs.com/java/repo/ và phụ thuộc duy nhất, vì vậy việc biên dịch chỉ cần một lệnh:
mvn compile exec:java
Triển khai lớp nhập từng bước
Các bước dưới đây theo dõi một tệp yêu cầu bồi thường từ hộp thư đến chỉ mục. Mỗi bước tương ứng với một hoặc hai phương thức trong RagChunksDemo.java. Chúng tôi giữ chúng dưới dạng các phương thức tĩnh thuần mục đích, để bạn có thể đưa bất kỳ phương thức nào vào một worker hiện có mà không cần áp dụng toàn bộ.
Bước 1 - Mở mỗi tệp và định tuyến nó
Mỗi tệp được tải lên sẽ có một Parser riêng. Tên tệp trở thành source id, và tệp cấp cao nhất không có parent.
// One call per uploaded claim document
String sourceId = new File(path).getName();
try (Parser parser = new Parser(path)) {
return chunkParser(parser, sourceId, null, 0); // null parent: top-level file
} catch (UnsupportedDocumentFormatException ex) {
// An unknown format is logged and skipped, the batch keeps going
System.out.println("skipped (unsupported format): " + sourceId);
return new ArrayList<>();
}
chunkParser sau đó trích xuất phần thân, chia thành các đoạn và đệ quy vào các tệp đính kèm khi độ sâu dưới 2.
Bước 2 - Yêu cầu Markdown, chấp nhận Văn bản thuần
Bước trích xuất kiểm tra định dạng hỗ trợ gì thay vì mã cứng danh sách các phần mở rộng.
if (parser.getFeatures().isFormattedText()) {
// Headings, lists and tables survive as Markdown
FormattedTextOptions options =
new FormattedTextOptions(FormattedTextMode.Markdown);
try (TextReader reader = parser.getFormattedText(options)) {
if (reader != null) {
return new ExtractedText("markdown", reader.readToEnd());
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
try (TextReader reader = parser.getText()) {
if (reader != null) { // fallback for formats without formatted text
return new ExtractedText("plain", reader.readToEnd());
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return new ExtractedText("none", ""); // e.g. a photo with no OCR
Tại sao các cài đặt này quan trọng đối với dữ liệu yêu cầu bồi thường:
FormattedTextMode.Markdown: tiêu đề “Findings” của người định giá sẽ tới bộ chia đoạn dưới dạng## Findings, vì vậy nó có thể trở thành điểm tách và một trích dẫn.isFormattedText(): trong lần chạy mẫu, DOCX và email trả về Markdown trong khi PDF quay lại văn bản thuần, và trườngformatghi lại điều đã xảy ra.- Kết quả
none: ảnh yêu cầu bồi thường trong ZIP không tạo ra đoạn nào nếu không có OCR, điều này trung thực và dễ giám sát.
Bước 3 - Chia tách tại các tiêu đề của người định giá
Bộ chia đoạn giữ một ngăn xếp các tiêu đề hiện tại ở mỗi cấp độ Markdown (tối đa sáu). Một tiêu đề mới đóng phần đang chạy và đặt lại mọi thứ dưới cấp độ của nó.
for (String line : markdown.split("\\r?\\n", -1)) {
Matcher heading = HEADING.matcher(line); // "#" to "######" + title
if (heading.matches()) {
// Close the previous section under the old path
addSection(chunks, section.toString(), sourceId, parentId, path, format);
section.setLength(0);
int level = heading.group(1).length();
stack[level - 1] = heading.group(2).trim();
for (int i = level; i < stack.length; i++) {
stack[i] = null; // forget deeper headings
}
path = joinPath(stack); // "Heading 1 > Heading 1.2"
}
section.append(line).append('\n');
}
Các phần có hơn 1500 ký tự sẽ được cắt tại ngắt đoạn, vì vậy một phần “findings” dài sẽ thành nhiều đoạn chia sẻ cùng một đường dẫn tiêu đề. Trên tệp Word mẫu, điều này tạo ra các đường dẫn như Heading 1 > Heading 1.2 > Heading 1.2.1.
Bước 4 - Theo dõi tệp đính kèm và ghi JSON Lines
Đây là bước mà bàn làm việc yêu cầu bồi thường quan tâm nhất. getContainer() liệt kê các tệp đính kèm email và các mục ZIP; mỗi mục mở thành tài liệu con và kế thừa id của cha.
Iterable<ContainerItem> items = parser.getContainer();
if (items == null) {
return chunks; // not an email or archive
}
for (ContainerItem item : items) {
// "claim-0412.eml/report.pdf" style ids keep the lineage readable
String childId = sourceId + "/" + item.getFilePath();
try (Parser child = item.openParser()) {
chunks.addAll(chunkParser(child, childId, sourceId, depth + 1));
} catch (UnsupportedDocumentFormatException ex) {
System.out.println("skipped (unsupported format): " + childId);
}
}
writeJsonl sau đó ghi một dòng UTF‑8 cho mỗi đoạn với các trường id, source, parent, heading_path, format và text. Với bốn đầu vào mẫu, quá trình chạy tạo ra 22 dòng. Đoạn từ tệp đính kèm email mẫu là email-with-attachment.eml/attachment.txt#0, và parent của nó là email-with-attachment.eml. Cặp này cho phép trợ lý nói “từ báo cáo đính kèm email ngày 14 tháng 3” thay vì “từ đâu đó trong kho lưu”.
Quy trình thực tế: Tái lập chỉ mục yêu cầu bồi thường hàng tuần
Hãy tưởng tượng một đội vận hành yêu cầu bồi thường xuất khẩu các hộp thư đã đóng trong tuần mỗi thứ Sáu dưới dạng tệp EML và các gói ZIP chứa tài liệu hỗ trợ. Một worker Java đã chuyển các xuất khẩu này vào kho tài liệu. Thêm bước nhập nghĩa là gọi chunkDocument cho mỗi tệp và nối đầu ra JSON Lines vào hàng đợi nhúng.
Bước 4 là thứ giữ báo cáo dự trữ gắn vào email đã gửi nó. Bước 3 có nghĩa là khi trợ lý trích dẫn “Findings”, trích dẫn sẽ ghi tên tệp và tiêu đề thay vì chỉ số đoạn. Quy tắc chung của tôi cho loại chỉ mục này: nếu một đoạn không thể được trích dẫn lại tới một tệp và một tiêu đề, nó không nên có trong chỉ mục.
Tác động kinh doanh: Những gì thay đổi
| Khía cạnh | Cấu hình điển hình trước đây | Với quy trình GroupDocs.Parser |
|---|---|---|
| Nơi các tệp được phân tích | Điểm cuối bên thứ ba | Bên trong JVM của bạn |
| Mô hình chi phí phân tích | Theo trang, mỗi lần tái lập chỉ mục | Không có phí đám mây theo trang |
| Ranh giới đoạn | Cửa sổ token cố định | Tiêu đề của tác giả, giới hạn 1500 ký tự |
| Đính kèm email | Thường bị bỏ qua hoặc làm phẳng | Phân tích như tài liệu con |
| Dữ liệu trích dẫn | Tên tệp ở mức tối đa | source, parent và heading_path |
| Phụ thuộc thời gian chạy | SDK cộng với truy cập mạng | Một artifact Maven |
Hiệu ứng tổng hợp là một chỉ mục mà đội tuân thủ có thể phê duyệt và một trợ lý mà các câu trả lời chỉ tới tài liệu và phần thực tế.
Các kịch bản bảo hiểm khác mà GroupDocs.Parser phù hợp
Khi lớp nhập đã tồn tại, cùng một đoạn mã phục vụ các công việc nặng tài liệu khác:
- Tìm kiếm nội dung hợp đồng: tài liệu Word của hợp đồng được chia theo tiêu đề điều khoản, vì vậy câu trả lời trích dẫn đúng phần.
- Đơn nộp của môi giới: tải lên ZIP chứa PDF và bảng tính hỗn hợp, lập chỉ mục từng mục, mỗi mục gắn với đơn nộp.
- Xử lý khiếu nại: email khách hàng và các tệp đính kèm được lập chỉ mục cùng nhau, với email là cha của mỗi đoạn đính kèm.
Bắt đầu trong môi trường yêu cầu bồi thường của bạn
Sao chép mẫu, chạy nó với một vài email đã xuất khẩu của bạn, và mở output/chunks.jsonl để kiểm tra đường dẫn tiêu đề và parent id trước khi tích hợp vào công việc nhúng. Các ghi chú kiến trúc từng bước có trong documentation use case for this pipeline, và Markdown output reference liệt kê các định dạng mà chế độ này giữ lại.