乐于分享
好东西不私藏

AI大模型核心概念(下):Prompt到Agent

AI大模型核心概念(下):Prompt到Agent

下篇:从 Prompt 到 Agent 的工程全景 — 提示语、上下文与驾驭三大工程、Skill、FC+MCP、Agent 设计、ReAct、SDD、模型路由与评测

上篇讲了 AI 怎么"看懂"文字,中篇讲了模型怎么"变聪明"。这篇是三部曲最关键的一篇:模型有了,怎么把它变成能在真实环境里稳定干活的 AI 系统。


大模型从"会聊天"到"能交付",中间隔的不是一个更好的提示词,而是一整套工程体系。

这套体系经历了三次重心迁移——从"怎么说"(Prompt Engineering),到"��什么"(Context Engineering),再到"如何让模型在真实执行中持续做对"(Harness Engineering)。

这一篇,我们把这三次迁移拆开来看,然后再深入到 Agent 的完整工程实践。


一、Prompt Engineering — "我该怎么对模型说"

一句提示词,效果天差地别

同一个模型,换一种说法,输出质量可能差三倍。

说"帮我总结这篇文章" → 模型给一段无关痛痒的概述。

说"请以资深技术编辑的身份,用三段结构总结这篇文章:先讲核心观点,再讲论证方式,最后讲局限性,每段不超过 150 字" → 输出立竿见影好很多。

这就是 Prompt Engineering 最早的价值:模型不是不会,而是你没有把约束讲清楚。

Prompt Engineering 为什么有效

因为大模型是一个对上下文极度敏感的"概率生成系统"。它不是命令行——不会严格按指令执行。它的行为取决于你喂给它的所有文本构成的"概率空间":

  • 你给它什么身份,它沿着那个身份分布去采样
  • 你给它什么例子,它沿着那个模式继续补全
  • 你强调什么约束,它把那部分当成高权重信号

Prompt Engineering 的本质,不是"下命令",是塑造局部概率空间

Prompt 的四层体系

在实际工程中,Prompt 不是一句话,而是一个分层的体系:

层级内容示例
系统指令定义角色、规则、边界"你是一个有 10 年经验的 Python 后端工程师..."
Few-shot 示例示范输入输出格式给 2-3 个"问题→回答"对,固定输出范式
用户输入当前任务描述"帮我写一个处理 CSV 文件的函数"
输出约束格式、长度、风格"用 JSON 格式输出,包含 risks、complexity 字段"

每一层都在缩小模型的"搜索空间",让它更准确。

高质量 Prompt 的五个要素

① 角色设定。 格式:"你是一个 X 领域的专家,擅长 A/B/C"。差的:不说角色。好的:限定专业视角。

② 上下文完整。 差:"这个有 Bug,帮我修"。好:"以下是一个 Python 函数,输入用户 ID,输出用户名。当用户不存在时应抛出 UserNotFoundError。现在输入 -1 时会崩溃——帮我修复:[代码]"

③ 输出格式明确。 差:"分析一下这个需求"。好:"用 JSON 输出,包含字段:risks(风险列表)、complexity(low/medium/high)、estimatedDays(整数)"

④ 思维链引导。 在末尾加"请一步步思考,展示你的推理过程"。复杂推理任务准确率可提升 20-40%。

⑤ 拒答边界。 先划红线,再让回答。比如"如果资料里没有相关信息,直接说'不知道',不要编造。"

Prompt 的六个常见陷阱

陷阱现象解法
指令冲突System Prompt 和用户输入矛盾明确优先级
上下文污染历史对话干扰当前回答关键任务开新会话
负面指令无效"不要做 X"往往不如"做 Y"用正面指令替代
过长 Prompt 稀释重点指令太多,模型"忘了"核心约束精简指令 + Few-shot
格式不稳定同样 Prompt 输出格式不一致加 Few-shot 固定格式
Prompt Injection用户在输入里嵌入特殊指令输入清洗 + 职责分离

Prompt 的天花板

Prompt 非常擅长:澄清任务、约束输出、激发已有能力。但它不擅长:凭空补齐缺失知识、管理大量动态信息、处理长链条任务中的状态变化。

说得直接一点:Prompt 解决的是"表达问题",不是"信息问题"。

当任务从单轮对话进入真实业务场景,你会发现模型答得不好,未必是因为你不会问——可能是因为你根本没把需要的材料给它看。

