本篇属于 智能体面试与工程基础 系列。
A25|P0:asyncio、线程和进程怎么选?
口述: asyncio适合可等待的I/O,通过协作调度让任务在等待点让出执行。阻塞库可考虑受控线程池;CPU密集任务考虑进程或释放GIL的实现。不能把CPython所有版本、构建及第三方库都说成同一GIL行为。Python任务文档
追问: async def里直接调用同步HTTP库会怎样?
A26|P0:FastAPI异步接口里有阻塞代码怎么办?
口述: 直接在async路由里运行阻塞操作会占住事件循环,拖慢同worker的其他请求。优先异步客户端,必要时显式卸载同步调用;CPU长任务考虑进程/任务worker。框架会对普通def路由做线程池处理,但不会自动替你卸载async函数内部随便调用的同步函数。FastAPI说明
追问: 线程池耗尽后,队列长度与超时怎么控制?
A27|P0:多个工具如何并发?
口述: 只并发无依赖且资源/副作用不冲突的调用,设全局及每工具并发上限。定义一个失败时取消其他任务,还是收集部分结果;例如TaskGroup与gather默认失败语义不同,要明确选择并测试取消清理。Python任务文档
追问: 限制了同时执行数,是否仍创建了几十万个等待任务?
A28|P0:为什么用SSE?
口述: SSE适合服务端向浏览器持续发送文本事件,例如token增量与任务状态;真正双向高频通信可考虑WebSocket。要处理代理缓冲、心跳、断线及事件序号。EventSource的自动重连不是服务端自动恢复任务,续传仍需事件存储与协议。SSE说明
追问: 先显示了一部分文本后报错,用什么事件告诉前端?
A29|P0:用户停止或断网,任务怎么取消?
口述: 先明确断线是取消还是允许后台继续;显式停止请求通过run_id传播取消信号,停止后续调度并清理资源。取消本地协程不一定停止远端模型计费或已提交副作用,要单独跟踪状态与提供方能力。
追问: 用户重新连接如何区分“仍在运行”和“已取消但结果回来了”?
A30|P0:长任务、Session、checkpoint存在哪里?
口述: 长任务可先返回job_id交给持久化worker执行,SSE订阅事件,连接寿命与任务寿命分开。数据库保存关键状态/版本,Redis可作缓存与协调,持久checkpoint按run或thread定位;仅进程内存不能满足重启恢复。LangGraph持久化
追问: Session、run、thread的ID映射和租户归属怎样设计?
A31|P0:同一Session并发更新如何避免冲突?
口述: 定义是否允许同会话多run。可按会话串行化,或用version条件更新与冲突重试;细粒度合并要有业务规则。单机async锁不能覆盖多个worker。不要在等待长时间模型响应期间一直持有数据库事务锁。
追问: 同一任务重复投递如何保证结果不覆盖新版本?
A32|P0:限流、并发控制与背压有什么区别?
口述: 限流控制单位时间准入,并发限制控制正在执行的数量,背压控制上游生产速度和排队压力。模型请求还受RPM、TPM与租户预算约束。设有界队列、超时、拒绝或降级;吞吐不能通过无限开线程解决。
追问: 每个请求允许10个工具并行,100个请求同时到来会怎样?
A33|P1:Redis与消息队列分别放什么?
口述: Redis可以缓存、限流和协调,但关键状态能否放其中取决于持久化、复制与失效要求;队列用于长任务与异步事件,消费端要按投递语义去重。Kafka的事务语义不自动覆盖任意外部API的副作用。
追问: 数据库状态写成功而事件发送失败,能否用outbox并实现消费幂等?
A34|P0:权限、Prompt Injection与人工审批怎样落地?
口述: 外部文档和日志是数据,不能授予权限;运行程序负责工具白名单、租户授权、参数与目标校验、隔离与审计。高风险操作把具体目标和参数交给用户确认,审批应绑定本次操作,参数变化后重新判断。prompt不能替代执行层控制。
追问: 文档要求模型把token发到某个URL,哪一层会阻止?
A35|P0:数据库事务与Agent操作日志怎么结合?
口述: 用事务保证任务状态和数据库内执行记录一致,用唯一约束或条件更新实现幂等竞争。防脏读只是其中一项;业务审计需要记录谁在什么版本下执行了什么。外部操作与本地事务不原子时,用执行状态机和补偿/对账设计。
追问: 日志能否先标“成功”再调用API?回调重复怎样处理?
A36|P0:怎样定位性能和内存问题?
口述: 分解排队、模型首token、生成、检索、工具与数据库耗时,观察P95/P99、队列积压、内存和连接数。检查无界历史、缓存、任务引用与未关闭资源。模型成本可用减少无效调用、相关工具筛选、缓存和模型路由优化,但必须同时做质量回归。
追问: 缓存键如何包含租户、权限、模型/提示版本和数据时效?
A47|P1:如何把单体 Agent 服务扩到千级 QPS?
先定义口径: 千级是请求接入、任务完成还是模型调用 QPS?同步短问答、长任务与流式连接不能混算。按稳定系统的平均关系 在途任务数 ≈ 到达率 × 平均停留时间 估算:假设每秒1000个任务、平均30秒,约有30000个在途任务;这只是容量估算,不是实测成绩,突发和长尾还需额外余量。
实施顺序: 建立模型与工具调用次数、token、耗时分布,核算供应商 RPM/TPM;无状态接入层把长任务送入持久队列,有界worker执行,任务状态外置并按租户/会话隔离。连接层支持SSE心跳与续传,队列按年龄及积压告警,避免只盯CPU。
故障与发布: 依赖超时、退避重试、熔断、隔离并发池和降级同时考虑,避免重试放大流量。先用模拟依赖压测服务容量,再受控验证真实模型限额与端到端质量;按版本小流量灰度,跟踪错误率、P95/P99、成功任务成本,保留回滚和旧checkpoint兼容方案。
追问: 网关能接收1000 QPS,但模型只能处理其中十分之一,应排队、拒绝、降级还是改变产品交互?给出有上限的等待与用户反馈,而不是无限扩线程。