🚀 前端工程师如何构建 AI Harness(架构 + 代码设计 + 落地实践)
一篇写给"已经开始做 AI,但不想停留在 Demo 阶段"的前端工程师
一、问题背景:为什么你需要 AI Harness?
很多团队在接入 AI 后,很快会遇到这些问题:
- ❓ prompt 改了一点,效果变差但不知道为什么
- ❓ 不同模型表现不一致,无法稳定
- ❓ AI 输出偶尔离谱,但无法复现
- ❓ 每次优化都像"玄学调参"
- ❓ 没有办法做回归测试
这些问题的本质只有一个:
❗你在"用 AI",但没有"工程化 AI"
二、什么是 AI Harness?
一句话定义:
AI Harness = 让 AI 从"能用"变成"可控、可测、可观测、可回归"的工程系统
从 Prompt 到 Harness
随着 AI 处理任务复杂度的增加,工程重点经历了三个阶段的演进:
| 阶段 | 核心关注点 | 隐喻 | 解决的问题 |
|---|---|---|---|
| Prompt Engineering (2023) | 说什么 | 指令 | 如何通过提示词让 AI 交付单次结果。 |
| Context Engineering (2025) | 知道什么 | 信息 | 如何通过 RAG 和动态上下文构建让 AI 获得所需信息。 |
| Harness Engineering (2026) | 在什么环境做事 | 环境/闭环 | 如何构建约束、反馈与控制系统,让 Agent Reliable 执行任务。 |
一个直观类比
| AI 组件 | 类比 |
|---|---|
| LLM | 发动机 |
| AI Harness | 方向盘 + 仪表盘 + 测试系统 |
为什么它重要?
现实一点说:
- 模型能力:越来越接近
- 工程能力:差距巨大
👉 真正的壁垒在这里:
谁能稳定地"用好 AI",而不是谁能调用 API
三、整体架构(前端可落地版)
sql
┌──────────────────────────────────────────────┐
│ Frontend App │
│ Chat / Admin / SaaS / Tooling UI │
└──────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ AI Service Layer │
│ prompt / model / tool / parser / retry │
└──────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌───────────┐ ┌─────────────┐ ┌──────────────┐
│ LLM APIs │ │ Tool System │ │ Eval System │
└───────────┘ └─────────────┘ └──────────────┘
│ │ │
└──────┬────────┴───────┬───────┘
▼ ▼
┌──────────────────────────────────────────────┐
│ Observability Layer │
│ trace / logs / token / latency │
└──────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ Regression Harness │
│ dataset / scoring / CI │
└──────────────────────────────────────────────┘
四、核心设计思想(非常关键)
在实现之前,先明确几个核心原则:
1️⃣ Scene(场景驱动)
👉 不要把 AI 当成一个"万能函数"
错误写法:
scss
runAI("帮我干点事")
正确方式:
css
runAI({
scene: "bug-fix",
input,
})
👉 每个场景:
- prompt 不同
- 工具不同
- 模型不同
- 输出结构不同
2️⃣ 工具优先,而不是 prompt 堆砌
很多人会这样做:
erlang
请你分析问题,如果需要可以假设...
👉 这是不稳定的
正确方式:
diff
你可以使用以下工具:
- searchDocs
- runTests
- queryAPI
👉 本质:
用工具约束模型,而不是靠 prompt 想象
3️⃣ 可观测性优先
如果你没有记录:
- prompt
- tool 调用
- 输出
👉 你就无法 debug
4️⃣ Eval 驱动优化
不要这样:
"我感觉这个 prompt 更好了"
要这样:
python
旧版本:78% pass
新版本:85% pass
五、分层设计(5 层)
1️⃣ UI 层
职责:
- 输入 / 展示
- 流式渲染
- 中断 / 重试
lua
type ChatMessage = {
id: string
role: 'user' | 'assistant'
content: string
status?: 'streaming' | 'done'
}
2️⃣ AI Service 层(核心)
👉 相当于 AI 的 BFF
负责:
- prompt 构建
- model routing
- tool orchestration
- output parsing
- retry / fallback
核心调用方式
csharp
const result = await runAI({
scene: 'bug-fix',
userInput,
context,
})
3️⃣ Tool 层
标准定义
typescript
export interface AITool<Input, Output> {
name: string
description: string
schema: ZodSchema<Input>
execute(input: Input): Promise<Output>
}
示例工具
css
export const searchDocsTool: AITool<
{ query: string },
{ results: string[] }
> = {
name: 'searchDocs',
description: 'Search internal docs',
schema: z.object({
query: z.string(),
}),
async execute(input) {
return searchDocs(input.query)
},
}
Tool Registry
ini
const tools = {
searchDocs: searchDocsTool,
runTests: runTestsTool,
}
4️⃣ Observability 层
为什么必须有?
否则你会遇到:
- "昨天还好好的"
- "偶现 bug"
- "不知道模型为什么这么答"
Trace 结构
typescript
type AITrace = {
traceId: string
scene: string
model: string
prompt: string
toolCalls: Array<{
name: string
args: unknown
result: unknown
duration: number
}>
output: unknown
latency: number
success: boolean
}
5️⃣ Eval / Regression 层
示例数据集
css
[ { "id": "faq-1", "input": "退款规则是什么?", "expected": { "mustInclude": ["7天", "原路退回"]
}
}
]
Runner
php
for (const testCase of dataset) {
const result = await runAI({
scene: 'faq',
userInput: testCase.input,
})
const passed = evaluate(result, testCase.expected)
}
六、核心代码结构(推荐)
arduino
src/
├── ai/
│ ├── core/
│ │ ├── ai-service.ts
│ │ ├── model-router.ts
│ │ ├── prompt-builder.ts
│ │ ├── output-parser.ts
│ │ └── trace.ts
│ │
│ ├── scenes/
│ │ ├── bug-fix.scene.ts
│ │ ├── faq.scene.ts
│ │
│ ├── tools/
│ │ ├── search-docs.tool.ts
│ │ ├── run-tests.tool.ts
│ │
│ ├── eval/
│ │ ├── datasets/
│ │ ├── run-eval.ts
│ │
│ └── adapters/
│ ├── openai.adapter.ts
│
├── server/
│ └── api/
│
└── apps/
└── chat/
七、Scene 抽象(关键)
typescript
export interface AIScene {
name: string
tools?: string[]
model?: string
buildPrompt(input): Promise<string>
parseOutput(raw: string): unknown
}
示例:Bug Fix
javascript
export const bugFixScene: AIScene = {
name: 'bug-fix',
tools: ['searchDocs', 'runTests'],
async buildPrompt({ userInput }) {
return `
You are a senior frontend engineer.
Analyze the bug and return JSON:
{
"rootCause": "",
"fixPlan": []
}
Bug:
${userInput}
`
},
parseOutput(raw) {
return JSON.parse(raw)
},
}
八、AI Service 实现(核心)
csharp
export async function runAI(params) {
const scene = getScene(params.scene)
const model = resolveModel(scene.name)
const prompt = await scene.buildPrompt(params)
const result = await callModel({
model,
prompt,
tools: scene.tools,
})
return scene.parseOutput(result)
}
九、推荐落地场景(非常现实)
1️⃣ 文档问答
👉 提升研发效率
👉 减少重复沟通
2️⃣ Code Review
输入:
- diff
输出:
- 风险点
- 建议
3️⃣ AI 修 Bug(最有价值)
流程:
Bug → 分析 → 检索 → 修复 → 测试 → 输出
十、MVP 落地建议
第一阶段只做:
markdown
1. Chat UI
2. runAI
3. 2 个工具
4. trace
5. 10 条测试数据
👉 一周可落地
十一、常见坑
❌ prompt 写死
👉 后期不可维护
❌ 工具不稳定
👉 模型直接崩
❌ 没有 trace
👉 无法 debug
❌ 没有 eval
👉 优化靠感觉
❌ 一上来做 Agent
👉 容易翻车
正确路径:
问答 → 建议 → 半自动 → 自动化
十二、总结
对于前端工程师来说:
👉 AI Harness 是一个非常好的切入点
因为它结合了:
- 工程能力
- 架构能力
- 系统设计
- AI 应用能力
🔚 最后一句
未来 AI 的差距不在于:
谁会用 AI
而在于:
谁能把 AI 稳定地用在真实业务中
如果你看到这里,说明你已经不是在"用 AI"了。
你是在构建 AI 系统。