Context Engineering vs Harness Engineering vs Prompt Engineering

这三个概念构成了 LLM 应用开发的三层技术栈,从微观到宏观、从单次交互到系统架构层层递进。


一、Prompt Engineering(提示词工程)

概念

设计、优化输入给 LLM 的文本指令,以获取最佳输出。这是最基础、最微观的层次。

核心特点

  • 作用范围:单次 LLM 调用
  • 输入输出:文本 → 文本
  • 优化目标:输出质量、准确性、格式
  • 调试方式:人工调整提示词,观察输出变化

典型技术

// 1. 角色扮演
const prompt = `你是一位资深 Python 工程师,请审查以下代码...`;

// 2. 思维链(Chain of Thought)
const prompt = `请逐步推理:1. 首先... 2. 然后...`;

// 3. Few-shot 示例
const prompt = `示例1: ... → ...\n示例2: ... → ...\n现在处理:`;

// 4. 输出格式约束
const prompt = `以 JSON 格式输出:{"field1": "", "field2": ""}`;

局限性

  • ❌ 无状态管理(每次调用独立)
  • ❌ 无法处理超长上下文
  • ❌ 不能调用外部工具
  • ❌ 无错误恢复机制

二、Harness Engineering(脚手架工程)

概念

构建 LLM 应用的外部系统和工具链,包括工具定义、状态管理、错误处理、成本控制等。这是中间层,负责"编排"。

核心特点

  • 作用范围:整个 Agent/应用会话
  • 主要组件:工具、状态、缓存、降级、监控
  • 优化目标:系统可靠性、成本控制、用户体验
  • 调试方式:日志、链路追踪、A/B 测试

核心组件

class Harness {
  // 1. 工具定义(让 LLM 调用外部能力)
  tools = {
    read_file: { handler: async (path) => {...} },
    execute_bash: { handler: async (cmd) => {...} },
    search_web: { handler: async (query) => {...} }
  };
  
  // 2. 状态管理(上下文窗口控制)
  manageContext() {
    if (tokenCount > 0.75 * maxTokens) {
      this.compress();  // 压缩历史
    }
  }
  
  // 3. 缓存策略(降低成本)
  setupCache() {
    // 标记稳定前缀,复用 KV Cache
    this.cachePrefix = [systemPrompt, toolDefinitions];
  }
  
  // 4. 错误处理与降级
  async callWithFallback(prompt) {
    try {
      return await callModel('opus', prompt);
    } catch {
      return await callModel('sonnet', prompt);  // 降级
    }
  }
  
  // 5. 成本控制
  estimateCost(messages) {
    return countTokens(messages) * 0.015 / 1000;
  }
}

解决的核心问题

问题Harness 解决方案
上下文溢出压缩、摘要、滑动窗口
工具调用失败重试、降级、超时控制
成本失控Token 计数、缓存、模型路由
响应不稳定多次采样、投票机制
安全风险工具白名单、沙箱执行

三、Context Engineering(上下文工程)

概念

设计、管理、优化 LLM 在整个任务生命周期中能看到的所有信息。这是最宏观的层次,关注"信息生态"。

核心特点

  • 作用范围:跨会话、跨 Agent、长期任务
  • 主要对象:信息选择、压缩、记忆、共享
  • 优化目标:信息密度、长期一致性、知识复用
  • 调试方式:信息检索评估、记忆召回率

上下文的层次结构

Level 4: 长期记忆(跨会话)
         ├─ 向量数据库
         ├─ 知识图谱
         └─ 用户偏好

Level 3: 工作区上下文(项目级)
         ├─ CLAUDE.md / README
         ├─ 项目结构
         └─ 近期修改

Level 2: 会话上下文(本次对话)
         ├─ 历史消息
         ├─ 已执行操作
         └─ 中间决策

Level 1: 瞬时上下文(当前消息)
         ├─ 用户最新输入
         └─ 临时工具结果

关键技术

// 1. 信息选择(只加载相关内容)
class ContextSelector {
  async select(query, codebase) {
    // 从 10 万行代码中检索最相关的 5 个文件
    const relevant = await vectorDB.search(query, { topK: 5 });
    // 每个文件只提取相关函数(而非全部)
    return relevant.map(f => this.extractRelevantSnippets(f));
  }
}

// 2. 信息压缩(有损但保留关键结构)
class ContextCompressor {
  compress(code, level) {
    if (level === 1) return this.extractSignatures(code);     // 只剩函数名
    if (level === 2) return this.extractSignaturesAndComments(code);
    return this.simplifyImplementation(code);                  // 保留逻辑但简化
  }
}

// 3. 长期记忆(跨会话存储)
class LongTermMemory {
  async memorize(decision) {
    await vectorDB.add(decision.embedding, decision.summary);
    await knowledgeGraph.createRelation(decision.from, decision.to);
  }
  
  async recall(question) {
    return await vectorDB.search(question);  // 语义检索
  }
}

三者的核心区别

对比表格

