AI 应用开发 / Agent 面试题

按主题归类,相似问题已合并。括号内为原始题号。答案结合三个真实项目(mate-assist / jarvis-registry / rag_api)作答,并对齐官方知识点。
答题策略:先讲官方原理/取舍,再落到我项目里怎么做的 + 为什么,最后点一句踩坑/效果。


项目

项目 A:mate-assist —— 汽车销售助手后端

  • 定位:基于 FastAPI + LangGraph 的汽车销售助手后端,给一线销售提供「知识问答 + 销售话术 + 图片识车」能力。
  • 核心流程图(LangGraph 对话主图):
flowchart TD
    S([用户请求 /chat]) --> CC[context_control
上下文裁剪 · 滚动摘要] CC --> VP[vision_perceive
识图→结构化事实·接地 last_car] VP --> QR[query_rewrite
指代消解→自包含query] QR --> IC[intent_classify
意图分类 · 回写 last_intent] IC -->|route_by_intent 确定性查表| R{意图路由} R -->|knowledge / sales_support| RT[rag_retrieve
多路召回+rerank] R -->|chat| GEN R -->|discourse| DIS[discourse 话术
槽位填充·缺参interrupt反问] --> E([END]) R -->|vision_answer| VA[vision_answer 渲染识图结论] --> E RT -->|route_after_retrieve| RG[rag_grade
相关性打分 CRAG] RT -.直接够用.-> GEN RG -->|relevant| GEN[generate_answer
流式 SSE · 不加retry] RG -->|irrelevant| RW[rag_rewrite
换角度·rewrite_count 上限防死循环] RW --> RT GEN --> ME[memory_extract
后台异步抽取长期记忆] ME --> E
  • 四层模块:接入层 FastAPI/SSE → 编排层 LangGraph StateGraph(上图节点+条件边)→ 能力层 RAG(Weaviate+reranker)/记忆(checkpointer+MySQL store)/视觉/话术 → 基础设施 MySQL·Redis·COS·OTel·prompt-manager。
  • 关键设计:
    • State 里 messages(ground truth,add_messages reducer + checkpointer 持久化)和 model_input(本轮喂模型的临时上下文,覆盖语义)严格分离,裁剪/摘要/记忆注入只写 model_input,绝不回写 messages,防止污染历史。
    • rewritten_query(给生成/意图用的自包含问题)和 retrieval_query(给检索换角度用的词)严格隔离,防止检索截短词污染用户真实问题。
    • last_intent、last_car 持久化跨轮透传,解决「加个价格 / 换个版本」这类追问被无状态重判带偏。
    • 节点级 RetryPolicy(max_attempts=3),只重试瞬时故障(network/5xx/限流),generate_answer 流式节点不重试(重试会重复吐字)。
  • 技术栈:FastAPI、LangGraph(StateGraph + Checkpointer + Store)、MySQL(对话/记忆/checkpoint)、Redis、Weaviate 向量库、独立 reranker 服务、腾讯 COS(图片)、OpenTelemetry。
  • 提示词运维:prompt 资产独立放 prompt-manager 仓库,本地热加载、线上按不可变 release tag 加载,和代码解耦;catalog.py 在工作树不干净 / tag 不匹配时拒绝加载,测试走 fixture 镜像。
  • 离线侧:另有 Celery + Beat 跑批(约 1w 顾问、客户画像 + 推荐策略),源表(只读外部库)与结果库分库,首次全量 + 后续增量合并(latest-wins)。
  • 回归体系:scripts/ 下一整套端到端黑盒回归(意图延续、长期记忆、合规门禁、视觉、媒体、RAG 等),run_all_regression.py 统一入口接 CI。

面试可量化的亮点:滚动摘要让长对话 token 成本恒定;媒体链路优化把一次 /chat 从 2 分 7 秒降到正常;离线跑批并发 limit 8→20 让闸门等待 P50 32.5s→10.5s。

项目 B:jarvis-registry —— 企业级 MCP Gateway / A2A 编排平台

  • 定位:开源的企业级 MCP(Model Context Protocol)网关 + A2A(Agent-to-Agent)编排平台,让任意 AI copilot / 自治 Agent 安全、受治理地访问企业内部工具和数据。
  • 核心能力:
    • MCP 网关 / 反向代理:所有 AI 客户端统一经一个认证入口,走 MCP over SSE / Streamable HTTP。
    • 身份与鉴权:OAuth 2.0 / OIDC,对接 Keycloak、Cognito、Entra ID,自己不写认证代码。
    • 细粒度 ACL:middleware/rbac.py + acl_schema.py,scope / role 权限细到单个工具级别。
    • 语义化工具发现:services/search(FAISS 向量检索)对 skill/描述/tag 做语义搜索,Agent 运行时按需找到对的 MCP server / A2A agent。
    • 无状态网关:mcpgw/core/client_info_store.py 用 Redis 缓存 client-info,网关做成 stateless,可水平扩容。
    • 审计与可观测:全量请求日志、OpenTelemetry tracing、Prometheus metrics。
    • Federation + workflow-worker:多注册中心联邦 + 工作流 executor/scheduler。
  • 一句话价值:解决企业 AI「工具访问碎片化 + 安全盲区」问题——把鉴权、权限、审计、发现从每个 Agent 里抽出来,下沉到网关。
  • 核心流程图(MCP 网关 / A2A 编排):
flowchart TD
    subgraph CL[AI 客户端 / Agent]
      A[Cursor · Claude Desktop · Copilot]
      O[Orchestrator Agent]
    end
    A -->|MCP over SSE/HTTP| GW
    O -->|MCP over SSE/HTTP| GW
    GW[统一认证入口 / 反向代理] --> AUTH[身份认证
OAuth2·OIDC
Keycloak/Cognito/Entra] AUTH --> ACL[RBAC / ACL
scope·role 细到工具级] ACL --> PROXY[MCP 反向代理
无状态 · Redis client-info 缓存] DISC[语义工具发现
FAISS 向量检索 skill/tag] -.运行时按需定位.-> PROXY PROXY --> M1[MCP Server A] PROXY --> M2[MCP Server B] PROXY --> W[A2A Worker Agent] PROXY --> OBS[审计 & 可观测
全量日志·OTel·Prometheus] FED[Federation 多注册中心联邦] -.-> PROXY WF[workflow-worker
executor · scheduler] -.-> PROXY

项目 C:rag_api —— ID-based RAG 索引/检索微服务

  • 定位:LangChain + FastAPI 的异步、可扩展 RAG 后端,文档按 file_id 组织 embedding,用 PostgreSQL/pgvector 做向量库。给 LibreChat 等上层提供「文档入库 / 检索 / 删除」的 RAG 基础能力——是把 RAG 当独立服务沉淀,而不是塞在 Agent 里。
  • 核心能力:
    • 文件级(ID-based)索引:embedding 按 file_id 分组,配合文件元数据做精准定向检索(只在指定文件集里检索),天然支持多租户/权限隔离。
    • 可插拔 embedding:openai / azure / bedrock / huggingface(sentence-transformers) / TEI / vertexai / ollama 一套配置切换,模型和模型维度解耦。
    • 可插拔向量库:默认 pgvector,也支持 Atlas MongoDB 向量检索(cosine + file_id filter)。
    • 多格式文档解析:pypdf / unstructured / docx / pptx / xlsx / csv / markdown,PDF 图片走 RapidOCR 抽取。
    • 分块:langchain_text_splitters,默认 CHUNK_SIZE=1500 / CHUNK_OVERLAP=100。
    • 鉴权:JWT 验签(假设上游签发),security middleware。
  • 工程亮点:asyncpg 连接池 + 有界共享线程池(ThreadPoolExecutor,按 CPU 核数、上限 8)跑 CPU 密集的 embedding/解析,不阻塞事件循环;embedding 路由异步化;pgvector 索引 ensure_vector_indexes + PostgreSQL 查询优化 + 可选 detailed query logging 排查慢查询;支持 PG Unix socket 连接。
  • 一句话价值:把「切片/embedding/入库/检索」做成与业务解耦的通用服务,上层 Agent 只管调接口;对比 mate-assist 把 RAG 作为图里的子链,这里是RAG-as-a-Service。
  • 核心流程图(入库 + 检索双流程):
flowchart LR
    subgraph ING[入库 POST /documents]
      U[上传文件 + file_id] --> LD[document_loader
pdf/docx/pptx/xlsx/csv/md
PDF图→RapidOCR] LD --> SP[text_splitter
chunk 1500 / overlap 100] SP --> EM[embedding 可插拔
openai/azure/bedrock/HF/TEI/ollama] EM --> VS[(pgvector / Atlas
按 file_id 分组)] end subgraph QRY[检索 POST /query] Q[query + file_id 范围] --> EQ[embed query] EQ --> SR[向量检索
元数据按 file_id 过滤] VS --> SR SR --> TK[topK chunks → 上层 LLM] end TP[[有界线程池 ThreadPoolExecutor
CPU密集:解析/embedding]] -.run_in_executor.-> LD TP -.-> EM DB[(asyncpg 连接池)] -.异步 I/O.-> VS

面试组合拳(三项目各打一个点):

  • mate-assist 讲「单 Agent 对话系统的深度」——RAG 子链/记忆分层/状态图/流式/合规;
  • jarvis-registry 讲「Agent 基础设施的广度」——MCP 网关/多 Agent/权限/可观测;
  • rag_api 讲「RAG 工程基建」——ID-based 索引/pgvector/可插拔 embedding/异步线程池。
    问 RAG 原理用 mate-assist 的检索-精排-grade 子链答效果,问 RAG 工程/选型用 rag_api 答基建。

