Skip to main content
Glama

vnlaw-kg

Biến văn bản luật thành knowledge graph tra cứu được — rồi cắm thẳng vào AI của bạn.

CI PyPI Python License Tests Zero deps

Nạp PDF luật vào → nhận graph có cấu trúc → AI trả lời kèm trích dẫn nguyên văn, không bịa số điều.


Vấn đề

Hỏi một LLM "mức phạt vi phạm hợp đồng thương mại tối đa là bao nhiêu?" — nó thường trả lời đúng 8%, nhưng dẫn sai số điều. Trong pháp lý, sai một số điều là mất toàn bộ độ tin cậy.

vnlaw-kg buộc AI đọc trước khi trích. Mọi kết quả đều kèm nguyên văn, mã tra lại được, và trạng thái hiệu lực.

Demo

$ vnlaw-kg ingest luat-thuong-mai.pdf bo-luat-dan-su.pdf --doc-id LTM BLDS --db kho.db

Đã nạp 2 tài liệu → kho.db
  LTM:  324 điều,  684 khoản, độ phủ 99.9%
  BLDS: 689 điều, 1418 khoản, độ phủ 100.0%
  Graph: 3439 node / 3720 cạnh
$ vnlaw-kg search "mức phạt vi phạm hợp đồng tối đa" --db kho.db -k 2

### Điều 301 — LTM  (điểm 0.0333)
    Mức phạt vi phạm
    Mức phạt đối với vi phạm nghĩa vụ hợp đồng hoặc tổng mức phạt đối với
    nhiều vi phạm do các bên thỏa thuận trong hợp đồng, nhưng không quá 8%
    giá trị phần nghĩa vụ hợp đồng bị vi phạm, trừ trường hợp quy định tại
    Điều 266 của Luật này.

### Điều 300 — LTM  (điểm 0.0323)
    Phạt vi phạm
    ...

Điều đã bãi bỏ không im lặng biến mất — nó nói rõ ai đã bãi bỏ và từ bao giờ:

$ vnlaw-kg article LTM 102 --db kho.db

=== Điều 102 — LTM ===
Vị trí: Chương IV. XÚC TIẾN THƯƠNG MẠI > Mục 2
Trạng thái: ĐÃ BỊ BÃI BỎ

Điều 102. (được bãi bỏ)

✎ Lịch sử sửa đổi:
   • bãi bỏ bởi 75/2025/QH15 — Mục này bao gồm các điều 102...116 được bãi bỏ
     theo khoản 2 Điều 2 của Luật số 75/2025/QH15, hiệu lực từ 01/01/2026.

Trực quan hóa

Graph không chỉ để tra cứu — nó cho thấy cụm quy phạm nào phải đọc cùng nhau:

Mạng dẫn chiếu

vnlaw-kg viz --db kho.db -o graph.html     # đồ thị tương tác, mở bằng browser
vnlaw-kg viz --db kho.db --format svg -o network.svg

Cài đặt

pip install vnlaw-kg                 # lõi — KHÔNG phụ thuộc gì
pip install "vnlaw-kg[all]"          # + TF-IDF, PDF, DOCX, HTML

Lõi chỉ dùng SQLite + FTS5 có sẵn trong Python, chạy hoàn toàn ngoại tuyến — quan trọng với hồ sơ pháp lý nhạy cảm. CI kiểm tra điều này mỗi lần commit.

Extra

Thêm gì

Khi nào cần

[search]

scikit-learn

truy hồi TF-IDF — khuyến nghị

[embeddings]

sentence-transformers

câu hỏi trò chuyện, không dùng từ của luật

[pdf]

pypdf

máy không có pdftotext (poppler)

[docx]

python-docx

đọc file Word

[graph]

kuzu

truy vấn graph nâng cao khi nạp nhiều luật

Cắm vào AI qua MCP

Đây là cách dùng chính. Thêm vào claude_desktop_config.json (hoặc cấu hình MCP của Cursor / Cline):

{
  "mcpServers": {
    "vnlaw-kg": {
      "command": "vnlaw-kg",
      "args": ["mcp", "--db", "/duong/dan/kho.db"]
    }
  }
}

AI nhận 5 tool: search_law, get_article, get_concept, get_outline, list_documents. Từ đó bạn hỏi bằng ngôn ngữ tự nhiên và nó tự tra graph thay vì đoán theo trí nhớ.

Use case

Ai

Dùng để làm gì

Luật sư / pháp chế

Tra nhanh cụm quy phạm liên quan; kiểm tra điều đã bị bãi bỏ trước khi viện dẫn vào hợp đồng

Dev làm sản phẩm legal-tech

Backend RAG có cấu trúc, thay vì chunk PDF thô rồi cầu may

Doanh nghiệp

Nạp nội quy, quy chế nội bộ + luật liên quan vào một graph, cho nhân viên hỏi đáp

