agent_proj/docs/INTERVIEW_PREP.md

388 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 面试知识点总结
> 基于本项目的技术栈,总结面试常问知识点
---
## 一、LangChain 核心知识点
### 1.1 LangChain Agent 机制
#### Q1: 什么是 LangChain Agent? 它与 Chain 的区别?
| 特性 | Chain | Agent |
|------|-------|-------|
| 执行方式 | 固定流程,按顺序执行 | 动态决策,自主选择下一步 |
| 工具调用 | 预定义,需手动编写 | 自动判断是否调用工具 |
| 适用场景 | 固定流程 (如 RAG) | 需要推理和决策的场景 |
**项目中的应用**:
```python
# 使用 create_agent 创建 Agent
agent = create_agent(
model=ChatTongyi(model="qwen3-max"),
tools=[rag_summarize, get_weather, get_user_id],
system_prompt="你是一个智能助手"
)
```
#### Q2: 解释 ReAct 框架在 Agent 中的应用
**ReAct = Reasoning + Acting**
```
Thought: 我需要知道用户所在城市的天气
Action: get_weather
Action Input: 深圳
Observation: 天气晴朗26°C
Thought: 现在我有天气信息,可以回答用户问题了
```
**项目中的体现**:
- 系统提示词明确要求遵循 ReAct 框架
- Agent 自动完成 "思考→行动→观察→再思考" 循环
- 最多支持 5 次工具调用
### 1.2 LangChain Middleware 中间件机制
#### Q3: LangChain 中间件是什么? 如何实现?
LangChain 中间件是 LangGraph 提供的钩子机制,用于在 Agent 执行过程中注入自定义逻辑。
**项目中的三种中间件**:
1. **wrap_tool_call** - 工具调用包装
```python
@wrap_tool_call
def monitor_tool(request, handler):
# 工具调用前
logger.info(f"执行工具: {request.tool_call['name']}")
result = handler(request) # 调用实际工具
# 工具调用后
return result
```
2. **before_model** - 模型调用前
```python
@before_model
def log_before_model(state, runtime):
# 每次调用 LLM 前记录日志
logger.info(f"即将调用模型,当前有 {len(state['messages'])} 条消息")
return None
```
3. **dynamic_prompt** - 动态提示词
```python
@dynamic_prompt
def report_prompt_switch(request):
is_report = request.runtime.context.get("report", False)
if is_report:
return load_report_prompts() # 切换为报告生成 Prompt
return load_system_prompts()
```
#### Q4: 中间件的应用场景有哪些?
| 场景 | 中间件类型 |
|------|-----------|
| 日志记录 | before_model, wrap_tool_call |
| 性能监控 | wrap_tool_call |
| 动态提示词 | dynamic_prompt |
| 权限控制 | wrap_tool_call |
| 结果缓存 | wrap_tool_call |
---
## 二、RAG (检索增强生成)
### 2.1 RAG 核心流程
```
用户 query
┌─────────────────┐
│ 向量检索 │ ← Chroma Retriever
└────────┬────────┘
│ 返回 Top-K 相关文档
┌─────────────────┐
│ 构建 Prompt │ ← 拼接 query + context
└────────┬────────┘
┌─────────────────┐
│ LLM 生成回答 │ ← 通义千问
└────────┬────────┘
返回结果
```
### 2.2 关键面试题
#### Q5: 为什么需要 RAG? 直接用 LLM 不可以吗?
| 方案 | 优点 | 缺点 |
|------|------|------|
| 直接 LLM | 简单 | 知识截止、可能幻觉、无法访问私域知识 |
| RAG | 实时性、可引用私域知识、减少幻觉 | 增加复杂度、依赖检索质量 |
#### Q6: RAG 中的关键环节有哪些?
1. **文档加载**: PyPDFLoader, TextLoader
2. **文本分片**: RecursiveCharacterTextSplitter
- chunk_size: 每片大小
- chunk_overlap: 重叠区域 (保持上下文)
- separators: 分隔符优先级
3. **向量化**: Embedding 模型
4. **向量存储**: Chroma
5. **相似度检索**: Cosine similarity, Top-K
6. **结果拼接**: Query + Context → Prompt
#### Q7: 如何优化 RAG 效果?
| 优化方向 | 方法 |
|----------|------|
| 检索质量 | 调整 chunk_size、overlap、使用 better embedding |
| 召回率 | 增加 Top-K、使用混合检索 |
| 排序rerank | 使用 rerank 模型二次排序 |
| Prompt 工程 | 优化 RAG Prompt 模板 |
### 2.3 项目中的 RAG 实现
```python
# rag_service.py
class RagSummarizeService:
def rag_summarize(self, query: str) -> str:
# 1. 向量检索
context_docs = self.retriever.invoke(query)
# 2. 拼接上下文
context = ""
for doc in context_docs:
context += f"[参考资料]: {doc.page_content} | {doc.metadata}\n"
# 3. 调用 LLM 生成
return self.chain.invoke({
"input": query,
"context": context
})
```
---
## 三、向量数据库 (Chroma)
### 3.1 Chroma 核心概念
| 概念 | 说明 |
|------|------|
| Collection | 类似表,存储一类文档 |
| Embedding Function | 向量化函数 |
| Document | 包含 page_content 和 metadata |
| Retriever | 检索器,支持相似度搜索 |
### 3.2 面试题
#### Q8: Chroma 的优势?
- 轻量级,易于部署
- Python 原生,集成方便
- 支持持久化存储
- 与 LangChain 无缝集成
#### Q9: Chroma 与其他向量库 (Milvus/Pinecone) 的区别?
| 特性 | Chroma | Milvus | Pinecone |
|------|--------|--------|----------|
| 部署方式 | 本地/嵌入 | 服务端 | SaaS |
| 规模 | 中小 | 大规模 | 大规模 |
| 成熟度 | 一般 | 高 | 高 |
---
## 四、Streamlit Web 开发
### 4.1 项目中的应用
```python
# app.py
import streamlit as st
st.title("智扫通智能机器人客服")
# 会话状态管理
if "agent" not in st.session_state:
st.session_state["agent"] = ReactAgent()
# 聊天记录
for message in st.session_state["message"]:
st.chat_message(message["role"]).write(message["content"])
# 用户输入
prompt = st.chat_input()
# 流式输出
if prompt:
stream = agent.excute_stream(prompt)
st.chat_message("assistant").write_stream(capture(stream))
```
### 4.2 关键面试题
#### Q10: Streamlit 的核心机制?
- **声明式 UI**: 通过 st.xxx() 声明组件
- **脚本式**: 每次交互重新运行整个脚本
- **状态管理**: session_state 保持会话状态
- **热重载**: 修改代码自动刷新
#### Q11: 如何实现流式输出?
```python
# 方法1: write_stream
st.write_stream(generator_function)
# 方法2: 自定义 (本项目使用)
def capture(generator, cache_list):
for chunk in generator:
cache_list.append(chunk)
for char in chunk:
time.sleep(0.05) # 模拟打字效果
yield char
```
---
## 五、设计模式
### 5.1 工厂模式 (Factory Pattern)
```python
# model/factory.py
class BaseModelFactory(ABC):
@abstractmethod
def generator(self) -> Optional[Embeddings | BaseChatModel]:
pass
class ChatModelFactory(BaseModelFactory):
def generator(self) -> Optional[BaseChatModel]:
return ChatTongyi(model=rag_conf["chat_model_name"])
class EmbeddingsFactory(BaseModelFactory):
def generator(self) -> Optional[Embeddings]:
return DashScopeEmbeddings(model=rag_conf["embeddings_model_name"])
```
**好处**: 统一创建入口,便于后续更换模型
### 5.2 配置中心化
所有配置集中在 config/ 目录的 YAML 文件中:
- rag.yaml: 模型配置
- chroma.yaml: 向量库配置
- agent.yaml: Agent 配置
- prompts.yaml: Prompt 路径配置
### 5.3 中间件模式
利用装饰器和钩子实现横切关注点:
- 日志
- 监控
- 动态提示词切换
---
## 六、工程实践
### 6.1 日志管理
```python
# utils/logger_handler.py
def get_logger(name: str = "Agent"):
logger = logging.getLogger(name)
# 双写: 控制台 + 文件
console_handler = logging.StreamHandler()
file_handler = logging.FileHandler(log_file, encoding='utf-8')
return logger
```
### 6.2 路径管理
```python
# utils/path_tool.py
def get_project_root():
cur_file = os.path.abspath(__file__)
proj_dir = os.path.dirname(os.path.dirname(cur_file))
return proj_dir
def get_abs_path(relative_path):
return os.path.join(get_project_root(), relative_path)
```
### 6.3 MD5 去重
```python
# vector_store.py
# 通过 MD5 避免重复加载文档
md5_hex = get_file_md5_hex(path)
if check_md5_hex(md5_hex):
continue # 已存在,跳过
self.vector_store.add_documents(split_doc)
save_md5(md5_hex)
```
---
## 七、LLM & Embedding
### 7.1 通义千问 (Qwen)
- **模型**: qwen3-max (阿里云)
- **调用**: langchain_community.chat_models.tongyi.ChatTongyi
### 7.2 DashScope Embedding
- **模型**: text-embedding-v4
- **用途**: 将文本转为向量
- **调用**: langchain_community.embeddings.DashScopeEmbeddings
---
## 八、常见面试扩展问题
### Q12: 如何保证 Agent 工具调用的安全性?
1. **工具入参校验**: Pydantic 类型提示
2. **调用次数限制**: 最多 N 次
3. **工具白名单**: 只允许调用指定工具
4. **中间件监控**: 记录所有调用
### Q13: Agent 如何实现"思考过程"可视化?
```python
# 项目中的实现
for chunk in res:
last_msg = chunk["messages"][-1]
if last_msg.tool_calls:
# 显示思考过程
print(f"工具调用: {last_msg.tool_calls}")
```
### Q14: RAG 召回率低怎么排查?
1. 检查 chunk_size 是否合适
2. 检查 embedding 质量
3. 查看检索到的文档是否相关
4. 调整 Top-K 值
5. 检查分片是否有意义 (避免切断句子)
### Q15: 生产环境部署注意什么?
1. **API 限流**: 添加重试机制
2. **错误处理**: 工具调用失败处理
3. **日志**: 完整日志记录
4. **监控**: 调用次数、耗时监控
5. **缓存**: 热门 query 缓存结果