首页 › 面试专攻 › AI Agent 面试八股文 -- 总目录 › 企业级 AI Agent 项目面试问答集(上)

企业级 AI Agent 项目面试问答集(上)

第一类:架构设计类问题​

Q1: 为什么选择 ReAct 模式而不是 Plan-and-Execute?​

Situation: 在设计企业级 AI Agent 系统时,需要在 ReAct(Reasoning + Acting)和 Plan-and-Execute 两种主流 Agent 范式之间做出架构决策。业务场景包括客服问答、知识检索、工具调用等多种任务类型。​

Task: 选择一种既能满足实时交互需求,又能处理复杂多步任务的 Agent 架构范式。​

Action:​

对比分析两种范式:​

◦

ReAct:思考-行动-观察的循环模式,每一步都基于当前观察做出决策,具有强交互性和动态适应能力。​

◦

Plan-and-Execute:先制定完整计划,再按步骤执行,适合任务结构明确、步骤可预见的场景。​

基于业务场景评估:​

◦

企业客服场景中,用户意图经常在对话中变化(如从查订单变成要退款),ReAct 能实时调整策略。​

◦

Plan-and-Execute 在计划阶段就需要确定所有步骤,一旦中间步骤失败,整个计划需要重做。​

◦

ReAct 的流式特性天然支持"边思考边输出",用户体验更好。​

技术可行性评估:​

◦

ReAct 的 Prompt 模板更灵活,可以通过 few-shot 快速调整行为。​

◦

ReAct 与 Function Calling 天然兼容,每次思考后可以调用工具。​

◦

通过设置最大迭代次数(max_iterations=10)和超时机制,可有效防止死循环。​

混合方案设计:​

◦

实际落地中采用 ReAct 为主、Plan 为辅的混合方案。​

◦

简单查询(单步任务):直接走 ReAct 单次循环。​

◦

复杂任务(多步骤):先用 LLM 生成粗粒度 Plan,每个步骤内部用 ReAct 执行。​

Result:​

•

系统平均响应时间从纯 Plan-and-Execute 的 8s 降低到 ReAct 模式的 3.2s(简单任务直接缩短为单步)。​

•

任务完成率从 78% 提升到 91%,因为 ReAct 能根据中间结果动态调整策略。​

•

用户满意度提升 15%,因为流式输出让用户感知到更快的响应。​

​

​

Q2: 为什么采用多路检索而不是单一向量检索?​

Situation: 企业知识库包含大量结构化和非结构化数据,单一向量检索在某些场景下召回率不足。例如,精确的编号查询(如"工单号 WO-20240315-001")在纯语义检索中表现很差。​

Task: 设计一个兼顾语义理解和精确匹配的检索架构,提升知识检索的准确率和召回率。​

Action:​

多路检索架构设计:​

◦

向量检索(语义通道): 使用 Milvus 存储文档向量,基于 embedding 相似度做语义召回,top_k=20。​

◦

关键词检索(精确通道): 使用 Elasticsearch 做 BM25 检索,处理精确查询、编号匹配等场景,top_k=20。​

结果融合策略:​

◦

采用 RRF(Reciprocal Rank Fusion)算法融合多路结果。​

◦

公式:RRF_score = Σ 1/(k + rank_i),其中 k=60 是平滑常数。​

◦

每路检索结果独立排序后,通过 RRF 算法统一排名。​

查询路由策略:​

◦

意图识别模块判断查询类型,动态激活不同检索通道。​

◦

精确查询(含编号、代码等)→ 优先走关键词通道。​

◦

概念性问题("什么是微服务")→ 优先走向量通道。​

◦

关系查询("谁负责某项目")→ 启用知识图谱通道。​

Result:​

•

整体检索准确率(Precision@5)从单一向量检索的 72% 提升到多路融合的 89%。​

•

召回率(Recall@20)从 65% 提升到 93%。​

•

精确编号类查询的命中率从 30% 提升到 98%。​

​

​

Q3: Agent 编排器是怎么设计的?为什么这样设计?​

Situation: 系统需要协调多个组件(意图识别、检索、生成、工具调用等)的执行流程,需要一个灵活且可扩展的编排机制。​

Task: 设计一个能支持多种执行模式(顺序、并行、条件分支)且易于扩展的 Agent 编排器。​

Action:​

核心架构 —— 状态机 + 事件驱动:​

​

代码块​

Plain Text

用户输入 → 意图识别 → 路由决策 → 执行计划 → 工具/检索调用 → 结果整合 → 响应生成​

◦

定义了 7 个核心状态:INIT → INTENT_PARSED → PLANNED → EXECUTING → TOOL_CALLED → SYNTHESIZING → COMPLETED​

◦

每个状态转换由事件触发,通过状态转换表控制流程。​

​

编排器核心组件:​

◦

AgentOrchestrator(总编排器): 管理整体流程,维护执行上下文。​

◦

TaskPlanner(任务规划器): 将复杂任务分解为子任务 DAG(有向无环图)。​

◦

ToolDispatcher(工具分发器): 根据 Function Calling 结果调用对应工具。​

◦

ContextManager(上下文管理器): 维护对话历史、工具调用结果等上下文信息。​

设计决策的考量:​

◦

为什么用状态机? 可枚举所有合法状态转换,便于 debug 和异常处理,比纯 LLM 链式调用更可控。​

◦

为什么用事件驱动? 解耦各组件,支持异步执行和并行工具调用,提升系统吞吐量。​

◦

为什么用 DAG 而非线性队列? 支持并行子任务(如同时查数据库和调 API),减少总执行时间。​

可扩展性设计:​

◦

新增工具只需实现 BaseTool 接口并注册到 ToolRegistry。​

◦

新增 Agent 类型只需定义新的状态转换规则。​

◦

通过配置文件管理流程编排,无需修改核心代码。​

Result:​

•

支持了 12 种不同的业务流程编排,每种只需配置不覅改代码。​

•

新工具接入时间从原来的 2 天缩短到 2 小时(标准化接口)。​

•

并行工具调用使复杂任务执行时间缩短 40%。​

​

​

Q4: 多 Agent 协作和单 Agent 有什么区别?你怎么选择?​

Situation: 随着业务复杂度增加,单个 Agent 的 Prompt 越来越长,工具数量越来越多,开始出现能力退化和维护困难的问题。​

Task: 评估是否需要从单 Agent 架构迁移到多 Agent 协作架构,以及如何设计协作机制。​

Action:​

单 Agent 的瓶颈分析:​

◦

单 Agent 的系统 Prompt 超过 4000 tokens 后,指令遵循能力明显下降。​

◦

工具数量超过 15 个时,LLM 选择工具的准确率从 95% 下降到 78%。​

◦

所有逻辑耦合在一个 Prompt 中,修改一个功能可能影响其他功能。​

多 Agent 架构设计:​

◦

Supervisor Agent(主管 Agent): 负责意图识别和任务路由,不直接执行任务。​

◦

RAG Agent(检索 Agent): 专注于知识检索和答案生成。​

◦

Tool Agent(工具 Agent): 专注于外部 API 调用和数据处理。​

◦

Summary Agent(摘要 Agent): 专注于长文本摘要和对话总结。​

协作机制:​

◦

通信方式: Agent 之间通过结构化消息传递(JSON Schema 定义),避免自然语言传递导致的信息损失。​

◦

执行策略: Supervisor 判断任务类型后,将任务分派给专业 Agent;支持顺序执行和并行执行。​

◦

结果汇总: 由 Supervisor Agent 整合各子 Agent 结果,生成最终回答。​

选择标准:​

◦

工具数 ≤ 8 且业务逻辑简单 → 单 Agent。​

◦

工具数 > 8 或需要专业分工 → 多 Agent。​

◦

有跨域协作需求(如同时查知识库和调外部 API)→ 多 Agent。​

Result:​

•

迁移到多 Agent 后,工具选择准确率回升到 96%。​

•

每个 Agent 的 Prompt 控制在 2000 tokens 以内,维护性大幅提升。​

•

新增业务场景只需新增专业 Agent,不影响现有功能。​

•

系统整体任务完成率从 85% 提升到 93%。​

​

​

Q5: 意图识别模块是怎么实现的?​

Situation: 企业客服场景中,用户意图多样(咨询、投诉、查询订单、操作请求等),且存在大量隐含意图和多意图混合的情况(如"我的订单怎么还没到,我要退款"同时包含查询和操作意图)。​

Task: 设计一个准确率高、可扩展的意图识别模块,能处理多意图和隐含意图。​

Action:​

两阶段意图识别架构:​

◦

第一阶段 —— 粗分类(基于规则 + 小模型):​

▪

正则匹配高频模式(如订单号格式 [A-Z]{2}-\d{8}-\d{3})。​

▪

FastText 轻量分类器做初步意图分类(延迟 < 5ms)。​

意图体系设计(三级分类):​

​

代码块​

Plain Text

L1: 咨询/操作/投诉/闲聊​

L2: 产品咨询/技术咨询/订单查询/退款申请/...​

L3: 具体产品线/具体操作类型/...​

​

置信度阈值策略:​

◦

confidence ≥ 0.85 → 直接执行。​

◦

0.6 ≤ confidence < 0.85 → 向用户确认意图。​

◦

confidence < 0.6 → 追问澄清。​

Result:​

•

意图识别准确率达到 94%(测试集 5000 条标注数据)。​

•

多意图识别 F1-score 达到 0.89。​

•

第一阶段处理了 80% 查询,LLM 调用量减少 80%,节省了大量 token 成本。​

​

​

Q6: 为什么选择 Milvus 而不是其他向量数据库?​

Situation: 项目需要一个向量数据库来存储和检索文档 embedding,候选方案包括 Milvus、Pinecone、Weaviate、Qdrant、Chroma、FAISS 等。​

Task: 综合评估各方案的性能、功能、运维成本,选择最适合企业级场景的向量数据库。​

Action:​

排除不适合的方案:​

深度对比 Milvus vs Weaviate vs Qdrant:​

◦

性能: Milvus 在 1000 万级向量上 QPS 达到 2000+,Qdrant 约 1500,Weaviate 约 1200。​

◦

扩展性: Milvus 原生支持分布式部署(计算存储分离),可水平扩展。Qdrant 的分布式能力相对较弱。​

◦

索引类型: Milvus 支持 IVF_FLAT、IVF_SQ8、HNSW、DiskANN 等多种索引,可根据数据规模选择最优方案。​

◦

混合搜索: Milvus 2.x 支持标量过滤 + 向量搜索的混合查询,满足"按部门+语义"的业务需求。​

◦

生态: Milvus 有 LangChain、LlamaIndex 等主流框架的官方集成。​

◦

社区: Milvus 是 LF AI & Data 基金会毕业项目,社区活跃,长期维护有保障。​

POC 验证(基于 200 万文档的真实数据):​

◦

建立测试基准,对比查询延迟、召回率、资源占用。​

◦

Milvus:P99 延迟 45ms,召回率 98.2%,内存占用 16GB。​

Result:​

•

最终选择 Milvus,部署了 3 节点集群。​

•

线上稳定运行 8 个月,P99 延迟稳定在 50ms 以内。​

•

数据量从 200 万增长到 800 万文档,通过水平扩展平滑支撑。​

​

​

Q7: 系统的可扩展性是怎么设计的?​

Situation: 系统需要支持业务快速迭代,包括新增工具、新增知识源、新增 Agent 类型、新增模型等,不能每次都改核心代码。​