问题的焦点从"怎么说"变成了"给什么"——第二次迁移来了。


二、Context Engineering — "模型应该看到什么"

从"一句话"到"一整套输入环境"

在 Context Engineering 的视角下,给模型的不是一段"系统提示词+用户输入",而是一整套经过设计的信息环境

它包括:
- 用户当前输入
- 历史对话(全文 or 摘要 or 压缩版)
- 外部知识检索结果(RAG 返回的文档片段)
- 工具调用返回
- 当前任务状态
- 系统规则与安全约束
- 其他 Agent 传过来的结构化结果

Prompt 只是 Context 的一部分,不是全部。

为什么 Context Engineering 会兴起

核心原因:模型的使用场景变了。

最早的主流交互是一问一答。这个模式下,Prompt 的权重很高——任务短、链路短、状态少。

但 Agent 开始火以后,模型被放进真实的执行环境:要持续多轮对话、要调搜索/浏览器/代码/数据库等工具、要在多步骤间传递中间结果、要根据外部反馈修正计划。

这时候,你已经不是在优化"单次回答对不对"——而是在优化"一整条任务链路能不能跑通"。

Context Engineering 的五个关键问题

问题一:窗口里塞什么?

128K 的上下文窗口,不意味着你应该把 128K 信息全塞进去。Lost in the Middle 效应告诉我们:中间的信息最容易被模型忽略。所以重要的信息要放在开头或结尾。

问题二:哪些该完整保留,哪些该摘要压缩?

历史对话太长会占满窗口。做法:
- 最近 3 轮 → 原文保留
- 更早的对话 → 摘要压缩
- 工具返回结果 → 裁剪掉冗余字段

问题三:信息什么时候塞进去?

不是"一开始全部给"。Skill 的渐进式披露机制把事情分三层:
- 元数据层(~50 Token):技能名称、触发条件——全局加载
- 指令层(~500 Token):标准作业流程——触发时才加载
- 资源层:脚本、模板、API 文档——执行时才加载

不让模型从第一秒就背着所有信息。

问题四:多 Agent 之间怎么传信息?

Agent A 的输出给 Agent B——是给原文、摘要、还是结构化字段?原文信息完整但占 Token;结构化字段省空间但丢失细节;摘要介于两者之间。

问题五:上下文缓存(Context Caching)

如果多轮对话使用相同的系统提示词,不用每次都重新计算——缓存这部分计算结果,显著降低首 Token 延迟。Claude 和 Gemini 都支持 Prompt Cache。

Context Engineering 的局限

即使信息是对的,模型也未必会稳定执行对。它可能:计划很好但执行偏了、调了工具但误解了结果、中间某步出错后继续一路错下去、在长流程里逐渐偏航却没人发现。

Prompt 和 Context 都主要作用在"输入侧"——一个优化意图表达,一个优化信息供给。但当模型开始连续行动时,还有一个更难的问题:谁来持续监督它、约束它、纠正它?

这就是第三次迁移——Harness Engineering。


三、Harness Engineering — "如何让模型稳定执行"

不只是"驾驭",是对整个执行过程的工程化

Harness 这个词本身就有"缰绳、马具、约束装置"的意思。放在 AI 系统里,它的含义很直白:当模型从"回答问题"走向"执行任务",系统不能只负责给信息,还必须负责驾驭过程。

LangChain 工程师给了一个非常精准的定义:

Agent = Model + Harness
Harness = Agent - Model

Harness 是在 Agent 环境中除了模型以外的所有东西——它决定了模型看到什么、能做什么、按什么规则做、做错了怎么纠偏、最后如何把能力稳定地交付出来。

三层工程体系的关系

用一个例子串起来——假设你要让一个新人完成一次重要客户拜访:

Prompt Engineering → 你把任务讲清楚:
"见面先寒暄,再介绍方案,再问需求,最后确认下一步。"

Context Engineering → 你给他准备资料:
客户背景、过往沟通记录、产品报价、竞品情况、会议目标。

Harness Engineering → 你不只说完话给资料就完了,你还会:
- 让他带着 checklist 去(约束)
- 关键节点实时汇报(观测)
- 核对纪要与录音(校验)
- 出现偏差马上纠正(纠偏)
- 按明确标准验收结果(验收)

