第1章 从 Prompt 到 Harness — AI 工程化的三次范式跃迁

“不是教AI说话,也不是给AI看信息,而是给AI搭一个标准化的工作台。”


1.1 引言:AI编程的三次革命

1.1.1 2023年:ChatGPT元年与Prompt Engineering的诞生

2022年11月30日,OpenAI发布了ChatGPT。这个产品像一颗石子投入平静的湖面,激起了整个人工智能行业的巨浪。在短短两个月内,ChatGPT的用户数突破了一亿,成为人类历史上增长最快的消费级应用。

但对于软件工程师而言,ChatGPT的意义远不止于一个聊天机器人。它第一次让我们看到了一个令人震撼的可能性:自然语言可以成为编程语言的高层抽象

在ChatGPT发布之前,软件工程师与计算机的交互方式几乎只有一种——编写代码。无论是Python的简洁优雅,还是C++的底层控制,本质上都是人类将思维转化为形式化的指令序列。这个过程需要严格的语法、精确的类型定义、对算法复杂度的深入理解。

ChatGPT改变了这一切。工程师第一次可以用自然语言描述需求,让AI生成代码:

请用Python写一个函数,输入一个字符串列表,返回按长度排序后的结果,
长度相同的按字母顺序排序。

AI几乎瞬间就能给出正确的实现:

def sort_strings(strings: list[str]) -> list[str]:
    return sorted(strings, key=lambda s: (len(s), s))

这个看似简单的交互,开启了一个全新的工程领域——Prompt Engineering(提示词工程)

Prompt Engineering的核心问题是:如何向AI表达需求,才能获得最好的输出?

这听起来像是一个语言学问题,但实际上是一个深刻的信息论问题。Shannon在1948年提出的信息论告诉我们,信息的传递受到信道容量和噪声的限制。在Prompt Engineering中,"信道"是自然语言,"噪声"是语言的模糊性和歧义性。

早期的Prompt Engineering实践者们迅速发现了一系列有效的模式:

Zero-shot Prompting(零样本提示):直接描述任务,不提供示例。

将以下英文翻译为中文:The quick brown fox jumps over the lazy dog.

Few-shot Prompting(少样本提示):提供几个输入-输出示例。

将以下文本分类为"正面"或"负面":

示例1:
文本:"这部电影太棒了!"
分类:正面

示例2:
文本:"服务态度很差。"
分类:负面

请分类以下文本:
文本:"性价比还行,就是位置有点偏。"
分类:

Chain-of-Thought(思维链):要求AI展示推理过程。

问题:一个商店有120个苹果,上午卖了40%,下午又进了80个,
现在有多少个苹果?

请一步一步思考,展示你的计算过程。

这些技术让AI的输出质量显著提升,但它们都有一个共同的局限:AI只是一个"回答机器"。它接收输入,产出输出,然后等待下一次输入。AI没有记忆、没有工具、没有自主行动的能力。

1.1.2 2025年:从RAG到Agentic AI,Context Engineering崛起

2024年到2025年,AI领域发生了两个关键变化:

  1. RAG(Retrieval-Augmented Generation,检索增强生成)技术的成熟
  2. AI Agent(智能体)概念的兴起

RAG解决了LLM的一个根本性局限:知识截止。当你问ChatGPT"今天的天气怎么样",它无法回答,因为它的训练数据有截止日期。RAG通过引入外部检索机制,让AI可以"查阅"实时信息:

查询

相关文档

文档+问题

用户提问

检索器

知识库

大语言模型

生成回答

RAG的成功让工程师们意识到:给AI看什么信息,比怎么问AI更重要。这个认知催生了Context Engineering(上下文工程)

Context Engineering不再局限于"如何写好一个提示词",而是关注"如何为AI构建一个完整的信息环境":

  • 知识管理:如何组织、索引、更新企业知识库
  • 检索优化:如何找到最相关的信息片段
  • 上下文窗口管理:如何在有限的token预算内最大化信息价值
  • 多模态融合:如何将文本、图像、代码、数据整合为统一的上下文

与此同时,AI Agent的概念开始从学术论文走向工程实践。与传统的"问答式"AI不同,Agent具备以下能力:

  • 工具使用:可以调用API、执行代码、操作数据库
  • 规划能力:可以将复杂任务分解为子任务
  • 记忆系统:可以记住之前的对话和操作
  • 自主行动:可以根据目标主动采取行动,而非被动等待输入
# 2025年的典型Agent架构
class SimpleAgent:
    def __init__(self, llm, tools, memory):
        self.llm = llm
        self.tools = tools  # Agent可以使用的工具
        self.memory = memory  # Agent的记忆系统
    
    def run(self, task: str) -> str:
        # ReAct模式:推理→行动→观察→循环
        while True:
            # 1. 推理:基于上下文决定下一步
            context = self.build_context(task)
            thought = self.llm.generate(context)
            
            # 2. 行动:执行工具调用
            if thought.has_tool_call():
                result = self.tools.execute(thought.tool_call)
                self.memory.add("observation", result)
            else:
                # 3. 完成:返回最终结果
                return thought.final_answer

Agent的出现让Context Engineering变得更加复杂和重要。Agent不仅需要"看到"相关信息,还需要:

  • 动态上下文:随着任务的推进,上下文需要不断更新
  • 工具上下文:Agent需要知道有哪些工具可用,每个工具的功能和参数
  • 历史上下文:Agent需要记住之前的操作和结果
  • 环境上下文:Agent需要了解当前系统的状态

1.1.3 2026年:Harness Engineering — 给AI Agent套上缰绳

到了2026年,一个令人不安的现象开始浮现:

AI Agent的能力越来越强,但它们也越来越难以控制。

一个典型的场景是这样的:你让一个AI Agent重构一段代码。Agent非常"积极"地完成了任务——它不仅重构了你指定的代码,还"自作主张"地修改了周围的架构,引入了一个新的设计模式,删除了它认为"不必要"的错误处理,甚至改变了API的接口签名。

从技术角度看,Agent做的每一件事都"有道理"。但从工程角度看,这是一场灾难:

  • 它违反了团队的架构规范
  • 它引入的变更影响了其他12个依赖这个API的服务
  • 它删除的错误处理其实是为了处理一个已知的边界情况
  • 它的设计模式选择虽然优雅,但与项目现有的代码风格不一致

这就是Harness Engineering要解决的核心问题。

Harness这个词来源于英语,原意是"马具"——套在马身上的缰绳、鞍具和笼头。一匹好马需要好的马具,不是因为马不好,而是因为马的力量越大,越需要精确的引导和控制。

**Harness Engineering(驾驭工程)**的核心定义是:

为AI Agent构建一个标准化的工作环境,通过结构化知识、自动化约束、可观测性、自修复机制和多Agent协作,确保Agent在发挥最大能力的同时,始终在人类设定的边界内工作。

用一个简洁的公式表达:

Harness = 知识系统 + 架构约束 + 可观测性 + 自修复 + 互审机制

1.1.4 为什么每次范式跃迁都不可避免?

回顾这三次范式跃迁,我们可以发现一个清晰的逻辑链条:

2026: Harness Engineering

2025: Context Engineering

2023: Prompt Engineering

指令优化到极限
但AI仍然犯错

信息优化到极限
但AI仍然失控

怎么跟AI说话

优化指令的表达方式

给AI看什么信息

优化AI的信息环境

构建什么环境让AI工作

优化AI的工作系统

每次跃迁的根本原因是上一代范式的天花板:

维度 Prompt Engineering Context Engineering Harness Engineering
核心问题 如何表达需求 如何提供信息 如何控制行为
优化对象 输入(Prompt) 上下文(Context) 环境(Environment)
反馈机制 无(开环) 有限(半闭环) 完整(闭环)
AI角色 回答机器 知识处理器 自主代理
人类角色 提问者 信息管理员 系统架构师
控制方式 语言控制 信息控制 系统控制
失败模式 幻觉、误解 信息过载、遗漏 越界、失控

Prompt Engineering的天花板是语言的模糊性。无论你怎么优化提示词,自然语言本身就有歧义。同一句话可以有多种理解,AI可能选择了你没有想到的那一种。

Context Engineering的天花板是控制力的缺失。你可以给AI提供完美的信息,但你无法保证AI会按照你期望的方式使用这些信息。信息再多,也只是"建议",不是"约束"。

Harness Engineering通过将人类规范转化为机器可执行的规则和机制,从根本上解决了控制力问题。它不是"告诉AI应该怎么做",而是"构建一个环境,让AI只能按照正确的方式做"。

这就像是从"告诉孩子不要碰热水"(Prompt),到"把热水壶放在孩子够不到的地方"(Context),再到"给热水壶安装防烫保护装置"(Harness)的演进。

1.1.5 三个时代的时间线

2022 11月 ChatGPT发布 2023 3月 GPT-4发布 6月 Prompt Engineering成为热门话题 9月 首批企业级Prompt工程实践 2024 2月 RAG技术成熟 6月 AI Agent概念兴起 10月 Context Engineering概念提出 2025 3月 Agentic AI进入生产环境 8月 Agent失控事件频发 12月 Harness Engineering概念形成 2026 3月 Harness Engineering框架发布 6月 企业级Harness平台涌现 AI工程化演进时间线