目录

  1. 项目介绍与软技能
  2. Agent 架构与模式选型
  3. 意图识别与路由
  4. RAG 全链路与检索
  5. 工具调用:Function Calling / MCP / Skill
  6. Agent 稳定性:异常、死循环、容错
  7. 记忆与上下文管理
  8. 多 Agent 协作
  9. 框架:LangGraph / LangChain / AgentScope
  10. 模型原理、调参与微调
  11. 流式输出 SSE
  12. 工程架构:异步、Redis、MySQL、可观测
  13. 评测与 Bad Case 闭环
  14. 成本控制
  15. 合规与安全(B 端重点)
  16. 模型与推理基础(原理兜底)
  17. Prompt 工程与高级 RAG 范式
  18. 手撕 / 现场编码高频题
  19. 部署与分布式(SRE 视角)
  20. 数字准备清单
  21. 自我介绍 + 项目 STAR 话术
  22. 反问面试官的好问题

一、项目介绍与软技能

1. 讲一个最熟悉/最复杂的 Agent 生产项目,架构分几层?(1 / 15 / 28 / 47 / 60 / 72)

  • 答题框架(四层):
    1. 接入层:FastAPI,SSE 流式接口,鉴权、限流、请求追踪。
    2. 编排层:LangGraph StateGraph,节点化编排(context_control / intent / rag / generate / memory),条件边路由。
    3. 能力层:RAG 检索(Weaviate + reranker)、工具调用、记忆(短期 checkpointer + 长期 MySQL store)、视觉识车。
    4. 基础设施:MySQL(对话/记忆/checkpoint)、Redis(会话/缓存/限流)、COS(图片)、OpenTelemetry(链路追踪)、prompt-manager(提示词版本化)。
  • 讲清调用量/延迟/成本:准备好数字——QPS、P95 延迟(流式首 token 时延 TTFT 单独说)、单次会话 token 成本、RAG 召回+rerank 耗时占比。
  • 踩坑点各备 1~2 个:如 messages 被摘要污染导致答非所问、意图无状态重判导致追问跑偏、流式节点加重试导致重复吐字。

2. RAG/Agent 项目的业务痛点是什么?(1)

  • mate-assist:销售面对几千条车型知识 + 话术,人工记不住、新车上市知识更新快;痛点是准确率(答错影响成单)和时效(知识随 release 更新)→ 用 RAG 把知识和模型解耦,prompt/知识独立版本化。
  • jarvis-registry:企业接入 AI 时每个 Agent 各自对接内部工具,重复造鉴权、权限、审计,且有安全盲区;痛点是治理与安全→ 用统一 MCP 网关收口。

3. 讲清一个最复杂的 AI 工作流(输入→推理→工具→记忆→输出→回写)(65)

  • 用 mate-assist 的「带图追问」链路举例:输入(图片+问题)→ vision_perceive 识车写 last_car → query_rewrite 指代消解 → intent 分类 → RAG 检索接地 → generate 流式输出 → memory_extract 抽取用户偏好回写长期记忆 + context_summary 回写会话表。强调每一步读什么写什么、哪些持久化。

4. 需求/排期/模型同学和工程同学怎么协同?(40)

  • 要点:需求先对齐评测标准(什么叫答对)再开工;模型同学管 prompt/召回效果、工程同学管链路/稳定性/可观测;用评测集 + Bad Case 看板做共同语言,避免「我觉得好了」的扯皮;prompt 用独立仓库版本化,模型同学可独立迭代不发版。

5. 用 codex/claude code 把模糊需求写成 Spec?(79)

  • 要点:先把模糊需求拆成可验收的输入/输出样例(给几个 Bad Case 当测试);明确边界与非目标;让编码 Agent 先产出方案再写码(plan-then-code);关键逻辑要求留可运行的自测。对齐「需求 = 可执行的验收用例」。

二、Agent 架构与模式选型

1. ReAct 和 Plan-and-Execute-Replan 的区别、场景、选型?(2)

  • ReAct:Reason→Act→Observe 循环,每步看结果再决定下一步。优点灵活、适合不确定步数/探索型任务;缺点步数发散、token 高、易绕圈。
  • Plan-and-Execute:先出完整计划再逐步执行,Replan 在偏离时重规划。优点可控、可并行、成本低;缺点计划僵化,环境突变要靠 replan 补救。
  • 选型:步骤可预判、追求稳定/低成本 → Plan-and-Execute 或干脆固定 workflow;步骤高度动态、需要试探 → ReAct。
  • 结合项目:mate-assist 对话链路可预判(意图→检索→生成),所以用确定性 LangGraph 图 + 条件边而非自由 ReAct,只在 RAG 子链留了「grade 不相关→重写重检索」的有界循环。这就是「能用 workflow 不用自由 Agent」。

2. AI 工作流和纯 Agent 自主规划的区别?什么时候不该上 Agent?(23 / 71)

  • Workflow:开发者预先编排好节点和路由,确定性高、可测、可观测、成本可控。
  • 纯 Agent:模型自己规划步骤和工具,灵活但不可控、难测、成本高。
  • 不该上 Agent 的场景:流程固定、强合规、低延迟要求、错一步代价大的场景——这时用 workflow + 规则。
  • 结合项目:mate-assist 绝大部分是 workflow,只有局部(RAG 换角度重检索)给了有限自主。「自主程度只在真正需要的地方给」。

3. Workflow、Graph、Loop 的区别?(59)

  • Workflow = 线性/DAG 的确定性流程;Graph = 带条件分支和回边的状态图(LangGraph);Loop = Agent 自我循环调工具直到满足条件。Loop 最灵活也最危险(死循环)。mate-assist 用 Graph,循环只在 RAG 子链且带 rewrite_count 上限。

4. Agentic RAG 和普通 RAG 的区别?什么时候让 Agent 再检索?(76)

  • 普通 RAG:一次检索→塞上下文→生成,固定单跳。
  • Agentic RAG:Agent 自己判断要不要检索、检索几次、换什么词、够不够再补一次(多跳/自省)。
  • 何时再检索:召回相关性不足、问题需要多跳、答案要跨多个文档聚合时。
  • 结合项目:mate-assist 的 rag_grade 给召回打相关性分,不相关就 rag_rewrite 换角度重检索——这就是轻量版 CRAG(Corrective RAG),但用 rewrite_count 卡死循环。

5. 复杂问题路由:何时直接 LLM / RAG / 图数据库 / 多子 Agent?(61)

  • 要点:闲聊/通用常识 → 直接 LLM;企业私有知识 → RAG;强关系/多跳推理(谁的上级是谁) → 图数据库;需要多技能协作/工具编排 → 多子 Agent。
  • 结合项目:mate-assist 的 route_by_intent 是确定性查表(intent→node),不是让模型自由决定,保证路由可测可控。

📌 实战:单意图 → 多意图编排。真实用户常一句话多意图:「梦想家和问界 M9 怎么比?再给几张对比图,顺便写段话术」。单标签分类器 + 单分支路由表达不了。我们的演进结论是把它拆成可执行任务图:有依赖的任务串行(先识别车型→再生成话术)、互不相关的并行(对比图 ∥ 话术)。关键认知是:这不是「分类器多输出几个标签」那么简单,而是编排层要支持 DAG 式的任务分解与汇总。

三、意图识别与路由

1. 意图识别怎么落地?规则/分类模型/LLM 路由怎么配合?如何避免误判进错工具/错 RAG?(16 / 48)

  • 三层配合:高频固定句式用规则/关键词(快、准、零成本)兜底;中间用轻量分类模型;复杂/长尾用 LLM 路由。三者按「便宜的先拦」排。
  • 避免误判:
    • 路由做成确定性查表(intent→node),不让模型直接决定走哪,降低发散。
    • 喂上一轮意图 last_intent 给分类器,让「加价格/加版本」这类追问沿用上轮意图,不被无状态重判带偏。
    • 低置信度时反问澄清而不是硬路由。
  • 结合项目:mate-assist 的 intent_classify_node + route_by_intent,意图分 knowledge/sales_support/chat/discourse/vision_answer,last_intent 持久化回写。

📌 实战 Bad Case(意图延续):知识类线程里用户逐轮精修——「加版本」「加价格」「去掉续航列」「那快充呢」——从第 2 轮起意图被无状态重判带偏:要么掉到闲聊返回空洞应答「好嘞这就给您加上😉」,要么掉到话术链路反问「您想要哪个场景的话术?」(场景陷阱)。修复 = intent_classify prompt 加「知识类多轮延续」规则 + State 持久化 last_intent 每轮喂回分类器。黑盒难直接读 intent,用服务日志 event_code=intent_classified(含 intent/last_intent)拿 ground-truth,这条已固化成 6_intent_continuity_regression_test.py 防回退。

2. 意图识别错了怎么发现、怎么兜底?(17)

  • 发现:线上埋点监控「路由后空召回率 / 用户追问&重问率 / 负反馈」;评测集覆盖易混意图。
  • 兜底:低置信度反问澄清;路由后若该分支明显无结果(如 RAG 空召回)回退到 chat 模板说明「没找到」而不是硬编;保留人工纠偏。
  • 结合项目:mate-assist 对「明确要图/视频但空召回」会保留 requested_media_types,用 RAG 接地模板说「暂未找到」,不掉到无知识 chat 模板。

3. 长对话里意图漂移怎么拉回?(35)

  • 用状态 + 记忆:持久化 last_intent / last_car / focus_car,每轮喂回;滚动摘要保留话题主线;指代消解把「它/这个」接地到当前焦点。mate-assist 三者都做了。

4. 意图识别+路由做成平台能力怎么给多业务用?(45)

  • 要点:把意图 schema、路由表、prompt 做成可配置(不同业务不同意图集和分支);统一 SDK/网关接入;各业务独立评测集。对应 jarvis-registry 的「网关收口 + 按业务隔离」思路。

