Semantic Kernel web plugin: đọc web có allowlist và lỗi rõ
Semantic Kernel web plugin là một plugin native viết bằng Python, cho phép agent dùng Semantic Kernel đọc nội dung một trang web khi model cần. Plugin kiểu này dễ viết, chỉ cần vài dòng với decorator kernel_function. Cái khó nằm ở chỗ khác: giới hạn plugin được đọc ở đâu, trả về gì cho model, và báo lỗi thế nào để model không đoán bừa. ProxyVN viết một plugin đọc web có danh sách miền cho phép, chạy với semantic-kernel 1.46.0 trên máy chủ fixture cục bộ ngày 03/11/2026, và ghi lại từng kết quả kể cả các ca lỗi.
Semantic Kernel web plugin: mục tiêu và phạm vi không lặp
Phần đầu chốt bài toán, đầu ra và giới hạn.
Bài toán
Một nhóm dựng trợ lý nội bộ bằng Semantic Kernel. Trợ lý cần đọc vài trang công khai của chính công ty: bảng giá, trang tài liệu, trang trạng thái dịch vụ. Trợ lý không được đọc trang khác, không được đi vào mạng nội bộ, và phải cho người dùng biết thông tin lấy từ URL nào, lúc nào.
Cách nhanh nhất là viết một hàm nhận URL rồi trả văn bản trang. Cách này chạy được ngay, nhưng để mở ba lỗ hổng. Model có thể gọi bất kỳ URL nào. Chuyển hướng có thể dẫn ra ngoài phạm vi. Lỗi trả về dưới dạng câu chữ khiến model không phân biệt được trang trống với trang lỗi.
Đầu ra nghiệm thu
Đầu ra là một plugin giới hạn miền, cùng bảng kết quả gọi plugin trên fixture. Mỗi kết quả có URL yêu cầu, URL cuối, mã trạng thái, thời điểm đọc, tiêu đề, văn bản đã cắt và một trường lỗi có cấu trúc. Bảng gồm cả ca thành công, ca 404, ca quá thời gian, ca chuyển hướng ra ngoài, ca sai loại nội dung và ca miền không được phép.
Plugin không tự có quyền dữ liệu
Một plugin chỉ là đoạn code được model gọi. Việc đăng ký plugin với kernel không cấp cho nó quyền đọc website nào. Quyền đọc đến từ điều khoản của website nguồn, từ robots.txt, và từ việc anh em có được phép thu thập dữ liệu đó hay không. Plugin trong bài chỉ đọc trang của chính mình trên máy chủ lab.
Ai nên đọc
Người viết agent bằng Semantic Kernel cho Python và cần cho agent đọc web một cách có kiểm soát. Người phụ trách bảo mật cần đánh giá một plugin do đội khác viết trước khi đưa vào sản phẩm. Người đã viết plugin đọc web và thấy model trích dẫn nội dung mà không ai biết lấy từ đâu.
Bài giả định người đọc đã biết tạo Kernel và gọi một dịch vụ chat. Phần nói về model chỉ đi tới mức cần để hiểu plugin được gọi ra sao.
Ranh giới với các bài gần
Bài không bàn MCP hay hosted tool của Microsoft Agent Framework, đó là chủ đề khác. Bài cũng không dựng RAG hay vector store. Trọng tâm là native plugin: chữ ký hàm, schema gửi cho model, kiểm tra miền và hình dạng kết quả.
Giới hạn của phép thử
Lab không có khóa API của OpenAI hay Azure OpenAI. Phần gọi plugin trực tiếp qua kernel.invoke chạy thật. Phần model tự gọi plugin chạy với một máy chủ mô phỏng Chat Completions trên 127.0.0.1 cổng 9513. Máy chủ này trả về lời gọi tool dựng sẵn, rồi ghi lại tin nhắn tool mà Semantic Kernel gửi ngược lên. Chất lượng quyết định của model thật không nằm trong phạm vi bài.
Tạo native plugin đọc nguồn web cho Semantic Kernel web plugin với schema hàm rõ
Phần này nói về khái niệm plugin theo tài liệu và cách model nhìn thấy plugin.
Plugin là gì trong Semantic Kernel
Theo trang Plugins trên Microsoft Learn, plugin là nhóm hàm mà Semantic Kernel đưa cho model AI qua cơ chế function calling. Native plugin là lớp Python hoặc C# có các phương thức được đánh dấu là hàm của kernel. Kernel đọc chữ ký phương thức, tạo schema, và gửi schema cho model cùng câu hỏi.
Model chỉ thấy tên, mô tả và schema

