这是关于 LLM 代码生成、工具调用(Function Calling)与 Agent 智能体 的进阶面试题集。这一领域是目前应用层最活跃的方向,考察重点在于工程落地的稳定性、安全性和可控性


216. 你如何设计一个“代码生成 + 单元测试 + 修复循环”的自动编程系统?关键组件有哪些?

核心架构:Iterative Refinement Loop (迭代优化循环)。

关键组件:

  1. Generator (LLM Coder): 负责根据需求生成代码。
    • Prompt 技巧: 要求输出完整的 Markdown 代码块,并包含必要的 import。
  2. Executor (Sandbox): 一个安全的隔离环境(如 Docker 容器),负责运行代码和测试用例。
  3. Judge (Test Suite):
    • 单元测试生成器: 让 LLM 针对需求先写测试用例(TDD 模式)。
    • 执行与断言: 运行测试,捕获 stdout, stderrExit Code
  4. Reflector (Feedback Loop):
    • 如果测试通过 -> 结束,输出代码。
    • 如果测试失败 -> 将 报错信息(Traceback) + 源代码 + 原需求 再次喂给 LLM,提示:“测试失败,错误如下,请分析原因并修复代码。”
  5. Controller: 限制最大循环次数(如 5 次),防止死循环浪费 Token。

217. 对于代码生成任务,如何在 Prompt / 模型选择 / post-process 上做优化,提高可执行率?

  1. Prompt 层面:
    • Chain-of-Thought (CoT): “请先写出伪代码或设计思路,然后再写具体实现。”
    • FIM (Fill-In-the-Middle): 如果是补全任务,明确 <PRE>, <SUF>, <MID> 标记。
    • 依赖约束: 明确指定库版本(如 Use Pydantic v2, not v1)。
  2. 模型选择:
    • 优先选择经过 Code SFT 的模型(如 DeepSeek-Coder-V2, Claude 3.5 Sonnet, Qwen2.5-Coder),它们对语法结构和 API 的记忆更准。
  3. 后处理 (Post-process) - 关键:
    • AST 解析 (Static Analysis): 使用 Python ast 模块尝试解析生成的代码。如果解析失败(语法错误),直接在后处理阶段修复(如自动补全括号)或打回重生成,不进沙箱。
    • Linter 自动修复: 调用 ruffblack 进行格式化和简单的 import 修复。
    • 代码提取: 稳健地提取 Markdown backticks 中的内容,过滤掉解释性文字。

218. 在真实工程项目中,如何限制 LLM 生成“危险代码”(如命令注入、越权读取等)?

三道防线 (Defense in Depth):

  1. Prompt 防御 (Pre-generation):
    • System Prompt:禁止使用 os.system, subprocess, exec, eval 等危险函数。
  2. 静态分析 (Post-generation):
    • 在代码执行前,使用 AST 扫描代码树。
    • 黑名单机制: 发现 import os, import shutil, open('/etc/passwd') 等特征直接拦截。
    • 正则扫描: 扫描 IP 地址、域名模式,防止外联。
  3. 沙箱隔离 (Runtime Execution):
    • 网络隔离: 容器无外网权限(No Internet Access),防止数据外泄。
    • 用户权限: 使用 nobody 或非 root 用户运行代码。
    • 文件系统: 只读挂载(Read-only FS),仅 /tmp 可写。
    • 资源限制: cgroups 限制 CPU 和 内存,防止挖矿或 Fork Bomb。

219. 设计一个“LLM + 工具调用(Tool Calling)”系统,你会如何描述工具 schema 并解析模型输出?

  1. Schema 定义 (Interface):
    • 遵循 OpenAI Function Calling 格式 (JSON Schema)。这是目前的事实标准。
    • 关键点: description 字段必须极其详尽。LLM 是靠 description 来语义匹配工具的。
    • 示例: 不写 "get_weather(loc)",而写 "get_weather(location: str): Get current temperature in Celsius for a given city name."
  2. 解析模型输出 (Parser):
    • 容错解析: LLM 输出的 JSON 经常缺括号或带注释。使用 json_repair 库或专门的“脏 JSON 解析器”。
    • 流式解析: 许多框架支持在 Stream 过程中实时解析 function name 和 arguments,提升响应速度。
  3. 验证 (Validation):
    • 使用 Pydantic 对解析出的参数进行校验(类型强转、范围检查)。如果校验失败,将 ValidationError 自动反馈给 LLM 让其重试。

220. 多工具调用场景下,如何让模型按正确顺序调用工具,并处理前后依赖关系?