1.2 Prompt Engineering:与AI对话的艺术

1.2.1 理论基础:信息论视角下的提示词工程

要深入理解Prompt Engineering,我们需要回到信息论的基本概念。

Shannon信息熵度量了一个随机变量的不确定性:

H(X) = -Σ p(x) log₂ p(x)

在Prompt Engineering中,我们可以将AI的输出看作一个随机变量Y,它受到Prompt(X)的条件约束。我们的目标是:

最小化 P(Y|X) 的条件熵 H(Y|X)

也就是说,给定Prompt X之后,AI输出Y的不确定性应该尽可能小。一个好的Prompt应该让AI"没有多少选择余地"——它应该清楚地知道你想要什么。

// 信息熵计算器:评估Prompt的信息效率
interface TokenProbability {
  token: string;
  probability: number;
}

class PromptEntropyCalculator {
  /**
   * 计算一组token分布的信息熵
   * 熵越低,说明分布越集中,Prompt越精确
   */
  static calculateEntropy(distribution: TokenProbability[]): number {
    let entropy = 0;
    for (const { probability } of distribution) {
      if (probability > 0) {
        entropy -= probability * Math.log2(probability);
      }
    }
    return entropy;
  }

  /**
   * 评估Prompt质量
   * 返回 0-100 分,分数越高说明Prompt越精确
   */
  static evaluatePromptQuality(
    promptEntropy: number,      // Prompt本身的信息熵
    outputEntropy: number,      // 输出的条件熵
    maxEntropy: number = 15     // 最大可能熵(词汇表大小决定)
  ): number {
    // 信息增益 = 输入熵 - 输出熵
    const informationGain = promptEntropy - outputEntropy;
    // 归一化到 0-100
    const score = Math.max(0, Math.min(100, 
      (informationGain / maxEntropy) * 100
    ));
    return Math.round(score);
  }
}

// 使用示例
const distribution: TokenProbability[] = [
  { token: "def", probability: 0.35 },
  { token: "class", probability: 0.25 },
  { token: "function", probability: 0.15 },
  { token: "import", probability: 0.10 },
  { token: "other", probability: 0.15 },
];

const entropy = PromptEntropyCalculator.calculateEntropy(distribution);
console.log(`信息熵: ${entropy.toFixed(2)} bits`);
// 输出: 信息熵: 2.10 bits
import math
from dataclasses import dataclass
from typing import List

@dataclass
class TokenProbability:
    token: str
    probability: float

class PromptEntropyCalculator:
    """信息熵计算器:评估Prompt的信息效率"""
    
    @staticmethod
    def calculate_entropy(distribution: List[TokenProbability]) -> float:
        """
        计算一组token分布的信息熵
        熵越低,说明分布越集中,Prompt越精确
        """
        entropy = 0.0
        for item in distribution:
            if item.probability > 0:
                entropy -= item.probability * math.log2(item.probability)
        return entropy
    
    @staticmethod
    def evaluate_prompt_quality(
        prompt_entropy: float,
        output_entropy: float,
        max_entropy: float = 15.0
    ) -> int:
        """
        评估Prompt质量
        返回 0-100 分,分数越高说明Prompt越精确
        """
        information_gain = prompt_entropy - output_entropy
        score = max(0, min(100, (information_gain / max_entropy) * 100))
        return round(score)

# 使用示例
distribution = [
    TokenProbability("def", 0.35),
    TokenProbability("class", 0.25),
    TokenProbability("function", 0.15),
    TokenProbability("import", 0.10),
    TokenProbability("other", 0.15),
]

entropy = PromptEntropyCalculator.calculate_entropy(distribution)
print(f"信息熵: {entropy:.2f} bits")
# 输出: 信息熵: 2.10 bits

1.2.2 核心技术全景

Zero-shot Prompting:最简单直接的方式,不提供任何示例。

// Zero-shot: 直接描述任务
const zeroShotPrompt = `
请将以下JSON数据转换为TypeScript接口定义:

{
  "name": "string",
  "age": "number", 
  "email": "string",
  "isActive": "boolean"
}
`;

Few-shot Prompting:提供几个输入-输出示例,让AI学习模式。

// Few-shot: 提供示例
const fewShotPrompt = `
请将JSON Schema转换为TypeScript接口。

示例1:
输入: {"id": "number", "title": "string"}
输出: interface Item { id: number; title: string; }

示例2:
输入: {"userId": "string", "count": "number", "tags": "string[]"}
输出: interface Stats { userId: string; count: number; tags: string[]; }

请转换:
输入: {"orderId": "string", "amount": "number", "status": "string", "items": "object[]"}
输出:
`;

Chain-of-Thought(CoT):要求AI展示推理过程。

// Chain-of-Thought: 引导逐步推理
const cotPrompt = `
请分析以下代码的时间复杂度,一步一步思考:

function findDuplicates(arr: number[]): number[] {
  const seen = new Set<number>();
  const duplicates = new Set<number>();
  for (const num of arr) {
    if (seen.has(num)) {
      duplicates.add(num);
    }
    seen.add(num);
  }
  return Array.from(duplicates);
}

请按以下步骤分析:
1. 识别主要的数据结构
2. 分析循环结构
3. 分析每个操作的时间复杂度
4. 给出总体时间复杂度和空间复杂度
`;

Self-Consistency(自一致性):多次生成,取多数结果。

// Self-Consistency: 多次生成取共识
async function selfConsistentGenerate(
  prompt: string,
  generateFn: (prompt: string) => Promise<string>,
  n: number = 5
): Promise<string> {
  // 并行生成多个结果
  const results = await Promise.all(
    Array.from({ length: n }, () => generateFn(prompt))
  );
  
  // 对结果进行归一化
  const normalized = results.map(r => r.trim().toLowerCase());
  
  // 统计频率
  const frequency = new Map<string, number>();
  for (const result of normalized) {
    frequency.set(result, (frequency.get(result) || 0) + 1);
  }
  
  // 返回频率最高的结果
  let bestResult = '';
  let maxCount = 0;
  for (const [result, count] of frequency) {
    if (count > maxCount) {
      maxCount = count;
      bestResult = result;
    }
  }
  
  console.log(`自一致性: ${maxCount}/${n} 个结果一致`);
  return bestResult;
}

1.2.3 真实案例分析

案例1:某电商平台的AI客服Prompt优化

某电商平台的AI客服系统最初使用简单的Prompt:

你是客服助手,请回答用户的问题。

这个Prompt的问题显而易见——AI不知道产品信息、不了解退换货政策、不清楚物流状态。结果:

  • 回答准确率:62%
  • 用户满意度:3.2/5
  • 人工转接率:38%

经过系统性的Prompt优化:

你是一位专业的电商客服助手。

## 你的职责
- 解答用户关于商品、订单、物流、售后的问题
- 提供友好的购物建议
- 引导用户完成购买流程

## 你的限制
- 如果不确定答案,诚实地告诉用户并建议联系人工客服
- 不提供竞品比较或贬低其他品牌
- 不承诺超出公司政策的优惠

## 回答格式
- 首先直接回答用户的问题
- 然后提供相关的补充信息
- 最后询问是否还有其他问题

## 语气
- 友好、专业、简洁
- 使用"您"而非"你"
- 适当使用emoji增加亲和力

优化后的效果:

指标 优化前 优化后 提升
回答准确率 62% 87% +40%
用户满意度 3.2/5 4.3/5 +34%
人工转接率 38% 15% -61%
平均处理时间 4.5分钟 2.1分钟 -53%

案例2:代码生成场景下的Prompt工程最佳实践

在代码生成场景中,Prompt Engineering的效果差异更为明显。

差的Prompt

写一个用户认证模块

好的Prompt

请用TypeScript实现一个用户认证模块,要求:

1. 技术栈:Express.js + JWT + bcrypt
2. 功能:
   - 用户注册(邮箱+密码)
   - 用户登录(返回JWT token)
   - Token验证中间件
   - 密码修改

3. 安全要求:
   - 密码使用bcrypt哈希(12轮)
   - JWT有效期24小时
   - 输入验证(使用zod)
   - 防止暴力破解(5次失败锁定15分钟)

4. 代码规范:
   - 使用async/await
   - 完整的错误处理
   - TypeScript strict模式
   - 导出类型定义

5. 项目结构:
   - auth.controller.ts(路由处理)
   - auth.service.ts(业务逻辑)
   - auth.middleware.ts(中间件)
   - auth.types.ts(类型定义)

后者生成的代码质量显著更高,几乎可以直接使用。

1.2.4 Prompt Engineering的天花板

尽管Prompt Engineering取得了显著的成果,但它有三个根本性的局限:

1. 上下文窗口限制

即使是128K甚至1M的上下文窗口,也远远无法容纳一个真实软件项目的全部信息。一个中等规模的项目可能有:

  • 100万行代码(约200MB纯文本)
  • 500页技术文档
  • 1000个API端点
  • 50个微服务的架构信息

这些信息不可能全部塞进一个Prompt中。

2. 幻觉问题的根本原因

LLM的本质是一个概率模型,它根据训练数据中的统计规律生成文本。当Prompt提供的信息不足以约束输出时,LLM会"编造"看起来合理但实际上不正确的信息。

