AndyGuffey/pgdip-ai-study
GitHub: AndyGuffey/pgdip-ai-study
一个系统化涵盖 RAG 全链路演进、LLM 安全防护演示及多智能体编排的 PGDip 课程实践脚本合集。
Stars: 0 | Forks: 0
# PGDip 学习代码 — RAG 与 LLM 安全
探索向量搜索、embeddings、检索增强生成 (RAG) 以及 LLM 安全的学习脚本合集,大致按照课程中每周/每天的顺序进行排列 (`w2_d4`, `w3_d1`, `w3_d2`, `w3_d3`, `w3_d4`, `w4_d1`, `w4_d2`, ...)。
## 按文件划分的主题
点击主题即可展开并查看逐文件的详细信息。
## 设置
`.venv` 中已经设置好了虚拟环境。要安装/更新依赖项:
```
python3 -m venv .venv # only needed if .venv doesn't exist yet
./.venv/bin/pip install -r requirements.txt
```
这些脚本中使用的核心依赖:
```
sentence-transformers
torch
numpy
networkx
matplotlib
langchain-core
langchain-text-splitters
langchain-community
langchain-huggingface
faiss-cpu
chromadb # w2_d4_vector_db_example3.py only
langchain-openai # w3_d1_rag_demo.py and w3_d2_rag2_demo.py only
openai # w3_d4_demo.py, w4_d1_openai_safe.py, w4_d2_small_agent.py, w4_d2_full_demo.py, w4_d3_multi_agent_demo.py, w4_d4_toy_calc_tool.py (uses the OpenAI SDK directly)
transformers # w4_d1_local_llm_injection.py only (local gpt2 model)
python-dotenv # w4_d3_multi_agent_demo.py and w4_d4_toy_calc_tool.py only (loads OPENAI_API_KEY from a .env file)
```
### API 密钥
`w3_d1_rag_demo.py`, `w3_d2_rag2_demo.py`, `w3_d4_demo.py`, `w4_d1_openai_safe.py`, `w4_d2_small_agent.py` 和 `w4_d2_full_demo.py` 会调用 OpenAI API,并期望在文件顶部的 `my_api_key` / `api_key` 变量中填入 key。**请勿提交真实的 API keys。** 在将此 repo 推送到 GitHub 之前,最好将 `OPENAI_API_KEY` 设置为环境变量或从 `.env` 文件(未被追踪)中加载,而不是将其硬编码。
`w4_d3_multi_agent_demo.py` 和 `w4_d4_toy_calc_tool.py` 已经遵循了该建议:它们(通过 `python-dotenv`)从未被追踪的 `.env` 文件中加载 `OPENAI_API_KEY`,而不是使用硬编码的变量 —— 在运行它们之前,请创建一个包含 `OPENAI_API_KEY=your-api-key-here` 的 `.env` 文件。
`w4_d1_local_llm_injection.py` 完全在本地运行(首次运行时通过 `transformers` 下载 `gpt2`),不需要 API key。
`w4_d4_open_ai_fun_call.py` 仅定义了一个工具 schema —— 它不调用 OpenAI API,也不需要 key。
## 运行脚本
```
./.venv/bin/python w3_d3_rag3_simple_rerank.py
```
## AI 使用声明
在准备此 repo 时使用了 AI 协助(Claude,通过 Claude Code),具体用于:
- 通过阅读现有脚本,编写上文“按文件划分的主题”部分中每个文件的摘要。
- 根据项目已安装的依赖生成 `requirements.txt`。
- 将项目依赖(matplotlib、openai)安装到本地虚拟环境中。
- 初始化 git 仓库并创建/推送此 GitHub repo。
Python 脚本本身是作者在 PGDip 课程中自己的学习成果。
未使用 AI 编写或修改 `.py` 文件中的代码,也未使用 AI 生成或处理任何真实的 API keys 或凭据 —— `my_api_key 占位符被有意留空(参见上文的 API keys 说明)。
分块与 embeddings
- **[d3_chunk_demo.py](d3_chunk_demo.py)** — RAG pipeline 前半部分的独立演示:基于词的重叠分块,使用 `sentence-transformers` 对块进行 embedding,以及对生成的向量进行余弦相似度搜索。不涉及向量数据库或 LLM —— 适合单独观察分块和语义搜索。向量数据库
- **[w2_d4_vector_db_example3.py](w2_d4_vector_db_example3.py)** — 使用 ChromaDB 作为向量存储:对带有丰富元数据的文档进行 embedding 和存储,通过相关性评分进行查询,根据访问控制字段 (`sensitivity`) 过滤结果,以及为了实现规模扩展将 collection 分片到多个 ChromaDB collection 中。RAG 基础 (RAG 1.0)
- **[w3_d1_rag_example_1.py](w3_d1_rag_example_1.py)** — 最基础的 RAG 示例:使用 `HuggingFaceEmbeddings` 对几个句子进行 embedding,将它们存储在 FAISS 中,并检索与查询最匹配的前几项。仅包含检索,不包含生成。 - **[w3_d1_rag_demo.py](w3_d1_rag_demo.py)** — 完整的端到端 RAG pipeline:文档分块 (`RecursiveCharacterTextSplitter`) → embeddings → FAISS 向量存储 → 检索器 → OpenAI LLM (`gpt-4o-mini`) → 生成带有来源追溯的答案。需要 OpenAI API key。混合检索 (RAG 2.0)
- **[w3_d2_rag2_demo.py](w3_d2_rag2_demo.py)** — 将稀疏关键词搜索 (BM25) 与稠密向量搜索 (FAISS) 结合成一个简单的混合检索器,并排比较每种方法的结果,然后将合并后的上下文提供给 OpenAI LLM 以生成答案。需要 OpenAI API key。重排序与图谱检索 (RAG 3.0)
- **[w3_d3_rag3_reranking_ex.py](w3_d3_rag3_reranking_ex.py)** — 最精简的重排序示例:使用 `CrossEncoder` 根据查询对固定的已检索文档列表进行评分,并按相关程度顺序打印出来。 - **[w3_d3_rag3_example](w3_d3_rag3_example)** — 使用 `networkx` 构建文档相似度图谱(当余弦相似度超过阈值时添加边),并使用 `matplotlib` 进行可视化。 - **[w3_d3_rag3_simple_rerank.py](w3_d3_rag3_simple_rerank.py)** — 将所有内容整合在一起:一个 `SimpleRAG3` 类,通过知识图谱遍历(embeddings + 手动定义的文档连接)检索候选内容,使用 `CrossEncoder` 对其进行重排序,组装上下文字符串,并渲染高亮显示已检索节点的知识图谱(保存到 `rag3_simple.png`)。带引用的置信度门控 RAG (RAG 4.0)
- **[w3_d4_confidence_ex1.py](w3_d4_confidence_ex1.py)** — 独立运行的最基础的置信度门控示例:对查询和几个候选文档进行 embedding,将 top-k 余弦相似度平均为一个单独的置信度分数,并根据其是否超过阈值来打印回退消息或“继续执行”消息。不调用 LLM。 - **[w3_d4_demo.py](w3_d4_demo.py)** — 在生成之前添加了置信度门控步骤:从一个小型知识库中检索最匹配项,计算基于相似度的置信度分数,并且仅当置信度超过阈值时才调用 LLM(通过原生 `openai` SDK)—— 否则它将返回“信心不足”的响应,而不是进行猜测。生成的答案带有内联的来源引用(例如 `[RefundPolicy.pdf]`)。如果未设置 key,则回退为打印 prompt 而不调用 API。需要 OpenAI API key。LLM 安全:prompt 注入与模糊测试
- **[w4_d1_local_llm_injection.py](w4_d1_local_llm_injection.py)** — 针对本地 `gpt2` 模型(通过 `transformers` 加载)演示了一个**易受攻击的** prompt 设计:“机密”直接嵌入在纯文本 prompt 中且没有角色隔离,因此可能会在交互式聊天循环中通过 prompt 注入泄露。旨在作为安全反模式以供学习,而不是可复制的模板。 - **[w4_d1_openai_safe.py](w4_d1_openai_safe.py)** — 同样的“不要泄露机密代码”场景,但是构建在 OpenAI 的 chat completions API 之上,使用正确的 `system` 角色,而不是将所有内容拼接到一个 prompt 字符串中。有助于将角色隔离的 prompt 与 `w4_d1_local_llm_injection.py` 中的原始方法进行比较 —— 请注意,仅靠 system prompt 并不能完全抵御注入。需要 OpenAI API key。 - **[w4_d1_prompt_fuzzing_script.py](w4_d1_prompt_fuzzing_script.py)** — Prompt 模糊测试:将一批已知的注入/越狱字符串(system prompt 提取、指令覆盖、“忽略限制”等)通过循环送入 LLM 中,以便审查响应中是否存在护栏失效,而不是每次只测试一个攻击 prompt。**注意:** 这是一个代码片段,它调用了文件中未定义的 `run_llm(...)` 函数 —— 在运行它之前,请将其连接到其他 `w4_d1_*` 脚本(或你自己)中的某个 `ask_llm` / `ask_local_llm` 函数。Agents:计划 → 执行 → 检查
- **[w4_d2_example1.py](w4_d2_example1.py)** — 关于 agent 状态/内存的最基础示例:一个 agent 可以在整个会话期间写入 (`remember`) 和读取 (`recall`) 的键值对存储,而不是仅依赖当前 prompt/context 中的内容。 - **[w4_d2_retry_backoff.py](w4_d2_retry_backoff.py)** — `w4_d2_full_demo.py` 所使用的带有指数退避的重试可靠性模式的独立示例:最多重试不稳定的 mock API 调用 3 次,在两次尝试之间等待的时间逐渐变长(`2 ** attempt` 秒),而不是立即重试或立即失败。 - **[w4_d2_small_agent.py](w4_d2_small_agent.py)** — 最基础的单工具 agent,演示了基本的**计划 → 执行 → 检查**循环:LLM 为查询计划使用哪个工具,代码根据该计划调用 mock 的 `get_weather` 工具,然后在返回最终答案之前检查结果。需要 OpenAI API key。 - **[w4_d2_full_demo.py](w4_d2_full_demo.py)** — 基于相同的计划 → 执行 → 检查循环构建的更完整的单 agent 演示,增加了:两个 mock 工具 (`get_weather`, `check_calendar`),通过 `retry_with_backoff` 实现的可靠性(针对不稳定的工具调用进行带有指数退避的重试),来自 `w4_d2_example1.py` 的 `AgentState` 内存模式(在多轮对话之间记住 `preferred_city`),以及当工具失败或没有工具匹配时的优雅回退响应。以交互式循环运行。需要 OpenAI API key。多 Agent 编排
- **[w4_d3_message_passing.py](w4_d3_message_passing.py)** — Planner → Executor → Verifier 形状的最基础草图:每个阶段都是一个普通函数,它接收前一阶段的字符串输出并返回一个新字符串,不进行 LLM 调用。适合在添加真正的 agents 之前查看 pipeline 的消息传递形状。 - **[w4_d3_agent_disagree.py](w4_d3_agent_disagree.py)** — 关于 agent 分歧的最基础说明:两个“agents”计算同一事物的略有不同 (`x * 2` 对比 `x * 2.0001`),从而对相同的输入产生不同的答案。不涉及 LLM —— 这是思考编排器应该如何检测和解决 agents 之间分歧的起点。 - **[w4_d3_deadlock_example.py](w4_d3_deadlock_example.py)** — 关于 agents 之间死锁的简化说明:Planner、Executor 和 Verifier 都在等待彼此继续,并且使用重复消息计数作为检测死锁并跳出循环的简单信号。不涉及 LLM。 - **[w4_d3_multi_agent_demo.py](w4_d3_multi_agent_demo.py)** — 三个具有不同角色的协作 agents:**Planner** 将任务分解为 2-4 个步骤,**Executor** 每次针对源文本执行一个步骤,**Verifier** 检查每个结果并返回 `APPROVE`/`REVISE`,在 `REVISE` 裁决时触发 Executor 进行一次重新尝试。编排循环驱动各个步骤,并将批准的结果连接起来形成最终答案。演示任务:总结一个段落并提取 3 个关键点。通过 `python-dotenv` 从 `.env` 文件加载 `OPENAI_API_KEY`。需要 OpenAI API key。OpenAI 函数/工具调用
- **[w4_d4_open_ai_fun_call.py](w4_d4_open_ai_fun_call.py)** — 仅包含函数调用中的工具 schema 部分:以 OpenAI API 期望的形状定义了一个 `add_numbers(a, b)` 工具规范(JSON-schema 风格的 `parameters`),没有客户端调用或执行逻辑。在将其连接到实际请求之前,可用作了解 schema 形状的最基础参考。 - **[w4_d4_toy_calc_tool.py](w4_d4_toy_calc_tool.py)** — OpenAI 函数/工具调用的完整往返过程:定义了一个 `add` 工具,在 `gpt-4o-mini` 可使用该工具的情况下向其发送用户消息,在模型请求调用时在本地执行该工具,将结果作为 `tool` 消息反馈到对话中,并要求模型根据该结果提供最终答案。通过 `python-dotenv` 从 `.env` 文件加载 `OPENAI_API_KEY`。需要 OpenAI API key。标签:DLL 劫持, Petitpotam, 人工智能, 凭据扫描, 向量数据库, 大语言模型, 学习笔记, 检索增强生成, 特权检测, 用户模式Hook绕过, 系统调用监控, 逆向工具