Xây dựng một Knowledge Graph duy nhất cho 46 Repository

Tôi là Ryan, CTO tại airCloset.

Tôi đã dành ba tháng để xây dựng code-graph. Đây là một knowledge graph duy nhất giúp thống nhất 46 repository thuộc nhiều dịch vụ khác nhau.

Nhiều người nghĩ rằng bạn chỉ cần đưa toàn bộ mã nguồn cho AI và đặt câu hỏi. Điều này thất bại vì hai lý do:

  • Cửa sổ ngữ cảnh (Context windows): Bạn không thể đưa hàng năm trời mã nguồn từ 46 repo vào trong một prompt duy nhất.
  • Ảo giác (Hallucination): AI mắc lỗi khi cố gắng suy luận các mối quan hệ. Nó bỏ lỡ các kết nối.

Để giải quyết vấn đề này, tôi đã sử dụng phân tích tĩnh (static analysis) để xây dựng một nguồn sự thật (source of truth).

Thách thức: Vượt qua các ranh giới

Một codebase lớn thường rất lộn xộn. Một API có thể được gọi bởi năm repository khác nhau. Một bảng cơ sở dữ liệu có thể được sử dụng bởi ba dịch vụ khác nhau.

Nếu bạn chỉ nhìn vào một repository, bạn sẽ bỏ lỡ bức tranh toàn cảnh. Điều này rất nguy hiểm. Nếu bạn thay đổi mã nguồn mà không thấy được phạm vi ảnh hưởng (blast radius) thực sự, bạn sẽ làm hỏng hệ thống.

Cách tiếp cận của tôi sử dụng tree-sitter để phân tích mã nguồn thành các cây cú pháp (syntax trees). Nhưng chỉ riêng tree-sitter thì không thể nhìn xuyên qua ranh giới giữa các repository.

Tôi đã xây dựng các boundary nodes (nút ranh giới) để giải quyết vấn đề này.

Cách thức hoạt động:

  • Chúng tôi trích xuất các mối quan hệ trong một repo bằng tree-sitter.
  • Chúng tôi sử dụng TypeScript Compiler API để giải quyết các kiểu dữ liệu (types) và biến (variables).
  • Chúng tôi sử dụng Gemini để xử lý các trường hợp động mà các công cụ khác bỏ lỡ.

Thay vì yêu cầu AI đoán, chúng tôi cung cấp cho nó các sự thật. Chúng tôi nói với nó: "API này cũng được gọi từ Repo X." Điều này giúp ngăn chặn tình trạng ảo giác.

Phần khó khăn: Sự đa dạng của các Framework

Cuộc chiến thực sự nằm ở việc trích xuất các ranh giới này. Mỗi framework lại định nghĩa ranh giới theo một cách khác nhau.

Một nhóm sử dụng NestJS decorators. Một nhóm khác sử dụng Express routes. Một nhóm khác lại dùng jQuery thuần. Mỗi loại tạo ra một cấu trúc khác nhau trong mã nguồn.

Để làm được điều này, chúng tôi phải xây dựng các bộ parser tùy chỉnh cho:

  • NestJS và TypeORM
  • Express và Fastify
  • AngularJS và Redux
  • Các cơ chế path-alias khác nhau

Chúng tôi phải hướng tới độ chính xác 99%. Nếu tỷ lệ kết nối chỉ đạt 90%, AI sẽ bỏ lỡ 10% các kết nối. Trong một hệ thống thực tế (production system), 10% đó chính là nơi các lỗi (bugs) ẩn náu.

Hiện tại, chúng tôi thực hiện kiểm tra hàng ngày. Nếu tỷ lệ kết nối giảm hơn 5%, chúng tôi sẽ nhận được cảnh báo. Điều này giúp phát hiện khi các pattern mã nguồn mới làm hỏng các bộ parser của chúng tôi.

Các hạn chế hiện tại

Knowledge graph này không hoàn hảo.

  • Tìm kiếm rất khó khăn. Bạn thường cần biết tên một hàm để bắt đầu tìm kiếm.
  • Bùng nổ nút (Node explosion). Việc đi theo một đường dẫn có thể kéo theo hàng ngàn hàm bổ trợ (helper functions) nhỏ nhặt và vô dụng.
  • Bảo trì. Mỗi khi một framework mới xuất hiện trong stack của chúng tôi, chúng tôi lại phải viết một bộ parser mới.

Đây là Phần 1. Trong Phần 2, tôi sẽ thảo luận về lớp service-product-graph (SPG) mà tôi đã xây dựng để khắc phục những lỗ hổng này.

Source: https://dev.to/ryantsuji/building-one-knowledge-graph-across-46-repositories-with-static-analysis-part-1-egm

Optional learning community: https://t.me/GyaanSetuAi