从信息论的角度看,这是因为 H(Y|X) > 0——给定Prompt之后,输出仍然有不确定性。只要这种不确定性存在,幻觉就不可能完全消除。

3. 无法控制Agent的行为边界

当AI从"回答机器"进化为"自主Agent"时,Prompt Engineering的局限变得更加明显。你可以告诉Agent"不要修改公共API",但这只是一个建议,不是一个约束。Agent可能会在"优化代码"的过程中不小心改变了API签名。

这就像是在一个没有护栏的悬崖边开车——你可以告诉司机"小心别掉下去",但真正安全的方式是安装护栏。

1.2.5 手把手实践:构建一个多轮对话的Prompt优化系统

让我们构建一个实际的Prompt优化系统。这个系统会分析用户的原始Prompt,自动优化它,并跟踪优化效果。

// prompt-optimizer.ts
interface PromptAnalysis {
  clarity: number;        // 清晰度 0-100
  specificity: number;    // 具体性 0-100
  completeness: number;   // 完整性 0-100
  structure: number;      // 结构化程度 0-100
  overallScore: number;   // 综合评分 0-100
  suggestions: string[];  // 优化建议
}

interface OptimizedPrompt {
  original: string;
  optimized: string;
  analysis: PromptAnalysis;
  improvements: string[];
}

class PromptOptimizer {
  // 检测Prompt中的关键要素
  private static readonly ELEMENTS = {
    role: /你是一位|作为|扮演|you are|act as/i,
    task: /请|请帮我|帮我|please|write|create|generate/i,
    format: /格式|输出|返回|format|output|return|json|markdown/i,
    constraint: /不要|禁止|必须|限制|要求|don't|must|should|require/i,
    example: /例如|示例|比如|example|e\.g\.|such as/i,
    context: /背景|场景|项目|技术栈|background|context|project/i,
  };

  /**
   * 分析Prompt质量
   */
  analyze(prompt: string): PromptAnalysis {
    const scores: Record<string, number> = {};
    const suggestions: string[] = [];

    // 清晰度:检查是否有模糊词
    const vagueWords = ['一些', '某些', '大概', '可能', '比较好', 'some', 'maybe', 'kind of'];
    const vagueCount = vagueWords.filter(w => prompt.includes(w)).length;
    scores.clarity = Math.max(0, 100 - vagueCount * 15);
    if (vagueCount > 0) {
      suggestions.push(`发现 ${vagueCount} 个模糊词,建议替换为精确描述`);
    }

    // 具体性:检查是否包含具体参数
    const hasNumbers = /\d+/.test(prompt);
    const hasCodeTerms = /function|class|interface|API|endpoint|database/i.test(prompt);
    const hasTechStack = /React|Python|TypeScript|Node\.js|PostgreSQL/i.test(prompt);
    scores.specificity = [hasNumbers, hasCodeTerms, hasTechStack]
      .filter(Boolean).length * 30 + 10;
    if (!hasNumbers) suggestions.push('建议添加具体的数值参数(如数量、大小限制)');
    if (!hasTechStack) suggestions.push('建议明确指定技术栈');

    // 完整性:检查关键要素
    const elementCount = Object.entries(PromptOptimizer.ELEMENTS)
      .filter(([, regex]) => regex.test(prompt)).length;
    scores.completeness = Math.round((elementCount / 6) * 100);
    
    const missing = Object.entries(PromptOptimizer.ELEMENTS)
      .filter(([, regex]) => !regex.test(prompt))
      .map(([name]) => name);
    if (missing.length > 0) {
      suggestions.push(`缺少以下要素: ${missing.join(', ')}`);
    }

    // 结构化程度:检查是否使用了标题、列表等
    const hasHeaders = /^#+\s/m.test(prompt) || /^\d+\.\s/m.test(prompt);
    const hasLists = /^[-*]\s/m.test(prompt);
    const hasSections = prompt.split('\n\n').length > 2;
    scores.structure = [hasHeaders, hasLists, hasSections]
      .filter(Boolean).length * 30 + 10;
    if (!hasHeaders) suggestions.push('建议使用标题(# 或数字编号)组织内容');
    if (!hasLists) suggestions.push('建议使用列表组织要求和条件');

    // 综合评分
    scores.overallScore = Math.round(
      scores.clarity * 0.25 +
      scores.specificity * 0.25 +
      scores.completeness * 0.30 +
      scores.structure * 0.20
    );

    return {
      clarity: scores.clarity,
      specificity: scores.specificity,
      completeness: scores.completeness,
      structure: scores.structure,
      overallScore: scores.overallScore,
      suggestions,
    };
  }

  /**
   * 优化Prompt
   */
  optimize(original: string): OptimizedPrompt {
    const analysis = this.analyze(original);
    const improvements: string[] = [];
    let optimized = original;

    // 1. 添加角色定义(如果缺失)
    if (!PromptOptimizer.ELEMENTS.role.test(optimized)) {
      optimized = `你是一位资深软件工程师,擅长代码设计、架构和最佳实践。\n\n${optimized}`;
      improvements.push('添加了角色定义');
    }

    // 2. 添加结构化标记(如果缺失)
    if (!PromptOptimizer.ELEMENTS.format.test(optimized)) {
      optimized += '\n\n## 输出要求\n- 使用Markdown格式\n- 包含代码注释\n- 提供使用示例';
      improvements.push('添加了输出格式要求');
    }

    // 3. 添加约束条件(如果缺失)
    if (!PromptOptimizer.ELEMENTS.constraint.test(optimized)) {
      optimized += '\n\n## 约束条件\n- 遵循SOLID原则\n- 包含错误处理\n- 使用TypeScript strict模式';
      improvements.push('添加了约束条件');
    }

    // 4. 添加上下文(如果缺失)
    if (!PromptOptimizer.ELEMENTS.context.test(optimized)) {
      optimized = `## 项目背景\n技术栈:TypeScript + Node.js + Express\n\n${optimized}`;
      improvements.push('添加了项目背景');
    }

    return { original, optimized, analysis, improvements };
  }
}

// 使用示例
const optimizer = new PromptOptimizer();

const original = "写一个用户认证模块";
const result = optimizer.optimize(original);

console.log(`原始Prompt评分: ${result.analysis.overallScore}/100`);
console.log(`优化建议:`, result.analysis.suggestions);
console.log(`\n优化后的Prompt:\n${result.optimized}`);
console.log(`\n改进项:`, result.improvements);
# prompt_optimizer.py
import re
from dataclasses import dataclass, field
from typing import Dict, List, Tuple

@dataclass
class PromptAnalysis:
    clarity: int = 0
    specificity: int = 0
    completeness: int = 0
    structure: int = 0
    overall_score: int = 0
    suggestions: List[str] = field(default_factory=list)

@dataclass
class OptimizedPrompt:
    original: str
    optimized: str
    analysis: PromptAnalysis
    improvements: List[str]

class PromptOptimizer:
    """Prompt优化器:分析并改进提示词质量"""
    
    ELEMENTS = {
        'role': re.compile(r'你是一位|作为|扮演|you are|act as', re.I),
        'task': re.compile(r'请|请帮我|帮我|please|write|create|generate', re.I),
        'format': re.compile(r'格式|输出|返回|format|output|return|json|markdown', re.I),
        'constraint': re.compile(r'不要|禁止|必须|限制|要求|don\'t|must|should|require', re.I),
        'example': re.compile(r'例如|示例|比如|example|e\.g\.|such as', re.I),
        'context': re.compile(r'背景|场景|项目|技术栈|background|context|project', re.I),
    }
    
    VAGUE_WORDS = ['一些', '某些', '大概', '可能', '比较好', 'some', 'maybe', 'kind of']
    
    def analyze(self, prompt: str) -> PromptAnalysis:
        """分析Prompt质量"""
        analysis = PromptAnalysis()
        
        # 清晰度
        vague_count = sum(1 for w in self.VAGUE_WORDS if w in prompt)
        analysis.clarity = max(0, 100 - vague_count * 15)
        if vague_count > 0:
            analysis.suggestions.append(f'发现 {vague_count} 个模糊词,建议替换为精确描述')
        
        # 具体性
        checks = [
            bool(re.search(r'\d+', prompt)),
            bool(re.search(r'function|class|interface|API|endpoint|database', prompt, re.I)),
            bool(re.search(r'React|Python|TypeScript|Node\.js|PostgreSQL', prompt, re.I)),
        ]
        analysis.specificity = sum(checks) * 30 + 10
        if not checks[0]:
            analysis.suggestions.append('建议添加具体的数值参数')
        if not checks[2]:
            analysis.suggestions.append('建议明确指定技术栈')
        
        # 完整性
        found = sum(1 for regex in self.ELEMENTS.values() if regex.search(prompt))
        analysis.completeness = round((found / len(self.ELEMENTS)) * 100)
        missing = [name for name, regex in self.ELEMENTS.items() 
                   if not regex.search(prompt)]
        if missing:
            analysis.suggestions.append(f'缺少以下要素: {", ".join(missing)}')
        
        # 结构化
        struct_checks = [
            bool(re.search(r'^#+\s', prompt, re.M)),
            bool(re.search(r'^[-*]\s', prompt, re.M)),
            len(prompt.split('\n\n')) > 2,
        ]
        analysis.structure = sum(struct_checks) * 30 + 10
        
        # 综合评分
        analysis.overall_score = round(
            analysis.clarity * 0.25 +
            analysis.specificity * 0.25 +
            analysis.completeness * 0.30 +
            analysis.structure * 0.20
        )
        
        return analysis
    
    def optimize(self, original: str) -> OptimizedPrompt:
        """优化Prompt"""
        analysis = self.analyze(original)
        improvements: List[str] = []
        optimized = original
        
        if not self.ELEMENTS['role'].search(optimized):
            optimized = f'你是一位资深软件工程师,擅长代码设计、架构和最佳实践。\n\n{optimized}'
            improvements.append('添加了角色定义')
        
        if not self.ELEMENTS['format'].search(optimized):
            optimized += '\n\n## 输出要求\n- 使用Markdown格式\n- 包含代码注释\n- 提供使用示例'
            improvements.append('添加了输出格式要求')
        
        if not self.ELEMENTS['constraint'].search(optimized):
            optimized += '\n\n## 约束条件\n- 遵循SOLID原则\n- 包含错误处理\n- 使用TypeScript strict模式'
            improvements.append('添加了约束条件')
        
        return OptimizedPrompt(original, optimized, analysis, improvements)