Nghiên cứu / giảng dạy

Phân tích mạng dẫn chiếu, đo mức độ trung tâm của từng chế định

Người dùng AI cá nhân

Cho Claude/Cursor một nguồn luật đáng tin thay vì để nó bịa

Benchmark

Đo trên Bộ luật Dân sự 2015 + Luật Thương mại 2005 (VBHN 2025), MacBook M-series:

Tốc độ

Thao tác

Thời gian

Nạp 2 luật (1.013 điều, 2.102 khoản)

0,42s

Nạp kèm chỉ mục TF-IDF

1,36s

Tìm kiếm (p50 / p95)

1ms / 3ms

Tra một điều

0,1ms

Kho SQLite

6,8 MB

Nạp vào KuzuDB bằng COPY

0,09s (so với 55s nếu CREATE từng dòng)

Độ chính xác parse — đối chiếu với bản dữ liệu đã kiểm chứng thủ công qua nhiều nguồn:

Điều

Khoản

Điều bãi bỏ

Độ phủ nội dung

Bộ luật Dân sự 2015

689/689

1.418/1.418

100%

Luật Thương mại 2005

324/324

684/684

23/23

99,9%

Cạnh REFERS_TO

243/243 (trùng 100% bản curated tay)

Chất lượng truy hồi — 19 câu hỏi pháp lý có đáp án biết trước (tests/test_retrieval_quality.py):

Chỉ số

Kết quả

Hit@1

11/19 = 58%

Hit@3

18/19 = 95%

Hit@5

19/19 = 100%

Con số lấy từ test chạy trong CI, không phải ước lượng — chạy lại bằng pytest tests/test_retrieval_quality.py. Bộ 19 câu còn nhỏ nên hãy đọc nó như mức sàn chống hồi quy, không phải điểm tuyệt đối; mở rộng bộ câu hỏi là việc đầu tiên trong hướng phát triển.

Câu hỏi định nghĩa ("thương nhân là gì") được định tuyến riêng qua cạnh DEFINES: nếu chỉ khớp từ khóa thì nó rớt khỏi top-10, vì cụm "thương nhân" xuất hiện ở hàng trăm điều.

Tự kiểm chất lượng — không cần viết test tay

Parse sai kiểu âm thầm nuốt mất nội dung là rủi ro lớn nhất: không con số đếm nào lộ ra. Nên mỗi lần nạp, thư viện tự chạy các bất biến cấu trúc đúng với mọi văn bản:

  • Độ phủ ký tự — bao nhiêu phần trăm nội dung nguồn thực sự vào graph

  • Liên tục số điều — thiếu điều giữa dải là dấu hiệu sót cả trang

  • Giải dẫn chiếu"Điều 266 của Luật này" có trỏ tới điều có thật không

  • Round-trip — lưu ra rồi đọc lại không đổi nội dung

  • Trùng số điều, điều rỗng, khoản đánh số bất thường

$ vnlaw-kg check ban-trich-mot-phan.pdf

✘ [GAP_ARTICLE]   Thiếu 215 số điều trong dải 1–319.
✘ [DANGLING_REF]  2 dẫn chiếu nội bộ trỏ tới điều không tồn tại (giải được 88,2%).

Nó phát hiện file là bản trích thiếu — không cần ai dạy trước về luật đó.

Dùng như thư viện

from vnlawkg import ingest, open_store

ingest("bo-luat-dan-su.pdf", db="kho.db")

with open_store("kho.db") as st:
    for hit in st.search("lãi suất cho vay tối đa", k=5):
        print(f"Điều {hit.num} ({hit.doc}) — {hit.title}")

    art = st.article("BLDS", "468")
    print(art["text"])
    for n in st.neighbors(art["id"], "REFERS_TO", "in"):
        print("được dẫn chiếu bởi:", n["props"]["cite"])

Hỗ trợ điều bổ sung (Điều 12a)

Luật sửa đổi chèn điều mới bằng hậu tố chữ: Điều 12a nằm giữa Điều 12Điều 13. Nhiều công cụ đọc số điều bằng int nên Điều 12a thành 12ghi đè Điều 12 thật, không báo lỗi. Ở đây số điều là chuỗi có khóa sắp xếp riêng, nên hai điều tồn tại độc lập.

Kiến trúc

tài liệu (PDF/DOCX/TXT/MD/HTML)
   │  loaders.py      — trích text: pdftotext > pypdf, OCR tùy chọn
   ▼
dialects/vietnam.py   — Phần/Chương/Mục/Tiểu mục/Điều/Khoản/Điểm,
   │                    footnote sửa đổi, điều & mục bị bãi bỏ
   ▼
model.py              — Document / Article / Clause / Point (trung lập)
   │
   ├─ validate.py     — bất biến cấu trúc, báo cáo ERROR/WARN/INFO
   ▼