三层不是互相取代的关系,是层层包含

Prompt 是对"提示词"的工程化

Context 是对"输入环境"的工程化

Harness 是对"整个执行控制系统"的工程化

边界一层比一层大,后者天然包含前者。越往后,你面对的不是"怎么问得更好",而是"怎么让系统持续稳定地跑"。

Harness 的六层架构

一个成熟的 Harness 至少包含六层:

第一层:上下文管理。 角色与目标定义、信息选择与裁剪(去掉不相干的、留下关键的)、上下文结构化组织(分层级、不堆砌)。做的是"让模型在正确的信息边界内思考"。

第二层:工具系统。 给什么工具(不是越全越好,围绕任务场景配置)、什么时候调用(判断当前上下文是否足够)、怎么把工具结果喂回模型(提炼有效证据,不是全量塞回)。

第三层:执行编排。 步骤划分、决策节点、中间产物、终止条件、异常处理逻辑。很多 Agent 不是不会某一步,而是不会"串起一整条链"。

第四层:状态与记忆。 当前任务进行到哪一步、哪些中间结果要保留、哪些内容形成长期记忆。临时状态、会话记忆、长期偏好——这三者必须分离,混在一起系统越来越乱。

第五层:评估与观测。 输出验收(是否满足任务要求)、环境验证(代码是否真的可运行)、自动测试、日志指标观测、质量归因(问题出在模型/上下文/工具/流程哪一环)。

第六层:约束、校验与失败恢复。 限制模型可做和不可做的事、输出前检查、失败时分析原因重试或切换备用路径。真实环境里失败是常态——搜索不准、API 超时、文档格式混乱——没有恢复机制,Agent 每次出错都只能从头来。

OpenAI 和 Anthropic 的 Harness 实践

Anthropic 的 Context Reset。 长任务中上下文满了,通常做法是压缩历史再跑。Anthropic 发现对于某些模型,仅压缩不够——模型接近窗口极限时会"焦虑",急于收尾。他们的做法是 Context Reset——直接换一个干净上下文的 Agent,两模型交班时把工作交接清楚。这很像工程里的"进程重启与状态恢复"——不是所有内存泄漏都能靠清理缓存解决。

Anthropic 的 Generator + Evaluator 分离。 让模型自己评估自己的产出时,它往往过度乐观。所以他们把"干活的人"和"打分的人"拆开——Planner 扩展需求、Generator 逐步实现、Evaluator 像 QA 一样实际操作应用检查质量。生产与验收必须分离——这是个朴素的工程原则,放在 AI 系统里同样成立。

OpenAI 的渐进式披露。 早期他们写了一个巨大的 AGENTS.md,把所有规范塞进去——Agent 反而更迷糊。最终方案是 AGENTS.md 只有约 100 行,充当"目录页",指向仓库里的详细文档(架构/设计/执行计划/质量评分)。Agent 先看目录,需要时再去查。文档新鲜度用 CI 自动校验,还有一个专门"文档园丁"Agent 定期扫描过期文档。

OpenAI 的"人类不写代码,只设计环境"。 他们的工程师核心工作是三件事:拆解意图(把产品目标拆成 Agent 能理解的小块)、补全能力(Agent 失败时问"环境里缺了什么"而不是"再试一次")、建立反馈回路(让 Agent 看到自己工作的结果)。当出了问题,修复方向几乎从来不是"更努力地调 Prompt",而是"缺了什么结构性能力"。


四、Skill — 大模型的"能力封装"

Skill 是什么

Skill 是一个结构化的本地文件夹,用来补充某个领域的流程、知识和工具。它的设计思想是——把"怎么让模型做好一个特定类型任务"这件事,从 Prompt 里抽出来,封装成可复用的模块。

这也是 Context Engineering 的典型实践:不让模型从第一秒就看到全部能力和全部信息,而是只在需要时暴露最相关的那部分。

Skill 的文件结构

一个典型的 Skill 包含:

my-skill/

├── SKILL.md          # 主说明:名称、触发条件、功能概述

├── rules/            # 规则与流程文档

│   └── sops.md       # 标准作业流程

├── templates/        # 模板与示例

│   └── report.md     # 输出模板

├── scripts/          # 脚本与工具

│   └── analyze.py    # 自定义分析脚本

└── references/       # 参考资料

    └── docs.md       # 领域知识