# 使用示例
if __name__ == '__main__':
    optimizer = PromptOptimizer()
    result = optimizer.optimize("写一个用户认证模块")
    
    print(f"原始Prompt评分: {result.analysis.overall_score}/100")
    print(f"优化建议: {result.analysis.suggestions}")
    print(f"\n优化后的Prompt:\n{result.optimized}")
    print(f"\n改进项: {result.improvements}")

1.3 Context Engineering:为AI构建信息世界

1.3.1 从"说什么"到"看什么"的范式转变

如果说Prompt Engineering关注的是"怎么跟AI说话",那么Context Engineering关注的是"给AI看什么信息"。

这个转变看似微小,实则深刻。它反映了我们对AI系统理解的一个根本性进步:

AI的输出质量不仅取决于你问了什么,更取决于它"看到"了什么。

用一个类比来理解:想象你是一个外科医生,你需要做一个复杂的手术。

  • Prompt Engineering 就像是在手术前告诉医生"请做好这个手术"——你需要用精确的语言描述手术要求
  • Context Engineering 就像是在手术前准备好所有的影像资料、病历记录、检验报告——你需要确保医生拥有所有必要的信息

显然,后者更重要。一个拥有完整病历但收到模糊指令的医生,很可能比一个只听到精确指令但对病人一无所知的医生做得更好。

Context Engineering的核心范畴包括:

  1. 知识管理:组织、索引、更新AI可以访问的知识
  2. 检索策略:在海量信息中找到最相关的片段
  3. 上下文组装:将多个信息源整合为连贯的上下文
  4. 上下文压缩:在有限的token预算内最大化信息价值
  5. 上下文更新:随着任务推进动态更新上下文

1.3.2 核心技术栈

RAG(检索增强生成)深度解析

RAG是Context Engineering最核心的技术。一个完整的RAG系统包含以下组件:

生成阶段

检索阶段

索引阶段

原始文档

文档解析

文本分块

向量化

向量数据库

用户查询

查询向量化

向量检索

重排序

上下文组装

Prompt构建

LLM生成

最终回答

文本分块策略是RAG的第一个关键决策:

// text-chunker.ts
interface Chunk {
  id: string;
  content: string;
  metadata: {
    source: string;
    startIndex: number;
    endIndex: number;
    section?: string;
    level?: number;
  };
  embedding?: number[];
}

interface ChunkingOptions {
  chunkSize: number;       // 每块的最大字符数
  overlap: number;         // 块之间的重叠字符数
  strategy: 'fixed' | 'sentence' | 'paragraph' | 'semantic';
  respectHeaders: boolean; // 是否尊重Markdown标题
}

class TextChunker {
  private options: Required<ChunkingOptions>;

  constructor(options: Partial<ChunkingOptions> = {}) {
    this.options = {
      chunkSize: options.chunkSize ?? 1000,
      overlap: options.overlap ?? 200,
      strategy: options.strategy ?? 'paragraph',
      respectHeaders: options.respectHeaders ?? true,
    };
  }

  /**
   * 将文档分割为语义块
   */
  chunk(text: string, source: string = 'unknown'): Chunk[] {
    switch (this.options.strategy) {
      case 'fixed':
        return this.fixedChunk(text, source);
      case 'sentence':
        return this.sentenceChunk(text, source);
      case 'paragraph':
        return this.paragraphChunk(text, source);
      case 'semantic':
        return this.semanticChunk(text, source);
      default:
        return this.paragraphChunk(text, source);
    }
  }

  /**
   * 固定大小分块(带重叠)
   */
  private fixedChunk(text: string, source: string): Chunk[] {
    const chunks: Chunk[] = [];
    const { chunkSize, overlap } = this.options;
    
    let start = 0;
    let chunkIndex = 0;
    
    while (start < text.length) {
      const end = Math.min(start + chunkSize, text.length);
      const content = text.slice(start, end);
      
      chunks.push({
        id: `${source}-chunk-${chunkIndex}`,
        content,
        metadata: {
          source,
          startIndex: start,
          endIndex: end,
        },
      });
      
      start += chunkSize - overlap;
      chunkIndex++;
    }
    
    return chunks;
  }