graph.py              — dẫn chiếu, khái niệm, sửa đổi, liên kết chéo tài liệu
   ▼
store.py              — SQLite + FTS5 (+ TF-IDF / embeddings), hợp nhất RRF
   │
   ├─ cli.py    ├─ mcp_server.py   ├─ visualize.py   └─ exporters.py
   │  dòng lệnh │  cho AI           HTML/SVG          JSON/Cypher/GraphML/Kuzu

Thêm hệ thống pháp luật khác

Cấu trúc Phần/Chương/Mục/Điều là đặc thù Việt Nam, nên phần nhận dạng tách thành dialect plugin:

from vnlawkg import register

@register
class MyDialect:
    name = "xx"
    description = "..."
    def detect(self, text: str) -> float: ...      # điểm tin cậy 0..1
    def parse(self, text, *, doc_id, metadata=None): ...

Gói bên thứ ba đăng ký qua entry point legalkg.dialects là dùng được ngay, không cần sửa lõi.

Xuất sang công cụ khác

vnlaw-kg export --db kho.db --format cypher  -o kg.cypher    # Neo4j
vnlaw-kg export --db kho.db --format graphml -o kg.graphml   # Gephi / yEd

Với KuzuDB, bản xuất sinh CSV + COPY nên chạy được truy vấn mà SQL phẳng làm rất tệ:

-- Điều nào CÒN hiệu lực nhưng vẫn dẫn chiếu tới điều ĐÃ BỊ BÃI BỎ?
MATCH (a:Ent)-[e:Rel]->(b:Ent)
WHERE e.rel='REFERS_TO' AND a.status='active' AND b.status='repealed'
RETURN a.cite, b.cite;

Giới hạn cần biết

  • Chỉ trích xuất được thứ có trong văn bản. Không có án lệ, không có nghị định hướng dẫn trừ khi bạn tự nạp.

  • Dẫn chiếu dạng chữ ("theo quy định của pháp luật về đất đai") không nối được thành cạnh vì không nêu số điều.

  • Không phiên bản hóa theo thời gian: graph phản ánh đúng bản văn bạn nạp. Muốn tra luật tại thời điểm ký hợp đồng năm 2019 thì phải nạp bản hợp nhất tương ứng.

  • OCR luôn có sai sót. Với PDF scan, hãy đọc kỹ báo cáo tự kiểm và đối chiếu vài điều mẫu.

  • Đây là công cụ tra cứu, không phải tư vấn pháp lý. Luôn đối chiếu bản gốc trước khi dùng vào việc quan trọng.

Hướng phát triển

Đóng góp cho bất kỳ mục nào đều được hoan nghênh — mục có 🎯 là chỗ dễ bắt đầu nhất.

Ngắn hạn

  • 🎯 Mở rộng bộ câu hỏi benchmark lên 100+ câu, phủ nhiều chế định hơn

  • 🎯 Bắt dẫn chiếu tới khoản/điểm cụ thể (khoản 2 Điều 301) thành cạnh riêng, không chỉ tới cấp điều

  • Nhận diện dẫn chiếu dạng chữ ("pháp luật về đất đai") và nối tới ExternalDocument

  • Cải thiện Hit@1 bằng rerank: dùng cạnh DEFINES/REFERS_TO làm tín hiệu xếp hạng

Trung hạn

  • Phiên bản hóa theo thời gian — truy vấn "luật này quy định thế nào vào ngày 01/06/2019", dựng từ chuỗi văn bản hợp nhất

  • Diff giữa hai bản hợp nhất — chỉ ra chính xác điều nào đổi, đổi thế nào

  • Dialect cho nghị định, thông tư, quyết định (cấu trúc hơi khác luật)

  • Nạp án lệ và nối tới điều luật mà bản án viện dẫn

  • Web UI để tải file lên và duyệt graph, cho người không dùng dòng lệnh

Dài hạn

  • Dialect cho hệ thống pháp luật khác (EU directives, US Code) qua entry point có sẵn

  • Phát hiện xung đột quy phạm: hai điều cùng điều chỉnh một quan hệ nhưng khác nội dung

  • Suy luận trên graph: tự gợi ý cụm điều cần đọc cho một tình huống, dựa trên đường đi dẫn chiếu

  • Gói dữ liệu dựng sẵn cho các luật phổ biến, tải về là dùng ngay

Đóng góp

git clone https://github.com/handonn2000/vnlawkg && cd vnlawkg
pip install -e ".[dev]"
pytest -q && ruff check src tests

Hữu ích nhất: mẫu văn bản làm hỏng parser (kèm file tái hiện) — mỗi định dạng lạ được vá là công cụ chắc chắn hơn một chút.

Giấy phép

Apache-2.0 — dùng được cho mục đích thương mại, có điều khoản bảo hộ sáng chế.


Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/handonn2000/vnlawkg'

If you have feedback or need assistance with the MCP directory API, please join our Discord server