SKILL.md 最关键——它决定了模型在什么场景下自动加载这个 Skill,以及加载后应该遵循什么规则。

Skill vs MCP Tool

SkillMCP Tool
粒度完整领域能力包单个函数/工具
内容流程+知识+工具+模板一个 API 调用
定义者用户自己设计第三方服务提供
典型大小数百行文档+脚本几十行 JSON Schema

Skill 是"生产线",MCP Tool 是"螺丝刀"。Agent 需要两者都用。


五、Function Calling & MCP — 让 LLM 突破文字边界

LLM 的根本限制

LLM 只能输出文本。不能执行代码、不能读写文件、不能调用 API 获取实时数据、不能控制任何外部系统。如果没有任何扩展,它就是个"纯文字生成机"。

Function Calling(函数调用协议) 就是为此诞生的:让 LLM 在需要时输出一段结构化的 JSON "指令",由外部代码真正执行,再把结果反馈给模型。

Function Calling 的完整流程

以"查北京天气"为例:

Step 1:定义工具。 开发者把工具的"说明书"传给模型——函数名、功能描述、参数类型和说明。description 是关键——模型根据这段文字判断"什么时候该调哪个工具"。

Step 2:LLM 输出调用指令。 用户问"北京今天天气怎么样?"模型的回应不是自然语言,而是一段 JSON:

{"name":"get_weather","parameters":{"city":"北京","unit":"celsius"}}

Step 3:外部代码执行工具。 代码解析 JSON,真正调天气 API。

Step 4:结果注入 Context,再次调用 LLM。 把工具结果写入对话历史,重新发给 LLM。

Step 5:LLM 基于真实数据生成回答。 "北京今天晴,22°C,湿度 45%。"

关键认知:LLM 自己什么都没执行——它只是输出了一段 JSON,外部系统帮它完成了真正的动作。

LLM "决定"调哪个工具的机制

LLM 没有专门的"决策模块"。它的决策和生成文字完全一样——预测下一个 Token。训练时,OpenAI/Anthropic 给了模型大量"什么时候该调工具"的示例数据,模型学会了:Context 里有工具列表+用户问实时信息 → 下一个 Token 大概率是 {"name":...} 而不是自然语言。

本质上,LLM 只是在"续写"一段包含工具调用格式的对话,和写普通文字没有区别。

多工具串联:Agent 的雏形

用户:"帮我查北京和上海的天气,然后推荐周末去哪个城市。"

  • Round 1:LLM 调用 get_weather(city="北京")
  • Round 2:结果注入 Context,LLM 调用 get_weather(city="上海")
  • Round 3:两个结果都在 Context 里,LLM 综合生成推荐

这种模式就是 Agent 的雏形——LLM 自主规划多个步骤,逐步完成目标。

MCP:不只调用,还要"连接"

Function Calling 解决了"怎么调"的问题。MCP(Model Context Protocol,模型上下文协议)解决的是"怎么连"——它是 AI 应用的"USB-C 接口",给 AI 提供标准化的方式去连接外部数据源和工具。

FC 和 MCP 的分层关系:

应用层:Agent 编排(做什么任务、调什么工具、什么时候停)

   ↓

协议层:Function Calling(模型怎么决定调工具)

   ↓

连接层:MCP(怎么连上工具 — 工具发现、连接管理、权限控制)

   ↓

执行层:实际工具(数据库、搜索引擎、文件系统...)

核心结论:FC 和 MCP 不是竞争关系。FC 是"调用方式",MCP 是"连接协议"——两者分层协作。

MCP 的核心价值:
- 标准化:所有工具通过同一协议接入,不用为每个工具写定制代码
- 工具发现:新工具上线后自动出现在模型可用的工具列表中
- 安全性:统一管理认证、授权和数据流,避免每个工具各自实现安全逻辑


六、Agent 设计 — 让 LLM 从"问答机器"变成"执行者"

什么是 Agent

纯 LLM 是一个"问答机器":一问一答,不能主动做事。

Agent 在 LLM 之上加了一个执行循环(Agent Loop)

用户目标

  → 思考(LLM:我现在要做什么?)

  → 行动(调用工具,外部执行)

  → 观察(工具结果注入 Context)

  → 判断(LLM:目标完成了吗?)

  → 没完成 → 继续循环

  → 完成 → 输出结果

