Logo
热心市民王先生

技术原理核心

技术研究 LLM 系统架构

LLM 指令遵循的三层控制架构:Prompt 工程、API 约束与系统验证

深度分析:指令遵循的三层控制架构

提高 LLM 指令遵循稳定性的核心在于构建多层防御体系,而非依赖单一手段。我们将这套架构称为三层控制模型(Three-Layer Control Model):

┌─────────────────────────────────────────────────────────┐
│                   Layer 1: Prompt 层                      │
│         通过结构化表达引导模型理解意图                      │
│  ┌─────────────┬──────────────┬─────────────────────┐    │
│  │ 角色定义    │ 上下文引导   │ 输出模板            │    │
│  │ Role        │ Context      │ Output Template     │    │
│  └─────────────┴──────────────┴─────────────────────┘    │
├─────────────────────────────────────────────────────────┤
│                   Layer 2: API 层                         │
│         通过参数和 schema 强制约束模型输出                    │
│  ┌─────────────┬──────────────┬─────────────────────┐    │
│  │ 采样参数    │ Structured   │ Token 限制          │    │
│  │ Temperature │ Outputs      │ Max Tokens          │    │
│  └─────────────┴──────────────┴─────────────────────┘    │
├─────────────────────────────────────────────────────────┤
│                   Layer 3: 系统层                         │
│         通过验证、重试和 fallback 保证最终可靠性               │
│  ┌─────────────┬──────────────┬─────────────────────┐    │
│  │ Schema      │ 重试与       │ 多 Provider         │    │
│  │ Validation  │ Circuit      │ Fallback            │    │
│  │             │ Breaker      │                     │    │
│  └─────────────┴──────────────┴─────────────────────┘    │
└─────────────────────────────────────────────────────────┘

各层有效性对比

层级控制强度实现复杂度可靠性提升成本影响
Prompt 层低 - 依赖模型自律+10-20%可能增加输入 token
API 层中 - 软性约束+40-60%Structured Outputs 可能略慢
系统层高 - 硬性约束+80-95%重试增加成本和延迟

关键洞察:单一层次最多提升到 80-90% 的可靠性,三层结合才能达到 99%+ 的生产级标准。

架构图:完整指令遵循控制流程

系统架构总览

flowchart TD
    subgraph Client["客户端层"]
        A[用户请求] --> B[Prompt 模板引擎]
        B --> C[注入变量与上下文]
    end
    
    subgraph API["API 控制层"]
        C --> D[设置 API 参数]
        D --> E{选择输出模式}
        E -->|高可靠性 | F[Structured Output]
        E -->|标准 | G[JSON Mode]
        E -->|灵活 | H[Free Text]
        F --> I[Pydantic/Zod Schema]
        G --> J[JSON Schema]
    end
    
    subgraph Model["模型层"]
        I --> K[LLM API - OpenAI/Claude/Gemini]
        J --> K
        H --> K
        K --> L{生成响应}
    end
    
    subgraph System["系统验证层"]
        L --> M[Schema 验证器]
        M -->|通过 | N[返回结果]
        M -->|失败 | O{重试次数 < 阈值?}
        O -->|是 | P[注入错误反馈]
        P --> B
        O -->|否 | Q[Fallback 到备用模型]
        Q --> K
    end
    
    subgraph Monitor["监控层"]
        N --> R[记录指标]
        Q --> R
        R --> S[Dashboard]
        R --> T[Alerting]
    end
    
    style Client fill:#e1f5fe
    style API fill:#fff3e0
    style Model fill:#f3e5f5
    style System fill:#e8f5e9
    style Monitor fill:#ffebee

数据流与验证循环

sequenceDiagram
    participant User as 用户
    participant App as 应用层
    participant Validator as 验证器
    participant LLM as LLM API
    participant Monitor as 监控系统
    
    User->>App: 请求(带约束)
    App->>App: 构建 Prompt + Schema
    App->>LLM: API 调用(temperature=0.2)
    
    alt 第一次尝试
        LLM-->>Validator: 返回 JSON
        Validator->>Validator: Schema 验证
        Validator-->>App: 验证通过
        App->>Monitor: 记录成功指标
        App-->>User: 返回结果
    else 验证失败
        Validator-->>App: 验证错误
        App->>App: 检查重试预算
        App->>LLM: 重试(注入错误信息)
        LLM-->>Validator: 返回修正 JSON
        Validator->>Validator: Schema 验证
        Validator-->>App: 验证通过
        App->>Monitor: 记录重试指标
        App-->>User: 返回结果
    end
    
    Note over App,Monitor: 每次交互都记录到追踪系统