  /**
   * 按段落分块(尊重自然边界)
   */
  private paragraphChunk(text: string, source: string): Chunk[] {
    const chunks: Chunk[] = [];
    const paragraphs = text.split(/\n\n+/);
    const { chunkSize } = this.options;
    
    let currentContent = '';
    let startIndex = 0;
    let chunkIndex = 0;
    let currentSection = '';
    
    for (const paragraph of paragraphs) {
      // 检测是否是标题
      const headerMatch = paragraph.match(/^(#{1,6})\s+(.+)/);
      if (headerMatch) {
        currentSection = headerMatch[2];
      }
      
      // 如果当前块加上新段落超过大小限制,先保存当前块
      if (currentContent.length + paragraph.length > chunkSize && currentContent) {
        chunks.push({
          id: `${source}-chunk-${chunkIndex}`,
          content: currentContent.trim(),
          metadata: {
            source,
            startIndex,
            endIndex: startIndex + currentContent.length,
            section: currentSection,
          },
        });
        
        startIndex += currentContent.length;
        currentContent = '';
        chunkIndex++;
      }
      
      currentContent += paragraph + '\n\n';
    }
    
    // 保存最后一块
    if (currentContent.trim()) {
      chunks.push({
        id: `${source}-chunk-${chunkIndex}`,
        content: currentContent.trim(),
        metadata: {
          source,
          startIndex,
          endIndex: startIndex + currentContent.length,
          section: currentSection,
        },
      });
    }
    
    return chunks;
  }

  /**
   * 按句子分块
   */
  private sentenceChunk(text: string, source: string): Chunk[] {
    // 中英文句子分割
    const sentences = text.split(/(?<=[。!?.!?])\s+/);
    const chunks: Chunk[] = [];
    const { chunkSize } = this.options;
    
    let currentContent = '';
    let startIndex = 0;
    let chunkIndex = 0;
    
    for (const sentence of sentences) {
      if (currentContent.length + sentence.length > chunkSize && currentContent) {
        chunks.push({
          id: `${source}-chunk-${chunkIndex}`,
          content: currentContent.trim(),
          metadata: { source, startIndex, endIndex: startIndex + currentContent.length },
        });
        startIndex += currentContent.length;
        currentContent = '';
        chunkIndex++;
      }
      currentContent += sentence + ' ';
    }
    
    if (currentContent.trim()) {
      chunks.push({
        id: `${source}-chunk-${chunkIndex}`,
        content: currentContent.trim(),
        metadata: { source, startIndex, endIndex: startIndex + currentContent.length },
      });
    }
    
    return chunks;
  }

  /**
   * 语义分块(基于内容相似度)
   */
  private semanticChunk(text: string, source: string): Chunk[] {
    // 简化版:先按段落分割,然后合并语义相近的段落
    const paragraphs = text.split(/\n\n+/).filter(p => p.trim());
    const chunks: Chunk[] = [];
    const { chunkSize } = this.options;
    
    let currentContent = '';
    let chunkIndex = 0;
    
    for (let i = 0; i < paragraphs.length; i++) {
      const paragraph = paragraphs[i];
      
      if (currentContent.length + paragraph.length > chunkSize && currentContent) {
        chunks.push({
          id: `${source}-chunk-${chunkIndex}`,
          content: currentContent.trim(),
          metadata: { source, startIndex: 0, endIndex: currentContent.length },
        });
        currentContent = '';
        chunkIndex++;
      }
      
      currentContent += paragraph + '\n\n';
    }
    
    if (currentContent.trim()) {
      chunks.push({
        id: `${source}-chunk-${chunkIndex}`,
        content: currentContent.trim(),
        metadata: { source, startIndex: 0, endIndex: currentContent.length },
      });
    }
    
    return chunks;
  }
}

// 使用示例
const chunker = new TextChunker({ 
  chunkSize: 500, 
  overlap: 100, 
  strategy: 'paragraph' 
});

const document = `# TypeScript 最佳实践

## 类型安全
使用 strict 模式可以获得更好的类型检查...

## 异步编程
使用 async/await 替代 Promise.then() 链...

## 错误处理
使用自定义错误类型提供更丰富的错误信息...`;

const chunks = chunker.chunk(document, 'typescript-best-practices');
console.log(`分块数量: ${chunks.length}`);
chunks.forEach(c => console.log(`[${c.id}] ${c.content.length} chars`));

向量数据库选型与优化

向量数据库是RAG系统的核心组件。以下是主流向量数据库的对比:

数据库 索引算法 最大规模 特色功能 适用场景
Pinecone HNSW 数十亿 全托管、低延迟 云原生应用
Weaviate HNSW+倒排 数十亿 GraphQL API、多模态 知识图谱
Chroma HNSW 百万级 轻量、嵌入式 原型开发
PGVector IVFFlat/HNSW 百万级 PostgreSQL集成 已有PG生态
Milvus 多种 十亿级 分布式、GPU加速 大规模生产
# vector_store.py - 向量存储抽象层
import numpy as np
from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import List, Optional, Dict, Any
import hashlib

@dataclass
class VectorDocument:
    """向量文档"""
    id: str
    content: str
    embedding: List[float]
    metadata: Dict[str, Any]
    score: float = 0.0

class VectorStore(ABC):
    """向量存储抽象基类"""
    
    @abstractmethod
    def add(self, documents: List[VectorDocument]) -> None:
        """添加文档"""
        pass
    
    @abstractmethod
    def search(
        self, 
        query_embedding: List[float], 
        top_k: int = 5,
        filters: Optional[Dict] = None
    ) -> List[VectorDocument]:
        """相似度搜索"""
        pass
    
    @abstractmethod
    def delete(self, ids: List[str]) -> None:
        """删除文档"""
        pass

class InMemoryVectorStore(VectorStore):
    """内存向量存储(适用于原型开发和小规模应用)"""
    
    def __init__(self, dimension: int = 1536):
        self.dimension = dimension
        self.documents: Dict[str, VectorDocument] = {}
    
    def add(self, documents: List[VectorDocument]) -> None:
        for doc in documents:
            self.documents[doc.id] = doc
    
    def search(
        self,
        query_embedding: List[float],
        top_k: int = 5,
        filters: Optional[Dict] = None
    ) -> List[VectorDocument]:
        query = np.array(query_embedding)
        results = []
        
        for doc in self.documents.values():
            # 过滤
            if filters:
                match = all(
                    doc.metadata.get(k) == v 
                    for k, v in filters.items()
                )
                if not match:
                    continue
            
            # 计算余弦相似度
            doc_vec = np.array(doc.embedding)
            similarity = np.dot(query, doc_vec) / (
                np.linalg.norm(query) * np.linalg.norm(doc_vec)
            )
            doc.score = float(similarity)
            results.append(doc)
        
        # 按相似度排序
        results.sort(key=lambda d: d.score, reverse=True)
        return results[:top_k]
    
    def delete(self, ids: List[str]) -> None:
        for doc_id in ids:
            self.documents.pop(doc_id, None)

class EmbeddingService:
    """Embedding服务(支持多种模型)"""
    
    def __init__(self, model: str = 'text-embedding-3-small'):
        self.model = model
        self.dimension = 1536 if 'small' in model else 3072
    
    def embed(self, texts: List[str]) -> List[List[float]]:
        """
        生成文本embedding
        实际使用时替换为真实API调用
        """
        # 模拟实现:使用简单的哈希生成伪embedding
        embeddings = []
        for text in texts:
            # 基于文本内容生成确定性伪向量
            h = hashlib.sha256(text.encode()).digest()
            seed = int.from_bytes(h[:4], 'big')
            rng = np.random.RandomState(seed)
            vec = rng.randn(self.dimension).tolist()
            # 归一化
            norm = np.linalg.norm(vec)
            vec = [v / norm for v in vec]
            embeddings.append(vec)
        return embeddings
    
    def embed_query(self, query: str) -> List[float]:
        """生成查询embedding"""
        return self.embed([query])[0]

# 使用示例
if __name__ == '__main__':
    store = InMemoryVectorStore()
    embedder = EmbeddingService()
    
    # 添加文档
    texts = [
        "TypeScript是JavaScript的超集,添加了类型系统",
        "Python是一种解释型、面向对象的高级编程语言",
        "Rust注重安全性和性能,特别适合系统编程",
    ]
    
    embeddings = embedder.embed(texts)
    docs = [
        VectorDocument(
            id=f"doc-{i}",
            content=text,
            embedding=emb,
            metadata={"language": "programming"}
        )
        for i, (text, emb) in enumerate(zip(texts, embeddings))
    ]
    store.add(docs)
    
    # 搜索
    query_emb = embedder.embed_query("什么是类型安全的编程语言?")
    results = store.search(query_emb, top_k=2)
    
    for r in results:
        print(f"[{r.score:.3f}] {r.content}")

1.3.3 知识图谱与GraphRAG

传统RAG的局限在于它是"扁平"的——它把文档切块、向量化,然后基于向量相似度检索。这种方式忽略了文档之间的关系

GraphRAG通过引入知识图谱,解决了这个问题。知识图谱以图结构组织信息:

  • 节点(Node):实体(人、概念、代码模块等)
  • 边(Edge):关系(属于、依赖、引用等)
  • 属性(Property):节点和边的附加信息

超集

编译为

使用

使用

基于

使用

运行时

TypeScript

JavaScript

React

Express

Next.js

Node.js

GraphRAG的优势在于:

  1. 多跳推理:可以从A出发,经过B到达C
  2. 关系感知:理解实体之间的关系类型
  3. 子图检索:返回的不是孤立的文本块,而是相关的知识子图
// graph-rag.ts
interface KnowledgeNode {
  id: string;
  type: string;        // 节点类型:concept, module, api, person
  label: string;       // 显示名称
  content: string;     // 详细内容
  properties: Record<string, any>;
  embedding?: number[];
}

interface KnowledgeEdge {
  source: string;      // 源节点ID
  target: string;      // 目标节点ID
  type: string;        // 关系类型:depends_on, implements, related_to
  weight: number;      // 权重 0-1
  properties: Record<string, any>;
}

interface SubGraph {
  nodes: KnowledgeNode[];
  edges: KnowledgeEdge[];
  rootId: string;      // 中心节点
  contextText: string;  // 拼接后的上下文文本
}

class KnowledgeGraph {
  private nodes = new Map<string, KnowledgeNode>();
  private edges: KnowledgeEdge[] = [];
  private adjacency = new Map<string, Set<string>>(); // 邻接表

  addNode(node: KnowledgeNode): void {
    this.nodes.set(node.id, node);
    if (!this.adjacency.has(node.id)) {
      this.adjacency.set(node.id, new Set());
    }
  }

  addEdge(edge: KnowledgeEdge): void {
    this.edges.push(edge);
    this.adjacency.get(edge.source)?.add(edge.target);
    this.adjacency.get(edge.target)?.add(edge.source); // 无向图
  }

  /**
   * 从指定节点出发,提取k-hop子图
   */
  extractSubGraph(rootId: string, hops: number = 2, maxNodes: number = 20): SubGraph {
    const visited = new Set<string>();
    const queue: Array<{ id: string; depth: number }> = [{ id: rootId, depth: 0 }];
    const subNodes: KnowledgeNode[] = [];
    const subEdges: KnowledgeEdge[] = [];

    while (queue.length > 0 && subNodes.length < maxNodes) {
      const { id, depth } = queue.shift()!;
      
      if (visited.has(id)) continue;
      visited.add(id);

      const node = this.nodes.get(id);
      if (node) {
        subNodes.push(node);
      }

      // 如果还没达到最大跳数,继续扩展
      if (depth < hops) {
        const neighbors = this.adjacency.get(id) || new Set();
        for (const neighborId of neighbors) {
          if (!visited.has(neighborId)) {
            queue.push({ id: neighborId, depth: depth + 1 });
          }
        }
      }
    }

    // 收集子图内的边
    const nodeIds = new Set(subNodes.map(n => n.id));
    for (const edge of this.edges) {
      if (nodeIds.has(edge.source) && nodeIds.has(edge.target)) {
        subEdges.push(edge);
      }
    }

    // 生成上下文文本
    const contextText = this.subGraphToContext(subNodes, subEdges);

    return { nodes: subNodes, edges: subEdges, rootId, contextText };
  }

  /**
   * 将子图转换为LLM可理解的文本
   */
  private subGraphToContext(nodes: KnowledgeNode[], edges: KnowledgeEdge[]): string {
    let text = '## 相关知识\n\n';
    
    // 节点信息
    text += '### 实体\n';
    for (const node of nodes) {
      text += `- **${node.label}** (${node.type}): ${node.content}\n`;
    }
    
    // 关系信息
    text += '\n### 关系\n';
    for (const edge of edges) {
      const source = this.nodes.get(edge.source)?.label || edge.source;
      const target = this.nodes.get(edge.target)?.label || edge.target;
      text += `- ${source} → [${edge.type}] → ${target}\n`;
    }
    
    return text;
  }

  /**
   * 基于向量相似度的图检索
   */
  semanticSearch(
    queryEmbedding: number[], 
    topK: number = 5
  ): KnowledgeNode[] {
    const scored: Array<{ node: KnowledgeNode; score: number }> = [];
    
    for (const node of this.nodes.values()) {
      if (!node.embedding) continue;
      
      // 余弦相似度
      const score = this.cosineSimilarity(queryEmbedding, node.embedding);
      scored.push({ node, score });
    }
    
    scored.sort((a, b) => b.score - a.score);
    return scored.slice(0, topK).map(s => s.node);
  }

  private cosineSimilarity(a: number[], b: number[]): number {
    let dot = 0, normA = 0, normB = 0;
    for (let i = 0; i < a.length; i++) {
      dot += a[i] * b[i];
      normA += a[i] * a[i];
      normB += b[i] * b[i];
    }
    return dot / (Math.sqrt(normA) * Math.sqrt(normB));
  }
}

// 使用示例
const graph = new KnowledgeGraph();

// 构建知识图谱
graph.addNode({
  id: 'typescript', type: 'concept', label: 'TypeScript',
  content: 'TypeScript是JavaScript的类型安全超集', properties: {}
});
graph.addNode({
  id: 'react', type: 'framework', label: 'React',
  content: 'React是用于构建用户界面的JavaScript库', properties: {}
});
graph.addNode({
  id: 'nextjs', type: 'framework', label: 'Next.js',
  content: 'Next.js是基于React的全栈Web框架', properties: {}
});

graph.addEdge({
  source: 'typescript', target: 'react',
  type: 'commonly_used_with', weight: 0.9, properties: {}
});
graph.addEdge({
  source: 'react', target: 'nextjs',
  type: 'foundation_of', weight: 0.95, properties: {}
});

// 提取子图
const subGraph = graph.extractSubGraph('nextjs', 2);
console.log(subGraph.contextText);

1.3.4 Context Engineering的局限

尽管Context Engineering比Prompt Engineering前进了一大步,但它仍然有三个关键局限:

1. 信息过载问题

当你可以给AI提供大量信息时,一个反直觉的现象出现了:信息越多,AI的表现不一定越好

这是因为LLM的注意力机制在处理超长上下文时会出现"注意力稀释"(attention dilution)。模型可能会:

  • 忽略重要的信息片段(被其他信息淹没)
  • 过度关注不相关的细节
  • 在不同信息片段之间产生混淆

研究表明,在128K token的上下文中,模型对位于中间部分的信息关注度显著低于开头和结尾(“U形注意力曲线”)。

2. 无法约束Agent的行为模式

Context Engineering可以提供完美的信息,但它无法保证Agent会按照你期望的方式行动。

一个经典的例子:你给一个代码生成Agent提供了完整的架构文档和编码规范,但Agent仍然可能:

  • 选择了一个你认为不合适的设计模式(因为它在训练数据中更常见)
  • 忽略了某个架构约束(因为它判断这个约束"不重要")
  • “创造性地"修改了API接口(因为它觉得这样"更好”)

3. 缺乏反馈和自纠错机制

Context Engineering本质上是一个"前馈"系统——你提供信息,AI生成输出,然后就结束了。如果输出有问题,你需要:

