Why Business Agents Can’t Rely Solely on LLMs: Implementing Intent Recognition and Task Decomposition
The article explains that a production‑grade business agent must combine LLM‑driven intent understanding with deterministic rule‑based control, using a perception‑understanding‑planning‑execution‑feedback loop, two‑round prompting, strict JSON schemas, permission checks, and a state‑machine architecture to avoid unsafe, uncontrolled behavior.
Agent as a Closed‑Loop System
An industrial‑grade business agent consists of five stages: perception → understanding → planning → execution → feedback. The LLM only participates in the understanding and planning stages; all other stages are deterministic code.
Perception (user input, session context, identity)
↓
Understanding (intent, entity extraction, missing‑parameter detection → LLM)
↓
Planning (task decomposition, step orchestration, tool selection → LLM)
↓
Execution (DB query, API call, file export, email send → Agent code)
↓
Feedback (result aggregation, exception handling, multi‑turn clarification → Agent)Example request: “Help me check yesterday's sales, export Excel, and send to the boss.” The LLM can translate this into the intent sales_query and identify the required tools, but the agent must supply business facts such as which database stores the sales metric, the boss’s email address, and the user’s permission scope.
Hybrid Architecture: Rules + LLM + Agent
Rules & configuration define the boundary – which intents, parameters, tools, and permissions are allowed.
LLM performs semantic mapping: it converts natural language into a fixed set of codes.
Agent parses the structured result, auto‑fills parameters, asks clarification questions, validates the plan, and invokes the tools.
Mixing these responsibilities leads to instability (if the LLM handles everything) or unmaintainable keyword lists (if rules handle everything).
Why Pure Rule‑Based Systems Fail
For a fixed command like query order status, a rule‑based approach works. However, users phrase the same intent in many ways (e.g., “帮我看下昨天华东卖了多少”, “昨天零售那边 GMV 发我一下”). Maintaining an exhaustive synonym list quickly becomes impossible, and multi‑intent combinations cause rule explosion.
Why Pure LLM‑Based Systems Fail
The LLM can understand the phrase “yesterday's sales” but lacks access to:
Current user identity and department
Default business line and region permissions
Database, table, field mappings for the sales metric
Organizational email address for “the boss”
Because these are business facts, a model‑only plan may guess wrong values, which is unacceptable in production.
Two‑Round Call Pattern
Industrial agents split understanding into two rounds:
Coarse intent recognition : with minimal context the LLM decides the high‑level intent, which parameters are missing, and which tools might be needed.
Fine task decomposition : the agent loads the domain‑specific configuration (permissions, tables, tool schemas) and asks the LLM to produce a strict JSON plan.
This avoids the dead‑loop “to assemble context you need intent, to understand intent you need context”.
Constraining LLM Output
The agent defines an enumeration pool and forces the LLM to output only allowed codes. Example enumeration:
{
"params": [
{"code": "biz_line", "name": "业务线", "desc": "用户要查询的业务板块"},
{"code": "sale_area", "name": "销售区域", "desc": "销售数据所属区域"},
{"code": "time_range", "name": "统计时间", "desc": "查询数据的时间范围"},
{"code": "receiver", "name": "接收人", "desc": "报表发送对象"}
]
}Prompt (Chinese example) forces JSON output:
你是业务 Agent 的意图识别模块。
只能从以下枚举中选择,不允许创造新 code:
- intent_code: sales_query, report_export, email_send
- param_code: biz_line, sale_area, time_range, receiver
- tool_code: db_query, excel_export, email_send
输出必须是严格 JSON,schema 为:
{
"intent_code": "",
"tool_codes": [],
"filled_params": {},
"missing_codes": []
}Typical LLM response:
{
"intent_code": "sales_query",
"tool_codes": ["db_query", "excel_export", "email_send"],
"filled_params": {"time_range": "yesterday"},
"missing_codes": ["biz_line", "sale_area", "receiver"]
}Handling Missing Parameters
After receiving the JSON, the agent runs logic similar to:
def handle_missing_params(intent_result, user_context):
missing = intent_result["missing_codes"]
filled = dict(intent_result.get("filled_params", {}))
need_ask = []
for code in missing:
rule = PARAM_RULES[code]
value = try_auto_fill(code, rule, user_context)
if value is not None:
filled[code] = value
continue
if rule["required"]:
need_ask.append(code)
elif "default" in rule:
filled[code] = rule["default"]
if need_ask:
return {"status": "need_user_input", "message": build_question(need_ask), "filled_params": filled}
return {"status": "ready_to_plan", "filled_params": filled}Each parameter code is bound to a fixed clarification template, e.g.:
ASK_TEMPLATES = {
"biz_line": "请选择需要查询的业务线:{options}",
"sale_area": "请选择销售区域:{options}",
"receiver": "请确认报表接收人:{options}"
}State‑Machine View
The agent can be expressed as a deterministic state machine: IntentParsing: map user utterance to fixed codes. LoadContext: load domain configuration based on the intent. ParamCheck: auto‑fill, apply defaults, or ask for required fields. Planning: ask the LLM for a structured task plan. ValidatePlan: enforce whitelist, permission, and schema rules. Execute: invoke the tools.
Configuration Tables
Three JSON tables drive the deterministic logic:
# Parameter definition table
{
"biz_line": {"required": true, "auto_fill": "from_user_profile", "ask_template": "请补充需要查询的业务线。"},
"sale_area": {"required": true, "auto_fill": "from_permission_scope", "ask_template": "请补充需要统计的销售区域。"},
"time_range": {"required": true, "auto_fill": "from_user_text", "default": "yesterday"},
"receiver": {"required": false, "auto_fill": "from_org_relation", "ask_template": "请确认报表接收人。"}
}
# Intent‑to‑domain mapping
{
"sales_query": {"domain": "sales", "required_params": ["time_range", "biz_line", "sale_area"], "available_tools": ["db_query", "excel_export", "email_send"]}
}
# Tool schema
{
"db_query": {"required_args": ["database", "table", "filters", "fields"], "readonly": true},
"excel_export": {"required_args": ["rows", "file_name"]},
"email_send": {"required_args": ["to", "subject", "attachments"]}
}Task Planning Example
After all parameters are filled, the second‑round prompt includes business facts and asks the LLM for a strict JSON plan:
用户原始需求:
查昨天销售额,导出 Excel,发给老板。
已确认参数:
- time_range: yesterday
- biz_line: east_retail
- sale_area: east_china
- receiver: [email protected]
用户权限:
- 仅允许查询 east_china 区域
- 仅允许访问 sales_summary 指标
系统资源:
- database: biz_sales_db
- table: daily_sales_summary
- fields: date, biz_line, sale_area, sales_amount
可用工具:
- db_query(args)
- excel_export(args)
- email_send(args)
要求:只能输出严格 JSON,不能新增数据库、字段、收件人。LLM returns:
{
"steps": [
{"id": "step_1", "tool": "db_query", "args": {"database": "biz_sales_db", "table": "daily_sales_summary", "filters": {"date": "yesterday", "biz_line": "east_retail", "sale_area": "east_china"}, "fields": ["date", "biz_line", "sale_area", "sales_amount"]}},
{"id": "step_2", "tool": "excel_export", "depends_on": ["step_1"], "args": {"rows": "$step_1.rows", "file_name": "yesterday_sales.xlsx"}},
{"id": "step_3", "tool": "email_send", "depends_on": ["step_2"], "args": {"to": "[email protected]", "subject": "昨日销售额报表", "attachments": ["$step_2.file_path"]}}
]
}Before execution the agent validates the plan:
def validate_plan(plan, permission):
for step in plan["steps"]:
if step["tool"] not in permission.allowed_tools:
raise PermissionError("tool not allowed")
if step["tool"] == "db_query":
args = step["args"]
if args["database"] not in permission.allowed_databases:
raise PermissionError("database not allowed")
if args["table"] not in permission.allowed_tables:
raise PermissionError("table not allowed")
if args["filters"].get("sale_area") not in permission.allowed_areas:
raise PermissionError("area not allowed")
return TrueRobust Parsing and Error Handling
LLM output may be malformed. A three‑layer defensive stack is common:
Extract JSON block and deserialize.
Validate schema (intent, param, tool codes belong to allowed sets).
If validation fails, call the LLM to repair the output; if repair also fails, return a controlled error prompting the user to rephrase or choose from a limited intent list.
def robust_parse(raw_text):
try:
data = parse_json(raw_text)
validate_intent_result(data)
return data
except Exception:
fixed = call_llm_repair(raw_text, schema=INTENT_SCHEMA)
data = parse_json(fixed)
validate_intent_result(data)
return dataMulti‑Turn Dialogue Limits
To prevent endless loops, production agents enforce:
Maximum of 2‑3 parameter‑filling rounds.
Only required missing fields block progress; optional fields receive defaults.
Clarification questions present a closed list of options derived from the user’s permission scope.
Minimal Viable Architecture
Starting from a narrow domain (e.g., sales reports) define:
3 intents: sales_query, excel_export, email_send.
5 parameters: time range, business line, region, metric, receiver.
3 tools: read‑only DB query, Excel export, email send.
1 permission model mapping users to allowed business lines and regions.
State‑machine: IntentParsing → ParamCheck → Planning → ValidatePlan → Execute.
The LLM appears only in two places – intent recognition and task planning – while all other layers are deterministic engineering code.
Core Takeaway
Intent recognition and complex task decomposition rely on the LLM, but the agent must control the LLM’s input and output through enumerations, JSON schemas, configuration tables, permission checks, and a state‑machine. The LLM translates human language; the agent decides whether the action is allowed, how to perform it, and where to stop .
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
