Agent3 测试题答案

题目见 [[Agent3_学习笔记]]


基础概念

1. Agent3 使用哪个框架进行多智能体编排?它与普通 LangChain 链有什么区别?

使用 LangGraph 框架。

区别:

  • 普通 LangChain 链是线性的(A→B→C),数据只能单向流动,不支持循环和条件分支。
  • LangGraph 将流程建模为有向图,支持:
    • 条件边:根据状态决定走哪条路(如反思后决定是否重新规划)
    • 循环:支持迭代推理(Reflector 可以把流程送回 Planner)
    • 状态共享:所有节点共享同一个 AgentState,可以跨节点读写数据

2. ReAct 模式中的 “Re” 和 “Act” 分别代表什么?在 Agent3 中哪个节点体现了"Re"?

  • Re = Reasoning(推理):分析当前情况,思考下一步该做什么
  • Act = Acting(行动):实际执行操作(调用工具、查询数据库等)

在 Agent3 中,Reflector 节点体现了"Re"(推理/反思)。它负责检查 Executor 的结果质量,决定是否需要重新规划(循环)或直接输出答案。


3. Agent3 的五个 Agent 节点按顺序是什么?各自的职责是什么?

顺序节点职责
1Router(路由器)分析用户意图,分类为 data_query / analysis / research / general
2Planner(规划器)根据意图制定执行计划,选择需要调用的工具和步骤
3Executor(执行器)按计划调用工具(Text2SQL、Code Executor 等),收集结果
4Reflector(反思器)评估结果质量,决定是否需要更多分析(循环回 Planner)
5Critic(评审器)综合所有工具结果,生成最终的自然语言回答

4. AgentState 中的 iteration 字段有什么作用?默认最大值是多少?

iteration 字段记录当前已经完成的推理迭代次数,用于防止无限循环。

当 Reflector 判断需要重新规划时,iteration 加1。如果达到最大值,流程强制进入 Critic 生成最终答案,即使结果不够完美。

默认最大值:3 次(即最多经历3轮"规划→执行→反思"循环)


5. Text2SQL 工具的工作流程是什么?

1
2
3
4
5
1. 接收自然语言问题(如"市值最大的5只股票")
2. 将数据库 schema 信息(表名、字段名)注入到提示词中
3. 调用 LLM(qwen-max)生成 SQL 语句
4. 在 SQLite 数据库上执行生成的 SQL
5. 将查询结果(list of dicts)返回给 Executor 节点

工具与代码

6. Code Executor 为什么需要"沙盒"机制?列举至少3个被禁止的模块。

原因: Code Executor 会执行 LLM 生成的 Python 代码。LLM 生成的代码可能包含恶意操作(误操作或被注入),如删除文件、访问网络、读取系统信息等。沙盒通过限制可用模块来防止这些风险。

被禁止的模块(至少3个):

  • os —— 禁止文件系统操作和系统命令
  • subprocess —— 禁止创建子进程执行系统命令
  • socket —— 禁止网络连接
  • sys —— 禁止访问 Python 运行时环境
  • importlib —— 禁止动态导入模块绕过限制

7. RAG Search 的完整流程是什么?它与普通关键词搜索有什么本质区别?

RAG Search 流程:

1
2
3
4
5
离线阶段(建库):
  PDF/文档 → 分块(Chunking)→ text-embedding-v4 编码 → 向量存储

在线阶段(查询):
  用户问题 → text-embedding-v4 编码 → 余弦相似度计算 → 返回 Top-K 最相似段落

本质区别:

  • 关键词搜索:基于字符串匹配,必须包含相同词语才能命中。
    • 例:搜索"半导体"不会匹配"芯片"
  • 向量语义搜索:基于语义相似度,即使用词不同,只要含义相近就能命中。
    • 例:搜索"半导体"会匹配"集成电路"、“芯片”、“晶圆"等语义相关内容

8. 为什么 LLM 服务(services/llm.py)使用单例模式?

原因有两点:

  1. 避免重复初始化开销:每次创建 LLM 客户端需要读取配置、建立连接,使用单例确保全局只初始化一次。
  2. 资源复用:HTTP 连接池、API Key 验证等资源可以被所有节点共享,而不是每次调用都重新建立。

实现方式:通过 Python 模块级别的单例实例,所有需要使用 LLM 的地方都 import 同一个实例。


9. 数据链路:当用户问"帮我画茅台的净利润图"时,哪两个工具会被串联使用?数据是如何从第一个工具传递给第二个的?

两个工具:

  1. Text2SQL —— 查询茅台的净利润数据
  2. Code Executor —— 用数据绘制图表

