AI Agent Không Cần Thêm Ngữ Cảnh — Chúng Cần Ngữ Cảnh Được Kiểu Hóa

Công nghệ24 tháng 8, 2026·11 phút đọc

Bài viết phân tích một vấn đề cốt lõi trong thiết kế AI agent: khi các nguồn ngữ cảnh đa dạng (chỉ dẫn, bộ nhớ, dữ liệu truy xuất, đầu ra công cụ) bị ép thành chuỗi văn bản thuần, ranh giới ngữ nghĩa của chúng biến mất, dẫn đến các lỗi khó truy vết. Tác giả giới thiệu một runtime Python nhẹ, không phụ thuộc thư viện ngoài, hoạt động như một hệ thống kiểu dữ liệu cho ngữ cảnh, đảm bảo dữ liệu từ công cụ không thể âm thầm trở thành chỉ dẫn. Giải pháp này mang lại khả năng kiểm soát nguồn gốc và xác thực chặt chẽ trước khi prompt được tạo, giúp lập trình viên phát hiện lỗi cấu trúc sớm thay vì dựa vào mô hình để tự suy luận.

AI Agent Không Cần Thêm Ngữ Cảnh — Chúng Cần Ngữ Cảnh Được Kiểu Hóa

AI Agent Không Cần Thêm Ngữ Cảnh — Chúng Cần Ngữ Cảnh Được Kiểu Hóa

Khi xây dựng hệ thống AI agent, nhiều lập trình viên thường đối mặt với những lỗi kỳ lạ tưởng chừng do mô hình gây ra, nhưng thực chất lại bắt nguồn từ việc trộn lẫn các loại ngữ cảnh khác nhau thành một chuỗi văn bản duy nhất. Bài viết này đề xuất một giải pháp runtime nhẹ, không phụ thuộc thư viện ngoài, hoạt động như một hệ thống kiểu dữ liệu (type system) cho ngữ cảnh, giúp phân loại rõ ràng từng phần thông tin và ngăn chặn các lỗi cấu trúc trước khi chúng đến được mô hình. Phương pháp này hứa hẹn cải thiện khả năng gỡ lỗi và kiểm soát chất lượng dữ liệu, dù không trực tiếp nâng cao năng lực suy luận của AI.

Vấn đề Không Nằm Ở Việc Thiếu Ngữ Cảnh

Phản ứng thông thường khi một agent tạo ra kết quả bất thường là thêm thật nhiều ngữ cảnh: chèn thêm tài liệu truy xuất, thêm đoạn chỉ dẫn hệ thống, thêm ví dụ, thêm lời nhắc cho lần nhắc trước. Cách tiếp cận này xuất phát từ một trực giác hợp lý — kỹ thuật ngữ cảnh (context engineering) đã trở thành góc nhìn chính để cải thiện hành vi agent. Nhưng nó trả lời một câu hỏi: “điều gì nên đến với mô hình?” — trong khi bỏ qua một câu hỏi khác hoàn toàn: “runtime có biết mỗi phần ngữ cảnh thực sự là gì không?”

Trong một phiên chạy agent điển hình, runtime phải quản lý chỉ dẫn hệ thống, yêu cầu người dùng, tài liệu truy xuất từ vector store, lịch sử hội thoại, kết quả đầu ra công cụ và biến trạng thái ứng dụng. Khi tất cả được ghép thành một chuỗi duy nhất, ranh giới quan trọng biến mất:

  • Một kết quả công cụ có thể đọc giống như một chỉ dẫn chủ động.
  • Một sở thích lịch sử được nhớ có thể đọc như một yêu cầu cứng nhắc cho lượt hiện tại.
  • Một tài liệu tham chiếu truy xuất có thể đọc như một lệnh hệ thống có thẩm quyền.

Điều này không cần sự kiện bất thường nào. Nó xảy ra tự nhiên khi dữ liệu không đồng nhất bị nén bằng lệnh “\n”.join(...) ngây thơ trước khi trao cho mô hình. Runtime chưa từng gán kiểu cho dữ liệu.

