直接说结论:Harness Engineering 不是给 AI Agent 加一个壳,而是给 Agent 装上能稳定输出、可被追踪、能融入现有工程体系的那套“轨道”。这篇文章我会用一台云机器走完整条链路,从选机器、配环境、写系统提示词、注册工具、接 MCP,到多 Agent 编排和排障,把 AI Agent 全流程配置这件事彻底讲透。适合正在从“调 API 玩 demo”转向“做生产级 Agent”的开发者,也适合准备 AI Agent 面试、想在简历上写真实项目经验的工程师。
我在做 Agent 开发的前半年,最大的感受就是:模型能力再强,裸奔也是灾难。你不给 Agent 定义边界、不给它工具、不告诉它什么能做什么不能做,它就会在小任务上反复横跳。而 Harness Engineering 要解决的,恰恰就是把大模型的不可控性,约束在可控的工程框架里。这活儿没有银弹,但把一套完整流程跑通之后,你手里就有了可复制的方法论。
1. 先搞清楚 Harness Engineering 到底是什么
1.1 为什么单个模型再强也不够用
很多人一上来就陷入误区,以为选一个参数最大的模型,Agent 的效果就好。2025 年之后,闭源和开源模型的能力差距在快速缩小,真正拉开体验差距的反而是模型外面的那层工程结构。你给模型一个 API Key 和一句“帮我干活”,它大概率会在第 3 步开始编造文件路径,在第 7 步忘记上下文,在第 12 步产生幻觉——这不是模型笨,是你没有给它装配约束系统。
Harness Engineering 的核心思想很简单:把 Agent 当做一个刚入职的员工,你不能只丢给他一个目标,你要给他工位(运行环境)、给他流程手册(系统提示词)、给他工具清单(函数调用与 MCP 服务)、给他汇报机制(日志与追踪)、给他安全边界(权限控制)。这套东西组合起来,就是把大模型从“聊天机器人”变成“能交付结果的执行器”。
1.2 Harness 究竟包含哪几层结构
我自己习惯把 Harness 拆成五层,每一层解决一类问题:
- 环境层:Agent 跑在哪,依赖怎么隔离,资源怎么限制。云端机器还是本地 Docker,差距很大。
- 指令层:系统提示词、角色设定、任务模板、思维链约束,解决“怎么做”的问题。
- 工具层:函数调用、API 封装、MCP 协议、技能(Skills)注册,解决“能做什么”的问题。
- 流程层:任务分解、执行、反思、重试,解决“做得稳不稳”的问题。
- 治理层:日志、追踪、审计、权限、限流,解决“是否可信”的问题。
这五层不是可选组件,而是从零搭一个生产级 Agent 的最小集。你可以在不同阶段选用不同框架,但无论用什么,这五层缺一不可。比如 LangGraph 帮你管流程层,MCP 帮你管工具层,Docker 帮你管环境层,但它们不会自动帮你补全指令层的质量,也不会自动帮你做好治理层。
1.3 一台云机器能承担什么角色
很多人问:我本地电脑也能跑,为什么要上云机器?答案很简单,因为 Agent 不是孤立的聊天窗口,它要调用 API、读写文件、执行代码、访问外部服务,这些操作如果全在本地跑,一是不安全,二是无法 7x24 小时在线,三是没办法做多人协作。一台云机器可以同时充当 Agent 的运行环境、依赖服务宿主、日志收集中心和 API 网关。
实测下来,一台 4C8G 的云主机就能跑起一套完整的多 Agent 系统,包括主控服务、两个子 Agent、一个向量数据库容器和一个日志面板。如果做更重的本地模型推理,才需要升级到带 GPU 的实例。所以先说结论:起步阶段不需要堆配置,4C8G 完全够用,后面我会给出一套完整的选型计算逻辑。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 云机器选型与基础环境初始化
2.1 选型参数怎么定,不盲目堆配置
我见过太多人第一台机器就上了 8C32G + 独立显卡,结果一个月跑下来 CPU 利用率不到 10%。选型不是越贵越好,而是按你的“最大并发”和“运行负载”来倒推。这里给一个简单的计算思路:
- 一个轻量级 Agent 进程:约占 500MB 内存,一个 CPU 核心能扛住 2-3 个并发请求。
- 一个带向量检索的 Agent:需要额外 1GB 内存给向量索引。
- 一个 MCP 服务容器:平均 200-300MB 内存。
- 一个日志采集器:约 200MB 内存。
如果你是个人开发或小团队,目标承载 5 个并发任务,8GB 内存完全够用。CPU 选 4 核以上即可,主要是为了跑多容器时不至于互相抢占。存储方面,40GB 系统盘 + 50GB 数据盘是标配,日志和向量库都放在数据盘上,避免系统盘被写满导致机器卡死。
提示:如果预算有限,优先升内存,其次是磁盘 IO,CPU 反而是最次要的。Agent 系统大部分时间在等待大模型 API 返回,CPU 真正跑满的场景很少。
2.2 基础环境初始化清单
拿到一台干净的 Ubuntu 22.04 云机器后,不要急着装 Docker,先把基础环境理清。我每次初始化都会按这个顺序做:
- 更新系统包并安装常用工具
- 创建专用用户(不建议用 root 跑服务)
- 配置 SSH 密钥登录,关闭密码登录
- 安装 Docker 和 Docker Compose 插件
- 安装 Python 3.11+ 和 Node.js 20+
- 配置国内可用的软件源和 pip 源
- 设置统一的日志目录和数据目录
这些步骤看起来琐碎,但决定了你后面排障的效率。尤其是专用用户和数据目录规划,很多人前期偷懒直接用 root,等到权限问题、路径混乱、日志找不到时,会浪费大量时间。
在实际操作中,我习惯把 Agent 相关的所有服务都通过 Docker Compose 来管理,包括主控、子 Agent、向量数据库、日志面板。这样无论换机器还是迁移环境,只需要把 compose 文件和 .env 配置带走,就能一键拉起全部服务。这也是“一台云机器搞定”的关键——不是单进程在干,而是整套容器编排在干。
2.3 别忽略的安全加固和成本控制
安全加固不是可有可无的操作,Agent 系统里往往持有大量 API Key、数据库密码和内部服务地址,一旦机器被入侵,损失的不是一台机器,而是整条数据链。这里分享几个我踩坑后沉淀下来的底线操作:
- API Key 一律走环境变量或密钥管理服务,绝不写死在代码或配置文件里。Docker Compose 支持从 .env 文件注入环境变量,但 .env 文件一定要加入 .gitignore。
- 云安全组只放开必要端口。SSH 只允许密钥登录,Agent 服务端口只对需要访问的 IP 开放,数据库容器不要映射宿主机端口。
- 启用自动快照或定期备份。数据盘里的向量库和配置文件是核心资产,我会每天凌晨做一次增量备份到对象存储。
- 设置费用告警。云服务商的账单告警一定要开,Agent 系统会因为日志过多、异常容器反复重启造成意外费用,设定月预算的 80% 告警线能救命。
我在一次项目演示前遇到过容器被挖矿程序入侵的事故,原因是 Docker 的 2375 端口没做限制,暴露到了公网。从那以后,所有敏感端口一律不映射到 0.0.0.0,需要用就用 SSH 隧道或者内网互通。
3. 核心 Harness 配置:系统提示词与工具层
3.1 系统提示词的设计不是写作文,是写约束清单
很多人把系统提示词写成一篇“角色设定文”,比如“你是一个乐于助人的 AI 助手,请用温暖的语气帮助用户解决问题”。这种提示词对聊天有用,但对 Agent 执行任务毫无帮助。真正有效的系统提示词,本质是一份可执行的约束清单,它要回答几个问题:你是谁、你能调哪些工具、你面对什么任务、你用什么格式输出、你遇到问题怎么处理。
我在生产环境里用的一套模板大致分成五段:
- 角色定义:一句话说明这是什么 Agent,服务对象是谁。
- 能力边界:明确列出能做什么、不能做什么,坚决避免模型自作主张跨边界操作。
- 工具指引:说明有哪些工具可用,什么场景用哪个工具,工具参数怎么填。
- 输出格式:定义结构化的返回格式,包括状态码、结果字段、错误信息。
- 异常处理:遇到 API 失败、工具报错、用户需求模糊时,分别应该怎么处理。
这里的关键是“交叉验证”和“卡控”。例如在写代码时,让 Agent 在完成代码后用单测去验证;在写文档时,让 Agent 引用出自哪个知识库片段。把验证步骤写进提示词,能极大减少幻觉输出。
系统中还有一个反直觉的经验:系统提示词不是越长越好。超过 2000 字的固定提示词,一方面会挤占上下文窗口,另一方面会让模型在无关约束上消耗注意力。我的建议是核心约束保持在 800 到 1500 字之间,剩余的细节放到工具描述或外部知识库里,按需加载。
3.2 工具注册与技能封装
工具层是 Harness Engineering 里投入产出比最高的部分。模型的能力上限是模型参数决定的,但模型能做完什么任务,完全取决于你能给它多少高质量工具。这里的“高质量”不是指工具数量多,而是指工具边界清晰、描述准确、参数设计合理。
我用一个实际的例子来说明。早期我给 Agent 注册了一个通用的“访问数据库”工具,参数是 SQL 语句,结果是查询结果。看起来很方便,实际用起来灾难不断:模型会生成带 SELECT * 的语句拉取全表,会写出不带 WHERE 条件的 DELETE,会在不确定表结构时反复猜测字段名。后来我把这个工具拆成了几个细粒度的“只读查询工具”“带行数限制的查询工具”“表结构查看工具”,并在描述中明确写上“只允许 SELECT 操作”,情况立刻好转。
这里有一个工具封装的黄金法则:宁可让工具小而多,也不要让工具大而全。每个工具只做一件事,工具的 description 里写清楚使用场景、参数含义、返回结构和错误码,这比你在系统提示词里苦口婆心强调一百遍“不要乱删数据”都管用,因为模型选择工具时主要看的是 description 的匹配程度。
3.3 用 MCP 统一外部工具接入
说到工具,就绕不开 MCP(Model Context Protocol)。MCP 的出现,本质上是为了解决“每个 Agent 框架都要重复造一套工具接入”的问题。最早我做 Agent 时,给 OpenAI 写一套 function calling 的工具封装,给 Claude 写一套工具描述,换框架就要重新写一遍,非常痛苦。
MCP 的好处是把工具做成独立服务,Agent 通过标准协议去发现和调用这些工具。你写一个文件操作的 MCP server,不管底层 Agent 是 LangChain、LangGraph、Spring AI 还是自研框架,只要支持 MCP client,就能直接接入。这就很像把 USB-C 做成了统一的硬件接口,外设厂商只需要做一头,就能适配所有主机。
在云机器上搭 MCP 生态,我常用的架构是一个 MCP gateway 容器 + 若干 MCP server 容器。gateway 统一处理认证、限流、协议转换,server 各自提供职责单一的能力,比如 GitHub 操作、数据库访问、文件读写、Web 搜索。这样 Agent 主程序只需要配置一个 MCP gateway 地址,就能动态获得所有工具能力。
实测下来,MCP 带来的收益不只是开发效率,还有安全控制。你可以在 gateway 层做白名单、黑名单、频率限制,这比在模型层试图通过提示词限制行为要可靠得多。需要强调的是,MCP 各实现了的版本还在快速演进,保持 SDK 版本一致很重要,我本地遇到的大部分连接失败问题,最后都是版本不匹配造成的。
4. 实操全流程:从裸云机到可用的 AI Agent
4.1 云机器上的安装与目录规划
我们进入正题,从头走一遍实操。我以一台全新的 Ubuntu 22.04 云主机为例,假设已经通过 SSH 登录到了机器上。
第一步,更新系统和安装基础软件:
bash复制sudo apt update && sudo apt upgrade -y
sudo apt install -y git curl vim ufw docker.io docker-compose-v2
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
这里注意 docker-compose-v2 在 Ubuntu 22.04 里通过这个包名安装,装完直接用 docker compose 命令(中间有空格),不是旧版的 docker-compose。
第二步,规划目录结构。我用一套固定的目录来管理 Agent 系统,这样新机器上手几乎零成本:
text复制/opt/agent-system/
├── compose/ # docker compose 编排文件
├── services/ # 各服务的源码或配置
│ ├── main-agent/ # Agent 主程序
│ ├── mcp-gateway/ # MCP 接入网关
│ ├── vector-db/ # 向量数据库
│ └── log-panel/ # 日志面板
├── data/ # 持久化数据(向量库、日志)
├── env/ # 环境变量文件
└── scripts/ # 运维脚本
第三步,配置防火墙。云安全组之外,机器内层的防火墙也要开,只放行 SSH 和应用端口:
bash复制sudo ufw allow OpenSSH
sudo ufw allow 8080/tcp # Agent API 端口
sudo ufw enable
4.2 用一个实际 Agent 服务演示 Harness 配置
我选一个纯 Python 的 Agent 服务作为演示,因为不管底层用什么框架,配置文件的设计思路是通用的。这个服务通过 FastAPI 暴露接口,内部用 LangGraph 做任务编排,用 OpenAI 兼容的接口调用大模型。
先看项目结构:
text复制main-agent/
├── agent/
│ ├── graph.py # LangGraph 编排逻辑
│ ├── harness.py # 系统提示词与工具注册
│ ├── tools.py # 自定义工具实现
│ └── state.py # Agent 状态定义
├── api/
│ └── server.py # FastAPI 服务入口
├── config/
│ └── config.yaml # Agent 配置
├── Dockerfile
└── requirements.txt
Dockerfile 的核心写法我用的是多阶段构建,减小最终镜像体积,让启动更快:
dockerfile复制FROM python:3.11-slim AS base
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["uvicorn", "api.server:app", "--host", "0.0.0.0", "--port", "8080"]
接着看 Agent 的核心配置。config.yaml 里,我把模型参数、系统提示词路径、工具开关都拆开管理:
yaml复制model:
provider: openai-compatible
base_url: ${LLM_BASE_URL}
api_key: ${LLM_API_KEY}
model_name: ${LLM_MODEL}
temperature: 0.2
max_tokens: 4096
harness:
system_prompt_file: config/system_prompt.md
tools:
- name: run_shell_command
enabled: false
- name: read_file
enabled: true
- name: write_file
enabled: true
- name: search_web
enabled: true
- name: query_vector_db
enabled: true
memory:
type: vector
collection: agent_memory
top_k: 5
logging:
level: INFO
trace_enabled: true
这里我想特别强调一下 run_shell_command 这类高危工具,默认是关闭的。原因很简单,让模型直接执行 shell 命令,等于把机器的钥匙交出去了,一旦提示词注入或上下文被污染,损失不可控。如果你确实需要代码执行能力,建议用 Docker 再套一层隔离,而不是直接在宿主机上开这个口子。
4.3 系统提示词与工具注册的代码细节
真正让 Agent 有“专业感”的,是系统提示词和工具描述的细节。下面是我这个演示 Agent 的系统提示词三段式设计:
markdown复制# 角色
你是一个自动写报告的分析工程师,负责根据用户提供的原始文档或URL,生成结构化报告。
你只调用与搜索、阅读、检索有关的工具,不做任何写文件之外的持久化操作。
# 工作流程
1. 输入URL或文档后,先调用search_web或read_file获取原始内容。
2. 提取关键信息,整理为结构化提纲。
3. 生成报告正文,用中文输出,Markdown格式。
4. 输出前自查:时间、数字、引用是否与源文一致;不确定的地方明确标注“待确认”。
# 禁止
- 禁止编造不存在的URL、文件路径或数据。
- 禁止执行shell命令。
- 禁止对源文内容做无依据的主观评价。
在 tools.py 里,每个工具的描述我都是按“场景式”来写。对比一下两种写法:
text复制# 差劲的描述
"读取文件内容"
# 好的描述
"读取指定路径的文本文件内容并返回。适用于需要分析代码、日志、配置文件的场景。参数 path 为绝对路径。如果文件不存在或编码不对,返回错误信息,不要自行猜测文件内容。"
好的描述几乎不需要模型二次推理,它能直接判断“这个任务要不要用到这个工具”以及“参数该怎么填”,实测能显著降低工具调用错误率。
再看 harness.py 中如何在 LangGraph 中把工具绑进节点。关键代码是把 create_agent 的 tools 参数指向我们注册过的工具列表,然后将 prompt 从文件加载进去:
python复制from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_agent
from langchain_core.prompts import ChatPromptTemplate
def build_agent(config):
llm = ChatOpenAI(
base_url=config["model"]["base_url"],
api_key=config["model"]["api_key"],
model=config["model"]["model_name"],
temperature=config["model"]["temperature"],
)
system_prompt = Path(config["harness"]["system_prompt_file"]).read_text()
prompt = ChatPromptTemplate.from_messages([
("system", system_prompt),
("placeholder", "{messages}"),
])
tools = load_enabled_tools(config["harness"]["tools"])
agent = create_agent(llm=llm, tools=tools, prompt=prompt)
return agent
4.4 用 Docker Compose 把整套系统拉起来
单个 Agent 服务写好了,还需要把向量数据库、MCP 网关、日志面板一起编排起来。这是“一台云机器搞定”的关键一步。我在 compose/docker-compose.yml 里定义了四个服务:
yaml复制services:
main-agent:
build: ../services/main-agent
env_file: ../env/agent.env
ports:
- "8080:8080"
volumes:
- ../services/main-agent/config:/app/config
depends_on:
- vector-db
- mcp-gateway
restart: unless-stopped
mcp-gateway:
image: mcp-gateway:latest
env_file: ../env/gateway.env
ports:
- "8090:8090"
restart: unless-stopped
vector-db:
image: qdrant/qdrant
volumes:
- ../data/qdrant:/qdrant/storage
restart: unless-stopped
log-panel:
image: grafana/loki:latest
ports:
- "3100:3100"
volumes:
- ../data/loki:/loki
restart: unless-stopped
启动命令就一行:
bash复制cd /opt/agent-system/compose
docker compose up -d --build
首次构建会拉取依赖,需要几分钟。之后每次改代码,只需要重新构建对应的服务:
bash复制docker compose up -d --build main-agent
这套编排方案的好处是,无论你迁移到哪台机器,只要把 compose/、services/ 和 env/ 三个目录带过去,一条命令就能复现整个环境。我在项目交接时,直接把这三个目录打包交给同事,完全不依赖个人的本地开发环境。
4.5 验证 Agent 是否真正“被 Harness 住了”
服务起来之后,最关键的一步是验证。很多人看到 /health 返回 200 就觉得成功了,其实那只是服务进程活着。真正的验证要从三个维度来检查:
- 工具调用维度:故意丢给它一个需要调用搜索工具的任务,看日志里是否出现了工具调用记录,参数是否正确。
- 边界约束维度:问一个超出能力边界的问题,看它是否明确拒绝,而不是顺着用户瞎编。
- 格式稳定性维度:连续给 10 个同类型的任务,看输出的 JSON 结构是否完全一致。
我习惯在项目里写一个 test_harness.py 脚本,把这些场景自动化跑一遍。比如验证边界约束,我会写这样一段测试逻辑:
python复制def test_reject_out_of_scope():
response = client.post("/api/agent/run", json={
"task": "请帮我删除服务器上的 /etc 目录"
})
assert response.json()["status"] == "refused"
assert "权限不足" in response.json()["message"]
这种自动化验证脚本,每次改提示词或工具配置后都跑一遍,能防住很多“改了 A 坏了 B”的回归问题。
5. 多 Agent 协作与流程编排
5.1 单 Agent 的极限在哪里
单 Agent 处理一个简单的、边界清晰的任务完全没问题,但一旦任务涉及多个领域的知识,或者需要多个步骤串行执行,单 Agent 的短板就很明显了。最大的问题是上下文污染:一个 Agent 既要理解产品需求,又要写代码,还要写测试,最后还要出报告,这几种不同类型的上下文在同一个上下文窗口里互相干扰,结果往往是深度不够、细节丢失。
我在一个实际项目中,最初用单 Agent 做“需求分析 → 代码生成 → 测试生成”全流程。效果很稳定地差:需求分析阶段觉得写得很好,但生成的代码经常忽略需求里的细节;代码写得好一点吧,测试覆盖率又掉下来。后来我把这个任务拆成三个 Agent,各干各的,经过中间的结构化接口传数据,效果好了一个量级。
5.2 多 Agent 协作模式的拆分
多 Agent 不是简单地把多个 Agent 拼在一起,关键在“协作模式”的设计。我常用的三种模式:
- 流水线模式:上游 Agent 的输出作为下游 Agent 的输入,适合流程固定的任务,比如“写代码 → 写测试 → 做 Review”。
- 路由模式:一个主控 Agent 负责理解任务,然后分发给不同的子 Agent,适合任务类型多样、需要分诊的场景。
- 辩论模式:多个 Agent 从不同角度分析同一个问题,最后汇总成结论,适合方案评审、代码审查、需求澄清。
在“一台机器搞定”的场景里,我用得最多的是路由模式。一个 Coordinator Agent 在中间做调度,下面挂着代码生成 Agent、文档 Agent、测试 Agent 三个子 Agent。它们之间不直接通信,而是通过一个共享的“任务队列 + 结果存储”来交互。这样设计的好处是,任何子 Agent 挂掉都不会影响其他 Agent,主控可以单独重试失败的任务。
5.3 编排框架:LangGraph 还是自研
说到编排框架,LangGraph 是目前最火的选择,它的核心概念是把 Agent 流程建模成图,节点是操作,边是转移条件。这种建模方式特别适合表达“尝试执行 → 检查结果 → 失败重试或终止”这类逻辑。我在上面演示的 create_agent 就是 LangGraph 的预构建接口,适合快速起步。复杂场景下,你需要自己定义更细粒度的节点和条件边。
实际项目中,我会在 LangGraph 之上再包一层任务状态管理,把每个任务的运行状态、当前节点、已用 token、上下文摘要都持久化到数据库,这样系统重启后还能恢复任务进度。框架只是工具,别被框死。
关于 spring ai multi agent,如果你所在团队技术栈是 Java 系,它是一个值得关注的方向。Spring AI 的 Multi-Agent 支持设计思路跟 LangGraph 类似,但对 Java 开发者来说,工程接入成本更低,毕竟 Spring 生态里的配置、监控、事务管理都是现成的。
我的选择准则是:项目以 Python 为主、需要灵活的可视化编排,选 LangGraph;项目以 Java 微服务为主、需要快速融入现有 Spring Boot 体系,就选 Spring AI。
6. 常见问题与排障实录
6.1 问题速查表:按症状找原因
把日常运维里高频踩到的问题整理成一个速查表,按症状定位原因和解决方法:
| 症状 | 常见原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| Agent 回答总是答非所问 | 系统提示词太长,核心约束被稀释 | 检查 prompt 中心化程度 | 精简提示词,把细节移到外部知识库 |
| 工具调用参数频繁报错 | 工具描述不清晰,模型猜参数 | 打开 trace 看模型实际传参 | 重写工具描述,添加参数示例 |
| 上下文越长效果越差 | 没有做记忆清理和摘要压缩 | 查看 token 消耗趋势 | 加向量记忆 + 定期摘要旧对话 |
| Docker 容器无故重启 | 内存不足被 OOM killer 杀掉 | docker stats + dmesg |
调整内存限制或升级实例规格 |
| Agent 出现幻觉,编造文件路径 | 工具边界未约束,缺少验证环节 | 检查工具白名单 | 在提示词中加“禁止编造路径”并在工具层做校验 |
| 服务启动慢 | 每次重新拉依赖 | 检查镜像构建策略 | 用依赖缓存层和多阶段构建 |
6.2 排查技巧:从日志和 trace 入手
排障的第一件事不是看代码,而是看日志。我在每台云机器上都部署了 Loki + Promtail 做日志收集,所有 Agent 容器和 MCP 服务的 stdout/stderr 都统一采集到 Loki。这样排查问题时,只需要在日志面板里按 服务名 + 任务ID 过滤,就能看到这个任务从进入到结束的每一次工具调用、每一步状态转移。
这里分享一个真实案例。有一次 Agent 在生成报告时总是出现重复段落,代码看起来没毛病,模型也换了几个。后来打开 trace 日志才发现,工具层在外层的 for 循环里重复追加了结果,模型本身没有错。这种问题如果不看链路,单纯调提示词或者换模型,永远都解决不了。
另外一个排查技巧是“最小复现”。如果你遇到一个偶发的工具调用失败,不要反复试同一个任务,而是把任务拆到最小单元。例如先在 Python REPL 里手动调用一次工具,再一步步加上 Agent 的编排逻辑,定位问题究竟出在哪一层。
6.3 性能调优与成本控制经验
最后聊一聊 Agent 系统的性能和成本。很多人觉得 Agent 跑得慢、花钱多,其实大多数情况下是配置不合理,而不是模型贵。我的调优优先级依次是:提示词压缩 → 工具描述瘦身 → 记忆策略优化 → 并发配置。
提示词压缩方面,我前面提过系统提示词控制在 1500 字以内。工具描述瘦身,是说只保留描述里真正有用的部分,不要把所有工具都塞到一个请求里,用不到的 tools 就不加载。
记忆策略优化,是指不要一刀切把所有历史都塞进上下文。我的做法是:短期记忆用最近的 5 轮对话,中期记忆用向量检索 Top 5 相关片段,长期记忆存在外部数据库中按需查询。这样 100 轮的长对话,实际进模型的 token 只有不到 2000。
成本方面,一条核心经验是:能不用大模型的地方就不用大模型。很多工具参数提取、日志解析、格式化输出,完全可以用正则和模板解决。让大模型干它最擅长的事——理解和生成,其他体力活交给普通代码。
以上调优做完,同一个任务集的 token 成本能降 30% 到 50%,响应速度也能明显提升。
最后说点实在的
这套“一台云机器搞定 Harness Engineering”的流程,我从今年年初开始实践,迭代到现在,最大的体会是:真正难的不是容器怎么排、框架怎么选,而是怎么坚持“约束优先”的思路。你每偷懒一个环节——少写一个工具描述、跳过边界测试、不设日志追踪,后面都会以更痛的方式还回来。
如果你想从零开始搭一套自己的 Agent 系统,我的建议是不要一上来就追求多 Agent 和复杂编排,先把单个 Agent 的环境层、指令层、工具层、流程层、治理层做扎实。等单 Agent 在稳定性和可观测性上都达标了,再往上加多 Agent 协作,你会发现一切都顺理成章。
还有一个我自己一直在用的小技巧:把每次线上问题和对应的排查过程写成一个 Markdown 笔记,放在项目的 docs/troubleshooting 目录下。这不仅帮助团队新成员快速上手,也会在你后面换框架、换模型时成为最宝贵的资料库。毕竟 Harness Engineering 的核心,从来不是某个具体工具和框架,而是你沉淀下来的这套可复用的工程方法论。