5. 【Case】"帮我退昨天买的充电宝"→Agent 查天气,怎么修?(27)

  • 排查顺序:① 意图分类错了?(退货→查天气,分类严重跑偏)② 路由表配错?③ 工具描述歧义导致选错工具?
  • 修法:先看意图置信度和分类输入(是否被历史污染);补该类 Bad Case 进评测集;加规则兜底高频「退货/退款」关键词;工具/意图描述去歧义;低置信反问。根因通常在意图层,别只在工具层打补丁。

四、RAG 全链路与检索

1. RAG 全链路:入库、清洗、分块、多模态解析、为什么选 Weaviate?(4)

  • 全链路:采集 → 清洗(去噪/去重/规范化)→ 分块(按语义/标题结构,带 overlap)→ embedding → 入向量库 → 检索 → rerank → 进上下文 → 生成。
  • 多模态:PDF 用版面解析,表格转结构化(Markdown/行列保序),图片走 OCR/视觉模型抽描述再 embedding;mate-assist 单独有视觉识车链路(vision_perceive)。

📌 实战:多模态「感知-接地-行动」三段解耦。被识别的实体(车型)藏在像素里,下游专业链(话术/RAG)是文本+槽位驱动的。错误做法是让「一次视觉调用」既看图又当生成器——破坏概念完整性、无法组合。正确做法三段解耦:① Perception 视觉步骤只输出结构化事实(非自由文本);② Grounding 把事实写进持久化槽位/焦点实体(last_car,且 confidence≥medium + 过受控车型库校验才写);③ Routing→Action 正常按「模态+任务」派给专家,各专家消费同一接地槽位。核心一句:"分开处理"的是感知,不是任务执行——感知是喂给共享管线的预处理,不是死胡同分支。

  • 为什么 Weaviate:支持向量+关键词混合检索、带元数据过滤、schema 化、易水平扩展、生态成熟。按「团队熟悉度 + 混合检索 + 过滤能力」选型,不是唯一答案。

📌 实战:向量库选型 pgvector vs 专用向量库。rag_api 用的是 PostgreSQL/pgvector。取舍:pgvector 的最大优势是和业务数据同库——向量、文件元数据、权限在一个事务里,省一套中间件、运维简单、支持 SQL 元数据过滤;代价是超大规模(亿级向量)性能和索引能力不如专用库(Weaviate/Milvus)。所以:中小规模 + 强元数据过滤 + 想少运维 → pgvector;超大规模 + 极致召回性能 → 专用向量库。rag_api 还抽象了 VECTOR_DB_TYPE,pgvector 和 Atlas MongoDB 可切换,说明向量库应该是可插拔的。

📌 实战:ID-based(文件级)RAG。rag_api 的 embedding 按 file_id 分组,检索时按文件元数据圈定范围再检索——好处是多租户/权限隔离天然(只检索你有权限的文件)、删除/更新以文件为单位干净利落(删文件就删它的所有 chunk)。这是 B 端知识库很实用的设计:知识更新频繁时按文件增量重建,不用全库重算。

2. 多路召回怎么搭?向量/BM25/知识图谱/元数据过滤各负责什么?怎么融合进 Rerank?(3 / 51)

  • 各自分工:向量召回管语义(同义/改写/口语);BM25/关键词管精确术语/型号/编号/低频词(向量恰恰弱在字面精确);知识图谱管关系/多跳;元数据过滤管权限/品牌/时间等硬条件(先过滤再检索,省算力也防串权限)。
  • 为什么要混合(hybrid search):稠密向量会漏「字面精确但语义平平」的词(车架号、配置代号),稀疏 BM25 会漏「换了说法」的——两者互补。
  • 融合方法:
    • RRF(Reciprocal Rank Fusion):score(d)=Σ 1/(k+rank_i(d)),k 常取 60,只用排名不用原始分,天然免去「余弦分和 BM25 分不可比」的归一化难题,社区默认首选(ES/Weaviate 内置)。
    • 加权分数融合:各路分数先归一化(min-max / z-score)再加权,可调权重但要调参、易被异常分带偏。
  • 查询侧增强(社区):HyDE(先让 LLM 生成假设答案再拿它检索,缓解 query 与 doc 不同构)、multi-query / query expansion(一问改写成多条并路召回)、step-back prompting(先退一步问更抽象的问题)。
  • 结合项目:mate-assist 关键词+向量多路召回、分数融合后过独立 reranker 服务;query_rewrite 节点做的指代消解本质就是检索前 query 增强——把「它续航多少」接地成「泰山续航多少」再召回。

3. Rerank 的作用?rerank 模型 vs 向量库各解决什么?放哪个阶段?(3 / 77)

  • 向量库(召回/recall 阶段):bi-encoder,快、粗,负责「别漏」,从全库捞回候选。
  • Rerank(精排阶段):cross-encoder,query 和 doc 一起进模型算相关性,准、慢,负责「排对」,对召回的几十条做精排。
  • 位置:召回之后、进 LLM 之前。先召回缩小候选,再 rerank 精排,兼顾速度和精度。

4. Reranker 为什么不能全库跑?cross vs bi-encoder?没 GPU 怎么办?(52)

  • 不能全库跑:cross-encoder 把 query 和 doc 拼在一起过一次模型算相关性,每对一次前向,全库 O(N) 太慢太贵,所以只对召回的候选集(几十~几百条)精排。
  • 三种结构(能分清加分):
    • bi-encoder:query/doc 各自独立编码成向量,可离线预计算、检索快、精度一般——召回用。
    • cross-encoder:query+doc 联合编码、交互充分、精度高但不可预计算——精排用。
    • late interaction(ColBERT):token 级向量 + MaxSim,兼顾精度与可预计算,适合大规模精排。
  • 具体模型:开源 bge-reranker-v2-m3、Jina reranker;云服务 Cohere Rerank。向量侧 embedding 常用 bge-m3 / text-embedding-3 / Jina。
  • 没 GPU:用 RRF 纯排名融合(零模型)做轻量重排;或小 CPU 友好 rerank 模型 + 限候选数;或把 rerank 做成独立服务按需扩容——mate-assist 就是独立 reranker 服务,和主链路解耦,可单独上 GPU/扩缩容。

5. chunk size、overlap、embedding、rerank 怎么调?优先级?(36)

  • 优先级一般:先切片(chunk/overlap)→ 再 embedding 模型 → 再召回策略 → 最后 rerank,因为切片错了后面全废。
  • chunk 太大噪声多、太小丢上下文;overlap 防切断语义;embedding 选领域匹配的;rerank 调 topN。调参要以评测集驱动,别凭感觉。
  • 进阶切分策略(社区):① 语义切分(按句向量相似度断句,而非固定长度);② 父子 / small-to-big(parent-document retriever:用小块保召回精度,命中后返回所在大块给 LLM 保上下文完整);③ 按结构切(Markdown 标题层级、表格行列保序,技术文档尤其重要);④ late chunking(先整文过长上下文 embedding 再切,保留跨块语义)。

📌 实战:embedding 要做成可插拔 + 注意维度耦合。rag_api 把 embedding provider 抽象成配置(openai/azure/bedrock/huggingface/TEI/vertexai/ollama 一键切),默认 text-embedding-3-small。两个坑:① 换 embedding 模型 = 向量维度变 = 全库要重建索引(1536 维 ↔ 其它维不兼容),不能热切;② 本地/私有部署用 HuggingFace sentence-transformers 或 TEI 省钱、数据不出境,B 端常用。chunk 默认 1500/overlap 100 是通用起点,领域文档要按评测集再调。

6. RAG 接在项目哪里?检索结果怎么进 Agent 上下文?(18)

  • mate-assist:RAG 是图里的子链(rag_retrieve→grade→generate),检索结果写进 State 的 retrieved_records,generate 节点用RAG 接地模板把它拼进 model_input(注意:只进 model_input,不进 messages 历史)。

7. RAG 召回质量差,先查召回/重排/切片/prompt?(19)

  • 排查顺序:① 先看召回(相关 doc 到底在不在 topK 里)——不在就是切片/embedding/召回策略问题;② 在但排序靠后 → rerank;③ doc 对但答错 → prompt/生成。「先定位在召回还是生成」,别一上来改 prompt。

8. 幻觉的原因?RAG 怎么缓解?召回对了模型仍编造怎么办?(12)

  • 原因:训练数据缺失/过时、模型过度自信补全、上下文不足。
  • RAG 缓解:用检索到的事实接地 + prompt 要求「只依据给定资料回答」。
  • 召回对仍编造:① prompt 强约束 + 要求引用来源/片段(带 citation 可追溯);② 降 temperature;③ 加答案核查(生成后校验每句是否出自召回);④ 召回不足就明确说「不知道」而非编。
  • 社区方法 / 幻觉检测:RAG Triad(TruLens 的三相关性——context relevance 召回相不相关、groundedness 答案是否出自召回、answer relevance 答案切不切题);RAGAS 的 faithfulness(忠实度)/ answer relevancy 量化幻觉;SelfCheckGPT(多次采样看是否自洽)做无参考检测;Self-RAG / CRAG(模型自判要不要检索、召回够不够、要不要纠偏)。
  • 结合项目:mate-assist 的 rag_grade 就是 groundedness 思想的工程落地——召回不相关宁可 rag_rewrite 重检索/兜底也不硬生成。

五、工具调用:Function Calling / MCP / Skill