数据传递方式:

  • Text2SQL 执行 SQL 后,将结果(list of dicts 格式,如 [{year: 2022, net_profit: 627亿}, ...])存入 AgentState.tool_results
  • Code Executor 的执行计划中包含 use_previous_data: true 标志
  • Executor 节点检测到此标志后,自动将上一步的查询结果作为 data 变量注入到 Code Executor 的执行环境中
  • Python 代码中直接使用 pd.DataFrame(data) 访问该数据

10. use_previous_data 标志位在哪个工具中使用,它的作用是什么?

Code Executor(代码执行器) 工具中使用。

作用: 当执行计划中某个 Code Executor 步骤设置了 use_previous_data: true 时,Executor 节点会自动将上一步工具的输出结果(通常是 Text2SQL 的查询结果)注入到代码执行环境中,作为名为 data 的变量。这样 Python 代码无需重新查询数据库,直接对 data 进行分析即可,实现了工具间的数据链路


架构设计

11. LangGraph 中的"条件边”(conditional edge)有什么作用?在 Agent3 中哪里用到了条件边?

作用: 条件边根据当前 AgentState 的内容动态决定下一个要执行的节点,实现流程分叉和循环。

在 Agent3 中的应用位置(agents/graph.py):

  • Reflector 节点之后有条件边:
    • 如果反思结果是"需要更多分析" 且 iteration < 3 → 跳回 Planner 重新规划
    • 如果反思结果是"质量足够" 或 iteration >= 3 → 进入 Critic 生成最终答案

12. Agent3 的 API 层使用的是什么框架?/api/chat/stream 端点实现了什么功能?

框架: FastAPI

/api/chat/stream 功能: 实现流式响应(Streaming Response)。与普通的 /api/chat 不同,流式接口不会等到完整答案生成后才返回,而是通过 Server-Sent Events(SSE)或 chunked transfer encoding,将 LLM 生成的文本逐字/逐块实时推送给客户端,用户可以看到答案逐渐出现,提升交互体验。


13. 数据库中有哪5张表?各自存储什么数据?

表名数据内容
stocks股票基本信息(代码、名称、行业、市值、PE、PB 等),共15条
financials财务数据(营收、净利润、ROE、ROA、资产负债率等),共75条
market_data行情数据(开高低收、成交量、涨跌幅),共300条
research_reports研究报告(标题、分析师、评级、目标价、摘要等),共51条
analysis_history分析历史记录(会话ID、查询内容、使用的工具等)

14. 如果你要给 Agent3 新增一个"情感分析工具",需要修改哪些文件?

最少需要修改/新增以下文件:

  1. 新建 tools/sentiment_analyzer.py —— 实现情感分析工具类,包含 run() 方法和工具描述
  2. 修改 tools/__init__.py —— 导出新工具类
  3. 修改 agents/nodes.py —— 在 ExecutorNode.__init__ 中注册新工具:
    1
    
    self.tools["sentiment_analyzer"] = SentimentAnalyzerTool()
    
  4. 修改 api/routes.py(可选)—— 如果需要单独的 API 端点暴露该工具
  5. 修改 agents/nodes.py 中的 Planner 提示词 —— 让 Planner 知道有情感分析工具可用,以及何时应该选择它

15. Agent3 的架构分为几层?从用户请求到数据库查询,请描述完整的调用链。

共5层架构:

1
API 层 → Agents 层 → Tools 层 → Services 层 → Database 层

完整调用链(以"查询茅台市值"为例):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1. [API ] 用户 POST /api/chat {"message": "茅台市值多少?"}
    api/routes.py 接收请求

2. [Agents  - Router] 分析意图  "data_query"
    更新 AgentState.intent

3. [Agents  - Planner] 制定计划  使用 text2sql 工具
    更新 AgentState.plan

4. [Agents  - Executor] 读取计划,调用 Text2SQL 工具
    调用 tools/text2sql.py

5. [Tools  - Text2SQL] 调用 LLM 生成 SQL
    调用 services/llm.py

6. [Services  - LLM] 调用 DashScope qwen-max API
    返回 SQL: "SELECT market_cap FROM stocks WHERE stock_name='茅台'"

7. [Tools  - Text2SQL] 执行 SQL
    通过 SQLAlchemy 访问 database/

8. [Database ] SQLite 查询 stocks 
    返回结果 {market_cap: 2100000000000}

9. [工具→ExecutorReflectorCritic] 逐层处理并生成最终答案

10. [API ] 返回 JSON 响应给用户