Task: 设计一套可扩展架构,让新功能接入的边际成本趋近于零。​

Action:​

插件化工具系统:​

class BaseTool(ABC):@abstractmethoddef name(self) -> str: ...@abstractmethoddef description(self) -> str: ...@abstractmethoddef parameters_schema(self) -> dict: ...@abstractmethodasync def execute(self, **kwargs) -> ToolResult: ...​

◦

所有工具继承 BaseTool,通过 ToolRegistry 自动注册。​

◦

工具描述自动生成 Function Calling 的 JSON Schema。​

可配置的检索管道:​

◦

检索管道通过 YAML 配置文件定义:​

retrieval_pipeline:​

- name: vector_searchengine: milvustop_k: 20weight: 0.6​

- name: keyword_searchengine: elasticsearchtop_k: 20weight: 0.4reranker:model: bge-reranker-v2-m3top_k: 5​

◦

新增检索通道只需添加配置项和实现对应引擎接口。​

模型抽象层:​

◦

统一的 LLMProvider 接口,支持 OpenAI、Anthropic、本地模型等。​

◦

通过配置切换模型,不修改业务代码。​

事件总线:​

Result:​

•

新工具接入:平均 2 小时(实现接口 + 写配置)。​

•

新检索通道接入:半天。​

•

切换底层模型:改一行配置,零代码改动。​

•

系统在 6 个月内新增了 8 个工具、3 个检索通道,核心代码零修改。​

​

​

Q8: 如果让你重新设计这个系统,你会怎么改进?​

Situation: 系统已经稳定运行一段时间,积累了很多实践经验和教训,有一些当初的设计决策在回头看是可以优化的。​

Task: 基于实际运行经验,总结需要改进的点,给出具体的优化方案。​

Action:​

评估引入(Evaluation-Driven Development):​

可观测性增强:​

◦

当初的日志系统是后补的,trace 不够完整。​

◦

改进:从第一行代码就接入 LangSmith / LangFuse,实现全链路 trace。​

◦

每个 Agent 步骤都有 span,可以在 dashboard 上看到完整的推理链路。​

Streaming 优先架构:​

◦

当初是先实现同步接口,后来改成流式,改造成本很高。​

◦

改进:从设计阶段就以 SSE/WebSocket 流式为默认通信方式。​

更细粒度的模型路由:​

◦

当初只有简单/复杂两档路由。​

◦

改进:根据任务类型(分类/生成/推理/摘要)、输入长度、质量要求,做更细粒度的模型选择。​

Agent 记忆系统重构:​

◦

当初的记忆系统比较粗糙,只是简单的窗口截断。​

◦

改进:实现分层记忆(工作记忆 + 情景记忆 + 语义记忆),引入记忆索引和检索机制。​

Result: 这些改进方案已经在新版本中逐步实施,形成了团队的最佳实践文档。这个反思过程本身也体现了持续优化的工程思维。​

​

​

Q9: 你的系统能支持多少并发?怎么评估的?​

Situation: 系统上线前需要进行压力测试,评估系统的并发处理能力,确保能满足业务高峰期的需求。​

Task: 设计压测方案,找到系统的性能瓶颈和容量上限。​

Action:​

压测工具和方法:​

◦

使用 Locust 进行分布式压测,模拟真实用户行为。​

◦

压测场景:简单问答(单轮)、多轮对话、RAG 检索问答、工具调用。​

系统配置(压测环境):​

◦

API 服务:4 个 Pod,每个 4C8G。​

◦

Milvus:3 节点集群,每节点 8C32G。​

◦

Redis:3 节点 Sentinel 集群。​

◦

LLM:使用云端 API(GPT-4 级别),QPS 限制 200。​

压测结果:​

◦

50 并发:P99 延迟 2.8s,QPS 48,错误率 0%。​

◦

100 并发:P99 延迟 4.2s,QPS 85,错误率 0.1%。​

◦

200 并发:P99 延迟 8.5s,QPS 120,错误率 2.3%。​

◦

300 并发:P99 延迟 15s+,QPS 110(开始下降),错误率 8.7%。​

瓶颈分析:​

◦

主要瓶颈在 LLM API 的 QPS 限制和延迟。​

◦

Milvus 检索在 200 并发下仍然很轻松(延迟 < 80ms)。​

Result:​

•

系统安全容量上限定为 150 并发(P99 < 5s,错误率 < 0.5%)。​

•

日常业务高峰约 80 并发,有充足余量。​

•

制定了弹性扩缩容策略:并发超过 120 时自动扩容 API Pod。​

​

​

Q10: 为什么要做模型路由?直接用一个模型不行吗?​

Situation: 系统每月的 LLM API 费用高达数万元,且不同类型的查询对模型能力的需求差异很大。简单查询用 GPT-4 是浪费,复杂推理用小模型又不够。​

Task: 设计一个智能模型路由机制,在保证回答质量的前提下,显著降低 token 成本。​

Action:​

分析查询分布:​

◦

统计发现 60% 的查询是简单问答(事实检索、FAQ),小模型即可胜任。​

◦

25% 是中等复杂度(需要多步推理或知识综合)。​

路由策略设计:​

​

代码块​

Plain Text

路由判断维度:​

├── 任务复杂度:简单检索 / 多步推理 / 复杂生成​

├── 上下文长度:短文本 / 长文本​

├── 质量要求:普通回答 / 高精度回答​

└── 用户等级:普通用户 / VIP 用户​

​

模型矩阵:​

◦

轻量模型(GPT-4o-mini / Claude 3 Haiku): 简单问答、意图分类、实体提取。​

◦

标准模型(GPT-4o / Claude 3.5 Sonnet): 中等复杂度推理、RAG 答案生成。​

◦

强力模型(GPT-4 / Claude 3 Opus): 复杂推理、长文本分析、关键业务决策。​

路由器实现:​

Result:​

•

月均 token 成本降低 62%(从 5 万降到 1.9 万)。​

•

回答质量几乎无损(用户满意度仅下降 1.2%)。​

•

系统整体延迟降低 35%(小模型响应更快)。​

​

​

Q11: 怎么设计的对话管理和上下文维护?​

Situation: 企业客服场景中多轮对话非常普遍,需要在多轮交互中维护一致的上下文,同时控制 token 消耗。​

Task: 设计对话管理系统,在有限的 context window 内高效利用上下文信息。​

Action:​

分层上下文管理:​

◦

系统层: System Prompt(固定,约 800 tokens),定义 Agent 角色和行为规范。​

◦

会话层: 对话历史(动态,滑动窗口),最近 N 轮对话。​

窗口管理策略:​

◦

维护最近 10 轮对话的完整记录。​

◦

超过 10 轮时,前面的对话自动摘要压缩。​

◦

摘要保留关键信息:用户意图、关键决策、未解决的问题。​

Token 预算分配:​

◦

假设总 context window 为 8K tokens:​

▪

System Prompt:800 tokens(10%)​

▪

对话历史 + 摘要:2400 tokens(30%)​

▪

检索上下文:3200 tokens(40%)​

▪

预留输出:1600 tokens(20%)​

Result:​

•

多轮对话的上下文一致性从 76% 提升到 94%(基于人工评估)。​

•

token 消耗控制在预算内,无超限导致的截断问题。​

•

支持最长 50 轮对话不丢失关键上下文。​

​

​

Q12: 你的系统支持哪些模型?怎么做模型适配的?​

Situation: 企业客户有不同的模型偏好:有的要用 OpenAI,有的要用国产模型(如通义千问、文心一言),有的有本地部署需求。​

Task: 设计统一的模型抽象层,让系统可以无缝切换不同的 LLM 提供商。​

Action:​

统一接口抽象:​

class LLMProvider(ABC):async def chat(self, messages, **kwargs) -> LLMResponse: ...async def stream_chat(self, messages, **kwargs) -> AsyncIterator[str]: ...def count_tokens(self, text) -> int: ...def get_model_info(self) -> ModelInfo: ...​

适配器模式实现:​

◦

OpenAIProvider:适配 OpenAI / Azure OpenAI API。​

◦

AnthropicProvider:适配 Claude 系列。​

◦

QwenProvider:适配通义千问(兼容 OpenAI 格式)。​

◦

LocalProvider:适配 vLLM / Ollama 部署的本地模型。​

差异化处理:​

◦

Function Calling 格式:OpenAI 用 tools 字段,Claude 用 tool_use,统一抽象后业务无感知。​

◦

Token 计算:不同模型的 tokenizer 不同,每个 Provider 实现自己的 count_tokens。​

◦

流式响应:不同 API 的 SSE 格式略有差异,在 Provider 层统一处理。​

Result:​

•

支持 6 种模型提供商,切换只需改配置。​

•

新模型适配:平均 1 天完成(实现 Provider + 测试)。​

•

多个客户使用不同模型,同一套业务代码。​

​

​

Q13: 如何处理长文档输入?上下文窗口不够怎么办?​

Situation: 企业文档动辄数万字甚至数十万字,远超模型的 context window 限制(如 GPT-4 的 8K/32K/128K)。​

Task: 设计一套长文档处理方案,在不丢失关键信息的前提下,让系统能处理任意长度的文档。​

Action:​

分块策略(Chunking):​

◦

基于语义的分块(不是简单按固定长度切分):​

▪

先按章节/段落自然分割。​

▪

每个 chunk 大小目标 512 tokens,允许 ±20% 浮动。​

▪

相邻 chunk 有 10% 的重叠,避免语义断裂。​

◦

递归分块:先按 \n\n 分,不够再按 \n 分,再按句号分。​

Map-Reduce 策略(超长文档总结):​

◦

Map 阶段:对每个 chunk 独立做摘要。​

◦

Reduce 阶段:对所有 chunk 摘要再做综合总结。​

Refine 策略(需要细节的场景):​

◦

逐 chunk 处理,每次将上一步结果和当前 chunk 一起输入。​

◦

适用于"找到文档中所有提到的风险点"类需求。​

智能截断(实时问答场景):​

◦

RAG 检索后,只取最相关的 top-5 chunk 放入 context。​

◦

通过 reranker 精排,确保最相关的内容在前面。​

Result:​

•

支持处理最长 50 万字的文档。​

•

Map-Reduce 总结准确率达到 88%(与人工总结对比)。​

•

实时问答场景的检索-生成延迟控制在 3s 以内。​

​

​

Q14: 系统的安全架构是怎么设计的?​

Situation: 企业级 AI 系统面临多种安全威胁:Prompt 注入、数据泄露、恶意输入、越权访问等。​

Task: 建立多层安全防护体系,确保系统的安全性和数据合规性。​

Action:​

输入安全层(Prompt 注入防护):​

◦

输入预处理:特殊字符转义、长度限制(单次输入 ≤ 2000 字符)。​

◦

注入检测模型:训练了一个轻量级分类器,识别常见注入模式(如"忽略之前的指令"、"你现在是..."等)。​

◦

角色隔离:用户输入和系统指令严格分离(不拼接在同一个 message 中)。​

数据安全层:​

◦

敏感信息脱敏:PII(个人身份信息)在输入 LLM 前自动脱敏,输出后还原。​

◦

知识库权限控制:不同角色可访问不同的知识分区(基于 RBAC)。​

◦

日志脱敏:对话日志中的敏感信息自动打码。​

输出安全层:​

◦

输出内容审核:调用内容安全 API 检查输出是否包含违规内容。​

系统安全层:​

◦