1. Function Calling 原理?MCP 是什么?MCP 和 Skill 区别?(6)

  • Function Calling 原理:给模型工具的 JSON Schema(名字/描述/参数),模型把「调哪个工具+参数」输出成结构化 JSON(底层是受约束解码/训练出来的能力),外部代码执行后把结果作为 tool 角色消息回喂,模型据此续写。模型只决策不执行,支持并行工具调用(一轮吐多个 tool_call)。
  • MCP(Model Context Protocol):Anthropic 2024 开源的开放协议,统一「AI 应用 ↔ 工具/数据源」的接法,官方比喻「AI 的 USB-C」。架构 Host(Claude Desktop/Cursor 等)↔ MCP Server;Server 暴露三类原语:Tools(可调函数)、Resources(可读数据/文件)、Prompts(预设模板)。传输:本地 stdio、远程 SSE / Streamable HTTP。价值:把 M×N 集成爆炸降成 M+N。
  • MCP vs Function Calling:不对立——Function Calling 是模型层「怎么决定调用」,MCP 是系统层「工具怎么被标准化接入/发现」;MCP tool 最终仍以 function calling 形式交给模型。
  • MCP vs Skill:MCP 是接入协议;Skill 是一个能力单元;一个 MCP server 可暴露多个 skill。
  • A2A(Agent-to-Agent):Google 提的 Agent 间协作协议,与 MCP 互补——MCP 管「Agent 调工具」,A2A 管「Agent 调 Agent」。
  • 结合项目:jarvis-registry 就是企业级 MCP 网关 + A2A 编排平台——统一认证入口反代所有 MCP server,FAISS 语义发现 tool,ACL 控到工具级,同时编排 A2A worker agent,把 MCP/A2A 的「接入、发现、鉴权、审计」做成基础设施。

2. 工具膨胀(几百个 skill)怎么做工具发现,避免塞爆 prompt?(5)

  • 核心:别把所有工具塞进 prompt,用检索式工具发现——对工具的名称/描述/tag 做 embedding,运行时按当前 query 语义检索 topK 相关工具只喂这几个给模型。
  • 配合:工具分组/命名空间、按意图预过滤、按权限过滤(无权限的不进候选)。
  • 结合项目:jarvis-registry 的 services/search 用 FAISS 对 skill/描述/tag 做语义搜索,Agent 运行时才找到对的 server/agent,不是全量进 prompt。这是这题的标准答案。

3. 工具调用的 schema 校验、参数修正、重试、限流、降级?(56)

  • schema 校验:用 Pydantic/JSON Schema 校验模型吐的参数;缺参/类型错 → 回喂报错让模型自我修正(反射重试)。
  • 重试:瞬时故障(超时/5xx/限流)指数退避重试 + 幂等键;限流:令牌桶/信号量控并发;降级:下游挂了走缓存/默认值/友好兜底话术。
  • 结合项目:mate-assist 节点级 RetryPolicy 只重试瞬时故障;jarvis-registry 网关层统一做限流/鉴权/降级。详见第六章。

六、Agent 稳定性:异常、死循环、容错

1. 工具调用异常(JSON 解析失败/参数缺失/超时):重试、幂等、熔断?(7)

  • JSON 解析失败/参数缺失:校验后把错误回喂模型自我修正(限次数),仍失败则降级。
  • 超时:设超时 + 指数退避重试,但写操作必须带幂等键(否则重试重复下单/重复退款)。
  • 熔断:下游连续失败触发熔断器(circuit breaker),快速失败走降级,避免雪崩;半开探测恢复。
  • 结合项目:mate-assist default_retry_on 排除 ValueError/TypeError 等编程错误,只重试瞬时故障——这是关键,编程 bug 重试没用还放大。

📌 实战:确定性错误被误当瞬时错误重试(离线跑批事故)。ASR 片段「我姓习」触发豆包 finish_reason=content_filter,应用错误地把它包成 LLMBatchTransientError → 相同输入重试 4 次、最终整门店跑批失败。教训:按错误类型分流——content_filter、LengthFinishReasonError 是确定性错误,重试一定再失败,必须直接失败/跳过/降级,绝不整任务重试;只有 network/5xx/限流才退避重试。另一个坑:LengthFinishReasonError 平均要 74 秒才失败,长期占用并发名额,要设更激进的超时。

2. Agent 调用失败/超时/脏数据怎么处理?(21 / 56)

  • 失败/超时:重试+熔断+降级(同上)。
  • 脏数据:出参也要 schema 校验;不信任下游,做字段白名单/范围校验;脏数据触发兜底而非直接喂给模型(防二次幻觉/注入)。

3. 循环调用/死循环/无限工具调用怎么防?max step 之外还有啥?(34 / 59 / 68 / 74)

  • max step / 递归上限:最基础,LangGraph 有 recursion_limit。
  • 重复动作检测:记录 (工具,参数) 指纹,重复同一调用直接打断。
  • 结果校验/进展判定:每步判断是否有实质进展,无进展计数超限就停。
  • 预算上限:token / 调用次数 / 时间预算,超了强制收尾。
  • 结合项目:mate-assist RAG 子链用 rewrite_count 卡重写次数,到上限就直接 generate,不无限重检索。「max step 是底线,重复检测 + 进展判定 + 预算才是真正的防线」。

七、记忆与上下文管理

1. 记忆分层/三层记忆:会话级、工作/实体级、长期分别存什么?何时读写?怎么防污染?(8 / 9 / 49)

  • 三层:
    • 会话级(短期):当前对话消息,存 checkpointer(mate-assist 用 MySQL checkpointer),随会话走。
    • 工作/实体级:本轮/近期的焦点实体和槽位(如 focus_car/last_car/last_intent),跨轮透传。
    • 长期:用户画像/偏好,跨会话,存长期 store(mate-assist memory/mysql_store)。
  • 何时写:generate 后的 memory_extract 节点抽取并写长期记忆;何时读:下一轮按需注入 model_input。
  • 防污染(关键):
    • 记忆/摘要只写 model_input,绝不回写 messages(ground truth 不被污染)。
    • 长期记忆写入要抽取+校验(置信度门槛),mate-assist 的 last_car 只有 confidence≥medium 且过受控车型库校验才写。
    • 冲突偏好做合并策略,不是无脑覆盖。

📌 实战 1:namespace 必须带业务 scope 防串味。同一销售(同 user_id)跨会话聊不同客户:客户 A=30 万/泰山、客户 B=50 万/梦想家。若 namespace 只用 user_id,再开客户 A 会话问预算会串到客户 B 的 50 万。解法:记忆 namespace = user_id + customer_id,scope 隔离。这条固化成 9_long_term_memory_regression_test.py 的 M3。

📌 实战 2:记忆抽取异步、不阻塞首字。memory_extract 是生成后的后台异步任务写 profile,不卡用户首 token;代价是时序敏感——回归脚本要轮询 GET /users/{uid}/memory 确认落库,别把「还没抽完」误报成「没记住」。

📌 实战 3:画像增量合并(跑批侧)。客户画像不是每天全量重算,而是首次全量 + 后续增量合并,latest-wins(昨天意向「泰山」今天「泰山 X8」→ 更新为泰山 X8);存储用「稳定列 + JSON 属性袋」(schema_version + 开放 attributes + evidence)可扩展模型。

📌 实战 4:会话"毒化"事故(高频考点)。失败轮(如网关返回 400)只把用户输入落进 checkpointer、没写回助手消息,历史里就沉淀出连续多条孤儿 HumanMessage;豆包/火山网关要求 Human/AI 交替,于是此后每轮都 400、会话永久卡死。处置:写运维脚本 clean_poisoned_thread.py 把「最后一条 AIMessage 之后的所有消息」用 RemoveMessage 删掉,让历史以 AI 收尾、恢复交替;走真实 build_graph 的 aupdate_state,确保 last_car/context_summary 等其它 channel 不丢;默认 DRY-RUN。根因修复在上游:失败轮要么回滚本轮 Human、要么补一条占位 AI 消息。

2. 三层记忆在长期任务里怎么演化:新事实写入/旧事实过期/冲突合并/画像重建?(62)

  • 新事实:抽取后带时间戳写入;旧事实:TTL/版本化过期;冲突:以新+高置信覆盖或保留多值+场景区分;跨会话画像:定期用历史会话聚合重建。强调「记忆要有生命周期,不是只增不删」。
  • 社区框架(可点名):MemGPT / Letta(把 LLM 当 OS,分「主上下文 + 外部记忆」自动换页)、mem0(抽取-更新-检索的记忆层,带冲突消解)、LangGraph/LlamaIndex 的 memory 模块。mate-assist 的三层记忆 + memory_extract 异步抽取 + latest-wins 冲突合并,就是这套思想的自研落地。

3. 上下文超长怎么处理?滑动窗口/摘要/关键信息抽取/向量检索历史怎么组合?(9 / 50)

  • 滑动窗口:保最近 N 轮,适合短对话、强时序。
  • 摘要压缩:把旧消息折叠成摘要,适合长对话。
  • 关键信息抽取:只留结构化关键事实(槽位/实体)。
  • 向量检索历史:历史入库,按当前问题检索相关片段,适合超长、跨会话。
  • 组合:近期用窗口原文 + 远期用滚动摘要 + 关键实体结构化 + 必要时检索历史。
  • 结合项目:mate-assist context_control 做增量滚动摘要——已折叠进摘要的旧消息用 RemoveMessage 裁出 messages,摘要持久化到 checkpointer + 回写 conversations.context_summary,下一轮只摘「老摘要 + 新增轮次」,成本恒定。这是亮点。

4. 长对话怎么防上下文漂移?State 状态机怎么设计?(8)

  • State 设计原则:ground truth(messages)与临时上下文(model_input)分离;跨轮状态(intent/car)持久化透传;每个字段注释清楚谁写、谁读、是否持久化、reducer 语义。mate-assist 的 ChatState 就是这么设计的。

