Cases/Blue Book
Dongfang Yiteng: An Execution Agent from Zero to Stable Delivery
From the Dongfang Yiteng execution agent (case by Bo Liang)
1. First, draw the line clearly: an execution agent is not a content-generation agent
Dongfang Yiteng is a SaaS company. Its existing product is a service matrix covering enterprise personnel, organization, attendance, approvals, and payroll, reaching down to integrate with banks and tax authorities for one-click payroll calculation, online-banking disbursement, and tax filing. It already serves more than twenty thousand enterprises in a stable way. When large models took off, the team's initial judgment was the same as that of many SaaS companies: if we implement each of our existing API endpoints as an MCP Server under the MCP protocol, can we then build a bot that helps users automatically complete those complex business-process operations?
The moment they tried to land a few core business scenarios that were not even particularly complex, this path stopped working, and the reason it stopped working was precisely MCP's openness and flexibility. In the MCP protocol, the agent acts as a Client: it perceives tools, calls tools, and stuffs the call results back into the context as text. It is not responsible for understanding or preparing parameters; understanding and generating the parameters is handed entirely to the LLM. This design lets the agent hot-plug and register all kinds of Servers, and it has enormous value in general-purpose assistant scenarios aimed at large numbers of individual users. The problem is that what Dongfang Yiteng needed to land was not content generation but execution. What it wanted was to turn a user's colloquial business intent into reliable orchestrated calls across a series of business APIs: automatically build a salary group, automatically build an attendance group, automatically calculate payroll and initiate disbursement, automatically run the entire onboarding process for a new employee. These are all serious process-oriented affairs. They must accurately maintain the state of large numbers of business entities in the system, and that must be done through strict API calls.
The expense-reimbursement example used at the outset states this hurdle most clearly. In an expense-control system, reimbursement usually goes "first create the request, then upload the invoice, then submit for approval, then query the result." A human doing this in a GUI has no trouble at all, because the program long ago nailed down which method each button calls and what parameters it binds. When you upload an invoice against a reimbursement record you just created, the invoice-upload endpoint naturally carries the id of that request. Hand this to an agent to do automatically and those explicit operations disappear; which tool to call and which parameters to prepare are all the agent's responsibility. Between the connected steps there is not only an ordering driven by business logic; the input and output parameters themselves have strict binding and passing relationships. The request id bound when uploading the invoice must be the very id the business system returned in the previous step, not an arbitrary id, and certainly not one the model makes up itself. Under the MCP playbook, all call parameters are generated by the LLM, and the LLM's generation is always unstable and prone to drift. No matter how many JSON Schema constraints you add or how much stronger a model you switch to, there are still times it errs and hallucinates. The team fell into this pit: they appended each step's call result to the context like a tool_call, and let the model parse the binding for the next step's parameters out of the context. In practice this was extremely unreliable, sometimes succeeding and sometimes failing, and when it would fail was neither controllable nor predictable. This is consistent with the essential nature of the LLM as a probabilistic model function: the team wanted certainty, and certainty cannot rest on probability alone. The conflict is at the root.
MCP deserves a fair positioning here. MCP itself is a highly valuable approach. It is not that it cannot do enterprise-grade scenarios; it depends on the scenario. Take an application doing secondary-market equity research: searching for information, generating reports, generating opinions, automatically producing slide decks. It needs to call many external tools, but what each step passes along is mainly textual, content-type results, with no strict mechanical-state parameter binding. First query data in parallel, then summarize, then feed it to report generation, then add a round of review and quality check. This is the same architectural family at the trunk as a travel assistant going "check the map → check the weather → aggregate and generate a travel plan," and MCP was a good approach for it all along. Dongfang Yiteng classifies this kind as a content-generation agent, and classifies what it itself needed to build as an execution agent: automating the delivery of complete business processes inside enterprise business systems. The core complexity of the two is not on the same order of magnitude, and this is the starting point for every trade-off in the architecture that follows.
2. Business goals: first reject the pseudo-needs, then lock down the real pain point
The technical architecture is driven by the business, so before discussing technical details the team first solved a problem harder than the technology: what scenario is actually worth landing, rather than a pseudo-need that only flatters its builders.
In early discussions, quite a few colleagues reflexively proposed generative tasks, especially the "let the agent help the enterprise do analysis and decision-making" kind: workforce-utilization analysis, salary-structure optimization suggestions, attendance and payroll report analysis. These can be done, they produce results easily, and they can quickly yield visually attractive reports. But the team rejected them all. The reason is that they fail to grasp the essence of what brings significant value to the user. Most of the companies Dongfang Yiteng serves are small and medium-sized enterprises, which often do not even do data analysis or make data-driven decisions in their daily operations. Even among the deeply served medium-to-large enterprises with thousands of employees, few really want AI to help with operational analysis. Operational decisions essentially emerge from the operator's intuition within the full context of running daily operations; it is rare to be able to directly analyze something valuable from a single slice of local surface data.
The real pain point lies at the other end, in the trivial transactional operations. With this SaaS, enterprises no longer have to pull together Excel sheets each month to account for payroll, social insurance, and individual income tax by hand. After configuring it once, if the data does not change month to month, payroll is one click and disbursement is one click. Yet users still reported that the operations were too cumbersome and the software too tiring to learn. In-depth interviews found that the problem lay in that "once" configuration. At cold start, you have to configure the enterprise's existing salary structure into the system's salary groups and salary items, build out employees and the organization, and set or adjust pay for each person. To achieve a high degree of automation each month, you also have to build attendance groups, attendance rules, and approval rules, because these are all data elements payroll calculation needs. This whole set often deters new users; some get a headache right after the pre-sales demo and introduction. An interesting difference is that wherever an operations-delivery team was dispatched to help the customer set it up, once users actually used it in the first month the feedback was basically positive. And the more extreme users went further, wishing they could even skip entering a few pages each month to click "one-click payroll" to reconcile, then "one-click disbursement, one-click tax filing." They wanted to authorize the machine to reconcile and do it itself.
This thread eventually converged on a positioning with clear value. The salary-management scenario that many small business owners hope for can be stated in one sentence: "There is this employee. I want to use this human resource at an actual all-in cost of 10,000 yuan a month. The specifics of the salary items, social insurance, and housing fund, I neither want to understand nor see." This is the service positioning worth landing. What the boss needs to focus on is just "10,000 yuan a month used one human resource," while the system side must guarantee clear business data and compliant employment: automatically configure salary items such as base pay, allowances, and bonuses for this human resource, accurately account for social insurance and housing fund, and accurately complete payroll disbursement, social-insurance declaration and payment, and individual-income-tax declaration and payment, so that even a boss without professional HR skills and without a hired HR can employ people compliantly. Encapsulating the complexity the user does not want to attend to, with rigorous and complete internal logic, is the value an execution agent must deliver, not putting a pretty report on display.
After locking the goal there is still one engineering discipline: the broad direction can be "ultimately agents everywhere, the existing GUI interaction disappears entirely," but in actual delivery you must first specify one core target scenario to land first, and use it to drive the whole framework and technical details forward. This first anchor scenario chosen is the rapid salary-group setup that runs through the rest of this piece.
3. A progressive start: let the problems push your thinking, build a polished front end early, and put observability first
The back end was written in Go, without any off-the-shelf agent development framework, for reasons we will not expand on. What is really worth sharing is the start-up methodology: once the big goal is locked, land only one small step at a time, and let the problems that appear and the gap to the goal push your thinking. Putting your attention on complex tool orchestration and strict calls right from the start drags in too much complexity, mental load spikes, and it is easy to grind to a halt. Experienced engineers all know that the hard part of many projects is precisely the start-up phase: too much complexity and too many scenario considerations in your head, afraid of failing to think things through and burying early technical debt, both hesitant and apprehensive about how to take the first step. Once the first step is taken and the project gets a good start, under the guidance of a clear core business goal the subsequent evolution often falls into place naturally.
The first step starts from the simplest place: get the basic data pipeline of user dialogue and agent reply connected, so that a person can hold a continuous conversation with the agent. Attention is not on how skills and tools are defined, registered, or used autonomously; all of that is deferred.
There are two pieces of experience here that come from enterprise deployment and differ greatly from the free improvisation of an individual developer.
The first is that the front end should be built in sync early, and you should spend extra effort making it polished in interaction and styling. It is fair enough that individual developers love the command line, but when landing a project in a team and an enterprise, building a presentation interface that looks good against the real situation as early as possible is crucial for raising development efficiency and reducing internal resistance within the company. A decent front end boosts the team's confidence, and when you hit long-running, hard technical problems it relieves the sense of frustration, because every time you see it you feel it already looks like a product. The more practical side is internal to the enterprise: a month after the project starts, some people lose patience, and colleagues on the business and marketing sides start paying attention. They will not patiently listen to you explain in the command line or in code how impressive the design you have landed is; they will only sense it from a presentable front end. When every stage shows a good-looking, presentable page, external resistance is much smaller, and it can even win you resources. Conversely, you may have put enormous effort into implementing a complex mechanism, only to be seen as a team going nowhere just because one page's styling looks bad. With AI IDEs available now, building a nice front end early is not hard, and this should be done early.
The second is to build out observability from the very start; this is the strongly recommended piece of experience. Observability here has a specific meaning. It does not refer to the agent's observation of the world it is in; it refers to making the agent's awareness and behavior observable to the developer: fully showing the series of actions the agent produces in a conversation, along with the thinking and reasoning that drives those actions, that is, its mental activity and its bodily activity. Concretely, the landing is to lay out the entire execution process of one conversation clearly along a timeline, rather than presenting only the two layers of user input and final reply with the middle process a black box. For each step you need to see both what action the agent produced and, in time order, the LLM-call details of that step: the prompt actually used at runtime, the LLM's output, and the various costs related to that step. On the action side, the practice is to encapsulate and abstract all of the agent's activity and program logic into semantic events, such as user-intent recognition, intent-gateway routing decision, and ReAct execution. These debugging details can be turned off when shipped to production and turned on in the front end during development. This makes the development experience close to assembling or repairing a Swiss mechanical watch inside a transparent glass dome: complex and intricate as it is, you can always directly see where each part is working, and the more complex the system, the more it keeps mental load in check. The deep landing of this piece is in the G5 Observability slice.
With the dialogue pipeline connected and attachments uploadable, the agent's main input is in, and once the full observability infrastructure is laid out you have the foundation to stack capabilities on top step by step.
4. Dualism: first turn the living and uncertain into the dead and controllable
The first capability stacked on top is intent recognition. This belongs to perception, but the perception wanted here goes a step further: having understood the user dialogue, you cannot simply feed back that the dialogue is over; you have to clearly obtain a control signal here, used to select the logical branch that drives the agent downstream. The most core engineering logic is: with user dialogue as input, use a prompt to guide the LLM to return structured output, converging and abstracting the user intent down to one of a few downstream control signals the system can accept.
Early deployment recognized three basic intents. One is chit-chat: a specialized vertical-scenario agent has a limited budget, you must prevent users from treating it as a general assistant, and once an obviously domain-irrelevant chat is recognized you intercept and end it as soon as possible, without launching the costly reasoning and action that follow. The second is consulting business knowledge, for example uploading a salary table and wanting the agent to analyze it; this kind needs no complex reasoning or action planning, just retrieve the supporting domain knowledge and combine it with the input in a single LLM call. The third is understanding the intent and accurately orchestrating a series of tools to complete the target task; this is the core scenario, requiring more complex reasoning and action. These three were defined early as chat, analyze, resolve (later evolving, to fit downstream business logic better, into richer signals such as task, information, produce, chat). Because the LLM is unreliable, a fallback was set here: when no intent is parsed, it is uniformly tagged as unknown, and the downstream has fallback logic for unknown.
Right when the first intent-recognition step landed, the team already saw the embryo of something: within the output of one capability step there exist separated distinct planes. What could be recognized at this point already included a control plane and a narrative plane. The agent perceives the narrative plane in its various reasoning and synthesis steps, while the agent's operating logic is driven by a stable control plane. The idea is the same as distinguishing the data plane and the control plane in Kubernetes.
This dualism is the cognitive foundation of the whole system. For someone new to agentic development, understanding it is a key breakthrough: it frees you from the tangled, complex thinking of "intelligence" and "uncertainty." First turn the living and uncertain into the dead and controllable, because only the dead can be controlled first. The control plane must be mechanized; what is called control is the mechanical. The narrative plane has its own control mechanisms too, but those are a matter of a series of semantic compression, assembly, writing, and read-time injection, not strict mechanical state control; it is "steering." The object of steering has, to some degree, details you cannot fully command, like riding a horse: you rely on equipment plus riding skill to make it act according to your expectations most of the time, but you are not quite sure what is in its head or whether it will suddenly quit on you. Only when these two planes run in parallel do you have a basic agentic system: without clear control signals the system engineering cannot be driven at all, and the narrative context, continuously serving as input to each step's reasoning, in turn produces control signals at different levels.
How to do intent recognition deeply is covered in the R2 Complexity Routing slice.
5. The orchestrator: the home of all capabilities, plus the intent gateway's intercept-and-route
Once you have the control signal from intent recognition, you need to take different execution branches according to different signals, and here a key architectural component naturally surfaces: the orchestrator, the orchestrator of the entire runtime execution flow. It is the core skeleton of agent operation, and all capabilities are mounted and registered on it. Starting from receiving the user dialogue input, it parses and obtains the control-flow signals along the chain, and orchestrates each step's actions according to the signals: this may be calling other capabilities of the agent, distilling memory at some step, retrieving external knowledge, or judging that this conversation is complete and synthesizing the final reply. The agent appearing to understand intent, to have memory, to be able to summarize experience, and to be able to call skills and tools are all, in essence, branches and leaves growing on this strict, precise control-flow trunk behind the scenes. This is something traditional engineering already knows well; the increment the LLM brings is that it can converge and anchor natural-language information onto control signals at all kinds of boundaries, thereby driving seemingly boundlessly free intelligent activity, while in fact every step keeps putting it back in chains. The running process is divergence, convergence, divergence again, convergence again.
In the engineering implementation the orchestrator need not be exposed at the outermost layer. The outermost layer wraps a thin MessageHandler facade that takes the user input and forwards it to the orchestrator, and is dedicated to the capabilities of the user presentation layer. When the orchestrator executes, it freely emits activity events that conform to a unified structural specification, and the MessageHandler listens to these events on a channel and renders the output with SSE, letting the user see a typewriter-effect execution flow and dialogue flow. This "performance logic" is not coupled into the orchestrator, keeping it focused on control. This is exactly where the benefit of choosing Go shows: implementing this kind of event publish-subscribe with native goroutines and channels is very easy. Other mainstream languages can certainly do it too, but you have to write more code.
With the orchestrator in place and intent recognition producing control signals, the next step is to define the consumer of the signals. This maps naturally to an intercept-and-route pattern: the consumer is an intent-gateway component. With it, chat ends directly with an orchestrated, mechanical dialogue (if you like, you need not even call an LLM to synthesize the reply), and analyze, resolve, and unknown each orchestrate a different downstream execution chain. The input to the intent gateway is the control signal, and its output is a definite downstream activity orchestration chain. The large entry boundary is always definite. The main entry receiving the original dialogue and first fixing the intent is the pre stage. The reply synthesized and returned to the user at the end is the post stage. It is the middle stage in between that is the flexibly orchestrable part. Once the orchestrator landed, every capability unit had a home and could be focused on as you stack upward.
6. Reasoning: chain-of-thought reasoning, where each step both contributes to the narrative and produces a control signal
The resolve intent represents the need to concretely understand the user's intent and complete the assigned task. But intent is only a coarse signal; it has no clear description and has not converged to an executable control signal, so the next step is to further understand the intent and map it as quickly as possible to a problem space that can be solved. This calls for landing reasoning and action.
The reasoning step uses chain-of-thought reasoning: guiding the agent to think step by step, observing the previous thinking result before thinking again, until it exceeds a set step count or the LLM judges the reasoning complete. At this step you can clearly appreciate the positioning of the narrative plane: the raw material for reasoning is not just a few control signals, but the full contextual semantics. What is passed down from upstream includes both control signals and the full narrative state. The input to the LLM call for reasoning includes both the user's original input and the conclusions produced in the intent-recognition stage. Generally speaking, the only thing an LLM call ever does is dialogue and reasoning; the complex control flow and operations all have to be implemented by you in the program. So this step takes, on the input side, both the upstream control signal and the narrative content. The team named the assembled narrative input ReasonContext, a complex struct containing content at various semantic levels (initially just two or three fields). The output is still the same old playbook: converge back to structured output, only then can it accurately drive the action further downstream.
There is a key constraint here: the control signal produced by chain-of-thought reasoning must clearly indicate what action can be done as the next step, and must be able to map to callable logic in the program (retrieve the knowledge base, call a certain tool or skill, plan the task further, continue reasoning, or end the dialogue directly). Note that it produces only the "next action," not all actions. Once an action happens the world state changes, and you have to decide the next step again in combination with the goal and the latest context; deciding too early is both unnecessary and impossible to settle. The task and the goal become clearer step by step. How to do chain-of-thought reasoning deeply is in the R1 Chain-of-Thought slice.
7. Action: ReAct, with tool calls encapsulated within the action capability
Once reasoning has reasoned out the "next step," it must hand off to action to take it on. Of course you could code it by taking it on with the corresponding function directly, but that does not fit this scenario's deduction. Reasoning reasoned out only one step, and you still have to do a step and look at a step, so the action capability itself must combine reasoning and action: do a step, look at a step, and if the goal is not reached, do another, continuously approaching the goal. This means tool calls must be encapsulated into the action capability, rather than called bare. This grew naturally out of the engineering evolution, and it is exactly the ReAct action pattern.
In the landing, each round of ReAct has explicit Thought, Action, Observation data structures, and the three-piece set, as one block, is appended to a structure called the scratchpad. Later steps continue reasoning along what was previously completed by reading the block chains of the scratchpad. Each step, according to the control signal produced by reasoning, completes one actual operation in the orchestrator, which may be calling a tool or skill, retrieving the knowledge base, or even making another LLM reasoning call. Once done, it checks how the progress stands against the user's goal, looping on. So skills and tool calls are not called bare at the orchestrator layer but encapsulated in the action capability, because a single call actually has many capabilities and scenarios surrounding it to handle. How to set the control signals is most specific to your own scenario; in theory you could even set a signal like "there is a mole, abort the transaction," and the downstream could directly close the communication stream and not even return a reply. With the orchestrator, this is easy to do. How to do tool calls and the declaration of mechanical-state coordinates deeply is in the A1 Tool Dispatch slice.
8. Plan-and-execute: forced out by ReAct's step-overshoot and step-skip
Once ReAct and the upper-layer orchestrator were in place, an agent that could reason and act was already alive. At this point tool, skill, and knowledge-base call contracts were first connected with mocks: the interfaces were fully designed and fixed at production grade, while data and calls were simulated first, with the real external capabilities connected once the capabilities were complete. The focus was first on whether the agent could correctly recall, at the semantic level, the information, tools, and skills it should find.
In the mock stage, while validating the rapid salary-group setup scenario, the team found the next capability to land. This scenario is: after the user expresses a salary-group request, match the semantically closest salary-group template through a vector database, first take a snapshot of the enterprise's existing salary-group data, confirm the snapshot is established before importing the template, and roll back with the snapshot if the import fails. This string of steps cannot be out of order; it has strict progressive dependencies, the same family as that reimbursement example. The initial idea was very natural: describe all the APIs as tools, describe in the skill how each scenario should be orchestrated, feed "call which step first, then which step" to the agent as narrative context, and expect it to run out the correct order itself within ReAct. It sounds reasonable, but in practice it did not work. After the skill orchestration was given to the model as narrative context, sometimes it ran correctly and sometimes it obviously overshot a step or skipped one, causing the task not to meet expectations. The root cause is still the LLM's uncertainty: handing the execution order to a probabilistic model to judge on the spot cannot guarantee it is correct every time.
So the team recognized that one more action pattern was still missing: plan-and-execute, where the several steps to be completed are first clearly planned and nailed down, rather than doing a step and looking at a step. Its landing complexity is an order of magnitude higher than ReAct's. ReAct's core control structure is essentially a chained loop with an exit boundary; once the concept is understood the data structure is easy to write. Plan-and-execute has to clearly plan and manage the scheduling and dependencies of several consecutive tasks, and must maintain a more complex task-planning and scheduling state. Its core constructs are a task DAG, a planner, an executor, an acceptor, plus a task state machine and a dynamic maintenance mechanism for the task-graph state. The most laborious part is the task state-machine model: each node has its own state, and the precondition for a downstream node to be scheduled and started is that all its upstream dependency nodes are completed and this node is ready; the whole scheduling semantics is driven by this state machine. The book can give the conceptual abstraction and reduce a lot of mental load, but it cannot give this kind of low-level engineering detail; this piece took the team considerable extra design effort to get right. Control flows between the orchestrator and the specific action patterns: as ReAct runs along and finds the picture has become clear, it can be planned into several parallel or serial tasks, so it hands control back to the orchestrator and switches to plan-and-execute. The two patterns need not be either-or; just switch according to how clear the task is. How to do this piece deeply is in the A2 Plan-and-Execute slice.
9. Governance: HITL blocking on critical tasks and human-reviewed continuation, falling into place via the state machine
After implementing that complex task state mechanism, there is an unavoidable enterprise-grade scenario that connects right on: human-in-the-loop (HITL) control over sensitive or dangerous operations. The execution flow reaching a certain critical position must block and wait for human approval, and after approval is granted it can fully restore the execution state of the context that was just interrupted, with the agent finally completing the execution.
This generalized scenario is common, but its complexity differs across businesses, and it can be subdivided into two forms. One is human-reviewed continuation that involves only the narrative state, like an AI coding IDE where the agent has formed a plan but worries about breaking the existing logic: this round of dialogue ends and asks whether you confirm; you input "continue" or "confirm" in the next round, and it continues to completion based on the full narrative context of the session. This kind is essentially still generating content based on the narrative context (writing code is just maintaining the content of a text file), and it is easy to implement in engineering; you just end this round and let the user continue initiating narrative natural-language dialogue in the next round. The other is more complex: at this moment the agent is to run a script or command in a local terminal; it does not end this round of dialogue but blocks the current execution flow and pops up a board asking whether you Accept, and once Accept is clicked the execution flow resumes from where it was blocked. This kind has to first build a task state model and land a task state machine, and must also maintain the global state of the task graph and the state of downstream nodes after one task blocks when a single planning run produces multiple tasks. With only ReAct, implementing this mechanism would require thinking through a whole set specially. But after landing plan-and-execute you already naturally have a task DAG, a state machine, a scheduler, and an executor, so further implementing blocking and human-reviewed continuation at critical tasks or critical tool calls is easy and falls into place; you can even use declarative configuration to maintain which critical tasks or tool calls need to block for human review. How to do this piece deeply is in the G1 Approval Gate slice.
10. The mechanical state plane: the most core complexity of this whole system
When the real APIs were connected and real skills and knowledge bases were configured to deliver the salary-group setup scenario, it would not run through. The problem is that up to this step, although the agent could plan out several dependent tasks, in the state consistency and passing between tasks it was still in an MCP-like form: after the first task succeeds, assemble the result into the dialogue context, let the second task obtain and bind parameters from the latest context, and advance in turn. A travel-assistant-type agent can play this way, because the parameters it passes are textual-leaning. Having the model generate a city parameter from a long stretch of context chatting about Shanghai is hard to get wrong. The weather data structure is slightly more complex, but drifting from "moderate rain" to "rainy" is not much of a problem either, because it participates as downstream narrative input in a generative task, and the semantic deviation is not fatal.
Dongfang Yiteng's scenario is different. The first step of salary-group setup, based on session information such as user id and enterprise id plus the business goal the user entered, calls the template-matching endpoint; matching a suitable template returns a template_id, and when the downstream imports the template it must accurately use this template_id as the input parameter. The difference lies precisely in this id: the various ids in an enterprise are commonly 64-bit or even 128-bit random strings generated by snowflake algorithms. Getting the model to accurately reproduce such an id verbatim after perceiving the dialogue content is extremely challenging, hundreds of times harder than that classic "how many r's are in strawberry" question; it amounts to asking it exactly what each digit of this id is, with not a single digit allowed to be wrong. Purely calling a large model to reproduce a 64-bit random id verbatim still cannot be done smoothly to this day, and this is determined by the LLM's essence: it is a stateless probabilistic model function, every call is a fresh generation, and even if you tell it the id value in the context, it will not "take and use" your parameter; it will only "attempt to generate" your parameter. A token like "Shanghai" has an enormous weight across models, while that kind of random string is likely something the model has seen for the first time in its life, so the probability of error in having it generated is very high. In this scenario, an id missing one digit fails validation and causes execution failure, and an id wrong by one digit is more serious: the agent may "succeed" in execution while actually corrupting business data and not completing the expected state change and scenario delivery.
How to solve this is not covered in the design-pattern book, nor can a ready-made solution be found in the available off-the-shelf material; the material is almost all the MCP playbook of having the LLM generate parameters by JSON Schema. So this was the most core complexity Dongfang Yiteng once faced during deployment, a problem specific to its own scenario that predecessors had not publicly solved.
After a period of thinking, design, and trial and error, the eventual solution is to strictly identify and separate out the mechanical state plane of the agent's entire running process, completely separating the state reads, writes, binding, and passing in business API calls from the content the LLM participates in, and not letting the LLM generate it either, but mechanically and accurately maintaining it at each execution step of the agent according to the tool-call receipts. These parameters and state values are no longer mixed into the narrative context for the model to perceive and then generate and bind; instead, within the global state a dedicated plane responsible for reading, writing, taking, and using state values is clearly carved out, named the mechanical state plane, because these values are strict, stable, and consistent.
For this solution to hold, the precondition is that this system is an enterprise-grade closed system: it neither needs nor wants users to plug in external tools arbitrarily, and all tools are managed and registered by the team itself. This means that at agent startup it can determine the dictionary of all possible state keys in the world it perceives: there are system-level ones (the identity and permission information in the user's login session), there are API-endpoint-level ones, and beyond these there are almost no other state keys to write or read. So as long as you define and standardize the description protocol for registering skills and tools, you register all possible keys on the mechanical state plane at every tool- and skill-registration step. System-level state (such as user session information) is written at the corresponding critical events, for example when the user logs in.
More critical are the coordinates. Each tool declares its own mechanical-state parameter dependency coordinates: which parameter it needs, what the key is, and which tool should produce it at which runtime level. Each tool is both a producer and a consumer of the mechanical state plane. The mechanical state plane is only responsible for the uniqueness of the key coordinate jointly determined by key name and scope, and for maintaining the key's latest state. Which coordinate's parameter each tool needs to take is declared and validated by the tool itself. You can picture the agent, at startup, maintaining a whole wall of little cells, each cell corresponding to a mechanical-state parameter, each key uniquely described by "the parameter's supplier + the runtime step that produced it," each cell just maintaining the latest value along the session timeline, and a consumer that wants a certain state simply going to read the corresponding cell. At runtime each parameter corresponds to a Provenance struct, a unique coordinate parsed and assembled from the various specifications and descriptions, and it is the core of how this mechanism can work reliably and stably. The supporting execution chain is: the Skill declares the SOP, the Workspace guarantees ordering, the Tool declares the production and consumption of state, the SessionState stores the value plus Provenance, and the RunPipeline does the unified parsing.
This way the scenario obtained an extremely stable and robust solution: everything is handed to strict context data structures and the program, and parameters are no longer generated by an LLM that drifts. And all the existing SaaS APIs need no modification whatsoever; as long as they are exposed through the gateway they can be perceived and used by the agent, flexibly orchestrating and combining any number of coherently called APIs according to different scenarios, completing the full delivery of complex business scenarios, with no errors in parameter writing, reading, or binding. The engineering slice of this piece corresponds to A1 Tool Dispatch.
11. The unified session state plane: separation of three powers
As the narrative plane and the mechanical state plane were clearly identified and concretely landed, the team gained a clearer division of the entire runtime context system, eventually stabilizing into the trunk design: a three-way unified session state plane. Besides the previously defined narrative state plane and mechanical state plane, the third plane had in fact long been implemented; it just had not been separately defined as a kind of context state before. That is the context in the plan-and-execute pattern responsible for task state and scheduling. When this context was first built, the narrative state was mixed into it, and each node's task result detail was also read, written, and passed within it. Now a clear separation has been made: the byproducts produced during task execution go into the narrative plane and the mechanical state plane respectively, while the task-scheduling state manages only the scheduling-orchestration semantics.
The separation of three powers each governs its own segment, with clear boundaries.
The narrative state plane (SessionNarrative) uses natural language to continuously gather and organize what has happened, answering "what does the user want, and how far have we gotten." Some information is saved in full, some is saved after compression and distillation, some is only in memory, some is persisted to the DB or even has an embedding vector index built and stored in a vector store. Its persistent source of truth is the anchor table and the ledger table; the writers are the AnchorRepository and appendLedgerEvent, and the readers are the LLM prefix and final reply projected by Distill. It is not responsible for scheduling state, mechanical state, or parameter-validation contracts; it is responsible only for the agent's perception and understanding of the world and the current situation. The core three-piece set of this plane is in the next section, and the deep slices are M3 Progress Tracking and P1 Context Triage.
The mechanical state plane (SessionState) governs the mechanical-parameter dictionary of the entire agent, answering "where do the API parameters come from, and are they correct." What it stores is the Cell model: scope, key, value, producer, provenance. Its data character is strict key-value and contract, its persistent source of truth is Cells materialized from Timeline events, and at each step it listens to mechanical-state parameter events and updates through the SessionState Manager. The readers are the RunPipeline, governance, and precondition validation. It is not responsible for the scheduling graph, the narrative, or memory.
The task-scheduling state plane (Workspace) cares only about the order and state of nodes in the task DAG, answering "which step runs first, and is it done." The scheduling semantics is that a downstream task can be scheduled and started concurrently only on the precondition that all upstream nodes are completed and this node is ready.
Separating these three things—"what the user wants and how far we have gotten" in natural language, "where the API parameters come from and whether they are correct" machine-readable, "which step runs first and whether it is done" as a scheduling graph—is the fundamental reason this system can deliver stably. The hard part of an enterprise-grade execution agent was never whether it can call APIs, but, on the premise that the interfaces cannot be modified, making the parameters of every API step have a unique, auditable, fail-fast mechanical source. The unified session state plane is the engineering answer to that source.
12. The core three-piece set of the narrative plane: anchor, ledger, collection
The narrative plane appeared as early as the intent-recognition stage. For someone who has not deeply worked on agent deployment it is fairly abstract; its core semantic content can be summed up as a kind of "description of goal and progress," like a work notebook: the agent records what it has done as it executes, while reminding itself not to forget its original aim and to keep the goal in mind. It is made up of three core elements.
The anchor (anchor) anchors each session's and conversation's original user input as the immutable top-level goal. Why this anchor? Because this is an agent for delivering complex business scenarios; the execution chain is very long, and from receiving the original request at the entry it passes all the way through reasoning, action, and task planning, with information continuously processed, expanded, or compressed and distilled as it is passed down. If the narrative content were purely a chained one-way passing of the previous step's output as the next step's input, then over a long path it would gradually deviate from the original goal. By the task-planning stage, the input used to generate the plan may have become the train of thought from the reasoning process, while the user goal makes up only a small share. There is also a common situation: first complete one round of dialogue and ask the user whether to continue, and in the next round the user sends only the two characters "continue." When the agent starts reasoning it is very likely to deviate from the essential goal, either unable to understand what "continue" is or just blindly acting on its own understanding of "continue." So in every reasoning context the user's original goal must be passed down as fixed data.
The ledger (ledger) is a key progress summary of a continuous, appended summary record: it semantically compresses and summarizes the completed key-milestone reasoning or action before storing it. Later steps, while knowing the user goal, must also know what was done before and what results were achieved, so as to reason about what this step should complete.
The collection (collection) is the temporary in-memory information formed at some critical reasoning steps by distilling and projecting the ledger once more. Even though the ledger is already distilled information, over a long chain it still piles up a fairly long context, and it is impossible to stuff the full amount into the prompt. So at critical reasoning steps, according to the scenario to be injected at that moment, a set of temporary information is projected and trimmed from the ledger and injected together with the anchor. This way the agent both grasps the previously important milestones and does not take up too much context, just like taking over work: the previous steps were each completed by other colleagues, and what you need to understand is which key milestones they completed, and you only care about those most relevant to the task at hand. This action of "doing distillation projection at the critical-reasoning entry and injecting the trimmed collection" has its deep slice in P1 Context Triage, and the progress semantics of the anchor-ledger-collection three-piece set is in M3 Progress Tracking.
13. The memory system: L1/L2/L3 layering and recall of experience and lessons
To make the agent work better in enterprise-grade scenarios, you still need various supporting systems, and the memory system is an indispensable piece. The team divides memory into three layers: L1, L2, L3. Worth mentioning here is L3: what it saves is experience-and-lesson-type semantic information, produced by distilling and summarizing the narrative context state at the time when a task succeeds or fails. This information helps reasoning. If it was previously discovered which skill can solve a certain scenario, this reasoning can converge quickly, a kind of déjà-vu check of a same-kind task. Conversely, if some intermediate-step interface call failed before, this task's planning can first call the health-check endpoint to confirm the API has recovered before orchestrating execution, sparing the wasted execution of the prior tasks of some heavyweight scenarios.
The landing experience is not to recall memory at every reasoning step; that is too costly. The practice is to do L3 recall at the critical reasoning entries of the flow: the first reasoning of chain-of-thought, the first reasoning of ReAct, and when executing task planning. These large capability-boundary entries most need comprehensive reference information, and if the first step goes right under more comprehensive information it is easy for one right step to lead to step-by-step rightness. In addition, L2 memory is persisted in the DB, and L3 memory is in a vector store with an embedding semantic index; the L3 data structure can save the id pointing to the L2 original memory fact, recalling the detail when the specific source information of that L3 experience fragment at the time is needed. This is consistent with the idea, in the design patterns, of offloading and loading memory pages similar to operating-system memory; it is a concrete implementation of that pattern. How to do L3 experience-and-lesson and critical-boundary recall deeply is in the M1 Layered Retention slice.
14. The full architecture picture and a migration guide
Looking at this thread from the start, the whole system grew this way. First draw the line clearly between execution and content generation, reject the pseudo-needs, and lock the real pain point. Then start from a ChatLoop, build a polished front end early, and put observability first. At intent recognition, discover the dualism of the control plane and the narrative plane, stand up the orchestrator as the home of all capabilities, and pair it with the intent gateway's intercept-and-route. Stack chain-of-thought reasoning on top (each step contributing to the narrative and producing a control signal) and ReAct (tools encapsulated within the action capability). ReAct's step-overshoot and step-skip force out plan-and-execute (task DAG plus state machine), and by way of this state machine, HITL blocking on critical tasks and human-reviewed continuation connect on, falling into place. Finally, facing the most core mechanical-state parameter-binding problem, stand up the mechanical state plane (Provenance coordinates + producer-consumer + tools declaring dependency coordinates at registration, with original APIs needing no modification, fail-fast), converge the entire runtime context into the separation of three powers of the unified session state plane, and pair it with the narrative plane's anchor-ledger-collection and the L1/L2/L3 memory system. This whole thing can be counted as a concrete implementation of agent design patterns: perception, reasoning, action, memory, reflection, collaboration, governance—these capabilities have conceptual abstractions in the book, and what the team did was land the abstractions into real data structures and code, then fill in the low-level engineering details the book cannot cover exhaustively (the task state machine, the mechanical state plane, and the like).
Under what conditions can another SaaS migrate this architecture. The hardest criterion is whether your scenario is execution-type: the task steps are clear, there are strict dependencies and state-parameter passing between steps, and a step-overshoot, step-skip, or one-digit parameter error directly causes delivery failure or corrupts business data. If these hold, the whole set—the control-plane/narrative-plane dualism, the orchestrator, plan-and-execute, and especially the mechanical state plane—is worth adopting wholesale. For the mechanical state plane to hold, add one more precondition: your system is an enterprise-grade closed system, with tools managed and registered by yourself and users not allowed to plug in external tools arbitrarily, so that at startup all possible state keys can be determined as a dictionary and the parameter coordinates nailed down.
Conversely, if your scenario is content-generation-type—querying data, summarizing, generating reports, that kind—with loose steps, high fault tolerance, and textual content rather than strict mechanical parameters passed between steps, then MCP was a good approach all along, and there is no need to introduce the heavy machinery of task graphs, state machines, and the mechanical state plane; forcing it on is over-engineering. The core complexity of the two is not on the same order of magnitude. Before migrating, first classify your own scenario into the correct one of the two; that is the first step to using this architecture well.
This is an ADPS blue book (enterprise practice). Back to Cases or the pattern matrix.