将小型语言模型作为控制平面来驾驭复杂系统

本文探讨了一种新颖的架构模式:将小型语言模型作为控制平面,来编排和管理复杂的AI系统。它详细阐述了该模式的优势、实现原理,并通过一个事件响应平台的实例和Python代码示例展示了其实际应用。

小型语言模型作为控制平面来驾驭复杂系统

小型语言模型不仅能回答问题;它们还可以充当“控制大脑”,在服务、工具和更大的模型之间路由工作。

大多数团队采用相同的策略来接触人工智能:将一个大语言模型集成到应用程序中,连接一些工具/产品等,然后随着新用例和功能的增加,逐渐看着复杂性增长。 这正是发生在我身上的事情。一个起初只是“聊天机器人”的项目演变成了:

  • 多个模型(例如,用于聊天的原始LLM、用于检索的嵌入模型、视觉模型等)
  • 一大堆需要以某种方式编排的工具和API
  • 不同层的检索逻辑、特征存储、向量数据库等
  • 多层护栏、用于跟踪系统采取行动的审计日志、和/或在系统完成行动前需要的人工审批步骤

胶水逻辑开始渗透到每个服务中。提示词散落在整个代码库中。调试一个错误决策意味着要追踪三个不同系统中的日志。 在某个时刻,我意识到我不再是在“构建一个AI系统”;我是在对抗这个架构。 这促使我转向了一种不同的模式:利用小型语言模型作为控制平面,一个专门的“大脑”来决定接下来发生什么,并让堆栈的其余部分专注于执行实际任务。 本文阐述了我如何看待SLM作为控制平面,为什么这种模式在实践中对我很有效,以及如何在您自己的系统中实现它。

我所指的“小型语言模型”和“控制平面”

当我说小型语言模型时,我指的是参数远少于当今旗舰LLM的模型(通常在50亿参数以下),旨在:

  • 运行成本低(通常在单个GPU甚至CPU上)
  • 足够快,以至于在每个请求上调用它都不会感到痛苦(低延迟推理)
  • 易于使用您自己的领域数据进行微调以适应您的特定用例
  • 可部署在本地或边缘,以实现数据的隐私和控制

在我的实验和原型中,这通常意味着来自诸如 Phi-3、LLaMA 3 8B、Mistral-7B 等系列模型,以及其他可以通过 Ollama 等工具在本地运行或在轻量级服务器上运行的紧凑模型。

控制平面与数据平面(我经常使用的类比)

在网络、Kubernetes 和服务网格的上下文中,经常讨论:

  • 控制平面 – 建立并强制执行策略:路由规则、安全策略和配置。它是“大脑”。
  • 数据平面 – 实际执行这些策略:转发数据包、终止TLS、路由请求等。它是“双手”。

控制平面不接触每个数据包;相反,它决定应该发生什么动作,相应地配置数据平面,并监控其性能。 我意识到我可以对AI系统采用相同的模式:

  • SLM控制平面 – 确定目标,选择工具/模型,编排步骤序列,并强制执行约束。
  • 数据平面 – 包括微服务、向量存储、更大的LLM、CV模型和事务系统,它们执行实际工作。

一旦我开始思考“这个SLM是我的控制平面”,我的AI系统架构就变得清晰多了。

为什么SLM能成为优秀的控制平面(根据经验)

是的,您可以在应用程序的所有方面使用一个巨大的LLM(请求解释;调用专用服务/工具;生成响应)。我尝试过,在生产中很快就变得很痛苦。 以下是我转向使用SLM作为控制平面的原因。

1. 可承受的成本和延迟 路由和编排发生在每个请求上。仅仅为了决定调用哪个下游服务而使用一个4000亿参数的模型是大材小用。切换到使用SLM进行规划和路由后,我获得了:

  • 降低了单次请求成本 – 当您为每个用户请求调用多个工具/服务时,这非常有益。
  • 更低的延迟 – 当您的控制循环是用户体验的重要组成部分时,这是必需的。

2. 本地和隔离部署 开发人员偏爱SLM的一个主要原因是其部署能力:

  • 在开发人员工作站上进行本地开发
  • 在本地或在私有VPC中,用于受监管的领域(金融、医疗、能源)

这使得SLM成为敏感数据无法离开您网络的环境的天然控制平面。