维度Prompt EngineeringHarness EngineeringContext Engineering
作用范围单次 LLM 调用Agent 会话生命周期跨会话、跨 Agent
时间尺度毫秒级分钟-小时级天-周级
主要对象文本指令工具、状态、错误信息选择、压缩、记忆
优化目标输出质量系统可靠性、成本信息密度、长期一致性
典型问题"怎么让模型理解意图?""Agent卡住了怎么办?""如何记住上周的决定?"
失败后果回答质量差系统崩溃、成本失控重复工作、决策矛盾
调试方式人工调整提示词日志、链路追踪检索评估、召回率
依赖关系独立依赖好的 Prompt依赖 Harness 提供存储

一句话总结

  • Prompt Engineering怎么说(微观表达)
  • Harness Engineering怎么做(中观系统)
  • Context Engineering知道什么(宏观信息)

协作关系图

用户需求
    ↓
┌─────────────────────────────────────────┐
│  Context Engineering(宏观)             │
│  "应该加载哪些历史决策?"                 │
│  "如何压缩10万行代码到2000 token?"       │
│  "如何记住上周的架构决策?"               │
└─────────────┬───────────────────────────┘
              ↓ 提供精选/压缩后的信息
┌─────────────────────────────────────────┐
│  Harness Engineering(中观)            │
│  "如何定义工具让Agent调用?"              │
│  "上下文快满了,要不要压缩?"             │
│  "工具调用失败,重试还是降级?"           │
└─────────────┬───────────────────────────┘
              ↓ 构建请求、管理状态
┌─────────────────────────────────────────┐
│  Prompt Engineering(微观)              │
│  "系统提示词怎么写?"                     │
│  "这个工具描述怎么让模型理解?"            │
│  "如何用few-shot示例引导输出格式?"       │
└─────────────┬───────────────────────────┘
              ↓ 构造最终 Prompt
           LLM 调用

实际案例对比

场景:构建一个代码审查 Agent

// ========== 1. Prompt Engineering ==========
// 关注:如何让模型输出高质量审查意见

const reviewPrompt = `
你是一位资深代码审查专家。审查以下代码:

规则:
1. 安全性:检查 SQL 注入、XSS
2. 性能:检查 N+1 查询
3. 可维护性:检查命名、注释

输出格式:
- 🔴 严重问题
- 🟡 建议改进

代码:
${code}
`;

// ========== 2. Harness Engineering ==========
// 关注:如何让 Agent 稳定运行、控制成本

class CodeReviewHarness {
  async review(prUrl) {
    // 工具定义
    const tools = {
      get_diff: () => fetchDiff(prUrl),
      run_linter: (code) => eslint(code),
      get_file_history: (path) => gitLog(path)
    };
    
    // 状态管理:避免上下文溢出
    let context = { reviewedFiles: [], comments: [] };
    
    // 错误处理:工具调用失败时降级
    try {
      const diff = await tools.get_diff();
      for (const file of diff.files) {
        const issues = await this.reviewFile(file);
        context.comments.push(...issues);
      }
    } catch (error) {
      // 降级:只做静态分析
      return this.staticAnalysisOnly();
    }
    
    // 成本控制:预估 token 消耗
    if (this.estimateCost(context) > 0.5) {
      await this.compressHistory();
    }
    
    return context;
  }
}

// ========== 3. Context Engineering ==========
// 关注:应该加载哪些信息?如何压缩?如何记忆?

class CodeReviewContext {
  async buildContext(pr) {
    return {
      // 当前 PR 的变更
      currentDiff: await this.getDiff(pr),
      
      // 相关历史决策(从向量库检索)
      pastDecisions: await this.vectorDB.search(
        pr.description, 
        { filter: { type: 'architectural', limit: 5 } }
      ),
      
      // 项目规范(从 CLAUDE.md 加载)
      projectRules: await this.loadClaudeMd(),
      
      // 压缩策略:只保留关键信息
      compressedHistory: this.compress(pastDecisions, {
        keepSignatures: true,
        dropImplementation: true
      })
    };
  }
}

发展路径

const learningPath = {
  beginner: "只做 Prompt Engineering",
  intermediate: "Prompt + Harness(工具、状态、错误处理)",
  advanced: "完整三层(重点是 Context Engineering)"
};

// 投入产出比
const roi = {
  promptEngineering: "低成本、高回报(适合简单任务)",
  harnessEngineering: "中成本、中回报(适合生产环境)",
  contextEngineering: "高成本、高回报(适合复杂长期任务)"
};

总结

核心区别

层次核心问题关键产出
Prompt如何表达意图?高质量的单次回复
Harness如何构建可靠系统?稳定运行的 Agent
Context如何管理信息生态?长期一致的知识体系

现代 LLM 应用的竞争壁垒

2023 年:Prompt Engineering 是核心技能
2024 年:Harness Engineering 成为标配
2025 年:Context Engineering 是真正的护城河

原因:当基础能力(提示词、工具调用)被模型内置后,真正区分产品优劣的是如何管理信息——知道保留什么、丢弃什么、从哪里检索、如何压缩。这也是 Claude Code、Cursor 等产品的核心竞争力所在。