[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"learning-part-9-langchain":3,"learning-all":13},{"id":4,"slug":5,"title":6,"description":7,"level":8,"topic":9,"url":10,"content":11,"sortOrder":12},7,"part-9-langchain","Part 9 · LangChain 框架","目标：用 LangChain 把\"模型、提示词、检索、记忆、工具\"串成可复用的链和 Agent。","INTERMEDIATE","LangChain",null,"# Part 7 · LangChain 框架\r\n\r\n\r\n---\r\n\r\n## Section 1 · LangChain 是什么 + 装环境\r\n\r\n**Subsection 1 · 概念**\r\n```\r\nLangChain = 一个\"乐高框架\"，把 LLM 应用常用的零件做成了标准积木：\r\n  Prompt模板 \u002F 模型封装 \u002F 记忆 \u002F 检索 \u002F 工具 \u002F 链\r\nLangGraph = LangChain 家的\"图编排\"，做 Agent 状态机（站8用）\r\n```\r\n- 💡 一句话：它不给你模型，它帮你\"组装\"模型应用。\r\n\r\n**Subsection 2 · 装库**\r\ncmd：\r\n```\r\npip install langchain langchain-openai langchain-community\r\n```\r\n- ✅ 预期看到：三个 Successfully installed。\r\n\r\n**Subsection 3 · 跑第一个 LangChain 代码**\r\n新建 `lc_first.py`：\r\n```python\r\nimport os\r\nfrom dotenv import load_dotenv\r\nfrom langchain_openai import ChatOpenAI\r\n\r\nload_dotenv()\r\n\r\n# 用 LangChain 包一层 DeepSeek\r\nllm = ChatOpenAI(\r\n    model=\"deepseek-chat\",\r\n    api_key=os.getenv(\"DEEPSEEK_API_KEY\"),\r\n    base_url=\"https:\u002F\u002Fapi.deepseek.com\",\r\n)\r\n\r\nresp = llm.invoke(\"你好，用一句话介绍你自己\")\r\nprint(resp.content)\r\n```\r\n- ✅ 预期看到：模型自我介绍。\r\n- 💡 注意：LangChain 把\"返回\"统一封装成 `resp.content`，这就是它的价值之一——**换模型不用改业务代码**。\r\n\r\n**过关**：能跑通 lc_first.py = Section 1 完成。\r\n\r\n---\r\n\r\n## Section 2 · ChatModels vs LLMs + 角色消息\r\n\r\n**Subsection 1 · 区别**\r\n```\r\nLLM          老的纯文本接口，输入输出都是字符串\r\nChatModel    现在的对话接口，输入是消息列表（system\u002Fuser\u002Fassistant），更强大\r\n```\r\n- 💡 你现在用的 ChatOpenAI 就是 ChatModel，主流都走这个。\r\n\r\n**Subsection 2 · 跑多角色消息**\r\n新建 `lc_roles.py`：\r\n```python\r\nimport os\r\nfrom dotenv import load_dotenv\r\nfrom langchain_openai import ChatOpenAI\r\n\r\nload_dotenv()\r\nllm = ChatOpenAI(model=\"deepseek-chat\", api_key=os.getenv(\"DEEPSEEK_API_KEY\"), base_url=\"https:\u002F\u002Fapi.deepseek.com\")\r\n\r\nmessages = [\r\n    {\"role\": \"system\", \"content\": \"你是资深中文编辑，只改错别字和病句，不改变风格。\"},\r\n    {\"role\": \"user\", \"content\": \"我今天去了公司，发现会议室以经被别人占用了。\"},\r\n]\r\nprint(llm.invoke(messages).content)\r\n```\r\n- ✅ 预期看到：修正后的句子（\"已经\"）。\r\n\r\n**过关**：能跑通并理解 system 角色的作用 = Section 2 完成。\r\n\r\n---\r\n\r\n## Section 3 · PromptTemplate（提示词模板化）\r\n\r\n**Subsection 1 · 跑模板**\r\n新建 `lc_prompt.py`：\r\n```python\r\nimport os\r\nfrom dotenv import load_dotenv\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.prompts import ChatPromptTemplate\r\n\r\nload_dotenv()\r\nllm = ChatOpenAI(model=\"deepseek-chat\", api_key=os.getenv(\"DEEPSEEK_API_KEY\"), base_url=\"https:\u002F\u002Fapi.deepseek.com\")\r\n\r\n# 定义模板：变量用 {xxx} 占位\r\nprompt = ChatPromptTemplate.from_messages([\r\n    (\"system\", \"你是{topic}专家，回答要专业且简短。\"),\r\n    (\"user\", \"请解释：{question}\"),\r\n])\r\n\r\n# 模板 + 模型 = 一条链\r\nchain = prompt | llm\r\n\r\n# 不同参数复用同一条链\r\nfor t, q in [(\"健身\", \"深蹲怎么练\"), (\"编程\", \"什么是递归\")]:\r\n    print(t, \"=>\", chain.invoke({\"topic\": t, \"question\": q}).content, \"\\n\")\r\n```\r\n- ✅ 预期看到：同一个模板，换参数输出不同专家的回答。\r\n- 💡 `prompt | llm` 这种 `|` 就是 LCEL 链式写法（Section 6 详讲）。\r\n\r\n**过关**：能跑通模板复用 = Section 3 完成。\r\n\r\n---\r\n\r\n## Section 4 · 输出解析器（让输出变成数据结构）\r\n\r\n**Subsection 1 · 跑结构化输出**\r\n新建 `lc_output.py`：\r\n```python\r\nimport os\r\nfrom dotenv import load_dotenv\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.prompts import ChatPromptTemplate\r\nfrom langchain_core.output_parsers import JsonOutputParser\r\n\r\nload_dotenv()\r\nllm = ChatOpenAI(model=\"deepseek-chat\", api_key=os.getenv(\"DEEPSEEK_API_KEY\"), base_url=\"https:\u002F\u002Fapi.deepseek.com\")\r\n\r\nparser = JsonOutputParser()  # 自动把输出解析成 dict\r\n\r\nprompt = ChatPromptTemplate.from_messages([\r\n    (\"system\", \"提取信息，只输出 JSON，不要其他文字。字段：name, price, category。\"),\r\n    (\"user\", \"{text}\"),\r\n])\r\nchain = prompt | llm | parser\r\n\r\nresult = chain.invoke({\"text\": \"这款机械键盘卖399元，属于外设类\"})\r\nprint(result)\r\nprint(\"价格:\", result[\"price\"])\r\n```\r\n- ✅ 预期看到：一个 dict，且能取到 price。\r\n- 💡 这比Part 3 手写 json.loads 更稳，解析器还能接 Pydantic 模型校验。\r\n\r\n**过关**：能跑通并取到字段 = Section 4 完成。\r\n\r\n---\r\n\r\n## Section 5 · Memory 记忆（多轮对话不\"失忆\"）\r\n\r\n**Subsection 1 · 跑带记忆的对话**\r\n新建 `lc_memory.py`：\r\n```python\r\nimport os\r\nfrom dotenv import load_dotenv\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.messages import HumanMessage, AIMessage\r\n\r\nload_dotenv()\r\nllm = ChatOpenAI(model=\"deepseek-chat\", api_key=os.getenv(\"DEEPSEEK_API_KEY\"), base_url=\"https:\u002F\u002Fapi.deepseek.com\")\r\n\r\n# 手动维护对话历史：这就是\"记忆\"的最原始形态\r\nhistory = [\r\n    HumanMessage(\"我叫小明\"),\r\n    AIMessage(\"你好小明，很高兴认识你！\"),\r\n]\r\nhistory.append(HumanMessage(\"我叫什么名字？\"))\r\nprint(llm.invoke(history).content)   # 应该记得\"小明\"\r\n\r\n# 清空历史再问\r\nprint(llm.invoke([HumanMessage(\"我叫什么名字？\")]).content)  # 不知道了\r\n```\r\n- ✅ 预期看到：第一个回答出\"小明\"，第二个答不出。\r\n- 💡 关键：**模型本身没有记忆，记忆 = 你把历史拼进 messages 再发给它**。\r\n\r\n**Subsection 2 · 认识 Memory 组件**\r\nLangChain 有 `ConversationBufferMemory` 等现成组件帮你自动管理历史。知道有这东西即可，底层就是上面这个原理。\r\n\r\n**过关**：能跑通并说清\"记忆的原理\" = Section 5 完成。\r\n\r\n---\r\n\r\n## Section 6 · LCEL 链式组合（LangChain 的招牌语法）\r\n\r\n**Subsection 1 · 理解 `|`**\r\n```\r\nLCEL（LangChain Expression Language）\r\nprompt | llm | parser\r\n= 数据像水流过管道：prompt 生成消息 → llm 生成回答 → parser 解析\r\n好处：好读、好组合、自带流式和重试\r\n```\r\n\r\n**Subsection 2 · 跑一条完整 LCEL 链**\r\n新建 `lc_lcel.py`：\r\n```python\r\nimport os\r\nfrom dotenv import load_dotenv\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.prompts import ChatPromptTemplate\r\n\r\nload_dotenv()\r\nllm = ChatOpenAI(model=\"deepseek-chat\", api_key=os.getenv(\"DEEPSEEK_API_KEY\"), base_url=\"https:\u002F\u002Fapi.deepseek.com\")\r\n\r\nprompt = ChatPromptTemplate.from_messages([\r\n    (\"system\", \"把用户输入翻译成英文，只输出翻译结果。\"),\r\n    (\"user\", \"{text}\"),\r\n])\r\nchain = prompt | llm\r\n\r\n# 流式输出（LCEL 自带）\r\nfor chunk in chain.stream({\"text\": \"你好，很高兴认识你\"}):\r\n    print(chunk.content, end=\"\", flush=True)\r\n```\r\n- ✅ 预期看到：英文翻译以打字机效果输出。\r\n\r\n**过关**：能跑通 LCEL 流式 = Section 6 完成。\r\n\r\n---\r\n\r\n## Section 7 · 用 LCEL 串起 RAG\r\n\r\n**Subsection 1 · 写 LangChain 版 RAG**\r\n新建 `lc_rag.py`：\r\n```python\r\nimport os\r\nfrom dotenv import load_dotenv\r\nfrom langchain_openai import ChatOpenAI, OpenAIEmbeddings\r\nfrom langchain_community.vectorstores import Chroma\r\nfrom langchain_core.prompts import ChatPromptTemplate\r\nfrom langchain_text_splitters import RecursiveCharacterTextSplitter\r\nfrom langchain_community.document_loaders import TextLoader\r\n\r\nload_dotenv()\r\nllm = ChatOpenAI(model=\"deepseek-chat\", api_key=os.getenv(\"DEEPSEEK_API_KEY\"), base_url=\"https:\u002F\u002Fapi.deepseek.com\")\r\n\r\n# 用 DeepSeek 的 embedding 接口（或换 bge）。这里用 OpenAI 兼容方式：\r\nfrom langchain_openai import OpenAIEmbeddings\r\nembeddings = OpenAIEmbeddings(\r\n    model=\"text-embedding-v1\",   # 用 DashScope 的兼容接口时需要；简单起见先注释\r\n    api_key=os.getenv(\"DEEPSEEK_API_KEY\"),\r\n    base_url=\"https:\u002F\u002Fapi.deepseek.com\",\r\n)\r\n```\r\n- ⚠️ DeepSeek 目前没有 embedding 接口。改用阿里 DashScope 的 OpenAI 兼容 embedding（Part 6 已注册）：把 base_url 换成 `https:\u002F\u002Fdashscope.aliyuncs.com\u002Fcompatible-mode\u002Fv1`，api_key 换成 DashScope 的 Key，model 用 `text-embedding-v1`。如果你拿 DashScope Key 麻烦，退回Part 5 的 bge 方案做向量（本步可暂缓，直接看下面用 bge 版本）。\r\n\r\n**Subsection 2 · 用 bge 的简化版（直接用Part 5 成果）**\r\n```python\r\n# 如果上面 DashScope 不顺，就用Part 5 的 rag_tool 继续，LangChain 只学\"串链\"这部分：\r\nprompt = ChatPromptTemplate.from_messages([\r\n    (\"system\", \"根据资料回答，资料没有就说没有：\\n{context}\"),\r\n    (\"user\", \"{question}\"),\r\n])\r\nchain = prompt | llm\r\n# context 从站5的检索结果来\r\n```\r\n- 跑通这个简化版，理解\"LCEL 串 RAG\"的骨架：**检索得 context → 模板拼 context → llm 生成**。\r\n- ✅ 预期看到：能正常回答。\r\n\r\n**过关**：理解并跑通\"检索+模板+生成\"的 LCEL 骨架 = Section 7 完成（本日不追求生产级，Part 14 会完整重写）。\r\n\r\n---\r\n\r\n## Section 8 · 工具 Tools（自定义函数）\r\n\r\n**Subsection 1 · 定义工具**\r\n新建 `lc_tool.py`：\r\n```python\r\nimport os\r\nfrom dotenv import load_dotenv\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.tools import tool\r\n\r\nload_dotenv()\r\nllm = ChatOpenAI(model=\"deepseek-chat\", api_key=os.getenv(\"DEEPSEEK_API_KEY\"), base_url=\"https:\u002F\u002Fapi.deepseek.com\")\r\n\r\n@tool\r\ndef add(a: int, b: int) -> int:\r\n    \"\"\"两数相加。用这个工具做精确计算，避免模型算错。\"\"\"\r\n    return a + b\r\n\r\nprint(\"工具名:\", add.name)\r\nprint(\"调用:\", add.invoke({\"a\": 3, \"b\": 4}))\r\n```\r\n- ✅ 预期看到：`工具名: add` 和 `调用: 7`。\r\n- 💡 工具 = 一个带说明（docstring）的 Python 函数，模型看到说明才知道\"什么时候该用它\"。\r\n\r\n**过关**：能定义并调用一个工具 = Section 8 完成。\r\n\r\n---\r\n\r\n## Section 9 · Agent 雏形（让模型自己决定调用工具）\r\n\r\n**Subsection 1 · 跑工具调用 Agent**\r\n新建 `lc_agent.py`：\r\n```python\r\nimport os\r\nfrom dotenv import load_dotenv\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_core.tools import tool\r\nfrom langchain.agents import create_agent\r\n\r\nload_dotenv()\r\nllm = ChatOpenAI(model=\"deepseek-chat\", api_key=os.getenv(\"DEEPSEEK_API_KEY\"), base_url=\"https:\u002F\u002Fapi.deepseek.com\")\r\n\r\n@tool\r\ndef multiply(a: int, b: int) -> int:\r\n    \"\"\"两数相乘。\"\"\"\r\n    return a * b\r\n\r\ntools = [multiply]\r\n\r\n# LangChain 1.x 用 create_agent，不再需要 create_tool_calling_agent + AgentExecutor\r\n# system_prompt 替代旧版的 ChatPromptTemplate\r\n# debug=True 打印工具调用过程（替代旧版 verbose=True）\r\nagent = create_agent(\r\n    model=llm,\r\n    tools=tools,\r\n    system_prompt=\"你是计算助手，需要时调用工具。\",\r\n    debug=True,\r\n)\r\n\r\nresult = agent.invoke({\"messages\": [{\"role\": \"user\", \"content\": \"123 乘以 456 等于多少？\"}]})\r\nprint(result[\"messages\"][-1].content)\r\n```\r\n- ✅ 预期看到：debug 日志里出现工具调用，模型算出正确结果 56088。\r\n- 💡 这就是 **Function Calling \u002F 工具调用**：模型自己判断\"这题要调 multiply\"，把参数填好调用，再用结果回答。Agent 的地基。\r\n- ⚠️ LangChain 1.x 变化：`create_tool_calling_agent` + `AgentExecutor` 已移除，统一用 `create_agent`；输入从 `{\"input\": \"...\"}` 改成 `{\"messages\": [...]}`。\r\n\r\n**过关**：能跑通\"模型自动调工具\" = Section 9 完成。\r\n\r\n---\r\n\r\n## Section 10 · LangGraph 初步（Agent 的图编排）\r\n\r\n**Subsection 1 · 装库**\r\ncmd：`pip install langgraph`\r\n\r\n**Subsection 2 · 跑一个最简状态机**\r\n新建 `lg_first.py`：\r\n```python\r\nfrom typing import TypedDict\r\nfrom langgraph.graph import StateGraph, END\r\n\r\nclass State(TypedDict):\r\n    total: int\r\n\r\ndef add_one(state: State):\r\n    return {\"total\": state[\"total\"] + 1}\r\n\r\n# 建图：两个节点顺序执行\r\ng = StateGraph(State)\r\ng.add_node(\"a\", add_one)\r\ng.add_node(\"b\", add_one)\r\ng.set_entry_point(\"a\")\r\ng.add_edge(\"a\", \"b\")\r\ng.add_edge(\"b\", END)\r\n\r\napp = g.compile()\r\nprint(app.invoke({\"total\": 0}))   # 预期 {'total': 2}\r\n```\r\n- ✅ 预期看到：`{'total': 2}`（经过两次 +1）。\r\n- 💡 LangGraph = 把 Agent 流程画成\"状态图\"：节点是动作，边是流转。复杂 Agent 用它才不乱。现在先知道怎么建节点连边。\r\n\r\n**过关**：能跑通并理解\"节点+边\" = Section 10 完成。\r\n\r\n---\r\n\r\n## Section 11 · Tavily 搜索工具（让 Agent 联网）\r\n\r\n**Subsection 1 · 拿 Tavily Key**\r\n- 打开 https:\u002F\u002Ftavily.com 注册，创建一个 API Key（免费额度够学习），存进 `.env`：\r\n```\r\nTAVILY_API_KEY=tvly-你的key\r\n```\r\n\r\n**Subsection 2 · 跑联网搜索**\r\ncmd：`pip install langchain-community tavily-python`\r\n新建 `lc_tavily.py`：\r\n```python\r\nimport os\r\nfrom dotenv import load_dotenv\r\nfrom langchain_community.tools import TavilySearchResults\r\n\r\nload_dotenv()\r\ntool = TavilySearchResults(max_results=3)\r\nresult = tool.invoke(\"2026年大模型行业有什么大新闻\")\r\nfor r in result:\r\n    print(r[\"title\"], \"|\", r[\"url\"])\r\n```\r\n- ✅ 预期看到：3 条真实的网页搜索结果。\r\n- 💡 这就是\"给 Agent 接上网\"：搜索工具返回实时信息，模型再基于它回答。\r\n\r\n**过关**：能跑通联网搜索 = Section 11 完成。\r\n\r\n---\r\n\r\n## Section 12 · 用 LangChain 完整重写站 5 的 RAG\r\n\r\n**Subsection 1 · 完整重写**\r\n新建 `lc_kb.py`（用 langchain 的文档加载\u002F切分\u002F向量库，替换站5的手写代码）：\r\n```python\r\nimport os\r\nfrom dotenv import load_dotenv\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_community.document_loaders import TextLoader\r\nfrom langchain_text_splitters import RecursiveCharacterTextSplitter\r\nfrom langchain_community.vectorstores import Chroma\r\nfrom langchain_community.embeddings import HuggingFaceEmbeddings\r\nfrom langchain_core.prompts import ChatPromptTemplate\r\n\r\nload_dotenv()\r\nllm = ChatOpenAI(model=\"deepseek-chat\", api_key=os.getenv(\"DEEPSEEK_API_KEY\"), base_url=\"https:\u002F\u002Fapi.deepseek.com\")\r\n\r\n# 1. 加载 + 切分\r\nloader = TextLoader(\"rag_data\u002Fcompany.md\", encoding=\"utf-8\")\r\ndocs = loader.load()\r\nsplitter = RecursiveCharacterTextSplitter(chunk_size=200, chunk_overlap=40)\r\nchunks = splitter.split_documents(docs)\r\n\r\n# 2. 向量化 + 入库（用 bge，免 DashScope Key）\r\nembeddings = HuggingFaceEmbeddings(model_name=\"BAAI\u002Fbge-small-zh-v1.5\")\r\ndb = Chroma.from_documents(chunks, embeddings, persist_directory=\"lc_db\")\r\n\r\n# 3. 检索 + 生成\r\nretriever = db.as_retriever(search_kwargs={\"k\": 3})\r\nprompt = ChatPromptTemplate.from_messages([\r\n    (\"system\", \"根据资料回答，没有就说没有：\\n{context}\"),\r\n    (\"human\", \"{question}\"),\r\n])\r\n\r\ndef ask(q):\r\n    context = \"\\n\".join(d.page_content for d in retriever.invoke(q))\r\n    return llm.invoke(prompt.format_messages(question=q, context=context)).content\r\n\r\nprint(ask(\"迟到会怎么样？\"))\r\n```\r\n- ✅ 预期看到：基于公司.md 的正确回答。\r\n- 💡 对比Part 5 手写版：LangChain 把\"加载\u002F切分\u002F入库\u002F检索\"全部标准化了。这就是框架的价值。\r\n\r\n**过关**：重写跑通 = Section 12 完成。\r\n\r\n---\r\n\r\n## Section 13 · 多轮对话知识库（记忆 + RAG 合体）\r\n\r\n**Subsection 1 · 组装**\r\n新建 `lc_memory_rag.py`：把 Section 5 的记忆思路 + Section 12 的 RAG 合体：\r\n```python\r\nimport os\r\nfrom dotenv import load_dotenv\r\nfrom langchain_openai import ChatOpenAI\r\nfrom langchain_community.vectorstores import Chroma\r\nfrom langchain_community.embeddings import HuggingFaceEmbeddings\r\nfrom langchain_core.messages import HumanMessage, AIMessage\r\n\r\nload_dotenv()\r\nllm = ChatOpenAI(model=\"deepseek-chat\", api_key=os.getenv(\"DEEPSEEK_API_KEY\"), base_url=\"https:\u002F\u002Fapi.deepseek.com\")\r\nembeddings = HuggingFaceEmbeddings(model_name=\"BAAI\u002Fbge-small-zh-v1.5\")\r\ndb = Chroma(persist_directory=\"lc_db\", embedding_function=embeddings)\r\nretriever = db.as_retriever(search_kwargs={\"k\": 3})\r\n\r\nhistory = []  # 记忆\r\n\r\ndef chat(user_input):\r\n    # 检索\r\n    context = \"\\n\".join(d.page_content for d in retriever.invoke(user_input))\r\n    # 拼历史 + 资料 + 问题\r\n    messages = [{\"role\": \"system\", \"content\": f\"根据资料回答：\\n{context}\"}]\r\n    messages += history\r\n    messages.append({\"role\": \"user\", \"content\": user_input})\r\n    resp = llm.invoke(messages).content\r\n    history.append(HumanMessage(user_input))\r\n    history.append(AIMessage(resp))\r\n    return resp\r\n\r\nwhile True:\r\n    q = input(\"你：\")\r\n    if q == \"exit\":\r\n        break\r\n    print(\"助手：\", chat(q))\r\n```\r\n- 连续问：\"迟到怎么处理\" → \"那请假呢\" → \"我刚才问了什么\" 感受记忆生效。\r\n- ✅ 预期看到：多轮连贯，且能记住前面问过什么。\r\n\r\n**过关**：多轮知识库跑通 = Section 13 完成。\r\n\r\n---\r\n\r\n## Section 14 · 常见坑与测试\r\n\r\n**Subsection 1 · 记坑**\r\n```\r\n坑1  DeepSeek 没有 embedding 接口 → 用 bge（HuggingFaceEmbeddings）\r\n坑2  Chroma persist 目录重名冲突 → 换目录名或删掉旧的\r\n坑3  模型\"看不到工具说明\" → 工具 docstring 必须写清楚\r\n坑4  LCEL 流式报错 → 检查模型是否支持 stream\r\n坑5  历史无限增长 → 超长截断\u002F只保留最近 N 轮\r\n```\r\n\r\n**Subsection 2 · 测试**\r\n- 跑一遍 Section 13 的多轮对话，测 5 个不同问题 + 连续追问，记录是否都正常。\r\n\r\n**过关**：坑笔记写完 + 测试通过 = Section 14 完成。\r\n\r\n---\r\n\r\n## Section 15 · 站 7 验收\r\n\r\n**勾选**\r\n- [ ] lc_first.py 跑通，理解 ChatModel 封装\r\n- [ ] 会写 PromptTemplate 并复用\r\n- [ ] 会做结构化输出（JsonOutputParser）\r\n- [ ] 理解\"记忆=拼历史\"，lc_memory.py 跑通\r\n- [ ] LCEL 链式 + 流式跑通\r\n- [ ] 会定义工具，lc_agent.py 模型自动调工具\r\n- [ ] LangGraph 最简状态机跑通\r\n- [ ] Tavily 联网搜索跑通\r\n- [ ] LangChain 版 RAG（lc_kb.py）跑通\r\n- [ ] 多轮记忆知识库跑通（Section 13）\r\n- [ ] 常见坑笔记写完\r\n\r\n**写 300 字Part 7 总结**：LangChain\u002FLangGraph 解决了什么，你最喜欢哪个能力。\r\n\r\n**全勾选 = Part 9 通过** → 进入下一站 Part 10 · Agent 基础，15 天：规划\u002F记忆\u002F工具\u002F执行 + Function Calling 深入）。",9,[14,21,27,33,39,45,51,56,61,62,68,75,81,87,93,99,105,111,117,123,129],{"id":15,"slug":16,"title":17,"description":18,"level":19,"topic":20,"url":10,"content":10,"sortOrder":15},1,"part-1-llm-basics","Part 1 · 大模型基础认知","小白零基础友好。这一站不写代码，只建立\"大模型到底是什么\"的骨架。","BEGINNER","大模型认知",{"id":22,"slug":23,"title":24,"description":25,"level":19,"topic":26,"url":10,"content":10,"sortOrder":22},2,"part-2-llm-principles","Part 2 · 大模型原理 · 入门实操","这一站不卷数学，只把\"理解模型所需的知识\"讲透。；站 2A 解决\"理解模型\"，站 2B 解决\"面试能答\"。；这一层是\"有余力再做\"，不做也不影响你进入站 3。","大模型原理",{"id":28,"slug":29,"title":30,"description":31,"level":19,"topic":26,"url":10,"content":10,"sortOrder":32},100,"part-3-llm-principles-deep","Part 3 · 大模型原理 · 面试深入","数学基础、机器学习、神经网络、词向量、思维链等面试必考原理",3,{"id":34,"slug":35,"title":36,"description":37,"level":8,"topic":26,"url":10,"content":10,"sortOrder":38},101,"part-4-llm-principles-advanced","Part 4 · 大模型原理 · 进阶可选","从零写迷你模型、RLHF、PPO、分布式训练实操等进阶内容",4,{"id":32,"slug":40,"title":41,"description":42,"level":19,"topic":43,"url":10,"content":10,"sortOrder":44},"part-5-prompt-engineering","Part 5 · Prompt 提示词工程","从这里开始，你每天都要真的调大模型 API。","提示工程",5,{"id":38,"slug":46,"title":47,"description":48,"level":19,"topic":49,"url":10,"content":10,"sortOrder":50},"part-6-llm-api","Part 6 · 大模型 API 调用","站 3 你已经调通了 API。这一站把\"调用\"做成专业水准：","API 工程",6,{"id":44,"slug":52,"title":53,"description":54,"level":8,"topic":55,"url":10,"content":10,"sortOrder":4},"part-7-rag","Part 7 · RAG 检索增强生成","这一站是\"能落地\"的关键：让模型回答**你的私有知识**。","RAG",{"id":50,"slug":57,"title":58,"description":59,"level":8,"topic":55,"url":10,"content":10,"sortOrder":60},"part-8-rag-optimization","Part 8 · RAG 优化与评估","站 5 你做出了\"能跑\"的 RAG。这一站把它做到\"能打\"：",8,{"id":4,"slug":5,"title":6,"description":7,"level":8,"topic":9,"url":10,"content":10,"sortOrder":12},{"id":60,"slug":63,"title":64,"description":65,"level":8,"topic":66,"url":10,"content":10,"sortOrder":67},"part-10-agent","Part 10 · Agent 基础","让模型从\"会聊天\"变成\"能干活\"：自己拆任务、调工具、看结果、再行动。","Agent",10,{"id":12,"slug":69,"title":70,"description":71,"level":72,"topic":73,"url":10,"content":10,"sortOrder":74},"part-11-multi-agent","Part 11 · 多 Agent 与 Agent IDE","从\"单个 Agent\"升级到\"多 Agent 协作\"，并掌握 AutoGen \u002F LangGraph \u002F GPTs \u002F Coze \u002F Dify 五个工具。","ADVANCED","多 Agent",11,{"id":67,"slug":76,"title":77,"description":78,"level":72,"topic":79,"url":10,"content":10,"sortOrder":80},"part-12-llamaindex","Part 12 · LlamaIndex","站 5~7 你用了 LangChain 做 RAG。LlamaIndex 是另一条专攻\"数据 + LLM\"的路线。","LlamaIndex",12,{"id":74,"slug":82,"title":83,"description":84,"level":72,"topic":85,"url":10,"content":10,"sortOrder":86},"part-13-transformer","Part 13 · Transformer 深入","站 2A 建立了直觉，这一站把手写代码跑通——从\"懂概念\"到\"写得出\"。","Transformer",13,{"id":80,"slug":88,"title":89,"description":90,"level":72,"topic":91,"url":10,"content":10,"sortOrder":92},"part-14-open-models","Part 14 · 开源模型与私有化部署","目标：把主流开源模型在本地\u002F服务器跑通，理解服务化工程（显存、量化、并发）。","模型部署",14,{"id":86,"slug":94,"title":95,"description":96,"level":72,"topic":97,"url":10,"content":10,"sortOrder":98},"part-15-finetuning","Part 15 · 模型微调 Fine-Tuning","目标：理解\"什么时候必须微调、怎么选基座、怎么备数据\"，并完整跑通一次业务微调。","微调",15,{"id":92,"slug":100,"title":101,"description":102,"level":72,"topic":103,"url":10,"content":10,"sortOrder":104},"part-16-peft-lora","Part 16 · PEFT 参数高效微调","重点吃透 **LoRA**：用极少量可训练参数微调大模型（消费级显卡就能跑）。","PEFT\u002FLoRA",16,{"id":98,"slug":106,"title":107,"description":108,"level":72,"topic":109,"url":10,"content":10,"sortOrder":110},"part-17-quantization","Part 17 · 模型量化","目标：理解\"为什么量化、主流算法各自思路\"，能动手量化并评估效果。","量化",17,{"id":104,"slug":112,"title":113,"description":114,"level":72,"topic":115,"url":10,"content":10,"sortOrder":116},"part-18-data-evaluation","Part 18 · 训练数据与模型评估","数据决定模型上限，评估决定你\"能不能交付\"。","数据与评估",18,{"id":110,"slug":118,"title":119,"description":120,"level":72,"topic":121,"url":10,"content":10,"sortOrder":122},"part-19-multimodal","Part 19 · 多模态应用","让 AI 同时\"看得懂图、听得了音、说得出话\"。","多模态",19,{"id":116,"slug":124,"title":125,"description":126,"level":72,"topic":127,"url":10,"content":10,"sortOrder":128},"part-20-projects-career","Part 20 · 项目实战 + 求职备战","把 0→1 到 1→100 学到的全部收敛成**能展示、能讲、能面试**的项目。","项目与求职",20,{"id":130,"slug":131,"title":132,"description":133,"level":72,"topic":134,"url":10,"content":10,"sortOrder":135},102,"extra-2026-ai-tech","额外篇 · 2026 年 AI 应用开发必学的 5 项成熟技术","从近半年爆发的技术里，挑出已经过了尝鲜期、能真正用在项目里的 5 项：推理模型、MCP、多模态、GraphRAG、AI 编程工具链，每项都给到能跑通的代码。","AI 工程实践",21]