Chuyển tới nội dung
cd /blog

Khai thác vòng lặp: Làm sao các thay đổi trở thành ký ức tổ chức

[Kiến trúc][Quy trình làm việc]

> Các commit Git trở thành các mục changelog có cấu trúc và các bản ghi quyết định kiến trúc, sau đó được đưa trở lại vào AI agent như một ký ức tổ chức có thể truy vấn.

Các con số trong bài này phản ánh hệ thống tại thời điểm xuất bản (tháng 2/2026). Xem trang team của chúng tôi để biết số liệu hiện tại.

Mọi đội kỹ thuật đều đối mặt với cùng một thách thức: các thay đổi diễn ra liên tục, nhưng cái lý do đằng sau những thay đổi đó lại biến mất. Sáu tháng sau, ai đó hỏi “tại sao chúng ta lại chọn DuckDB cho các giai đoạn pipeline?” và câu trả lời chỉ tồn tại trong đầu người đã đưa ra quyết định đó — nếu người đó vẫn còn ở đây.

Chúng tôi đã xây dựng một quy trình khai thác (mining workflow) khép kín vòng lặp này. Các thay đổi chảy qua các commit git, được xử lý bởi pipeline khai thác của chúng tôi, trở thành các mục changelog có cấu trúc và các bản ghi quyết định kiến trúc, sau đó được đưa trở lại vào các AI agent của chúng tôi thông qua các truy vấn CLI. Kết quả: một ký ức tổ chức mà cả con người và AI đều có thể truy cập.

Vấn đề: Quyết định bốc hơi

Hãy xem xét một kịch bản điển hình. Một developer commit:

feat(canonical): add DuckDB runtime for pipeline stages

Commit này đại diện cho một lựa chọn kiến trúc quan trọng. Đội đã đánh giá các phương án, cân nhắc sự đánh đổi, và chốt DuckDB vì những lý do cụ thể. Nhưng toàn bộ ngữ cảnh đó sống trong:

  • Một luồng Slack (có lẽ đã bị xóa)
  • Ký ức của ai đó (chắc chắn đang phai mờ)
  • Một comment trong mã (có thể, nếu may mắn)

Ba tháng sau, một thành viên mới trong đội hỏi: “Tôi nên dùng DuckDB hay SQLite cho giai đoạn mới này?” Không có ký ức tổ chức, họ hoặc phải phát minh lại bánh xe hoặc đưa ra những lựa chọn không nhất quán.

Vòng lặp: Từ Commit đến ngữ cảnh

Quy trình khai thác của chúng tôi biến lịch sử git thành tri thức có thể truy vấn:

Git Commits


┌─────────────────────┐
│  mine sync          │  ← Build index from git history
└─────────────────────┘


┌─────────────────────┐
│  mine candidates    │  ← Surface commits for review
└─────────────────────┘


┌─────────────────────┐
│  Classification     │  ← Human or LLM assessment
│  (changelog or ADR) │
└─────────────────────┘

    ├──────────────────────┐
    ▼                      ▼
┌─────────────┐    ┌───────────────┐
│ Changelog   │    │ Decisions     │
│ Ledger      │    │ Registry      │
│ (JSONL)     │    │ (YAML files)  │
└─────────────┘    └───────────────┘
    │                      │
    ▼                      ▼
┌─────────────┐    ┌───────────────┐
│ CHANGELOG.md│    │ orkestra CLI  │
│ per package │    │ queries       │
└─────────────┘    └───────────────┘
    │                      │
    └──────────────────────┘


      ┌───────────────┐
      │ AI Agents     │
      │ (via CLI)     │
      └───────────────┘

Insight cốt lõi: cả changelog lẫn quyết định kiến trúc đều chảy ra từ cùng một lịch sử git, được xử lý qua một pipeline thống nhất. Điều này đảm bảo không có gì lọt qua kẽ hở.

Cách khai thác hoạt động

Bước 1: Đồng bộ chỉ mục

uv run orkestra mine sync

Lệnh này quét lịch sử git và xây dựng một chỉ mục của tất cả các commit. Nó trích xuất các tín hiệu có cấu trúc từ mỗi commit:

  • Loại commit theo quy ước (conventional commit type) (feat, fix, chore, docs)
  • Scope (package hoặc khu vực nào)
  • Các dấu hiệu breaking change
  • Các file bị động đến và các chỉ số độ phức tạp

Bước 2: Kiểm tra trạng thái độ phủ

uv run orkestra mine status

Đây là trạng thái hiện tại của chúng tôi trông như thế nào:

Mining Status
=============

Decisions
---------
  Coverage:        100.0%
    Processed:     15637  (of 15637)
    Extracted:       476
    Skipped:       15161

Changelog
---------
  Coverage:        100.0%
    Processed:     15637  (of 15637)
    Released:       6799
    Skipped:        8838

15.637 commit đã được xử lý. 476 trở thành quyết định kiến trúc. 6.799 trở thành mục changelog. Mọi commit đều được phân loại.

Bước 3: Lấy các ứng viên để rà soát

uv run orkestra mine candidates --limit 50 --full

Lệnh này làm nổi lên những commit chưa được xử lý, kèm đầy đủ ngữ cảnh để phân loại:

on
{
  "sha": "90571786d99166c0039ca2e80e4d9cd96184bd85",
  "date": "2026-01-26",
  "subject": "feat(canonical): add DuckDB runtime for pipeline stages",
  "signals": {
    "commit_type": "feat",
    "scope": "canonical",
    "breaking": false,
    "is_releasable_type": true,
    "domains_affected": ["pipeline", "data-architecture"]
  },
  "body": "Establishes DuckDB as canonical in-process analytical database...",
  "files_changed": ["packages/canonical/pipelines/stages/duckdb_runtime.py", "..."],
  "stats": {"files": 8, "insertions": 450, "deletions": 120}
}

Các tín hiệu giúp định hướng việc phân loại: is_releasable_type: true gợi ý rằng commit này nên xuất hiện trong changelog. Số lượng dòng thêm vào lớn và các file hạ tầng gợi ý rằng nó cũng có thể là một quyết định kiến trúc.

Bước 4: Phân loại commit

Hai con đường tách nhánh ở đây: mục changelog và quyết định kiến trúc.

Đối với mục changelog:

uv run orkestra mine classify abc123 --changelog added

Điều này ghi nhận rằng commit abc123 nên xuất hiện trong changelog dưới danh mục “Added.”

Đối với quyết định kiến trúc:

Trước tiên, lấy một decision ID thật:

uv run orkestra decisions new --domain pipeline --dry-run
# Returns: DEC-PL-143

Sau đó phân loại kèm decision ID đó:

uv run orkestra mine classify abc123 --decision DEC-PL-143

Điều này liên kết commit với một bản ghi quyết định sẽ được tạo mới hoặc cập nhật.

Đối với xử lý theo lô (điều chúng tôi thực sự làm):

# Generate classifications file with LLM assistance
uv run orkestra mine commit --input classifications.jsonl

Định dạng JSONL hỗ trợ cả hai domain trong một lượt:

on
l
{"sha":"abc123","domain":"changelog","action":"release","category":"added","summary":"Add DuckDB runtime for pipeline stages"}
{"sha":"abc123","domain":"decisions","action":"extract","decision_id":"DEC-PL-142"}
{"sha":"def456","domain":"changelog","action":"skip","reason":"Chore: dependency update"}

Bước 5: Render đầu ra

uv run orkestra changelog render --package <pkg>

Điều này sinh ra các file CHANGELOG.md cho từng package từ ledger. Các changelog là các tài sản dẫn xuất — xóa chúng đi và chúng sẽ được tái sinh hoàn hảo từ ledger nguồn.

Cấu trúc bản ghi quyết định

Các quyết định đã trích xuất trở thành các file YAML với metadata phong phú:

id: DEC-PL-142
title: Adopt DuckDB as Canonical Processing Runtime for Pipeline Stages
domain: pipeline
status: active
created: '2026-01-26'
summary: |
  Establishes DuckDB as the canonical in-process analytical database for pipeline
  stage transformations. Provides a shared runtime module that resolves settings
  from pipeline defaults with stage-level overrides.

context: |
  Pipeline stages performing data transformations each independently configured
  DuckDB connections. This led to inconsistent settings, duplicated configuration
  code, and no way to tune DuckDB globally for a pipeline run.

rationale:
  - DuckDB provides efficient in-process OLAP with zero configuration deployment
  - Centralized runtime module eliminates duplicated DuckDB setup across stages
  - Hierarchical settings enable global tuning with stage-level overrides
  - Memory limits and thread counts can be adjusted per-pipeline

impact:
  positive:
    - Consistent DuckDB configuration across all pipeline stages
    - Single point of control for memory/thread tuning
    - Reduced code duplication in conversion and export stages
  negative:
    - Adds dependency on shared runtime module
    - Stages must adopt new configuration pattern

