科大讯飞 AI 应用一面:Agent Harness、沙箱隔离与评测
- 轮次
- 一面
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
- 自我介绍。实习为什么没有参加转正,之后还会投相同部门或岗位吗?
- 第三个实习的异步工作流是什么框架,解决什么问题?
- 小站点网络隔离导致升级失败,原问题和改造方案是什么?
- DB 队列具体如何设计和执行?
- 第二个实习搜索链路 P99 优化是如何定位、改造并验证的?
- 并行后某个数据源仍很慢,是否一直等到两路都返回?
- Guava / Tair 两级缓存和 JVM 本地缓存解决什么业务问题,为什么需要?
- 本地缓存一致性是否需要考虑,当前如何处理?广播更新 JVM 本地缓存靠谱吗,有没有其他方法?
- 第一个实习 Agent Harness 服务什么场景?Runtime、Workflow 和 Node 如何分层?
- 是否类似 Dify / 扣子?调研过哪些开源方案?
- 分层上下文 Roadmap 怎样解决长任务历史堆积与关键证据丢失?
- 什么时候检测并触发压缩?大 Tool Result 的阈值是什么?
- 上一轮 Tool 返回特别长怎么办?原始结果会保留吗?
- 摘要会影响 KV / Prefix Cache 命中吗?怎样降低影响?
- Skill 路由评测主要评测什么,怎样做?路由差是否只改 description?Skill 很多或功能重叠时怎么办?
- 评测面向内置 Skill 还是业务方 Skill?怎样反馈业务方优化?
- 平时开发使用什么 AI Coding 工具和模型?对比过这些模型吗?哪个开发效率更高?
- 为什么选择自研 Agent Runtime,而不是直接使用开源框架?
- Runtime 的沙箱与隔离机制如何做?gVisor 是什么?
- gVisor 与 Docker 容器、虚拟机有何不同?
- 把本地 Coding Agent 做成多人使用的 SaaS,架构、创建、复用与销毁如何设计?
- 编码项目的正式文件如何保存?实例销毁后怎样继续使用?
- microVM 是什么?与普通 VM、Docker 的区别以及隔离强度如何理解?
- Codex / Claude Code 等工具的本地沙箱如何做?
《参考解析》
异步工作流与 DB 队列:异步工作流的价值是把”必须做完才能返回”的长任务变成”提交后异步执行、可查询进度”,典型场景是批量处理与外部调用。用数据库做队列(而非 MQ)的取舍是:实现简单、天然持久化、可事务内入队(与业务写入原子),但吞吐低、需要自己处理轮询频率、锁竞争和清理。设计要点包括——用状态机字段(PENDING/RUNNING/SUCCESS/FAILED)+ 版本号做条件更新来抢任务(UPDATE ... WHERE status='PENDING' AND id=?),避免多个 worker 抢到同一条;失败任务要有重试次数与退避;处理中的任务要有租约和超时回收(worker 挂了任务不能永久卡住);以及定期归档已完成记录控制表体积。
网络隔离导致升级失败怎么改造:这类问题的根因通常是升级流程依赖”中心节点主动连到小站点”(推模式),而小站点在 NAT/防火墙后就不可达。改造方向是反转连接方向——改为小站点主动向中心拉取(轮询或长连接),中心只维护”期望版本”状态,端侧自己比对并下载升级包,上报进度。这样既穿透了网络隔离,也让升级变成幂等的”收敛到期望状态”,重试天然安全。配套要做的是:断点续传、升级包校验(哈希/签名)、灰度分批、失败回滚,以及端侧离线时的重试策略。
并行后某个数据源仍很慢:不能一直等——要设每个分支独立的超时,超时就用降级结果(空结果或缓存值)并记录降级指标。整体采用”先到先用”的收敛策略:关键数据必须等,非关键数据可缺失。同时要监控各分支的 P99,避免慢分支长期拖累整体而不被发现。
本地缓存一致性与广播更新:本地缓存(JVM 内)的优势是零网络开销,代价是多实例各存一份、更新不同步。广播失效(发布订阅通知各实例删 key)是常见做法,但不可靠——消息会丢、实例可能离线、网络分区时收不到。所以必须叠加兜底:TTL 上限(即使通知丢失也会自然过期)、定期全量刷新版本号、以及读时校验版本(版本旧就丢弃并回源)。更稳的做法是”版本号 + 短 TTL”,把广播当作加速而不是正确性依赖。
Agent Harness 的分层:Runtime 负责执行环境与生命周期(进程/沙箱、工具注册、模型调用、状态持久化、可观测);Workflow 负责任务编排(步骤定义、条件分支、重试与补偿);Node 是最小执行单元(一次模型调用、一次工具调用或一段确定性逻辑)。这样分层的好处是”换编排不影响执行、换模型不影响编排”,也便于单独测试每一层。与 Dify/扣子的差别通常在可控性与深度:通用平台面向可视化搭建,自研 Runtime 面向内部系统的深度集成(权限、私有工具、专有上下文策略)。
分层上下文与压缩触发:分层是为了同时控制体积和保留关键证据——最近若干轮保留原文、更早的内容做摘要、再早的只留索引与结论,原始内容落到外部存储并保留可按需回查的 ID。压缩触发通常有几个信号:Token 数超过阈值(如模型窗口的 X%)、轮数超过阈值、或检测到上下文里包含大量已无用的工具结果。大 Tool Result 的阈值按字节数或 Token 数设,超过就先裁剪(只留关键字段/前后片段)并标注截断,原始结果必须保留在外部存储——因为后续步骤可能真的需要它。
摘要对 Prefix Cache 的影响:会影响。Prefix Cache 按前缀逐 token 匹配,摘要一旦改变(哪怕只是重新生成导致措辞不同),被改动的部分之后全部缓存失效,成本和首 token 延迟都会上升。降低影响的做法是:把稳定内容(系统指令、工具定义、固定示例)放在最前面且保持字节级一致;把易变的摘要放在靠后;摘要尽量”追加式”而不是”重写式”(例如保留旧的摘要段不动,只追加新的压缩段);以及固定摘要模板与措辞风格,减少无意义差异。
Skill 路由评测:评的是”给定用户请求,该不该加载某个 Skill、加载得对不对”。要构造正例(应当路由到 A)和反例(相似但属于 B,或不该加载任何 Skill),指标用准确率/召回率/混淆矩阵,重点看误路由的方向(漏加载 vs 错加载)。路由差不能只改 description——Skill 数量多、功能重叠时,需要在元数据层面做区分(触发条件、不适用场景、示例),甚至做两级路由(先按域粗分再精挑)。评测对象要区分内置 Skill 与业务方 Skill:内置的可以直接改,业务方的要靠”路由失败样本 + 改进建议”反馈回去,形成闭环。
为什么自研 Runtime 而不是用开源框架:常见理由有三类——控制力(需要深度定制上下文策略、权限模型、审计与合规)、集成度(要接内部工具、内部模型网关、内部权限体系,开源框架改造成本高于自研)、以及可观测与成本(需要按业务维度统计 token 与成本、做精细限流)。反面理由也要能说:自研的代价是维护成本与生态缺失,所以要能说明”哪些用了开源、哪些自研、边界在哪”。
沙箱与隔离:Docker 容器共享宿主内核,用 namespace 做资源视图隔离、cgroup 做资源限制,隔离强度中等——内核漏洞可能被逃逸。gVisor 在应用与宿主内核之间插入一个用户态内核(Sentry),把系统调用拦截并重新实现,攻击面大幅缩小,代价是系统调用开销和部分兼容性问题。microVM(如 Firecracker)给每个实例一个独立内核,启动快(百毫秒级)且隔离接近传统 VM,是”多租户跑不可信代码”的主流选择。传统 VM 隔离最强但启动慢、资源开销大。给 Coding Agent 做沙箱还有额外要求:文件系统要能挂载项目并控制写权限、网络要能限制外联、进程要有超时与资源上限,且销毁时确保不残留凭证。
把本地 Coding Agent 做成多人 SaaS:关键是”每个会话一个隔离实例 + 项目文件持久化”。创建:按用户请求拉起 microVM/容器,挂载该用户的项目卷,注入临时凭证(短期、按仓库限权)。复用:同一用户同一项目可复用暖实例(保留依赖缓存缩短冷启动),但要隔离不同用户的实例。销毁:空闲超时回收,销毁前确保代码已提交/推送、工作区落持久卷,凭证失效。项目文件的保存有两条路——持续挂载持久卷(实时同步)或以 Git 为真源(要求 Agent 定期提交并推送)。后者更干净:实例本身无状态,销毁后重建只需重新 clone。还要处理并发编辑冲突(同一项目多次会话)、配额与成本归因、以及审计日志。