Sơ đồ kiến trúc minh họa luồng dữ liệu trước và sau khi áp dụng kiểu hóaSơ đồ kiến trúc minh họa luồng dữ liệu trước và sau khi áp dụng kiểu hóa

Ví dụ, một công cụ vận chuyển trả về ngày giao hàng kèm ghi chú lịch sử chưa định dạng: “Đơn hàng sẽ đến ngày 19/8. Yêu cầu trước đó của khách: 25/8.” Pipelines chuẩn không phân biệt hai dòng này — cả hai chỉ là đầu ra công cụ và được nối thẳng vào prompt builder. Không có sự thực thi cấu trúc nào ở bất kỳ đâu. Khi đến prompt builder, “đầu ra công cụ” và “chỉ dẫn hệ thống” là cùng một kiểu dữ liệu: str.

Tại Sao Delimiter Không Phải Hệ Thống Kiểu

Một phản đối hợp lý: XML tags hoặc Markdown headers có thể phân định ngữ cảnh. Nhưng định dạng chỉ là lựa chọn trình bày, không phải đảm bảo runtime. XML tags mô tả ý định cho người đọc và mô hình, nhưng không ngăn mã ứng dụng thực thi prompt += f"{tool_result}". Không có gì trong delimiter ngăn dòng đó biên dịch và chạy sạch sẽ. Ranh giới mà delimiter muốn truyền đạt chỉ tồn tại bên trong chuỗi prompt cuối, sau khi quyết định cấu trúc đã được thực hiện trong mã. Đến khi XML tags được render, sự nhầm lẫn kiểu — nếu xảy ra — đã diễn ra âm thầm.

Giả Thuyết và Cách Thực Hiện

Nếu ngữ cảnh mang kiểu tường minh trước khi tuần tự hóa, runtime có thể thực thi các quy tắc xác định về cách kiểu được phép thay đổi, bắt lỗi ngay khoảnh khắc nó xảy ra. Đây là ý tưởng tương tự như Design by Contract của Bertrand Meyer từ những năm 1980 — đưa tiền điều kiện và hậu điều kiện tường minh cho các hàm, để vi phạm lộ diện ngay lập tức.

Chuỗi bằng chứng minh họa cách kiểu hóa và xác thực được áp dụng trước khi tuần tự hóa promptChuỗi bằng chứng minh họa cách kiểu hóa và xác thực được áp dụng trước khi tuần tự hóa prompt

Bốn Loại Ngữ Cảnh Cốt Lõi

Runtime sử dụng bốn loại nền tảng, triển khai bằng Python Enum: INSTRUCTION, EVIDENCE, MEMORY, TOOL_OUTPUT. Mỗi mục ngữ cảnh là một dataclass mang năm thuộc tính siêu dữ liệu bên cạnh văn bản thô: context_type (một trong bốn giá trị), source (hệ thống, công cụ, retriever), created (timestamp), request_id (mã duy nhất), và derived_from (mã mục đã biến đổi thành mục này).

Thuộc tính derived_from quan trọng hơn dự kiến ban đầu — nó biến việc thăng hạng kiểu thành thứ có thể kiểm toán, thay vì thao tác xảy ra âm thầm bên trong hàm phụ trợ.

Cơ Chế Thực Thi

ContextStore duy trì một sổ cái nội bộ ánh xạ nội dung thô sang kiểu được đăng ký ban đầu. Khi cùng nội dung xuất hiện lại dưới kiểu được bảo vệ mà không đi qua bước biến đổi tường minh, store từ chối thao tác:

existing = self._ledger.get(key)
if existing is not None:
    origin_type, origin_id = existing
    if origin_type != context_type:
        if context_type in PROTECTED_TYPES and not _via_transform:
            raise ContextTypeError(
                f"{origin_type.value} cannot be inserted into "
                f"{context_type.value} context "
                f"(content first registered as {origin_type.value}, id={origin_id})"
            )