核心差异:

纯 LLMAgent
交互方式一问一答自主多步执行
工具使用可调用任意工具
状态保持单次对话跨步骤追踪状态
主动性被动响应可自主规划和执行
错误处理重试/切换方案

LLM 在 Agent 中扮演什么角色

LLM 是 Agent 的"大脑",工具是"四肢"。

LLM 具体负责:意图理解(把自然语言拆成可执行计划)、工具选择(决定调哪个工具传什么参数)、结果解读(理解工具返回内容并判断下一步)、错误处理(工具失败时决定重试还是换方案)、任务完成判断。

关键认知:LLM 每次只处理当前 Context 内的信息。 它看不到"过去做了啥"——只能看到被注入 Context 的工具结果和对话历史。Agent 框架的核心工作之一就是把每步的工具结果正确地写入 Context,让 LLM 能"记住"已做过什么。

Claude Code:一个实战 Agent 解剖

Claude Code 是 Anthropic 官方的命令行 AI 编程助手,采用工具增强的 Agent 架构。LLM 被放进一个循环里持续决策和执行。

一个完整任务链路("帮我把这个函数改成异步的"):

1. LLM 决策:先读文件 → 调用 Read 工具

2. 文件内容注入 Context → LLM 理解代码结构,规划方案

3. LLM 决策:修改函数 → 调用 Edit 工具

4. 修改结果注入 Context → LLM 检查是否需要同步改调用方

5. LLM 决策:搜索调用处 → 调用 Grep 工具

6. 搜索结果注入 Context → LLM 逐一修改调用方

7. LLM 决策:验证 → 调用 Bash 运行测试

8. 测试结果注入 Context → 通过,任务完成

每一步 LLM 做的事都是:理解当前状态 → 决定下一步 → 解读结果 → 继续或结束。

权限分级机制:读操作自动执行、写操作需确认、危险命令(rm -rf/force push)永远需确认。Agent 越自主,确认机制越要严格——这是 Human-in-the-loop 的核心实践。

OpenClaw:多平台 Agent 网关

OpenClaw 是开源的个人 AI 助手网关,核心理念是"你在哪里聊天,AI 就在哪里"。它把 Claude/GPT/Gemini 接入 WhatsApp、Telegram、Slack 等日常 IM 工具。

LLM 在 OpenClaw 中有三个角色:
- 对话者:理解用户语言,生成回复
- 工具调度员:决定何时调搜索/代码执行等工具
- 内容生成器:基于工具返回的真实数据组织最终回答

LLM 可热切换:主模型失败时自动换备用模型——LLM 对 Agent 层透明。不同 Agent 可配不同 LLM(个人助手用 Opus、编程助手用 Sonnet)。

Agent 设计的四个关键原则

原则一:Human-in-the-loop。 高风险操作必须人工确认。Claude Code 的权限分级是最佳实践——Agent 越自主,确认机制越要严格。

原则二:工具边界即能力边界。 Agent 能做什么,完全由工具决定。设计 Agent = 设计工具集 + 设计权限边界。

原则三:失败是常态,容错是必须。 工具调用在生产环境中有不可忽视的失败率。需要重试机制、降级策略、人工介入触发点。

原则四:Context 是稀缺资源。 长任务中 Context Window 会耗尽——要在耗尽前主动压缩历史、提炼关键信息,而不是等溢出再处理。


七、ReAct — AI 的"思考-行动"循环

ReAct = Reasoning + Acting

ReAct 是一个推理框架,核心很简单:不只是在脑子里想,而是想一步、做一步、看结果、再继续想。

Thought: 我需要查北京天气

Action: call get_weather("北京")

Observation: 北京今天 22°C,晴

Thought: 还需要查上海天气

Action: call get_weather("上海")

Observation: 上海今天 26°C,多云

Thought: 北京 22 度晴天更适合出游

Final Answer: 推荐去北京

ReAct 的每次"思考"和"行动"都写入 Context,形成了驱动的执行力。它是几乎所有现代 Agent 框架(LangChain、AutoGPT、Claude Code)的基础循环。

为什么 ReAct 比纯 CoT 更好

纯 CoT:只在"脑子里"想。对于需要真实世界信息(天气、搜索结果、文件内容)的任务,空想解决不了问题。

