AI智能体应用开发面试题
生成时间:2026-06-15 21:35
题目数量:10道
知识范围:1-3年岗位要求,聚焦全新考点(避免与历史题库重复)
【面试题】1. MCP(Model Context Protocol)是什么?你在实际项目中是怎么用它来连接智能体和外部工具的?
【标准答案】 MCP是Anthropic推出的开放协议,核心思路是把"工具调用"标准化——就像USB-C统一了外设接口一样,MCP统一了智能体与外部工具、数据源的连接方式。
MCP的核心架构:
- MCP Server:工具提供方,实现一个标准接口暴露工具和数据资源
- MCP Client:智能体侧,通过协议自动发现Server的能力
- 传输层:支持stdio(本地进程间通信)和SSE(远程服务)
我的实战经验: 在一个内部数据分析Agent项目中,我把五个数据源(MySQL、ClickHouse、Elasticsearch、公司API网关、文件系统)各封装成一个MCP Server。Agent启动时自动发现所有可用工具,无需硬编码工具列表。
收益:
- 新增数据源只需加一个MCP Server,Agent zero-code接入
- 工具描述统一管理,工具文档自动同步到模型侧
- 安全性提升:MCP Server可以独立做鉴权,不会把内部API Key暴露给Agent
相比传统Function Calling的优势: 传统方式要在代码里显式定义每个工具的JSON Schema,MCP让工具发现变成运行时动态的——Agent问Server"你支持什么"就行了。这对工具数量超过20个的场景特别有用。
【面试题】2. 智能体在工作流执行过程中意外中断了(如服务重启、API超时),你如何设计"中断恢复"机制来保证不丢失进度?
【标准答案】 这是生产环境必须解决的问题。我设计的方案叫"检查点+补偿事务"模式:
核心思路:把Agent的每次决策和中间结果都持久化,中断后从最近的检查点恢复。
第一层:状态持久化 每次Agent执行完一个步骤(Thought/Action/Observation),都把完整状态写入数据库:
{
"session_id": "xxx",
"step_index": 5,
"status": "done",
"state": {
"已完成工具调用": ["搜索竞品列表", "分析竞品A"],
"当前任务": "分析竞品B",
"pending_tools": ["分析竞品C", "汇总报告"],
"accumulated_context": "已分析竞品A和B..."
},
"created_at": "2026-06-15 21:00:00"
}用LangGraph的StateGraph天然支持这个模式——它的State对象可以配置为持久化到PostgreSQL或Redis。
第二层:幂等性设计 工具调用必须是幂等的——调用一次和调用多次效果一样。比如"发送邮件"就不幂等,实现方式是先存草稿(幂等),再触发发送(带唯一ID去重)。
第三层:恢复策略 中断后恢复时:
- 读取最新检查点,加载state
- 检查pending_tools,跳过已完成步骤
- 重新执行未完成的工具调用
- 用事务ID去重,避免重复执行副作用
实战案例: 我们做数据报告Agent,一次任务可能要跑30分钟。加了检查点后,半夜API超时中断,第二天重启后自动从第7步继续跑,用户完全没感知。
框架支持:
- LangGraph的
Checkpointer+SqliteSaver/PostgresSaver - CrewAI的
KickoffTask支持异步+重入
【面试题】3. GraphRAG和传统RAG有什么区别?你什么时候会选择用GraphRAG?
【标准答案】 传统RAG是把文档切块后向量化存向量库,检索时找语义相似的块。适合"答案在一个文档块里"的场景。
GraphRAG是在文档之上建知识图谱:提取实体(人、事、物)和关系(实体之间的连接),检索时既做语义搜索也做图谱遍历。适合"答案需要跨文档推理"或"需要发现实体间关系"的场景。
核心区别:
| 维度 | 传统RAG | GraphRAG |
|---|---|---|
| 数据结构 | 文档块向量 | 实体+关系+社区摘要 |
| 检索方式 | 向量相似度 | 向量检索 + 图遍历 + 社区查询 |
| 适合问题 | "苹果的毛利率是多少?" | "苹果和微软的供应链有什么共同点?" |
| 推理能力 | 弱(需要模型自己关联) | 强(图结构天然展示关系) |
| 构建成本 | 低 | 高(提取+建图+社区检测) |
| 维护成本 | 低 | 高(图谱更新复杂) |
选型判断:
- 问题多数是直接查询型("XX公司的XX指标")→ 传统RAG够用
- 问题需要多跳推理("哪些公司同时与A和B有合作关系")→ GraphRAG
- 数据量大且关系密集(如论文评审、法律案例、医疗诊断)→ GraphRAG值
我的实战: 做一个企业内网知识库时,一开始用传统RAG效果尚可,但用户问"这个部门和那个部门有什么协作历史"这类跨文档问题时,传统RAG就抓瞎了。改用Microsoft的GraphRAG方案后,提取出部门、项目、人员的关系图谱,这类问题准确率从55%提升到82%。
部署姿势:不需要所有数据都走GraphRAG,可以分层——简单问答走传统RAG(快且便宜),复杂推理走GraphRAG(慢但准),用"问题复杂度分类器"做路由。
【面试题】4. 你在智能体开发中怎么用结构化输出(Structured Output)?遇到过什么坑?
【标准答案】 结构化输出是让Agent从"写文章"变成"填表格"的能力,对构建可靠Agent至关重要。
我的用法:
- 工具调用参数:用
response_format={"type": "json_schema", "json_schema": {...}}强制模型输出合法JSON,而不是靠Prompt约束 - Agent的决策输出:要求Agent输出固定Schema,比如
{"thought": "...", "next_action": "call_tool", "tool_name": "search", "parameters": {...}} - RAG答案格式:要求答案包含
{"answer": "...", "confidence": 0.9, "sources": ["doc1", "doc2"]},方便下游做置信度判断和引用溯源
踩过的坑:
坑1:复杂嵌套Schema模型经常漏字段 用gpt-4o-mini输出深层嵌套的JSON Schema,经常漏掉optional字段或给出不合法的枚举值。 解决:Schema尽量扁平化,嵌套不超过2层;用Pydantic做后置校验,校验失败重试一次(在Prompt里附上错误信息让模型修正)。
坑2:结构化输出和Function Calling冲突 同时用response_format和tools参数,某些API版本不支持。 解决:如果既要用工具又需要结构化输出,我统一走Function Calling路径(把所有输出需求定义成一个叫final_answer的工具)。
坑3:Schema版本管理 换了Schema结构,旧Session存的数据和新Schema不兼容。 解决:Schema文件用Semantic Version,在metadata里记录版本号,下游做兼容转换。
实战技巧:
from openai import OpenAI
from pydantic import BaseModel
class AgentOutput(BaseModel):
thought: str
action: str # "call_tool" | "final_answer" | "ask_clarification"
tool_name: str | None = None
tool_params: dict | None = None
final_answer: str | None = None
# 强制结构化输出
response = client.beta.chat.completions.parse(
model="gpt-4o",
messages=[...],
response_format=AgentOutput,
)注:
response_format传Pydantic模型是OpenAI SDK的parse模式,会自动校验Schema
核心建议:结构化输出不应该只靠"告诉模型",要用API的原生能力(response_format、tools、strict=true)来做强制约束。
【面试题】5. 智能体系统的可观测性你是怎么做的?说一套从日志到追踪再到分析的完整方案。
【标准答案】 Agent系统的可观测性比传统后端Web服务复杂得多——因为有"推理链路"在里面,每一步都是LLM调用,不能只靠"状态码200"来判断。
我的三层可观测性架构:
第一层:结构化日志(Logging) 不只是记"调用了LLM",而是记:
{
"trace_id": "xxx",
"session_id": "xxx",
"step_type": "llm_call",
"model": "gpt-4o",
"prompt_tokens": 2500,
"completion_tokens": 350,
"latency_ms": 1200,
"temperature": 0.3,
"tools_called": ["search", "analyze"],
"success": true,
"user_input_hash": "xxx"
}每条日志挂上trace_id,串联整条Agent推理链路。
第二层:链路追踪(Tracing) 用OpenTelemetry + LangSmith/LangFuse做分布式追踪:
关键追踪指标:
- 端到端响应时间(P50/P95/P99)
- 每步的LLM调用耗时和token消耗
- 工具调用成功率、耗时
- 重试次数和原因
- Agent最终是否成功完成任务
LangSmith的用法:给LangChain的Runnable配置callbacks=[LangSmithCallbackHandler()],所有链路的输入输出、token消耗、耗时全自动追踪。
第三层:质量评估(Evaluation) 日志和追踪只是"发生了什么",质量评估回答"做得好不好":
自动化评估:
- 用LLM-as-Judge:用一个强模型(GPT-4o/Claude)给Agent的回答打分(准确性、完整性、安全性)
- 用
RAGAS评估RAG链路:Faithfulness、Answer Relevancy、Context Precision - Tool调用成功率、平均重试次数
- 用户显式反馈(👍👎)收集率
我的监控看板(Grafana): 放四个核心图:
- 端到端成功率趋势图(过去24h/7d)
- Token消耗按用户/功能拆分的柱状图
- 工具调用成功率热力图(按工具×时间)
- 用户满意度趋势(👍率/👎率)
实战案例: 接入LangSmith后,我发现某个工具调用成功但平均耗时5秒,排查发现是网络问题,切换到内网API后降到200ms。没有tracing根本抓不到这个问题。
工具推荐:
- 快速起步:LangSmith(和LangChain天然集成)
- 自托管/数据合规:LangFuse(开源,支持自部署)
- 大规模生产:OpenTelemetry + 自建收束
【面试题】6. 大模型的长上下文窗口(128K+ tokens)越来越普及,你怎么利用它?又有哪些实际坑?
【标准答案】 长上下文既是礼物也是陷阱,我的观点是"用但别滥用"。
我利用长上下文的方式:
1. 替代RAG的简单场景 当数据量小(<200页文档)且不需要频繁更新时,直接把全文塞进System Prompt,省掉RAG的复杂链路。比如给Agent一份完整的用户手册,而不是切块检索。
2. 多轮对话不丢上下文 用128K窗口可以存下10-20轮完整对话(含历史工具的调用结果),不需要做"记忆摘要压缩"。这让Agent在多轮交互中保持"完整记忆"。
3. 批量处理 一次传入50条待处理的记录,让模型批量生成结果,用结构化输出分离,减少API调用次数。
踩过的坑:
坑1:注意力衰减(Lost in the Middle) 模型对"中间部分"的记忆最差,开头和结尾记得最牢。把100页文档放中间,50-70页的内容经常被忽略。 解决:
- 把最重要的信息放开头和结尾
- 或者分段处理:先让模型扫描全文摘要,再对关键章节深入分析
- 用Anthropic的Prompt Caching把文档缓存,减少注意力衰减
坑2:Token成本并不便宜 128K token输入的成本=纯文本的30-50倍。如果每天处理1000次请求,用长上下文的费用是RAG方案的5-10倍。 解决:只对需要全局上下文的请求用长上下文(如"总结全文"),简单的单点查询走RAG。
坑3:延迟大幅增加 输入50K tokens时,首Token延迟可能从500ms飙到5-10秒。 解决:用Prompt Caching(Anthropic)或KV Cache优化,把重复的文档内容缓存起来,首Token延迟能降70%。
我的选型策略:
数据量 < 100页 + 不需要频繁更新 → 直接长上下文(省去RAG)
数据量 > 100页 + 需要实时更新 → RAG(成本可控)
数据量 > 500页 + 需要全局推理 → GraphRAG + 长上下文做最后汇总【面试题】7. 你做过代码生成Agent吗?怎么保证生成的代码是正确且安全的?
【标准答案】 做过一个"自动修复Bug"的Agent,嵌入到CI/CD流水线里。
架构设计(四阶段):
阶段1:代码理解 把代码仓库上下文(文件结构、相关代码块、Git diff)注入到Agent的上下文中。关键是用"仓库地图"——只传相关文件,不传整个仓库(用embedding检索相关代码)。
阶段2:代码生成 Agent用few-shot示例+结构化输出生成代码变更:
{
"changed_files": ["src/api/handler.py"],
"changes": [
{
"file": "src/api/handler.py",
"operation": "modify", // "create" | "modify" | "delete"
"start_line": 42,
"end_line": 55,
"new_content": "def handle_request(...):\n ..."
}
]
}阶段3:安全执行沙箱 生成的代码绝不能直接执行。我的做法:
- 隔离沙箱:用Docker容器执行,限制文件系统只读、网络断连、CPU/内存配额
- 静态分析:自动跑pylint/mypy/bandit做代码质量审查
- 单元测试:自动生成测试用例并执行,通过率<90%的代码变更自动标记为"不可用"
阶段4:人工审核入口 Agent生成的代码以PR形式提交,加上AI Review Comment,必须有真人 approve 才能合并到主分支。
实战中遇到的关键问题:
问题1:Agent容易生成"看似正确但实际有逻辑漏洞"的代码解决:要求Agent输出"变更的测试用例"和"变更理由",Reviewer Agent用这些信息做交叉验证。
问题2:Agent会保留旧代码中的安全隐患(如硬编码密码)解决:在代码分析阶段,加一道安全扫描工具(如Semgrep),自动标记安全风险点,Agent生成时必须处理这些标记。
问题3:Agent生成代码依赖一个第三方库不存在解决:沙箱执行时自动检测导入失败,把错误信息反馈给Agent让其修正。
安全原则:代码生成Agent的核心原则是 "generate but not execute without human approval"——不要相信模型生成的代码直接能跑,更不要相信它没安全漏洞。
【面试题】8. 语义缓存(Semantic Caching)怎么做?对降本有多大帮助?
【标准答案】 语义缓存不是"相同问题直接命中缓存"(那是传统KV缓存),而是"语义相似的问题复用答案"——用户问"退款要多久"和"退款时间多长"得到同样的答案。
实现方案:
用户问题 → Embedding → 向量检索缓存库 → 命中(相似度>阈值) → 直接返回缓存答案
→ 未命中 → 调用LLM → 存缓存 → 返回核心参数:
- 相似度阈值:0.85-0.95(默认0.90),太高命中少,太低会返回不相关答案
- 缓存TTL:根据场景设定,事实性问题设长(24h),时效性问题设短(5min)
- 缓存大小:常见FAQ场景存最近1000条就够了
技术实现(Redis + Embedding):
import numpy as np
from redis import Redis
class SemanticCache:
def __init__(self, threshold=0.90):
self.redis = Redis()
self.threshold = threshold
def get(self, query: str) -> str | None:
q_vec = embed(query) # 用户问题转向量
# 检索缓存的query向量,计算相似度
for cached_query, cached_answer, vec_blob in self.redis.hscan_iter("semantic_cache"):
cached_vec = np.frombuffer(vec_blob, dtype=np.float32)
sim = cosine_similarity(q_vec, cached_vec)
if sim > self.threshold:
return cached_answer
return None
def set(self, query: str, answer: str):
vec = embed(query).tobytes()
self.redis.hset("semantic_cache", query, answer)
self.redis.hset("semantic_vecs", query, vec)
self.redis.expire("semantic_cache", 86400) # 24h TTL更成熟的方案:用向量数据库代替Redis做缓存检索,适合大规模场景。
- Redisearch(Redis的向量搜索模块)
- Qdrant/Pinecone做缓存库(和RAG复用一套基础设施)
对降本的实际效果:
我们一个知识问答Agent,上线后前两周数据:
- 总查询量:50,000次
- 语义缓存命中率:~30%(常见多的是"退款"/"登录"/"如何"这类高频问题)
- 节省的LLM调用:15,000次
- 按GPT-4o mini计费,每月节省约$600
命中率优化技巧:
- 双阈值策略:高阈值(0.95)直接返回,中阈值(0.85-0.95)返回时标注"可能不完全匹配,仅供参考"
- Query归一化:统一语言(英文→中文)、去掉停用词、同义词替换,提升命中率
- 缓存预热:上线前把历史FAQ扔进去预缓存,启动即有命中
注意事项:
- 时效性敏感场景(如"今天天气")不要走语义缓存,设category标记
- 个人化问题(如"我的订单")不要走语义缓存,涉及隐私
- 定期清理冷数据,防止缓存膨胀
语义缓存是成本控制中最被低估的手段——实现简单、收益显著,建议所有RAG/Agent项目都加上。
【面试题】9. 你怎么系统化地评估一个智能体的效果?用哪些指标?用什么工具?
【标准答案】 智能体评估比传统软件复杂——不只测"功不功能正常",还要测"回答质量"和"用户体验"。我的评估框架分三层:
第一层:功能正确性(Functional Correctness)指标:
- Tool调用成功率:Agent是否正确选择了工具并传了正确参数
- 任务完成率:Agent是否完成了用户的目标(如"查询订单"最后确实返回了订单信息)
- 意图识别准确率:Agent是否准确理解了用户意图
- Schema合规率:Agent输出是否符合要求的结构化格式
测试方法:准备50-100条标注好的测试用例(输入+预期输出),跑回归测试。用pytest写自动化用例,断言Agent的输出是否符合预期。
第二层:答案质量(Answer Quality)
LLM-as-Judge(自动化评分): 用更强的模型(GPT-4o/Claude)对Agent的回答做多维评分:
- 准确性(Accuracy):回答是否基于事实,1-5分
- 完整性(Completeness):是否回答了用户所有子问题
- 安全性(Safety):是否包含有风险或不当内容
- 引用正确性(Citation):RAG答案的引用是否真实命中
from ragas import SingleTurnSample
from ragas.llms import LangchainLLM
sample = SingleTurnSample(
user_input="退款多久到账?",
response="通常3-5个工作日,政策见...",
retrieved_contexts=["退款政策文档片段"], # RAG上下文
reference="3-5个工作日" # 期望答案
)
scorer = Faithfulness(llm=LangchainLLM(ChatOpenAI(model="gpt-4o")))
score = scorer.single_turn_score(sample)第三层:用户体验(User Experience)
- 用户满意度:对话后的👍👎点击率,目标>85%
- 首次解决率:Agent是否在首次交互中解决了用户问题(没发重问或转人工)
- 平均对话轮数:轮数越少效果越好(说明一次就懂了)
- 转人工率:越转人工说明Agent效果越差,目标<20%
评估工具推荐:
- RAGAS:RAG链路质量评估,最成熟的方案
- LangSmith / LangFuse:自带评估模块,支持在线评估+人工标注
- DeepEval:支持多种Agent和LLM的评估指标,CI集成方便
- 自建评估平台:大规模团队建议自建,把测试用例管理+自动评估+人工标注+趋势报表放一起
我的评估流程(每周跑一次):
- 从生产环境随机抽取100条对话(去隐私后)
- 自动跑LLM-as-Judge评分
- 人工标注Top-10高分和低分对话(用来校准自动评分)
- 对比上周数据,看趋势
- 发现某个指标下降,追查到具体问题类型,进入优化流程
核心原则:指标不是为了"好看",而是为了"发现问题"。如果一个指标连续两周不变化,说明它没在驱动优化,该换指标了。
【面试题】10. 你遇到过的AI Agent端到端响应慢的问题,从用户提问到收到回复,你排查过哪些瓶颈?怎么优化到1秒以内?
【标准答案】 端到端延迟优化是Agent工程化的必答题。我按"定位→优化"两步走。
第一步:链路拆解,找到瓶颈
一个典型Agent请求从发出到回复的完整链路:
用户请求 → 网络传输 → 意图识别(LLM) → 检索RAG(向量库)
→ 重排序(Cross Encoder) → 组装Prompt → LLM生成(首Token)
→ Streaming响应 → 网络传输 → 用户看到在生产中实际测到的各环节耗时占比(200次采样均值):
| 环节 | 耗时 | 占比 |
|---|---|---|
| 意图识别LLM | 200-400ms | 15% |
| 向量检索 | 20-50ms | 2% |
| Rerank | 50-150ms | 5% |
| LLM生成(首Token) | 500-2000ms | 50-60% |
| Streaming传输 | 200-500ms | 15% |
| 网络+序列化 | 100-200ms | 8% |
瓶颈很明确:LLM的首Token延迟是所有环节中最慢的。
第二步:针对性优化(从收益最高到最低)
优化1:LLM首Token加速(收益最大)
- Prompt Caching:用Anthropic的Prompt Caching或OpenAI的Project,把System Prompt和知识库上下文提前缓存,首Token延迟从2s降到300ms
- 模型选型:相同能力下选首Token更快的模型,如Claude Haiku比Sonite快,Gemini Flash比Pro快
- 降低Prompt长度:System Prompt不要超过2000 tokens,长文档走RAG而不是全文塞入
优化2:流式输出(Streaming)
- 用SSE(Server-Sent Events)边生成边输出,用户不需要等全部生成完
- 实测"读完前100字"的时间:非流式5s → 流式1.2s(TTP=Time To First Token + 100字生成时间)
优化3:并行化非依赖步骤
- 意图识别和向量检索可以并行,因为两者无依赖关系
- 用
asyncio.gather并行调用,节省串行等待时间
async def handle_request(query):
# 并行执行意图识别和向量检索
intent_task = detect_intent(query) # LLM调用
rag_task = retrieve_knowledge(query) # 向量检索
intent, docs = await asyncio.gather(intent_task, rag_task)
# 然后再合成回答优化4:缓存策略
- 语义缓存:语义相似的问题直接返回缓存答案,跳过LLM调用(命中时延迟从2s降到20ms)
- KV Cache共享:相同用户的相似请求复用模型内部的KV Cache
优化5:轻量级预判(前置过滤)
- 简单问题(如"你好"、"你是谁")直接用规则引擎回复,不走大模型
- 实现:用一个分类模型(可以是小模型BERT或setFit)做0-shot/1-shot判断,100ms以内
优化6:基础设施优化
- 向量数据库加连接池,避免每次建连接(Qdrant的gRPC默认有连接池)
- 模型实例保持warm状态(Serverless冷启动可以提前预热)
- CDN加速静态资源(前端文件、图标等)
我的优化前后数据对比:
| 指标 | 优化前 | 优化后 |
|---|---|---|
| P50延迟 | 3.2s | 0.8s |
| P95延迟 | 8.5s | 2.1s |
| P99延迟 | 15s | 4.5s |
| 首Token出现时间 | 2.5s | 0.8s |
| 日处理请求数 | 5000 | 5000(成本下降60%) |
最立竿见影的三个优化(按收益排序):
- Prompt Caching → 首Token延迟降60%
- 语义缓存 → 命中请求从3s降到20ms
- 并行化意图识别+RAG检索 → 串行变并行省500ms
一句话总结:不要一上来就折腾代码,先用量化手段找到瓶颈,LLM的首Token延迟永远是最大的优化空间,Prompt Caching + Streaming是默认必加的最小套餐。
本题库由AI智能体应用开发面试题生成器自动生成,聚焦1-3年经验岗位核心考点。本批次全部为全新考点,与历史题库无重复。