Schema model nhìn thấy
Model không đọc code của plugin. Nó chỉ thấy tên hàm, mô tả, tên tham số, kiểu và mô tả từng tham số. Mọi giới hạn viết trong code, như danh sách miền, model không biết trừ khi mô tả nói ra. Vì vậy mô tả nên nêu rõ hàm chỉ đọc miền được phép, và trả JSON có trường error.
Schema mà Semantic Kernel tạo ra
Lab in schema của hàm read_page bằng hàm chuyển đổi metadata sang định dạng function calling của Semantic Kernel 1.46.0. Kết quả có type function, tên web-read_page, mô tả tiếng Việt nguyên văn, và parameters là object với hai thuộc tính. url có kiểu string kèm mô tả, max_chars có kiểu integer kèm mô tả. Trường required chỉ có url, vì max_chars có giá trị mặc định.
Tên hàm có gạch nối
Tên gửi cho model là tên plugin, gạch nối, tên hàm. Plugin đăng ký với tên web nên hàm thành web-read_page. Khi đọc log của model hay transcript, tìm theo tên này, không phải read_page. Tên plugin nên ngắn và không trùng giữa các plugin.
Ít hàm, mỗi hàm một việc
Tài liệu Plugins khuyên đặt tên và mô tả hàm rõ ràng, và không đưa quá nhiều hàm cho model cùng lúc. Mỗi hàm thêm vào là thêm token cho schema trong mọi request, và thêm khả năng model chọn nhầm. Với nhu cầu đọc web, một hàm read_page là đủ. Không cần thêm hàm tải ảnh, tải tệp hay gửi form vào cùng plugin.
Nếu sau này cần tìm kiếm, tách thành plugin riêng với allowlist riêng. Hai việc có rủi ro khác nhau thì nên có giới hạn khác nhau.
Annotated là chỗ viết mô tả tham số
Mô tả tham số lấy từ chuỗi thứ hai trong Annotated. Thiếu Annotated, tham số vẫn có kiểu nhưng không có mô tả, và model phải đoán ý nghĩa từ tên. Với tham số url, mô tả nên nói rõ cần URL đầy đủ có http hoặc https, để model không gửi đường dẫn tương đối.
Định nghĩa native plugin và schema tham số hàm đọc nguồn cho Semantic Kernel web plugin
Phần này là code plugin đã chạy trong lab.
Phiên bản lab
Thành phần |
Phiên bản |
|---|---|
Python |
3.12.10, venv riêng, Windows 10 |
semantic-kernel |
1.46.0 |
httpx |
0.28.1 |
openai |
3.42.1 |
pydantic |
2.13.5 |
Khung lớp plugin
from typing import Annotated
from urllib.parse import urlsplit, urljoin
import datetime, httpx
from semantic_kernel.functions import kernel_function
class WebReaderPlugin:
def __init__(self, allowed_hosts, timeout=3.0, max_bytes=200_000, max_redirects=3):
self.allowed = allowed_hosts; self.timeout = timeout
self.max_bytes = max_bytes; self.max_redirects = max_redirects
def _host_ok(self, url):
u = urlsplit(url)
return u.scheme in ("http", "https") and u.netloc.lower() in self.allowed
@kernel_function(name="read_page",
description="Đọc văn bản của một trang web thuộc miền được phép. "
"Trả JSON gồm url, final_url, status, fetched_at, title, text, error.")
async def read_page(self, url: Annotated[str, "URL đầy đủ, bắt đầu bằng http hoặc https"],
max_chars: Annotated[int, "Số ký tự tối đa của text trả về"] = 2000) -> str:
...
Phần thân hàm được trình bày ở các mục sau. Bản đầy đủ nằm trong thư mục lab, khoảng 60 dòng.
Vì sao hàm là async
Phương thức read_page khai báo async và dùng httpx.AsyncClient. Semantic Kernel cho Python hỗ trợ cả hàm đồng bộ lẫn bất đồng bộ. Với hàm có chờ mạng, async giúp kernel không chặn vòng lặp sự kiện khi model gọi nhiều hàm song song. Lab gọi tuần tự nên không đo khác biệt tốc độ, chỉ ghi lại lựa chọn thiết kế.
Danh sách miền so theo host và cổng
_host_ok so netloc, tức host kèm cổng, với một tập miền cho phép. Lab cho phép đúng 127.0.0.1:9511. Kết quả: localhost:9511 bị từ chối dù cùng máy và cùng cổng, vì chuỗi host khác. 127.0.0.1:9512 bị từ chối vì khác cổng. Nếu website có cả bản có www và không có www, phải liệt kê cả hai.
So sánh chuỗi chính xác như vậy đơn giản và dễ kiểm. Cách so theo hậu tố, ví dụ mọi host kết thúc bằng tên miền chính, linh hoạt hơn nhưng phải cẩn thận với tên miền giả có đuôi giống.
Chỉ nhận http và https
Hàm kiểm scheme trước. URL dạng file:///C:/Windows/win.ini bị từ chối với mã DOMAIN_NOT_ALLOWED và chi tiết là chuỗi rỗng. Thiếu bước này, một thư viện HTTP khác có thể đọc tệp cục bộ hoặc giao thức lạ khi model gửi URL kỳ quặc.
Tắt tự theo chuyển hướng
httpx.AsyncClient được tạo với follow_redirects bằng False. Plugin tự đọc header Location, ghép thành URL đầy đủ, kiểm lại miền, rồi mới đi tiếp. Số lần chuyển hướng tối đa là 3. Đây là phần quan trọng nhất của plugin, phần thử nghiệm sẽ cho thấy lý do.
Giới hạn kích thước và thời gian
Plugin đọc phản hồi theo luồng và dừng khi vượt 200.000 byte, đánh dấu truncated. Thời gian chờ là 3 giây. Văn bản trả về cho model được cắt thêm theo max_chars. Model không cần cả trang, và mỗi ký tự thừa là token phải trả tiền.
Đăng ký Semantic Kernel web plugin với kernel theo SDK đã khóa
Phần này đi qua đăng ký và hai cách gọi.
Một kernel hay nhiều kernel
Kernel là đối tượng nhẹ, tạo nhiều kernel cho nhiều mục đích là chuyện bình thường. Một cách tổ chức gọn: kernel cho trợ lý tra cứu chỉ có plugin web với allowlist trang công khai, kernel cho trợ lý nội bộ có plugin web với allowlist khác. Hai allowlist không trộn lẫn, và mỗi kernel dễ kiểm hơn một kernel chứa mọi thứ.
Cách này cũng giúp thử nghiệm. Bộ test cho trợ lý tra cứu chỉ cần dựng kernel với đúng plugin của nó, không phải giả lập cả hệ thống.
Đăng ký plugin
from semantic_kernel import Kernel
kernel = Kernel()
kernel.add_plugin(WebReaderPlugin({"127.0.0.1:9511"}), plugin_name="web")
add_plugin nhận một đối tượng plugin và tên. Danh sách miền được truyền khi khởi tạo, không phải tham số mà model điều khiển. Đây là điểm cốt lõi: model chọn URL, nhưng code quyết định URL đó có được đọc không.
Gọi trực tiếp qua kernel.invoke
kernel.invoke với plugin_name, function_name và tham số theo tên cho phép gọi plugin mà không cần model. Lab dùng cách này để chạy mười URL thử và đo thời gian. Kết quả trả về có thuộc tính value là giá trị hàm trả về.
Gọi trực tiếp là cách kiểm thử plugin nhanh nhất. Nên có một bộ test gọi plugin qua kernel.invoke trước khi cho model dùng.
Model tự gọi plugin
Khi đặt function_choice_behavior là FunctionChoiceBehavior.Auto trong thiết lập thực thi, Semantic Kernel gửi schema của mọi hàm đã đăng ký cho model. Model trả về lời gọi tool, kernel tự gọi hàm, gửi kết quả ngược lên model dưới dạng tin nhắn role tool, rồi nhận câu trả lời cuối.
Lab dùng OpenAIChatCompletion với một AsyncOpenAI trỏ tới máy chủ mô phỏng. Request đầu tiên mà máy chủ nhận có khóa tools chứa schema của web-read_page.
Chỉ đưa plugin cần thiết cho từng lượt
FunctionChoiceBehavior.Auto mặc định gửi mọi hàm đã đăng ký. Kernel dùng chung cho nhiều tính năng có thể đã có plugin gửi email hay ghi cơ sở dữ liệu. Thiết lập thực thi cho phép lọc hàm theo tên plugin hoặc tên hàm. Với lượt hỏi chỉ cần tra cứu, chỉ đưa plugin web, để model không có lựa chọn gọi nhầm hàm có tác dụng phụ.
Lab chỉ đăng ký một plugin nên không thử bộ lọc này. Khi áp dụng, kiểm bằng cách đọc khóa tools trong request đầu tiên gửi tới model, như máy chủ mô phỏng đã làm.
Tham số sai kiểu do model gửi
Máy chủ mô phỏng gửi lời gọi với max_chars là chuỗi abc. Semantic Kernel ghi log FunctionExecutionException và gửi lên model tin nhắn tool có nội dung báo tham số max_chars không chuyển được sang int. Hàm của plugin không chạy.
Tham số sai tên
Lần khác, lời gọi dùng tên link thay vì url. Tin nhắn tool báo thiếu tham số bắt buộc url, nhận tham số lạ link, và đề nghị sửa tham số cho khớp chữ ký hàm. Cả hai ca đều không làm chương trình dừng. Model nhận được thông báo lỗi và có cơ hội gọi lại.
Trả cấu trúc URL, thời gian và lỗi thay vì text không nguồn trong Semantic Kernel web plugin
Phần này nói về hình dạng kết quả và một bẫy khi trả dict.
Các trường kết quả
Trường |
Ý nghĩa |
|---|---|
url |
URL model yêu cầu |
final_url |
URL thật sự được đọc sau chuyển hướng hợp lệ |
status |
Mã HTTP cuối cùng |
content_type |
Header Content-Type |
fetched_at |
Thời điểm đọc, UTC, định dạng ISO |
title |
Nội dung thẻ title |
text |
Văn bản đã bỏ thẻ, script, style và cắt theo max_chars |
truncated |
Đã cắt nội dung hay chưa |
error |
Null, hoặc object có code và detail |
Mã lỗi có cấu trúc
Plugin dùng bảy mã lỗi: DOMAIN_NOT_ALLOWED, REDIRECT_NOT_ALLOWED, TOO_MANY_REDIRECTS, TIMEOUT, NETWORK, HTTP_STATUS và UNSUPPORTED_TYPE. Mỗi mã kèm detail ngắn như tên miền, URL đích, tên exception hay mã HTTP. Model đọc mã lỗi dễ hơn đọc câu văn, và code phía sau thống kê được theo mã.
Bẫy: trả dict thì model nhận repr của Python