5. 共享 memory 和私有 memory 怎么设计?(67)

  • 私有:每个 Agent/会话独占,隔离防串味;共享:多 Agent 协作需要的公共黑板(任务状态/中间结果),要做访问控制 + 写冲突处理。见第八章。

八、多 Agent 协作

1. 子 Agent 之间怎么通讯、任务怎么拆分?(20)

  • 通讯:① 共享黑板/State(LangGraph 共享 state);② 消息传递(A2A);③ 经网关中转。
  • 拆分:按能力边界(检索/计算/写操作各一个)或流程阶段(规划/执行/审查)拆。
  • 结合项目:jarvis-registry 是 A2A 编排平台——orchestrator agent 协调 worker agent,全部经同一安全网关通讯,统一鉴权审计。

2. Supervisor/Planner/Worker/Reviewer 的边界怎么划?工具集能共用吗?(73)

  • 边界:Supervisor 调度分发、Planner 拆计划、Worker 执行具体任务、Reviewer 校验结果。职责单一、输入输出契约清晰。
  • 工具集:可共用底层工具,但按角色+权限做 ACL 限制——Worker 能调写操作,Reviewer 只读。对应 jarvis-registry 的工具级 ACL。

3. 多 Agent 上下文怎么传?会不会越传越多/污染?(66 / 67)

  • 会——这是多 Agent 的核心坑。对策:① 传摘要/结构化结果而非全量历史;② 私有 memory 隔离、共享 memory 做访问控制;③ 每层只传下游需要的最小上下文。

4. 子 Agent 再调 Agent,token 怎么炸?怎么隔离状态?(75)

  • token 炸因为上下文层层累加。对策:子 Agent 独立 context 窗口(状态隔离),只返回结论/摘要给父 Agent,不回传全过程;设每层 token 预算;限制嵌套深度。

5. 怎么避免两个 Agent 互相甩锅式调用?(33)

  • 明确职责边界和终止条件;禁止循环调用(调用图做成 DAG 或带环检测);每个 Agent 必须对自己的输出负责(不能无脑转发);加全局 step/预算上限。

6. 多 Agent 平台化:工具权限、沙箱、审计、成本怎么管?(43)

  • 这题就是 jarvis-registry 的主场:
    • 权限:OAuth2/OIDC 身份 + RBAC/ACL scope 细到工具级(middleware/rbac.py)。
    • 沙箱:工具经网关代理执行,隔离、限流、超时。
    • 审计:全量请求日志 + OpenTelemetry tracing + Prometheus metrics。
    • 成本:网关统一统计 token/调用次数,按租户/Agent 配额。

九、框架:LangGraph / LangChain / AgentScope

1. LangChain 和 LangGraph 区别?何时链够用、何时必须上状态图?(53)

  • LangChain:链式编排(Chain),线性、无状态记忆跨步、分支弱。适合简单单向流程(如一次 RAG 问答)。
  • LangGraph:状态图,有 State、条件分支、回边、持久化 checkpointer。适合多轮、带分支/循环、需断点恢复的复杂 Agent。
  • 何时上图:需要条件路由、循环(重检索)、多轮状态、人工审核中断恢复时——mate-assist 全部需要,所以用 LangGraph。

2. LangGraph 的 State/Node/Edge/Conditional Edge 实际怎么用?(63)

  • State:TypedDict + reducer(如 add_messages),节点读写。
  • Node:一个函数,接收 state 返回 state 增量。
  • Edge:固定跳转;Conditional Edge:路由函数返回 key,查表决定下一节点。
  • 结合项目:mate-assist add_conditional_edges("intent_classify", route_by_intent, _ROUTE_TO_NODE)——路由函数出口映射到节点名,确定性查表(非模型决策)。

3. State/Reducer/Checkpointer 怎么做断点恢复和多轮对话?(54)

  • Reducer:定义 state 字段如何合并(追加 vs 覆盖),如 messages 用 add_messages 追加。
  • Checkpointer:每步把 state 持久化(按 thread_id),崩溃/中断后可从断点恢复,也是多轮对话记忆的载体和人工审核中断(interrupt)恢复的基础。
  • 结合项目:mate-assist 用 MySQL checkpointer,thread_id 对应会话;messages 用 add_messages reducer,model_input 用覆盖语义。

4. 图数据库选 Neo4j 还是其他?实体/关系/属性怎么建模?图查询和向量召回怎么互补?(55)

  • 选型:Neo4j 成熟、Cypher 易用;也可 NebulaGraph(大规模)。按规模和团队选。
  • 建模:实体=节点、关系=边、属性挂节点/边。
  • 互补:向量召回管模糊语义匹配,图查询管精确多跳关系(A 的配件兼容哪些车型);GraphRAG 思路——先向量定位实体,再图上扩展关系补全上下文。

十、模型原理、调参与微调

1. KV Cache 原理?temperature/top_p/top_k?B 端怎么调参?(11)

  • 原理:Transformer 自回归逐 token 生成,每步都要对前缀所有 token 做 attention。KV Cache 把每层已算过的 Key/Value 缓存下来,新 token 只算自己的 Q 去和缓存的 K/V 交互,把每步的 O(n²) 重算摊薄成 O(n),空间换时间。代价:显存 ≈ 2 × 层数 × 序列长 × 隐藏维 × batch,长上下文下 KV Cache 本身就吃爆显存。
  • 社区优化(能点名加分):
    • PagedAttention / vLLM:像 OS 分页一样管理 KV Cache,消除显存碎片,吞吐翻数倍,已是推理引擎事实标准。
    • GQA / MQA(分组/多查询注意力):多个 Q 头共享一组 K/V,直接缩小 KV Cache(Llama-2/3、Mistral 都用)。
    • Prefix Caching 前缀缓存:相同系统 prompt / few-shot 前缀的 KV 跨请求复用——这正是各家 API「缓存命中 token 更便宜」的底层(直接关系成本,见第十四章)。
  • 采样参数:temperature 缩放 logits 控随机性(0≈贪心、越高越发散);top_k 只在概率最高 k 个里采样;top_p(核采样)在累积概率达 p 的最小集合里采样,比 top_k 自适应。注意:即使 temperature=0 也不保证完全可复现(浮点非结合性、batch、MoE 路由都会引抖动)。
  • B 端调参:要稳定/可复现/少幻觉 → temperature 0~0.3、top_p 收紧(~0.8)、固定 seed;抽取/分类/function-calling 用近 0 温保结构稳定;创意话术可放到 0.7。
  • 结合项目:mate-assist 知识问答/意图分类走低温保稳定、话术生成略高保多样;长对话靠滚动摘要压上下文,顺带也压住了 KV Cache 显存和首 token 延迟。

2. RAG vs Fine-tuning 怎么选?B 端客户场景?(13)

  • RAG:知识频繁更新、要可溯源、要隔离权限时用;改知识不动模型。
  • Fine-tuning:改风格/格式/固定行为模式、领域术语习惯时用;不适合装易变知识。
  • B 端:知识多变 + 要溯源 + 多租户隔离 → 优先 RAG;特定输出风格再叠 SFT。mate-assist 选 RAG(车型知识随上市更新)。

3. LoRA 原理?Merge 权重优缺点?SFT/DPO 对齐目标?何时微调何时 RAG?(14)

  • LoRA 原理:冻结原权重 W,旁路加低秩分解 ΔW = B·A(A 把维度降到 rank r、B 升回原维),只训 A/B。基于「微调的权重更新是低秩的」假设。超参:rank r(8/16/32,越大容量越大越易过拟合)、alpha(缩放,常令 alpha=2r)、作用层(常 q/v proj,也可全 attention+MLP)。可训参数降到全量的 0.1%~1%。
  • QLoRA:主干先 4bit 量化(NF4)再在上面训 LoRA,单张消费级卡就能微调 7B~13B——社区最常用的省钱方案。
  • Merge 权重:把 B·A 加回 W。优点:推理零额外开销、部署简单;缺点:失去可插拔性、不能动态切多适配器、多任务要各 merge 出多份全量权重。不 merge 则一主干挂多 LoRA 热切(多租户各一份)。
  • 对齐三段:SFT(监督微调)学「输入→理想输出」,教格式/风格/领域语气;RLHF/PPO 用奖励模型 + RL 对齐偏好,效果好但复杂不稳;DPO(Direct Preference Optimization)用「优答 vs 劣答」成对数据直接优化、绕开显式奖励模型,简单稳定是社区主流,衍生 ORPO/KTO/SimPO。
  • 坑:微调有灾难性遗忘(学新忘旧),且知识类微调「背不准还更自信」;数据质量 > 数量(几千条高质常胜过几万条噪声)。
  • 何时微调/RAG:知识多变/要溯源/多租户 → RAG;固定风格/输出格式/领域语气/想缩短 prompt → 微调;常组合(RAG 装知识 + LoRA 调风格)。
  • 结合项目:mate-assist 车型知识随上市频繁更新 + 要可溯源 → 坚决走 RAG 不微调;话术风格靠 prompt 工程(prompt-manager 版本化)而非微调,迭代更快、可回滚。

十一、流式输出 SSE

1. SSE 怎么实现?异常断流怎么处理?乱序问题?(10)

  • 实现:HTTP long-lived 连接,text/event-stream,服务端逐 token yield data 帧;FastAPI 用 StreamingResponse/EventSourceResponse;LangGraph 用 stream_mode="messages" 逐 token 透出。
  • 异常断流:SSE 自带 id: + 客户端 Last-Event-ID 自动重连;服务端用心跳帧保活;生成中断要发结束/错误帧让前端收尾。
  • 乱序:SSE 基于单条 TCP 连接天然有序,乱序风险主要在前端并发处理或多路合并——用序号帧保证拼接顺序。
  • 结合项目:mate-assist generate_answer 用 stream_mode="messages" 逐 token 透出,SSE 结束帧带 faq_list/discourse_ask 等元信息;正因流式,generate 节点特意不加 retry(重试会向客户端重复吐字)——这是流式和重试冲突的经典坑。