多 Provider Fallback 架构

graph TD
    A[请求到达] --> B{健康检查}
    B -->|Primary 可用 | C[调用 Primary<br/>GPT-4o]
    B -->|Primary 不可用 | D{Secondary 可用?}
    D -->|是 | E[调用 Secondary<br/>Claude 4.5]
    D -->|否 | F{Tertiary 可用?}
    F -->|是 | G[调用 Tertiary<br/>Gemini 3]
    F -->|否 | H[降级:缓存/错误]
    
    C --> I{验证通过?}
    E --> I
    G --> I
    
    I -->|是 | J[返回结果]
    I -->|否 | K{尝试下一个 Provider}
    K --> D
    
    style C fill:#c8e6c9
    style E fill:#fff9c4
    style G fill:#ffccbc
    style H fill:#ffcdd2

核心组件详解

1. Prompt 结构化引擎

作用:将非结构化需求转换为模型易理解的格式

关键技术

# 使用 XML tags 分隔不同部分(Anthropic 推荐)
prompt = """
<role>
你是一位资深的数据分析师,专注于从非结构化文本中提取结构化信息。
</role>

<context>
用户需要提取的事件信息将用于日历系统集成,必须严格遵守 ISO 8601 日期格式。
</context>

<instructions>
1. 识别文本中所有的事件
2. 提取事件名称、日期、参与者和地点
3. 如果信息缺失,使用 null 而非猜测
4. 日期必须转换为 YYYY-MM-DD 格式
</instructions>

<constraints>
- 只输出 JSON,不要有任何解释文字
- 日期字段不能为空,找不到则填 null
- 参与者必须是数组,即使只有一个人
- 不要使用 Markdown 格式,纯 JSON
</constraints>

<input>
{user_input}
</input>

<output_format>
{
  "events": [
    {
      "name": "string",
      "date": "YYYY-MM-DD or null",
      "participants": ["string"],
      "location": "string or null"
    }
  ]
}
</output_format>
"""

为什么有效

  • XML tags 提供清晰的语义边界,模型不会混淆指令与输入
  • <constraints> 显式列出负面约束,减少违反
  • <output_format> 提供视觉模板,比纯文字描述更直观

2. Structured Outputs(结构化输出)

OpenAI 实现(100% Schema 合规保证):

from pydantic import BaseModel, Field
from openai import OpenAI

class CalendarEvent(BaseModel):
    name: str = Field(description="事件名称")
    date: str | None = Field(description="ISO 8601 日期格式 YYYY-MM-DD")
    participants: list[str] = Field(description="参与者列表")
    location: str | None = Field(description="地点")

class EventExtraction(BaseModel):
    events: list[CalendarEvent]

client = OpenAI()

completion = client.chat.completions.parse(
    model="gpt-4o-2024-08-06",
    messages=[
        {"role": "system", "content": "提取日历事件,严格遵守 schema"},
        {"role": "user", "content": "Alice 和 Bob 下周五下午 3 点在星巴克开会"}
    ],
    response_format=CalendarEvent  # 关键:强制 schema 约束
)

event = completion.choices[0].message.parsed  # 类型安全,保证合规

Anthropic 实现(约 99% 合规率):

from anthropic import Anthropic
from pydantic import BaseModel

client = Anthropic()

response = client.messages.parse(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    system="Extract calendar events from the input text.",
    messages=[
        {"role": "user", "content": "Meeting with Alice on Friday"},
    ],
    output_config={
        "type": "json_schema",
        "name": "calendar_event",
        "schema": {
            "type": "object",
            "properties": {
                "events": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "name": {"type": "string"},
                            "date": {"type": "string", "format": "date"},
                            "participants": {
                                "type": "array",
                                "items": {"type": "string"}
                            }
                        },
                        "required": ["name", "date", "participants"]
                    }
                }
            },
            "required": ["events"]
        }
    }
)

events = response.output[0].content  # JSON 字符串,需解析

为什么 Structured Outputs 比 JSON Mode 更可靠

