在上一篇文章中,我们梳理了 Transformer、RAG、Function Calling 以及 MCP 的基础原理。如果说第一篇关注的是单点能力(如何调用模型、如何连接数据),那么这一篇我们将聚焦于工程架构

当前 AI 应用开发(如 Cursor、Windsurf、Devin 等)的核心挑战,在于如何将无状态的 LLM 转化为有状态、可执行复杂任务的系统。这涉及到三个核心概念的工程化落地:Skill(技能封装)Agent(智能体循环)Workflow(工作流编排)

本文将从代码实现与数据流转的角度,深入剖析这三者的实现原理。

Skill:从 Prompt 到可执行单元

在早期的 AI 开发中,Prompt 是零散的字符串。但在复杂的工程中,我们需要一种标准化的格式来封装“特定领域的解决能力”,这就是 Skill。

Skill 本质上是一个包含指令、上下文、工具和元数据的配置对象。 它是 Agent 在运行时动态挂载的“驱动程序”。

Skill 的数据结构

一个标准的 Skill 在 Node.js 环境下通常被定义为如下结构:

interface Skill {
  // 元数据:用于路由分发
  metadata: {
    id: string;
    name: string;
    version: string;
    description: string; // 用于 Semantic Router 匹配
  };

  // 核心指令:System Prompt 的片段
  instruction: string;

  // 上下文注入:动态或静态的知识
  context: {
    files?: string[];     // 静态文档路径
    dynamic?: () => Promise<string>; // 运行时获取的状态 (e.g. 当前用户ID、系统时间)
  };

  // 工具集:该技能可用的原子能力
  tools: ToolDefinition[]; 
}

// 示例:定义一个 SQL 查询技能
const sqlExpertSkill: Skill = {
  metadata: {
    id: 'sql-expert-v1',
    name: 'SQL Generator & Executor',
    description: 'When users need to query database or analyze data via SQL',
  },
  instruction: `
    You are a PostgreSQL expert. 
    1. Always explain the query plan before execution.
    2. Read-only queries allowed.
    3. Use ISO 8601 for dates.
  `,
  context: {
    files: ['./docs/db_schema.md'], // 注入表结构
  },
  tools: [runQueryTool, listTablesTool] // 挂载 MCP 工具或本地函数
};

Skill 的加载与执行流程

Skill 的核心价值在于按需加载。我们不需要将所有 Prompt 和 Tool 一次性塞入 Context Window,而是通过路由动态激活。

Runtime Context

Skill Registry

Match: SQL

Match: Bug fix

用户输入 User Input

Router 意图识别

Coding Skill

Data Analysis Skill

General Chat Skill

Context Assembler

System Prompt + Skill Instruction

Global Context + Skill Files

Registered Tools

LLM Inference

Agent:从无状态推理到有状态循环

LLM 本身是无状态的(Stateless),输入什么输出什么。Agent 则是通过**循环(Loop)记忆(Memory)**机制,让 LLM 具备了连续执行任务的能力。

目前主流的 Agent 架构通常基于 ReAct (Reasoning + Acting) 模式。

ReAct 循环

Agent 的核心是一个 while 循环,直到 LLM 判定任务结束或达到最大迭代次数。伪代码如下:

async function runAgentLoop(userQuery, tools) {
  let messages = [
    { role: 'system', content: 'You are a helpful assistant...' },
    { role: 'user', content: userQuery }
  ];

  let iterations = 0;
  const MAX_ITERATIONS = 10;

  while (iterations < MAX_ITERATIONS) {
    // 1. 调用 LLM
    const response = await llm.chat({ messages, tools });
    const message = response.choices[0].message;

    // 2. 将 LLM 的回复加入历史
    messages.push(message);

    // 3. 判断是否需要停止(无工具调用则视为回答完毕)
    if (!message.tool_calls || message.tool_calls.length === 0) {
      return message.content;
    }

    // 4. 执行工具调用 (Action)
    for (const toolCall of message.tool_calls) {
      const toolName = toolCall.function.name;
      const args = JSON.parse(toolCall.function.arguments);
      
      // 执行具体函数
      const result = await executeTool(toolName, args);
      
      // 5. 将工具结果回填给 LLM (Observation)
      // 注意:这一步是为了让 LLM 在下一次循环中看到工具执行的结果,从而生成最终回答
      messages.push({
        role: 'tool',
        tool_call_id: toolCall.id,
        content: JSON.stringify(result)
      });
    }

    iterations++;
  }
}

Agent 状态流转图

工具环境(API/DB) LLM AgentCore Client 工具环境(API/DB) LLM AgentCore Client 循环结束 opt [无工具调用] loop [ReAct Loop] 任务指令 当前消息历史 (History) 返回思考 (Thought) + 工具调用 (Call) 返回最终结果 执行工具 (Action) 返回执行结果 (Observation) 更新消息历史 (Append History)

Workflow:确定性的编排

当单一 Agent 无法胜任复杂场景(如先写需求文档,再写代码,最后运行测试)时,我们需要引入 Workflow(工作流)

Agent 倾向于自主决策(Probabilistic),而 Workflow 强调确定性的流程控制(Deterministic)。在实际工程中,通常采用 DAG(有向无环图)State Graph(状态图) 来编排多个 Agent。

常见的 Workflow 模式

1. Planning Pattern (规划-执行模式)

将任务拆解为 Plan,然后逐一 Execute。

Execution Loop

生成 Plan List

取下一个 Task

执行结果

结果检查

否/重试

列表为空

用户需求

Planner Agent

Controller

Worker Agent

Reflector Agent

是否通过?

总结输出

End

2. Multi-Agent Handoff (多智能体协作)

类似工厂流水线,上游 Agent 的输出作为下游 Agent 的输入。

PRD文档

源代码

Review意见

User

Product Manager Agent

Developer Agent

Code Reviewer Agent

通过?

Deployer Agent

伪代码:基于状态图的编排

使用类似 LangGraph 的逻辑来定义工作流:

// 定义状态
const State = {
  input: String,
  code: String,
  review_comments: String,
  status: 'planning' | 'coding' | 'reviewing' | 'finished'
};

// 定义节点(Node)
async function codingNode(state) {
  const code = await codingAgent.generate(state.input);
  return { ...state, code, status: 'reviewing' };
}

async function reviewNode(state) {
  const comments = await reviewAgent.check(state.code);
  if (comments.hasCriticalIssues) {
    return { ...state, review_comments: comments, status: 'coding' }; // 回退
  }
  return { ...state, status: 'finished' };
}

// 定义图(Graph)
const graph = new StateGraph();
graph.addNode('coder', codingNode);
graph.addNode('reviewer', reviewNode);

// 定义边(Edge)
graph.addEdge('coder', 'reviewer');
graph.addConditionalEdge('reviewer', (state) => {
  return state.status === 'coding' ? 'coder' : 'end';
});

// 执行
await graph.compile().invoke({ input: "Implement a login page" });

工程化挑战:结构化输出与评估

在企业级落地中,仅有架构是不够的,必须解决稳定性和可观测性问题。

结构化输出 (Structured Output)

LLM 默认输出非结构化文本。为了让 Workflow 中的节点能够通信,必须强制 LLM 输出严格的 JSON。

实现方案:

  1. Instruction Tuning:在 Prompt 中给出 JSON 示例(稳定性一般)。
  2. Function Calling Mode:利用 Tool Call 参数必须为 JSON 的特性(稳定性高)。
  3. Grammar Sampling:在推理引擎层(如 llama.cpp)使用 BNF 语法约束 Token 采样(稳定性最高)。
// 利用 Zod 定义输出 Schema
import { z } from 'zod';

const AnalysisSchema = z.object({
  sentiment: z.enum(['positive', 'neutral', 'negative']),
  key_points: z.array(z.string()),
  confidence_score: z.number().min(0).max(1)
});

// 大部分现代 SDK 支持直接传递 Schema
const result = await llm.generateObject({
  model: 'gpt-4',
  schema: AnalysisSchema,
  prompt: '分析这段客户反馈...'
});

自动化评估 (Evals)

Agent 系统是一个黑盒,必须建立评估流水线。

测试数据集 (Dataset)

Agent System

实际输出

标准答案 (Ground Truth)

Judge LLM (GPT-4)

准确性

幻觉检测

工具使用正确率

结语

从 Transformer 的底层原理,到 Skill、Agent、Workflow 的上层架构,我们已经完整梳理了构建现代 AI 应用的技术栈。

  • Skill 解决了“能力复用”与“上下文隔离”的问题。
  • Agent 解决了“复杂任务自动推演”的问题。
  • Workflow 解决了“多步骤协作”与“过程可控性”的问题。

未来的竞争焦点将不再局限于模型本身的参数量,而在于谁能构建出更高效的 Agent Runtime 和更丰富的 Skill 生态。希望这两篇文章能为你构建自己的 AI 应用提供扎实的工程参考。

更多推荐