📌 实战 1:别让模型逐 token 复制长内容。早期把完整媒体标签(<image src="很长的 COS 签名 URL" poster="...">)塞进 Prompt 要模型原样复制,导致模型逐 token 吐超长 URL,一次 /chat 耗时 2 分 7 秒、响应体 182KB。优化:Prompt 里只放短占位符/媒体 id,真实 URL 由后端拼接,不进模型。结论:流式场景下「模型要输出的 token 数」直接决定延迟和成本,长 URL/大 JSON 这类死内容一律移出模型。

📌 实战 2:SSE 把辅助 token 当正文透出的 bug。stream_mode="messages" 会把图里所有 LLM 节点的 token 都往外吐——场景兜底匹配的辅助 LLM 吐的英文场景 key(close_deal/general_service)被当正文流给了前端。要按节点/标签过滤,只透出 generate_answer 的正文流;已固化成合规回归的 PART 4。

十二、工程架构:异步、Redis、MySQL、可观测

1. Agent 调用链里异步 vs 同步怎么选?为什么?(64)

  • Agent 链路大量是 I/O 密集(调 LLM、检索、工具 HTTP),用 asyncio 异步能在等待时让出,大幅提升并发吞吐;CPU 密集(本地 rerank/编码)用线程池/进程池别阻塞事件循环。mate-assist 全链路 async(FastAPI + async 节点)。

2. asyncio 批量跑 Agent 为什么不能无脑并发?怎么限流?(70)

  • 无脑并发会打爆下游(LLM 限流 429、DB 连接耗尽、内存爆)。限流:asyncio.Semaphore 控并发数、令牌桶控速率、gather 分批、下游连接池上限。「并发是为了吞吐,不是越多越好」。

📌 实战:CPU 密集任务别放事件循环,用有界线程池。rag_api 的 embedding 计算、文档解析是 CPU 密集的,直接在 async 路由里跑会阻塞整个事件循环。做法:在 lifespan 里建一个有界共享 ThreadPoolExecutor(按 os.cpu_count()、上限 8),CPU 活用 run_in_executor 丢进去,async 只管 I/O(asyncpg 连接池调 PG)。「async 快的是 I/O 等待,CPU 活要进线程/进程池,而且池要有界防打爆」。embedding 路由本身也做了异步化,批量入库时并发可控。

3. 怎么设计可观测的 Agent 调用链?(22)

  • 三支柱:Tracing(一次请求跨节点/工具/LLM 的 span,带 trace_id)、Metrics(QPS/延迟/token/成功率)、Logging(结构化日志带 trace_id 串联)。
  • 结合项目:mate-assist observability/ 有 otel.py/tracing.py/node_span.py/llm_callback.py/metrics.py——每个图节点一个 span,LLM 回调记 token,OpenTelemetry 导出;jarvis-registry 网关层统一 OTel + Prometheus。

4. Redis 在 Agent 里用在哪?会话状态/意图缓存/工具结果缓存/分布式锁/限流?(57 / 78)

  • 会话状态:热会话缓存(比每次查 DB 快)。
  • 缓存:意图结果、召回结果、工具结果缓存(相同 query 命中省 LLM/检索成本)。
  • 分布式锁:同一会话并发请求串行化、防重复执行(SETNX + 过期)。
  • 限流:令牌桶/滑动窗口计数。
  • 结合项目:jarvis-registry 用 Redis 做 client-info 缓存让 MCP 网关无状态化(client_info_store.py),这样网关可水平扩容——这是很好的答法。

5. MySQL 存对话/记忆/任务状态怎么分表?热点用户怎么避免单表膨胀?(58)

  • 分表:按 user_id / 时间 分库分表(如按 user_id hash 分片 + 按月归档冷数据);对话消息表量大,冷热分离(热数据在线表、冷数据归档表/对象存储)。
  • 热点用户:会话加 Redis 缓存层挡读;大会话滚动摘要压缩(见第七章)控制单会话消息行数。mate-assist 的滚动摘要同时也是控表膨胀的手段。

📌 实战:源/结果分库 + 只读引擎。离线画像跑批读的是外部业务库(ai_mate,只读),结果写本地库。做法是两个独立引擎:只读 source_engine(PROFILING_SOURCE_DATABASE_URL,强制与结果库 DATABASE_URL 不同库,为空即启动报错)+ 写主库引擎;DB 访问统一走 db_session()(只读)/ db_transaction()(写)两个上下文。避免跑批把线上在线库拖垮,也防误写源表。

6. 【补充】离线跑批怎么做并发调度和可靠性?(源自跑批优化实战)

  • 调度:Celery + Beat(分布式 worker、可重试、可横向扩展),错峰触发避免 23:00 后画像/简报/暂败任务同时 fan-out 争抢。
  • 并发闸门别用一个全局值:早期所有离线业务共享一个固定并发闸门,应升级成 provider/model 并发 + RPM + TPM + 业务配额 的联合调度器。
  • 边际递减要讲清:并发 limit 8→20,闸门等待 P50 从 32.5s 降到 10.5s,但 P95 仍 76s——继续调大边际收益递减,还会挤压在线对话、触发网关限流。调参要用分位数说话,不是只看均值。

十三、评测与 Bad Case 闭环

1. 怎么定义 Agent 答得对?评测集谁建、标签谁标?(25)

  • 定义「对」:拆成可量化维度——意图正确、检索命中、答案事实正确、格式/话术合规。不同场景不同标准。
  • 谁建/标:业务+算法共建评测集(覆盖真实分布+易错长尾);标签由业务专家标(金标),可用 LLM 预标 + 人工复核降本。

2. 智能体评测怎么做?离线 vs 线上分别看什么指标?(29)

  • 离线:固定评测集,看准确率/召回命中率/意图准确率/幻觉率;可复现、迭代用。
  • 线上:真实流量,看用户负反馈率/重问率/会话完成率/人工接管率/成本延迟;反映真实体验。
  • RAG 专项指标(社区框架 RAGAS / TruLens / DeepEval):context precision/recall(召回质量)、faithfulness(忠实度/反幻觉)、answer relevancy(切题度);检索单看 Hit@k / MRR / NDCG。
  • Agent 专项:工具选择准确率、参数正确率、任务完成率(task success)、轨迹/步数效率。
  • 平台:LangSmith / Langfuse 做 trace + 评测 + 数据集回流,与线上可观测打通。

3. 自动评测和人工评测怎么配合?评分怎么防主观?(30)

  • 自动(含 LLM-as-judge)跑量、覆盖全集;人工抽检校准、处理长尾和争议。防主观:明确评分 Rubric(维度+分档+示例)、多人标注算一致性(Kappa)、LLM judge 给固定标准 + few-shot 锚点。

4. 评测体系从 0 到 1,先搭数据/指标/平台/看板?(41)

  • 顺序:先数据(评测集)→ 再指标(定义对错)→ 再平台(自动化跑)→ 最后看板(可视化趋势)。没有数据和指标,平台看板都是空壳。

5. 评测集只有 200 条,线上几十万用户,怎么看结论?(39)

  • 200 条不能代表线上分布,只能做回归/相对比较(版本间好坏),不能当绝对准确率。要补:按线上真实分布分层采样扩充、持续从 Bad Case 回流扩集、用线上指标交叉验证。强调「小评测集看相对变化,别当绝对真理」。

6. Bad Case 闭环系统怎么设计(采集→归类→复盘→回归)?要不要产品化?ROI 怎么讲?(31 / 42)

  • 闭环:采集(负反馈/人工接管/低置信自动捞)→ 归类(按意图/检索/生成/工具分桶)→ 复盘(定位根因层)→ 修复 → 回归(进评测集防复发)。
  • 产品化 ROI:Bad Case 多、迭代频繁时值得产品化(自动采集+看板+回归),把人工排查时间换成系统化沉淀;跟老板讲「单次人工排查成本 × 频次 vs 系统投入 + 复发率下降带来的准确率提升」。

7. Bad Case 来了,从用户原话/意图/检索/工具/模型输出怎么逐层定位?(24)

  • 分层定位(顺着链路走):① 用户原话是否有歧义/脏输入 → ② 指代消解/改写对不对 → ③ 意图分类对不对 → ④ 路由对不对 → ⑤ 检索召回+rerank 有没有命中 → ⑥ 工具调用参数/结果对不对 → ⑦ 模型生成有没有忠于上下文。mate-assist 的链路节点天然就是定位锚点(有 trace+每节点 span,能看每层中间产物)。

8. 相似 Bad Case 反复出现,怎么判断是数据/prompt/检索/模型问题?(32)

  • 数据问题:知识库缺这条/过时 → 补数据;检索问题:数据在但召不回 → 调切片/召回;prompt 问题:召回对但答偏 → 改 prompt;模型问题:换模型/加约束仍不行才是模型能力上限。按链路做消融(固定其他变量只改一层看是否解决)。

9. 【Case】Agent 线上大面积答非所问,第一反应和排查顺序?(26)

  • 第一反应:先止血不先 debug——看是不是刚发版(prompt/模型/知识库/路由表变更),能回滚先回滚。
  • 排查顺序:看监控(哪个意图/分支集中出问题)→ 看是全局还是局部 → 全局多半是公共依赖(模型降级/检索服务挂/prompt 发错 tag/embedding 版本不匹配)→ 局部看具体分支。先定位爆炸半径再修。