核心:ReAct (Reasoning + Acting) 或 Planning。

  1. 显式规划 (Explicit Planning):
    • 在 System Prompt 中要求:在调用工具前,先生成一个 Plan:1. 第一步做什么,2. 第二步做什么。
    • 这能让模型意识到任务的依赖性(先查 ID,再查订单)。
  2. 上下文传递 (Context Passing):
    • 观察结果回填: Tool A 执行完,将结果(Output)作为 role="tool" 的消息塞回 History。
    • 自动依赖注入: 下一轮生成的 Prompt 包含了上一轮的结果。LLM 会自然地提取 Tool A 的输出作为 Tool B 的输入。
  3. DAG 执行器:
    • 对于复杂的并行任务,让 LLM 生成一个 DAG(有向无环图)任务列表,代码层解析 DAG,并行执行无依赖的工具,串行执行有依赖的工具。

221. 你如何在 Agent 系统中控制“推理深度”和“调用次数”,避免无限循环和成本炸裂?

  1. 硬限制 (Hard Limits):
    • Max Steps: 设定 max_iterations = 10。超过次数强制终止,返回“任务未完成”。
    • Token Budget: 设定单次 Session 的最大 Token 消耗量。
  2. 循环检测 (Loop Detection):
    • 指纹匹配: 记录过去 N 步的 (Tool_Name, Tool_Args)。如果发现连续三次调用完全相同的参数,判定为卡死。
    • 干预策略: 触发循环检测后,向 Context 中插入系统提示:System: 你似乎陷入了循环调用,请尝试改变策略或结束任务。
  3. 明确终止条件:
    • 提供一个 finish_task()final_answer() 工具,强迫模型在完成时显式调用,而不是一直空转。

222. 在复杂业务流程(例如报销、工单审批)中,如何用 LLM + 工具调用做“流程编排”?

架构:SOP-based Agent (基于标准作业程序的智能体)。

  1. 状态机 (Finite State Machine - FSM):
    • 不要把整个大流程都塞给 LLM。将流程拆分为状态:提交 -> 初审 -> 复核 -> 打款
    • LLM 充当状态流转引擎
  2. 动态工具挂载 (Dynamic Tool Binding):
    • 在“初审”状态,LLM 只能看到 approve, reject, ask_for_more_info 这三个工具。
    • 只有状态流转到“打款”,才挂载 execute_payment 工具。防止越权调用。
  3. SOP 注入:
    • System Prompt 中包含当前步骤的 SOP(标准操作流程):当前是初审阶段,你需要核对发票金额,如果超过 5000 需转交人工。

223. 你如何记录和回放 Agent 的“思考过程”和调用链,以便调试和优化?

可观测性方案 (Tracing):

  1. 结构化日志 (Trace/Span):
    • 使用 OpenTelemetry 标准或 LangSmith/Langfuse 格式。
    • Root Span: 用户 Query。
    • Child Spans: Thought (LLM Generation) -> Action (Tool Call) -> Observation (Tool Output).
  2. 关键字段:
    • Step_Index, Latency, Token_Usage, Input_Context, Output_Result.
  3. 回放机制 (Replay):
    • 将日志中的 Input_ContextTool_Output 提取出来。
    • 在本地 Mock 掉工具调用(直接返回日志中的 Output),只让 LLM 重新推理。这样可以低成本验证“修改 Prompt 后,LLM 的推理逻辑是否变好了”。

224. 对于高可靠性场景,你会如何为 LLM 的工具调用增加“规则引擎”或“验证器”?

模式:Neuro-Symbolic AI (神经符号主义) - LLM 负责意图,代码负责规则。

  1. 参数校验器 (Pydantic/JSON Schema):
    • 最基础的防御。确保转账金额是数字,日期格式正确。
  2. 业务规则层 (Guardrails):
    • 在 LLM 生成 Tool Call 后,执行前 拦截。
    • 规则示例: “如果 transfer_amount > 10000user_level != VIP,拦截并报错。”
    • 实现: 类似于 NeMo Guardrails 或自定义 Python 装饰器。
  3. Human-in-the-loop (人工确认):
    • 对于高危操作(删库、转账),规则引擎暂停执行,向前端推送“确认卡片”,用户点击 Approve 后,Agent 继续执行后续步骤。

225. 在一个多 Agent 协同系统中,你如何设计角色划分和通信机制?