API 鉴权:JWT + API Key 双重认证。​

◦

速率限制:每用户每分钟最多 20 次请求。​

◦

审计日志:所有操作可追溯。​

Result:​

•

Prompt 注入防护拦截率 97%(基于 1000 个攻击样本测试)。​

•

零数据泄露事故。​

•

通过了公司内部安全团队的渗透测试。​

​

​

Q15: 你怎么看待 MCP(Model Context Protocol)?在你的系统中是怎么使用的?​

Situation: Anthropic 发布了 MCP 协议,提供了一种标准化的方式让 AI 模型与外部工具和数据源交互。需要评估是否在系统中采用 MCP。​

Task: 评估 MCP 的价值,决定是否以及如何在现有系统中集成 MCP。​

Action:​

MCP 核心价值分析:​

◦

标准化接口: 定义了 tools、resources、prompts 三大原语,统一了不同工具的接入方式。​

◦

双向通信: 基于 JSON-RPC 2.0,支持服务端主动推送通知。​

◦

传输灵活: 支持 stdio(本地进程)和 SSE(远程服务)两种传输方式。​

与 Function Calling 的对比:​

◦

Function Calling 是模型厂商的私有协议,每个厂商格式不同。​

◦

MCP 是开放协议,理论上可以跨模型、跨客户端复用工具。​

◦

MCP 更适合构建工具生态,Function Calling 更适合简单集成。​

在系统中的应用:​

◦

将现有工具封装为 MCP Server,对外提供标准化接口。​

◦

数据库查询、API 调用、文件操作等工具都通过 MCP Server 暴露。​

◦

内部 Agent 调用工具时,通过 MCP Client 发起请求。​

落地挑战和解决:​

◦

MCP 生态还在早期,部分工具的 MCP 封装需要自己开发。​

◦

安全审核:每个 MCP Server 的权限需要严格控制。​

◦

性能开销:MCP 协议的序列化/反序列化有额外开销(约 5ms),可接受。​

Result:​

•

工具接入标准化后,新工具的平均接入时间从 2 天缩短到 4 小时。​

•

工具可以在不同项目之间复用,减少重复开发。​

•

为后续接入社区 MCP 工具生态奠定基础。​

​

​

Q16: 如何设计 Agent 的错误恢复和重试机制?​

Situation: 生产环境中 Agent 执行过程会遇到各种错误:LLM API 超时、工具调用失败、检索无结果等。简单的重试可能导致资源浪费或无限循环。​

Task: 设计一套智能的错误恢复机制,让 Agent 能优雅地处理各种异常情况。​

Action:​

分层错误处理:​

指数退避重试:​

​

代码块​

Plain Text

retry_delay = base_delay * (2 ^ attempt) + random_jitter​

base_delay = 1s, max_delay = 30s, max_attempts = 3​

​

Agent 级别的自愈:​

◦

工具调用失败时,Agent 会收到错误信息,由 LLM 决定下一步:​

▪

换一种方式调用工具(修改参数)。​

▪

尝试使用替代工具。​

▪

告知用户无法完成并解释原因。​

断点续传:​

◦

复杂任务的中间状态持久化到 Redis。​

◦

系统崩溃后可以从最近的检查点恢复执行。​

Result:​

•

因 API 超时导致的用户可见错误从 5% 降低到 0.3%。​

•

模型降级机制确保了 99.5% 的可用性。​

•

断点续传避免了复杂任务的重复执行,节省了约 15% 的 token 成本。​

​

​

Q17: 你的系统支持多租户吗?怎么实现的?​

Situation: 系统需要同时服务多个企业客户,每个客户有自己的知识库、配置和数据隔离要求。​

Task: 设计多租户架构,确保数据隔离、配置独立、性能互不影响。​

Action:​

数据隔离策略:​

◦

知识库隔离: 每个租户在 Milvus 中使用独立的 Collection(分区方案在数据量大时性能不好)。​

◦

对话数据隔离: 每个租户的对话记录存储在独立的数据库 schema 中。​

◦

缓存隔离: Redis 中使用 tenant_id: 作为 key 前缀。​

配置独立:​

◦

每个租户可以自定义:System Prompt、工具集合、模型选择、检索策略。​

◦

配置存储在数据库中,支持热更新(无需重启服务)。​

资源限制:​

◦

每个租户有独立的 QPS 限制和 token 配额。​

◦

使用 Redis 令牌桶算法实现限流。​

◦

超出配额时返回 429 Too Many Requests。​

Result:​

•

支持了 20+ 企业客户同时使用。​

•

零数据泄露事故(严格的 tenant_id 过滤)。​

•

单个客户的异常不会影响其他客户(资源隔离)。​

​

​

Q18: 你怎么看 Agent 架构的未来发展?​

Situation: AI Agent 技术发展迅速,架构范式在不断演进,需要对未来趋势有前瞻性判断。​

Task: 分析 Agent 架构的发展趋势,给出有见地的观点。​

Action:​

当前阶段的特点(2024-2025):​

◦

以 ReAct、Plan-and-Execute 为主的单 Agent 架构成熟。​

◦

多 Agent 协作开始落地但尚不成熟。​

◦

工具生态(MCP、Function Calling)快速发展。​

近期趋势(2025-2026):​

◦

Agent 工作流 + 自主决策的混合: 关键路径用确定性工作流,非关键路径让 Agent 自主决策。​

◦

长期记忆的突破: 从简单的向量存储到结构化的长期记忆系统。​

◦

多模态 Agent: 不仅处理文本,还能理解和生成图像、代码、数据分析。​

中期展望(2026-2028):​

◦

Agent-to-Agent 协议标准化: 类似 MCP 但面向 Agent 间通信。​

◦

自我进化的 Agent: Agent 能从历史执行经验中学习和优化。​

◦

端到端的 Agent 开发平台: 从开发、测试、部署到监控的全生命周期平台。​

我的核心观点:​

◦

Agent 的核心价值不是替代人,而是做信息和工具之间的桥梁。​

◦

确定性和灵活性的平衡是 Agent 架构的核心挑战。​

◦

可观测性和可控性是企业级 Agent 落地的关键。​

Result: 这些观点不仅是对技术趋势的判断,也指导了我们的技术选型和架构演进方向。​

​

​

第二类:技术实现类问题​

Q1: 向量数据库是怎么选型的?分块策略是什么?​

Situation: 企业知识库包含多种格式的文档(PDF、Word、HTML、Markdown),需要建立高效的向量检索系统。文档分块质量直接影响检索效果。​

Task: 选择合适的向量数据库并设计科学的文档分块策略。​

Action:​

向量数据库选型(详见架构类 Q6): 最终选择 Milvus。​

分块策略设计:​

◦

递归字符分块(默认策略):​

▪

分隔符优先级:\n\n → \n → 。 → , → 空格​

▪

chunk_size = 512 tokens,chunk_overlap = 50 tokens(约 10%)​

◦

语义分块(高质量场景):​

▪

先计算每个句子的 embedding。​

▪

相邻句子的余弦相似度低于阈值 0.7 时,视为语义断点。​

▪

在语义断点处切分,保证每个 chunk 语义完整。​

◦

结构化分块(特殊文档):​

分块元数据管理:​

◦

每个 chunk 存储元数据:文档ID、标题、章节路径、页码、分块位置。​

◦

检索时可利用元数据做过滤(如"只查某个文档的内容")。​

分块质量评估:​

◦

自建评估集,对比不同分块策略的检索命中率。​

◦

定期抽样检查分块质量,调整参数。​

Result:​

•

语义分块比固定长度分块的检索准确率提升 12%。​

•

结构化分块在技术文档场景下准确率提升 18%。​

•

分块参数经过 3 轮调优后趋于稳定。​

​

​

Q2: ReAct 的 Prompt 是怎么设计的?​

Situation: ReAct 模式的效果严重依赖 Prompt 设计质量。需要让 LLM 严格遵循 Thought → Action → Observation 的循环模式,同时保持灵活性。​

Task: 设计一套高效且鲁棒的 ReAct Prompt 模板。​

Action:​

Prompt 结构设计:​

​

代码块​

Plain Text

[System Prompt]​

你是一个企业级AI助手。请严格按照以下格式回答问题:​

​

Thought: 分析用户问题,决定下一步行动​

Action: 选择要调用的工具​

Action Input: 工具的输入参数(JSON格式)​

Observation: 工具返回的结果​

... (可以重复多次 Thought/Action/Observation)​

​

关键设计原则:​

◦

格式约束严格: 使用明确的关键词(Thought/Action/Observation/Final Answer)做解析锚点。​

◦

工具描述精确: 每个工具的描述包含"什么时候用"和"参数格式",减少错用。​

◦

安全兜底: 设置最大迭代次数,防止无限循环。​

◦

Few-shot 示例: 在 System Prompt 中提供 2-3 个高质量示例,覆盖单步和多步场景。​

Prompt 版本管理:​

◦

所有 Prompt 模板版本化管理(Git),每次修改有 changelog。​

◦

A/B 测试不同版本的 Prompt,基于评估指标选择最优版本。​

常见问题处理:​

◦

LLM 有时会跳过 Thought 直接给 Action → 在解析时检查并补充默认 Thought。​

◦

LLM 有时输出格式不标准 → 正则解析 + LLM 重新格式化兜底。​

Result:​

•

Prompt 遵循率从初始版本的 78% 提升到优化后的 96%。​

•

工具选择准确率 95%。​

•

经过 5 个版本迭代,形成了稳定的 Prompt 模板。​

​

​

Q3: 熔断器是怎么实现的?三个状态是什么?​

Situation: LLM API 和外部服务经常出现间歇性故障,如果持续重试会浪费资源并增加延迟。需要一个熔断机制来快速失败和自动恢复。​

Task: 实现 Circuit Breaker 模式,保护系统在下游服务异常时的稳定性。​

Action:​

三个核心状态:​

◦

CLOSED(闭合/正常): 请求正常通过,记录失败率。​

◦

OPEN(断开/熔断): 所有请求直接失败(返回降级响应),不再调用下游。​

◦

HALF_OPEN(半开/探测): 允许少量探测请求通过,检测下游是否恢复。​

状态转换规则:​

​

代码块​

Plain Text

CLOSED → OPEN:最近 60s 内失败率超过 50%(至少 10 次请求)​

OPEN → HALF_OPEN:熔断 30s 后自动进入半开状态​

HALF_OPEN → CLOSED:连续 3 次探测成功 → 恢复正常​

HALF_OPEN → OPEN:任何一次探测失败 → 重新熔断​

​

实现细节:​

class CircuitBreaker:def init(self, failure_threshold=0.5, recovery_timeout=30,min_requests=10, probe_success_threshold=3):self.state = State.CLOSEDself.failure_count = 0self.success_count = 0self.last_failure_time = Noneself.probe_success_count = 0self._window = deque(maxlen=100) # 滑动窗口async def call(self, func, *args, **kwargs):if self.state == State.OPEN:if time.time() - self.last_failure_time > self.recovery_timeout:self.state = State.HALF_OPENelse:raise CircuitOpenError("Circuit is open")​

try:result = await func(*args, **kwargs)self._on_success()return resultexcept Exception as e:self._on_failure()raise​

降级策略:​

◦

熔断时返回缓存的结果(如果有)。​

◦

切换到备用服务(如主模型熔断后切换到备用模型)。​

◦

返回兜底话术("系统繁忙,请稍后重试")。​

Result:​

