This commit is contained in:
2026-09-22 15:42:25 +08:00
commit 8e86665096
60 changed files with 22339 additions and 0 deletions
@@ -0,0 +1,117 @@
# 阶段八 · 项目 1:Level1 入门 —— ReAct 智能问答 Agent
> 所属:阶段八 从入门到生产的实战项目路线
> 定位:让一切从「手写一个 Agent 循环」开始。这一级不追求花哨,只求你把「思考-行动-观察」这套最底层的循环亲手写一遍、跑一遍、拆一遍,再套上框架——只有亲手写过,才知道框架帮你做了什么。
## 项目概览
| 项 | 内容 |
|-|-|
| 难度 | Level1 入门 |
| 核心功能 | 集成搜索 + 计算器,实现「思考-行动-观察」闭环 |
| 技术栈 | LangGraph + OpenAI + Tavily |
| 周期 | 1-2 周 |
| 核心学习目标 | 手写理解 Agent 循环;工具调用流程;状态流转;处理解析异常 |
## 一句话看懂本项目的循环
```mermaid
graph TD
A[用户提问] --> B[LLM 思考<br/>ReAct: 决定用什么工具]
B --> C{模型想调用工具?}
C -->|是| D[执行工具<br/>search / calculator]
D --> E[把结果当观察<br/>Observation 回传]
E --> B
C -->|否| F[生成最终回答]
F --> G[结束]
```
> 核心认知:**Agent 的本质就是一个「想 → 做 → 看 → 再想」的循环**,直到模型确认答案。掌握这个循环,后面所有花哨能力都是它的变体。
> 🔬 **深度理解 · ReAct 智能问答(思考-行动-观察循环)**:
> 1. **本质**:ReAct 不是某种框架或库,而是"推理(Reasoning)"与"行动(Acting)"交替进行的推理范式——模型先把自然语言问题转成语义清晰的推理链,再把推理链拆成可执行的工具动作,最后把动作结果读回上下文继续推理,直至不需要再动作为止。
> 2. **机制**:每一轮沿「Thought(我该查什么/算什么)→ Action(选定工具+参数)→ Observation(工具返回值回填到对话历史)」推进;关键的闭环在于 `Observation` 必须放进输入上下文,模型下一轮才能"基于事实再推理"。这里的 `max_turns` 熔断对应 LangGraph 的 `recursion_limit`,本质都是用"步数上限"把不可控的循环收敛成有限步。
> 3. **为什么重要**:它把"怎么查、查完怎么办"的决策权交给模型而非写死规则,让一个 Agent 能应对开放式、非预枚举的问题;它也是后面所有高级能力(RAG、多智能体、Text-to-SQL)的最底层公共骨架,任何 Agent 都逃不开这个循环。
> 4. **易错点/常见误解**:不要以为 ReAct 就是"调两三次 API"——最难的是每一步的失败分支(动作解析失败、工具报错、结果为空)。真正的工程难点是让模型在"观察到了坏结果时改变方案"而不是继续原样复读;同理,"不加熔断"不是性能问题而是资金/算力风险,`max_turns` 不是可选的便利而是必须的底线。
## 学习内容详情
### 1. 为什么先手写、再套框架
先用阶段二的 [react_agent.py](../../code/阶段二/react_agent.py) 手写一遍,再用 LangGraph 重写一遍。对比的关键在「框架帮你做了什么」:状态管理、循环终止、错误兜底、断点重放,框架都封装好了,但你得先见过它们裸写的样子,才知道自己改的是什么。
> ⏳ **短期可不深究**:LangGraph 等框架封装的「断点重放 / Checkpoint 持久化」这类内部机制,第一遍知道"它存在、解决跨进程恢复状态的问题"即可,等你真正需要做状态落库(对应 Level5)时再深挖实现。
### 2. 必须亲手验证的三个现象
这三个现象,是判断你「真的懂了」而非「跑通了就行」的分水岭:
| 现象 | 为什么重要 | 对应代码 |
|-|-|-|
| 工具返回「错误」时模型自我纠错 | 决策质量来自反馈循环 | `tool_result` 错误被回传,模型换方案 |
| 网络抖动时的重试 | 真实环境不可能零失败 | `except` 捕获 + 指数退避重试 |
| 去掉 `max_turns` 后无解问题无限循环 | 上线的烧钱风险源头 | 熔断必须存在 |
### 3. 手写骨架(对照阶段二)
```python
def run_agent(question: str, tools: dict, max_turns: int = 6) -> str:
"""极简 ReAct 主循环: 思考→行动→观察, 加了 max_turns 熔断"""
messages = [{"role": "user", "content": question}]
for turn in range(max_turns): # 熔断: 防死循环烧钱
thought = llm.invoke(messages) # ① 思考
action = parse_action(thought) # ② 解析是否要调工具
if action is None: # ③ 不再调工具 → 给出结论
return thought
result = tools[action["name"]](**action["args"]) # ④ 行动
messages.append({"role": "tool", "content": str(result)}) # ⑤ 观察回传
return "已达最大轮次, 请重新提问" # 熔断兜底
```
要点:状态就是 `messages` 这个列表,每一轮在它上面追加「行动 + 观察」,保持完整现场。
> ⏳ **短期可不深究**:`parse_action` 内部怎么把模型的自然语言转成结构化工具调用(正则 / JSON 解析 / few-shot 提示)这套细节,第一遍知道"解析失败要兜底"即可,真实生产基本会交给 LangGraph 等框架的工具调用机制去处理,不用自己手写解析器。
## 本节验收清单
- [ ] 手写版 ReAct 能跑通搜索 + 计算两个工具
- [ ] LangGraph 版实现同样的闭环,并能解释每个 Node / Edge
- [ ] 设置了 `recursion_limit` 熔断并验证生效
- [ ] 复现过至少一种失败模式(格式解析失败 / 死循环 / 幻觉)并修复
## 排期与前置依赖
- **前置**:阶段二 ReAct(第 6 周手写基础)、阶段三 LangGraph 核心(第 7-8 周同步推进)。
- **建议排期**:第 7-8 周,1-2 周完成。
- **配套 Demo**:[阶段二手写 Agent](../../code/阶段二/react_agent.py) + [阶段三 LangGraph Agent](../../code/阶段三/react_langgraph_agent.py),先把这两个都跑通,再对照双手写对比笔记。
## 本节常见面试题(深度解析)
> 针对本节核心知识的面试高频点,配合"本质+机制"式理解,能让你答得既有深度又有广度。
### 面试题 1:请解释什么是 ReAct,它和"直接叫模型回答"或"纯 Prompt"的本质区别是什么?
- **面试官想考察**:你是否把 ReAct 当作"三步循环"的运行范式而非某个具体 API,以及你是否理解它对模型能力边界(上下文长度、推理步数)的依赖。
- **专业作答(含深度)**:
1. 先给定义:ReAct = Reasoning + Acting 交织的推理范式,把任务拆成「思考 → 行动 → 观察」交替进行。
2. 对比三者的差异:纯 Prompt 是一次性生成、模型"只能想象不能动手";ReAct 通过工具行动把外部世界(检索、计算、API)拉进推理,Observe 结果再回填上下文继续思考。
3. 点出关键本质:不是模型"更聪明了",而是我们给模型搭建了"可观察、可修正"的环境;同一模型下 ReAct 能解决单次推理解不了的组合型、需要外部信息的任务。
4. 补充边界:ReAct 有成本(多轮 token)与延迟(串行多步),且依赖模型工具调用稳定(解析、参数、JSON),因此熔断与容错必不可少。
- **加分亮点 / 深度追问**:可主动提到 ReAct 与 CoT(思维链)的关系——CoT 只有推理不落地执行,ReAct 在 CoT 之上加了行动与环境反馈;追问时能回答"何时该纯 CoT、何时该 ReAct(是否需要外部信息/工具)"更显功力。
### 面试题 2:为什么 Agent 循环里必须有 `max_turns` / `recursion_limit` 熔断?去掉会怎样?
- **面试官想考察**:你有没有真正想过"无限循环"在实际系统中的危害,而不仅是背了"要有熔断"这个结论。
- **专业作答(含深度)**:
1. 熔断的本质:给不可控的递归给一个上界,把"可能无限/超长"的执行收敛成有限步,是工程上的终止性保障。
2. 后果层面的三层危害:钱(每轮都调 LLM + 工具,token 与 API 费用随轮数线性上涨)、延迟(用户等不起,服务线程被占满可能损及整体 QPS)、正确性(模型在无解问题上容易原地打转,产出重复或无意义输出)。
3. 机制澄清:`max_turns` 不是"防止模型想太久"的性能参数,而是资金/算力/可用性的安全底线;达到上限应给出明确兜底回复而非静默失败。
4. 关联现实:生产系统常叠加超时、重试上限、工具失败降级,熔断只是第一道,Level4 的"报错自修正限 2 次"就是同一思路的不同形态。
- **加分亮点 / 深度追问**:可补充"熔断阈值怎么定"——需权衡正常任务的轮数分布与极端场景,设太紧会截断合法多步任务、太松烧钱;被追问"如何观察是否该调阈值"时可答"用链路日志做轮数分布统计"。
### 面试题 3:Agent 在工具调用时返回了错误或异常,一个"能上生产"的实现该如何处理?
- **面试官想考察**:你如何处理失败分支,是否理解"反馈闭环"是 ReAct 质量的关键,而不只是"报错就好"。
- **专业作答(含深度)**:
1. 原则:把错误当 Observation 回传,让模型基于事实决策,而不是崩溃或忽略——这正是"自我纠错"的来源。
2. 分层处理:捕获异常并结构化成对模型友好的错误文本(含可重试提示);对可重试的抖动(网络、限流)用指数退避重试;对逻辑错误(参数不合法)回传后让模型换方案。
3. 兜底防线:重试要有上限(如 MAX_RETRY=2),外加总轮数熔断,防止"修不好就无限修"烧钱。
4. 可观测:错误信息带上 trace/环节标识,便于定位是哪一步失败,为 Bad-case 沉淀打基础。
- **加分亮点 / 深度追问**:可提到"错误信息设计"本身是 prompt 工程的一部分——给模型看到"可行动"的错误("参数 x 需为整数")比看到裸堆栈更能促成修正;追问"什么情况不该重试"时可答参数类/业务类错误重试无意义,应直接回传模型调整方案。
@@ -0,0 +1,131 @@
# 阶段八 · 项目 2:Level2 进阶 —— 知识库 RAG Agent
> 所属:阶段八 从入门到生产的实战项目路线
> 定位:给 Agent 装上「自己的资料」。这一级把文档变成可检索的知识底座,并让它按需查询、带来源作答,是绝大多数「企业知识问答」产品的最小原型。
## 项目概览
| 项 | 内容 |
|-|-|
| 难度 | Level2 进阶 |
| 核心功能 | 文档上传、知识库问答、引用溯源、流式输出 |
| 技术栈 | LlamaIndex + Qdrant + LangGraph + Streamlit |
| 周期 | 2-3 周 |
| 核心学习目标 | RAG 与 Agent 结合;向量库使用;流式输出;文档解析各类异常 |
## 一句话看懂本项目的数据流
```mermaid
graph LR
A[文档上传] --> B[加载+解析<br/>PDF/扫描件/超大文件]
B --> C[分块<br/>语义/父子分块]
C --> D[向量化<br/>中文BGE Embedding]
D --> E[存入Qdrant<br/>带元数据]
F[用户提问] --> G{Agent判断}
G -->|需要查| H[混合检索<br/>向量+BM25]
H --> I[Rerank精排]
I --> J[元数据过滤]
J --> K[组装上下文→LLM]
K --> L[答案+引用溯源<br/>来源+页码]
```
> 核心认知:**RAG 的价值在于「能用公司的资料回答,而不是编」**。检索质量(分块、混合、精排)直接决定回答质量,检索垃圾,模型再强也答不对。
> 🔬 **深度理解 · 知识库 RAG(检索增强生成)**:
> 1. **本质**:RAG 不是一种检索算法,而是"先检索、再把检索结果拼进上下文让它生成"的组合范式——它通过"给模型在生成时喂入外部事实",把模型的生成能力约束在"基于证据回答"上,从而缓解幻觉与知识过期。
> 2. **机制**:离线把文档切块 Embedding 成向量入库;在线把用户提问也 Embedding 成向量,用相似度在库里召回 Top-K 片段,将片段拼入 prompt 后让 LLM 基于这些内容作答。质量的关键不在 Embedding 本身,而在"怎么切块、怎么召回、怎么排序(分块质量 + 混合检索 + Rerank)"这条链路。
> 3. **为什么重要**:它解决了 LLM 三大硬伤里最现实的两种——知识不在训练集内(新文档/私有资料)与知识过期(模型训练截止后的事实),且比微调更轻、可控、可追溯来源。
> 4. **易错点/常见误解**:最容易踩的坑是"检索到的片段顺序/相关性不够也硬答"——RAG 提升的是"答对的概率",前提是检索质量过关;同时别忘了"检索无关内容也算污染",垃圾进则垃圾出,模型再强也救不回低质量检索,所以必须有 score 阈值与"宁可不答"的兜底。
## 学习内容详情
### 1. 数据链路(离线索引阶段)
文档加载 → 分块(语义分块 / 父子分块)→ 向量化(中文 BGE Embedding)→ 存入 Qdrant。这一步只做一次,产出可检索的向量索引。
> ⏳ **短期可不深究**:语义分块 vs 父子分块的具体切分算法(如何感知段落边界、父块与子块如何映射)第一遍知道"分块影响检索粒度"即可,等真正遇到"长文档召回碎片化/上下文不足"再回来调分块策略,不必一开始就纠结原理。
### 2. 检索进阶(在线查询阶段)
| 手段 | 作用 | 说明 |
|-|-|-|
| 混合检索 | 召回更全 | 向量(语义)+ BM25(关键词)互补 |
| Rerank 精排 | 排序更准 | 对召回结果做交叉注意力精排 |
| 元数据过滤 | 更精准 | 按文档 / 章节 / 权限过滤,只查该查的 |
### 3. Agent 化:Agent-RAG 而非普通 RAG
把检索封装成 `@tool`,用 LangGraph 编排——模型自主决定「何时查、查几轮、要不要追问」,区别于一次性「查完就答」的朴素 RAG。
> 🔬 **深度理解 · Agent-RAG vs 一次性朴素 RAG**:
> 1. **本质**:两者的差别不在"会不会检索",而在"检索是不是一个可被模型在推理过程中反复决策的动作"。朴素 RAG 是"查一次就答"的流水线,Agent-RAG 把检索变成可多轮调用的工具。
> 2. **机制**:朴素 RAG 在生成前强行走一遍"向量化→召回→拼接",一次成型;Agent-RAG 则让模型自主决定「这个问题要不要查、查几轮、查到什么程度再回答」——可以在中途追问用户、可以基于上一轮检索结果再查,把检索从固定步骤升级为策略性动作。
> 3. **为什么重要**:它解决了朴素 RAG 的两个弱点——"无需检索的闲聊也硬查一遍(浪费+引入噪声)"和"一个问题需要分解成多次检索(复杂查询一次查不完)"。
> 4. **易错点/常见误解**:不要把"多轮检索"等同于"质量自动更高"——给模型更多检索自由度也意味着更多失败点与成本,通常要配检索失败降级、轮次上限与 score 阈值;Agent-RAG 适合复杂、多跳查询,简单事实问答用朴素 RAG 已经足够且更稳。
```python
@tool("search_kb")
def search_kb(query: str, top_k: int = 5) -> list:
"""Agent-RAG 的检索工具: 模型自主决定何时调用、调几轮"""
hits = hybrid_search(query, top_k=top_k) # 向量+BM25 混合
hits = rerank(query, hits) # 精排
return [{"content": h.text, "source": h.meta["file"], "page": h.meta["page"]}
for h in hits[:top_k]]
```
### 4. 引用溯源 + 流式输出
- **引用溯源**:答案必须标注来源文件与页码(生产必备,否则答错无从追责)。
- **流式输出**:用 SSE 逐 token 返回,前端 Streamlit / 浏览器呈现打字机效果,体感更快。
## 必须处理的异常
- **文档解析**:PDF 乱码、扫描件(需 PaddleOCR)、超大文件分块、编码问题——这是索引阶段最现实的一批坑。
- **检索无结果 / 低分块干扰**:加 score 阈值过滤,宁可「不知道」也不乱答。
- **模型输出 JSON 残缺**:pydantic 兜底 + 让模型重写(对照阶段四 RAG 与阶段六内容创作)。
> ⏳ **短期可不深究**:扫描件的 PDF 需要 PaddleOCR 这类 OCR 方案把图片文字还原成可检索文本,这一课第一遍遇到"文档能读"即可跳过,等真正拿到大量扫描件/图片型 PDF 的业务场景再专门攻坚 OCR,属于"遇到再学"的边缘需求。
## 本节验收清单
- [ ] 能上传多种格式文档并完成知识库索引
- [ ] 问答带引用溯源(来源 + 页码)
- [ ] 实现了 SSE 流式输出
- [ ] 混合检索 + Rerank 已落地并对比过单路检索的提升
## 排期与前置依赖
- **前置**:阶段四 RAG 技术体系 + 向量数据库记忆存储([rag_agent.py](../../code/阶段四/rag_agent.py) 先跑通)。
- **建议排期**:第 9-10 周,2-3 周完成;与阶段八 Level4(数据分析)共享向量库与检索经验。
- **关键对照**:本项目是「文档知识」RAG;Level4 是「结构化数据库」SQL Agent,两者共同点是都要求「答得准、可追溯」。
## 本节常见面试题(深度解析)
> 针对本节核心知识的面试高频点,配合"本质+机制"式理解,能让你答得既有深度又有广度。
### 面试题 1:请解释 RAG 的工作流程,并指出决定其问答质量的关键环节是什么?
- **面试官想考察**:你是把 RAG 当成"检索+生成"两步,还是真的理解整条链路里每个环节都在影响质量。
- **专业作答(含深度)**:
1. 流程拆环:文档加载 → 分块 → Embedding 向量化 → 入库;查询时把用户问题向量化 → 相似度召回 → 拼接上下文 → 让 LLM 基于证据作答。可补充混合检索(向量+BM25)与 Rerank 作为提升召回/排序的手段。
2. 点出关键:质量瓶颈通常不在 LLM,而在检索链——分块粒度决定"召回的是块还是破碎片段",召回质量决定"喂进上下文的证据对不对",排序质量决定"正确片段是否排在前面被采信"。
3. 给出判断标准:检索垃圾 → 生成必错(垃圾进垃圾出);所以要配 score 阈值、"宁可不答"与引用溯源来兜底。
4. 适当抽象:RAG 本质是"给生成加证据约束",与微调的差别在于不动模型权重、可控、可溯源。
- **加分亮点 / 深度追问**:可主动对比"朴素 RAG vs Agent-RAG"与"向量检索 vs 混合检索",并提到父子分块解决"召回碎片化"这类进阶痛点;追问"RAG 与微调怎么选"时可答"资料私有/更新频繁用 RAG,风格/领域能力固化用微调,二者常互补"。
### 面试题 2:为什么单靠向量(语义)检索还不够,还要上混合检索和 Rerank?
- **面试官想考察**:你是否理解语义检索的盲区,以及"召回"与"精排"两个阶段目标的不同。
- **专业作答(含深度)**:
1. 说清向量检索的盲区:它擅长"语义近义"("退款流程"召回"退货怎么操作"),但对精确标识符/专有名词准召回弱(如 SKU、型号、人名/编号),关键词组成的边界硬查询反而查不准。
2. 混合检索的分工:BM25 精准命中关键词/专有词,向量捕捉词面不同但意思相近的表达,两者互补召回更全。
3. Rerank 解决的问题:召回的 Top-K 还都是"粗排",用交叉注意力(query 与每个片段整体做深度交互打分)把真正相关的那条顶上,修正向量距离度量的浅层局限。
4. 权衡与误区:多一路检索与精排都增加延迟与成本,简单知识库未必需要;Rerank 是把"两阶段"质量再做一次排序增强,不是万能,召回阶段就丢了的内容精排也救不回。
- **加分亮点 / 深度追问**:可提"召回率 vs 精度的取舍(先求全再求准)",以及"为何要先召回粗排再精排(避免对全库做昂贵交叉注意力)";被追问时可解释 BM25 的词频—逆文档频率直觉与向量维数/度量(余弦等)的差异。
### 面试题 3:RAG 系统如何保证"答得准"并"可追溯"?产品化要注意什么?
- **面试官想考察**:你是否具备把 RAG 从 Demo 变成可靠功能的工程意识(兜底 + 问责)。
- **专业作答(含深度)**:
1. 答得准:检索这一侧用混合检索+Rerank 提质量;判定这一侧加 score 阈值,低于阈值宁可"不知道"也不乱答,配合检索无结果/低分块过滤。
2. 可追溯:返回结果必须带引用溯源(来源文件+页码+片段),让答案能对得上证据,查错可追责——这是企业级 RAG 的底线能力。
3. 结构可靠性:模型输出做结构化校验(JSON pydantic 兜底、残缺重写),避免下游解析崩。
4. 工程闭环:建评测集验证"改检索参数/改动 prompt"是否真的变好,避免凭感觉调参;与 Level5 的 Bad-case 回流与回归测试联动。
- **加分亮点 / 深度追问**:可主动引入"索引与查询分离(离线建好库、在线只查)",并提到权限控制(按元数据过滤控制谁能查哪些文档);追问"低分结果该不该暴露给用户"时可答倾向不暴露并给引导式回复,避免误导。
@@ -0,0 +1,122 @@
# 阶段八 · 项目 3:Level3 高级 —— 多角色内容创作团队
> 所属:阶段八 从入门到生产的实战项目路线
> 定位:把「一个人干到底」升级成「一个团队分工协作」。这一级用多个 Agent 各司其职(策划 / 撰稿 / 校对)自动产出长文,你要学会的是角色分工、任务调度与协作冲突的处理——多智能体落地的最小完整闭环。
## 项目概览
| 项 | 内容 |
|-|-|
| 难度 | Level3 高级 |
| 核心功能 | 策划 + 撰稿 + 校对多 Agent 协作,自动产出长文 |
| 技术栈 | CrewAI / LangGraph 多智能体 + 搜索工具 |
| 周期 | 3-4 周 |
| 核心学习目标 | 多 Agent 角色分工;任务调度;消息通信;处理协作冲突 |
## 一句话看懂本项目的协作流水线
```mermaid
graph TD
P[策划 Agent<br/>定主题/大纲] --> W[撰稿 Agent<br/>分章写作]
W --> C[校对 Agent<br/>独立上下文审稿]
C --> Q{冲突/质量问题?}
Q -->|有| R[冲突检测<br/>版本比对+仲裁]
R --> W
Q -->|无| S[产出长文<br/>素材可溯源]
```
> 核心认知:多 Agent 的价值不是「数更多」,而是**每个角色拥有独立上下文和专一职责**。策划管全局、撰稿管表达、校对管挑错——各自只盯着自己那部分,反而比一个「全能 Agent」更可控。
> 🔬 **深度理解 · 多角色内容创作(多智能体协作 + 独立上下文)**:
> 1. **本质**:它不是"同时跑多个 LLM",而是把一条大任务按"专业分工"拆成多个各有**独立上下文窗口**的执行单元,让"任务状态"而非"同一个对话历史"在角色间传递——每个 Agent 只携带它职责所需的上下文。
> 2. **机制**:由一个流程/主管把产出物(大纲、分章、审稿意见)作为显式的 `context` 注入下一角色;角色间通过"任务产出物 + 引用"通信而不是共享全部 token,避免上下文爆炸与相互污染。冲突时用优先规则/仲裁/人工兜底收口。
> 3. **为什么重要**:单个 Agent 一旦把"全局+细节"全塞进一个上下文,会出现长文本失控、自相矛盾、"每个角色都想抢话筒";多角色通过责权隔离提升可解释性、可质量控制和可溯源,也对应"让对的人看对的上下文"。
> 4. **易错点/常见误解**:别以为角色越多越好——每多一个角色就多一层编排成本与失败点;真正的关键是"职责边界清不清晰、context 传得准不准",而非"Agent 数量"。误把"多个角色"做成"共享同一上下文的分身"就是空壳多智能体,拿不到分工红利。
## 学习内容详情
### 1. 角色分工与职责边界
| 角色 | 职责 | 独立上下文 |
|-|-|-|
| 策划 | 定主题、搭大纲、定读者与风格 | 只看到主题与目标 |
| 撰稿 | 按大纲分章写作 | 只看到大纲 + 已写章节摘要 |
| 校对 | 审稿挑错、一致性检查 | 只看到成稿,独立于写作过程 |
### 2. 实现二选一
- **CrewAI**:快速上手,用 `role + goal + backstory + task.expected_output` 声明式配置,适合体验多 Agent 协作。
- **LangGraph Supervisor**:更可控,由主管 Agent 路由派活(对照阶段三示例 36、阶段五多智能体 Supervisor)。生产团队更常用这种「主管派活、工人干活」的图式。
> ⏳ **短期可不深究**:CrewAI 的 `backstory`/`goal` 等声明式字段怎么写才能"调教出好角色"这类偏框架内套路细节,第一遍照着模板配通即可;重点是理解"每个角色独立上下文+专人负责",别把时间耗在框架专属配置的调优上。
### 3. 消息通信:防互相污染
任务 `context` 显式声明「上游产出注入」,每个角色只拿到它该看的,避免一个 Agent 的中间输出污染另一个的判断。
### 4. 素材必须来自搜索(事实底座)
所有论点必须由搜索工具提供来源,防止产出一台「高级编造机」。这是长文「可溯源」而不是「像真的」的底线(对照阶段五防幻觉、阶段六内容创作)。
## 必须处理的问题
| 问题 | 处理 |
|-|-|
| 协作冲突 | 两个 Agent 对同一内容结论矛盾 → 冲突检测(版本比对)+ 优先级规则 / 人工仲裁 |
| 长文本失控 | 大纲锚定 + 章节摘要传递,一次只写一章(对照阶段六内容创作) |
| 素材编造 | 引用必须来自搜索工具,缺来源即打回 |
```python
def resolve_conflict(v1: str, v2: str, priority_roles: list) -> str:
"""冲突仲裁: 按优先级规则解决两个角色的矛盾结论, 必要时转人工"""
for role in priority_roles: # 例如 校对 > 撰稿
if v1.get("role") == role:
return v1["content"]
return "MANUAL_REVIEW" # 无法自动裁决 → 人工拍板
```
> ⏳ **短期可不深究**:冲突检测里"版本比对"具体用哪种文本 diff 算法(如按行/按句相似度、编辑距离)第一遍不用深究,知道"靠相似度/结构化比对找出两版差异、再按优先级仲裁"的思路即可,真到做长文一致性校验时再按需选工具。
## 本节验收清单
- [ ] 三个角色分工明确,长文自动产出完整
- [ ] 能说清所用框架的状态流转方式(CrewAI 或 LangGraph 图)
- [ ] 处理过一次协作冲突并给出解决策略
- [ ] 产出内容可溯源到素材,非凭空编造
## 排期与前置依赖
- **前置**:阶段五多智能体系统进阶 + 阶段六内容创作 Agent;阶段三 CrewAI / LangGraph supervisor 至少跑通一个。
- **建议排期**:第 12 周,3-4 周完成。
- **配套 Demo**:阶段五[多智能体工作流 Agent](../../code/阶段五/planning_memory_agent.py)(含 Supervisor 分工、断点恢复、冲突仲裁思路),先读懂它的三个 Worker 是怎么被调度的。
## 本节常见面试题(深度解析)
> 针对本节核心知识的面试高频点,配合"本质+机制"式理解,能让你答得既有深度又有广度。
### 面试题 1:多 Agent 协作和"一个 Agent 用很长的 prompt 分步干完"相比,优势到底在哪?什么情况下它反而没必要?
- **面试官想考察**:你是否明白多智能体的价值不是为了"堆数量",而是"独立上下文 + 职责隔离",以及是否能判断它的适用边界。
- **专业作答(含深度)**:
1. 关键差异:多 Agent 的核心是**每个角色的独立上下文窗口与专一职责**,而非单纯的流程分步——single Agent 分步仍共享同一上下文与同一系统人格。
2. 优势四条:上下文隔离防"互相污染与被无关信息稀释";职责单一使每步的 prompt 更聚焦、更易控制质量;可溯源(哪个角色产出了什么);独立编排与并行/重试。
3. 适用边界:任务复杂、需要不同专业知识与观点交锋(策划/撰文/校对)、产出可拆分为有界子任务时更划算;简单、单线任务上多 Agent 是徒增延迟、token 与失败点。
4. 一句话总结:多智能体是"用结构换可控",只有职责隔离能带来收益时才值得上。
- **加分亮点 / 深度追问**:可主动提"上下文隔离 vs 上下文共享的 token 成本权衡"和"主管-工人(Supervisor-Worker)vs 全连接 Sha 拓扑差异";经追问可谈"何时该把角色合并/拆细,取决于子任务是否需要独立的 prompt 状态"。
### 面试题 2:多 Agent 之间如何通信才能避免"上下文污染"?
- **面试官想考察**:你如何处理多 Agent 的消息/上下文传递,是否理解"传产出物而非共享全部历史"。
- **专业作答(含深度)**:
1. 原则:优先传递"该角色完成任务所需的产出物"(大纲、章节摘要、审稿意见),通过显式 `context` 声明依赖,而不是让所有 Agent 共享同一份对话历史。
2. 这样做的三点收益:控制每角色的上下文规模(省 token、降低噪声);避免"上游中间不可靠输出"污染下游判断;让依赖关系可追踪、可复现。
3. 补充务实手段:必要时只传摘要而非全文、保持每步产出可引用,确保关键事实不被改写丢失。
4. 风险提示:过度压缩 context 会丢失细节,压缩不足又回到"传全量"——要在"信息够用"与"上下文可控"间平衡。
- **加分亮点 / 深度追问**:可提到"产出物结构化(schema)+ 可追溯引用"的设计,确保下游能对回上游原文;追问"若各角色结论冲突怎么办"正好引出下一题。
### 面试题 3:两个 Agent 对同一内容的结论互相矛盾时,你怎么设计冲突检测与仲裁?
- **面试官想考察**:你是否对"多智能体运行的现实问题(结论不一致)"有落地思路,而不只是会搭个流程。
- **专业作答(含深度)**:
1. 冲突来源先说清:不同角色职责/视角不同,给出互相矛盾的版本是常态,不是 bug。
2. 检测:用结构化比对/相似度找出两版的实质差异点(是真矛盾还是表述差异)。
3. 仲裁三层:先按**优先级规则**(如校对 > 撰稿,谁更权威谁说了算);无明确优先级时引入**第三方裁决 Agent**或历史规则;仍存疑则**转人工(MANUAL_REVIEW)**兜底,绝不让模型自行糊弄过去。
4. 升华:仲裁结果应可解释、可审计,把"最终采用了谁的版本、为什么"记录下来,便于沉淀规则与复盘。
- **加分亮点 / 深度追问**:可补充"优先级本身就是一种领域知识,需业务方确认",以及"多次冲突说明职责边界或 context 传错了,应回到上游排查而非只修仲裁";追问可延伸到"如何防止仲裁 Agent 再引入新偏差"(限定其只看两版结论与理由)。
@@ -0,0 +1,136 @@
# 阶段八 · 项目 4:Level4 实战级 —— 数据分析 Agent
> 所属:阶段八 从入门到生产的实战项目路线
> 定位:让 Agent 直接对业务数据库「说人话、查数据、出图表」。这一级的核心不是『会查』,而是『既有用又安全』——能读懂业务口径、产出对的 SQL,同时一道防线都不漏,不让模型把公司数据弄坏。
> **内容复用说明**:本项目的 Schema Prompt 与五道防线实现,与阶段六 [02《数据分析 Agent》](../06-阶段六-垂直领域Agent落地实践/02-数据分析Agent.md)、[阶段六综合实战《数据分析 Text-to-SQL Agent》](../06-阶段六-垂直领域Agent落地实践/06-阶段六综合实战-数据分析Agent.md)共用同一套方案,此处不再重复贴代码;差异点在于本 Level 追加 **FastAPI 接口层 + 图表输出 + 报告生成**(见下文「工具链与 API 层」),五道防线代码也按 API 层返回结构调整(`status` 字典)。
## 项目概览
| 项 | 内容 |
|-|-|
| 难度 | Level4 实战级 |
| 核心功能 | 自然语言查库、自动图表、分析报告生成 |
| 技术栈 | LangGraph + SQL Agent + Pandas + FastAPI |
| 周期 | 4-6 周 |
| 核心学习目标 | Agent 对接业务数据库;SQL 风险;工具调用失败处理;输出校验 |
## 一句话看懂本项目的闭环
```mermaid
graph TD
U[自然语言提问] --> A[第一杠杆<br/>元数据描述+语义层]
A --> B[生成SQL]
B --> C{五道防线}
C -->|只读账号/白名单/参数化/校验| D[执行查询]
D --> E[图表生成<br/>bar/line/pie]
E --> F[报告组装]
F --> G[Analyst答复]
```
> 核心认知:**数据分析 Agent 的价值 = 问得动 + 答得准 + 破坏不了数据**。前两者靠元数据描述与语义层,后者靠无论如何都不越界的那道只读底线。
> 🔬 **深度理解 · 数据分析 Agent(Text-to-SQL + 安全边界)**:
> 1. **本质**:它把"自然语言 → SQL → 查库 → 图表/报告"串成一条可控流水线,本质是"用 LLM 做数据库的翻译器+执行器",但真正决定成败的往往不是翻译的炫技,而是"**语义对不对、SQL 安不安全**"这两个非模型问题。
> 2. **机制**:第一杠杆是把表的 schema(字段、类型、注释、示例行)与业务口径(如"营收"的确切定义)作为上下文喂给模型,让它在"懂业务口径"的前提下生成 SQL;随后 SQL 过"白名单/参数化/校验/限重试"等多道防线才落到数据库执行,结果再转图表与报告。
> 3. **为什么重要**:它让业务人员不写 SQL 也能跨表取数出图,把数据能力平民化;同时因为是"直接对生产库"操作,安全与准确是准入条件,少了任一条防线就不是能上线的产品。
> 4. **易错点/常见误解**:最大误区是"把能力押在让模型写出更完美的 SQL 上"——事实上业务口径模糊才是错报援引的主因,所以要先做语义层/口径固化;另一误区是把"只读"想成防御的全部,实际还要叠加校验与重试上限,形成纵深防线。
## 学习内容详情
### 1. Text-to-SQL:第一杠杆是元数据描述
把表 / 字段 / 注释 / 示例行 / 业务口径一次性喂给模型,它才能生成对的 SQL。描述越准,SQL 越对,比反复调 prompt 技巧更有效。
### 2. 五道防线(对照阶段六数据分析 Agent)
| 防线 | 作用 | 关键点 |
|-|-|-|
| 只读账号 | 根防线 | 数据库层限权,模型想 DELETE 也执行不了 |
| SQL 白名单校验 | 只放 SELECT / WITH | 挡在入口 |
| 参数化执行 | 防拼接注入 | 绝不字符串拼接 |
| 结果校验 | 空结果不编 | 行数 / 空结果 / 耗时异常 |
| 报错自修正 | 出错自动重试 | 限 2 次,避免无限烧 |
```python
ALLOWED_PREFIX = ("SELECT", "WITH")
MAX_RETRY = 2
def defend_and_run(sql: str, params: tuple, db) -> dict:
"""五道防线(2,3,4): 白名单 + 参数化 + 结果校验"""
if not sql.strip().upper().startswith(ALLOWED_PREFIX):
return {"status": "rejected", "reason": "仅为只读查询"} # ②
try:
result = db.execute(sql, params) # ③ 参数化
if not result:
return {"status": "empty", "message": "查询为空, 请核实, 勿编造"} # ④
return {"status": "ok", "data": result}
except Exception as e:
return {"status": "failed", "reason": str(e)[:100]} # ⑤ 交回模型改
```
> 🔬 **深度理解 · 五道防线(纵深防御 Dead-Defense)**:
> 1. **本质**:它用"多条不同层级的防线叠加"来防御"同一类核心风险(模型越界/注入/出错)",而不是指望单一道关卡完美——本质是安全工程里"纵深防御"思想在 LLM 落地控制器上的具体化。
> 2. **机制**:每一道防线的失效假设不同——只读账号连数据库层都不给写权限(最硬底线)、白名单把非 SELECT 挡在入口、参数化消除拼接注入、结果校验挡住空结果瞎编、报错自修正把失败交回模型并限 2 次——任何一道失守,其余仍可为兜底。
> 3. **为什么重要**:因为"模型是概率性的、会犯错甚至会被 prompt 诱导",所以必须把安全交给"非 LLM 的确定性代码"来兜底——防的是"系统性的、可证明的"越界行为,而不是防某一个 prompt 漏洞。
> 4. **易错点/常见误解**:别把某道防线当"唯一保险"——只读账号虽硬,但若配合了错误的白名单/缺参数化仍可能被绕过或误伤;也别忘了"只读≠安全",仍有排序/大表扫描把库打挂的风险,结果校验耗时异常就是要拦这个。真正确保的是"从最下层到最上层层层可拦截"。
### 3. 工具链与 API 层
- **工具链**:`run_sql`(查询)+ `plot_chart`(bar / line / pie 图表)+ `report`(报告组装)。
- **API 层**:FastAPI 暴露接口,带鉴权与限流——让 Agent 被安全地对外调用。
> ⏳ **短期可不深究**:`plot_chart` 具体用哪个绘图库(matplotlib / Plotly / ECharts 等)以及各种图表的样式参数搭配,第一遍会"给定数据出基础 bar/line/pie 图"即可;图表美化的细节等交付对外报告再按需打磨,不用一开始就钻研样式工程。
## 必须处理的问题
- **SQL 注入**:参数化,绝不字符串拼接。
- **工具调用失败**:报错文本回传模型自动修正(限重试 2 次,对照阶段六 `MAX_RETRY`)。
- **输出校验**:SQL 合法性 + 结果合理性(行数 / 空结果 / 耗时异常)。
- **业务语义**:语义层固化口径(「营收」= `SUM(amount) WHERE status='paid'`),避免三个用户问出三种营收。
> ⏳ **短期可不深究**:语义层的具体落地形态(写死口径映射表 / 在 schema 描述里带口径注释 / 建独立语义视图)第一遍知道"要解决口径不统一"即可,选哪种取决于团队的数据治理成熟度,不必一开始就实现复杂的语义中间层。
## 本节验收清单
- [ ] 自然语言查询能正确转 SQL 并返回结果
- [ ] 五道防线全部落地并验证(含注入攻击测试)
- [ ] 能自动生成图表并组装成一份分析报告
- [ ] 错误 SQL 能自动修正并成功重跑
## 排期与前置依赖
- **前置**:阶段六数据分析 Agent([data_analysis_agent.py](../../code/阶段六/data_analysis_agent.py) 先跑通五道防线)+ 阶段七 SQL 工具的对立工程做法。
- **建议排期**:第 13-14 周,4-6 周完成;这是阶段六 01 数据分析、阶段七监控的一次综合应用。
- **关键**:本项目给的 [Demo](../../code/阶段六/data_analysis_agent.py) 是离线教学版(内存表 + 五道防线);本项目要把它升级到真实 PostgreSQL + FastAPI + 图表输出。
## 本节常见面试题(深度解析)
> 针对本节核心知识的面试高频点,配合"本质+机制"式理解,能让你答得既有深度又有广度。
### 面试题 1:Text-to-SQL 里,为什么"元数据描述 + 语义层"是第一杠杆?比反复调 prompt 更有效在哪?
- **面试官想考察**:你是否理解"让模型写出对 SQL"的瓶颈在"输入信息(schema/口径)"而非"提示技巧"。
- **专业作答(含深度)**:
1. 归因:SQL 写错大多是"不知道表结构/字段含义/业务口径"导致的,而不是"不会写 SQL"——补信息比洗 prompt 更对症。
2. 具体做法:把表/字段/类型/注释/示例行/业务口径一次性喂给模型,等价于给它"残缺数据库文档",让它在"懂口径"的前提下建模。
3. 对比 prompt 技巧:调 prompt 是让模型"更努力猜",元数据+语义层是"减少它需要猜的内容",后者是决定性输入、可随 schema 变更更新,更具扩展性。
4. 联系本项目:口径统一(「营收」有唯一定义)直接削掉"三个用户问出三种营收",这是准确性 vs 偶然命中的分水岭。
- **加分亮点 / 深度追问**:可主动提到"few-shot 例子的 schema 上下文也能给模型接地气的模板",以及"语义层把口径固化到系统而非 prompt 里,天然可审计";追问"为什么同一口径不同 SQL 都算对"时可谈"结果等价 vs 写法等价"。
### 面试题 2:请完整讲一遍你的「五道防线」,并说明为什么安全不能只靠一条只读账号。
- **面试官想考察**:你是否用"纵深防御"的工程视角看待 LLM 落地控制,而不只是背五个名字。
- **专业作答(含深度)**:
1. 逐条展开:只读账号(数据库层最硬、模型想 DELETE 也执行不了);SQL 白名单(只放 SELECT/WITH,挡入口);参数化执行(消除注入,杜绝字符串拼接);结果校验(空结果/行数/耗时异常时不编造);报错自修正(交回模型限 2 次避免无限烧)。
2. 回答"为什么不全靠只读":只读挡的是"写"风险,防不了注入读取越权、防不了大表全扫拖垮库、防不了空结果胡说——风险是多维的,单点防线管不住多类威胁。
3. 机制关系:讲清"确定性代码兜底概率性模型"这一本质——防御核心交给非 LLM 的可证明逻辑,而不是信任模型永远守规矩。
4. 举一反三:限重试/超时同样属于把"不可控的循环"收敛成有限步,体现的是同一思维。
- **加分亮点 / 深度追问**:可主动补"最小权限 + 网络层隔离(内网/只读副本)"与"关键查询加耗时看门狗";追问"如何测试这五道防线"时可答"注入攻击测试 + 越权用例 + 空/巨量结果用例"构成验收矩阵。
### 面试题 3:模型还是一次问法查出空结果或很明显错的数据,你怎么让它"承认不知道"而不是硬编?
- **面试官想考察**:你如何处理 LLM 的幻觉在数据查询场景的放大——这是分析型 Agent 最容易失分的地方。
- **专业作答(含深度)**:
1. 机制:在结果校验/工具层就拦截——空结果、超时、异常这些"确定性信号"由代码判定并回传,避免模型拿到空结果仍自行脑补答案。
2. prompt 纪律:在系统层约束"空结果不许编造、要如实告知用户去核实",把"不知道"设为显式合法态,而不是逼模型给出一个数字。
3. 校验维度:行数、空结果、耗时异常都要看——"无数据"也是有效结论,但不能伪造成"查询成功有数据"。
4. 工程闭环:把这类"低置信/错误"样例沉进 Bad-case 队列,持续精修 prompt 与语义层。
- **加分亮点 / 深度追问**:可对比"结构化约束"与"提示约束"——对"不给编答案"这种关键约束,优先用代码强制(校验拦截)而非仅靠 prompt 期望;追问"空结果到底该展示什么"时可答"给出'无匹配数据+可能的核实建议'而非编造数值"。
@@ -0,0 +1,149 @@
# 阶段八 · 项目 5:Level5 生产级 —— 企业智能客服 Agent
> 所属:阶段八 从入门到生产的实战项目路线
> 定位:阶段八的收尾,也是整个 16 周学习计划的毕业设计。这一级把前面所有阶段能力捏合成一个「能上线、能扩、能迭代」的完整生产系统——不是 Demo,是真的能部署给用户用的产品。
## 项目概览
| 项 | 内容 |
|-|-|
| 难度 | Level5 生产级 |
| 核心功能 | 知识库答疑 + 工单创建 + 人工转接 + 多租户后台 |
| 技术栈 | LangGraph + RAG + 工单系统 + 管理后台 + Docker 部署 |
| 周期 | 6-8 周 |
| 核心学习目标 | 完整工程落地;权限、持久化、监控告警;线上迭代闭环 |
## 一句话看懂本项目的系统分层
```mermaid
graph TD
U[用户入口<br/>客服前台] --> R[意图分流<br/>客服/订单/转人工]
R --> Q[知识问答 RAG<br/>Level2 能力]
Q --> E{能否满足?}
E -->|否| T[建工单<br/>Level4 能力]
E -->|是| A[答复]
T --> S[多租户后台<br/>权限/监控/工单管理]
S --> D[Docker Compose 部署<br/>应用+worker+Redis+PG+Qdrant]
```
> 核心认知:**生产级不是在功能上加花活,而是把每个环节的『不靠谱』都堵住**——状态不丢、权限不漏、故障可控、数据可追。这才是从 0 到 1 之后真正拉开差距的地方。
> 🔬 **深度理解 · 企业智能客服(从 Demo 到生产系统)**:
> 1. **本质**:生产级不是"多了几个功能按钮",而是把系统从"在理想条件下能跑"提升到"在真实恶劣条件下也可靠可用"——核心矛盾从'能不能实现'变成'故障/权限/合规/迭代'这些非功能属性。
> 2. **机制**:把每类『不靠谱』用确定性机制堵上——状态持久化(Checkpointer + Redis/PG,重启不丢),多租户隔离(thread_id = 租户+会话、向量元数据过滤),权限分级(高危操作审批),审计(append-only 存储 + trace_id 串链路),监控告警与优雅停机、评测/Bad-case 闭环。
> 3. **为什么重要**:它决定了系统能否进企业采购清单——补上可用性、合规、可迭代这些能力,领先的不再是"技术炫技",而是"敢不敢交付给真实用户生产环境"。
> 4. **易错点/常见误解**:别把生产化简化成"能多租户计数 + 能 Docker 跑起来"——真正的生产指标是"故障能发现、状态不丢、数据能对齐、能力能越改越好"。也常有人以为"功能越多越生产",恰恰相反,克制地收敛 scope、把底线机制做扎实才更接近生产。
## 学习内容详情
### 1. 项目要点(完整工程落地)
- **骨架**:意图分流 → 知识问答(RAG,复用 Level2)→ 满足不了 → 转人工 / 建工单(复用 Level4 的 SQL 与数据能力)。
- **多租户隔离**:`thread_id = 租户 ID + 会话 ID`;向量库元数据过滤实现租户级隔离(对照阶段六客服与阶段四向量库)。
- **状态持久化**:Checkpointer + 存储后端(Redis / Postgres);服务重启任务状态不丢(对照阶段五断点、阶段七部署)。
- **权限控制**:敏感操作(查订单 / 工单)按角色权限分级;高危动作人工审批。
- **监控告警**:任务成功率 / LLM 失败率告警 + 完整链路日志(对照阶段七监控)。
- **部署**:Docker Compose 一键拉起「应用 + worker + Redis + PG + Qdrant」(对照阶段七 docker-compose);生产规模上 K8s + HPA(呼应[阶段七 02《部署与伸缩》](../07-阶段七-工程化部署与运维/02-部署与伸缩.md)),Docker Compose 用于开发与演示。
> 🔬 **深度理解 · 多租户隔离(Multi-Tenancy)**:
> 1. **本质**:多租户隔离是在"一套系统服务多个客户(租户)"的同时,保证 A 租户的数据/会话/权限**在逻辑与物理上都不可见于 B 租户**——它不是"多用户登录",而是"租户级的数据边界"。
> 2. **机制**:落地靠"身份贯穿 + 滤波贯穿"——每个请求都解析出租户(`thread_id = 租户+会话`),状态层按租户分上下文;检索层用向量库的元数据过滤(每个文档/块带 tenant 字段)只召回本租户内容;再叠加权限分级为租户内/跨租户的高危操作设闸。
> 3. **为什么重要**:这是企业级软件的商业前提(多租户才能规模化售卖给多客户),也是最容**易被忽略导致数据越权的重大事故点**;隔离不好,售后纠纷与合规处罚都来。
> 4. **易错点/常见误解**:最容易漏的是"只做了应用层隔离却漏了检索/缓存/后台导出的隔离",让 B 租户通过向量检索或工单后台看到 A 租户数据;另一个误区是"用 thread_id 隔离就够"——必须贯穿状态、检索、数据库查询、文件/后台全链路,处处带租户条件。
> ⏳ **短期可不深究**:K8s + HPA(水平自动扩缩容)这套容器编排的生产细节,第一遍知道"It 是用来在更大流量下弹性部署/扩容的手段"即可;当前用 Docker Compose 跑通单机部署已经够完成学习,K8s 等真到数十倍流量/多副本的规模再系统学,属于"按需进阶"的环节。
### 2. 必须落地的工程实践
- **评测闭环**:自建评测集 + Bad-case 队列 + 回归测试(改 prompt 重跑评测,对照阶段五评测 + 阶段七 Bad-case 闭环)。
- **优雅停机**:发布时在途请求不切断(对照阶段七调用优雅停机机制)。
- **满意度回流**:低分会话自动进 Bad-case 队列(写 Click 埋点,异步入队)。
- 文档交付与复盘:项目文档 + 每周末复盘。
> ⏳ **短期可不深究**:埋点上报的具体实现(事件打点字段怎么设计、ClickHouse 这类分析库的建表/聚合写法、异步入队用哪套 MQ)第一遍知道"要记录低分会话并回流"即可,等真正做用户行为分析平台再细化,属于数据/基础设施侧的可选加分项。
```python
def thread_key(tenant_id: str, session_id: str) -> str:
"""多租户 + 会话的状态签名: 每个租户每个会话独立上下文"""
return f"{tenant_id}:{session_id}"
```
### 3. 合规与审计(企业级必选项)
企业级与「能跑」的分水岭不是功能数量,而是合规能力——缺这一节,系统进不了企业采购清单。
**a) 审计日志**:所有敏感操作(查订单、创建工单、权限变更、转人工)统一记录四要素——**谁**(user_id)、**何时**(时间戳 + trace_id 串联完整链路)、**做了什么**(工具 + 参数)、**结果**(成功 / 失败 + 摘要)。审计日志落**独立只追加(append-only)存储**,不与业务日志混放(业务日志滚动清理,审计日志须可追溯数年)。
```python
import json, time
def audit_log(user_id, trace_id, action, params, ok, summary, sink) -> None:
"""敏感操作审计: 谁/何时/做了什么/结果 —— 独立 append-only 存储"""
sink.append(json.dumps({ # 生产: append-only 表/日志桶, 不给 UPDATE/DELETE 权限
"ts": round(time.time(), 3), "user_id": user_id, "trace_id": trace_id,
"action": action, "params": params, # 如 {"tool": "query_order", "order_id": "A1024"}
"result": "ok" if ok else "fail", "summary": summary[:100],
}, ensure_ascii=False))
# 查订单 / 建工单 / 权限变更 / 转人工 四类敏感操作出口统一调用
audit_log("u_1001", "tr_8f2a", "query_order", {"order_id": "A1024"},
ok=True, summary="返回脱敏后订单摘要", sink=audit_store)
```
**b) PII 与数据分级**:三级——**明文**(非敏感业务标识,如订单号)/ **掩码**(默认展示层,手机号 138****1234)/ **加密**(原文密文落库,授权后解密)。手机号默认掩码展示,**完整值仅授权角色可见**(客服主管,或用户本人核身通过后),对照阶段六客服的 PII 脱敏小节。
**c) 数据驻留与保留期限**:GDPR / PIPL 要求数据不出境 / 境内存储——选境内区域 + 自托管观测(LangFuse 而非境外 SaaS);用户有权请求数据删除(被遗忘权)。对话记录设保留期限(如 **180 天**)到期自动清理——定时任务同时清掉 PG 与向量库里的副本(对照阶段四:入库的 embedding 也是个人数据)。
> ⚠️ **合规是采购评审的否决项**:企业采购评审里安全与合规一票否决——功能再花哨,没有审计日志与数据分级直接出局。Level5 演示至少要落地**审计日志**这一项。
## 本节验收清单
- [ ] Docker Compose 一键部署整套环境并跑通
- [ ] 状态落库 + 中断恢复验证(重启进程任务不丢)
- [ ] 有多租户隔离与权限分级
- [ ] 敏感操作有独立审计日志(append-only,可用 trace_id 串起完整链路)
- [ ] 有完整链路日志 + 至少一项业务监控告警
- [ ] 有自建评测集并跑过一轮迭代闭环
## 排期与前置依赖
- **前置**:Level2(RAG)与 Level4(SQL 与数据)是能力底座;阶段七工程化是工程底座。
- **建议排期**:第 15-16 周,6-8 周(可与 Level4 收尾并行)。
- **毕业判定**:这份系统能独立部署、能告警自愈、能靠 Bad-case 闭环持续变好 > 功能堆得多。
## 阶段八整体补充建议
- Level 1-2 对应计划第 7-10 周(见 [四个月学习计划](../09-四个月学习计划.md))。
- Level 3-5 建议在掌握基础后串行攻坚,同一项目同时沉淀其 Bad-case 与评测脚本。
- 五个 Level 与前面阶段的能力对应:Level1→阶段二三、Level2→阶段四、Level3→阶段五、Level4→阶段六、Level5→阶段七。**每做一个 Level,就是一次对前面知识的大串讲**。
## 本节常见面试题(深度解析)
> 针对本节核心知识的面试高频点,配合"本质+机制"式理解,能让你答得既有深度又有广度。
### 面试题 1:多租户场景下,如何确保 A 租户的数据不会被 B 租户查到?你会在哪些层做隔离?
- **面试官想考察**:你是否把多租户当作"贯穿全链路的数据边界"来设计,而非只在登录层做个标识。
- **专业作答(含深度)**:
1. 先说本质:多租户 = 身份贯穿(每个请求解析出 tenant)+ 滤波贯穿(每一层查询都带 tenant 条件),目标是租户级不可越权。
2. 分四层展开:状态层(`thread_id = 租户+会话`,上下文按租户隔离);检索层(向量库元数据过滤,仅召回本租户文档块);数据库层(SQL 处处带租户条件 + 行级权限);后台/文件层(工单、导出、缓存不跨租户)。
3. 点出常见缺口:只做应用层而漏了检索/缓存/后台导出,是越权事故的高发点;隔离要"处处带租户条件",不是"在某一个面加一把锁"。
4. 补充测试意识:越权用例(用 B 租户身份访问 A 租户资源)应纳入验收清单。
- **加分亮点 / 深度追问**:可主动提"过滤的默认行为"——宁可查不到也不跨租户可查,检索兜底要做对;追问"多租户与多用户登录的关系"时可答"多用户是身份,多租户是数据边界,二者正交叠加"。
### 面试题 2:为什么敏感操作的审计日志必须用 append-only 存储,并用 trace_id 串起完整链路?
- **面试官想考察**:你是否理解审计日志与业务日志在"可信、可追溯"上的根本差异。
- **专业作答(含深度)**:
1. 审计日志要能回答"谁、何时、做了什么、结果如何",且**不可被事后篡改**——append-only(只追加、不给 UPDATE/DELETE 权限、物理上不滚动清理)才能保证证据可信,这是它与可清理的业务日志最本质的区别。
2. 什么时候记:只记敏感操作(查订单、建工单、权限变更、转人工)并记录"工具+参数+结果摘要",不过度记录以免噪声淹没关键链路。
3. trace_id 的作用:把一次用户请求跨多个服务/规约环节的日志串成一条完整链路,任何一环出问题都能端到端定位,配合只追加存储形成"完整、不可变"的证据链。
4. 合规加成:这直接对应 GDPP/PIPL 与采购评审对"可审计、可追责"的要求,是企业能进采购清单的前提。
- **加分亮点 / 深度追问**:可对比"审计日志(append-only、不可改)vs 业务日志(滚动清理、可变)"的取舍;追问"日志也含 PII 怎么办"时可答"敏感字段脱敏后入库 + 完整值仅授权角色可见"。
### 面试题 3:一个客服 Agent 上线后怎么保证它能"越用越好",而不是上线即封版?
- **面试官想考察**:你是否具备线上迭代闭环(Evaluate-Bad-case-回归)的工程思路,而不是只会交付功能。
- **专业作答(含深度)**:
1. 闭环起点:建一套自建评测集 + Bad-case 队列,把"答错的、发生率低的、新出现的反例"收集起来。
2. 迭代机制:每次改 prompt/检索/业务规则都重跑回归测试,量化评估"是否真的变好",用数据而非感觉决定是否上线。
3. 主动回流:满意度低分会话异步入队,形成"线上真实信号 → 修复 → 回归"的正向循环,让系统适配真实用户分布。
4. 兜底保障:发布走优雅停机(在途请求不切断),监控告警兜底,出事能发现、能回滚。
- **加分亮点 / 深度追问**:可把"评测集要防腐坏"(防"把评测集背进去反而过拟合")作为进阶点,或用"Bad-case 队列就是你的微调/提示优化燃料"来串联多级能力;追问"如何衡量变好"可答"用技能指标(准确率、分流成功率、转人工率下降)对齐业务目标"。
@@ -0,0 +1,154 @@
# 阶段八 · 综合实战:五级项目路线导航器(离线可运行)
> 所属:阶段八 从入门到生产的实战项目路线
> 定位:阶段八是整份学习计划的收尾,用一个「五级项目导航器」把五个 Level 的递进关系、前置依赖、能力覆盖、排期串成一张可执行的路线图——你做完每一级就勾掉一格,导航器提醒你下一步补哪些前置。它是阶段八五篇项目文档的地图。
## 一句话看懂本 Demo
`project_roadmap_navigator.py` 用纯 Python 标准库,把阶段八五级项目组织成一份可运行的路线导航器:
```mermaid
graph TD
A["阶段八综合实战<br/>project_roadmap_navigator.py"] --> B[Part1 五级递进路线<br/>依赖前置]
A --> C[Part2 能力覆盖图<br/>重学前置索引]
A --> D[Part3 进度跟踪<br/>打卡→下一步]
A --> E[Part4 排期映射<br/>对齐16周计划]
```
> 核心一句话:**实战项目最怕的不是难,而是不知道现在该做什么、缺什么前置**。这个导航器把「先修哪个阶段 → 再做哪个 Level → 覆盖什么能力」固化成一张可勾选的地图。
> 🔬 **深度理解 · 五级项目路线的递进关系与"从 Demo 走向生产"**:
> 1. **本质**:五个 Level 不是"五个并列的作业",而是一条**递进的能力爬升带**——每一级都是上一级的知识底座加上一层新的核心心智,前级的产出物(Agent 循环、RAG、多智能体分工、SQL 安全)被后级复用在更大的系统里。
> 2. **递进机制**:Level1 打通"Agent 循环"这个最底层的骨架;Level2 给 Agent 接上"知识检索(RAG)";Level3 升级为"多 Agent 分工协作";Level4 转向"结构化数据 + 安全性(Text-to-SQL + 五道防线)";Level5 把前四者的能力凝成"一个能上线、能扩、能迭代的生产系统"。每上一级,复杂度从'实现算法'上升到'管理工程与安全'。
> 3. **如何从 Demo 走向生产**:不是"功能变多",而是逐级引入生产属性——状态不丢、权限不漏、故障可控、数据可追;Level 1-4 更多是"把能力跑通(Demo)",Level5 是"把可靠性、合规、迭代闭环补齐(生产)",这也是为什么 Level5 是毕业设计。
> 4. **易错点/常见误解**:别把"跳级"当捷径——每级的前置依赖是硬性的(如做 Level5 必须已有 RAG + SQL + 工程化底座),跳级常因前置能力未建而返工;也别把"Demo 跑通"误当作"生产就绪",两者差在可靠性/合规/可迭代这些非功能属性上。
## 运行方式
```
python3 code/阶段八/project_roadmap_navigator.py
```
不需要 API Key、不需要外网、不需要装任何第三方库(只依赖标准库)。
## 完整代码位置
[code/阶段八/project_roadmap_navigator.py](../../code/阶段八/project_roadmap_navigator.py)
---
## 每个 Part 在讲什么
### Part 1 · 五级递进路线(对应 5 篇 Level 文档)
用 `LEVELS` 数据结构描述五个项目:「难度 / 周期 / 前置依赖 / 覆盖能力 / 关联 Demo」。它把五篇项目文档([Level1](01-Level1-ReAct智能问答Agent.md) 到 [Level5](05-Level5-企业智能客服Agent.md))的骨架抽出来,一眼看清递进关系:
```python
LEVELS = [
{"id": 1, "name": "ReAct 智能问答", "difficulty": "入门", "weeks": "1-2 周",
"inherits": ["阶段二 ReAct", "阶段三 LangGraph"], # 前置
"skills": ["手写Agent循环", "工具调用", "状态流转", "解析异常"]},
...
]
```
运行输出的要点:**每个 Level 必须先消化它的"依赖前置"里的阶段,才能顺利开工**。
### Part 2 · 能力覆盖图(重学前置索引)
把每个 Level 会用到的能力列出,帮你建立「做项目时该回去复习哪篇」的索引。例如 L4 数据分析要复用「Text-to-SQL / 五道防线」,对应回头读阶段六小点 2。
### Part 3 · 进度跟踪(打卡 → 下一步)
`RoadmapTracker` 记住你勾掉的 Level,自动给出「下一个应做的项目」和「还缺哪些前置阶段」:
```python
class RoadmapTracker:
def __init__(self, levels):
self.done = set() # 已完成的 Level 编号
def mark_done(self, level_id):
self.done.add(level_id) # 做完一个就打卡
def next_up(self):
for lv in self.levels: # 找未完成中编号最小者
if lv["id"] not in self.done:
return lv
def missing_prereq(self, lv, stage_done):
# 截取 "阶段X" 前缀(兼容 "阶段二 ReAct" 与 "阶段01-数据分析" 两种命名),
# 检查是否已在已掌握阶段集合里
missing = [it for it in lv["inherits"]
if it.startswith("阶段")
and it.split("-")[0].split(" ")[0] not in stage_done]
return missing
```
> ⏳ **短期可不深究**:`missing_prereq` 里"截取『阶段X』前缀来兼容两种命名('阶段二 ReAct' 与 '阶段01-数据分析')"这种字符串解析的小 hack,第一遍看思路即可——它只是为了统一命名格式而做的容错,不是本项目主线,不需要逐行背下来。
运行输出演示:已完成 L1、L2 且只掌握阶段二~四时,导航器会建议「下一步 L3」并提示「仍缺前置:阶段五、阶段六 → 先去消化再开工」。这正是很多学习者会踩的坑——**跳级做高 Level,却发现前置能力还没建起来**。
### Part 4 · 排期映射(对齐四个月学习计划)
把每个 Level 的周数区间画成进度条,与 [四个月学习计划](../09-四个月学习计划.md) 对齐,让你知道本周该在哪个 Level 上发力。
> ⏳ **短期可不深究**:这个 Demo 用纯标准库手画"进度条"的终端渲染细节(字符宽度、填充、对齐)只是教学展示用的实现技巧,第一遍不用纠结它画得漂不漂亮,重点是理解"排期对齐"这个学习规划的思路;真要好看的图表,交给前端或现成库即可。
---
## 运行结果预览
```
阶段八 · 五级项目路线(从入门到生产)
L1 [入门] ReAct 智能问答 (1-2 周) ->
L2 [进阶] 知识库 RAG (2-3 周) ->
L3 [高级] 多角色内容创作 (3-4 周) ->
L4 [实战] 数据分析 SQL Agent (4-6 周) ->
L5 [生产] 企业智能客服 (6-8 周)
...
[进度跟踪] 当前已掌握: 阶段二~四 → 建议下一步 L3, 但仍缺前置: 阶段五、阶段六
```
## 怎么用它来规划自己的学习
| 场景 | 用法 |
|-|-|
| 刚开始阶段八 | 先从 Part 1 看五级递进,决定从哪个 Level 切入 |
| 卡在某一级 | 用 Part 2 能力覆盖图,回读对应前置阶段文档补课 |
| 觉得自己能跳级 | 跑 Part 3,看导航器提示缺哪些前置 |
| 规划每周时间 | 对照 Part 4 排期条,锁定本周要攻坚的 Level |
## 本节自检
- [ ] 能只靠 Part 1 说清五级项目的递进关系
- [ ] 知道每个 Level 前置依赖的是哪些阶段(Level1→阶段二三 … Level5→阶段七)
- [ ] 能用 Part 2 说出:做 L4 数据分析前该回去读哪篇
- [ ] 已跑通导航器,并用它规划了自己下一步要做的 Level
## 本节常见面试题(深度解析)
> 针对本节核心知识的面试高频点,配合"本质+机制"式理解,能让你答得既有深度又有广度。
### 面试题 1:请讲清楚这五个 Learn 的递进关系,以及每一级分别复用了前级的哪些能力。
- **面试官想考察**:你是否把五级当作一条"能力递进链"而非五个孤立项目,能否说清每级解决了什么问题、又为后级提供了什么。
- **专业作答(含深度)**:
1. 逐级推进:Level1 打通 Agent 基础循环(思考-行动-观察);Level2 给循环接上知识检索(RAG,复用 Level1 的 Agent 编排);Level3 上升为多 Agent 分工(复用前面循环+检索,叠加 Supervisor 调度);Level4 转向结构化 DB(Text-to-SQL + 五道防线,复用 Agent 工具调用);Level5 把上述能力凝成生产系统(复用 RAG、SQL、工程化、监控、评测)。
2. 抽出主线:本质是"同一种 Agent 能力在不同复杂度场景的复用与加厚"——每级都在前级底座上加一个新的能力维度和一类工程质量。
3. 关联前置阶段:Level1↔阶段二三、Level2↔阶段四、Level3↔阶段五、Level4↔阶段六、Level5↔阶段七,每级都是前面知识的综合演练。
4. 落点:真正的收获不是"做了五个 Demo",而是"每一级整合一次前面的知识,最终能自己组装出可上线的系统"。
- **加分亮点 / 深度追问**:可主动把"递进"抽象为"从实现算法 → 管理数据 → 协调多体 → 守护安全 → 掌控工程"的能力维度叠加;追问"为什么 Level5 是毕业设计"时可答"因为它要求前面所有非功能属性(可靠性/合规/可迭代)同时到位"。
### 面试题 2:为什么要"先修前置阶段,再做对应 Level",跳级会带来什么后果?
- **面试官想考察**:你是否真正理解"能力依赖"而非背下结论,以及能否说清跳级的具体代价。
- **专业作答(含深度)**:
1. 依赖关系为何必要:高级 Level 直接调用前级的"心智模型"(如没有"独立上下文"概念就无法理解多 Agent 里的 supervisor;不懂五道防线就做不了可上线的 SQL Agent),前置缺失时项目会变成"装样子跑通"。
2. 跳级的代价展开:返工(缺失能力导致推倒重来)、误判(把"跑通"当"会了",实际不懂底层设计)、连带失败(前置能力建立后才发现高级设计要推翻)。
3. 用导航器落地:RoadmapTracker 的 `missing_prereq` 正是把这种依赖"程序化"——它提醒你补哪些前置,而不是让你凭感觉跳级。
4. 结论:合理路径是"前置已握 → 再做该 Level",这也是为什么文档明确"每个 Level 必须先消化它的依赖前置里的阶段才能顺利开工"。
- **加分亮点 / 深度追问**:可补充"我这里会跳过与本职业场景无关的前置,但对直接承担任务的 Level 前置绝不跳"的务实取舍;追问"何时可以适度并行"时可答"低耦合的前置(如基础 RAG)可与后续 Level 平行推进,但门槛性的(如 SQL 安全)必须先立"。
### 面试题 3:这份导航器把"从 Demo 走向生产"做了怎样的固化?它适合怎么用于真实项目规划?
- **面试官想考察**:你是否理解"把学习/项目路线结构化、可追踪"的工程化规划思维,而不只把它当一个小脚本。
- **专业作答(含深度)**:
1. 它固化的不是代码,而是"递进关系 + 前置依赖 + 能力覆盖 + 排期"四类元信息——把隐性的能力因果显式化成可查询、可勾选的地图。
2. 四个 Part 对应四种规划动作:看递进(该从哪个 Level 切入)、查能力覆盖(做某级该回读哪篇)、查前置(能不能跳级)、对齐排期(本周攻哪个)。
3. 迁移价值:同样的"依赖建模 + 进度跟踪"思路可直接用于真实项目/团队——把任务依赖、前置技能、里程碑排期用同样的结构化数据管起来,避免"凭感觉排期、缺少约束导致延期"。
4. 与生产的连接:这个"缺失前置就提示补齐"的机制,和 Level5 里"Bad-case 缺失就回流补齐"其实是同一种"缺口检测+补课"的循环思想。
- **加分亮点 / 深度追问**:可谈到"把路线数据化后可以做风险预测(哪些 Level 可能卡人)",或"这套导航思想可演化为知识图谱/依赖图来承载更多课程";追问"导航器对真实生产的局限"时可答"它是静态依赖,真实项目还有动态/并行依赖,需人工补充判断"。