特性JSON ModeStructured Outputs
保证级别最佳努力(~95%)强制约束(100% OpenAI)
错误处理解析失败需手动重试自动拒绝不合规输出
类型安全需手动验证Pydantic/Zod 自动验证
Token 效率需要 verbose schema精简 schema,节省 30-60%

3. 验证与重试循环

import instructor
from pydantic import BaseModel, ValidationError
from openai import OpenAI

# Instructor 库自动处理验证 - 重试循环
client = instructor.patch(OpenAI())

class UserExtraction(BaseModel):
    name: str
    email: str
    age: int | None
    
    @field_validator('email')
    def validate_email(cls, v):
        if '@' not in v:
            raise ValueError('Invalid email format')
        return v

try:
    user = client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "我叫小明,邮箱是 not-an-email"}],
        response_model=UserExtraction,
        max_retries=3  # 自动重试最多 3 次
    )
except ValidationError as e:
    # 即使重试也失败,处理最终错误
    log_error(e)
    raise

Instructor 的工作原理

flowchart LR
    A[发送请求] --> B[LLM 返回 JSON]
    B --> C[Pydantic 验证]
    C -->|通过 | D[返回结果]
    C -->|失败 | E{重试次数 < max?}
    E -->|是 | F[构建错误反馈]
    F --> G[注入错误到 prompt]
    G --> A
    E -->|否 | H[抛出 ValidationError]
    
    style C fill:#fff9c4
    style F fill:#ffccbc

错误反馈示例

原始响应:{"name": "小明", "email": "not-an-email", "age": 25}
验证错误:ValueError: Invalid email format

修正后的 prompt 添加:

错误:上一次响应的 email 字段验证失败 原因:‘not-an-email’ 不是有效的 email 格式 请修正并提供有效的 email 地址

4. Circuit Breaker(熔断器)

from pybreaker import CircuitBreaker

class LLMClient:
    def __init__(self):
        self.breaker = CircuitBreaker(
            fail_threshold=5,      # 5 次失败后打开
            recovery_timeout=60,   # 60 秒后尝试恢复
            expected_exception=(RateLimitError, APIError)
        )
    
    @circuit
    def call_llm(self, prompt):
        return self.client.chat.completions.create(
            model="gpt-4o",
            messages=[{"role": "user", "content": prompt}]
        )

# 使用
client = LLMClient()
try:
    response = client.call_llm("提取事件...")
except CircuitBreakerError:
    # 快速失败,切换到备用 provider
    response = fallback_client.call_llm("提取事件...")

状态机

stateDiagram-v2
    [*] --> Closed: 初始状态
    Closed --> Open: 失败次数 ≥ 阈值
    Open --> HalfOpen: recovery_timeout 到期
    HalfOpen --> Closed: 试探请求成功
    HalfOpen --> Open: 试探请求失败
    Closed --> Closed: 请求成功(重置失败计数)
    
    note right of Closed: 正常处理请求
    note right of Open: 立即失败,触发 fallback
    note right of HalfOpen: 允许一个试探请求

设计哲学

1. 防御性设计(Defensive Design)

原则:永远不信任模型的输出,总是验证

信任但验证 → 不信任,必验证
  • Schema 验证是必须,不是可选
  • 重试是预期内,不是异常
  • Fallback 是计划中,不是紧急修复

2. 分层降级(Graceful Degradation)

当某一层失效时,下一层接管:

Prompt 失败 → API Structured Outputs 兜底
API 失败 → 系统层重试/验证兜底
系统层失败 → Fallback 到备用模型
所有模型失败 → 返回缓存或友好错误

3. 可观测性优先(Observability First)

无法度量,就无法改进

每个请求必须记录:

  • Prompt 版本
  • Model + 参数
  • 响应时间(time-to-first-token, inter-token)
  • 验证结果(通过/失败 + 错误类型)
  • 重试次数
  • 最终状态(成功/fallback/失败)

4. 显式优于隐式(Explicit Over Implicit)

# ❌ 隐式:依赖模型理解
"请返回 JSON 格式"

# ✅ 显式:Schema + 验证
response_format=CalendarEvent  # Pydantic 模型
# ❌ 隐式:默认重试
try:
    call_llm()
except:
    call_llm()  # 无限重试风险

# ✅ 显式:有界重试
for attempt in range(max_retries):
    try:
        return call_llm()
    except RetriableError as e:
        wait = exponential_backoff(attempt)
        sleep(wait)
raise MaxRetriesExceeded()

参考资料