source_commits:
  - sha: 90571786d99166c0039ca2e80e4d9cd96184bd85
    message: 'feat(canonical): add DuckDB runtime for pipeline stages'
    date: '2026-01-26'
    role: primary

files:
  - packages/canonical/pipelines/stages/duckdb_runtime.py
  - packages/canonical/pipelines/runner.py
  - packages/canonical/pipelines/stages/convert_hdx_admin_boundaries_to_geoparquet.py

related:
  - DEC-DA-014  # Data architecture decisions that influenced this

Mọi quyết định đều liên kết ngược về các commit nguồn của nó. Mọi quyết định đều chỉ rõ những file nào nó ảnh hưởng. Các quan hệ giữa các quyết định là tường minh.

Tích hợp CLI: Truy vấn ký ức tổ chức

Đây là nơi vòng lặp khép lại. Các agent có thể truy vấn quyết định qua CLI:

# Search by topic
uv run orkestra decisions search --query "retry"

Trả về các quyết định về logic thử lại, xử lý lỗi, các mẫu khôi phục.

# Get full details on a specific decision
uv run orkestra decisions info DEC-PL-142

Trả về bản ghi quyết định đầy đủ kèm ngữ cảnh, lý do, và tác động.

# List recent decisions for context
uv run orkestra decisions list --limit 15

Cho thấy những lựa chọn kiến trúc nào đã được thực hiện gần đây.

Cách các agent sử dụng điều này

Các chỉ dẫn nền tảng của orchestrator của chúng tôi bao gồm:

**Essential CLI commands:**
- `orkestra decisions search "X"` — Find architectural decisions

Khi một agent được yêu cầu triển khai thứ gì đó liên quan đến DuckDB, nó có thể kiểm tra trước:

uv run orkestra decisions search --query "DuckDB"

Và khám phá ra DEC-PL-142, học được:

  • Vì sao chúng tôi chọn DuckDB (context)
  • Cách dùng nó đúng cách (agent_guidance)
  • Những file nào cần xem (files)
  • Những quyết định liên quan nào tồn tại (related)

Agent không phát minh lại bánh xe. Nó xây dựng dựa trên các mẫu đã được thiết lập.

Bài kiểm tra ba câu hỏi

Không phải commit nào cũng xứng đáng có một bản ghi quyết định. Chúng tôi dùng Bài kiểm tra ba câu hỏi để lọc:

  1. Việc này có khó để đưa ra không? Nó có đòi hỏi phân tích đáng kể, đánh giá sự đánh đổi, hoặc tranh luận không?
  2. Việc thay đổi nó có tốn kém không? Việc đảo ngược quyết định này có đòi hỏi phải làm lại đáng kể không?
  3. Nó có tác động toàn hệ thống không? Nó có ảnh hưởng đến nhiều package hoặc thiết lập các mẫu mà những người khác sẽ tuân theo không?

Nếu một commit trả lời “có” cho ít nhất một trong các câu hỏi này, nó là ứng viên để trích xuất thành quyết định. Tỷ lệ điển hình của chúng tôi: 1-4 quyết định trên mỗi 100 commit (khoảng 1-4%).

Đối với các mục changelog, thanh chắn thấp hơn: bất kỳ thay đổi nào hướng đến người dùng (tính năng, sửa lỗi, cải tiến) đều được ghi lại. Các công việc vặt nội bộ, cập nhật tài liệu, và refactor thường bị bỏ qua. Tỷ lệ điển hình của chúng tôi: 30-50 mục changelog trên mỗi 100 commit.

Lưu trữ dữ liệu: Ledger chỉ-thêm (Append-Only)

Hệ thống khai thác dùng các ledger JSONL chỉ-thêm để vận hành đa agent không xung đột:

packages/orchestration/ai_assets/reference/changelog/
├── commits_processed.jsonl  # Classification ledger (both domains)
├── release_notes.jsonl      # Changelog entries
└── commits_index.yaml       # Derived index (gitignored)

packages/orchestration/ai_assets/reference/decisions/
├── registry.yaml            # Decision index
└── records/
    ├── DEC-AD-001.yaml
    ├── DEC-AD-002.yaml
    └── ...

Định dạng JSONL với merge=union trong .gitattributes nghĩa là nhiều agent có thể phân loại commit đồng thời mà không có xung đột merge. Mỗi dòng độc lập với nhau.

Cổng xác thực

Trước mỗi phiên khai thác, chúng tôi chạy xác thực:

uv run orkestra mine validate --quick

