Agent面试详解(上):从模型接口到可恢复的运行时
原创 · 约 16 分钟阅读 · 阅读 --

Agent面试详解(上):从模型接口到可恢复的运行时

作者: Alex Xiang


《Agent面试详解》系列:上篇:运行时与上下文 · 中篇:记忆、工具与并发(待发布) · 下篇:评测、安全与落地(待发布)

最近刷到几段讨论 DeepSeek Agent 岗位和面试的视频。里面反复出现的问题很有代表性:上下文窗口怎么选,多用户并发怎么处理,长期记忆会不会无限膨胀,一个 Agent 跑几十步以后为什么越来越不稳定。

这些问题表面上像面试题,实际已经越过 Prompt 和框架用法,进入运行时、分布式系统、数据治理和工程架构的范围。

DeepSeek 的公开招聘也能印证这个变化。当前职位列表中已经出现 Agent Harness、Agent Infra、Agent 后端和 Code Agent 数据等不同方向。它需要的不是一个“会调模型 API 的人”,而是一支能把模型能力变成稳定产品的完整团队。DeepSeek 官方招聘

这个系列不整理“面试题标准答案”,而是从零设计一套企业级 Agent。假设它支持多租户,可以连续执行 100 步,能访问内部与外部工具,进程崩溃后可以恢复,高风险操作必须审批,所有行为可以审计和评测。

上篇先处理底座:模型、Harness 和环境是什么关系,运行时如何保存状态,长任务为什么会失控,上下文窗口应该怎样管理。

DeepSeek 最近在招什么人

Agent 这个词过去太宽泛。一个聊天框接上搜索 API,也有人叫它 Agent;一个可以操作代码仓库、跑几小时、修改外部状态的系统,也叫 Agent。两者显然不是同一种工程问题。

DeepSeek 当前公开岗位把边界划得更清楚:Agent Harness 团队、Agent Infra、Agent 后端、Code Agent 数据、搜索算法与架构分别承担不同工作。可以用一个简化公式表达这种分工:

Model + Harness = Agent

如果把真实工作环境也纳入系统,公式还要再补一项:

Model + Harness + Environment = Agent System

Model、Harness 与 Environment 分别承担推理、运行时编排和真实环境交互,三者组合才构成完整 Agent 系统

模型负责理解、推理和生成决策;Harness 决定模型能看到什么、能调用什么、怎样保存状态、失败后如何恢复;Environment 则提供代码仓库、浏览器、数据库、业务 API 和权限边界。离开后两层,模型再强也只能在对话框里给建议。

近期的 Harness Engineering 研究把这层运行时拆成任务定义、上下文选择、工具访问、项目记忆、任务状态、可观测性、失败归因、验证、权限和人工干预等职责。它强调的不是“模型能否生成一个 patch”,而是整个系统能否交付一个可验证、可归因、可维护的修改。AI Harness Engineering

这也是 Agent 面试变硬的原因:考察对象从某个框架的 API,变成了一个完整软件系统。

先把企业级架构画出来

先不要急着讨论 LangGraph、AutoGen 或某个 SDK。框架选型之前,应该先确定系统边界。

企业级 Agent 的入口、运行时、队列、工具、记忆、审批和审计模块

一套可以长期运行的企业 Agent,至少需要下面这些模块。

模块主要职责不应该负责什么
API Gateway认证、租户解析、限流、请求入口不编排 Agent 步骤
Run Manager创建、去重、取消、恢复和查询 run不直接执行工具
State Machine驱动 Agent Loop,约束状态迁移不保存全部业务数据
Planner拆任务、维护依赖、触发重规划不绕过权限调用工具
Context Builder组装每一轮模型输入不把数据库当成聊天记录倾倒
Model Router按难度、风险、延迟和成本选模型不决定业务权限
Scheduler排队、并发、租约、重试和背压不持有长期数据库事务
Tool Gateway发现、校验、授权和执行工具不暴露 Secret 给模型
Sandbox隔离 Shell、浏览器和代码执行不承担全局调度
Memory Service记忆写入、合并、检索和遗忘不控制 Agent Loop
Approval Center审核高风险和不可逆操作不替模型补参数
Trace / Eval记录轨迹、证据、指标和评测结果不反向污染运行状态

模块之间怎么通信

短查询可以走 HTTP 或 gRPC,例如 Run Manager 查询一个 run 的状态;长操作应该进入消息队列,例如一个需要运行十分钟的浏览器任务。状态变化最好发布版本化事件,而不是让所有模块直接读写同一批表。

有三条边界尤其重要:

  1. Tool Gateway 不应依赖 Planner 的内部对象,只接受稳定的 Tool Call Contract。
  2. Memory Service 不应知道某个框架的 message class,只存储有版本的领域对象。
  3. 数据库事务不能跨模型调用、工具调用、文件 I/O 或网络 I/O。

模型和工具调用放在事务之外,数据库事务只包围最后的原子状态更新