JSON thay vì repr
Bản đầu của plugin trả về dict. Máy chủ mô phỏng ghi lại tin nhắn tool mà Semantic Kernel 1.46.0 gửi lên. Nội dung là chuỗi dạng repr của Python: nháy đơn quanh khóa, None thay cho null, False thay cho false. Chuỗi này không phải JSON hợp lệ.
Model đọc được repr ở mức nào đó, nhưng mô tả hàm hứa trả JSON. Công cụ phía sau phân tích transcript bằng json.loads sẽ lỗi. Lab sửa bằng cách cho hàm trả về chuỗi json.dumps với ensure_ascii False. Lần chạy lại, json.loads đọc tin nhắn tool thành công.
Lỗi phải là dữ liệu, không phải exception
Plugin bắt exception của httpx và chuyển thành trường error. Nếu để exception bay ra, Semantic Kernel vẫn gửi một thông báo lỗi lên model, nhưng là câu văn do framework soạn, không có mã lỗi hay URL đích. Model khó phân biệt trang không tồn tại với mạng chập chờn.
Có mã lỗi riêng, model có thể phản hồi đúng ngữ cảnh. Với DOMAIN_NOT_ALLOWED, nó nói với người dùng rằng trang nằm ngoài phạm vi. Với TIMEOUT, nó có thể đề nghị thử lại sau. Code giám sát phía sau đếm được bao nhiêu lượt bị chặn miền mỗi ngày, một tín hiệu tốt để phát hiện lạm dụng.
Tại sao cần fetched_at
Nội dung web thay đổi. Bảng giá đọc lúc 9 giờ có thể khác lúc 15 giờ. fetched_at cho người dùng và cho người kiểm duyệt biết câu trả lời dựa trên phiên bản nào. Lab ghi theo UTC, ví dụ 2026-11-03T09:31:47+00:00, để không nhầm múi giờ khi so log.
Bỏ script và style trước khi trả
Hàm dùng biểu thức chính quy để bỏ khối script, style và mọi thẻ HTML, rồi gộp khoảng trắng. Trang /ok có một đoạn script gọi hàm x, text trả về không còn đoạn này. Cách làm đơn giản, đủ cho trang tĩnh đơn giản. Với trang phức tạp, nên dùng thư viện trích nội dung chính để bỏ menu, chân trang và quảng cáo.
Đừng gửi HTML thô cho model. HTML tốn token gấp nhiều lần văn bản, và các đoạn script hay thuộc tính ẩn có thể chứa chỉ dẫn lạ mà model coi như lệnh. Văn bản sạch giảm cả chi phí lẫn rủi ro.
Văn bản trích phải có nguồn
Câu trả lời cuối của model nên trích URL từ trường final_url, không phải url. Hai trường giống nhau khi không có chuyển hướng. Khi có chuyển hướng hợp lệ trong cùng miền, final_url mới là trang thật sự được đọc. Chỉ dẫn hệ thống nên yêu cầu model nêu final_url và fetched_at khi trích dẫn.
Kiểm allowlist miền và kết quả gọi Semantic Kernel web plugin trên fixture
Phần này là bảng kết quả chính của lab.
Fixture
Hai máy chủ http.server của Python chạy trên 127.0.0.1 cổng 9511 và 9512. Cổng 9511 là miền được phép, có trang /ok, trang /slow chờ 6 giây, trang /redir-out chuyển hướng 302 sang cổng 9512, trang /pdf trả application/pdf và trang /big khoảng 2 MB. Cổng 9512 có trang /secret đóng vai dữ liệu nội bộ. Mỗi máy chủ ghi mọi request vào tệp log.
Bảng kết quả mười URL
URL thử |
Thời gian |
Mã lỗi |
Ghi chú |
|---|---|---|---|
9511/ok |
0,41 giây |
không |
title Bảng giá, text đã bỏ script |
9511/khong-co |
0,24 giây |
HTTP_STATUS |
detail 404 |
9511/slow |
3,26 giây |
TIMEOUT |
ReadTimeout, ngưỡng 3 giây |
9511/redir-out |
0,25 giây |
REDIRECT_NOT_ALLOWED |
detail là URL cổng 9512 |
9511/pdf |
0,23 giây |
UNSUPPORTED_TYPE |
application/pdf |
9511/big |
0,23 giây |
không |
truncated true |
9512/secret |
0,00 giây |
DOMAIN_NOT_ALLOWED |
không gửi request |
example.com |
0,00 giây |
DOMAIN_NOT_ALLOWED |
không gửi request |
file:///C:/Windows/win.ini |
0,00 giây |
DOMAIN_NOT_ALLOWED |
scheme sai |
localhost:9511/ok |
0,00 giây |
DOMAIN_NOT_ALLOWED |
host khác chuỗi |
Log máy chủ xác nhận
Log của máy chủ cổng 9511 có đúng sáu request, User-Agent là sk-web-plugin-lab/0.1. Log của máy chủ cổng 9512 trống. Plugin chưa từng gửi request nào tới miền không được phép, kể cả khi bị chuyển hướng sang đó.
Đối chứng với hàm đọc web ngây thơ