•

下游服务故障时,系统响应时间从 30s(超时等待)降低到 100ms(快速失败)。​

•

自动恢复机制确保下游恢复后 30s 内自动恢复正常。​

•

级联故障发生率降低 90%。​

​

​

Q4: 记忆系统的短期和长期记忆是怎么配合的?​

Situation: Agent 需要在单次对话中维护上下文(短期记忆),同时在跨会话中记住用户偏好和历史交互(长期记忆)。​

Task: 设计分层记忆系统,实现短期和长期记忆的协同工作。​

Action:​

短期记忆(Working Memory):​

◦

存储位置:内存(进程内 + Redis 备份)。​

◦

内容:当前会话的对话历史、中间推理结果、工具调用结果。​

◦

管理策略:​

▪

滑动窗口:保留最近 10 轮完整对话。​

▪

超出窗口的对话自动摘要压缩。​

▪

会话结束后 30 分钟过期清理。​

长期记忆(Long-term Memory):​

◦

存储位置:PostgreSQL(结构化信息)+ Milvus(语义检索)。​

短期 → 长期记忆的转化:​

◦

会话结束时,LLM 自动提取本次对话的关键信息:​

▪

用户提到的新偏好。​

▪

解决的问题和方案。​

▪

未解决的问题。​

◦

提取结果写入长期记忆。​

长期 → 短期记忆的召回:​

◦

新会话开始时,根据用户 ID 加载用户画像。​

◦

根据当前话题,从长期记忆中检索相关历史信息。​

◦

将召回的信息注入到当前会话的 context 中。​

Result:​

•

跨会话上下文一致性从 30% 提升到 78%。​

•

用户偏好记忆准确率 85%(基于 200 个测试 case)。​

•

长期记忆占用控制在每用户 50MB 以内。​

​

​

Q5: 文档解析支持哪些格式?怎么处理表格和图片?​

Situation: 企业知识库中的文档格式多样,包括 PDF、Word、Excel、PPT、HTML、Markdown 等,且包含大量表格和图片。​

Task: 建立一套全格式文档解析管道,确保各类内容都能被有效提取和索引。​

Action:​

支持的文档格式和解析工具:​

​

#aGeTaTaTmzZu text { white-space: pre; }#aGeTaTaTmzZu .fb0 { stroke: var(--N900-FG, 0.15); }#aGeTaTaTmzZu .fb0 {stroke: rgba(31,35,41, 0.15)}#aGeTaTaTmzZu .fx0 { stroke-miterlimit: 10; }#aGeTaTaTmzZu .fx0 {stroke-miterlimit: 10}#aGeTaTaTmzZu .fa1 { fill: rgb(187, 191, 196); }#aGeTaTaTmzZu .fa1 {fill: rgb(187, 191, 196)}#aGeTaTaTmzZu .fx1 { font: 400 12px MonospacedNumber, LarkHackSafariFont, LarkEmojiFont, LarkChineseQuote, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Tahoma, "PingFang SC", "Microsoft Yahei", Arial, "Hiragino Sans GB", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; }#aGeTaTaTmzZu .fx1 {font-style: normal}#aGeTaTaTmzZu .fx2 { text-anchor: middle; }#aGeTaTaTmzZu .fx2 {text-anchor: middle}#aGeTaTaTmzZu .fx3 { dominant-baseline: central; }#aGeTaTaTmzZu .fx3 {dominant-baseline: central}#aGeTaTaTmzZu .fx4 { stroke: none; }#aGeTaTaTmzZu .fx4 {stroke: none}#aGeTaTaTmzZu .fc0 { fill: var(--text-caption); }#aGeTaTaTmzZu .fc0 {fill: #646a73}#aGeTaTaTmzZu .fa2 { fill: var(--text-link-disabled); }#aGeTaTaTmzZu .fa2 {fill: rgb(187, 191, 196)}#aGeTaTaTmzZu .fx5 { font: 400 13px MonospacedNumber, LarkHackSafariFont, LarkEmojiFont, LarkChineseQuote, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Tahoma, "PingFang SC", "Microsoft Yahei", Arial, "Hiragino Sans GB", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; }#aGeTaTaTmzZu .fx5 {font-style: normal}#aGeTaTaTmzZu .fx6 { text-anchor: start; }#aGeTaTaTmzZu .fx6 {text-anchor: start}#aGeTaTaTmzZu .fx7 { dominant-baseline: alphabetic; }#aGeTaTaTmzZu .fx7 {dominant-baseline: alphabetic}#aGeTaTaTmzZu .fc1 { fill: rgb(0, 0, 0); }#aGeTaTaTmzZu .fc1 {fill: rgb(0, 0, 0)}#aGeTaTaTmzZu .fb1 { fill: var(--N900-FG, 0.15); }#aGeTaTaTmzZu .fb1 {fill: rgba(31,35,41, 0.15)}#aGeTaTaTmzZu .fb2 { fill: rgb(209, 217, 224); }#aGeTaTaTmzZu .fb2 {fill: rgb(209, 217, 224)}#aGeTaTaTmzZu .fa3 { fill: var(--bg-body); }#aGeTaTaTmzZu .fa3 {fill: #fff}ABC1234567格式PDFWordExcelPPTHTMLMarkdown解析工具PyMuPDF + pdfplumberpython-docxopenpyxlpython-pptxBeautifulSoupmarkdown-it特殊处理版面分析区分正文/表格/图片保留标题层级结构每个 sheet 独立处理幻灯片逐页提取文本清洗标签,保留结构保留标题层级

​

表格处理策略:​

◦

简单表格(< 10行10列): 转为 Markdown 表格格式,整表作为一个 chunk。​

◦

复杂表格(大型数据表): 转为结构化描述文本("表格共 X 行 Y 列,列名分别是..."),并生成自然语言摘要。​

图片处理策略:​

◦

OCR 提取: 使用 PaddleOCR 提取图片中的文字。​

◦

图片描述: 对非文字图片(流程图、架构图等),使用多模态模型(GPT-4V)生成图片描述。​

◦

图片索引: 图片描述文本作为 chunk 索引到向量库,同时保存图片 URL 用于溯源展示。​

解析质量保证:​

◦

建立解析质量评估集(100 份文档的标准解析结果)。​

◦

每次更新解析逻辑后,自动跑评估集对比。​

◦

人工抽检:每周随机抽查 20 份文档的解析结果。​

Result:​

•

支持 6 种主流文档格式,覆盖 98% 的企业文档。​

•

表格信息提取准确率 91%(基于 500 个表格的评估)。​

•

图片 OCR 识别准确率 94%。​

​

​

Q6: 重排序是怎么做的?用的什么模型?​

Situation: 多路检索后得到大量候选 chunk(通常 30-60 个),需要精排后选出最相关的 top-5 给 LLM 生成答案。粗排的向量相似度和 BM25 分数不够精确。​

Task: 实现高质量的重排序(Reranking)模块,提升最终检索精度。​

Action:​

Reranker 模型选择:​

◦

对比了三个主流 reranker:​

▪

BGE-Reranker-v2-M3(最终选择): 支持中英文,精度高,模型大小适中(568MB)。​

▪

Cohere Rerank: 效果好但需要调 API,增加延迟和成本。​

▪

Cross-encoder/ms-marco-MiniLM-L-12-v2: 英文效果好,中文不行。​

重排序流程:​

​

代码块​

Plain Text

​

性能优化:​

◦

Reranker 模型部署在 GPU 服务器上(T4 显卡),batch 推理。​

◦

40 条候选的 rerank 耗时约 120ms(batch_size=40, GPU)。​

◦

对于实时性要求极高的场景,可跳过 rerank 直接取 top-5。​

分数阈值策略:​

◦

rerank_score ≥ 0.7 → 高相关,直接使用。​

◦

0.4 ≤ rerank_score < 0.7 → 中等相关,作为补充信息。​

◦

rerank_score < 0.4 → 低相关,丢弃。​

◦

如果所有 chunk 分数 < 0.4 → 触发"知识库中没有找到相关信息"的回复。​

Result:​

•

重排序后 Precision@5 从 78% 提升到 92%。​

•

NDCG@5 从 0.72 提升到 0.89。​

•

Rerank 延迟 120ms,在整体 3s 响应时间中占比可接受。​

​

​

Q7: Function Calling 和 MCP 有什么区别?你怎么选的?​

Situation: 系统需要让 Agent 调用外部工具。Function Calling(OpenAI 原生支持)和 MCP(Anthropic 提出的开放协议)是两种主流方案。​

Task: 理解两者的差异,选择适合项目的方案或混合使用。​

Action:​

Function Calling 特点:​

◦

定义在模型侧: 工具定义作为 API 请求的一部分发送给模型。​

◦

模型原生支持: GPT-4、Claude 等都内置支持,工具选择由模型完成。​

◦

简单直接: 适合快速接入少量工具。​

◦

耦合模型: 不同模型的 Function Calling 格式有差异。​

MCP 特点:​

◦

独立于模型: 工具通过 MCP Server 独立运行,通过标准协议通信。​

◦

生态复用: 一个 MCP Server 可以被任何 MCP Client 使用。​

◦

双向通信: 支持服务端推送通知和进度更新。​

◦

资源抽象: 除了工具(tools),还有资源(resources)和提示(prompts)原语。​

◦

权限控制: 协议层面支持能力协商和权限控制。​

对比表:​

​

​

项目选择 —— 混合方案:​

◦

内部简单工具(如数据库查询、文本处理): 使用 Function Calling,因为实现简单,无需额外部署。​

◦

外部复杂服务(如第三方 API、需要独立运行的工具): 封装为 MCP Server。​

◦

底层统一: 在编排器层面做了统一抽象,业务代码不感知具体是 FC 还是 MCP。​

Result:​

•

Function Calling 覆盖了 70% 的工具调用场景(简单高效)。​

•

MCP 覆盖了 30% 的复杂工具场景(标准化、可复用)。​

•

统一抽象层使得切换方案对业务代码零影响。​

​

​

Q8: 会话摘要压缩的阈值是多少?怎么确定的?​

Situation: 长对话会导致 context window 超限,需要对历史对话做摘要压缩。但压缩太早会丢失信息,压缩太晚会超出 token 限制。​

Task: 确定最优的摘要压缩阈值和策略。​

Action:​

阈值设定:​

◦

触发阈值: 当对话历史占用超过 context window 的 40% 时触发压缩。​

◦

以 8K context 为例:对话历史超过 3200 tokens 时开始压缩。​

◦

保留窗口: 最近 3 轮对话始终保留原文,不压缩。​

阈值确定过程:​

◦

实验了三个阈值:30%、40%、50%。​

◦

30%:压缩太频繁,信息损失明显,回答质量下降 8%。​

◦

40%:平衡点,信息保留度和 token 效率最优。​

◦

50%:在长对话(>15 轮)时 context 容易超限。​

摘要策略:​

​

代码块​

Plain Text

Prompt: 请将以下对话历史压缩为简洁的摘要,保留以下关键信息:​

1. 用户的核心诉求​

​

增量摘要(渐进式压缩):​

◦

不是一次性压缩所有历史,而是每次只压缩最旧的 3-5 轮。​

◦

新的摘要与旧的摘要合并,形成递进式摘要。​

◦

避免单次压缩大量内容导致的信息损失。​

Result:​

•

40% 阈值下,支持最长 50 轮对话不丢失关键上下文。​

•

