第1章-从Prompt到Harness《智驭》
第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领域发生了两个关键变化:
- RAG(Retrieval-Augmented Generation,检索增强生成)技术的成熟
- 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 为什么每次范式跃迁都不可避免?
回顾这三次范式跃迁,我们可以发现一个清晰的逻辑链条:
每次跃迁的根本原因是上一代范式的天花板:
| 维度 | 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 三个时代的时间线
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的核心范畴包括:
- 知识管理:组织、索引、更新AI可以访问的知识
- 检索策略:在海量信息中找到最相关的片段
- 上下文组装:将多个信息源整合为连贯的上下文
- 上下文压缩:在有限的token预算内最大化信息价值
- 上下文更新:随着任务推进动态更新上下文
1.3.2 核心技术栈
RAG(检索增强生成)深度解析
RAG是Context Engineering最核心的技术。一个完整的RAG系统包含以下组件:
文本分块策略是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):节点和边的附加信息
GraphRAG的优势在于:
- 多跳推理:可以从A出发,经过B到达C
- 关系感知:理解实体之间的关系类型
- 子图检索:返回的不是孤立的文本块,而是相关的知识子图
// 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生成输出,然后就结束了。如果输出有问题,你需要:
- 发现问题(可能很晚才发现)
- 分析问题的原因
- 调整上下文
- 重新生成
这个过程中没有自动化的反馈和修正机制。每次都需要人类介入。
这三个局限,正是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 与前两个范式的本质区别
| 维度 | 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的输出质量。
系统论(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已经走过了幻灭低谷,进入了复苏期。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.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之后是什么?
如果我们将这个演进逻辑推演到更远:
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)
- 你的团队有标准化的Prompt模板吗?
- 你有Prompt效果评估机制吗?
- 你有Prompt最佳实践知识库吗?
- 你定期优化和更新Prompt吗?
- 你使用Few-shot和CoT等高级技巧吗?
- 你有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 升级路线图
L1 → L2(2-4周):
- 收集团队常用的Prompt
- 提炼为标准化模板
- 建立Prompt效果评估机制
L2 → L3(2-4周):
- 整理项目文档和知识库
- 搭建RAG系统
- 实现上下文管理策略
L3 → L4(1-3个月):
- 添加架构约束系统
- 实现可观测性
- 构建自修复机制
- 建立互审流程
L4 → L5(3-6个月):
- 实现Harness参数自动调优
- 构建A/B测试框架
- 建立效果长期追踪
1.7 本章小结与思考题
核心概念回顾
本章我们学习了:
- Prompt Engineering(2023):优化与AI对话的方式,关注"怎么说"
- Context Engineering(2025):优化AI的信息环境,关注"看什么"
- Harness Engineering(2026):构建AI的工作环境,关注"怎么控制"
三者是递进和包含的关系,而非替代。
Harness Engineering的五大核心组件:
- 📚 结构化知识系统
- 🔧 机械化架构约束
- 👁️ 可观测性注入
- 🔄 自修复闭环
- 🤝 Agent互审机制
思考题
-
分析题:选择一个你正在使用的AI工具,分析它属于Prompt Engineering、Context Engineering还是Harness Engineering的范畴?它缺少哪些Harness组件?
-
设计题:如果你要为一个10人开发团队设计Harness系统,你会从哪个组件开始?为什么?
-
对比题:比较Kubernetes的控制循环和Harness Engineering的自修复闭环,它们有什么共同点和不同点?
-
评估题:使用本章的成熟度模型评估你当前团队的AI工程化水平,制定一个3个月的升级计划。
-
批判题:Harness Engineering可能面临哪些挑战和局限?它是否有可能被下一代范式取代?
-
实践题:选择一个小项目,实现一个最简版的Harness系统(至少包含知识系统和架构约束),记录你的体验和发现。
-
信息论题:从信息论角度分析,为什么Prompt Engineering存在天花板?如何用数学公式描述这个天花板?
-
经济学题:计算在你的团队中实施Harness Engineering的ROI。考虑投入(开发时间、工具成本)和产出(效率提升、质量改善、故障减少)。
-
哲学题:Harness Engineering将人类的角色从"代码编写者"转变为"环境设计者"。这种角色转变对程序员的职业身份意味着什么?
-
预测题:你认为2028年AI工程的主流范式会是什么?请给出你的理由。
延伸阅读
- Shannon, C.E. (1948). A Mathematical Theory of Communication
- Wiener, N. (1948). Cybernetics: Or Control and Communication in the Animal and the Machine
- Andrej Karpathy (2025). The hottest new programming language is English
- Latent Space Podcast (2025). Why Context Engineering is the Next Frontier
- Anthropic (2026). Building Reliable AI Agents: A Harness Engineering Approach
下一章预告:第2章《控制论与反馈循环》,我们将深入探索Harness Engineering的理论基石,从瓦特调速器讲到AI Agent的闭环控制系统。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)