Việc thay đổi kiểu hợp pháp vẫn có đường đi rõ ràng: hàm transform() cho phép đầu ra công cụ trở thành bằng chứng, nhưng chỉ sau khi vượt qua kiểm tra xác thực tối thiểu (như từ chối chuỗi chứa “error” hoặc “failed”), và luôn đính kèm dấu vết derived_from.

Minh họa quá trình biến đổi thành công có theo dõi dòng dõiMinh họa quá trình biến đổi thành công có theo dõi dòng dõi

Điểm quan trọng: không có bước nào yêu cầu mô hình tham gia. Loại không được suy luận từ văn bản sau đó — nó được khai báo bởi phần ứng dụng tạo ra nội dung, giống như cách kiểu trả về của hàm được khai báo tại nơi viết hàm, chứ không phải đoán tại nơi gọi.

ContextAssembler là nơi duy nhất biến các đối tượng có kiểu thành chuỗi. Nó duyệt các mục theo thứ tự cố định (chỉ dẫn → bộ nhớ → bằng chứng → đầu ra công cụ) và render từng phần với nhãn rõ ràng. Mọi thứ phía trên bước này hoạt động trên các đối tượng ContextItem với trường kiểm tra được.

Kết Quả Chạy Thực Tế

Chương trình demo chạy thành công với 8/8 kiểm tra vượt qua, hoàn toàn không cần gọi LLM. Kết quả cho thấy:

  • Ba đối tượng đi vào, ba đối tượng có kiểu đi ra với nguồn và ID tường minh.
  • Việc thăng hạng hợp lệ (tool output → evidence) được chấp nhận và ghi nhận.
  • Việc chèn tool output vào instruction context bị từ chối — “tool_output cannot be inserted into instruction context”.
  • Đầu ra công cụ lỗi (chứa “Status: failed”) không thể được thăng hạng thành bằng chứng ngay cả qua đường hợp lệ.

Tám kiểm tra bao gồm: chống thăng hạng evidence thành instruction, đảm bảo bộ nhớ lịch sử và trạng thái hiện tại cùng tồn tại mà không đè nhau, xác nhận rằng nỗ lực chèn bất hợp pháp không làm thay đổi đối tượng gốc, và xác thực rằng đường biến đổi hợp lệ không phải lối đi tự do.

Đáng chú ý, tác giả phát hiện một lỗi thực tế trong chính runtime: khi transform() đăng ký lại nội dung dưới kiểu mới, nó ghi đè ID đăng ký ban đầu, khiến thông báo lỗi trỏ sai nguồn. Việc sửa chỉ là một điều kiện bảo vệ để khóa ID đầu tiên — minh chứng rằng loại lỗi này có thể xảy ra ở bất kỳ đâu, và hệ thống kiểu hóa giúp bắt chúng hiệu quả.

Ba Lớp, Không Phải Thay Thế Nhau

Cần phân biệt ba khái niệm thường bị nhầm lẫn:

  • Prompt engineering — cách diễn đạt một chỉ dẫn, vận hành trên từ ngữ chính xác trong thông điệp gửi mô hình.
  • Context engineering — thông tin nào cần đến mô hình cho một lượt, quản lý lựa chọn (truy xuất, tra cứu bộ nhớ, cắt tỉa) dưới ngân sách token.
  • Context typing — một khi context engineering chọn thông tin, mỗi mục được phép đại diện cho điều gì và runtime có thể thực hiện thao tác nào trên nó trước khi tuần tự hóa.

Các lớp này xếp chồng, không thay thế nhau. Một đối tượng ngữ cảnh có kiểu vẫn cần được cấu trúc thành prompt rõ ràng; ngược lại, prompt được đánh bóng mà sinh từ ngữ cảnh sai kiểu vẫn không an toàn.

So sánh luồng gỡ lỗi trước và sau khi áp dụng kiểu hóa ngữ cảnhSo sánh luồng gỡ lỗi trước và sau khi áp dụng kiểu hóa ngữ cảnh