  1. 发现问题(可能很晚才发现)
  2. 分析问题的原因
  3. 调整上下文
  4. 重新生成

这个过程中没有自动化的反馈和修正机制。每次都需要人类介入。

这三个局限,正是Harness Engineering要解决的问题。


1.4 Harness Engineering:为AI构建工作环境

1.4.1 定义与核心理念

Harness Engineering的核心定义:

为AI Agent构建一个标准化的工作环境,通过结构化知识自动化约束可观测性自修复机制多Agent协作,确保Agent在发挥最大能力的同时,始终在人类设定的边界内工作。

Harness的词源学

Harness这个词源于古法语"harnais",最初指军事装备。后来演变为指马具——套在马身上的缰绳、鞍具和笼头。在工程领域,harness也指线束(wiring harness)——将电线、连接器组织成一个有序的系统。

这些含义完美地映射了Harness Engineering的核心理念:

  • 缰绳:约束和引导(架构约束)
  • 鞍具:提供支持和舒适(知识系统)
  • 笼头:控制方向(可观测性)
  • 线束:将各个组件组织成有序系统(系统集成)

1.4.2 与前两个范式的本质区别

Harness Engineering

违规

通过

人类设计环境

AI在环境中工作

自动约束检查

自动修正

自动审查

人类最终决策

Context Engineering

不好

人类组织信息

AI处理信息

AI生成输出

人类评估

Prompt Engineering

不好

人类写Prompt

AI生成输出

人类评估

维度 Prompt Context Harness
人类做什么 写指令 组织信息 设计环境
AI做什么 回答问题 处理信息 在环境中工作
错误处理 人工发现 人工发现 自动检测+修正
质量保证 人工评估 人工评估 自动约束+互审
控制方式 语言建议 信息引导 机制约束
反馈回路 人工闭环 人工闭环 自动闭环+人工监督

三者的关系不是替代,而是递进和包含:

Harness Engineering ⊃ Context Engineering ⊃ Prompt Engineering

一个完善的Harness系统包含了优秀的Context管理和精确的Prompt设计。

1.4.3 Harness Engineering的哲学基础

Harness Engineering不是凭空产生的技术概念,它深深扎根于三个经典的理论体系:

控制论(Cybernetics):反馈与稳态

控制论的核心思想是:通过反馈机制维持系统的稳态

瓦特的调速器通过离心力反馈控制蒸汽机的转速;K8s通过控制循环(reconciliation loop)维持集群的期望状态;Harness Engineering通过自动检测和修正机制维持Agent的输出质量。

偏差

控制信号

输出

反馈

测量值

期望状态
质量标准

比较器

控制器
Harness

被控对象
AI Agent

输出结果

传感器
检测器

系统论(Systems Theory):整体大于部分之和

系统论强调:系统的行为不能通过分析其组件来完全预测

Harness Engineering的五大组件(知识系统、架构约束、可观测性、自修复、互审机制)不是独立工作的,它们的协同作用产生了"1+1>2"的效果。例如:

  • 可观测性系统检测到的问题,可以自动触发修复机制
  • 修复后的代码,需要重新通过架构约束检查
  • 互审机制的反馈,可以更新知识系统

信息论(Information Theory):信道容量与噪声控制

信息论告诉我们:信道的容量是有限的,噪声会降低信息传递的效率

在Harness Engineering中,Agent的上下文窗口就是"信道"。Harness系统通过结构化知识系统控制信息的"信噪比",确保Agent接收到的是高质量的、相关的信息,而不是信息垃圾。

1.4.4 为什么2026年需要Harness Engineering

1. Agent能力越强,失控风险越大

2026年的AI Agent已经不是2023年的"聊天机器人"。它们可以:

  • 编写和修改代码(包括跨文件的架构重构)
  • 执行系统命令(shell、git、数据库操作)
  • 调用外部API(支付、通信、部署)
  • 管理其他Agent(任务分配、结果汇总)

这些能力意味着,一个失控的Agent可以在短时间内造成巨大的破坏。

2. 从工具到代理的角色转变

在2023-2024年,AI是"工具"——人类发起操作,AI执行,人类检查结果。

在2025-2026年,AI是"代理"——AI可以自主决定执行什么操作、如何执行、何时执行。

从"工具"到"代理"的转变,意味着控制权的转移。人类不再直接控制每一个操作,而是设定目标和边界。Harness Engineering就是管理这种控制权转移的工程方法。

3. 企业级AI部署的刚需

企业在部署AI时面临的核心挑战不是"AI能不能做",而是"AI能不能可靠地做"。Harness Engineering提供了:

  • 可审计性:所有Agent操作都有完整的日志记录
  • 可预测性:Agent的行为在预设的边界内
  • 可恢复性:出现问题时可以自动回滚和修复
  • 可扩展性:一套Harness可以管理多个Agent

1.4.5 手把手实践:你的第一个Harness配置

让我们从零开始,构建一个简单的Harness配置,用于约束AI Agent的代码生成行为。

# harness.config.yaml — 你的第一个Harness配置文件
version: "1.0"

# 1. 结构化知识系统
knowledge:
  # 知识库路径(Agent可以访问的信息)
  sources:
    - path: "./docs/architecture.md"
      type: "markdown"
      priority: "high"
    - path: "./docs/api-spec.yaml"
      type: "openapi"
      priority: "high"
    - path: "./docs/coding-standards.md"
      type: "markdown"
      priority: "medium"
  
  # 知识检索策略
  retrieval:
    strategy: "semantic"    # 语义检索
    top_k: 5                # 检索最相关的5个片段
    max_tokens: 4000        # 知识上下文最大token数

# 2. 机械化架构约束
constraints:
  # 代码风格约束
  code_style:
    language: "typescript"
    rules:
      - "no-any: error"           # 禁止使用any类型
      - "explicit-return: error"  # 必须显式声明返回类型
      - "max-params: [error, 5]"  # 函数参数不超过5个
      - "max-lines: [warn, 100]"  # 函数体不超过100行
  