如果多个模块共享 ORM 对象、共享进程内全局状态、共享一条长事务,系统在单机 Demo 里很方便,到了多 Worker、重试和滚动升级时就会迅速失控。

Agent Loop 怎样从 Demo 变成运行时

最小 Agent Loop 通常写成这样:

while not done:
    response = model(messages, tools=tools)
    if response.tool_call:
        result = execute(response.tool_call)
        messages.append(result)
    else:
        done = True

它适合教学,不适合企业运行。至少缺少状态持久化、预算、取消、错误分类、并发控制、审批和完成证据。

更接近真实系统的循环是:

读取 run 与 checkpoint
  → 构造本轮上下文
  → 模型规划下一动作
  → 策略与权限检查
  → 执行工具或等待审批
  → 持久化 observation
  → 更新任务状态
  → 验证完成条件
  → 继续、重试、重规划、暂停或结束

每一步都要能够回答三个问题:

  • 这一步的输入来自哪个版本的状态?
  • 这一步是否已经产生外部副作用?
  • 进程现在崩溃,下一台 Worker 从哪里继续?

“完成”不是模型说了算

模型输出 done,只能表示它认为自己完成了。系统还要运行验证器。例如代码 Agent 必须检查目标测试、相关回归测试和工作区 diff;数据 Agent 必须核对查询范围、行数和口径;客服 Agent 必须确认工单状态确实改变。

完成条件应该是机器可观察的状态:

completion:
  required:
    - target_tests_passed
    - regression_tests_passed
    - no_unapproved_side_effects
    - final_evidence_attached
  max_steps: 100
  max_duration_seconds: 7200

这里的 max_steps 是安全上限,不是让 Agent 必须跑满 100 步。真正的结束条件来自证据,预算只负责在异常时切断循环。

跑到五十步为什么容易崩

长任务最先碰到的通常不是模型智力,而是上下文管理。

如果每次工具调用都把原始结果追加到 messages,上下文会持续膨胀。更麻烦的是,Token 变多不只意味着成本变高,还意味着关键约束被大量 observation 淹没、旧错误继续传播、模型开始重复已经做过的工作。

不要只按“最近 N 轮”截断

固定保留最近 10 轮很简单,但不可靠:一次浏览器 DOM 或日志输出可能比十轮普通对话还长,而第 11 轮恰好可能保存了不可丢失的架构决策。

更稳妥的是按 Token 预算组装混合窗口

固定区:system policy、目标、权限和不可变约束
任务区:当前 plan、未完成步骤、最近 checkpoint、关键决策
动态区:最近交互、本步工具摘要、按需检索的记忆
预留区:模型输出、Tool Schema、下一轮 observation

上下文水位达到不同阈值时,分别监控、压缩、外置和停止扩展

阈值怎样设

不能等模型 API 返回“context too long”才处理。一个可落地的初始方案是:

上下文水位动作
60%–70%开始监控重复内容,工具大结果只保存摘要
75%–80%生成 checkpoint,压缩旧轨迹
85%大型原始结果全部外置,只保留引用和关键事实
90%停止扩展任务,不再接收不可预测的大结果
接近硬限制从 checkpoint 启动新线程,或交还人工

真正的输入预算不是模型标称上下文上限:

可用输入预算 =
上下文上限
- 最大输出预算
- Tool Schema
- 安全预留
- 序列化与格式化开销

建议至少留出 10%–20% 给输出和不可预测增长。对于会返回大结果的浏览器、日志和数据库工具,预留还要更高。阈值不是行业标准,应根据真实轨迹、模型输出长度和工具分布持续校准。

溢出前的兜底顺序

  1. 删除可以重新获取的原始工具结果。
  2. 合并重复 observation。
  3. 把旧步骤压缩成带证据引用的 checkpoint。
  4. 只加载当前阶段需要的工具定义。
  5. 将独立工作拆给 Subagent,隔离上下文。
  6. 冻结旧线程,用结构化状态启动新线程。
  7. 仍无法压缩时暂停,而不是静默丢掉约束。

DeepSeek 的上下文缓存可以降低相同前缀的延迟和成本,但缓存并不能解决上下文语义污染。它优化的是重复计算,不是信息选择。DeepSeek Context Caching

上篇留下的接口

到这里,Agent 已经有了运行时骨架:每一步受状态机约束,慢调用不占用数据库事务,完成依赖证据,上下文按预算组装,进程可以从 checkpoint 恢复。

但状态能够恢复,不代表长期记忆可信;工具能够调用,也不代表它不会越权或重复产生副作用。中篇继续处理最容易把 Demo 拖垮的三件事:记忆、工具和多用户并发。

**接下来:**中篇将继续讨论记忆、工具与多用户并发,暂未发布。

《Agent面试详解》系列:上篇:运行时与上下文 · 中篇:记忆、工具与并发(待发布) · 下篇:评测、安全与落地(待发布)

打开原图 ↗