10. 【补充】端到端回归体系怎么工程化?(源自 scripts/ 回归实战)

  • 黑盒端到端:对运行中的服务打真实 /chat,用可观测信号间接判定(意图对不对看日志 event_code=intent_classified、不空洞应答、不误进场景陷阱),不依赖内部实现细节。
  • 进程隔离 + 不阻断:run_all_regression.py 每个子脚本独立进程跑、失败不阻断后续、末尾打汇总表、整体有失败以非零退出码接 CI;支持 --only/--skip 按编号跑。
  • 硬断言 vs 软断言:确定性的(红线词黑名单不出现)是硬断言失败即 FAIL;LLM 措辞多变的(应有安抚措辞)是软断言,缺失记 DEGRADED 而非 FAIL,降误判。
  • 异步链路要轮询:记忆抽取是后台任务,断言前轮询落库,避免误报。
  • 工程细节:所有网络回归脚本加 NO_PROXY='*' 绕本机代理防慢失败。
  • 每修一个 Bad Case 就固化成一条回归:意图延续、长期记忆串味、合规红线、会话毒化、视觉识别、媒体流——都从线上 Bad Case 沉淀成脚本防回退。

11. 老板说准确率 80%→95%,怎么操作?(38)

  • 先拆:95% 在哪个维度、哪个评测集上?先做 Bad Case 归因看 80% 错的那 20% 分布在哪层(检索?意图?生成?)→ 抓占比最大的根因集中打(通常 RAG 召回和意图是大头)→ 每修一类进回归集 → 迭代逼近。强调「准确率提升是归因驱动的,不是拍脑袋」,并说明最后几个点边际成本陡增,要和老板对齐投入产出。

十四、成本控制

1. Agent 线上成本炸了(token/工具/检索都高),先砍哪块?(46)

  • 先归因(可观测统计各项占比),砍占比最大的。一般优先级:① 砍无效 LLM 调用(能用规则/缓存的不调模型)→ ② 压上下文 token(滚动摘要、只喂必要上下文)→ ③ 缓存(意图/召回/工具结果)→ ④ 减检索次数/路数 → ⑤ 大小模型分级(简单问题走小模型)。

2. 高并发下 LLM 成本怎么控 token 和钱?(69)

  • 省 token:精简 prompt、上下文压缩、输出长度上限、few-shot 按需。
  • 省钱:缓存命中、小模型分流、批处理、KV cache 复用;设租户/会话预算上限超了降级。
  • 结合项目:mate-assist 滚动摘要让长对话 token 成本恒定;jarvis-registry 网关统一配额统计。

3. RAG+多 Agent+工作流,技术选型怎么平衡效果/延迟/成本?(44)

  • 三角权衡:效果↑通常延迟↑成本↑。做法:按场景分级——简单问答少跳少 Agent、复杂问题才上多跳 Agentic RAG + 多 Agent;延迟敏感的用缓存+小模型+并行召回;用评测集量化「每多一跳/多一路召回带来的效果增益 vs 延迟成本增量」,只在增益划算处加。「用数据驱动取舍,不是堆满所有能力」。

十五、合规与安全(B 端重点)

B 端销售场景,答错不只是体验问题,可能是合规/法律风险。这块能讲出来是加分项。

1. Agent 输出合规怎么守?(源自话术合规门禁实战)

  • 三大失败模式(销售场景):① 该生成却被「请选择场景」顶回不生成;② 投诉/故障/功能等服务诉求被无视、硬转卖车(被全局「每轮推进成交」prompt 带偏);③ 逼单乱承诺(虚构优惠/稀缺/回购)、诱导代付(最危险)、贬低友商。
  • 守法方式:
    • 红线词黑名单 = 确定性硬门禁:诱导代付、乱承诺、贬低竞品的措辞一律拦,不靠模型自觉。
    • 兜底场景:无销售线索的服务诉求路由到 general_service 承接(安抚/解决导向),不硬转卖车。
    • 门禁回归(12_compliance_regression_test.py):红线词硬断言 FAIL、应有措辞软断言 DEGRADED,防 prompt 调整悄悄回退。

2. 根因不一定在 Prompt——也可能在代码

  • 📌 实战教训:话术「反问菜单」失败模式,根因其实在代码的确定性槽位提取(discourse_slots.py 里 scene 是必填槽位,命中 0 个就 interrupt() 反问),改 prompt 根本不生效;兜底场景 general_service 因为不在 SceneEnum 枚举里是死代码,必须靠代码 wiring 才能用。定位要先分清「这是 prompt 控制的还是代码控制的」,别在错误的层打补丁。

3. PII / 内容安全怎么处理?

  • PII:对话/录音入库和喂模型前做 PII 识别与脱敏(姓名/电话/身份证/车牌),调研过 content-filter 与 PII 的社区方案。
  • 内容过滤:模型网关自带 content_filter(如豆包对敏感词返回 finish_reason=content_filter),应用要正确识别为确定性拒绝(不是瞬时错误、不重试,见第六章实战),并给用户体面兜底。
  • 输入侧:警惕 prompt 注入——检索到的文档、用户上传内容都是不可信数据,不能当指令执行;工具出参也要校验防二次注入。

4. LLM 应用安全有哪些系统性风险?(OWASP LLM Top 10)

  • 面试能报出框架加分:OWASP LLM Top 10(2025)覆盖——LLM01 Prompt Injection(直接/间接注入,最高频)、LLM02 敏感信息泄漏、LLM05 不安全的输出处理(模型输出直接拼 SQL/命令/HTML → 注入)、LLM06 过度代理权限(Agent 工具权限过大)、LLM08 向量/embedding 投毒、LLM10 无限资源消耗(成本/DoS)等。
  • 工程对策串起来:输入侧——检索内容/用户上传当不可信数据、做隔离与标注;输出侧——结构化校验、转义、不直接执行模型吐的代码;工具侧——最小权限 ACL + 沙箱 + 审计(jarvis-registry 的工具级 ACL 正是治 LLM06);资源侧——token/调用预算上限治 LLM10(见第十四章)。

十六、模型与推理基础(原理兜底)

这些是「应用层问多了必然往下探」的底层,答不出会显得只会调 API。不用背公式,但要讲清机制和取舍。

1. Transformer / Self-Attention 原理?为什么是 O(n²)?

  • Self-Attention:每个 token 生成 Query/Key/Value 三个向量;用自己的 Q 和所有 token 的 K 点积得到注意力权重(softmax(QKᵀ/√d)),再加权求和各 token 的 V。本质是「每个词按相关性从全序列聚合信息」。
  • 多头:多组 QKV 并行,各看不同子空间关系,拼接后投影。
  • O(n²):每个 token 要和其它所有 token 算相关性 → n×n 注意力矩阵,这就是长上下文又贵又慢的根因,也是 FlashAttention(IO 优化)、稀疏/线性注意力要解决的。
  • 比 RNN 强在:全序列并行(RNN 必须串行)、长距离依赖一步可达。

2. 位置编码?长上下文怎么外推?

  • Attention 本身对顺序无感,要靠位置编码注入次序。绝对位置编码(原始 Transformer 正弦)、RoPE 旋转位置编码(Llama 系主流,把位置编码成旋转、相对位置友好)、ALiBi(给注意力加距离惩罚)。
  • 长上下文外推:YaRN / NTK 插值(缩放 RoPE 频率,把训练时 4k 的模型撑到几十 k)。但注意Lost in the Middle(Liu et al. 2023)——超长上下文里中间部分信息最易被忽略,所以重要内容放开头/结尾,别指望「塞进去就会用」。

3. Embedding 原理?相似度怎么算?

  • 原理:用对比学习训练句/段编码器,把语义近的文本拉近、远的推开;输出定长向量(如 1536 维)。池化方式(CLS / mean pooling)、是否归一化影响效果。
  • 相似度:cosine(最常用,只看方向)、dot(含模长)、L2。向量归一化后 cosine 与 dot 等价。
  • 要点:embedding 模型要和检索语料领域匹配;多语言选多语模型(bge-m3);换模型=换维度=全库重建(见第四章实战)。

4. 推理为什么慢/贵?有哪些优化?

  • 两阶段:Prefill(并行处理输入 prompt,算力瓶颈)+ Decode(逐 token 生成,受显存带宽瓶颈,KV Cache 在这)。首 token 延迟(TTFT) 看 prefill,吐字速度看 decode。
  • 优化:vLLM/PagedAttention(显存管理)+ continuous batching(动态拼批提吞吐)、投机解码 speculative decoding(小模型草稿 + 大模型校验,加速 decode)、量化(GPTQ/AWQ/GGUF/INT8-FP8,省显存降延迟、略损精度)、GQA/MQA(见 KV Cache)。
  • MoE:混合专家,每 token 只激活部分专家,总参数大但单次推理激活少(DeepSeek、Mixtral),省算力但调度/显存更复杂。

十七、Prompt 工程与高级 RAG 范式

1. Prompt 工程有哪些实打实的手段?

  • 基本要素:角色 + 任务 + 约束 + 输出格式 + few-shot 示例;指令放开头、长上下文关键信息放首尾(对抗 Lost in the Middle)。
  • 推理增强:CoT(Chain-of-Thought,让模型分步想)、Few-shot CoT / Zero-shot CoT(“let’s think step by step”)、Self-Consistency(多次采样取多数票)、ReAct(思考-行动-观察交替,Agent 基础)、Step-back(先抽象再具体)。
  • 结构化输出:JSON mode / guided decoding / 受约束解码(用 schema 约束生成,保证可解析)、function calling 出结构化参数。工程上一定要 schema 校验 + 失败回喂重修,别信模型永远吐合法 JSON。
  • 工程化:prompt 要版本化、可回滚、可灰度——mate-assist 用独立 prompt-manager 仓库 + release tag 管理,模型同学改 prompt 不用发版、线上按不可变 tag 加载。

