7.3 The IoT DC3 Agentic Center in Practice
7.3.1 The IoT DC3 Agentic Center: Current Implementation and Runtime Mapping
What precedes is the logical model of a complete industrial agent runtime. Returning to IoT DC3, we must first distinguish between "capabilities the current source code already provides" and "runtime targets aimed at the future." Writing every target capability as present fact would overstate the system; treating the Agentic Center as nothing more than a chat interface would ignore the controlled execution foundation it has already built.
The more accurate positioning is this: the current Agentic Center is a governed conversational tool runtime with conversations, model adaptation, explicit tools, tenant context, and human-confirmed writes — but it is not yet a general-purpose, long-term task agent runtime.
How Current Capabilities Map to the Four Runtime Planes
The decision plane already has a unified model invocation entry. ChatClientFactory builds and caches the corresponding ChatClient from the Provider and model configuration, so upper-layer conversation and tool code does not bind to a single model vendor. Decision-making today happens mostly within one conversation request; there is no independent long-term task planner or cross-event scheduler yet.
The context plane already persists conversations and messages and carries tenant, user, and conversation information on every tool call. It can support multi-turn conversation replay and identity-constrained capability invocation, but it does not yet amount to a full long-term memory system: there is no unified domain Memory lifecycle, importance filtering, expiry eviction, or cross-task retrieval strategy; retrieval-augmented generation (RAG) also remains an extensible capability rather than a built-in default data path.
The execution plane already forms an explicit tool catalog. The source contains ten Tool classes; the current MethodToolCallbackProvider registers eight categories of capability — Tenant, User, Device, Driver, Profile, Point, PointValue, and System — while CommandTool and EventTool are not yet registered. Tools reuse platform services through Facades instead of copying device protocols and business logic into the model adaptation layer. The Model Context Protocol (MCP) entry on the Gateway side also provides a tool catalog, connection authorization, and a whitelist, so external agents can discover a trimmed set of platform capabilities by protocol.
The governance plane already covers the critical write paths. ToolContext supplies tenant, user, and conversation context; a point-write tool creates a PENDING Action with a limited validity period, and only after user confirmation does ActionService take it into the real command path. The MCP entry has its own OAuth, connection authorization, tool whitelist, and confirmation state, and cannot be simplified, together with the Agentic Center's internal Action, into one and the same interceptor. Existing logs, messages, Actions, and command records give audit a foundation, but a unified run_id, task state machine, step-level tracing, leases, and recovery and compensation semantics are still missing.
Current Maturity Matrix
| Runtime capability | Current status | Precise boundary |
|---|---|---|
| Model adaptation | Available | Supports Provider/Model configuration and ChatClient construction; not an automatic model-routing strategy |
| Conversation context | Available | Supports message persistence and conversation continuity; not long-term domain Memory |
| Tool registration | Available | Eight tool categories explicitly registered today; not every Bean with @Tool is automatically visible |
| MCP capability exposure | Available | Supports tool catalog, connection authorization, and whitelist; MCP does not handle task orchestration |
| Controlled point writes | Available | Waits for confirmation through a PENDING Action; does not control devices directly |
| Audit and observability | Partially available | Conversations, Actions, commands, and logs exist separately; not yet unified into a task trace |
| RAG and domain Memory | Partially available / extensible | The book gives the method, but it is not currently a complete default path of the Agentic Center |
| Workflow and Skill registration | To be built | No general step states, conditions, compensation, or versioned Skill lifecycle yet |
| Long-term task scheduling | To be built | No unified run_id, leases, checkpoint recovery, event triggering, or cross-process scheduling yet |
| Runtime recovery | To be built | Actions solve a specific confirmation problem; not a general retry, idempotency, and compensation engine |
This matrix sets the baseline for reading what follows: the Device, Driver, and PointValue tools discussed in Sections 7.3.2 through 7.3.4 are verifiable implementations that exist today; intelligent alarm orchestration, RAG, long-term autonomous tasks, and multi-agent collaboration are capabilities that still need to evolve on this foundation. When evaluating the system, answer "what runs today" and "what must be added next" separately, instead of summarizing the entire maturity picture with a vague "supports agents."
7.3.2 DeviceTool: Device Search and Control
Devices are the core entity of an IoT platform. Traditional operations interfaces suit precise configuration, but when handling an alarm the operator often knows only a device name, code, driver, or thing model, and must first search for the device before correlating status and point values. DeviceTool exposes these read-only queries as model tools, making natural language a retrieval entry point into existing device data.
Currently Provided Methods
The current DeviceTool reaches platform data through DeviceFacade, PointFacade, PointValueFacade, and optionally StatusHealthFacade; its main methods include:
lookupDeviceById,lookupDevicesByIds: look up one device or a batch by ID;searchDevices: paginated search by device name, code, or Driver ID;listDevicesByDriverId,listDevicesByProfileId: list devices by driver or thing model;getDeviceLatestPointValues: return a snapshot of the device's bound points and their latest values;getDeviceStatusesByIds,getDeviceStatusesByProfileId: query online/offline status.
All of these methods are query capabilities. The current DeviceTool has no device creation, attribute modification, or device control methods, and no annotation logic for "automatic second confirmation of device writes." Real point-write commands are prepared as pending Actions by PointValueTool and must not be mixed into DeviceTool.
The simplified code below preserves the key boundary from the source: take the tenant ID from ToolContext, build a tenant-scoped query, and return a structured result through a Facade.
@Tool(description = "Search for devices with optional filters")
public AgenticToolResult<FacadePage<FacadeDeviceBO>> searchDevices(
String deviceName,
String deviceCode,
Long driverId,
int page,
int size,
ToolContext toolContext) {
Long tenantId = AgenticToolContextUtil.requireTenantId(toolContext);
FacadeDeviceQuery query = new FacadeDeviceQuery();
query.setDeviceName(deviceName);
query.setDeviceCode(deviceCode);
query.setDriverId(driverId);
query.setTenantId(tenantId);
query.setPage(AgenticToolUtil.page(page, size));
return AgenticToolResult.ok("Device page loaded", deviceFacade.listByPage(query));
}A tool method can obtain the tenant from ToolContext because the caller injected it when starting the conversation. The assembly happens on the ChatClient side, illustrated below:
// Illustrative: ToolContext is assembled on the business side; tenant and user come from
// the trusted request context (the principal injected by the gateway), not model-generated fields; parameter key names follow the project's constant definitions
String answer = chatClient.prompt()
.user(question)
.tools(agenticToolCallbackProvider) // registers the eight Tool categories described in Section 7.3.1
.toolContext(Map.of(
"tenantId", requestContext.getTenantId(),
"userId", requestContext.getUserId(),
"conversationId", conversationId))
.call()
.content();The key-value pairs passed to toolContext(...) are forwarded as-is to the ToolContext parameter in the tool method's signature, and methods such as AgenticToolContextUtil.requireTenantId(...) read their values from it; the conversation ID also serves the chat memory of Section 7.2.4 and the attribution of write Actions. The identity comes from the platform's logged-in session, not from model output — this is the premise that lets every Tool in this section trust ToolContext directly.
For a request such as "check the thermostat status in workshop 3," the model can first use searchDevices to find candidate devices, then getDeviceStatusesByIds to query status, and finally getDeviceLatestPointValues to summarize the key points. Every step returns a structured result; the model only chooses the next step and organizes the explanation — it does not read the database directly.
The engineering value of DeviceTool is shortening the query path, not replacing the device management interface. Batch import, complex configuration, and topology editing should still be done in professional interfaces or scripts; model tools are a better fit for ad-hoc retrieval, cross-object correlation, and explanatory result summaries.
7.3.3 DriverTool: Driver Configuration and Management
The Driver is the key entity between protocol access and device management. When troubleshooting an offline device, the operator usually must first confirm which Driver the device belongs to, then judge whether the Driver itself is online and whether its devices are failing broadly. DriverTool gives the model the query capabilities this diagnostic chain needs.
Currently Provided Methods
The current DriverTool's capabilities include:
lookupDriverById,lookupDriversByIds: look up Drivers by ID;lookupDriverByDeviceId: reverse lookup of the Driver a device belongs to;searchDrivers: paginated search for Drivers by name;getDriverStatusesByIds: query Driver online/offline status;getDriverDeviceStatusSummary: count how many devices under a Driver are online and offline.
All of these methods are read-only queries. The current source has no listDriverTypes, configureDriver, or toggleDriver tool methods, and no @WriteOperation(requiresConfirmation = true) annotation. Creating, modifying, starting, or stopping a Driver remains the job of the platform's existing management APIs and interfaces; future capabilities suggested in this book must not be described as current implementation.
A conversation that fits the current capability boundary: the operator says "why is device S3012 offline?" The model first locates the device with DeviceTool.searchDevices, finds the owning Driver with DriverTool.lookupDriverByDeviceId, then calls getDriverStatusesByIds and getDriverDeviceStatusSummary. If the Driver is online but only this device is offline, the evidence points more to the field link or the device itself; if the Driver is offline and its devices are broadly offline, the Driver process, network, and configuration should be checked first.
Diagnostics of this kind do not directly change runtime state, yet they string devices, Drivers, and status data into one explanatory chain. If Driver start/stop is opened up later, it should add a separate high-risk Action type, permission checks, idempotency control, and audit records — not simply a boolean parameter attached to a query method.
7.3.4 PointValueTool: Real-Time Data Read and Write
Point values are the data most often queried — and most in need of cautious writing — in IoT operations. The current PointValueTool provides four categories of capability through PointValueFacade, PointCommandFacade, and ActionService:
getLatestPointValue: query the latest value by Device ID and Point ID;getPointValueHistory: query historical values and return a directly plottable numeric series and statistical summary;readPointValue: submit a read command so the Driver actively reads the specified point from the physical device;writePointValue: prepare a write command without executing it directly.
Latest and historical values are provided uniformly by the Data Center. The current Data Center holds latest values in a local Caffeine cache and writes historical data to PostgreSQL; this must not be written up as MongoDB, TDengine, or another time-series database that is not deployed.
The Real Write-Confirmation Flow
writePointValue uses no fictitious @WriteOperation annotation and is not automatically intercepted and executed inside Spring AI. It first validates that Device ID, Point ID, and the write value are present, then takes tenant, user, and conversation information from ToolContext, calls ActionService.createWritePointValueAction to create a PENDING Action valid for 10 minutes, and returns the actionId to the client.
@Tool(description = "Prepare a point write command")
public AgenticToolResult<PointCommandResult> writePointValue(
Long deviceId,
Long pointId,
String value,
ToolContext toolContext) {
RequestHeader.PrincipalHeader header =
AgenticToolContextUtil.requirePrincipalHeader(toolContext);
String conversationId =
AgenticToolContextUtil.requireConversationId(toolContext);
String actionId = actionService.createWritePointValueAction(
conversationId, deviceId, pointId, value, header);
return AgenticToolResult.ok(
"Write command is pending user confirmation",
new PointCommandResult(deviceId, pointId, value, false, true, actionId));
}The client can query the pending Actions of the current conversation and call the Action interface to confirm or reject. On confirmation, ActionService atomically claims the Action conditioned on tenant, user, status, and expiry time; only a record still PENDING and not expired can proceed. The service then calls PointCommandFacade.submitWrite to submit the write command, and the status is updated to EXECUTED or FAILED. The command then reaches the physical device through Data, RabbitMQ, and the corresponding Driver.
This design splits "the model proposes a write" and "the platform actually executes" into two explicit steps; the basis of confirmation is a persisted Action, not the model saying "confirmed" in natural language. If value-range validation, rate limiting, or multi-level approval must be added, they should continue to be implemented in platform services and the Action flow — they cannot be guaranteed by prompts.
7.3.5 Natural-Language Operations: Conversation Instead of Dashboards
The value of natural-language operations is letting the model combine multiple read-only queries and controlled writes as the task requires, not building another set of business interfaces for the platform. Take "check the thermostat in workshop 3 and write the target temperature to 24" as an example; the steps that fit the current implementation boundary are:
- Call
DeviceTool.searchDevicesto find candidate devices; - Call
DeviceTool.getDeviceStatusesByIdsto rule out offline devices; - Call
PointToolto locate the Point for the target temperature; - Call
PointValueTool.getLatestPointValueto read the current value; - Call
PointValueTool.writePointValueto create a pending Action; - The client displays the Device, Point, target value, and
actionId; after the user confirms, the Action interface executes it.
This flow cannot call Tools that are not registered in the Provider (registration list in Section 7.3.1), and a Driver query tool must not be written up as a Driver configuration tool. The model is responsible for decomposing the task and explaining results; tenant boundaries, parameter validation, confirmation state, idempotency, and audit remain the responsibility of platform code.
Skills and CLI: Knowledge Alignment Only
This book introduces Skills and CLI to help readers understand common concepts in mainstream agent engineering; it is not claiming that IoT DC3 has already implemented these two product capabilities.
- Tools are the atomic capabilities implemented today, provided separately by Spring AI
@Toolmethods and the Gateway's MCP Tools endpoint; the two catalogs come from different sources and must not be treated as one automatically synchronized toolset. - Skills can be understood as a stable orchestration of multiple tools, prompt templates, and input/output contracts — "morning device check" or "offline diagnosis," for example. The current source has no Skill type, registry, or executor.
- CLI is the terminal-client form. A command like
dc3 agent "query offline devices"only illustrates the ideal interaction; the current project has nodc3 agentcommand.
If Skills are implemented in the future, they should add an explicit orchestration layer on top of existing tools and keep reusing tenant, permission, and Action confirmation; if a CLI is implemented, it should be responsible only for argument parsing, authentication, and output display, calling server-side capabilities through the existing HTTP or MCP Tools and avoiding duplicated business logic.
A natural-language entry point suits queries, cross-object correlation, and a small number of controlled operations; batch configuration of hundreds or thousands of devices, millisecond-level monitoring, and protocol debugging should still use professional interfaces, automation scripts, or dedicated control systems.
7.3.6 Intelligent Alarm Analysis and Data Insights
After the rule engine raises an alarm, the operator usually has to open the device details, query the Driver status, page through historical values and repair records, and then judge the cause from experience. Automatically aggregating this information and handing it to the model for analysis is a natural evolution direction for the Agentic Center, but one point must be made clear: the RAG knowledge base, automatic alarm triggering, proactive push, and the anomaly-to-action pipeline are reference designs today, not capabilities already online in the default Compose deployment.
A Four-Stage Reference Pipeline
A workable intelligent alarm analysis scheme can be broken into four stages:
- Alarm intake and context aggregation: receive rule engine events, read devices, Drivers, Profiles, Points, and historical values per tenant, and assemble a structured context;
- RAG retrieval augmentation: retrieve similar cases from version-controlled SOPs (standard operating procedures), device manuals, and historical work orders, preserving source and version;
- LLM (large language model) diagnostic report generation: output facts, inferences, evidence sources, impact scope, and recommended steps, with a clear separation between "observed facts" and "model speculation";
- Result delivery and human decision: read-only diagnoses can be displayed directly; every write is turned into a pending Action, never letting the model control a device directly.
The currently registered DeviceTool, DriverTool, PointTool, and PointValueTool can supply part of the structured context, but the project does not yet have the VectorStore, case-ingestion jobs, or automatic trigger orchestration this pipeline needs. In implementation, RAG should be wired in as an independent capability, not assumed in the text to already exist.
The Realistic Bounds of Data Insights
PointValueTool.getPointValueHistory can already return historical values, numeric summaries, and chart data, so the model can explain trends for queries the user actively initiates — comparing the average, maximum, and direction of change over a recent window, for example. But "automatic inspection every 15 minutes," "predict a limit violation 30 minutes ahead," and "proactively push alarms" still need a scheduler, threshold configuration, replay validation, and notification channels; a single tool call cannot deliver them.
Engineering validation should cover at least three kinds of metric: whether retrieval hits the correct version of the material, whether the model mistakes inference for fact, and whether recommended actions are intercepted by the platform's Action flow. Offline log replay is safer than going live and trying things out: first use historical alarms to evaluate recall, false-positive rate, and actionability of recommendations, then decide whether to open automatic triggering. For device actions that cannot be undone, human confirmation or external approval should be kept even if automatic orchestration is completed in the future.
The correct positioning of intelligent alarm analysis is therefore "current tools as the data entry point, with RAG and orchestration layered on as needed" — not writing the not-yet-implemented vector store, default Command/Event tools, and autonomous execution chain into the present.