Skip to content

AI智能体应用开发面试题(2026-06-12 02:35) ​


【面试题】1. 你在做多智能体协作项目时,怎么避免"羊群效应"——多个Agent抢同一个工具或输出重复? ​

【标准答案】 核心思路是"角色分工+冲突仲裁"。

分工层面:每个Agent有明确的职责边界,比如专门负责搜索的只管搜索,负责写作的只管写作,物理上隔离工具调用权限,避免职责重叠。

协调层面:我一般会设计一个Orchestrator(编排器)Agent作为中枢,它负责拆解任务后,把子任务分发给专用Agent,最后汇总结果,而不是让Agent之间直接对等通信——对等通信在大模型里很容易变成"吵架"。

具体机制:任务分发时带上"独占锁"的语义,比如"你负责这个搜索任务,直到完成,其他人不能动";汇总阶段用去重逻辑,根据输出内容或语义指纹做相似度检测,把重复结果合并。

羊群效应的本质是缺乏中心调度,所以设计思路就是"让合适的人做合适的事,而不是所有人抢同一件事"。


【面试题】2. Dify的工作流编排里,如果某个节点失败了,怎么设计自动降级策略? ​

【标准答案】 Dify的工作流本身支持节点级别的错误处理,我一般分三层设计降级:

第一层:节点内重试。对不稳定节点(调用外部API、模型推理),配置3次指数退避重试,间隔10s/30s/90s,避免瞬时失败。

第二层:失败分支兜底。每个关键节点并联一个"降级节点",比如大模型生成失败时,自动切换到预设模板填充;搜索API超时时,切换到缓存结果或者返回"暂不可用"。

第三层:全局兜底。工作流最末端设置一个"默认回复"节点,无论前面哪步出错,最终用户拿到的是一个友好回复,而不是直接暴露错误。

设计原则是:降级不是隐藏问题,而是让系统在部分能力缺失时仍然可用,同时记录错误供后续排查。


【面试题】3. 1-3年经验的候选人在RAG系统里,怎么平衡"召回率"和"精确率"? ​

【标准答案】 核心矛盾是:召回低了漏答案,精确率低了噪音多。实操中我一般这么处理:

召回端:用混合检索——语义向量检索+关键词BM25同时跑,取并集或用RRF融合打分。向量化时选一个偏稠密的模型(哪怕牺牲一点精确率),比如text-embedding-3-small配合768维,比稀疏向量召回更全。

精确端:召回后加"重排序"(ReRanker),用Cohere或者LLM做二轮排序,把真正相关的Top-K提到最前面。提示词里明确要求"基于检索内容回答,不要依赖外部知识",减少模型幻觉带来的精确率下降。

一个经验:先保证召回够用(能答出来),再优化精确(答得准),因为漏答比噪音更致命。


【面试题】4. 面试官问"如果让你从0设计一个客服Agent,你的第一步是什么?" ​

【标准答案】 第一步是画清楚人机边界,不是直接写代码。

具体说,我先想清楚三件事:

  1. 哪些是规则性任务(查订单、退款政策、FAQ)——这些用工作流+知识库解决,不需要LLM参与,稳定可控。
  2. 哪些是真需要LLM理解的任务(复杂投诉、多轮对话意图判断)——这些才上Agent。
  3. 边界在哪——用户说什么话的时候,Agent应该转人工。

产出物是一张表:左边是用户问题类型,右边是处理方式(规则/Agent/转人工)。这张表定好了,后面搭框架才不会返工。

很多人一上来就搭LangChain链,结果搭完发现大部分问题其实用if-else就够了,这是经验不足最常见的问题。


【面试题】5. LangChain的LCEL链式调用里,RunnablePassthrough和RunnableParallel在什么场景用?怎么配合? ​

【标准答案】

RunnablePassthrough:透传输入,不做任何转换。用于把上游输入原封不动地传给下游,或者在链中间"插入"一个什么都不做的节点来保持数据流完整。

python
chain = prompt | model | output_parser
# 实际调用时,输入是 {"question": "xxx"}
# 如果想让输入透传到prompt,就用 RunnablePassthrough()

RunnableParallel:并行执行多个任务,接收一个字典,返回一个字典。常用于"同时查知识库+查数据库+查配置"这种可以并行跑的步骤,然后再把结果合并给LLM。

python
combined = RunnableParallel(
    context=retriever,
    config=config_retriever,
    history=memory
)
chain = combined | prompt | model

配合场景:比如先RunnableParallel同时拿多个数据源,再用RunnablePassthrough把结果透传给下一步的prompt,这是LCEL里最常见的组合之一。


【面试题】6. 多模态Agent在处理"图文混排"文档时,最大的坑是什么?怎么解决? ​

【标准答案】 最大的坑是布局信息丢失。

大多数多模态模型把图片整体喂进去,但图文混排文档(PPT、网页、PDF报表)有很强的空间结构——文字在左、图片在右,表格跨两栏。如果直接OCR或者整体描述,会丢失"哪里说的是什么"这个关键信息。

解决方案:

  1. 版面分析在前:用专门的版面分析模型(或者PP-Structure这类工具)先把文档切分成阅读顺序,识别标题段落在哪、图片标题在哪。
  2. 区域裁剪:按照版面分析结果,把文档切成小块,每块单独做OCR或描述,保持局部上下文。
  3. 结构化输出:最终输出不是纯文本,而是一张结构化JSON,标注每个内容块的位置和类型,后续RAG检索时按位置权重排序。

一句话总结:多模态不是把图片直接扔给VLM就完了,前处理和版面理解才是决定效果的关键。


【面试题】7. 智能体的"记忆系统"怎么设计,才能让对话有连贯性又不会超出上下文限制? ​

【标准答案】 我一般用三层记忆架构,按时间由近及远:

第一层:工作记忆(Conversation Summary)。最近的3-5轮对话,用LLM摘要压缩成一段话,不是原文拼接。这样5轮对话从500字压到80字,上下文开销小。

第二层:会话记忆(Session Memory)。当前会话的完整记录,但做滑动窗口,比如保留最近20轮,超出的部分同样摘要压缩。

第三层:长期记忆(Long-term Memory)。持久化存储用户偏好、历史任务、关键结论。用向量数据库按语义检索,只在需要时召回,不需要全量塞进上下文。

关键原则:不是记忆越多越好,而是"按需召回"。每次对话开始前,用语义检索从长期记忆里捞出相关的几条,作为system prompt的一部分注入进去。


【面试题】8. 用CrewAI做多Agent项目时,如果任务A依赖任务B的结果,怎么用Task Dependencies正确配置? ​

【标准答案】 CrewAI的任务依赖配置很直接,用context参数指定依赖:

python
task_b = Task(
    description="分析竞品数据",
    agent=analyst,
    expected_output="竞品对比表格"
)

task_a = Task(
    description="撰写推广方案",
    agent=writer,
    expected_output="完整方案文档",
    context=[task_b]  # 关键:这里声明依赖task_b
)

CrewAI的Crew在run的时候会自动等待task_b完成后,把它的输出作为context注入到task_a的prompt里,不需要手动传参。

常见踩坑点:很多人忘记在expected_output里写清楚输出格式,导致下游Agent拿到的是一堆废话没法用。所以expected_output要写得具体,比如"输出一张包含竞品名称、月活、价格三列的对比表格"。


【面试题】9. 你怎么理解"智能体的规划能力"?ReAct和Plan-and-Execute两种范式各适合什么场景? ​

【标准答案】

规划能力的本质:让模型不只是"见招拆招",而是能预判多步路径再执行。

ReAct范式:Think→Act→Observe循环,边做边想。适合任务路径不明确、环境反馈重要的场景,比如聊天机器人、动态搜索、工具组合探索。优点是灵活,缺点是步数不可控,容易在循环里打转。

Plan-and-Execute范式:先完整规划所有步骤,再按顺序执行。适合任务路径相对固定、步骤可预期的场景,比如数据清洗流水线、报告生成、批量处理任务。优点是可控可审计,缺点是规划错误会导致整条链失效。

我的选择习惯:ToB产品(客服、审批)用Plan-and-Execute,因为需要可解释可审计;ToC或者探索性场景用ReAct,灵活优先。


【面试题】10. 如果线上Agent响应变慢了,你怎么快速定位瓶颈是出在模型推理还是工具调用? ​

【标准答案】 快速定位的方法是打时间戳日志,每个环节单独计时:

Step1 [LLM推理]     →  2.3s  ✅ 正常
Step2 [工具选择]    →  0.1s  ✅ 正常
Step3 [知识库检索]  →  8.7s  ❌ 超时!
Step4 [结果生成]    →  省略

常见规律:

  • 如果是LLM推理慢 → 看模型响应时间曲线,是否模型限速了,考虑换更快的模型或加缓存
  • 如果是工具调用慢 → 优先检查网络延迟、API限速;如果工具是本地检索,看索引大小和硬件资源
  • 如果是生成内容长但慢 → 检查是否向向量库塞了太多无关内容,导致检索+生成都变慢

最实用的做法:在代码里用time.time()对每个环节打日志,配合日志的trace_id串联请求,线上跑一天就能画出性能瓶颈的热力图,定位准确率很高。