Redirect bị chặn
Để thấy giá trị của việc tắt tự theo chuyển hướng, lab chạy một hàm ngắn dùng httpx với follow_redirects bằng True, gọi cùng URL /redir-out. Kết quả: mã 200, URL cuối là trang /secret trên cổng 9512, nội dung là đoạn dữ liệu nội bộ. Log cổng 9512 ghi nhận request.
Nếu chỉ kiểm miền ở URL đầu vào rồi bật tự theo chuyển hướng, allowlist bị vô hiệu bởi một header Location. Đây là con đường phổ biến để một tool đọc web bị dùng đọc dữ liệu nội bộ.
Vì sao 9512 phải trống
Cổng 9512 mô phỏng một dịch vụ nội bộ, như trang quản trị hay máy chủ metadata của máy ảo. Trong môi trường đám mây, những địa chỉ như vậy có thể trả về thông tin nhạy cảm cho bất kỳ ai gửi request từ bên trong. Một tool đọc web chạy trên máy chủ, nếu đi theo chuyển hướng bừa, chính là cửa ngõ để đọc chúng.
Vì vậy tiêu chí nghiệm thu không phải plugin trả lỗi đúng mã, mà là máy chủ đích không nhận request nào. Trả lỗi đúng mã sau khi đã gửi request vẫn là rò rỉ.
Ca quá thời gian
Trang /slow chờ 6 giây, plugin dừng ở 3,26 giây với ReadTimeout. Khoảng 0,26 giây chênh là thời gian kết nối và xử lý. Không có ngưỡng này, một trang treo sẽ giữ lượt hỏi của người dùng tới khi client của model hết kiên nhẫn.
Thời gian của ca bị chặn
Bốn ca bị chặn theo miền đều trả về trong 0,00 giây theo đồng hồ của lab. Plugin quyết định trước khi mở kết nối, nên không có độ trễ mạng. Ca chuyển hướng ra ngoài mất 0,25 giây, bằng thời gian gửi một request tới cổng 9511 và nhận về 302. Không có request thứ hai.
Con số này còn cho một gợi ý vận hành: nếu thấy nhiều lỗi DOMAIN_NOT_ALLOWED liên tiếp trong log, đó là model đang thử nhiều URL ngoài phạm vi. Có thể do câu hỏi của người dùng, có thể do nội dung trang đã đọc chứa link dẫn dụ.
Ca nội dung lớn
Trang /big có khoảng 2 triệu byte. Plugin đọc tới hơn 200.000 byte thì dừng và đánh dấu truncated. Text trả về chỉ 60 ký tự theo max_chars của phép thử. Không có giới hạn byte, plugin sẽ đọc cả trang vào bộ nhớ trước khi cắt.
Lỗi do model sinh không làm hỏng plugin
Hai ca tham số sai kiểu và sai tên ở phần trước cho thấy Semantic Kernel kiểm tham số trước khi gọi hàm. Plugin không cần tự kiểm kiểu cơ bản. Nhưng nó vẫn phải tự kiểm giá trị: một chuỗi URL hợp lệ về kiểu vẫn có thể trỏ tới miền cấm.
Đầu ra nghiệm thu: plugin giới hạn miền và kết quả Semantic Kernel web plugin chứa URL thời gian cùng lỗi có cấu trúc
Phần cuối gom bộ bàn giao và vai trò của proxy.
Bộ bàn giao
Bộ bàn giao gồm tệp plugin, danh sách miền cho phép đặt trong cấu hình, bảng mười URL thử với mã lỗi, log hai máy chủ fixture và schema hàm mà model nhìn thấy. Kèm theo là ghi chú rằng hàm trả chuỗi JSON, không trả dict.
Ngưỡng nghiệm thu
Plugin đạt khi mọi URL ngoài allowlist trả DOMAIN_NOT_ALLOWED mà không phát sinh request, chuyển hướng ra ngoài trả REDIRECT_NOT_ALLOWED mà máy chủ đích không ghi nhận request, và tin nhắn tool gửi lên model đọc được bằng json.loads. Ca chậm phải dừng gần ngưỡng thời gian, ca lớn phải có truncated.
Ghi log mỗi lần gọi
Ngoài kết quả trả cho model, plugin nên ghi một dòng log mỗi lần gọi: thời điểm, URL, final_url, status, mã lỗi, số byte đọc. Log này độc lập với transcript của model. Khi người dùng hỏi tại sao trợ lý trả lời sai, đội vận hành tra log để biết plugin đã đọc gì, lúc nào.
Không ghi nội dung trang vào log nếu trang có dữ liệu cá nhân. URL và mã trạng thái là đủ cho phần lớn nhu cầu điều tra.
Kiểm thử tự động
Biến bảng mười URL thành bộ test pytest gọi kernel.invoke. Mỗi lần sửa plugin, chạy lại bộ test với fixture. Thêm một test đọc log máy chủ cổng 9512 và kiểm nó trống. Test này bắt được lỗi nếu ai đó bật lại follow_redirects.
Thay đổi allowlist cần duyệt
Allowlist là cấu hình quan trọng nhất của plugin. Đặt nó trong tệp cấu hình có kiểm soát phiên bản, mỗi lần thêm miền phải có người duyệt. Không cho model hay người dùng cuối thêm miền qua câu hỏi. Một allowlist dài dần theo thời gian mà không ai rà lại sẽ mất tác dụng.
Tôn trọng robots.txt và điều khoản
Plugin trong lab chỉ đọc trang của fixture. Khi dùng với trang thật, kể cả trang của chính công ty, nên có thêm bước đọc robots.txt và tuân theo. Cách đọc quy tắc có trong bài robots.txt khi crawl website. Với trang của bên thứ ba, cần xin phép hoặc dùng API chính thức của họ.
Khi nào cần proxy với Semantic Kernel web plugin
Plugin dùng httpx.AsyncClient. httpx đọc biến môi trường HTTP_PROXY và HTTPS_PROXY theo mặc định, hoặc nhận tham số proxy khi tạo client. Cách viết URL proxy có trong bài định dạng proxy.
Proxy cần khi trang nội bộ chỉ mở cho một IP cố định, hoặc khi cần xem phiên bản trang hiển thị cho người dùng tại Việt Nam. Khi cần IP tĩnh cho trường hợp này, anh em có thể mua proxy tĩnh Việt Nam tại trang chủ ProxyVN. Proxy không thay allowlist, không cấp quyền đọc và không vượt robots.txt. Khi bật proxy, allowlist vẫn kiểm theo host của URL đích, không theo host của proxy. Vai trò hợp lệ của proxy được phân tích trong bài Web Scraping proxy là gì.
Checklist Semantic Kernel web plugin