ReAct:想一步 → 拿到真实数据 → 基于真实数据再想下一步。幻觉大幅降低,因为每一步的推理都建立在工具返回的真实数据上。


八、SDD — 规格驱动开发

为什么必须 SDD

直接让 AI "帮我做一个登录功能",就像找了个外包但只给一句话。纯 Prompt 驱动的 AI 开发有三个致命问题:

  1. 需求漂移。AI 不知道你的约束——"这个接口不能改已有签名""这个错误码要跟前端约定好"。它按自己理解写,你改一遍它重写一遍,3 轮以后代码越来越乱。
  2. 历史逻辑丢失。上一轮说好"用 JWT + refresh token",下一轮改了路由逻辑,AI 可能悄悄切回 session。没有规格锁住决策历史,每次对话都是一次"重来"。
  3. 验收无依据。代码写出来了,你怎么判断它对不对?靠肉眼扫一遍吗?没有规格就没有自动化验收,没有自动化验收就等于每次上线都是凭运气。

SDD 就是解决这三个问题的:先写规格文档 → 确认规格 → AI 按规格实现 → 按规格验收。

SDD 的完整生命周期

需求输入

    ↓

┌─────────────────────────────┐

│  第一步:规格编写(Human)    │

│  - 明确需求目标和范围          │

│  - 定义系统行为(正常+异常)    │

│  - 声明设计约束和边界          │

│  - 拆分任务和验收标准          │

└─────────────┬───────────────┘

              ↓

┌─────────────────────────────┐

│  第二步:规格确认(Human+AI)  │

│  - AI 审核规格完整性           │

│  - 发现边界情况和遗漏          │

│  - Human 确认最终规格 ← 关键   │

└─────────────┬───────────────┘

              ↓

┌─────────────────────────────┐

│  第三步:AI 按规格实现        │

│  - 严格按步骤执行              │

│  - 不能修改规格里没说的东西    │

│  - 每一阶段代码对照验收标准    │

└─────────────┬───────────────┘

              ↓

┌─────────────────────────────┐

│  第四步:自动化验收           │

│  - 按规格中的验收标准逐条检查  │

│  - 通过 → 合并 / 不通过 → 退回 │

│  - 形成版本级的可追溯记录      │

└─────────────────────────────┘

每一步的决策权在哪? 第一步和第二步的确认是 Human 的——你定规格方向和最终拍板。第三步和第四步是 AI+自动化系统执行的——AI 写代码,自动化验收,Human 只需要看最终结果。这才是人机协作的正确分工。

怎么写一份好规格

好规格给 What(要什么),不给 How(怎么实现)。举一个具体例子——做一个"用户提现"功能:

差的规格(一句需求)

做一个提现功能。

AI 不知道:限不限额?手续费?支持什么方式?要什么校验?——写出来基本等于随机。

好的规格(结构化需求)

目标:做一个提现功能

范围:

  - 只支持微信零钱提现(暂不支持银行卡)

  - 单笔最低 1 元,最高 50000 元

  - 每人每天最多提现 3 次

  - 手续费:1000 元及以下收 2 元,以上收 0.1%

系统行为:

  正常路径:

    1. 用户发起提现请求(金额+微信 openid+备注)

    2. 校验余额足够、额度不超、次数不超

    3. 冻结资金

    4. 调用微信支付企业付款接口

    5. 微信返回成功 → 扣减余额 + 解冻 + 写入账务流水

    6. 推送提现成功通知

  异常路径:

    - 余额不足 → 返回错误码 BALANCE_NOT_ENOUGH + 当前余额

    - 微信接口超时 → 标记为"处理中",走异步对账

    - 微信回调失败 → 进入人工审核队列,冻结资金不解冻

    - 今日提现次数已满 → 返回错误码 DAILY_LIMIT_REACHED + "明日00:00重置"

设计约束:

  - 不修改现有 account 表的提现相关索引

  - 账务流水使用现有的 ledger 模块写入,不新建表

  - 敏感操作日志写入 audit_log,必须包含:操作人ID、时间戳、金额、目标 openid 前 4 后 2 位

任务拆分:

  1. 新建 withdraw 模块(controller + service + model)

  2. 实现提现校验逻辑(余额/额度/次数)

  3. 对接微信支付企业付款

  4. 实现账务流水记录

  5. 实现异步对账逻辑

  6. 单元测试覆盖正常+异常路径

