Agent 面试深度指南:三个问题背后的工程认知
从生产级 Agent Loop 稳定性、状态快照与回滚策略、Self-Healing 三个核心问题切入,拆解 Agent 系统的工程本质。不是八股文,是真刀真枪的实践经验
Agent 面试深度指南:三个问题背后的工程认知
问题一:怎么保证 Agent Loop 的稳定?
为什么这个问题能筛掉大部分人
很多人对 Agent 的理解止步于一个 ReAct 循环:
// ReAct 循环 —— demo 级别,生产环境不可用
async function reactLoop(observation: string): Promise<Action> {
while (true) {
const action = await llm.predict(observation);
if (action.isFinal) {
return action;
}
observation = await tool.execute(action);
}
}这个 demo 级别的代码在真实环境里几乎无法存活。真正跑过生产 Agent 的人都知道,这个循环里每一个接口都可能出问题,而且问题不是 " 偶尔 ",是 " 一定会在某个时刻 " 发生。
真实生产环境的 "dirty work" 清单
| 故障场景 | 表现 | 触发条件 |
|---|---|---|
| 死循环 | Agent 在两个工具间反复横跳,或重复调用同一工具 | 工具描述模糊、LLM 对结果理解偏差、缺乏终止条件 |
| 上下文溢出 | 单轮 token 数超过模型上限,API 返回 400 错误 | 长会话未做 compaction、工具返回超大结果、历史消息无限累积 |
| 模型 API 异常 | 429 Rate Limit、500 内部错误、响应超时 | 流量突增、模型厂商维护、网络抖动 |
| 工具调用失败 | 工具返回 500/404、参数格式错误、权限不足 | 下游服务变更、LLM 生成非法参数、认证过期 |
| SSE/流式推送卡住 | 客户端长时间收不到数据,连接假死 | 移动网络切换、代理服务器缓存、心跳缺失 |
| 幻觉导致的错误行动 | Agent 调用不存在的工具、构造非法 JSON | 模型能力边界、prompt 描述歧义、上下文干扰 |
能回答多少,全看自己真正处理过多少 dirty work。
生产级 Agent Loop 的七层防护体系
1. 循环硬边界:永远不要信任 while True
const MAX_STEPS = 30; // 根据任务复杂度设置
async function agentLoopWithHardLimit(observation: string): Promise<Action | PartialResult> {
for (let step = 0; step < MAX_STEPS; step++) {
const action = await agent.step(observation);
if (action.isTerminal) {
return action;
}
observation = await environment.execute(action);
}
// 触发 step limit,返回部分结果或转入人工
return {
type: "partial",
observation,
reason: "max_steps_reached",
};
}- max_steps 必须是硬限制,不是建议值——达到即强制终止
- 不同任务类型设置不同的上限:简单问答 10 步,代码生成 50 步,数据分析 30 步
- 达到上限时的策略:返回部分结果、降级为静态回复、或转人工
2. 死循环检测:识别重复模式
// 检测同一工具+参数组合的重复调用
const actionHistory = new Map<string, number>(); // key: `${tool_name}:${params_hash}` -> count
async function detectLoop(action: Action): Promise<void> {
const key = `${action.toolName}:${hashParams(action.params)}`;
const count = (actionHistory.get(key) ?? 0) + 1;
actionHistory.set(key, count);
if (count > MAX_REPEATS) {
throw new LoopDetectedError("检测到循环调用,转入人工处理");
}
}更精细的检测手段:
- 工具级去重:同一工具连续调用超过 2 次即告警
- 状态哈希去重:对 observation 做哈希,检测是否回到之前的状态
- 语义级去重:用 embedding 检测前后两轮 action 的语义相似度
3. 差异化重试:不同错误不同对待
这是生产 Agent 与 demo 的核心区别之一:
| 错误类型 | 根因 | 正确策略 | 错误策略 |
|---|---|---|---|
| 429 Rate Limit | 请求过快 | 指数退避 + jitter,1s → 2s → 4s | 立即重试(加剧问题) |
| 400 Bad Request | 请求参数非法 | 不重试,修复参数格式或 prompt | 盲目重试(同样报错) |
| 500 Server Error | 服务商内部故障 | 有限重试(2-3 次)后熔断 | 无限重试(资源耗尽) |
| Timeout | 网络/计算延迟 | 先检查操作是否实际已执行(幂等性),再决定重试 | 直接重试(可能导致重复写入) |
| Hallucination | 模型幻觉 | 不要原 prompt 重试,改用约束更强的 prompt 或换模型 | 同样 prompt 重试(大概率再幻觉) |
type RetryStrategy =
| { type: "exponential_backoff"; maxRetries: number; baseDelayMs: number }
| { type: "no_retry" }
| { type: "fixed_retry"; maxRetries: number }
| { type: "conditional_retry"; checkIdempotency: boolean }
| { type: "rephrase_and_retry"; model: string };
function resolveRetryStrategy(error: AgentError): RetryStrategy {
if (error instanceof RateLimitError) {
return { type: "exponential_backoff", maxRetries: 5, baseDelayMs: 1000 };
}
if (error instanceof BadRequestError) {
return { type: "no_retry" }; // 直接返回错误
}
if (error instanceof ServerError) {
return { type: "fixed_retry", maxRetries: 3 };
}
if (error instanceof TimeoutError) {
return { type: "conditional_retry", checkIdempotency: true };
}
if (error instanceof HallucinationError) {
return { type: "rephrase_and_retry", model: "stronger_model" };
}
return { type: "fixed_retry", maxRetries: 3 };
}4. 熔断器模式(Circuit Breaker)
当某个依赖(模型 API、工具服务)持续失败时,继续重试只会浪费资源。熔断器提供三种状态:
- Closed(闭合):正常通行,持续监控失败率
- Open(断开):失败率超过阈值(如 5 次连续失败),直接拒绝请求,fail-fast
- Half-Open(半开):经过冷却时间(如 30 秒),放少量探测请求通过,验证服务是否恢复
// 熔断器状态机
type CircuitState = "CLOSED" | "OPEN" | "HALF_OPEN";
interface CircuitBreakerConfig {
failureThreshold: number; // 连续失败阈值
recoveryTimeoutMs: number; // 恢复等待时间
halfOpenMaxCalls: number; // 半开状态探测请求数
}
class CircuitBreaker {
private state: CircuitState = "CLOSED";
private failureCount = 0;
private lastFailureTime?: number;
private halfOpenCalls = 0;
constructor(private config: CircuitBreakerConfig) {}
async execute<T>(fn: () => Promise<T>): Promise<T> {
if (this.state === "OPEN") {
if (Date.now() - (this.lastFailureTime ?? 0) > this.config.recoveryTimeoutMs) {
this.state = "HALF_OPEN";
this.halfOpenCalls = 0;
} else {
throw new CircuitOpenError("熔断器处于 OPEN 状态,快速失败");
}
}
if (this.state === "HALF_OPEN" && this.halfOpenCalls >= this.config.halfOpenMaxCalls) {
throw new CircuitOpenError("半开状态探测配额已用尽");
}
if (this.state === "HALF_OPEN") {
this.halfOpenCalls++;
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (err) {
this.onFailure();
throw err;
}
}
private onSuccess(): void {
this.failureCount = 0;
if (this.state === "HALF_OPEN") {
this.state = "CLOSED";
this.halfOpenCalls = 0;
}
}
private onFailure(): void {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.failureCount >= this.config.failureThreshold) {
this.state = "OPEN";
}
}
}
// 使用
const circuit = new CircuitBreaker({
failureThreshold: 5, // 5 次连续失败触发熔断
recoveryTimeoutMs: 30000, // 30 秒后尝试恢复
halfOpenMaxCalls: 2, // 半开状态最多 2 个探测请求
});
const result = await circuit.execute(() => openai.chat.completions.create(prompt));熔断器的生产价值:
- 防止一个挂掉的下游服务拖垮整个 Agent 系统
- 与降级策略配合:主模型熔断时自动切换到备用模型
- 为系统恢复争取时间窗口
5. 超时控制:永远不要无限等待
// 分层超时设计(单位:毫秒)
const TIMEOUTS = {
TASK: 120_000, // 整个任务 2 分钟
STEP: 30_000, // 单步 30 秒
LLM_CALL: 15_000, // LLM 调用 15 秒
TOOL: 10_000, // 工具执行 10 秒
SSE_HEARTBEAT: 60_000, // SSE 心跳超时 60 秒
} as const;
// 带超时的 Promise 包装器
async function withTimeout<T>(promise: Promise<T>, ms: number, context: string): Promise<T> {
const timeout = new Promise<never>((_, reject) =>
setTimeout(() => reject(new TimeoutError(`${context} 超时 (${ms}ms)`)), ms)
);
return Promise.race([promise, timeout]);
}SSE/流式连接的特殊处理:
- 心跳机制:服务端定期发送
:heartbeat\n\n,客户端检测心跳中断即重连 - Last-Event-ID:断线重连时携带上次接收的 event ID,服务端补发遗漏数据
- 指数退避重连:1s → 2s → 4s → 最大 30s,避免重连风暴
6. 优雅降级:坏了也要给出最优解
当 Agent 的核心能力受损时,不是直接报错,而是尽可能提供有用的响应:
| 故障组件 | 降级策略 |
|---|---|
| 主模型不可用 | 切换到备用模型(Claude → GPT → Gemini),或降级到更小模型 |
| 工具服务不可用 | 告知用户 " 暂时无法查询实时数据,但我可以基于已有知识回答 " |
| RAG 检索失败 | 直接用模型内置知识回答,不阻塞用户 |
| 记忆系统不可用 | 仅使用当前会话上下文继续对话 |
| 所有自动化都失败 | 返回结构化错误信息 + 转人工的入口 |
7. 上下文溢出防护:Compaction 是必选项
Agent 每轮循环都在累积历史消息,最终必然触及模型上下文上限。生产系统必须在达到上限前主动 compaction:
- 滑动窗口:保留最近 N 轮对话,丢弃更早的
- 工具结果折叠:保留工具调用记录但清空原始返回数据(尤其是大文件内容)
- 摘要替换:用廉价模型(如 Haiku/4o-mini)对历史对话做摘要,用摘要替代原文
- Head+Tail 策略:保留系统提示和初始任务(head)以及最近几轮(tail),丢弃中间部分
面试中这样答
初级回答:" 加 try-catch 和重试。"
深度回答:
- 首先定义 Agent Loop 的故障分层——基础设施层(API 超时、网络抖动)、模型层(幻觉、输出格式错误)、工具层(工具调用失败、返回异常)、编排层(死循环、上下文溢出)
- 每一层有对应的防护策略:基础设施层用熔断器 + 指数退避,模型层用输出校验 + prompt 约束,工具层用参数校验 + 备选工具,编排层用 max_steps + 循环检测
- 补充一个你在生产里实际遇到的案例:比如某次工具返回了 10MB 的 JSON 导致上下文溢出,你们是怎么通过 tool result truncation + compaction 解决的
- 强调观测的重要性——没有监控的防护都是盲打,需要跟踪 error rate、retry frequency、fallback rate、latency percentile 等指标
问题二:你在 Agent 的 Context 里面放了哪些东西?
这个问题在考察什么
Context Engineering 是 Agent 工程中最被低估的核心能力。同样一个 GPT-4o,context 放得好与不好,效果可能相差一个数量级。
这个问题能自然触及 Skills、MCP、RAG、Memory 等核心概念——如果一个人只能答 " 放系统提示和用户消息 ",基本确定只做过 demo。
Context 的分层架构
生产级 Agent 的 context 不是一个长字符串,而是一个分层组装、按需加载的结构:
┌─────────────────────────────────────────────────┐
│ Context Window (有限的宝贵资源) │
├─────────────────────────────────────────────────┤
│ Layer 1: System Prompt (系统指令) │
│ - Agent 的身份、行为准则 │
│ - 输出格式约束、安全策略 │
│ - 稳定存在,适合缓存 │
├─────────────────────────────────────────────────┤
│ Layer 2: Active Tools / MCP (工具层) │
│ - 当前可用的工具描述 (JSON Schema) │
│ - MCP Server 动态发现的工具 │
│ - 按需加载:复杂任务加载更多工具 │
├─────────────────────────────────────────────────┤
│ Layer 3: Retrieved Context (RAG) │
│ - 从向量数据库检索的 top-k 相关文档 │
│ - 动态变化,每轮可能不同 │
├─────────────────────────────────────────────────┤
│ Layer 4: Memory (记忆层) │
│ - Short-term: 当前会话的近期消息 │
│ - Long-term: 跨会话的用户偏好、历史决策 │
│ - Episodic: 关键事件、成功经验/失败教训 │
├─────────────────────────────────────────────────┤
│ Layer 5: Session History (会话历史) │
│ - 当前任务的对话轮次 │
│ - 经 compaction 处理的压缩历史 │
└─────────────────────────────────────────────────┘每一层的设计要点
1. System Prompt:稳定、精确、可缓存
你是 {product} 的 AI 助手,专门帮助用户解决 {domain} 问题。
## 行为准则
1. 优先使用 search_knowledge_base 工具查询知识库
2. 如果知识库无结果,明确告知用户"知识库中未找到相关信息"
3. 禁止编造不存在的产品功能
4. 每次回复使用结构化格式:问题分析 → 解决方案 → 相关链接
## 安全策略
- 遇到账号/密码相关请求,引导用户联系客服
- 涉及退款/投诉,自动触发工单创建工具
## 输出格式
{"analysis": "...", "solution": "...", "references": [...]}设计原则:
- 放在 context 最前面,最大化 prefix caching 的命中率
- 保持长期稳定,减少 cache invalidation
- 用结构化格式(Markdown/XML/JSON),LLM 对结构化指令的理解远好于纯文本
2. Tools / MCP:按需加载,而非全部塞入
不是所有工具都要每轮都塞给模型。工具描述很占 token(一个复杂工具可能 500-2000 tokens),工具多了 context 很快就满。
按需加载策略:
- 静态加载:核心工具(搜索、计算)始终保留
- 动态加载:根据用户意图识别,只加载相关工具。例如用户问代码问题,加载代码相关工具;问财务问题,加载财务工具
- MCP 动态发现:通过 MCP Server 在运行时动态获取可用工具列表,而非硬编码
interface Tool {
name: string;
category: string;
description: string;
}
interface Intent {
categories: string[];
confidence: number;
}
// 工具选择:用廉价模型做意图分类,按需加载工具
async function selectTools(userQuery: string, availableTools: Tool[]): Promise<Tool[]> {
const intent: Intent = await classifyIntent(userQuery, availableTools); // 用 Haiku,~$0.001
return availableTools.filter((tool) => intent.categories.includes(tool.category));
}MCP 的定位:
MCP(Model Context Protocol)是 Anthropic 推动的开放标准,用于标准化 Agent 与外部工具的集成。核心价值:
- 标准化:Agent 不需要为每个工具写自定义集成,MCP Server 提供统一接口
- 动态发现:Agent 运行时动态发现 MCP Server 提供的工具
- 安全隔离:工具执行在独立进程中,通过 stdio/SSE 通信,降低安全风险
- 生态复用:社区已有大量 MCP Server(GitHub、Slack、数据库、文件系统等)
面试时提到 MCP 说明你对 Agent 工具集成的前瞻架构有了解——但要注意,MCP 目前还在快速发展阶段,生产环境使用需要考虑稳定性。
3. RAG:检索什么、怎么检索
RAG 不是 " 把向量数据库接进来 " 这么简单:
- 分块策略(Chunking):按段落、语义、或固定 token 数分块?不同策略影响检索精度
- Embedding 模型选择:OpenAI text-embedding-3-large、BGE、M3E 等,需要根据领域数据测试
- 重排序(Rerank):先用向量检索 top-20,再用 cross-encoder 重排取 top-5
- 元数据过滤:按用户权限、文档类型、时间范围做前置过滤
- 上下文压缩:检索到的文档 chunk 可能很长,需要摘要或提取关键段落后再放入 context
4. Memory 层:短期记忆与长期记忆
短期记忆(Short-term Memory):
- 当前会话的对话历史
- 存在内存中,速度快,会话结束即清除
- 容量有限,需要 sliding window 或 compaction
长期记忆(Long-term Memory):
- 跨会话持久化的用户偏好、事实、经验
- 存储在外部数据库(PostgreSQL、Redis、向量数据库)
- 通过 embedding 检索按需加载
记忆的类型:
| 类型 | 内容 | 存储方式 | 检索方式 |
|---|---|---|---|
| Semantic | 用户偏好、产品偏好、身份信息 | 向量数据库 + 键值存储 | Embedding 相似度搜索 |
| Episodic | 关键对话片段、成功经验、失败教训 | 向量数据库 + 时间索引 | 按主题 + 时间检索 |
| Procedural | Agent 的操作流程、工具使用模式 | 规则引擎 / 少样本示例 | 按任务类型匹配 |
长期记忆的防损坏策略:
这是追问点——" 怎么保证长期的 Memory 记忆不坏掉?"
- 写入验证:记忆写入前 LLM 做质量校验,过滤低质量、矛盾的信息
- 版本控制:重要记忆保留历史版本,可回滚到之前的状态
- 冲突检测:新记忆与已有记忆矛盾时,触发冲突解决流程(人工确认或 LLM 仲裁)
- 定期清理:基于时间衰减(90 天未访问降低权重)和重要性评分清理过期记忆
- 摘要合并:定期用 LLM 将多条相关记忆合并为高质量摘要
- 人类审核:对关键业务记忆设置人工审核节点
5. Session History: compaction 的艺术
Session History 是上下文消耗的大头,compaction 策略直接影响 Agent 的长期表现:
| 策略 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| Sliding Window | 保留最近 N 轮,丢弃更早的 | 简单高效 | 可能丢弃关键历史信息 |
| Head+Tail | 保留开头(任务定义)和结尾(最近几轮),丢弃中间 | 兼顾任务定义和最新上下文 | 中间过程丢失 |
| Tool Result Clearing | 保留工具调用记录但清空详细返回数据 | 大幅减少 token | 无法回溯工具执行细节 |
| Summarization | 用廉价模型对历史做摘要 | 保留信息密度 | 摘要可能丢失关键细节(幻觉风险) |
| Semantic Selection | 用 embedding 检索与当前查询相关的历史消息 | 保留真正相关的上下文 | 增加检索开销 |
Claude Code 的五层 compaction pipeline 是目前业界比较先进的实践:
- Tool Result Compaction(折叠旧工具结果)
- Summarization(摘要旧对话)
- Sliding Window(保留最近 N 轮)
- Truncation(硬截断兜底)
- 每层按触发条件渐进式执行,gentle 策略优先
Context 组装的最佳实践
- 稳定内容在前,可变内容在后:系统提示、工具定义放前面,用户消息、检索结果放后面,最大化 prefix caching
- 给内容打标签:用 XML 标签包裹不同层的内容,帮助模型理解结构
- 控制总长度:预留 20% 的 context window 余量,避免触发 compaction 的紧急情况
- 敏感信息隔离:在 context 中标记隐私数据,确保不会出现在日志或缓存中
面试中这样答
初级回答:" 放系统提示、工具描述、用户消息。"
深度回答:
- 把 context 理解为一个分层组装的管道,每一层有不同的生命周期和加载策略
- 从 System Prompt(稳定、可缓存)→ Tools/MCP(按需加载)→ RAG(动态检索)→ Memory(按需检索)→ Session History(需 compaction)逐层讲解
- 主动提及 MCP 的价值和局限——标准化工具接入、动态发现、但仍在快速发展
- 重点讲 Memory 的设计:短期 vs 长期、semantic/episodic/procedural 三种类型、长期记忆的防损坏策略(写入验证、版本控制、冲突检测、定期清理)
- 讲一个你做过的 context optimization 案例:比如发现工具描述占用了 60% 的 context,通过动态工具选择减少了 50% 的 token 消耗
问题三:如何控制 Agent 的成本?
为什么这是必修课
真正做过 Agent 的人,肯定深知 token 成本远超其他所有基础设施——CI/CD、服务器、数据库加起来一年的成本可能都不如你一个月的 token 账单。
以一个实际场景为例:一个 200 步的 Agent 会话,用 Claude Opus 4(22.50/会话**。如果每天有 1000 个活跃用户,月成本接近 3-5/会话,月成本降至 $9-15 万——节省了 70-85%。
Agent 成本优化的五大杠杆
杠杆一:Prompt Caching(最高性价比,优先实施)
Prompt Caching 的原理:模型对输入做 attention 计算时会生成 KV Cache,如果前后两次请求的前缀相同,可以复用 KV Cache,只需处理新变化的 tokens。各厂商实现:
| 厂商 | 实现方式 | Cache Read 折扣 | Cache Write 成本 | TTL |
|---|---|---|---|---|
| Anthropic | 显式 cache_control 断点 | 90% 折扣 | 1.25x 输入价格 | 5 分钟(可续期)/ 1 小时 |
| OpenAI | 自动缓存(无需代码改动) | ~50-90% 折扣 | 免费 | 5-10 分钟 / 最长 24 小时 |
| Gemini | 显式 Context Caching API | 90% 折扣 | 有写成本 | 可配置,最长数小时 |
| DeepSeek | Context Caching API | 98% 折扣 | 有写成本 | 视具体模型 |
关键策略:
- Anthropic 的显式缓存:在 system prompt 和工具定义上设置
cache_control: {type: "ephemeral"}断点。适合多轮对话和 Agent 工具循环场景——每轮工具调用都复用相同的 system prompt + tools 前缀 - Gemini 的显式 vs 隐式缓存:
- 显式缓存:适合大文档问答场景,先创建缓存(一次性写成本),后续查询复用
- 隐式缓存:适合对话历史自动复用,无需额外配置
- 判断标准:如果文档 > 32K tokens 且会被多次查询,显式缓存更划算;小文档或一次性查询不需要缓存
- OpenAI 的自动缓存:最简单,prompt > 1024 tokens 自动触发,零代码改动
实战建议:
- 把稳定内容(system prompt、tools)放在 prompt 最前面
- 可变内容(用户消息、检索结果)放在后面
- 确保 cache prefix 字节级一致——任何微小变化都会导致 cache miss
- Cache hit 率低于 50% 时排查 prompt 结构是否稳定
杠杆二:Model Routing(模型路由,最大节省潜力)
不是所有任务都需要最强模型。一个分类任务用 GPT-4o-mini 和 GPT-4o 的结果可能一样,但成本相差 94%。
三级路由策略:
┌─────────────────────────────────────────────────┐
│ 用户请求 │
├─────────────────────────────────────────────────┤
│ Step 1: 意图分类(Haiku / 4o-mini, $0.001) │
├────────────┬────────────────────┬───────────────┤
│ 简单任务 │ 中等复杂度 │ 复杂任务 │
│ 10-20% │ 50-60% │ 20-30% │
├────────────┼────────────────────┼───────────────┤
│ Haiku │ Sonnet / 4o │ Opus / o1 │
│ $1/M │ $3/M │ $5-15/M │
└────────────┴────────────────────┴───────────────┘路由的实现方式:
- 规则路由:基于关键词、正则、或请求类型硬编码规则(零成本,适合场景明确)
- 分类器路由:用一个小模型做复杂度分类,再路由到对应模型(每次分类 $0.001,可忽略)
- 置信度路由:先用廉价模型回答,如果置信度低于阈值,再用强模型重试
- 级联路由(Cascading):廉价模型 → 中等模型 → 强模型,逐级升级直到质量达标
面试要点:要能讲出路由的质量监控——不能只管省钱不管质量。需要:
- 离线评估:定期抽样对比不同模型的输出质量
- 在线监控:跟踪用户满意度、下游任务成功率
- 逃逸舱:允许用户或特定功能强制使用最强模型
杠杆三:Context Compaction(上下文压缩)
Agent 会话越长,每轮的 input tokens 越多(因为要发送完整历史)。Compaction 的目标是在不丢失关键信息的前提下减少 token 数:
- Summarization:用廉价模型(Haiku/4o-mini)对历史对话做摘要,替代原始消息
- Tool Result Truncation:工具返回超大结果时截断或摘要(如代码搜索结果只保留前 10 条)
- Selective History:只保留用户消息和关键工具调用,丢弃中间推理过程
- Context Folding:子任务完成后折叠为摘要,不保留中间步骤
效果:compaction 通常能减少 50-70% 的上下文 tokens。
杠杆四:Batch Processing(异步场景)
OpenAI 和 Anthropic 都提供 Batch API,异步处理可接受延迟的任务,统一 50% 折扣:
适用场景:
- nightly 报告生成
- 大批量文档分类/标注
- 历史数据清洗
- 评估测试集
Batch + Caching 可叠加:batch 折扣 + cache read 折扣 = 最高 95% 的节省。
杠杆五:Prompt Optimization(精细打磨)
- 精简 system prompt:从 2000 tokens 压缩到 800 tokens,不影响效果
- 要求结构化输出:用 JSON/XML schema 约束输出,减少无效内容
- Tool description 优化:删除工具描述中的冗余信息,保留关键字段
- 避免重复:不要把同样的指令在 system prompt 和 few-shot 中重复
成本优化的 ROI 计算
用一个 Agent 会话的成本变化来说明五大杠杆的叠加效果:
| 优化阶段 | Input Cost | Output Cost | 总成本/会话 | 累计节省 |
|---|---|---|---|---|
| 基线(全部 Opus,无优化) | $20.00 | $2.50 | $22.50 | 0% |
| + Model Routing | $6.40 | $1.60 | $8.00 | 64% |
| + Context Compaction | $2.56 | $1.60 | $4.16 | 81% |
| + Prompt Caching | $0.50 | $1.60 | $2.10 | 91% |
| + Batch(异步场景) | $0.25 | $0.80 | $1.05 | 95% |
数字来源:基于 Anthropic Opus 3/M、Haiku $1/M 的定价计算,假设 200 步/会话,平均 20K input tokens/步。
成本监控体系
优化前先测量——不能优化你测量不了的东西:
| 指标 | 用途 | 告警阈值 |
|---|---|---|
| Cost per request | 定位高成本请求 | 超过基线 2x |
| Cost per user | 识别异常用户 | 单日超过阈值 |
| Cache hit rate | 验证缓存效果 | 低于 50% |
| Model distribution | 验证路由效果 | 强模型占比异常升高 |
| Token per request | 检测 context 膨胀 | 持续增长趋势 |
面试中这样答
初级回答:" 用更便宜的模型。"
深度回答:
- 先强调成本结构认知:token 成本是 Agent 最主要的成本项,远超基础设施
- 五大杠杆按优先级排序:Caching(最高 ROI)→ Model Routing(最大节省潜力)→ Compaction(解决上下文膨胀)→ Batch(异步场景)→ Prompt Optimization(持续打磨)
- 详细讲 Caching 的厂商差异:Anthropic 显式断点(90% off)、OpenAI 自动(零改动)、Gemini 显式/隐式的选择策略——比如大文档 QA 场景下 Gemini 显式缓存什么时候创建更合适(文档 > 32K tokens 且多次查询时)
- 讲 Model Routing 的质量保障:不能只看省钱,要有离线评估、在线监控、逃逸舱机制
- 给出一个你实际做过的 ROI 数字:比如 " 通过 routing 60% 流量到 Haiku + caching system prompt,我们把月度 API 账单从 1.2 万 "
总结:三个问题背后的共同认知
这三个问题分别对应 Agent 工程的三个核心维度:
| 问题 | 维度 | 核心能力 |
|---|---|---|
| Loop 稳定 | 可靠性工程 | 故障分层、防护体系、可观测性 |
| Context 设计 | 系统工程 | 架构分层、按需加载、状态管理 |
| 成本控制 | 经济学思维 | ROI 计算、杠杆优先级、量化决策 |
真正做过 Agent 的人,会在回答中自然流露出这些特质:
- 分层思维——不是给一个银弹方案,而是分层次、分场景地讨论 trade-off
- 量化意识——不只是说 " 能省钱 ",而是能算出省多少、怎么衡量
- 务实的悲观——默认一切都会出问题,系统设计围绕故障场景展开
- 持续迭代——不存在一劳永逸的方案,优化是持续过程
最后,原文说得好:认知和执行力从来就是不分家的。这三个问题的答案不需要背诵,它们来自你在生产环境里一次次踩坑、调试、优化的真实经历。如果你还没做过,至少先在面试前动手搭一个 Agent,跑长一点会话,看看哪些问题会出现——这比看一百篇博客都有效。
参考资源
- AI Agent Error Handling Best Practices - Agenticai Flow
- Designing Fault-Tolerant AI Agent Pipelines - Mightybot
- Context Engineering for AI Agents: A Deep Dive - Towards Data Science
- LLM Cost Optimization — Token Management, Caching & Model Routing
- Prompt Caching Guide: How to Cut API Costs by 90% - AI Outlooks
- Model Routing vs. Prompt Caching: Which Saves More on LLM Costs? - SimplifAI
- LLM Cost Optimization: 5 Levers to Cut API Spend 70-85% - MorphLLM
- How We Cut LLM Costs by 59% With Prompt Caching - ProjectDiscovery
- MCP Model Context Protocol Architecture - OpenClaw
- Dive into Claude Code: The Design Space of AI Agent Systems - arXiv