Checklist plugin
- Khóa phiên bản semantic-kernel và httpx.
- Viết mô tả hàm nói rõ chỉ đọc miền được phép và trả JSON.
- Dùng Annotated để mô tả từng tham số.
- So host và cổng với allowlist, chỉ nhận http và https.
- Tắt follow_redirects, kiểm miền ở mỗi bước chuyển hướng.
- Đặt ngưỡng thời gian, giới hạn byte và max_chars.
- Trả chuỗi JSON, không trả dict.
- Có trường error với code và detail, có fetched_at và final_url.
Câu hỏi thường gặp về Semantic Kernel web plugin
Đăng ký plugin có cho phép đọc mọi website không?
Không. Plugin chỉ là code. Quyền đọc dữ liệu đến từ website nguồn và từ allowlist do anh em đặt.
Tại sao model nhận dữ liệu có nháy đơn và None?
Hàm trả dict thì Semantic Kernel 1.46.0 gửi repr của Python. Trả chuỗi json.dumps để model nhận JSON.
Model gửi tham số sai thì sao?
Semantic Kernel báo lỗi trong tin nhắn tool, hàm không chạy, model có thể gọi lại với tham số đúng.
Có cần tắt follow_redirects không?
Có, nếu muốn allowlist có tác dụng. Lab cho thấy bật tự theo chuyển hướng là đọc được trang ngoài allowlist.
Tên hàm model thấy là gì?
Tên plugin, gạch nối, tên hàm. Ví dụ web-read_page.
Plugin có dùng được proxy không?
Có, qua biến môi trường của httpx hoặc tham số proxy khi tạo AsyncClient.
Semantic Kernel web plugin và những điều cần nhớ
Semantic Kernel web plugin viết nhanh, nhưng an toàn hay không nằm ở vài dòng kiểm tra. Allowlist theo host và cổng, kiểm lại ở mỗi chuyển hướng, giới hạn thời gian và kích thước, trả JSON có URL, thời điểm và mã lỗi. Lab cho thấy một header Location đủ để hàm đọc web ngây thơ đọc trang nội bộ. Cần IP tĩnh cho trang nội bộ mà Semantic Kernel web plugin phải đọc, liên hệ Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam.