让一次 LLM 调用跑起来很容易。让五个智能体在生产环境里可靠协作,是完全不同的问题。真实用户会打破假设,真实成本会迅速累积,真实故障会以本地环境里看不到的方式级联。
核心差异在于 harness。
这篇指南覆盖完整的工程图景:什么是 Agent Harness,它由哪些组件构成,如何设计支撑它的后端,以及如何把一个能跑的系统优化成生产级系统。
- Agent Harness
1.1 它是什么
Agent Harness 是把语言模型包成可用系统的基础设施层。它不是模型,也不是提示词。它是一层支撑结构,用来回答模型本身无法回答的问题:
- 智能体步骤之间的工作产物放在哪里?
- 每个智能体能看到什么上下文,又被明确禁止看到什么?
- 多个智能体如何协作,避免互相踩到对方的上下文窗口?
- 智能体产出坏结果,或者调用失败时怎么办?
- 成本如何追踪、设限和控制?
LLM 是推理引擎。Harness 是让它变得可用的系统。每一个严肃的智能体部署都有一个 harness,只是有些是显式设计出来的,有些是在迭代中偶然堆出来的。显式设计的版本更快、更便宜,也更容易调试。
1.2 五个组件
一个设计良好的 harness 由五个概念组合而成。每个概念都对应生产环境里运行智能体时会暴露出来的一类失败模式。
这五个组件是:
- Orchestrator:读取 brief,按顺序分派任务,验证完成情况,报告任务结束。
- Subagents:隔离的执行上下文,每个上下文只负责一个任务和一个输出产物。
- Skills:每个智能体自己的知识文档,用来定义角色、输出格式和规则。
- Backend:承载共享虚拟文件系统的状态层,智能体通过它在步骤之间传递工作产物。
- Context Engineering:控制每个智能体看见什么、什么时候看见、以什么顺序看见的工程纪律。
理解每个组件为什么存在,比记住 API 更有用。理解这些原因,后面的设计决策才更容易扩展。
- 后端
后端是 harness 的状态管理层。它回答每个多智能体系统都必须回答的问题:工作产物放在哪里?
2.1 用消息传状态的问题
最直观的做法,是通过对话消息传递智能体输出。Agent A 产出结构化洞察并返回。Orchestrator 保存这段响应,再把它作为消息内容传给 Agent B。
这会带来三个叠加的问题。
- 上下文膨胀。Orchestrator 线程里的每条消息,都会在后续每次调用中消耗 token。四个智能体运行完并把输出回传后,orchestrator 会携带几千个 token 的内容,而这些内容往往只有下一个智能体需要。任务结束前,每次调用都会为这些历史内容付费。
- 缺少检查界面。想看 Agent A 产出了什么,只能解析 orchestrator 的对话历史。调试会变成在推理轨迹里翻找内容。
- 耦合。Agent B 的行为依赖 Agent A 的响应以某个精确格式出现在对话里。Agent A 的输出 schema 一变,Agent B 就会坏掉。这种耦合在失败前通常不可见。
2.2 虚拟文件系统
StateBackend用虚拟文件系统解决这三个问题。它为每个任务提供一个内存中的工作区,作用域只覆盖本次运行。
智能体之间不通过消息传递内容。它们把文件写入工作区,再从工作区读取文件。
一个五智能体流水线的典型工作区,会在任务开始时预置一个brief.md,这是唯一输入。之后每个智能体各写一个文件:提取出的洞察、各个平台的草稿、最终审查笔记。提取器完成后,写入自己的输出文件,并用一句话确认。Orchestrator 的线程里只保存这一行确认,不保存内容。下一个智能体运行时,直接从文件读取。
这一个改动,就能让五智能体流水线中 orchestrator 的累计上下文减少大约 85%。每个中间产物都可以检查。智能体之间也被解耦:每个智能体按路径读文件,而不是按消息位置读内容。
2.3 预置文件与组装结果
工作区一开始是空的。在 orchestrator 运行前,把流水线需要的所有内容预先写入工作区:skill 文件、共享上下文文档,以及本次任务的 brief。这样可以把文件系统准备和智能体运行分开。第一次 LLM 调用发生前,工作区已经被完整定义。
流水线结束后,再读取工作区来组装结构化结果。这是调用方代码唯一读取文件内容的地方。
最佳实践:在流水线运行期间,orchestrator 代码不要读取工作区内容。Orchestrator 只根据文件是否存在来推断进度。内容只在最后读取一次。
2.4 从工作区推断进度
基于文件的工作区有一个容易被低估的性质:你可以通过哪些文件已经存在来推断流水线进度。智能体代码不需要显式进度回调。工作区状态就是进度状态。
- Skills
3.1 Skill 是什么
每个智能体都有一个具体任务。任务说明定义产出内容、输出格式和执行规则。这些内容写在 Skill 文件里。Skill 是 Markdown 文档,会和系统提示词一起加载到智能体上下文中。
关键设计决策是渐进式披露:每个智能体只加载自己需要的 skill。
把所有智能体的所有 skill 都塞进上下文,是一种常见但错误的做法,原因有两个。
Token 成本。Skill 是每次调用都会加载的静态上下文。一个 X 写作智能体如果加载了 LinkedIn 格式说明,就会在每次运行时为这些无关 token 付费,而且它们不会贡献到输出。
注意力退化。模型有时会应用错误上下文里的指令。一个智能体带着自己不需要的指令,就有一定概率被这些指令影响。无关上下文越多,问题越明显。
每个智能体明确声明自己加载哪个 skill。Skill resolver 只加载匹配的文件。五个智能体,五个 skill。每个智能体只看见自己的那一份。
3.2 工具作用域遵循同一原则
工具是 skill 概念的延伸。它们同样会增加 token,因为工具定义计入输入;也会增加行为表面积。
只给智能体它真正会用到的工具。审查智能体拿到事实核查工具,并且只有它负责验证外部声明。其他智能体不需要这个工具。不能调用外部 API 的写作智能体不应该拿到任何工具。一个用不上的工具只是开销:付了 token,增加了行为风险,没有收益。
最佳实践:一个智能体的 skill 和工具集合,应该压到完成具体任务所需的最小范围。只有在任务明确需要时再扩大作用域。
- 子智能体与隔离上下文
4.1 共享上下文窗口为什么会失败
如果把多智能体流水线跑在同一个对话线程里,每个智能体都会累积完整历史。等审查智能体运行时,它会带着 orchestrator 的计划推理、每个写作智能体的输出确认,以及修正过程里的所有来回消息。你会为这些 token 付费。质量也会下降,因为审查智能体在一堆与自己任务无关的内容里做推理。
4.2 子智能体在隔离环境中运行
每个子智能体都运行在独立会话中:自己的系统提示词、自己的 skill,以及它从工作区明确读取的内容。
Orchestrator 维护一份扁平的智能体描述列表。需要分派时,它根据描述选择智能体。子智能体在自己的上下文里运行,完成工作后写入工作区,然后这个上下文被回收。
成本差异很明显。一个五智能体流水线如果完全跑在共享线程里,到最后一步会累计 15,000 到 30,000 个历史 token。使用隔离子智能体时,每个智能体的上下文保持在 2,000 到 5,000 个 token。Orchestrator 的线程也保持轻量,因为它累积的是文件路径和单行确认,不是内容。
最佳实践:每个子智能体只在工作区产出一个文件。一个任务,一个文件。这样进度追踪简单,输出也容易检查。
- 上下文工程
上下文工程是控制什么进入智能体上下文窗口、什么时候进入、以什么顺序进入的工程纪律。它对成本和质量的影响,超过其他大多数工程决策。
5.1 静态内容先于动态内容
这是基础规则,必须无例外遵守。
静态内容是许多请求中完全相同的内容:系统提示词、skill 文件、工具定义、共享上下文文档。动态内容是每次请求都会变化的内容:任务 ID、用户输入、时间戳、本次任务参数。
正确顺序是:工具定义最先,因为最稳定;然后是系统提示词;然后是 skill 文件;然后是对话历史;最后是当前用户消息,也就是完全动态、永远无法缓存的部分。
模型服务商提供的 prompt caching 会缓存从前缀开始直到第一个动态内容之前的计算结果。缓存读取成本是正常输入价格的 10%。缓存未命中则按 100% 计费。
任何违反“静态先于动态”的做法都会破坏缓存前缀。常见问题包括:把任务 ID 或时间戳放进系统提示词,把用户特定数据嵌进 skill 文件路径,把环境特定 flag 放进系统消息,或者在请求之间改变工具定义。修正方式始终一样:把动态值移到用户消息里。
5.2 持久记忆与单次任务上下文
不是所有上下文都会以同样速度老化。
持久记忆是每个任务都稳定不变的内容:项目约定、行为指南、智能体如何处理边界情况。它应该放在共享文档里,在构建执行图时作为 memory 加载。每个 worker 进程只计算和缓存一次。
单次任务上下文是任务特定内容:用户的 README、请求的平台、语气要求。它应该放在任务开始时预置到工作区的 brief 文档里,作为流水线唯一的动态输入。
判断某段上下文应该放在哪里,可以问一个问题:它在 1,000 个不同任务中是否完全相同?如果是,它是持久记忆。如果会随任务变化,就应该放进 brief,绝不应该出现在系统提示词里。
5.3 线程压缩
长时间运行的流水线会让对话线程变长。旧轮次通常不如最近轮次相关,但仍然会在后续每次调用中消耗 token。
线程摘要中间件可以自动处理这个问题。当线程超过可配置的 token 阈值时,较早轮次会被压缩成摘要段落,最近 N 条消息保持原文,因为近期上下文最相关。
最佳实践:不要把摘要阈值设得太低。在上下文容量的 80% 处做摘要,能给智能体留下工作空间,又不会频繁压缩。40% 就开始摘要,会把 token 浪费在摘要开销上。
- Orchestrator
6.1 协调,而不是执行
Orchestrator 只负责一件事:读取 brief,按顺序分派任务,验证完成情况,报告结束。
它明确不产出内容。这是硬性的架构约束,不是建议。
Orchestrator 拥有系统里最宽的上下文。如果它开始推理领域任务,比如写内容、做事实判断、格式化输出,可能产出勉强可用的结果,但会付出几个代价:长推理轨迹填满上下文窗口,协调角色和领域角色混淆,并绕过子智能体实现的质量控制。只要 orchestrator 想产出领域内容,就说明设计里少了一个子智能体。
6.2 构建一次,持续复用
Orchestrator 的构建成本很高:从磁盘加载 skill 文件、初始化模型客户端、编译 graph。应该在进程级缓存它。每个 worker 构建一次,然后在所有任务之间复用。
一个 worker 每小时处理 40 个任务,只需要构建一次 graph,然后复用 40 次。模块级单例是 Python 里最简单也最可靠的模式。
6.3 在提示词中强制流水线不变量
Orchestrator 的系统提示词用来固化流水线规则:只生成 brief 中列出的平台,始终最后运行验证,把任务 ID 明确传给每个子智能体,永远不要直接写草稿文件,报告完成前确认文件存在。
这些是协调规则,不是提示。要写得明确、直接。Orchestrator 的提示词应该像技术运行手册,而不是创意 brief。
- 缓存栈
智能体系统里的缓存比传统应用更有杠杆,因为你可以在多个层级避免工作。每一层的成本节省、命中率和实现复杂度都不同。
7.1 第一层:Provider prompt caching
Anthropic 的 prompt cache 会缓存稳定提示词前缀的 KV tensor 计算结果。后续请求如果前缀完全相同,就以正常输入 token 价格的 10% 从缓存读取。
前提是严格遵守静态先于动态的顺序。Cache control 可以透明地应用在每条 system message 上,调用点不需要改变。
工程师容易漏掉几个约束:最低 token 阈值是 1,024。低于这个阈值的内容会静默缓存失败,没有错误、没有警告,只会缓存未命中并按全价计费。工具定义变化会让整个缓存层级失效。每个请求最多只能设置四个 cache breakpoint。
7.2 第二层:Redis LLM 响应缓存
Prompt caching 降低 token 成本,但不会消除 API 延迟,因为你仍然要发 HTTP 请求并等待响应。Redis 响应缓存位于 API 上游:命中时没有 HTTP 调用、没有 API 延迟,也没有 token 成本。
系统中的每一次 LLM 调用,包括 orchestrator 和所有子智能体,都会在发起 API 调用前先检查 Redis。缓存 key 是完整序列化消息列表与模型配置的哈希。把模型配置放进 key,意味着模型升级会自动生成新 key。
提示词变更时要给 key 加版本。没有版本管理时,坏提示词会被缓存并在几个小时里持续返回。部署时提升版本号,就能在不直接操作 Redis 的情况下刷新整层缓存。
TTL 按环境设置:开发环境 5 分钟,提示词编辑可以马上看到;预发环境 1 小时,足够稳定,可以捕获回归;生产环境 24 小时,最大化节省成本。
7.3 第三层:内容身份缓存
在一些系统里,同一份源材料会反复出现,比如不同用户提交同一个热门开源仓库,同一份文档被多次处理。内容身份缓存可以直接跳过最昂贵的流水线步骤。
对原始源内容做哈希。同一份文档即使用户指定参数不同,也会落到同一个 key,因为源内容相同。这层缓存基于内容身份,不基于提示词身份。命中时完全绕过 LLM:没有 API 调用、没有 token、没有延迟。TTL 可以更长,对大多数内容来说,七天也合理。
- Token 优化
Token 是 LLM 系统的成本单位。每一处低效都会在每个用户、每个请求、每次重试中累积。
8.1 执行前先估算
不要在没有估算 token 成本的情况下运行任务。一个粗略估算器可以用字符数除以四,这是英文文本的可靠近似值,再加上 skill 和上下文文件的固定开销。每个任务都记录这个估算。生产流量跑一周后,你会得到真实的 P50/P95 数据。这些数字能让你基于事实设置告警阈值,而不是猜。
8.2 在边界处校验并截断
输入进入队列前先校验大小。输入过大时优先截断,而不是拒绝。有些用户输入很长,但仍然应该得到结果,只是结果来自信息密度最高的部分。
截断要贴到结构边界上,比如段落换行或小节标题,避免把半句话传给模型。追加截断标记,让模型知道文档不完整。
8.3 按任务路由模型
流水线里的每个智能体不一定都需要最强、最贵的模型。从 Markdown 文档中做结构化抽取,小模型就能处理得很好。涉及多文档交叉引用和判断的任务,则更适合强推理模型。
把便宜模型路由给抽取、分类和格式校验。把强模型留给最终审查和复杂多步推理。如果设计正确,总流水线成本可以降低 40% 到 60%,整体输出质量不下降。
- 异步任务架构
9.1 为什么需要任务队列
非平凡智能体流水线通常需要 45 到 120 秒。HTTP 连接默认 30 秒就会超时。即使不超时,为每个活跃任务占着一个连接也很浪费资源。
正确架构是:立即接受请求,返回任务 ID,异步运行流水线。客户端轮询状态。Worker 完成后立刻把结果写入快速存储。轮询循环的总开销只有毫秒级。
9.2 用 Celery 处理 LLM 工作负载
LLM 任务是 I/O 密集型,不是 CPU 密集型。Worker 线程大部分时间都在等待 API 响应。这意味着并发数可以远高于 CPU 核数。geventpool 使用协作式多任务,线程在等待 I/O 时让出执行权,让其他任务运行。对于 4 核机器,如果每个任务 70% 到 80% 的时间在等 API 响应,同时跑 32 个 LLM 任务是合理的。
9.3 双存储模式
Redis 快,但不适合作为持久事实来源。Postgres 持久,但访问更慢。两者应该负责不同用途。
Redis 处理实时轮询场景,比如客户端每隔几秒检查状态,需要亚毫秒级响应。Postgres 处理历史场景:用户任务历史、计费、调试昨天的任务。
写入模式:每次状态变化都同时写入两边。读取模式:先查 Redis,如果 key 已过期,再回退到 Postgres。不要把 Redis 当成事实来源。TTL 过期是静默发生的。
- 开发工作流
10.1 先用本地模型,再用云模型验证
通过让 harness 接受任何 LangChain 兼容模型,把开发迭代和成本分开。开发阶段使用本地 Ollama 模型,免费、快速,也不需要 API key。
本地输出质量低于前沿模型。但它足以验证文件是否写入正确的工作区路径、orchestrator 是否按正确顺序分派任务、结果组装是否把工作区文件解析成预期结构,以及错误处理是否按设计运行。
当某个 skill 文件变化需要做质量验证时,切到云厂商跑一次测试。跑完立刻切回本地。这样提示词和 skill 开发的迭代成本基本为零。
10.2 测试 harness,而不是测试模型
Agent Harness 的单元测试应该测试 harness 行为,而不是模型输出。模型是不确定的,harness 不是。
应该测试的内容包括:工作区初始化是否产生预期文件结构,结果组装是否正确读取每种文件类型,token 估算是否对已知输入返回正确总量,截断是否正确贴到段落边界,缓存 key 生成是否确定,状态转移是否遵循定义好的合法转移图。
不应该在单元测试层面测试模型是否产出好内容。那属于使用真实模型的集成测试,应该定期运行,而不是每次提交都跑。
- 可观测性
LLM 系统的可观测性比传统系统更难,因为最重要的失败模式往往是质量退化。没有合适工具时,它是不可见的。慢 API 调用会出现在延迟指标里。智能体产出细微错误内容时,指标未必会告诉你。
11.1 结构化日志
每一行日志都应该可被机器解析。所有日志使用一致字段名,比如任务 ID、状态、步骤、耗时、响应是否来自缓存。这样即使没有结构化日志系统,也可以在完整日志历史里 grep、过滤和聚合。用这种格式,从日志文件里提取 P95 延迟就是一行 shell 命令。
11.2 LLM 调用追踪
结构化日志提供任务级可见性。追踪层提供调用级可见性:完整提示词、响应、实际 token 数、每次调用的延迟,并拆分到首 token 时间和生成时间,以及 orchestrator 与子智能体之间的完整调用树。
当用户报告输出错误时,你可以打开对应任务 ID 的 trace,直接看到哪个提示词产出了问题。没有这层能力,调试幻觉或错误智能体行为基本是在猜。
11.3 缓存命中率是成本信号
要显式追踪缓存表现。LLM 响应缓存命中率突然下降,通常意味着提示词发生了变化:动态值泄漏进了原本静态的区域,模型升级了,或者 skill 文件被意外修改。应该对它告警。这是成本事件,很容易等到账单周期结束才发现。
- 总结:设计原则
这篇指南里的每个决策都来自五条原则。
减少累计上下文。携带更少上下文的智能体更便宜、更快,也更专注。工作区后端、子智能体隔离、线程压缩,都服务于这条原则。
静态内容永远先于动态内容。Prompt caching 是已部署智能体系统里投资回报率最高的优化。它要求每个提示词中静态内容都排在动态内容之前,没有例外。
把知识限定在角色范围内。智能体应该只知道完成自己任务所需的内容。Skills、工具和上下文文件都应该收窄到最小范围。不必要的上下文会消耗 token,也会削弱专注度。
清晰分离职责。Orchestrator 负责协调,子智能体负责执行,后端负责保存状态。这些角色不应该重叠。一旦重叠,调试会明显变难。
花钱之前先估算、校验和设边界。Token 成本会累积。输入校验、执行前估算和硬性上限,可以避免失控支出变成生产事故。
这里描述的基础设施并不炫目,也不会出现在演示里。但它决定了一个智能体是只能在你笔记本上跑,还是能可靠服务真实用户。
- 结语
这篇指南来自另一种视角:你有真实用户、真实成本,系统还必须在凌晨三点你没有盯着的时候正常工作。
这五个组件解决的不是有趣的 AI 问题。它们解决的是枯燥的基础设施问题。而生产系统往往就栽在这些枯燥问题上。
学AI大模型的正确顺序,千万不要搞错了
🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!
有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!
就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋
📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇
学习路线:
✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经
以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!
我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~