  # 架构约束
  architecture:
    pattern: "layered"            # 分层架构
    layers:
      - name: "controller"
        can_access: ["service"]   # controller只能访问service
      - name: "service"
        can_access: ["repository", "model"]
      - name: "repository"
        can_access: ["model", "database"]
  
  # 安全约束
  security:
    - "no-sql-injection"
    - "no-xss"
    - "no-hardcoded-secrets"
    - "input-validation-required"

# 3. 可观测性
observability:
  # 日志配置
  logging:
    level: "info"
    include_thought_chain: true   # 记录Agent的推理链
    include_tool_calls: true      # 记录工具调用
  
  # 指标采集
  metrics:
    - "token_usage"
    - "execution_time"
    - "error_rate"
    - "code_quality_score"

# 4. 自修复
self_healing:
  enabled: true
  max_iterations: 3              # 最多修复3次
  strategies:
    - type: "test_driven"        # 测试驱动的修复
      test_command: "npm test"
    - type: "lint_fix"           # 代码规范修复
      lint_command: "npm run lint --fix"
  
  # 修复安全限制
  safety:
    max_files_changed: 5         # 单次修复最多修改5个文件
    require_human_approval: true # 高风险修复需人类审批

# 5. 互审机制
review:
  enabled: true
  reviewers:
    - role: "quality_reviewer"   # 代码质量审查
      focus: ["readability", "maintainability"]
    - role: "security_reviewer"  # 安全审查
      focus: ["vulnerabilities", "data_exposure"]
  
  # 评审策略
  strategy: "consensus"          # 共识模式:所有审查者都通过才算通过
  escalation:
    on_disagreement: "human"     # 审查者意见不一致时升级给人类
// harness-runner.ts — 使用Harness配置运行Agent
import { readFileSync } from 'fs';
import { parse as parseYaml } from 'yaml';

interface HarnessConfig {
  version: string;
  knowledge: {
    sources: Array<{ path: string; type: string; priority: string }>;
    retrieval: { strategy: string; top_k: number; max_tokens: number };
  };
  constraints: {
    code_style: { language: string; rules: string[] };
    architecture: { pattern: string; layers: Array<{ name: string; can_access: string[] }> };
    security: string[];
  };
  observability: {
    logging: { level: string; include_thought_chain: boolean; include_tool_calls: boolean };
    metrics: string[];
  };
  self_healing: {
    enabled: boolean;
    max_iterations: number;
    strategies: Array<{ type: string; test_command?: string; lint_command?: string }>;
    safety: { max_files_changed: number; require_human_approval: boolean };
  };
  review: {
    enabled: boolean;
    reviewers: Array<{ role: string; focus: string[] }>;
    strategy: string;
  };
}

class HarnessRunner {
  private config: HarnessConfig;
  private logs: Array<{ timestamp: Date; level: string; message: string; data?: any }> = [];

  constructor(configPath: string) {
    const raw = readFileSync(configPath, 'utf-8');
    this.config = parseYaml(raw);
    this.log('info', 'Harness初始化完成', { version: this.config.version });
  }

  /**
   * 运行Agent任务(完整Harness流程)
   */
  async run(task: string): Promise<HarnessResult> {
    const startTime = Date.now();
    this.log('info', `开始执行任务: ${task}`);

    // 第1步:加载知识
    const context = await this.loadKnowledge(task);
    this.log('info', `知识加载完成: ${context.length} 个片段`);

    // 第2步:构建带约束的Prompt
    const constrainedPrompt = this.buildConstrainedPrompt(task, context);
    this.log('info', '约束Prompt构建完成');

    // 第3步:执行Agent(带自修复循环)
    let result: AgentOutput | null = null;
    let iteration = 0;
    const maxIterations = this.config.self_healing.max_iterations;

    while (iteration < maxIterations) {
      iteration++;
      this.log('info', `执行迭代 ${iteration}/${maxIterations}`);

      // 执行Agent
      result = await this.executeAgent(constrainedPrompt);

      // 约束检查
      const violations = this.checkConstraints(result);
      
      if (violations.length === 0) {
        this.log('info', '所有约束检查通过');
        break;
      }

      this.log('warn', `发现 ${violations.length} 个约束违规`, { violations });

      // 自修复
      if (this.config.self_healing.enabled && iteration < maxIterations) {
        result = await this.selfHeal(result, violations);
        this.log('info', '自修复完成,重新检查');
      }
    }

    // 第4步:互审
    if (this.config.review.enabled && result) {
      const reviewResult = await this.runReview(result);
      if (!reviewResult.approved) {
        this.log('warn', '互审未通过', { issues: reviewResult.issues });
      }
    }

    // 第5步:收集指标
    const metrics = this.collectMetrics(startTime, result);
    this.log('info', '任务执行完成', { metrics });

    return {
      output: result!,
      iterations: iteration,
      metrics,
      logs: this.logs,
    };
  }

  private async loadKnowledge(task: string): Promise<string[]> {
    // 根据任务相关性从知识库检索信息
    const chunks: string[] = [];
    for (const source of this.config.knowledge.sources) {
      // 简化实现:读取所有高优先级知识
      if (source.priority === 'high') {
        try {
          const content = readFileSync(source.path, 'utf-8');
          chunks.push(`[${source.type}] ${content}`);
        } catch {
          this.log('warn', `无法读取知识源: ${source.path}`);
        }
      }
    }
    return chunks;
  }

  private buildConstrainedPrompt(task: string, context: string[]): string {
    const constraints = this.config.constraints;
    
    return `
## 任务
${task}

## 知识上下文
${context.join('\n\n')}

## 约束条件
### 代码风格
${constraints.code_style.rules.map(r => `- ${r}`).join('\n')}

### 架构规范
模式: ${constraints.architecture.pattern}
${constraints.architecture.layers.map(l => 
  `- ${l.name}层 可访问: ${l.can_access.join(', ')}`
).join('\n')}

### 安全要求
${constraints.security.map(s => `- ${s}`).join('\n')}

## 输出要求
请生成符合以上所有约束的代码。
`;
  }

  private async executeAgent(prompt: string): Promise<AgentOutput> {
    // 实际实现中调用LLM API
    this.log('info', 'Agent执行中...');
    return {
      code: '// Agent生成的代码',
      thoughtChain: ['分析任务需求', '检索相关知识', '生成代码实现'],
      toolCalls: [],
      tokenUsage: { input: 0, output: 0 },
    };
  }

  private checkConstraints(output: AgentOutput): ConstraintViolation[] {
    const violations: ConstraintViolation[] = [];
    
    // 检查代码风格
    if (output.code.includes(': any')) {
      violations.push({
        type: 'code_style',
        rule: 'no-any',
        message: '发现any类型使用',
        severity: 'error',
      });
    }

    return violations;
  }

  private async selfHeal(
    output: AgentOutput, 
    violations: ConstraintViolation[]
  ): Promise<AgentOutput> {
    this.log('info', `自修复: 处理 ${violations.length} 个违规`);
    // 实际实现中重新调用Agent,附带违规信息
    return output;
  }

  private async runReview(output: AgentOutput): Promise<ReviewResult> {
    this.log('info', '开始互审');
    return { approved: true, issues: [] };
  }

  private collectMetrics(startTime: number, output: AgentOutput | null): Metrics {
    return {
      totalTime: Date.now() - startTime,
      tokenUsage: output?.tokenUsage || { input: 0, output: 0 },
      logCount: this.logs.length,
    };
  }

  private log(level: string, message: string, data?: any): void {
    this.logs.push({ timestamp: new Date(), level, message, data });
    if (level === 'error' || level === 'warn') {
      console.log(`[${level.toUpperCase()}] ${message}`, data || '');
    }
  }
}

interface AgentOutput {
  code: string;
  thoughtChain: string[];
  toolCalls: string[];
  tokenUsage: { input: number; output: number };
}

interface ConstraintViolation {
  type: string;
  rule: string;
  message: string;
  severity: 'error' | 'warning' | 'info';
}

interface ReviewResult {
  approved: boolean;
  issues: string[];
}

interface Metrics {
  totalTime: number;
  tokenUsage: { input: number; output: number };
  logCount: number;
}

interface HarnessResult {
  output: AgentOutput;
  iterations: number;
  metrics: Metrics;
  logs: Array<{ timestamp: Date; level: string; message: string; data?: any }>;
}

// 使用示例
async function main() {
  const harness = new HarnessRunner('./harness.config.yaml');
  
  const result = await harness.run(
    '实现一个用户注册的API端点,接收邮箱和密码,返回用户ID'
  );
  
  console.log(`执行完成: ${result.iterations} 次迭代`);
  console.log(`耗时: ${result.metrics.totalTime}ms`);
  console.log(`Token使用: ${result.metrics.tokenUsage.input} + ${result.metrics.tokenUsage.output}`);
}

1.5 三次范式跃迁的深层逻辑

1.5.1 技术成熟度曲线分析

Gartner技术成熟度曲线

技术触发

期望膨胀

幻灭低谷

复苏爬坡

生产成熟

Prompt Engineering
2023: B→C

Context Engineering
2025: D→E

Harness Engineering
2026: A→B

每一次范式跃迁都遵循Gartner技术成熟度曲线的规律:

  1. 技术触发期:概念提出,早期实验
  2. 期望膨胀期:过度承诺,泡沫形成
  3. 幻灭低谷期:泡沫破裂,理性回归
  4. 复苏爬坡期:实际问题解决,最佳实践形成
  5. 生产成熟期:广泛采用,标准化

Prompt Engineering已经走过了幻灭低谷,进入了复苏期。Context Engineering正在从复苏期走向成熟期。Harness Engineering正处于技术触发期——概念刚刚形成,早期实践者开始探索。

1.5.2 从个人工具到企业基础设施的演进

阶段 特征 使用者 价值
个人工具 个人使用ChatGPT写代码 个人开发者 效率提升
团队工具 团队共享Prompt模板和知识库 开发团队 协作提升
部门平台 部门级Agent平台,集成CI/CD 技术部门 流程优化
企业基础设施 企业级Harness平台,全面覆盖 全公司 战略转型

1.5.3 经济学视角:每次跃迁背后的成本收益分析

从经济学角度看,每次范式跃迁都对应着投入产出比的一次质变

范式 投入 产出 ROI
Prompt Engineering 低(学习提示词技巧) 中(个人效率提升20-50%)
Context Engineering 中(构建知识库+RAG) 高(信息质量提升60-80%) 中高
Harness Engineering 高(构建完整Harness系统) 极高(AI可靠性提升90%+) 中→高

注意,Harness Engineering的初期投入较高,但长期ROI是最高的。这是因为:

  1. 自动化的约束和修复减少了人工审查成本
  2. 系统化的知识管理减少了重复劳动
  3. 可观测性减少了故障排查时间
  4. 互审机制提高了代码质量,减少了技术债务

1.5.4 社会学视角:人机协作关系的三次重塑

每次范式跃迁都重塑了人类与AI的协作关系:

Prompt Engineering时代(2023-2024):主仆关系

  • 人类是"主人",AI是"仆人"
  • 人类下达指令,AI执行
  • 人类需要精确地表达需求

Context Engineering时代(2024-2025):师生关系

  • 人类是"老师",AI是"学生"
  • 人类提供学习材料(上下文),AI学习并应用
  • 人类需要精心组织教学内容

Harness Engineering时代(2025-2026):架构师与工人关系

  • 人类是"架构师",AI是"工人"
  • 人类设计工作环境和规则,AI在其中工作
  • 人类需要系统思维和管理能力

1.5.5 未来展望:Harness之后是什么?

如果我们将这个演进逻辑推演到更远:

2023: Prompt Engineering
怎么跟AI说话

2025: Context Engineering
给AI看什么信息

2026: Harness Engineering
构建什么环境让AI工作

2028: Sovereign Engineering?
如何与AI共同进化

Sovereign Engineering(主权工程)——这可能是一个方向:当AI Agent具备了自我进化的能力,人类的角色将从"设计环境"进一步上升到"定义价值观和目标"。

但这是2028年的故事。现在,让我们聚焦于Harness Engineering。


1.6 实战指南:评估你的AI工程化水平

1.6.1 AI工程化成熟度模型(5级)

级别 名称 特征 典型表现
L1 临时使用 偶尔用ChatGPT辅助编程 效率提升10-20%
L2 系统Prompt 有固定的Prompt模板和最佳实践 效率提升30-50%
L3 Context工程 有RAG系统、知识库、上下文管理 输出质量提升60-80%
L4 Harness系统 有完整的约束、监控、修复、审查 可靠性90%+
L5 自进化Harness Harness系统能自我优化和进化 持续改进

1.6.2 自评估清单

回答以下30个问题,每题0-3分(0=完全没有,1=部分,2=基本,3=完善):

Prompt Engineering(L2)

  1. 你的团队有标准化的Prompt模板吗?
  2. 你有Prompt效果评估机制吗?
  3. 你有Prompt最佳实践知识库吗?
  4. 你定期优化和更新Prompt吗?
  5. 你使用Few-shot和CoT等高级技巧吗?
  6. 你有Prompt版本管理吗?

Context Engineering(L3)
7. 你有结构化的知识库吗?
8. 你使用RAG检索增强生成吗?
9. 你有上下文窗口管理策略吗?
10. 你有知识更新和质量控制流程吗?
11. 你使用知识图谱或GraphRAG吗?
12. 你有多模态上下文融合能力吗?

Harness Engineering - 知识系统(L4)
13. 你的Agent有按需加载的知识系统吗?
14. 知识检索的准确率是否超过85%?
15. 知识更新是否自动化?

Harness Engineering - 架构约束(L4)
16. 你有自动化的代码规范检查吗?
17. 你有架构合规性的自动验证吗?
18. 约束违反是否会自动阻止?

Harness Engineering - 可观测性(L4)
19. 你有Agent行为的完整日志吗?
20. 你有Agent性能指标的Dashboard吗?
21. 你有异常的自动告警吗?

Harness Engineering - 自修复(L4)
22. 你的Agent能自动检测错误吗?
23. 你的Agent能自动修复常见问题吗?
24. 你有修复后的自动验证吗?

Harness Engineering - 互审(L4)
25. 你有AI生成+AI审查的流程吗?
26. 你有多个Agent从不同角度审查吗?
27. 你有审查结果的自动聚合吗?

自进化(L5)
28. 你的Harness能根据反馈自动调整吗?
29. 你有A/B测试框架吗?
30. 你有Harness效果的长期趋势追踪吗?

评分标准:

  • 0-30分:L1(临时使用)
  • 31-45分:L2(系统Prompt)
  • 46-60分:L3(Context工程)
  • 61-80分:L4(Harness系统)
  • 81-90分:L5(自进化Harness)

1.6.3 升级路线图

建立Prompt模板

构建RAG系统

添加约束+监控

添加自进化

预计2-4周

预计1-3月

预计3-6月

L1: 临时使用

L2: 系统Prompt

L3: Context工程

L4: Harness系统

L5: 自进化Harness

L1 → L2(2-4周)

  1. 收集团队常用的Prompt
  2. 提炼为标准化模板
  3. 建立Prompt效果评估机制

L2 → L3(2-4周)

  1. 整理项目文档和知识库
  2. 搭建RAG系统
  3. 实现上下文管理策略

L3 → L4(1-3个月)

  1. 添加架构约束系统
  2. 实现可观测性
  3. 构建自修复机制
  4. 建立互审流程

L4 → L5(3-6个月)

  1. 实现Harness参数自动调优
  2. 构建A/B测试框架
  3. 建立效果长期追踪

1.7 本章小结与思考题

核心概念回顾

本章我们学习了:

  1. Prompt Engineering(2023):优化与AI对话的方式,关注"怎么说"
  2. Context Engineering(2025):优化AI的信息环境,关注"看什么"
  3. Harness Engineering(2026):构建AI的工作环境,关注"怎么控制"

三者是递进和包含的关系,而非替代。

Harness Engineering的五大核心组件:

  • 📚 结构化知识系统
  • 🔧 机械化架构约束
  • 👁️ 可观测性注入
  • 🔄 自修复闭环
  • 🤝 Agent互审机制

思考题

  1. 分析题:选择一个你正在使用的AI工具,分析它属于Prompt Engineering、Context Engineering还是Harness Engineering的范畴?它缺少哪些Harness组件?

  2. 设计题:如果你要为一个10人开发团队设计Harness系统,你会从哪个组件开始?为什么?

  3. 对比题:比较Kubernetes的控制循环和Harness Engineering的自修复闭环,它们有什么共同点和不同点?

  4. 评估题:使用本章的成熟度模型评估你当前团队的AI工程化水平,制定一个3个月的升级计划。

  5. 批判题:Harness Engineering可能面临哪些挑战和局限?它是否有可能被下一代范式取代?

  6. 实践题:选择一个小项目,实现一个最简版的Harness系统(至少包含知识系统和架构约束),记录你的体验和发现。

  7. 信息论题:从信息论角度分析,为什么Prompt Engineering存在天花板?如何用数学公式描述这个天花板?

  8. 经济学题:计算在你的团队中实施Harness Engineering的ROI。考虑投入(开发时间、工具成本)和产出(效率提升、质量改善、故障减少)。

  9. 哲学题:Harness Engineering将人类的角色从"代码编写者"转变为"环境设计者"。这种角色转变对程序员的职业身份意味着什么?

  10. 预测题:你认为2028年AI工程的主流范式会是什么?请给出你的理由。

延伸阅读

  1. Shannon, C.E. (1948). A Mathematical Theory of Communication
  2. Wiener, N. (1948). Cybernetics: Or Control and Communication in the Animal and the Machine
  3. Andrej Karpathy (2025). The hottest new programming language is English
  4. Latent Space Podcast (2025). Why Context Engineering is the Next Frontier
  5. Anthropic (2026). Building Reliable AI Agents: A Harness Engineering Approach

下一章预告:第2章《控制论与反馈循环》,我们将深入探索Harness Engineering的理论基石,从瓦特调速器讲到AI Agent的闭环控制系统。

Logo

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

更多推荐