摘要后的对话理解准确率为 91%(对比完整历史的 96%)。​

•

Token 节省约 60%(长对话场景)。​

​

​

Q9: RRF 融合排序的公式是什么?权重怎么调?​

Situation: 多路检索(向量 + 关键词 + 知识图谱)各自返回排序结果,需要融合成统一的排序。​

Task: 实现一个公平、有效的多路结果融合算法。​

Action:​

RRF(Reciprocal Rank Fusion)公式:​

​

代码块​

Plain Text

RRF_score(d) = Σ(i=1 to n) 1 / (k + rank_i(d))​

◦

d:文档​

◦

n:检索通道数量​

◦

rank_i(d):文档 d 在第 i 个通道中的排名(从 1 开始)​

◦

k:平滑常数(默认 60)​

​

为什么用 RRF 而不是加权分数融合?​

加权 RRF(Weighted RRF):​

​

代码块​

Plain Text

WRRF_score(d) = Σ(i=1 to n) w_i / (k + rank_i(d))​

◦

不同通道可以设置权重 w_i,反映不同通道的置信度。​

◦

默认权重:向量 0.6、关键词 0.3、知识图谱 0.1。​

​

权重调优方法:​

◦

建立标注评估集(500 条 query + 标准答案)。​

◦

使用网格搜索遍历权重组合:​

▪

向量:[0.4, 0.5, 0.6, 0.7]​

k 值调优:​

◦

k 越大,排名差异的影响越小(倾向于平均化)。​

◦

k 越小,高排名文档的优势越明显。​

◦

实验发现 k=60 是较优选择(经典值,Microsoft 论文推荐)。​

Result:​

•

加权 RRF 比等权 RRF 的 NDCG@5 提升 3.2%。​

•

最优权重组合:向量 0.6、关键词 0.3、知识图谱 0.1。​

•

比纯向量检索的 Precision@5 提升 17%。​

​

​

Q10: 嵌入模型用的什么?维度多少?怎么选的?​

Situation: 嵌入模型的选择直接影响向量检索质量。需要在效果、速度、成本之间找到平衡。​

Task: 选择最适合中文企业场景的嵌入模型。​

Action:​

候选模型对比:​

​

​

评估维度:​

最终选择 —— BGE-M3:​

◦

中文检索 Recall@10 最高(94.3%)。​

◦

原生支持中英日韩多语言和跨语言检索。​

◦

支持稠密向量(dense)、稀疏向量(sparse)、多向量(ColBERT)三种表示。​

◦

1024 维在效果和效率间取得平衡。​

◦

可以本地部署,无数据出境风险。​

部署方案:​

◦

使用 ONNX Runtime 加速推理。​

◦

GPU 部署(T4):单条 embedding 延迟 15ms,batch 1000 条约 3s。​

◦

预计算 + 增量更新:新文档入库时实时计算 embedding。​

Result:​

•

中文检索 Recall@10 达到 94.3%,比 text-embedding-3-large 高 2.1%。​

•

嵌入维度 1024,单条向量占 4KB,800 万文档的索引大小约 32GB。​

•

本地部署避免了 API 调用成本和延迟。​

​

​

Q11: Guardrails(护栏)是怎么实现的?​

Situation: Agent 的输出需要多维度的质量和安全把控:格式合规、内容安全、事实准确性、业务合规等。​

Task: 实现一套可扩展的 Guardrails 框架,确保 Agent 输出的质量和安全。​

Action:​

Guardrails 架构(输入侧 + 输出侧):​

​

代码块​

Plain Text

用户输入 → [输入 Guardrails] → Agent 处理 → [输出 Guardrails] → 最终响应​

​

输入侧 Guardrails:​

◦

Prompt 注入检测: 基于规则 + 分类器检测注入攻击(详见架构类 Q14)。​

◦

敏感信息检测: 正则匹配身份证号、手机号等 PII。​

◦

长度限制: 单次输入 ≤ 2000 字符。​

◦

话题过滤: 拒绝与业务无关的话题(如政治、暴力等)。​

输出侧 Guardrails:​

◦

格式检查: 检查输出是否符合预期格式(JSON Schema 验证等)。​

◦

内容安全: 调用内容审核 API 过滤违规内容。​

◦

事实核查: 检查输出中引用的事实是否与检索到的 chunk 一致。​

◦

幻觉检测: 对比输出和 context,标记可能的幻觉内容。​

可扩展设计:​

class BaseGuardrail(ABC):@abstractmethodasync def check(self, content: str, context: dict) -> GuardrailResult: ...​

​

class GuardrailPipeline:def init(self, guardrails: List[BaseGuardrail]):self.guardrails = guardrailsasync def run(self, content, context):for guardrail in self.guardrails:result = await guardrail.check(content, context)if not result.passed:return result # 快速失败return GuardrailResult(passed=True)​

Result:​

•

Prompt 注入拦截率 97%。​

•

输出内容安全合规率 99.8%。​

•

幻觉检测覆盖率 85%(仍有改进空间)。​

​

​

Q12: 怎么实现的 Streaming 流式输出?​

Situation: LLM 生成完整回答通常需要 3-10 秒,如果等完全生成后才返回,用户体验很差。需要实现逐 token 的流式输出。​

Task: 实现端到端的流式输出管道,从 LLM 到前端的全链路流式传输。​

Action:​

整体架构:​

​

代码块​

Plain Text

LLM API (SSE) → Backend (异步生成器) → API Gateway (SSE/WebSocket) → Frontend (EventSource)​

​

后端实现(Python FastAPI):​

@app.post("/chat/stream")async def chat_stream(request: ChatRequest):async def generate():async for chunk in agent.stream_chat(request.messages):data = json.dumps({"content": chunk, "type": "token"})yield f"data: {data}\n\n"yield f"data: {json.dumps({'type': 'done'})}\n\n"return StreamingResponse(generate(),media_type="text/event-stream",headers={"Cache-Control": "no-cache", "X-Accel-Buffering": "no"}​

)​

关键技术点:​

◦

禁用缓冲: Nginx 设置 X-Accel-Buffering: no,防止代理层缓冲 SSE。​

◦

心跳保活: 每 15 秒发送一个心跳事件,防止连接超时。​

◦

错误处理: 流式过程中出错时发送 error 事件,前端展示错误信息。​

◦

取消机制: 用户关闭页面时,后端检测到连接断开,取消 LLM API 调用。​

ReAct 模式下的流式处理:​

◦

Thought 阶段:不输出给用户(内部推理过程)。​

◦

Action 阶段:输出 "正在查询..." 等状态提示。​

◦

Final Answer 阶段:逐 token 流式输出给用户。​

◦

通过解析 token 流,区分不同阶段。​

Result:​

•

首 token 延迟(TTFT)从非流式的 3s 降低到 500ms。​

•

用户感知的响应速度提升 5x。​

•

流式连接稳定性 99.9%(心跳保活 + 自动重连)。​

​

​

Q13: 怎么做的日志和链路追踪?​

Situation: Agent 系统的执行链路复杂(用户输入 → 意图识别 → 检索 → 工具调用 → 生成),需要完整的可观测性来排查问题。​

Task: 建立全链路的日志和追踪系统。​

Action:​

日志分级体系:​

结构化日志格式:​

{"trace_id": "abc-123","span_id": "span-456","timestamp": "2024-03-15T10:30:00Z","service": "agent-orchestrator","event": "tool_call","tool_name": "search_knowledge","latency_ms": 245,"status": "success","metadata": {"query": "...", "result_count": 5}​

}​

链路追踪(基于 OpenTelemetry):​

◦

每个请求分配唯一 trace_id。​

◦

Agent 执行的每个阶段创建独立的 span:​

​

代码块​

Plain Text

​

可视化和告警:​

◦

日志收集:Fluentd → Elasticsearch → Kibana。​

◦

链路追踪可视化:Jaeger。​

◦

告警规则:P99 延迟 > 10s、错误率 > 1%、LLM 幻觉率 > 5% 时触发告警。​

Result:​

•

问题定位时间从平均 2 小时缩短到 15 分钟。​

•

全链路 trace 覆盖率 100%。​

•

通过日志分析发现并优化了 3 个性能瓶颈。​

​

​

Q14: 怎么做的异步并行处理?​

Situation: Agent 执行过程中有很多 I/O 密集型操作(LLM API 调用、数据库查询、外部 API 调用),同步执行会导致大量等待时间。​

Task: 识别可并行化的操作,用异步编程提升系统吞吐量。​

Action:​

异步框架选择:​

◦

基于 Python asyncio + FastAPI。​

◦

所有 I/O 操作使用 async/await。​

◦

使用 httpx.AsyncClient 替代 requests 做 HTTP 调用。​

并行化场景:​

◦

多路检索并行: 向量检索、关键词检索、知识图谱查询同时发起。​

并发控制:​

◦

使用 asyncio.Semaphore 控制最大并发数。​

◦

LLM API 调用并发限制为 50(受 API 限流限制)。​

◦

数据库连接池大小 20(避免打爆数据库)。​

异步队列处理:​

◦

非实时任务(如文档索引、日志分析)通过 Celery 异步任务队列处理。​

◦

避免阻塞实时请求的处理。​

Result:​

•

多路检索并行后,检索总延迟从 500ms(串行)降低到 200ms(并行)。​

•

系统整体 QPS 提升 2.5 倍。​

•

文档批量入库速度提升 4 倍。​

​

​

Q15: 知识图谱是怎么构建和使用的?​

Situation: 纯向量检索难以处理实体关系类查询(如"张三负责哪些项目"、"A 产品和 B 产品有什么关联"),需要知识图谱补充。​

Task: 构建领域知识图谱,并与向量检索系统协同工作。​

Action:​

知识图谱构建流程:​

◦

实体抽取: 使用 LLM 从文档中抽取实体(人名、产品、部门、项目等)。​

◦

关系抽取: 使用 LLM 识别实体间关系(负责、属于、依赖等)。​

◦

Schema 设计:​

​

代码块​

Plain Text

​

自动化构建管道:​

​

代码块​

Plain Text

文档 → 分段 → LLM 实体抽取 → LLM 关系抽取 → 去重合并 → 写入 Neo4j​

◦

使用 Prompt 模板约束输出格式。​

◦

人工审核:抽取结果的置信度 < 0.8 时进入审核队列。​

​

查询集成:​

◦

意图识别模块判断是否需要图谱查询。​

◦

生成 Cypher 查询语句:​

◦

MATCH (p:Person)-[:MANAGES]->(proj:Project)​

WHERE p.name = '张三'RETURN proj.name, proj.status​

Result:​

•

知识图谱包含 5 万个实体、12 万条关系。​

•

实体关系类查询的准确率从纯向量检索的 45% 提升到 87%。​

•

知识图谱月均查询量约 2000 次。​

​

​

Q16: 怎么做的 A/B 测试和 Prompt 版本管理?​

Situation: Prompt 的微小改动可能导致输出质量的显著变化,需要科学的方法来管理和评估 Prompt 变更。​

Task: 建立 Prompt 版本管理和 A/B 测试机制。​

Action:​

版本管理:​

◦

所有 Prompt 模板存储在数据库中(不硬编码)。​

◦

每个模板有版本号、创建时间、变更说明。​

◦

支持按百分比灰度发布(如新版本只对 10% 的流量生效)。​

A/B 测试框架:​

◦

请求进来时,根据用户 ID hash 分配实验组。​

◦

同时记录两个版本的回答和用户反馈。​