2. RAG 的演进范式?(Naive → Advanced → Modular)

  • Naive RAG:切块→embedding→单次检索→塞进 prompt→生成。问题:召回不准、答非所问、无纠错。
  • Advanced RAG:加检索前优化(query 改写/扩展/HyDE、元数据过滤)+ 检索后优化(rerank、压缩、去重、parent-doc 返回大块)。mate-assist / rag_api 都在这一层。
  • Modular RAG:检索、路由、记忆、工具变成可编排模块(接近 Agentic)。
  • 高级范式速查(按「要不要让系统自己纠错/多跳」升级):
    • HyDE:假设答案再检索(第四章)。
    • Parent-Document / small-to-big:小块召回、大块喂模型。
    • CRAG(Corrective RAG):给召回打分,差就触发纠偏(换源/重检索)——mate-assist 的 rag_grade→rag_rewrite 就是它。
    • Self-RAG:模型自判要不要检索、召回够不够、答案是否有据。
    • GraphRAG(微软):先抽实体关系建图 + 社区摘要,擅长「跨多文档的全局性问题」和多跳关系;和向量召回互补(第九章)。
    • Agentic RAG:把检索当工具交给 Agent 自主多轮调用(第二章)。
  • 一句话选型:单跳够用就别上 Agentic(贵、慢、难测);需要纠错上 CRAG,需要多跳关系上 GraphRAG,需要跨文档聚合+自主规划才上 Agentic RAG。

十八、手撕 / 现场编码高频题

大厂常要求现场写一段——不求花哨,能跑、边界清楚、讲得出复杂度即可。下面都是可直接背的最小实现。

1. 手写 Self-Attention(numpy)

import numpy as np

def softmax(x, axis=-1):
    x = x - x.max(axis=axis, keepdims=True)      # 数值稳定:减最大值防 exp 溢出
    e = np.exp(x)
    return e / e.sum(axis=axis, keepdims=True)

def self_attention(X, Wq, Wk, Wv, mask=None):
    """X: (seq, d_model);返回 (seq, d_k)。"""
    Q, K, V = X @ Wq, X @ Wk, X @ Wv             # 各 (seq, d_k)
    d_k = Q.shape[-1]
    scores = Q @ K.T / np.sqrt(d_k)              # (seq, seq),/√d_k 防梯度消失
    if mask is not None:                          # 因果掩码:上三角置 -inf
        scores = np.where(mask, scores, -1e9)
    return softmax(scores) @ V                    # 加权求和各 token 的 V
  • 讲点:/√d_k 的作用、causal mask 怎么来、多头就是切成 h 份各算再拼、复杂度 O(n²·d)。

2. 手写最小 RAG 检索(cosine top-k)

import numpy as np

def embed(texts):              # 占位:真实换成 bge / openai embedding
    ...

def retrieve(query, doc_vecs, docs, k=3):
    q = embed([query])[0]
    q = q / (np.linalg.norm(q) + 1e-8)
    d = doc_vecs / (np.linalg.norm(doc_vecs, axis=1, keepdims=True) + 1e-8)
    sims = d @ q               # 归一化后点积 = cosine
    top = np.argsort(-sims)[:k]
    return [(docs[i], float(sims[i])) for i in top]
  • 讲点:归一化后点积=cosine;大规模要换 ANN(HNSW/IVF)而非暴力 O(N);加元数据过滤就是先 mask 再排序。

3. 手写 RRF 多路融合

def rrf(rank_lists, k=60):
    """rank_lists: [[docA, docB...], [...]],每个是一路按相关性排好的 id。"""
    scores = {}
    for lst in rank_lists:
        for rank, doc in enumerate(lst):
            scores[doc] = scores.get(doc, 0) + 1 / (k + rank)
    return sorted(scores, key=scores.get, reverse=True)
  • 讲点:只用名次不用原始分,免归一化;k 调大→名次差异被抹平。

4. 带并发上限的异步批处理(Agent 常考)

import asyncio

async def run_all(items, worker, limit=8):
    sem = asyncio.Semaphore(limit)          # 关键:控并发防打爆下游/429
    async def guarded(x):
        async with sem:
            return await worker(x)
    return await asyncio.gather(*(guarded(x) for x in items))
  • 讲点:为什么不能无脑 gather(限流/连接池/内存);CPU 密集要 run_in_executor 进线程池(见第十二章实战)。

5. 滑动窗口裁上下文(控 token)

def clip_by_tokens(messages, count_tokens, budget):
    """保最近消息,总 token 不超 budget;真实再叠滚动摘要(第七章)。"""
    kept, total = [], 0
    for m in reversed(messages):            # 从最新往回留
        t = count_tokens(m)
        if total + t > budget:
            break
        kept.append(m); total += t
    return list(reversed(kept))

十九、部署与分布式(SRE 视角)

工程岗会问「怎么上线、怎么扩、挂了怎么办」。串起前面各章的工程点。

  • 容器化 / K8s:mate-assist 有 Dockerfile + k8s/ 编排;提示词走 git-sync sidecar 拉 prompt-manager 挂载给 app(镜像不打包 prompt,和代码解耦)。
  • 发布与灰度:prompt 按不可变 release tag 加载,改 prompt 不发版、可秒回滚;模型/路由可按租户灰度;配 verify_prompt_source.py 发布前校验 tag 一致。
  • 水平扩容靠无状态:网关/应用做无状态才能水平扩——jarvis-registry 把 client-info 放 Redis(client_info_store)让 MCP 网关 stateless;mate-assist 会话态落 MySQL checkpointer,实例可随意扩缩、崩溃可从断点恢复。
  • 模型网关:多 provider/模型做路由 + failover + 限流(豆包/火山等),按 RPM/TPM 配额调度(见第十二章联合调度器);content_filter 等确定性错误不重试(第六章)。
  • GPU 资源:把 reranker / embedding 做成独立服务(mate-assist 独立 reranker、rag_api embedding 线程池),GPU 活和主链路解耦,单独扩缩容、不被在线对话挤占。
  • 高可用兜底:下游挂了熔断降级(走缓存/兜底话术);离线跑批错峰 + 队列隔离避免洪峰(第十二章)。

二十、数字准备清单(面前填好、背熟)

「结合项目」最怕说不出量级。按下表把真实数字填进去,面试张口就来。(下列为要准备的维度,数值以你线上实际为准)

维度 取数口径 mate-assist rag_api jarvis-registry
规模 QPS / DAU / 文档量 / 工具数 销售数、日会话数 文档/chunk 量 接入 MCP server / 工具数、租户数
延迟 P50/P95、流式看 TTFT 对话 P95、首 token 入库/检索耗时 网关转发开销
效果 准确率 / 召回 Hit@k / 意图准确率 / 幻觉率 评测集准确率 检索 Hit@k、MRR 工具命中率
成本 单会话 token、月成本、缓存命中率 单轮 token、滚动摘要节省 embedding 成本 按租户配额
可靠性 成功率 / 超时率 / 人工接管率 线上成功率 — —
已知亮点数 优化前后对比 媒体 2m7s→正常;跑批闸门 P50 32.5→10.5s 线程池上限 8 无状态后可水平扩
  • 口径优先用可观测系统真实导出(mate-assist observability/metrics + OTel),别拍脑袋;说不准的给量级 + 怎么测的,比编一个精确假数字可信。

二十一、2 分钟自我介绍 + 项目 STAR 话术

  • 开场模板(30 秒):「我主要做 AI 应用 / Agent 后端,最近一年落了三个方向——① 一个生产级对话 Agent(mate-assist,FastAPI+LangGraph 的汽车销售助手,深度在 RAG/记忆/状态机/流式/合规);② 一个企业 Agent 基础设施(jarvis-registry,MCP 网关 + A2A 编排,广度在多 Agent/权限/可观测);③ 一个 RAG 索引检索微服务(rag_api,pgvector + 可插拔 embedding)。整体从单 Agent 深度到平台广度到RAG 基建都覆盖。」
  • STAR 讲项目(每个项目一段,按需展开):
    • S 场景:销售面对几千条车型知识+话术,人工记不住、新车知识更新快,答错影响成单。
    • T 任务:做一个准确、可控、低延迟、合规的销售助手后端。
    • A 行动:LangGraph 确定性图编排(意图→RAG 子链→生成→记忆);CRAG 式 grade+重检索防幻觉;messages/model_input 分离防污染;滚动摘要控 token;节点级重试只重瞬时故障;合规红线硬门禁;一整套端到端回归防回退。
    • R 结果:(填真实数字)准确率 X→Y、媒体链路 2m7s→正常、长对话 token 成本恒定、线上 Bad Case 闭环复发率下降。
  • 讲踩坑(面试官最爱):挑 1~2 个一手 Bad Case——会话"毒化"连续孤儿 Human 卡死、content_filter 被误当瞬时错误重试整门店失败、意图无状态重判带偏。能讲清现象→根因→修法→防回归就赢了。

二十二、反问面试官的好问题(收尾加分)

  • 团队现在 Agent/RAG 最大的瓶颈是效果、延迟还是成本?卡在哪一层?
  • 你们怎么定义和度量「答得对」?有没有评测集和 Bad Case 闭环?
  • 线上 Agent 的可观测和回归体系做到什么程度了?出了 Bad Case 怎么定位?
  • 模型是自研微调为主还是 API + RAG 为主?怎么平衡效果和成本?
  • 这个岗位半年内最想让我解决的一个具体问题是什么?