验收标准:

  - 所有正常路径单元测试通过

  - 所有异常路径单元测试通过

  - 微信支付 mock 下端到端验证通过

  - 并发场景下不会出现重复扣款(幂等校验)

  - API 响应时间 < 500ms(不含第三方接口超时)

这份规格写下来大概花了 10 分钟,但它做到了三件事:

  1. AI 不再猜。范围明确了"只支持微信零钱、不支持银行卡",AI 就不会自作主张加银行卡提现。
  2. 异常路径被穷举。最有价值的部分——余额不足、超时、回调失败——不是让你自己想,是你让 AI 知道的。漏了异常路径,上线就是事故。
  3. 验收可自动化。验收标准是具体的、可执行的——跑测试就能验证,不用人肉点一遍界面。

SDD 的四个常见陷阱

陷阱一:规格写太细。

把实现细节也写进规格——"先用 Python 的 decimal 库做金额计算,再调 WxPayService.transfer() 方法"——等于人先把代码在脑子里写了一遍,失去用 AI 的意义。

怎么判断太细了?记住一句话:如果你的规格里出现了具体的函数名、类名、变量名、数据库表的字段名,你大概率在替 AI 做它的工作。 除非这些是"不能改的约束"(比如不能改已有的 account 表索引),否则不应该出现在规格里。

陷阱二:规格写太粗。

只写一句"做个提现功能",给 AI 留一个 90% 的模糊空间——它只能用训练数据里最常见的"提现实现"来填这个空,而那个最常见的实现大概率跟你的系统长得不一样。

好规格给出边界。边界不是限制 AI,是保护你自己——你给 AI 画了一个圈,它可以在圈里尽情发挥,但不会跑出圈外把你已有的系统搞崩。

陷阱三:规格写了不验。

SDD 的真正威力在于"按规格验收"。规格里写的异常路径有 5 条、验收标准有 5 项——如果没人验证 AI 的输出是否符合这 10 条,规格就只是一份被忽略的文档。AI 生成代码后需要自动化规格符合性检查。

陷阱四:把 SDD 当成"写一次就完了"。

需求是会变的。SDD 不是瀑布模型里的"需求文档"——签完字就放冰箱里不动。SDD 规格是活的:需求变了 → 先改规格 → 确认 → 再让 AI 改代码。规格和代码始终一致,这是 SDD 对比"直接改代码"的最大优势——代码改了不看规格是什么,但规格为什么要改、怎么改的,你都留下了完整版本记录。

SDD 在 Agent 时代的真正角色

很多人把 SDD 理解成"写需求文档让 AI 写代码"——这只是最表层的用法。在 Agent 时代,SDD 的真正角色是稳定 Agent 行为的工程锚点

Agent 不是简单的代码生成器。它是一个自主的、多步执行的角色——它会调用工具、读写文件、发送网络请求、创建/删除数据库记录。一个每分钟可以执行几十个真实操作的 Agent,如果它的行为边界没有被规格锁死——它可能改错文件、删错数据、发错 API 请求。

SDD 在 Agent 场景下多了一层含义:给 Agent 的操作行为设定约束边界。

你把规格发给 Agent:

约束:

  - 只允许修改 src/modules/withdraw/ 下的文件

  - 数据库操作只允许 INSERT 到 withdraw_record 表,不允许 DELETE 任何记录

  - 调用外部 API 前必须经过 Human 确认

Agent 在 ReAct 循环里每做一个操作之前,先检查是否违反规格约束。这不是"让人多写点文档"的官僚主义,这是在用工程手段控制 Agent 这种"有能力但不够可靠"的系统的风险。

当你把 SDD 从"给代码生成器看的需求文档"升级为"给 Agent 看的操作约束"时,规格就从一个静态文档变成了一个实时生效的运行时规则引擎。

总结

SDD 的价值不是写一份漂亮的文档,而是完成了两件事:

  1. 降低 AI 的不确定性。 规格缩小了 AI 发挥的自由度,让它在你的系统边界内工作。
  2. 降低 Humans 的认知负荷。 你不需要在跟 AI 的每一轮对话里重复所有约束——规格一次写好,AI 每次执行前都读一次,相当于你请了一个永远记得所有边界条件的程序员。