◦

每个实验持续 7 天或累计 1000 次对话后出结论。​

评估指标:​

◦

自动化指标: 回答相关性(BERTScore)、格式遵循率、工具调用准确率。​

◦

人工评估: 随机抽取 100 条对话,3 位评估者打分(1-5 分)。​

◦

业务指标: 用户满意度评分、问题解决率、平均对话轮次。​

决策标准:​

◦

新版本在所有指标上至少不低于旧版本。​

◦

核心指标(回答相关性)提升 ≥ 2%,才接受新版本。​

Result:​

•

通过 A/B 测试发现了 3 个看似改进实际退步的 Prompt 修改。​

•

Prompt 迭代周期从"凭感觉改"变为"数据驱动改"。​

•

系统回答质量在 6 个月内稳步提升 18%。​

​

​

Q17: Token 计数和费用统计是怎么实现的?​

Situation: LLM API 按 token 计费,需要精确统计每次调用的 token 消耗,用于成本控制和计费。​

Task: 实现精确的 token 计数和费用统计系统。​

Action:​

Token 计数方案:​

◦

输入 Token: 使用对应模型的 tokenizer 在客户端预计算。​

▪

OpenAI:使用 tiktoken 库。​

费用计算:​

cost = (input_tokens * input_price + output_tokens * output_price) / 1000# GPT-4o: input $2.5/1M, output $10/1M# GPT-4o-mini: input $0.15/1M, output $0.6/1M​

统计维度:​

◦

按租户统计:每个客户的 token 消耗和费用。​

◦

按功能统计:意图识别、RAG 生成、摘要等各模块的消耗。​

◦

按模型统计:不同模型的使用量和费用占比。​

◦

按时间统计:日/周/月的消耗趋势。​

预算告警:​

◦

每个租户设置月度 token 预算。​

◦

消耗达到 80% 时提醒,100% 时限制(或降级到小模型)。​

Result:​

•

Token 计数误差控制在 2% 以内。​

•

月度成本报告自动生成,精确到每个功能模块。​

•

通过分析发现"会话摘要"模块是 token 消耗大户(占 25%),优化后降低了 40%。​

​

​

Q18: 怎么做的数据预处理和数据清洗?​

Situation: 企业文档质量参差不齐:有 OCR 错误、格式混乱、重复内容、过时信息等。低质量数据直接影响检索和生成质量。​

Task: 建立数据预处理管道,确保入库数据的质量。​

Action:​

数据清洗管道:​

​

代码块​

Plain Text

​

清洗规则:​

◦

去除噪音: 页眉页脚、水印文字、无意义空白。​

◦

格式标准化: 统一编码(UTF-8)、统一标点(全角/半角)。​

◦

OCR 纠错: 基于语言模型的拼写纠错(如"己术"→"技术")。​

◦

敏感信息脱敏: 手机号、身份证号等自动打码。​

去重策略:​

◦

完全重复: MD5 hash 去重。​

◦

近似重复: MinHash + LSH 算法,Jaccard 相似度 > 0.85 视为重复。​

◦

跨版本去重: 同一文档的不同版本,只保留最新版本。​

质量评估打分:​

◦

文本长度(太短的 chunk 信息量不足)。​

◦

语义完整性(句子是否完整)。​

◦

信息密度(关键词密度、实体密度)。​

◦

分数低于阈值的 chunk 标记为低质量,不参与检索。​

Result:​

•

数据清洗后,检索准确率提升 8%。​

•

去重减少了 15% 的存储空间。​

•

低质量 chunk 过滤后,LLM 生成的幻觉率降低 12%。​

​

​

第三类:性能优化类问题​

Q1: Token 成本是怎么控制的?​

Situation: 系统月均 token 消耗超过 5000 万,API 费用是运营成本的主要组成部分。​

Task: 在不影响回答质量的前提下,大幅降低 token 成本。​

Action:​

模型路由优化(最大收益):​

◦

60% 简单查询路由到 GPT-4o-mini(成本仅为 GPT-4o 的 1/17)。​

Prompt 精简:​

◦

System Prompt 从 1500 tokens 精简到 800 tokens(去除冗余描述)。​

◦

工具描述只在需要时动态注入,不是每次都带全部工具。​

◦

节省 20% 的输入 token。​

上下文优化:​

◦

检索结果从 top-10 减到 top-5(经过 rerank 后 top-5 已足够)。​

◦

对话历史及时摘要压缩。​

◦

减少 30% 的 context token。​

缓存策略:​

◦

语义缓存:相似问题命中缓存直接返回,跳过 LLM 调用。​

◦

FAQ 缓存:高频问题预计算答案。​

输出控制:​

◦

设置 max_tokens 限制(一般回答 512,详细回答 1024)。​

◦

避免 LLM 生成冗长的无用内容。​

Result:​

•

月均 token 成本从 5 万降到 1.9 万(降低 62%)。​

•

回答质量几乎无损(用户满意度仅下降 1.2%)。​

•

建立了 token 预算管理和告警机制。​

​

​

Q2: 延迟优化做了哪些措施?​

Situation: 系统初期端到端延迟(用户提问到收到回答)平均 6.5 秒,用户体验不佳,目标是降低到 3 秒以内。​

Task: 全链路延迟优化,将 P50 延迟降到 3 秒以内。​

Action:​

链路分析(各环节耗时):​

​

代码块​

Plain Text

意图识别:300ms​

检索(串行):500ms → 并行后 200ms​

Reranking:130ms​

LLM 生成(主要瓶颈):4500ms → 优化后 2500ms​

后处理:100ms​

总计:5530ms → 3130ms​

​

优化措施:​

◦

检索并行化: 多路检索从串行改为并行(-300ms)。​

◦

模型路由: 简单查询走快速模型(延迟 800ms vs 3000ms)。​

◦

流式输出: TTFT 500ms,用户感知到的等待时间大幅缩短。​

◦

预加载: 意图识别和检索并行执行(检索不需要等意图确定后再开始,可以先用原始 query 检索)。​

LLM 调用优化:​

◦

Prompt 精简减少输入 token,LLM 处理时间缩短。​

◦

使用 max_tokens 限制输出长度。​

◦

选择低延迟的 API 端点(如 Azure 中国区)。​

Result:​

•

P50 延迟从 6.5s 降低到 2.8s。​

•

P99 延迟从 15s 降低到 5.2s。​

•

流式输出的 TTFT 为 500ms,用户满意度提升 22%。​

​

​

Q3: 缓存策略是什么?命中率多少?​

Situation: 企业客服场景存在大量重复和相似的问题,每次都调用 LLM 浪费资源。​

Task: 设计多层缓存策略,提升系统响应速度并降低成本。​

Action:​

多层缓存架构:​

◦

L1 —— 精确匹配缓存(Redis):​

▪

Key:query 文本的 MD5 hash。​

▪

适用场景:完全相同的问题。​

▪

TTL:24 小时。​

▪

命中率:约 8%。​

◦

L2 —— 语义相似缓存(Redis + Milvus):​

▪

对 query 计算 embedding,在缓存向量库中检索。​

▪

相似度 > 0.95 时视为命中,直接返回缓存的回答。​

▪

TTL:12 小时。​

▪

命中率:约 7%。​

缓存更新策略:​

◦

被动失效: TTL 过期自动失效。​

◦

主动失效: 知识库更新时,清除相关问题的缓存。​

◦

预热策略: 系统启动时预加载 FAQ 缓存和高频问题缓存。​

缓存一致性:​

◦

知识库文档更新时,触发缓存清理事件。​

◦

使用事件总线通知缓存模块刷新。​

Result:​

•

总缓存命中率约 20%(L1 8% + L2 7% + L3 5%)。​

•

缓存命中时延迟 < 100ms(对比 LLM 调用的 3s)。​

•

节省约 20% 的 LLM API 调用成本。​

​

​

Q4: 流式输出是怎么实现的?​

(详见技术实现类 Q12,此处补充性能优化视角)​

Situation: 非流式模式下,用户需要等待 LLM 完全生成后才能看到回答,感知延迟长。​

Task: 实现全链路流式输出,优化用户感知延迟。​

Action:​

TTFT(Time To First Token)优化:​

◦

目标:TTFT < 500ms。​

◦

意图识别 + 检索在 LLM 开始生成前完成。​

◦

LLM 的第一个 token 通常在 200-500ms 内返回。​

TBT(Time Between Tokens)优化:​

◦

选择输出速度快的模型(GPT-4o-mini 的 TBT 约 10ms/token)。​

流式中的工具调用处理:​

◦

检测到 Action 开始时,发送状态消息"正在查询..."。​

◦

工具执行完成后,继续流式输出 Final Answer。​

◦

前端展示 loading 动画和工具调用状态。​

Result:​

•

TTFT P50 = 450ms,P99 = 800ms。​

•

用户感知的响应速度提升 5x。​

•

用户满意度提升 22%。​

​

​

Q5: 异步处理在哪些地方使用了?​

(详见技术实现类 Q14,此处补充更多场景)​

Situation: 系统中大量 I/O 密集型操作,同步处理会严重限制吞吐量。​

Task: 全面采用异步编程,提升系统并发处理能力。​

Action:​

实时路径(async/await):​

◦

LLM API 调用​

◦

向量数据库检索​

◦

Elasticsearch 查询​

◦

用户请求处理(FastAPI 全异步)​

准实时路径(异步任务队列):​

◦

对话记录入库​

◦

用户行为日志写入​

◦

实时告警推送​

离线路径(Celery 任务队列):​

◦

文档解析和索引构建​

◦

知识图谱更新​

并行编排:​

async def process_query(query):intent_task = asyncio.create_task(identify_intent(query))retrieval_task = asyncio.create_task(retrieve_documents(query))intent, docs = await asyncio.gather(intent_task, retrieval_task)return await generate_answer(intent, docs, query)​

Result:​

•

系统 QPS 从 30 提升到 85(2.8 倍)。​

•

文档索引速度提升 4 倍。​

•

内存使用率更平稳(避免了同步阻塞导致的内存堆积)。​

​

​

Q6: 数据库查询是怎么优化的?​

Situation: 随着数据量增长,部分数据库查询变慢,影响 Agent 工具调用的响应速度。​

Task: 优化数据库查询性能,确保工具调用延迟在可接受范围内。​

Action:​

向量数据库(Milvus)优化:​

◦

索引选择:数据量 < 100 万用 HNSW(延迟低),> 100 万用 IVF_SQ8(内存占用小)。​

◦

HNSW 参数调优:M=16, efConstruction=200, ef=128。​

◦

Collection 按租户分,避免跨租户查询。​

关系型数据库(PostgreSQL)优化:​

◦

为高频查询添加组合索引。​

◦

使用 EXPLAIN ANALYZE 分析慢查询。​

◦

对话历史表按月分区(partition)。​

◦

连接池配置:min=5, max=20, max_idle=300s。​

Redis 优化:​

◦

数据结构选择:缓存用 String,会话状态用 Hash,排行用 Sorted Set。​

◦

Key 设计规范:{service}:{tenant}:{type}:{id}。​

查询模式优化:​

◦

避免 N+1 查询(批量查询替代循环查询)。​

◦

使用预编译语句(PreparedStatement),减少 SQL 解析开销。​

◦

只查询需要的字段,避免 SELECT *。​

Result:​

•

向量检索 P99 延迟稳定在 50ms 以内。​

•

SQL 慢查询数量从日均 200 降到 5。​

