教程_Agent与MCP 小测验答案


1. AI Agent 的五大核心模块分别是什么?它们各自的职责是什么?

  • Planning(计划模块):理解目标任务,将复杂任务拆解为可执行的步骤,生成行动计划。例如判断用户的问题需要使用本地文档搜索还是网络搜索。
  • Memory(记忆模块):存储与任务相关的历史记录和上下文信息,支持长期记忆与短期记忆。在代码中体现为 memory_global 列表。
  • Tools(工具模块):调用外部工具(如 RAG 检索、Web 搜索、API 接口),实现感知-行动闭环。
  • Executor(执行模块):根据计划依次执行每一步操作,将结果存入 memory。对应代码中的 process_actions() 函数。
  • Output(输出模块):综合 memory 中的所有信息,调用 LLM 生成最终回答。对应 final_answer() 函数。

2. 在 RAG 系统中,BGE-M3 模型能够同时生成哪两种向量表示?它们各自擅长什么?

  • 稠密向量(Dense Vector):固定维度的浮点数向量,捕捉文本的语义信息,擅长语义相似度搜索。即使查询和文档使用不同的词汇,只要语义相关就能匹配。
  • 稀疏向量(Sparse Vector):高维但大部分值为零的向量,类似 TF-IDF 或 BM25,擅长关键词精确匹配。当查询包含特定术语(如"以人为本的座舱")时,能精确找到包含这些关键词的文档。

3. 在 Milvus 混合检索中,WeightedRanker(0.7, 1.0) 的两个参数分别控制什么?如果想让关键词匹配的权重更高,应该如何调整?

  • 第一个参数 0.7 是**稀疏向量(关键词匹配)**的权重。
  • 第二个参数 1.0 是**稠密向量(语义匹配)**的权重。
  • 如果想让关键词匹配的权重更高,应该增大第一个参数,例如 WeightedRanker(1.5, 1.0)WeightedRanker(1.0, 0.5)

4. 文本切块函数 chunk_text 中为什么要对表格做特殊处理?如果不做处理会怎样?

表格是一个语义完整的信息单元,行与行之间紧密关联。如果不做特殊处理,表格可能会被从中间切断,导致:

  • 上半部分只有表头没有数据
  • 下半部分只有数据没有表头
  • 两个 chunk 各自都无法表达完整的信息

特殊处理通过检测 | 字符识别表格,将整个表格作为一个完整的 chunk 保存。


5. Web 搜索模块中,WebScraper 类的 extract_main_content 方法为什么只提取 h1-h6p 标签,而不是所有 HTML 标签?

网页中包含大量非正文内容:导航栏、侧边栏、页脚、广告、脚本、样式等。这些内容通常使用 divnavfooteraside 等标签。h1-h6(标题)和 p(段落)标签通常包含网页的核心正文内容。此外,代码还通过 len(tag_text.split()) > 10 进一步过滤掉过短的文本片段(如按钮文字、菜单项),从而有效去除噪声。


6. Agent 的 Planning 模块在收到"比较一下和特斯拉的优劣势"这种查询时,为什么需要同时规划"本地文档搜索"和"网络搜索"两种工具?

因为这个查询涉及两个不同的信息源:

  • 星辰电动 ES9 的信息:存在于本地产品文档中,应通过本地文档搜索(RAG)获取
  • 特斯拉的信息:不在本地文档中,需要通过网络搜索获取

只使用一种工具无法同时获取双方的信息,因此 Planning 模块必须规划两种工具的组合使用。


7. 什么是 ReAct 框架?它如何解决 LLM 的幻觉问题?

ReAct(Reasoning + Acting)是一种将推理和行动交织在一起的框架。模型在每一步都先推理"应该做什么",然后执行行动(如调用搜索 API),再根据行动结果继续推理。

它解决幻觉问题的方式是:当模型不确定某个事实时,不是凭空编造(幻觉),而是通过调用外部工具(如搜索引擎、数据库)获取真实信息。外部信息为模型的推理提供了事实基础,从而减少了幻觉和错误传播。


