一、一个完整执行链路的解剖

当用户在对话框里输入“帮我把上个月的销售数据从CRM导出来,和财务系统的回款记录做比对,标出差异发给销售总监”时,AI智能体内部发生了什么?

从工程视角看,这条指令会经过五个环节:

自然语言指令
    │
    ▼
① 意图识别 ─── 用户想做什么?
    │  (意图:跨系统数据比对 + 报表生成 + 消息推送)
    ▼
② 任务拆解 ─── 需要哪些步骤?
    │  (Step1: 查CRM → Step2: 查财务 → Step3: 比对 → Step4: 推送)
    ▼
③ 工具选择 ─── 每步该调什么?
    │  (CRM连接器 / 财务系统连接器 / 数据比对模块 / 邮件服务)
    ▼
④ 系统调用 ─── 真正去执行
    │  (API调用 / 屏幕语义理解操作 / SQL查询)
    ▼
⑤ 结果验证 ─── 做对了吗?
       (数据格式检查 / 异常处理 / 结果确认)

大多数“套壳聊天机器人”只做了第①步。真正的AI智能体,五个环节缺一不可。下面逐一拆解工程实现。

二、意图识别:从“听懂”到“听懂业务”

2.1 通用意图识别

意图识别的第一步,是判断用户想要什么类型的操作。常见的企业场景意图包括:数据查询、报表生成、消息推送、流程审批、系统操作等。

from typing import List, Dict
from dataclasses import dataclass

@dataclass
class Intent:
    intent_type: str        # "query" | "generate_report" | "send_message" | "approve" | "operate_system"
    entities: Dict[str, str]  # 提取的实体:时间、组织、对象、目标等
    confidence: float       # 置信度

class IntentRecognizer:
    """意图识别器:从自然语言中提取结构化的操作意图"""
    
    def __init__(self, llm_client, business_terms: dict):
        self.llm = llm_client
        self.business_terms = business_terms  # 业务术语字典
    
    def recognize(self, user_input: str) -> Intent:
        # 构建Prompt,注入业务术语和可用的意图类型
        prompt = f"""
        你是一个企业AI助手的意图识别模块。
        
        可用的意图类型:
        - query: 查询数据(如"查一下上个月的销售额")
        - generate_report: 生成报表(如"生成销售月报")
        - send_message: 发送消息(如"通知销售团队开会")
        - operate_system: 操作系统(如"在ERP中录入发票")
        - multi_step: 多步骤复合任务(如"比对数据并发送报告")
        
        业务术语映射:
        {self.business_terms}
        
        用户输入:{user_input}
        
        请输出JSON格式:
        {{"intent_type": "...", "entities": {{...}}, "confidence": 0.0-1.0}}
        """
        
        response = self.llm.generate(prompt)
        return self._parse_response(response)

2.2 业务语义消歧

通用意图识别只能判断“用户想做什么类型的事”,但企业场景的真正难点在于业务语义的精确解析。

“上个月华东区的回款率”——这个短语中:

  • “上个月”是一个相对时间,需要换算为具体的日期范围
  • “华东区”是一个业务区域概念,在数据库中可能对应 province IN ('上海','江苏','浙江','安徽')
  • “回款率”是一个计算指标,公式是 回款金额 / 合同金额

这些映射关系,必须由业务术语字典来支撑。在沈管家AI数字员工的实践中,业务术语字典是“自然语言转SQL”引擎的核心组件之一,允许企业自定义业务词汇到数据库字段和计算逻辑的映射。

三、任务拆解:从“一个目标”到“一张DAG”

意图识别之后,智能体需要把用户的单一目标拆解为多个可执行的子任务。

3.1 任务拆解策略

拆解的关键是粒度的把握。拆得太粗,每个子任务太复杂,容易失败;拆得太细,子任务数量过多,调度开销大。

一个实用的原则是:每个子任务对应一次原子化的系统操作——一次数据查询、一次文件生成、一次消息发送。

3.2 DAG表示与依赖管理

拆解后的子任务之间存在依赖关系。例如,“比对数据”依赖“查询CRM”和“查询财务系统”两个步骤先完成。这种依赖关系适合用**有向无环图(DAG)**来表示:

from typing import List, Optional
from dataclasses import dataclass, field
import asyncio

@dataclass
class SubTask:
    task_id: str
    action: str                 # 要执行的操作类型
    connector: str              # 使用哪个连接器
    params: dict                # 操作参数
    depends_on: List[str] = field(default_factory=list)  # 依赖的任务ID
    status: str = "pending"     # pending | ready | running | success | failed
    result: Optional[dict] = None

class TaskDecomposer:
    """任务拆解器:将意图转化为DAG子任务"""
    
    def decompose(self, intent: Intent) -> List[SubTask]:
        # 根据意图类型和实体,生成子任务序列
        if intent.intent_type == "multi_step":
            return self._decompose_multi_step(intent)
        elif intent.intent_type == "query":
            return [SubTask(
                task_id="query_1",
                action="query_data",
                connector=self._select_connector(intent.entities),
                params={"query": intent.entities.get("target")}
            )]
        # ... 其他意图类型
        return []
    
    def _decompose_multi_step(self, intent: Intent) -> List[SubTask]:
        """拆解跨系统比对任务"""
        entities = intent.entities
        return [
            SubTask(
                task_id="fetch_crm",
                action="query_orders",
                connector="crm_connector",
                params={"date_range": entities.get("time_range")}
            ),
            SubTask(
                task_id="fetch_finance",
                action="query_payments",
                connector="finance_connector",
                params={"date_range": entities.get("time_range")}
            ),
            SubTask(
                task_id="compare_data",
                action="join_and_diff",
                connector="data_processor",
                params={"left": "fetch_crm", "right": "fetch_finance"},
                depends_on=["fetch_crm", "fetch_finance"]
            ),
            SubTask(
                task_id="send_report",
                action="send_email",
                connector="email_service",
                params={"to": entities.get("recipient")},
                depends_on=["compare_data"]
            )
        ]

四、工具选择:连接器矩阵的设计

拆解好子任务后,智能体需要为每个子任务选择合适的“工具”——即连接器。

4.1 连接器注册表

企业级智能体通常维护一个连接器注册表,记录每个可用连接器的能力、适用场景和调用方式:

class ConnectorRegistry:
    """连接器注册表:管理所有可用的系统连接器"""
    
    def __init__(self):
        self.connectors = {}
    
    def register(self, name: str, connector):
        self.connectors[name] = connector
    
    def select(self, action: str, context: dict) -> Optional[object]:
        """根据动作类型和执行上下文选择连接器"""
        # 优先级:精确匹配 → 模糊匹配 → 默认连接器
        if action in self.connectors:
            return self.connectors[action]
        # 根据上下文推断
        return self._infer_connector(action, context)

4.2 双模连接器:API与屏幕语义理解

企业IT环境的复杂性决定了连接器不能只有一种形态。API连接器适合有标准接口的系统,屏幕语义理解连接器适合无API的遗留系统。

class DualModeConnector:
    """双模连接器:API优先,屏幕语义理解兜底"""
    
    def __init__(self, api_config: dict, screen_config: dict):
        self.api_config = api_config
        self.screen_config = screen_config
        self.mode = "api"  # 当前模式:api | screen
    
    async def execute(self, action: str, params: dict) -> dict:
        # 优先尝试API模式
        if self.api_config.get("available"):
            try:
                result = await self._execute_via_api(action, params)
                return result
            except ApiException as e:
                # API失败,降级到屏幕语义理解
                self.mode = "screen"
                
        # 屏幕语义理解模式
        return await self._execute_via_screen(action, params)
    
    async def _execute_via_screen(self, action: str, params: dict) -> dict:
        """通过视觉识别操作界面"""
        # 截取当前屏幕
        screenshot = capture_screen()
        # 识别控件位置
        elements = detect_ui_elements(screenshot)
        # 生成操作序列
        actions = plan_operations(action, elements, params)
        # 执行操作
        for a in actions:
            execute_action(a)
            verify_result()
        return {"status": "success"}

这种双模设计在沈管家AI数字员工的执行层中有实践落地——有API的系统走标准接口,无API的C/S架构老系统走屏幕语义理解,用户在配置时无需感知底层差异。

五、系统调用:状态管理与异常处理

5.1 执行状态机

每个子任务的执行是一个有限状态机:

pending → ready → running → success
                        ↘ failed → retrying → success
                                  ↘ failed → skipped / escalated

状态转换必须持久化,以支持断点恢复:

class TaskStateManager:
    """任务状态管理器:持久化状态,支持断点恢复"""
    
    def __init__(self, state_store):  # state_store可以是Redis或数据库
        self.store = state_store
    
    def transition(self, task_id: str, from_status: str, to_status: str) -> bool:
        """原子化状态转换,防止并发冲突"""
        current = self.store.get(task_id)
        if current != from_status:
            return False
        self.store.set(task_id, to_status)
        return True
    
    def recover(self, task_id: str) -> str:
        """恢复中断的任务:从最后一个成功的步骤继续"""
        task_dag = self.store.get_dag(task_id)
        for node in task_dag:
            if node.status in ("pending", "ready", "running"):
                node.status = "ready"  # 重置为就绪,重新调度
        return task_dag

5.2 异常处理策略

生产环境中的异常远比Demo环境多。一个成熟的执行引擎需要定义清晰的异常处理策略:

异常类型处理策略示例
接口超时自动重试(3次,指数退避)网络抖动导致的临时失败
数据格式不符降级处理并标注某个字段为空或类型不匹配
权限不足暂停并通知人工尝试访问越权数据
系统不可用跳过该步骤,标记待补目标系统维护中

六、完整链路示例

以下是一个简化但可运行的完整示例,展示了从意图识别到系统调用的全链路:

class AgentExecutor:
    """AI智能体执行器:串联意图识别→任务拆解→工具选择→系统调用→结果验证"""
    
    def __init__(self, llm, registry, state_manager):
        self.recognizer = IntentRecognizer(llm, business_terms)
        self.decomposer = TaskDecomposer()
        self.registry = registry
        self.state = state_manager
    
    async def execute(self, user_input: str) -> dict:
        # Step 1: 意图识别
        intent = self.recognizer.recognize(user_input)
        if intent.confidence < 0.5:
            return {"error": "意图识别失败,请换一种说法"}
        
        # Step 2: 任务拆解
        subtasks = self.decomposer.decompose(intent)
        
        # Step 3: 拓扑排序,按依赖关系执行
        ready_queue = [t for t in subtasks if not t.depends_on]
        results = {}
        
        while ready_queue:
            task = ready_queue.pop(0)
            
            # Step 4: 工具选择与系统调用
            connector = self.registry.select(task.action, task.params)
            self.state.transition(task.task_id, "ready", "running")
            
            try:
                result = await connector.execute(task.action, task.params)
                
                # Step 5: 结果验证
                if self._validate_result(result):
                    self.state.transition(task.task_id, "running", "success")
                    results[task.task_id] = result
                else:
                    self.state.transition(task.task_id, "running", "failed")
                    results[task.task_id] = {"error": "结果验证失败"}
                    
            except Exception as e:
                self.state.transition(task.task_id, "running", "failed")
                results[task.task_id] = {"error": str(e)}
            
            # 释放依赖
            for t in subtasks:
                if task.task_id in t.depends_on:
                    t.depends_on.remove(task.task_id)
                    if not t.depends_on:
                        ready_queue.append(t)
        
        return results

七、工程要点总结

从意图识别到系统调用的完整链路,涉及以下核心工程问题:

  1. 意图识别的准确率:依赖大模型能力和业务术语字典的覆盖度
  2. 任务拆解的合理性:粒度要适中,每个子任务对应一次原子操作
  3. 连接器的覆盖广度:API模式与屏幕语义理解双模并存的必要性
  4. 状态管理的可靠性:持久化 + 断点恢复 + 并发控制
  5. 异常处理的完备性:重试、降级、人工介入的分级策略

评估一个AI智能体产品时,可以重点考察这五个环节的工程实现深度。功能列表上说“支持任务执行”很容易,但真正把五环节做扎实,需要大量的工程积累。

在调研中注意到,沈管家AI数字员工在这五环节上有较完整的实践——其“自然语言转SQL”引擎处理意图识别和语义消歧,DAG编排引擎负责任务拆解和依赖管理,双模连接器覆盖API和屏幕语义理解,SLA分级体系保障异常响应的时效性。这种端到端的工程闭环,是企业级AI数字员工与“大模型套壳”之间的本质区别。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