主题
高频面试题
如果让你从零设计一个 Agent 框架,你会优先实现哪些核心模块?为什么?
这道题不是让你复刻 LangChain 或某个 SDK,而是看你能否从最小可用 Agent Runtime 出发,按风险和复用价值安排框架能力。
面试官角度分析,想考什么
从零做框架你会先实现哪些模块?
考最小闭环:模型适配、Runner 循环、状态、工具执行、权限、trace 和 eval。哪些不该一开始就做复杂?
考克制:长期记忆、多 Agent、插件市场可以后置,先保证单 Agent 可控。这些优先级为什么合理?
考取舍:先解决不可控、不可调试、不可评估,再追求复杂编排。
可直接抄走的 30 秒参考答案
text
如果从零做 Agent 框架,我会先实现最小可控 runtime:模型适配层负责统一不同模型的调用和工具 schema;Runner 负责 agent loop、终止条件、重试和恢复;State 管消息、工具结果和 checkpoint;Tool Registry/Executor 管工具 schema、版本、执行和 MCP 接入;Policy/Guardrail 管权限、风险、人工确认和输出检查;Trace 记录模型、工具、策略和状态变化;Eval 用真实 case 做回归。长期记忆、多 Agent、插件生态和可视化编排可以后置,因为它们都依赖这些基础能力。面试回答详解,知其所以然
从零设计 Agent 框架,第一目标不是“功能多”,而是让一个 Agent 能可控地完成多步任务,并且出错时能定位、能恢复、能评估。框架的价值在于把每个项目都会重复写的运行时能力沉淀出来。
1. 第一优先级:模型适配层
模型适配层负责把不同模型供应商的差异收敛成框架内部统一接口:
- chat / responses 调用。
- tool schema 格式转换。
- streaming。
- structured output。
- token usage 和成本统计。
- retry、timeout、rate limit。
- 模型能力声明,例如是否支持并行工具调用、JSON schema、reasoning effort。
它的目标不是屏蔽所有差异,而是让上层 Runner 不被供应商 API 细节污染。面试里可以说:模型适配层是 portability,但不能抽象到丢失关键能力。
2. 第二优先级:Runner 和 Agent Loop
Runner 是框架的心脏,负责把一次用户请求推进成多步执行:
text
load state -> build context -> call model -> parse action
-> authorize -> execute tool -> reduce observation -> decide stopRunner 至少要支持:
- 最大步数、最大时间、最大 token。
- 工具调用循环。
- 工具结果回传。
- 终止条件。
- 错误重试和降级。
- 可中断、可恢复。
- streaming 输出和最终结果。
Agent 本身可以只是配置对象:name、instructions、tools、model、output schema、handoff candidates。Runner 才是行为入口。这个拆法方便版本化、测试和复用。
3. 第三优先级:状态和会话管理
Agent 不是单轮 completion,它需要维护会话和任务状态:
- 原始消息历史。
- 当前任务计划和进度。
- 工具调用记录。
- 中间 artifacts。
- 用户确认状态。
- 错误和重试信息。
- checkpoint 和可恢复快照。
状态层最好采用事件流 + 当前快照:
text
Event Log: user_message, model_action, tool_call, tool_result, approval, error
Snapshot: current_plan, active_agent, allowed_tools, task_status事件流用于审计和回放,快照用于快速恢复和继续执行。没有状态层,Agent 一旦工具失败、页面刷新或进程重启,就很难可靠恢复。
4. 第四优先级:工具注册、执行和 MCP 接入
工具层不是把 Python 函数包一下这么简单。它应该包括:
- Tool Registry:工具名、描述、schema、版本、owner、risk level。
- Tool Executor:执行本地函数、HTTP API、队列任务、MCP tools。
- 参数校验:JSON Schema、业务规则、默认值和类型转换。
- 结果规范:结构化 result、错误码、可展示摘要、原始 payload。
- 幂等、重试、超时、取消。
- 工具选择治理:动态白名单、工具分组、相似工具去重。
如果框架面向生态,MCP client 支持应尽早考虑,因为它能把外部 tools/resources/prompts 统一接入。但 MCP 不替代工具权限和审计。
5. 第五优先级:权限、策略和 Guardrail
工具能产生副作用后,框架必须有控制面:
- 输入风险识别和 prompt injection 防护。
- 动态工具白名单。
- 用户/租户/资源 ACL。
- 参数级 policy。
- 高风险动作人工确认。
- 输出安全检查和脱敏。
- 沙箱配置,例如文件、网络、CPU、内存。
这个模块要在工具执行前生效。LLM 可以建议动作,但不能决定自己是否有权执行。Guardrail 可以使用规则、小模型、分类器或人工审批,但最终要落在 runtime 的 allow/reject 决策上。
6. 第六优先级:Trace、日志和可观测性
没有 trace 的 Agent 框架很难进入生产。Trace 至少要覆盖:
- 每次模型调用的输入摘要、输出、模型、token、延迟。
- 每次工具调用的参数、结果、错误和耗时。
- policy 判断和审批记录。
- handoff、子 Agent、状态变更。
- 最终输出和用户反馈。
推荐用 span 结构:
text
trace
span: model_call
span: tool_call
span: guardrail
span: handoff
span: evaluatorTrace 是调试、评估、成本优化、安全审计和 badcase 回归的共同基础。
7. 第七优先级:Eval 和测试框架
Agent 框架如果没有 eval,很快会变成“改 prompt 靠感觉”。Eval 模块应支持:
- 离线数据集:输入、期望行为、工具 mock、判分逻辑。
- 轨迹评估:是否选对工具、参数是否正确、是否恢复错误。
- 输出评估:准确性、忠实性、完整性、格式。
- 安全评估:越权、泄漏、prompt injection。
- 回归比较:case-level pass/fail diff。
- LLM-as-judge、规则 judge、人工 review 的组合。
这部分可以一开始很轻,但必须早做,因为框架抽象好不好,需要 eval 反馈。
8. 后置模块:记忆、多 Agent、插件和 UI
在最小闭环稳定后,再扩展:
- Memory Service:长期偏好、事实、经验的写入、检索、冲突和删除。
- Multi-Agent / Handoff:子 Agent、路由、并行 worker、聚合器。
- Workflow Graph:显式状态机、节点、边、reducer。
- Plugin / Skill 系统:工具、prompt、资源包和版本管理。
- 人机协同 UI:审批、任务进度、trace 查看、artifact 预览。
- 部署层:队列、worker、租户隔离、成本配额、限流。
面试里要强调后置不是不重要,而是它们依赖前面的 state、tool、policy、trace 和 eval。
面试官追问3个问题
追问一:Agent 和 Runner 为什么要拆开?
- 考察点:抽象边界。
- 回答方向:Agent 是配置和角色,Runner 是执行行为。拆开后 Agent 可版本化、可复用、可测试,Runner 可以统一管理 loop、权限、trace 和恢复。
追问二:为什么 eval 要早做?
- 考察点:工程反馈闭环。
- 回答方向:Agent 行为非确定性强,prompt、模型、工具 schema 一改就可能回归。早做 eval 能指导抽象设计,并防止框架只在 demo 上好看。
追问三:长期记忆为什么不放第一优先级?
- 考察点:优先级判断。
- 回答方向:长期记忆依赖状态、权限、检索、注入、删除和评估。单 Agent loop 和工具权限不稳时,记忆只会放大污染和泄漏风险。
扩展知识
Agent 框架和 LLM SDK 的区别
LLM SDK 主要封装一次模型调用;Agent 框架要管理多步行动。区别可以压成一句:
text
LLM SDK 管 request/response,Agent Framework 管 task/run/trace。因此 Agent 框架必须处理状态、工具、权限、错误恢复、终止条件和评估。
轻量原语优先
OpenAI Agents SDK 把 Agent、Handoff、Guardrail、Tracing 做成核心原语;Anthropic 也强调先用简单模式,只有复杂度确实需要时再引入更复杂框架。面试里这能说明你不是为了抽象而抽象。
框架最怕隐藏控制权
如果框架把 loop、工具执行和状态更新全藏起来,开发者很难调试。好的框架应该让关键决策可配置、可观测、可测试,而不是只提供“自动 Agent”黑盒。