常见模式:

  1. 角色划分 (Specialization):
    • Router/Manager: 负责任务分发,不干具体活。
    • Worker (Coder): 专注写代码。
    • Worker (Reviewer): 专注找 Bug。
    • Worker (Executor): 专注运行环境。
  2. 通信拓扑:
    • 星型拓扑 (Supervisor): 所有 Worker 只和 Manager 说话。Manager 汇总信息后决定下一步叫谁。适合流程明确的任务。
    • 总线拓扑 (Shared Blackboard): 所有 Agent 共享一个 Memory/History。Agent A 说句话,B 和 C 都能看见。适合头脑风暴。
    • 状态图 (Graph-based - LangGraph): 明确定义节点(Agent)和边(转移条件)。Coder --commit--> Reviewer --pass--> Merge。这是目前最可控的方案。

226. 你如何评估一个“Agent 系统”相对于简单 LLM 接口是否真的带来了业务价值?

评估维度:Actionability (行动力) & Success Rate (成事率)。

  1. 对比基准: 纯 Chat LLM 只能给“建议”。Agent 能“交付结果”。
    • 指标: 任务闭环率 (Task Completion Rate)。用户说“帮我订票”,纯 LLM 只能给链接,Agent 能把票号返回。
  2. 成本/收益分析:
    • Agent 通常慢(多轮交互)且贵(Token 多)。
    • 公式: Value = (Agent 节省的人工工时 * 时薪) - (Agent Token 成本 + 延迟带来的体验折损)
  3. 鲁棒性 (Robustness):
    • 测试 Agent 在工具报错、网络超时情况下的自愈能力。如果一报错就挂,还不如让人工来做。

227. 对于代码解释、调试类 Agent,你会如何让它安全地执行用户代码并限制资源使用?

Sandbox 实现细节:

  1. Ephemeral Containers (瞬时容器):
    • 每个 Session 启动一个轻量级 Docker 容器或 Firecracker MicroVM。会话结束立即销毁。
  2. 资源配额 (Quotas):
    • Time: timeout=30s,防止死循环。
    • Memory: mem_limit=512MB,防止 OOM 攻击。
    • Disk: 限制写入量,防止填满磁盘。
  3. Kernel Level Isolation:
    • 使用 gVisorKata Containers,给容器加一层内核隔离,防止容器逃逸(Container Escape)。

228. 当 LLM 在工具调用返回错误时,你会如何提示模型进行自我纠错或切换备选方案?

策略:Error as Feedback (将错误视为反馈)。

  1. Raw Error Feed:
    • 不要在代码层 Swallow(吞掉)异常。
    • Exception: File not found 包装成 ToolOutput 返回给 LLM。
  2. Prompt 引导:
    • System Prompt 中加入:如果工具调用失败,请仔细阅读错误信息,尝试修改参数重试,或者尝试使用另一个工具。
  3. 重试策略 (Backoff):
    • 如果是网络波动(503),代码层自动重试。
    • 如果是参数错误(400),必须把球踢回给 LLM,让它修改参数。

229. 你如何设计一个“可观测性”体系来监控 Agent 的表现(成功率、调用次数、卡死率等)?

Dashboard 指标设计:

  1. 宏观业务指标:
    • Pass Rate: 最终任务成功的比例。
    • Avg Steps: 平均多少步完成任务(步数越少越智能)。
  2. 微观性能指标:
    • Tool Error Rate: 哪个工具经常报错?(说明工具描述写得烂,或者工具本身不稳定)。
    • Loop Rate: 触发死循环检测的频率。
    • Hallucination Rate: 尝试调用不存在的工具的频率。
  3. 成本指标:
    • Tokens per Task: 完成一个任务平均烧多少钱。

230. 如果一个 Agent 系统在生产中经常出现“奇怪行为”,你会从 Prompt、工具、环境哪个维度率先优化?

优化优先级:Prompt > Tools > Environment > Model。

  1. 第一顺位:Prompt (System Instructions):
    • 原因: 成本最低,见效最快。
    • 动作: 90% 的“奇怪行为”是因为指令模糊。通过增加 Few-shot Examples(少样本示例)明确告诉 Agent 在特定场景下该怎么做。
  2. 第二顺位:Tools (Description & Interface):
    • 原因: 模型经常选错工具或填错参数。
    • 动作: 优化 JSON Schema 的 description,把参数的边界条件写清楚。将一个复杂的万能工具拆分成三个原子工具。
  3. 第三顺位:Environment (RAG/Context):
    • 原因: 上下文中有噪音干扰了推理。
    • 动作: 优化 RAG 检索质量,减少 Context 长度。
  4. 最后顺位:Model (Fine-tuning):
    • 原因: 只有当基座模型智商不够理解复杂逻辑时,才考虑微调。这是最重、最贵的手段。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