Gợi Ý Thực Tế Cho Lập Trình Viên

Khi agent tạo phản hồi kỳ lạ, thay vì thêm ngay đoạn chỉ dẫn hệ thống khác, hãy đặt các câu hỏi cấu trúc:

  • Có phải chỉ dẫn bị trộn với bằng chứng bên ngoài ở đâu đó phía trên?
  • Có phải bộ nhớ lịch sử bị nhầm với trạng thái hiện tại?
  • Có phải kết quả công cụ thô được chèn vào ngữ cảnh mà không xác thực?
  • Có phải nội dung truy xuất bị nâng lên kênh chỉ dẫn mà nó không bao giờ nên chiếm giữ?

Nếu câu trả lời là “có” cho bất kỳ câu hỏi nào, thêm prompt chỉ trị triệu chứng. Sửa chữa thực sự nằm ở lớp runtime — nơi bạn có thể biết ngay điều gì thực sự hỏng, thay vì hy vọng bản vá prompt giải quyết cả hai vấn đề hoàn toàn khác nhau: ngữ cảnh bị hỏng trên đường vào, hay mô hình suy luận sai trên dữ liệu sạch.

Cách Tự Chạy Thử

Dự án gồm sáu module không phụ thuộc thư viện ngoài, chạy hai tập lệnh trong mili-giây mà không cần gọi mạng hay API key:

  • context_types.py — enum ContextType và ContextTypeError
  • context_item.py — dataclass ContextItem với trường theo dõi nguồn gốc
  • policy.py — định nghĩa kiểu được bảo vệ và chuyển đổi được phép
  • validator.py — ContextStore: sổ cái nguồn gốc và logic thực thi
  • assembler.py — ContextAssembler: biến mục có kiểu thành prompt có cấu trúc
  • transforms.py — quy tắc biến đổi tường minh
  • demo.py — ví dụ tra cứu đơn hàng
  • tests.py — tám kiểm tra đơn vị

Chạy bằng python demo.pypython tests.py. Lưu ý rằng request_id dựa trên uuid.uuid4(), nên ID của bạn sẽ khác — đó là hành vi mong đợi. Cấu trúc pipeline, lệnh từ chối và quy tắc thăng hạng giữ nguyên qua các lần chạy.

Kết Luận Thẳng Thắn

Đây là cơ chế thực thi có mục tiêu, bắt một lớp lỗi cụ thể: nội dung âm thầm thay đổi vai trò ngữ nghĩa trên đường vào prompt. Nó không phải framework orchestration agent hoàn chỉnh, không đảm bảo mô hình suy luận đúng, không loại bỏ hallucination, không đảm bảo đầu ra xác định qua các lần chạy.

Những gì nó cung cấp: ranh giới kiểu tường minh giữa các loại ngữ cảnh, nguồn gốc truy vết cho mọi mục (kể cả qua bước biến đổi), quy tắc thăng hạng được kiểm soát bằng whitelist nghiêm ngặt, kiểm tra xác thực xác định chạy hoàn toàn trong mã ứng dụng, và lắp ráp prompt có cấu trúc giữ nhãn cho mọi dữ kiện nền.

Giống như một chiếc thẻ kho trong nhà máy: nó không quyết định thứ bạn xây dựng, chỉ giữ các bộ phận lỗi tránh xa đống chỉ dẫn lắp ráp trước khi ai đó mắc lỗi đắt giá. Khoảng cách mà hệ thống kiểu hóa lấp đầy — giữa việc biết điều gì đến với mô hình và biết ý nghĩa của điều đó — đang làm một công việc thiết yếu cho mọi agent lấy ngữ cảnh từ nhiều nguồn, dù runtime hiện tại của bạn có thực thi tường minh hay không.

Chia sẻ:FacebookX
Nội dung tổng hợp bằng AI, mang tính tham khảo. Xem bài gốc ↗