3. 微调和可预测性 因为SLM更小,所以我对针对狭小范围的行为进行微调感到不那么内疚,例如:

  • “确定对此请求调用哪个微服务。”
  • “将此API有效负载转换为结构化事件。”
  • “确定此事件的分类并选择正确的工作流模板。”

通过适当的提示词设计和模式设计,我已经能够实现一致且结构化的输出(例如,具有固定模式的JSON),并最终得到更容易测试和推理的更确定行为。

4. 关注点分离 我看到的最大好处是关注点分离:

  • SLM控制平面在一个地方处理编排逻辑
  • 数据平面服务保持“简单但可靠”,专注于做好它们的本职工作

当我需要更换工具或模型时,通常可以在不重构整个系统的情况下完成。这感觉非常类似于服务网格和API网关分离策略与执行的方式。

“SLM作为控制平面”模式

以下是我根据实际经验定义该模式的方法。

SLM控制平面的职责

SLM是您的规划器和路由器,而不是您的业务逻辑:

  • 理解意图:解析用户/系统输入;识别目标、约束和安全规则。
  • 选择计划:决定应该调用哪些工具/服务/模型;可能将任务分解为多个步骤。
  • 发出结构化命令:生成机器可读的计划(例如JSON);指定工具名称、参数和顺序。
  • 处理反馈:检查工具响应;决定是重试、升级还是调用不同的工具;为下游消费者(UI、API、日志)总结结果。

SLM从不直接操作您的核心业务数据。它告诉其他组件该做什么,然后检查发生了什么。

数据平面的职责

数据平面是实际工作发生的地方:

  • 微服务:计费、库存、CRM、工单等。
  • 专业模型:嵌入模型、视觉模型、用于深度推理的更大的LLM。
  • 存储:向量数据库、SQL/NoSQL存储、日志管道。
  • 遗留系统:大型机、ERP、自定义业务线应用程序。

每个数据平面服务都提供一个狭小、定义明确的API:SLM不关心工具/服务内部如何工作,它只负责调用工具/服务并读取其输出。

示例架构:SLM引导事件响应平台

为了让这更具体,设想一个事件响应助手。

旧方法 您直接将一个大LLM连接到:

  • 日志搜索API
  • 指标API
  • 操作规程文档
  • PagerDuty / 工单集成

提示词变得越来越复杂,很快您不是在调试事件,而是在调试提示词:

“根据这些日志、指标、过去的事件和操作规程,解释正在发生什么,并决定我们是否应该呼叫值班人员…”

SLM控制平面方法 相反,您构建:

  • 一个小的控制 SLM,它:
    • 接收事件描述(警报负载、日志片段、上下文)
    • 决定调用哪些工具以及调用顺序
    • 聚合结果并返回简洁的决策
  • 一个由 工具/服务 组成的数据平面
    • search_logs(query, time_range)
    • get_metric(service, window)
    • find_similar_incident(payload)
    • lookup_runbook(service, symptom)
    • create_ticket(summary, severity)
    • 可选地,一个更大的LLM用于深度根因分析

高层流程:

  1. 警报传入。
  2. 控制SLM决定:“首先调用 search_logsget_metrics。”
  3. 工具运行,返回结构化数据。
  4. SLM查看结果,说:
    • 匹配事件 X → 使用严重性 HIGH 调用 lookup_runbookcreate_ticket
    • 或“不清楚 → 使用总结的上下文上报给人工处理。”

所有繁重的工作:日志扫描、指标聚合、工单创建,都存在于您可以用常规方式测试的代码中。SLM编排整个流程。

实现草图:Python中的简单SLM路由器

这是一个展示该模式的最小示例(与框架无关)。

1. 定义您的工具(数据平面函数)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import requests

def search_logs(query, time_range):
    resp = requests.get(
        "https://logs.internal/api/search",
        params={"q": query, "range": time_range},
        timeout=5,
    )
    resp.raise_for_status()
    return resp.json()

def get_metrics(service, window):
    resp = requests.get(
        "https://metrics.internal/api/stats",
        params={"service": service, "window": window},
        timeout=5,
    )
    resp.raise_for_status()
    return resp.json()

def create_ticket(summary, severity):
    resp = requests.post(
        "https://tickets.internal/api/tickets",
        json={"summary": summary, "severity": severity},
        timeout=5,
    )
    resp.raise_for_status()
    return resp.json()

