文章 / 输出约束——让模型说"该说的话"
Harness

输出约束——让模型说"该说的话"

2026.07.06 · 约 2800 字

前面三根缰绳管的是"模型能看到什么"(上下文管理)、"输出是否可信"(验证闭环)、"经验能否复用"(知识沉淀)。第四根缰绳回答的问题最简单,也最容易被忽略:模型的输出格式对吗?

在一个生产级 Agent 系统中,模型的输出往往不是给最终用户看的自然语言,而是给下游系统吃的结构化数据——JSON、函数调用参数、数据库查询语句、API 请求体。这些输出如果不符合预期格式,下游系统就会报错,甚至静默地做错事。

核心命题: 输出约束不是"限制模型的能力",而是"把模型的能力对准系统的接口"。格式不对的输出,内容再正确也没有用。

一、输出约束的三个层次

输出约束不是单一的技术,而是从 Prompt 到代码的三层防线:

第一层:Prompt 约束

在 Prompt 中明确告诉模型输出的格式要求。这是最基础也最重要的约束:

// 弱约束:"请以 JSON 格式返回"
// 强约束:
"你的回答必须是一个 JSON 对象,格式如下:
{
    \"action\": \"工具名称\",       // 必填,从可用工具列表中选择
    \"params\": {             // 必填,根据所选工具的参数 Schema
        \"param1\": \"值\"          // 每个参数必须符合类型要求
    },
    \"reasoning\": \"选择理由\"     // 必填,不超过 100 字
}

请确保:
1. 输出是合法的 JSON
2. 所有必填字段都已填写
3. 参数类型与 Schema 一致
4. 不需要 Markdown 包裹(直接输出 JSON)"

Prompt 约束的关键原则:越具体越好。"返回 JSON"不如"返回一个包含 id、name、status 三个字段的 JSON 对象"。"不要添加 Markdown"不如"直接输出纯 JSON,不要用 ```json 包裹"。

第二层:Schema 约束

Prompt 约束靠模型的"理解",Schema 约束靠系统的"强制"。当 API 支持结构化输出(Structured Output / JSON Mode)时,优先使用:

// 用 JSON Schema 约束模型输出(以 OpenAI API 为例)
const response = await openai.chat.completions.create({
    model: "gpt-4o",
    messages: [/* ... */],
    response_format: {
        type: "json_schema",
        json_schema: {
            name: "tool_call",
            strict: true,
            schema: {
                type: "object",
                properties: {
                    action: { type: "string", enum: ["query", "update", "delete"] },
                    params: { type: "object" },
                    reasoning: { type: "string", maxLength: 100 }
                },
                required: ["action", "params", "reasoning"],
                additionalProperties: false
            }
        }
    }
});

Schema 约束的优势:模型输出的 JSON 保证符合 Schema。如果模型生成的 JSON 不符合 Schema,API 会自动重试或报错,不会把非法输出传递到下游。

第三层:代码约束

即使有了 Prompt 约束和 Schema 约束,代码层面仍然需要做最终的兜底:

关键认知: 三层约束不是"选一个",而是"叠三层"。Prompt 约束管大部分情况,Schema 约束管格式合规,代码约束管最后的异常。每一层都在弥补上一层的盲区。

二、不只是 JSON——输出约束的更多场景

输出约束不只是让模型输出合法的 JSON。在更多场景中,约束的含义更广泛:

长度约束

模型可能生成过长的回复。在某些场景下(如 Tool 描述的返回、摘要生成),需要限制输出长度:

风格约束

模型回复的语气和风格应该与应用场景匹配:

安全约束

最严格的约束——模型不能说的内容:

三、约束与创造力的平衡

输出约束最常受到的批评是"限制了模型的创造力"。这个批评本身没错——约束确实限制了模型"能说的范围"。但问题不在于"是否限制",而在于"在什么地方限制"

在不同场景下,约束的强度不同:

┌────────────────────────────────────────────┐
│  松约束区域(创造力优先)                    │
│  ├─ 面向用户的对话回复                      │
│  ├─ 创意内容生成                            │
│  └─ 探索性分析                              │
│  策略:风格约束为主,格式约束为辅             │
├────────────────────────────────────────────┤
│  紧约束区域(精确性优先)                    │
│  ├─ 工具调用参数                            │
│  ├─ API 请求构建                            │
│  ├─ 数据库查询生成                          │
│  └─ 数据格式转换                            │
│  策略:Prompt + Schema + 代码三层全开        │
├────────────────────────────────────────────┤
│  零容忍区域(安全优先)                      │
│  ├─ 权限相关操作                            │
│  ├─ 财务/法律相关输出                       │
│  └─ 涉及用户隐私的回复                       │
│  策略:代码层面的强制约束 + 人工审批          │
└────────────────────────────────────────────┘

关键是在同一个 Agent 系统中,根据不同的输出类型动态调整约束强度。一个写客服回复的 Agent 和一个写 SQL 查询的 Agent,不应该使用相同的约束策略。

四、约束的工程实现

输出约束在工程上需要与 Agent 的框架深度集成:

// 输出约束管理器的核心结构
class OutputConstraintManager:
    def getConstraints(self, context):
        # 根据输出目标选择约束策略
        if context.target == "tool_call":
            return ToolCallConstraints(context.tool)
        elif context.target == "user_reply":
            return ReplyConstraints(context.scenario)
        elif context.target == "data_extraction":
            return SchemaConstraints(context.schema)
    
    def apply(self, output, constraints):
        # 应用约束(Prompt + Schema 已在 API 层面处理)
        # 代码层面做最终校验
        if constraints.validate(output):
            return output
        else:
            return constraints.fallback()  // 降级输出

五、Harness 的四根缰绳

到此,Harness 的四根缰绳全部到位:

Harness —— 控制大模型的第一根缰绳

┌────────────────────────────────────────────┐
│  ① 上下文管理                              │
│  问题:模型能看到什么                       │
│  答案:分层管理,把最重要的信息放在最前面     │
├────────────────────────────────────────────┤
│  ② 验证闭环                                │
│  问题:模型的输出是否可信                    │
│  答案:格式→语义→安全三层验证,失败走修正路径  │
├────────────────────────────────────────────┤
│  ③ 知识沉淀                                │
│  问题:经验能否复用                         │
│  答案:捕获→结构化→存储→索引→复用           │
├────────────────────────────────────────────┤
│  ④ 输出约束                                │
│  问题:输出格式对吗                         │
│  答案:Prompt→Schema→代码三层约束,兜底降级  │
└────────────────────────────────────────────┘

四根缰绳合在一起,不是为了"控制"模型,
而是为了让人与模型协作时,
系统是可预测、可维护、可改进的。

Harness 不是框架,不是工具库,是一套方法论。它的核心不是"阻止模型做错",而是让正确的行为更容易发生。四根缰绳分别管了模型的输入、处理、输出、成长——它们不是技术债,而是 Agent 系统走向生产环境的必修课。

💬 评论

加载中...
请友善发言