8. Reflexion 机制中的三个角色(行动者、评估者、自我反思)分别对应 Agent 代码中的哪些函数?

  • 行动者(Actor):对应 agent_plan() + process_actions(),负责规划和执行任务
  • 评估者(Evaluator):嵌入在 reflection() 函数中,评估已有信息(memory_global)是否足够回答用户问题
  • 自我反思(Self-Reflection):也在 reflection() 函数中,分析信息不足之处,生成补充查询(最多 3 个额外查询)

9. MCP 协议解决了什么问题?如果没有 MCP,M 个应用要对接 N 个工具需要多少适配器?有了 MCP 后呢?

MCP 解决的是 AI 应用与外部工具之间的标准化对接问题。

  • 没有 MCP:M 个应用 x N 个工具 = M x N 个适配器
  • 有了 MCP:每个应用实现 1 个 MCP Client + 每个工具实现 1 个 MCP Server = M + N 个适配器

这类似于 USB 协议对外设连接的标准化。


10. 在编写 MCP Server 时,@mcp.tool() 装饰器的函数 docstring 为什么重要?如果没有 docstring 会怎样?

Docstring 会被 MCP 框架自动提取并发送给 LLM,作为工具的功能描述。LLM 根据 docstring 来判断何时应该调用这个工具、如何传递参数。如果没有 docstring:

  • LLM 无法理解工具的用途,可能永远不会调用它
  • 即使调用,也可能传递错误的参数
  • 整个自动工具发现机制将失效

11. MCP Client 的 initialize_mcp 方法中,session.list_tools() 返回的信息包含哪些字段?这些信息如何被转换为 OpenAI Function Calling 格式?

session.list_tools() 返回的每个工具包含:

  • name:工具名称
  • description:工具描述(来自 docstring)
  • inputSchema:参数的 JSON Schema(从函数的类型注解自动生成)

转换为 OpenAI 格式:

1
2
3
4
5
6
7
8
{
  "type": "function",
  "function": {
    "name": tool.name,
    "description": tool.description,
    "parameters": tool.inputSchema
  }
}

12. 在 MCP Client 的 chat_with_tools 方法中,第二次调用 LLM 时为什么不传 tools 参数?

如果第二次调用仍传入 tools 参数,LLM 可能会再次决定调用工具,形成无限循环的工具调用链。不传 tools 参数可以确保 LLM 只基于已获取的工具结果生成文本回答,不会再次触发工具调用。同时还添加了一条系统消息:“请基于上述工具搜索结果,用中文为用户提供完整、准确的回答。不要再调用工具,直接回答即可。”


13. SalesPilot 项目中的 deduplicate_memory_global 函数的作用是什么?为什么需要对 memory 去重?

该函数对 memory 中所有检索结果按照 content_with_weight 字段进行全局去重。需要去重的原因:

  • Planning 模块会生成多个相关查询(如"ES9的优势"和"ES9的技术规格"),这些查询可能从同一个文档中检索到相同的片段
  • Reflexion 补充查询也可能重复检索到已有内容
  • 重复的内容会浪费 LLM 的上下文窗口(token),且可能导致 LLM 过度强调某些信息

14. 在 MCP Client 的 build_system_prompt 方法中,为什么要区分"必须使用工具"和"不要使用工具"两种情况?如果不做区分会有什么问题?

如果不做区分,LLM 可能会对每个问题都调用工具,包括"Python是什么"这类常识性问题。这会导致:

  • 不必要的 API 调用,增加延迟和成本
  • 搜索结果可能比 LLM 自身知识更差(搜索结果可能包含低质量内容)
  • 用户体验下降(简单问题也需要等待搜索)

通过明确区分,LLM 只在确实需要实时/最新信息时才调用工具。


15. SalesPilot 项目使用 SSE(Server-Sent Events)进行流式输出有什么优势?"role": "agent" 类型的消息有什么作用?

SSE 流式输出的优势:

  • 用户不需要等待整个回答生成完毕,可以实时看到回答逐步呈现
  • DeepSeek-R1 等推理模型的思考过程也可以实时展示
  • 提高用户体验,减少感知等待时间

"role": "agent" 消息的作用:

  • 在 Agent 执行搜索操作时,向前端推送当前正在执行的动作(如"正在执行本地文档搜索: ‘星辰ES9的技术规格’")
  • 让用户了解 Agent 的工作进度和决策过程
  • 增加系统的透明性和可信度