它的额外收益是追溯和问责——别人问你"为什么这个系统要做一个提现功能",你不需要用脑子回忆,规格本身就是一个完整的、被批准过的技术决策记录。出问题的时候,查规格就知道什么时候做的决定、谁批准的、为什么这么设计。这是软件开发里最稀缺的东西——不是代码,是决策记录。


九、模型路由 — 用便宜的模型处理简单任务

不是所有问题都需要最强模型

一个用户问"你好"也要调 GPT-4 回答——这是浪费。模型路由的核心思想:根据问题复杂度,把请求发给不同级别的模型。

三种路由策略

静态路由(规则路由)。 关键词匹配——看到"解释一下""定义一下" → 小模型。看到"分析""推理""编程" → 大模型。简单但灵活度不够。

LLM-as-Judge 路由。 用一个便宜模型先"看"问题,判断复杂度,再决定发给谁。比静态路由灵活,但判断本身偶尔会出错。

级联路由。 先调小模型 → 生成结果 → 用一个验证器评估质量 → 质量不达标 → 升级到大模型重跑。质量最好,但延迟最高(可能跑两遍)。

好的路由策略:在效果打九五折的同时,成本降到三分之一。没有 AI 系统需要所有请求全量发给最贵模型。


十、评测 — 怎么知道 AI 系统真的"好"

基准测试和真实场景是两个世界

模型在 MMLU 上拿 90% 不代表在生产环境能稳定工作。你的真实用户可能在凌晨三点用方言问会计问题——跟 MMLU 上的标准化选择题完全没有关系。

四层评测体系

第一层:能力评测(Benchmark)。 MMLU(通用知识)、HumanEval(代码)、GSM8K(数学)——快速知道模型的"基础素质"。成本低,跟你的业务场景可能毫不相关。

第二层:场景评测(Domain Eval)。 用你的业务数据构造评测集。比如你的客服系统场景:用户问"怎么开发票"、用户投诉"商品质量问题"——评测模型在这些真实场景下的表现。

第三层:LLM-as-Judge。 用一个大模型评估另一个模型的输出质量。不是单模型打分(自评失真),而是"交叉评委"——用 Claude 评 GPT 的输出,用 GPT 评 Claude 的输出。关键:给 Judge 明确的评分维度和 rubric,而不是模糊地问"这个回答好不好"。

第四层:线上评测(Online Eval)。 最终指标:用户满意度、任务完成率、转人工率。基准测试再高、离线评测再准,线上不行的系统就是不行。

Harness 的评测工具

lm-evaluation-harness(EleutherAI 开源)是当前最主流的评测框架,支持 200+ 基准测试统一跑分。但它的局限性也很明显:测的不是你的业务场景、模型可能在预训练时见过评测数据(数据污染导致虚高)。

自建评测体系六步法:收集真实用户问题 → 标注标准答案 → 构造不同难度级别 → 自动化跑分 → 人工抽查边缘 Case → 持续更新评测集(每周加新问题)。


写在结尾

下篇讲完了从 Prompt 到 Agent 的完整工程全景。三部曲到此结束。

回顾这三篇:

上篇讲了 AI 的"基础心脏"——Token 怎么分词、Embedding 怎么把文字变数字、Attention 怎么理解上下文、预训练怎么压缩知识。

中篇讲了"怎么训练"——SFT/RLHF/DPO 把模型从续写机器变成有用助手,Reasoning/CoT 激活思考能力,后训练收尾,MoE+蒸馏+Infra 让它便宜,幻觉是贯穿始终的工程挑战。

下篇讲了"怎么落地"——Prompt/Context/Harness 三层工程体系层层递进,Skill 封装能力,FC+MCP 突破文字边界,Agent+ReAct 实现自主执行,SDD 规格化开发,模型路由降本增效,评测体系守住质量底线。

一条完整的知识链:

看懂文字(上)

  → 学聪明(中)

    → 能干活(下)

AI 工程的核心竞争,不是"谁接入的模型更强",而是谁更早建立起一套成熟的工程体系——它知道该给模型看什么,允许模型做什么,要求模型如何验收结果,又在失败时如何把它拉回正轨。

提示语工程解决"说清楚",上下文工程解决"给对信息",Harness 工程解决"稳定执行"——三层缺一不可。


三部曲完。共 24 个核心概念,覆盖从 Token 分词到 Agent 落地的完整 AI 工程知识体系。