Điều này kiểm tra:

  • Tính hợp lệ của định dạng SHA
  • Sự tuân thủ định dạng decision ID
  • Không có mục trùng lặp cho cùng một SHA
  • Các quyết định được tham chiếu thực sự tồn tại

Sau khi phân loại, chúng tôi xác thực lại lần nữa trước khi commit các thay đổi.

Vì sao điều này quan trọng

Vòng lặp phản hồi mà chúng tôi đã xây dựng giải quyết một số vấn đề:

Đối với thành viên mới trong đội: Thay vì hỏi “tại sao chúng ta lại làm X?”, họ có thể tìm kiếm trong registry quyết định. Ngữ cảnh được bảo toàn.

Đối với AI agent: Chúng không hoạt động trong chân không. Chúng có thể truy vấn tri thức tổ chức trước khi đưa ra đề xuất. Khi được yêu cầu thêm một giai đoạn pipeline mới, chúng có thể khám phá ra mẫu DuckDB và làm theo.

Đối với tính nhất quán kiến trúc: Các quyết định tường minh và có thể tìm kiếm được. Khi ai đó đề xuất một cách tiếp cận mâu thuẫn với một quyết định hiện có, hệ thống có thể làm nổi lên xung đột đó.

Đối với việc sinh changelog: Ghi chú phát hành không phải là một cuộc chạy đua vào phút chót. Chúng là sản phẩm phụ của việc phân loại liên tục trong suốt quá trình phát triển.

Đối với onboarding: Các agent mới thừa hưởng toàn bộ ngữ cảnh của codebase. Chúng không chỉ thấy mã nguồn — chúng thấy cả những quyết định đã định hình nên nó.

Trạng thái hiện tại

Tính đến hôm nay:

  • 15.637 commit đã được xử lý qua pipeline
  • 476 quyết định kiến trúc đã được trích xuất và ghi lại tài liệu
  • 6.799 mục changelog đã được ghi nhận
  • Độ phủ 100% trên cả hai domain

Mọi commit kể từ khi chúng tôi bắt đầu đều đã được phân loại. Ký ức tổ chức đã hoàn chỉnh và có thể truy vấn được.

Bắt đầu

Nếu bạn muốn triển khai một thứ tương tự:

  1. Bắt đầu với conventional commit. Pipeline khai thác hoạt động tốt nhất khi các commit có tiền tố có cấu trúc (feat:, fix:, chore:).

  2. Định nghĩa các domain của bạn. Chúng tôi dùng các domain như pipeline, agent-design, observability, data-modeling. Chúng tổ chức các quyết định theo khu vực.

  3. Xây dựng thói quen phân loại. Việc khai thác chỉ hiệu quả khi các đội thường xuyên phân loại commit. Xử lý theo lô với sự hỗ trợ của LLM giúp mở rộng quy mô.

  4. Làm cho quyết định có thể truy vấn được. Giá trị tăng lên khi các agent có thể tìm kiếm quyết định qua CLI. Cấu trúc đầu ra của bạn để máy có thể tiêu thụ được.

  5. Khép kín vòng lặp. Các quyết định nên ảnh hưởng đến công việc trong tương lai. Đưa các tham chiếu quyết định vào chỉ dẫn agent và checklist rà soát mã.

Mục tiêu không phải là tài liệu hoàn hảo. Đó là làm cho cái lý do đằng sau các thay đổi trở nên dễ tiếp cận với cả con người và AI, ngay hôm nay và sáu tháng nữa. Khi các thay đổi trở thành ký ức tổ chức, các đội xây dựng dựa trên các mẫu đã được thiết lập thay vì phát minh lại chúng.


Quy trình khai thác là một phần của engine orchestration của chúng tôi, cụ thể là module context engine trong package orchestration của chúng tôi.

Đọc thêm liên quan

Thêm từ nhật ký xây dựng Maguyva

Tự cải thiện đệ quy theo ngôn ngữ: Mài giũa trí tuệ mã nguồn trên khoảng 280 ngôn ngữ_

Chúng tôi hỗ trợ trí tuệ mã nguồn cho khoảng 280 ngôn ngữ. Không con người nào có thể tự tay rà soát hết được. Vì vậy chúng tôi xây dựng một vòng lặp tự cải thiện đệ quy theo ngôn ngữ — kiểm tra ngẫu nhiên, dùng LLM làm giám khảo, sửa từng thứ một, xác thực lại — và chạy nó với một đội quân agent cách ly cho đến khi việc trích xuất thực sự đúng, chứ không chỉ xanh (green).

[Kiến trúc][Ngôn ngữ][Tác nhân]