AI Agents / Agent task design
AI Agents: Smallest useful toolset
Enforce a read-only agent toolset in the executor and prove that asking for a write cannot grant that permission.
Start hands-on practice · เริ่มภาคปฏิบัติ ↓Practical guide · คู่มือลงมือทำ
Download worksheet · ดาวน์โหลดขั้นตอนDetailed practical guide
Prepare your workspace and inputs
Save the complete program below as toolset_lab.py and run python3 toolset_lab.py. Use the synthetic ticket only; the example has no send-email or delete operation.
Platform context: Python 3.10+; local script and standard library. No API key or live data.
Scenario to reproduce or investigate
A summarization agent receives an instruction to send or delete a ticket even though its task only requires reading it. The backend must deny the operation before looking up or executing a function.
- Actual target and platform release
- Exact inputs or substituted values
- Baseline result
- Per-step expected and observed output
- Failure encountered and corrective action
- Final acceptance and recovery state
-
Define the required capability independently of the model
List the supported operation and its required arguments. The application task requires only ticket.read for ticket T1. Keep the allowlist in application configuration, and pass the current authenticated principal to the executor from your session layer.
Command, configuration or input
Allowed operation: ticket.read Allowed ticket: T1 Denied operations for this task: ticket.delete, email.sendExpected result · ผลที่ควรเห็นYou can explain why each granted operation is necessary to produce the summary.
If it fails · เมื่อไม่ผ่านIf the task requires no write, remove write methods from the task capability set instead of relying on prompt text.
-
Implement and test the executor boundary
The following is a complete local executor with a permitted read and negative tests. It checks the capability and resource before dispatch. The submitted operation name is treated as data, not imported or evaluated as code.
Save and run this example
TICKETS = {"T1": {"issue": "Printer unavailable", "owner": None}} CAPABILITIES = {"summarizer": {"ticket.read"}} RESOURCES = {"summarizer": {"T1"}} def execute(principal, operation, arguments): if not isinstance(principal, str) or not isinstance(operation, str): raise PermissionError("invalid principal or operation") if operation not in CAPABILITIES.get(principal, set()): raise PermissionError("operation denied") if not isinstance(arguments, dict) or set(arguments) != {"ticket_id"}: raise ValueError("unexpected argument") ticket_id = arguments["ticket_id"] if not isinstance(ticket_id, str): raise ValueError("ticket ID must be text") if ticket_id not in RESOURCES.get(principal, set()): raise PermissionError("resource denied") if operation == "ticket.read": return dict(TICKETS[ticket_id]) raise PermissionError("no handler") assert execute("summarizer", "ticket.read", {"ticket_id": "T1"})["owner"] is None for principal, operation, arguments in [ ("summarizer", "ticket.delete", {"ticket_id": "T1"}), ("summarizer", "email.send", {"ticket_id": "T1"}), ("summarizer", "ticket.read", {"ticket_id": "T2"}), ("unknown", "ticket.read", {"ticket_id": "T1"}), ]: try: execute(principal, operation, arguments) except PermissionError: continue raise AssertionError("forbidden call executed") assert set(TICKETS) == {"T1"} print("PASS: permitted read works; writes and cross-resource reads denied")Expected result · ผลที่ควรเห็นThe program prints PASS: permitted read works; writes and cross-resource reads denied. T1 is still present.
If it fails · เมื่อไม่ผ่านIf a forbidden operation runs, inspect authorization order. Permission must be checked before dispatch, and principal must come from the authenticated application context.
-
Integrate the policy without sharing a privileged client
Expose only the read schema to the model and route every call through execute. Use a production service identity with corresponding read permission; do not place an administrator client in model-accessible state. Log principal, operation, resource ID and denied reason without logging ticket contents or credentials. Add the four denied requests above to the integration test suite.
Command, configuration or input
Model tool schema → executor authorization → scoped backend read → sanitized resultExpected result · ผลที่ควรเห็นChanging a model request or tool description cannot expand the effective backend identity or resource allowlist.
If it fails · เมื่อไม่ผ่านIf a tool handler bypasses execute, move it behind the same authorization boundary and test direct handler access as well as normal model calls.
Check the result before marking this passed
An allowed ticket read succeeds, four denied cases fail before dispatch, and the ticket remains unchanged. Repeat these checks with the real backend test identity before rollout.
Record the observed result and evidence location in the downloaded worksheet. Mark unresolved or untested conditions explicitly.
Recovery and cleanup
Discard the in-memory fixture. Revert the integration configuration if the read path regresses; do not restore broad administrator access as a workaround.
Apply to actual work and known limits
Use the same boundary for your actual tool registry and backend identity. The local test proves this executor implementation; it does not verify a vendor IAM policy until tested against that backend.
Observed local fixture output · ผลรันตัวอย่าง
Implement and test the executor boundary
PASS: permitted read works; writes and cross-resource reads denied
Background, explanations and original notes
When to use it
Use this technique when converting an open-ended request into executable work. Keep the original objective and observable deliverables available to both the planner and the component that decides whether the run is complete.
What to do
Expose only the tools needed for the current task phase and document their boundaries.
Check the result
Present an unrelated request and verify that no irrelevant tool becomes available.
Save and compare results
Save the test input, configuration and result. Fix the failing boundary, repeat the same test and compare it with the saved working configuration.
Scope and limits
Agent orchestration with application-enforced task boundaries; framework-independent. These exercises have not been tested on your systems. Check feature support and configuration names against the installed release and linked documentation.