2. 为SLM定义一个规划模式。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "steps": [
    {
      "tool": "search_logs",
      "args": { "query": "...", "time_range": "15m" }
    },
    {
      "tool": "get_metrics",
      "args": { "service": "checkout", "window": "30m" }
    },
    {
      "tool": "create_ticket",
      "args": { "summary": "...", "severity": "HIGH" }
    }
  ]
}

3. 调用您的SLM来生成该计划。 这段伪代码假设您正在访问一个本地SLM端点(例如,通过Ollama托管的Phi-3)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import json
import requests

SLM_URL = "http://localhost:8000/v1/chat/completions"

PLAN_PROMPT = """
You are an incident-response planner. Given an alert, decide which tools to call
and in what order. Return ONLY valid JSON matching this schema:

{
  "steps": [
    { "tool": "<tool_name>", "args": { ... } }
  ]
}

Available tools:
- search_logs(query: string, time_range: string)
- get_metrics(service: string, window: string)
- create_ticket(summary: string, severity: "LOW"|"MEDIUM"|"HIGH")
"""

def ask_slm_for_plan(alert_text: str) -> dict:
    payload = {
        "model": "phi-3-mini",
        "messages": [
            {"role": "system", "content": PLAN_PROMPT},
            {"role": "user", "content": f"Alert: {alert_text}"}
        ],
        "temperature": 0.1
    }
    resp = requests.post(SLM_URL, json=payload, timeout=10)
    resp.raise_for_status()
    content = resp.json()["choices"][0]["message"]["content"]
    return json.loads(content)

在生产环境中,您需要添加:

  • JSON模式验证
  • 重试逻辑
  • 护栏或仅JSON解码器以避免格式错误的输出

……但这抓住了核心思想。

4. 在您的编排器中执行计划。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
TOOL_REGISTRY = {
    "search_logs": search_logs,
    "get_metrics": get_metrics,
    "create_ticket": create_ticket,
}

def execute_plan(plan: dict, context: dict | None = None):
    context = context or {}
    results = []

    for step in plan.get("steps", []):
        tool_name = step["tool"]
        args = step.get("args", {})

        if tool_name not in TOOL_REGISTRY:
            raise ValueError(f"Unknown tool: {tool_name}")

        tool_fn = TOOL_REGISTRY[tool_name]
        result = tool_fn(**args)
        results.append({"tool": tool_name, "result": result})

        # 可选地更新上下文,在另一个循环中反馈给SLM等。
        context[tool_name] = result

    return results

现在您的高层处理函数看起来像:

1
2
3
4
def handle_alert(alert_text: str):
    plan = ask_slm_for_plan(alert_text)
    results = execute_plan(plan)
    return {"plan": plan, "results": results}

您刚刚构建了:

  • 一个SLM控制平面(规划 + 路由)
  • 一个常规代码数据平面(工具/服务)

您可以在没有模型的情况下测试 search_logsget_metricscreate_ticket 甚至 execute_plan,然后使用记录的测试警报单独评估SLM行为。

我学到的设计经验

  • 保持SLM的工作小而明确
  • 使用SLM来把关访问和执行策略
  • 记录所有内容
  • 为确定性进行调整
  • 决定何时真正需要一个大LLM

该模式对我奏效(以及不奏效)的场景

合适的场景:

  • 具有许多工具和服务的系统(API、多个模型、外部SaaS)
  • 需要逐步计划和工具使用的代理工作流
  • 受监管或高风险环境,您希望有一个狭小、可审计的“大脑”
  • 成本敏感的场景,在每个请求上调用庞大的LLM是不可行的

可能过度设计: 另一方面,我不会在以下情况选择这种模式:

  • 任务是简单的一次性问答或摘要。
  • 只有一个单一的工具,没有分支逻辑。
  • 延迟预算非常紧张,以至于即使调用SLM也太多。

您不需要为所有事情都配置SLM控制平面。在编排复杂性需要专门的“AI路由器”的地方使用它。

结语

一旦我的AI系统不再是“聊天框后的单一模型”,而开始看起来更像分布式、代理化的平台,架构和模型选择一样重要这一点就变得显而易见。 将SLM视为控制平面给了我:

  • 一个用于规划和策略制定的集中化场所。
  • 简单、可测试的数据平面服务。
  • 自由混合和匹配底层更大的模型、工具和系统。
  • 明确的杠杆来调整成本、延迟和安全性。

您不必为了采用这种模式而移除所有的LLM使用。根据我的经验,成功来自于赋予SLM它最擅长的工作: 不是做所有事情——只是驾驭您的其余技术栈。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计