•

Redis 缓存命中率 95%,读延迟 < 1ms。​

​

​

Q7: 模型推理速度是怎么优化的?​

Situation: 本地部署的模型(用于 embedding、reranking 等)推理速度需要优化。​

Task: 提升本地模型的推理速度,降低延迟。​

Action:​

模型量化:​

◦

Embedding 模型(BGE-M3)使用 INT8 量化。​

◦

精度损失 < 0.5%,推理速度提升 40%。​

推理引擎优化:​

◦

使用 ONNX Runtime 替代 PyTorch 推理(速度提升 30%)。​

◦

启用 CUDA 加速和 TensorRT 优化。​

批处理(Batching):​

◦

Embedding 计算支持批量输入(batch_size=64)。​

◦

Reranking 支持批量推理(一次性对 40 个候选打分)。​

◦

使用动态批处理(Dynamic Batching):收集短时间内的请求合并处理。​

模型预加载:​

◦

服务启动时预加载模型到 GPU 显存。​

◦

避免首次请求的冷启动延迟。​

Result:​

•

Embedding 计算延迟:单条 15ms → 批量 1000 条 3s(均摊 3ms/条)。​

•

Reranking 延迟:40 条候选 120ms(batch 推理)。​

•

GPU 利用率从 30% 提升到 75%。​

​

​

Q8: 前端渲染性能怎么优化?​

Situation: 前端在展示流式输出和长对话时存在性能问题:频繁 DOM 更新导致卡顿、长对话列表滚动不流畅。​

Task: 优化前端渲染性能,确保流畅的用户体验。​

Action:​

流式输出渲染优化:​

◦

Token 缓冲:不是每收到一个 token 就更新 DOM,而是累积 50ms 的 token 后批量更新。​

◦

使用 requestAnimationFrame 控制更新频率。​

长对话列表优化:​

◦

虚拟滚动:只渲染可视区域内的消息气泡。​

◦

分页加载:历史消息按需加载,不一次性渲染。​

内存管理:​

◦

及时清理 EventSource 连接。​

◦

使用 WeakRef 管理消息对象引用。​

Result:​

•

流式输出时 FPS 从 30 提升到 60(无卡顿)。​

•

100+ 轮对话列表滚动流畅。​

•

页面内存占用降低 40%。​

​

​

Q9: 冷启动问题是怎么解决的?​

Situation: 系统重启或新实例扩容时存在冷启动问题:模型加载慢、缓存为空、连接池未预热。​

Task: 减少冷启动对用户的影响。​

Action:​

模型预加载:​

◦

使用 Kubernetes 的 readinessProbe,模型加载完成后才接收流量。​

◦

模型文件使用共享存储(NFS/OSS),避免每次从网络下载。​

◦

预加载时间:约 30s(embedding 模型 + reranker 模型)。​

缓存预热:​

◦

服务启动时自动加载 FAQ 缓存和热门问题缓存。​

◦

从其他健康实例同步缓存数据(peer 预热)。​

◦

预热完成前使用降级策略(跳过缓存直接查询)。​

连接池预建:​

◦

服务启动时立即创建最小数量的数据库连接。​

◦

Redis 连接预建并做 PING 检查。​

流量预热:​

Result:​

•

冷启动时间从 120s 降低到 45s。​

•

冷启动期间的请求成功率从 70% 提升到 98%。​

•

缓存预热后命中率快速回升到正常水平。​

​

​

Q10: 网络传输是怎么优化的?​

Situation: LLM API 通常部署在远端(如美西),网络延迟和带宽限制影响系统性能。​

Task: 优化网络传输环节的延迟和稳定性。​

Action:​

API 端点选择:​

◦

使用 Azure OpenAI 中国区/亚太区端点,减少跨洋延迟。​

◦

跨区域延迟从 200ms(美西)降到 40ms(亚太)。​

连接优化:​

◦

HTTP/2 多路复用,减少连接建立开销。​

◦

连接池复用,避免频繁 TLS 握手。​

◦

Keep-Alive 超时设置 120s。​

数据压缩:​

◦

请求/响应启用 gzip 压缩。​

◦

Prompt 中去除不必要的空格和换行,减少传输体积。​

多线路容灾:​

◦

配置多个 API 端点(主备)。​

◦

主端点超时 3s 后自动切换到备用端点。​

Result:​

•

API 网络延迟从 200ms 降到 40ms。​

•

网络相关的超时错误降低 80%。​

•

多线路容灾确保 99.9% 的可用性。​

​

​

Q11: Embedding 计算是怎么优化的?​

Situation: 知识库初始化需要对大量文档计算 embedding(800 万个 chunk),耗时过长。日常增量更新也需要高效的 embedding 计算。​

Task: 优化 embedding 计算的吞吐量和效率。​

Action:​

批量计算优化:​

◦

batch_size=256,GPU 利用率最大化。​

◦

使用 DataLoader 预加载数据,避免 GPU 等待 CPU 数据处理。​

增量更新策略:​

◦

文档变更检测:对比 MD5 hash,只对变更的文档重新计算 embedding。​

◦

新增文档实时计算并入库,不需要全量重建。​

多 GPU 并行:​

◦

使用 DataParallel 在多张 GPU 上并行计算。​

◦

4 张 T4 GPU 并行,吞吐量提升 3.6 倍。​

维度压缩(可选):​

◦

对于存储和检索速度敏感的场景,使用 PCA 将 1024 维降到 512 维。​

◦

召回率仅下降 1.2%,存储减少 50%。​

Result:​

•

800 万 chunk 的全量 embedding 计算:从 48 小时降到 12 小时。​

•

日常增量更新:1000 条新文档的 embedding 计算 < 30s。​

•

GPU 利用率稳定在 80%+。​

​

​

Q12: 怎么做的资源监控和自动扩缩容?​

Situation: 系统负载随业务高峰期波动很大(如促销期间请求量暴增 5 倍),固定资源配置要么浪费要么不足。​

Task: 实现基于业务指标的自动扩缩容。​

Action:​

监控指标:​

◦

基础指标: CPU、内存、网络 I/O。​

◦

业务指标: QPS、P99 延迟、错误率、LLM API 并发数。​

◦

自定义指标: 队列积压数、缓存命中率。​

HPA(水平 Pod 自动扩缩容):​

apiVersion: autoscaling/v2kind: HorizontalPodAutoscalerspec:minReplicas: 2maxReplicas: 10metrics:​

- type: Podspods:metric:name: requests_per_secondtarget:type: AverageValueaverageValue: "50"​

◦

QPS > 50/Pod 时扩容。​

◦

QPS < 20/Pod 持续 5 分钟时缩容。​

预测性扩容:​

◦

基于历史数据预测高峰时段,提前扩容。​

◦

促销等已知高峰事件手动预扩容。​

Result:​

•

高峰期自动扩容到 8 个 Pod,低谷期缩容到 2 个 Pod。​

•

资源成本降低 35%(对比固定 8 Pod 配置)。​

•

高峰期 P99 延迟始终保持 < 5s。​

​

​

第四类:故障处理类问题​

Q1: Agent 死循环怎么检测和防止的?​

Situation: ReAct 模式下,Agent 可能陷入"思考-行动-观察"的无限循环。例如检索结果不满意时反复重新检索,或反复调用同一工具但参数不变。​

Task: 设计检测和防止 Agent 死循环的机制。​

Action:​

硬性限制:​

◦

最大迭代次数:max_iterations = 10,超过强制结束。​

智能检测:​

◦

重复动作检测: 连续 2 次调用相同工具且参数相同(或高度相似),判定为循环。​

◦

进度检测: 每 3 轮迭代后检查是否有实质性进展(新信息、状态变化)。​

◦

回路检测: 状态机检测是否回到之前的状态。​

处理策略:​

◦

检测到循环后,在下一次 Thought 的 Prompt 中注入提示:​

​

代码块​

Plain Text

注意:你已经执行了相同的操作,请尝试不同的方法或直接给出最终回答。​

​

◦

如果注入提示后仍然循环 → 强制进入 Final Answer 阶段。​

◦

强制结束时,基于已有信息生成最好的回答,并标注"信息可能不完整"。​

根因分析和预防:​

◦

所有死循环事件记录日志,定期分析根因。​

◦

常见根因:工具描述不清导致选错工具、Prompt 指令矛盾、检索结果质量差。​

◦

针对性优化 Prompt 和工具描述。​

Result:​

•

死循环发生率从初始的 3% 降低到 0.2%。​

•

99.8% 的请求在 5 轮迭代内完成。​

•

死循环导致的用户投诉降低 95%。​

​

​

Q2: 模型幻觉怎么控制的?​

Situation: LLM 在没有足够信息时会"编造"内容(幻觉),在企业场景中这是严重的问题(如编造不存在的产品功能或价格)。​

Task: 多层次控制模型幻觉,确保回答基于事实。​

Action:​

RAG 基础(最重要):​

◦

所有回答都基于检索到的知识片段,要求 LLM 只使用提供的上下文信息。​

◦

Prompt 中明确声明:"只根据以下参考信息回答,如果信息不足,请明确说明无法回答。"​

引用机制:​

◦

要求 LLM 在回答中标注引用来源:[参考1]、[参考2]。​

◦

后处理检查引用是否真实存在于检索结果中。​

◦

没有引用的事实性陈述标记为"待验证"。​

幻觉检测(输出侧):​

◦

NLI(自然语言推断)检查: 检查回答中的每个关键陈述是否能从 context 中推断出来。​

◦

关键实体核验: 提取回答中的数字、日期、名称等关键实体,与 context 对比。​

◦

自我一致性检查: 让 LLM 对同一问题生成 3 次回答,如果答案不一致,标记为低置信度。​

降级策略:​

◦

检索结果相关性低(rerank score < 0.4)→ 回复"知识库中暂无相关信息"。​

◦

检测到可能的幻觉 → 在回答中添加提示"该信息仅供参考,建议核实"。​

温度控制:​

◦

事实性回答场景 temperature=0(确定性最高)。​

◦

创意性场景 temperature=0.7。​

Result:​

•

幻觉率从无防控的 18% 降低到 3%。​

•

关键业务场景(报价、合同条款等)的幻觉率 < 0.5%。​

•

用户对回答准确性的信任度提升 35%。​

​

​

Q3: 模型超时怎么处理?​

Situation: LLM API 调用有时会出现超长延迟(> 30s)或直接超时,影响用户体验。​

Task: 设计模型超时的处理策略,保证用户体验。​

Action:​

超时策略分级:​

超时处理流程:​

​

代码块​

Plain Text

首次调用超时 → 自动重试(切换备用端点,最多1次)​

→ 重试超时 → 降级到备用模型​

→ 备用模型也超时 → 返回兜底话术​

​

降级矩阵:​

​

​

用户侧处理:​

◦

流式模式下:超时前如果已有部分输出,告知用户"回答可能不完整"。​

◦

非流式模式:返回"处理时间较长,正在努力处理中...",并提供重试按钮。​

◦

记录超时请求,后台异步完成后主动推送结果。​

Result:​

•

用户可见的超时错误从 5% 降低到 0.5%。​

•

降级后的回答质量虽然有所下降,但 85% 的用户仍然接受。​

•

模型不可用时的系统可用性从 0% 提升到 95%(降级兜底)。​

​

​

Q4: 检索结果不准确怎么办?​

Situation: 检索结果不准确是 RAG 系统最常见的问题,表现为:召回的 chunk 与问题无关、关键信息未被召回、排序不准确。​

Task: 建立检索质量问题的诊断和优化流程。​

Action:​

问题诊断流程:​

​

代码块​

Plain Text

用户反馈 → 复现查询 → 查看检索结果 → 定位问题环节​

├── 分块问题:关键信息被切断 → 优化分块策略​

├── Embedding 质量:语义表示不准 → 评估/更换模型​

├── 检索参数:top_k 太小 → 调整参数​

├── 数据质量:源文档有误 → 数据清洗​

└── 查询理解:用户表述模糊 → query 重写​

​

Query 重写(Query Rewriting):​

◦

使用 LLM 将用户的口语化查询重写为更精确的检索查询。​

◦

示例:"这个东西怎么退" → "退货退款流程和规则"​

◦

多查询扩展:将一个模糊查询扩展为多个精确子查询,分别检索后融合。​

HyDE(Hypothetical Document Embedding):​

◦

让 LLM 生成一个"假设的理想回答"。​

检索后处理:​

◦

Reranker 精排(详见技术实现 Q6)。​

◦

上下文扩展:检索到的 chunk 自动扩展前后相邻 chunk,补充上下文。​

持续优化闭环:​

◦

每周分析"回答不满意"的反馈,追溯检索环节的问题。​

◦

定期更新评估集,跟踪检索质量指标。​

Result:​

•

Query 重写使检索准确率提升 15%。​

•

HyDE 在专业术语查询场景提升 22%。​

•

检索相关的用户投诉减少 60%。​

​

​

Q5: 工具调用失败怎么处理?​

Situation: Agent 调用外部工具(数据库查询、API 调用等)时可能失败:接口不可用、参数错误、权限不足、数据不存在等。​

Task: 设计工具调用失败的处理策略,保证 Agent 的鲁棒性。​

Action:​

错误分类和处理:​

​

​

Agent 自愈机制:​

错误信息标准化:​

class ToolError:error_type: str # TIMEOUT/PARAM_ERROR/AUTH_ERROR/NOT_FOUND/SYSTEM_ERRORmessage: str # 人可读的错误描述retryable: bool # 是否可重试suggestion: str # 建议的处理方式​

兜底机制:​

◦

工具调用连续失败 3 次 → 跳过该工具,基于已有信息回答。​

◦

所有工具都不可用 → 返回知识库检索的纯 RAG 回答。​

Result:​

•

工具调用的端到端成功率从 92% 提升到 98%。​

•

Agent 自主修正参数的成功率 78%。​

•

工具不可用时的用户体验保持在可接受水平(有降级回答)。​

​

​

Q6: 多 Agent 之间通信失败怎么处理?​

Situation: 多 Agent 架构中,Agent 之间通过消息传递协作。如果某个 Agent 挂掉或响应超时,会影响整个任务链。​

Task: 确保多 Agent 系统的容错性和可靠性。​

Action:​

通信超时控制:​

◦

每个 Agent 调用设置超时:30s(默认),复杂任务 60s。​

◦

超时后 Supervisor Agent 决定是否重试或跳过。​

Agent 健康检查:​

◦

每 10s 发送一次健康检查请求。​

◦

连续 3 次健康检查失败 → 标记 Agent 为不可用。​

◦

不可用的 Agent 不再接收新任务。​

任务重新分配:​

◦

Agent 失败后,任务重新分配给同类型的备份 Agent。​

◦

如果没有备份 Agent → 由 Supervisor Agent 尝试直接处理(降级)。​

消息持久化:​

◦

Agent 间的消息通过 Redis Stream 传递(有持久化)。​

◦

即使消费者 Agent 重启,未处理的消息不会丢失。​

Result:​

•

单个 Agent 故障不影响整体系统可用性。​

•

任务重新分配延迟 < 5s。​

•

系统整体可用性 99.5%。​

​

​

Q7: 知识库数据不一致怎么处理?​

Situation: 知识库中可能存在过时信息、矛盾信息(同一主题不同文档说法不一致)、或错误信息。​

Task: 检测和处理知识库中的数据不一致问题。​

Action:​

时效性管理:​

◦

每个文档/chunk 标记创建时间和更新时间。​

◦

检索结果中,近期文档的排序权重更高。​

◦

超过设定期限(如 1 年)的文档标记为"可能过时"。​

矛盾检测:​

◦

当检索到多个相关 chunk 时,检查它们是否包含矛盾信息。​

◦

检测方法:使用 NLI 模型判断两个文本片段是否矛盾。​

◦

发现矛盾时:优先使用更新的文档,并在回答中说明存在不同说法。​

数据质量巡检:​

◦

每周自动巡检:检查文档的可用性(链接是否有效、格式是否正常)。​

◦

每月人工审核:随机抽查 50 份文档,验证内容准确性。​

用户反馈闭环:​

◦

用户标记"回答错误"时,自动触发人工审核。​

◦

审核结果反馈到知识库(修正或标注)。​

Result:​

•

过时信息的误导率降低 70%。​

•

矛盾信息的检测覆盖率 80%。​

•

知识库数据质量评分从 3.6 提升到 4.2(满分 5 分)。​

​

​

Q8: 高并发下的限流降级策略是什么?​

Situation: 突发流量(如营销活动、批量查询)可能导致系统过载,需要保护核心服务不被打垮。​

Task: 设计分级限流和优雅降级策略。​

Action:​

限流层次:​

◦

API 网关层: 全局限流(总 QPS 上限 500)。​

◦

租户级限流: 每个租户有独立的 QPS 配额(如 50 QPS)。​

限流算法:​

◦

使用 Redis + 令牌桶算法(Token Bucket)。​

◦

支持突发流量(桶容量 = 2倍的 QPS 配额)。​

降级策略(分四个等级):​

​

代码块​

Plain Text

L0(正常):所有功能正常运行​

L1(轻微):关闭非核心功能(如推荐、个性化)​

L2(中度):模型降级(复杂查询也走快速模型)​

L3(严重):只返回缓存和FAQ回答,不调用LLM​

​

自动降级触发条件:​

◦

QPS > 阈值的 80% → L1。​

◦

LLM API 错误率 > 10% → L2。​

Result:​

•

在 5 倍突发流量下,核心功能仍然可用。​

•

降级响应延迟 < 200ms(缓存/FAQ)。​

•

零系统崩溃事故。​

​

​

Q9: 数据丢失和恢复策略是什么?​

Situation: 关键数据(对话历史、知识库索引、用户偏好等)的丢失会严重影响服务质量。​

Task: 建立完善的数据备份和恢复机制。​

Action:​

数据分级:​

◦

核心数据(RPO=0): 知识库原始文档、用户配置 → 实时同步备份。​

备份策略:​

◦

PostgreSQL:流式复制(主从同步)+ 每日全量备份 + WAL 归档。​

◦

Milvus:定期 snapshot + 原始文档可重建索引。​

◦

Redis:RDB 快照(每小时)+ AOF 持久化。​

恢复演练:​

◦

每季度做一次灾难恢复演练。​

◦

模拟场景:数据库主节点故障、向量库数据损坏、Redis 全部清空。​

◦

记录恢复时间(RTO),确保满足 SLA 要求。​

Result:​

•

核心数据零丢失(RPO=0,主从同步)。​

•

数据库故障恢复时间 < 5 分钟(主从切换)。​

•

向量库重建时间:约 6 小时(从原始文档重新计算 embedding)。​

​

​

Q10: 模型输出格式异常怎么处理?​

Situation: LLM 有时不按预期格式输出(如应输出 JSON 但输出了纯文本,或 ReAct 格式解析失败)。​

Task: 建立鲁棒的输出解析和纠正机制。​

Action:​

多层解析策略:​

​

代码块​

Plain Text

严格正则解析 → 宽松正则解析 → LLM 重格式化 → 降级处理​

​

具体实现:​

◦

第一层(严格正则): 标准格式匹配(如 Thought:(.*)Action:(.*))。​

◦

第二层(宽松正则): 忽略大小写、多余空格等微小差异。​

◦

第三层(LLM 修复): 用轻量模型将非标格式输出修复为标准格式。​

预防措施:​

◦

在 Prompt 中强调格式要求,提供明确示例。​

◦

使用 OpenAI 的 response_format(JSON mode)强制 JSON 输出。​

◦

对于 Claude,使用 tool_use 模式替代纯文本 Prompt 来获取结构化输出。​

监控告警:​

◦

记录每次解析失败的事件和原因。​

◦

格式遵循率 < 90% 时触发告警,检查 Prompt 是否需要优化。​

Result:​

•

格式解析成功率从 82% 提升到 98%。​

•

LLM 修复层兜底了约 5% 的解析失败。​

•

用户感知的格式异常从 8% 降低到 0.5%。​

​

​

Q11: 敏感信息泄露怎么防止?​

Situation: Agent 在处理用户请求时,可能接触到敏感信息(个人隐私、商业机密),需要防止信息通过 LLM 泄露。​

Task: 建立敏感信息的全生命周期防护机制。​

Action:​

输入脱敏:​

◦

使用正则 + NER 模型识别敏感信息:手机号、身份证号、银行卡号、邮箱、地址等。​

◦

替换为占位符:[手机号_1]、[身份证号_1]。​

◦

脱敏映射表存储在临时内存中(会话结束后清除)。​

输出还原:​

◦

LLM 回答中的占位符在返回前还原为原始值。​

◦

只还原用户有权查看的信息。​

LLM 不可信原则:​

◦

假设 LLM 可能记忆训练数据中的信息 → 敏感数据绝不发送给 LLM。​

日志安全:​

◦

对话日志中的敏感信息自动脱敏后再存储。​

◦

日志访问权限严格控制(最小权限原则)。​

Result:​

•

敏感信息防护覆盖率 99.5%。​

•

零信息泄露事故。​

•

通过了等保三级评审。​

​

​

Q12: 系统容量规划是怎么做的?​

Situation: 需要预估系统未来的资源需求,提前规划容量,避免资源不足或过度浪费。​

Task: 建立系统容量规划方法论。​

Action:​

容量模型:​

​

代码块​

Plain Text

所需 Pod 数 = 峰值 QPS / (单 Pod QPS × 0.7)​

# 0.7 是安全系数,留 30% 余量​

​

关键资源评估:​

◦

API Pod: 每 Pod 处理 25 QPS,峰值 200 QPS → 需要 12 Pod(冗余)。​

◦

Milvus: 1000 万向量约需 48GB 内存,3 节点每节点 16GB。​

◦

Redis: 缓存约 10GB,会话状态约 5GB → 16GB 集群。​

◦

PostgreSQL: 对话记录约 500GB/年 → 提前规划存储扩展。​

增长预测:​

◦

基于历史数据线性回归,预测未来 3-6 个月的增长。​

◦

每季度评审一次容量规划,调整资源配置。​

成本优化:​

◦

使用预留实例降低云服务成本(降低 30-40%)。​

Result:​

•

系统在业务增长 300% 时平滑扩容,无服务中断。​

•

资源利用率保持在 60-80%(既不浪费也有余量)。​

•

月度基础设施成本控制在预算范围内。​

​

​

​

本文档总计 92 个问题,涵盖架构设计、技术实现、性能优化、故障处理、工程质量、业务理解、基础知识七大类。 每个回答都力求技术深度和实用性,可直接用于面试准备。 建议结合自己的实际项目经验,适当调整具体的数据和细节。​

​

​