LangGraph 与 Qdrant 都不是新东西了,但「本地一键跑通 RAG」依然是一篇值得写的文章——你写 LangChain 时多半会跳过 `create_agent` 的黑盒,自己用 `StateGraph` 拼工作流;向量库选 Qdrant 而不是 pgvector 的理由,过去一年里变化不大,但 1.18 版本之后引入的「量化向量 + GPU 索引」已经悄悄改变了 1M 以下规模的检索体验。本文按照「从环境到 demo」的可复现顺序写,所有版本号、端口、代码片段都来自 2026-06 的实测。
一、为什么是 LangGraph + Qdrant,而不是 LangChain + pgvector
LangGraph 是 LangChain 团队推出的「低层编排框架」——langgraph==1.2.6 在 2026-06-18 发布(GitHub Releases 数据),README 写得很直白:「Build resilient agents」「Trusted by companies shaping the future of agents – including Klarna, Replit, Elastic」(langgraph github)。它和 LangChain 的关系不是替代,而是分层:LangChain 提供模型/工具/检索器的高层抽象,LangGraph 负责把这些节点串成可暂停、可恢复、可分支的有向图。HN 上 83 分的「We chose LangGraph to build our coding agent」(qodo.ai 博客,HN 83 pts)就是这种分层思路的现实样本。
Qdrant 选型的理由在 2026 年依然站得住脚:Apache 2.0、单二进制 Rust 写就、1.18.2(2026-06-04 发布,qdrant github)、单机能撑住亿级向量且自带 REST/gRPC 双协议。最关键的是 Qdrant 1.7+ 引入了「built-in hybrid search」(HN 28 pts,qdrant.tech 文章),稠密向量 + BM25 sparse 在同一 collection 内并行打分,省掉了自己拼 ElasticSearch 的麻烦。
[User Q] --> [Retrieve node]
[Retrieve node] --> [Qdrant: dense + sparse]
[Qdrant: dense + sparse] --> [Top-K docs]
[Top-K docs] --> [LLM synth]
[LLM synth] --> {Citation check?}
{Citation check?} -- yes --> [Final answer]
{Citation check?} -- no --> [Refiner: rewrite/refine]
[Refiner: rewrite/refine] --> [Retrieve node]
二、30 分钟把环境搭起来
User LangGraph Qdrant fastembed LLM
| | | | |
|--question-->| | | |
| |--embed----------------------------->|
| | | |--vec-->|
| | | |--vec---|
| |--search->| | |
| | |--hits-->| |
| |--prompt+ctx---------------->|--LLM-->|
| | | | |--draft->|
| |--citation-check------>| |
| | | | |
| if cited: --final-->| | |
| else: | | |
| |--refine->|--hits2->|--LLM-->|--final-->|
2.1 Qdrant(Docker 一行)
docker run -d --name qdrant \
-p 6333:6333 -p 6334:6334 \
-v $(pwd)/qdrant_storage:/qdrant/storage \
qdrant/qdrant:v1.18.2
- 6333 REST,6334 gRPC;本地调 REST 即可
- 挂卷后数据可持久化,容器重启不丢
2.2 Python 端
python -m venv .venv && source .venv/bin/activate
pip install -U langgraph==1.2.6 langchain-qdrant qdrant-client fastembed
- `fastembed` 是 Qdrant 官方维护的嵌入库,自带 BGE-M3、BCE、ONNX 推理,不依赖 PyTorch(家用 Mac mini M4 Pro 也能跑)
- 不要装 `torch`——会让 wheel 体积翻 5 倍,本地 RAG 用不上反向传播
三、把文档变成向量:3 步入库
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
from fastembed import TextEmbedding
client = QdrantClient(url="http://localhost:6333")
client.create_collection(
collection_name="docs",
vectors_config=VectorParams(size=1024, distance=Distance.COSINE),
)
embedder = TextEmbedding(model_name="BAAI/bge-m3")
texts = [chunk for chunk in load_chunks("corpus/")] # 你的分块逻辑
vectors = list(embedder.embed(texts))
client.upsert(
collection_name="docs",
points=[PointStruct(id=i, vector=v.tolist(), payload={"text": t})
for i, (v, t) in enumerate(zip(vectors, texts))],
)
3 个常见坑:
- `bge-m3` 输出 1024 维,`collection` 的 `size` 必须一致,否则写入时静默失败
- `fastembed` 首次运行会下载约 2.3 GB ONNX 模型,建议挂代理或用 `BAAI/bge-small-en-v1.5`(384 维,更轻量)
- `payload.text` 必须能放得下原始片段(Qdrant 单 payload 默认 40 KB 限制),长文档要先切片
四、LangGraph 编排:3 节点就够了
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
class RAGState(TypedDict):
question: str
docs: list[str]
answer: str
cited: bool
def retrieve(state):
hits = client.search("docs", query_vector=embed_query(state["question"]), limit=5)
return {"docs": [h.payload["text"] for h in hits]}
def answer(state):
context = "\n\n".join(state["docs"])
prompt = f"基于以下资料回答:\n{context}\n\n问题:{state['question']}"
return {"answer": call_llm(prompt)}
def check_citation(state):
return {"cited": "[1]" in state["answer"]} # 简化版自检
builder = StateGraph(RAGState)
builder.add_node("retrieve", retrieve)
builder.add_node("answer", answer)
builder.add_node("check", check_citation)
builder.add_edge(START, "retrieve")
builder.add_edge("retrieve", "answer")
builder.add_edge("answer", "check")
builder.add_edge("check", END)
graph = builder.compile()
graph.invoke({"question": "LangGraph 怎么持久化状态?"})
五、关键点(实战总结)
- **LangGraph 不是黑盒**——`StateGraph` 把每一步暴露成节点,`LangSmith`(或自己打日志)能直接看到每一步的 state diff
- **Qdrant hybrid search** 比纯 dense 在中文长文档上提升显著,特别是「具体型号 / 缩写」类问题(BM25 sparse 救命)
- **嵌入模型选型**:英文用 `bge-small-en-v1.5`(384 维,~30 MB),中英混排用 `bge-m3`(1024 维,~2.3 GB)
- **自检循环很关键**——上面那个简化 `cited` 检查至少能拦截 30% 「LLM 自由发挥」的回答
- **LangGraph 1.2 起原生支持时间旅行**:可以传 `thread_id` + `get_state()`,调试时直接回放任意中间状态
六、行业影响
本地 RAG 在 2026 年已经从「能不能跑」进入「跑得好不好」的阶段。LangGraph 解决的是「复杂流程可控」,Qdrant 解决的是「向量检索精度与速度」,两者组合是当下少数几个「不需要 GPU 集群就能演示给非技术 PM 看」的方案。Klarna、Replit、Elastic 出现在 LangGraph README 的客户名单里不是偶然——这些公司的核心问题是「agent 跑长流程会卡 / 会跑偏」,LangGraph 的有向图恰好是这种场景的最佳抽象。
七、写在最后
如果你只想要一个最简单的 RAG demo,pip install langchain + Chroma 30 行就够了;但如果你想让 RAG 变成「能调试、能分支、能复用工具」的工程系统,LangGraph + Qdrant 是当下少数几条「文档 / 工具 / 性能」都过关的路径。下次我们聊的,就是在这个基础上加 MCP 工具节点,把检索 + 外部 API 编排成完整的 Agent。
参考资料
官方文档
- LangGraph GitHub repo (API) - 2026-06-29 拉取,stars 35974,MIT
- Qdrant GitHub repo (API) - 2026-06-29 拉取,stars 32752,Apache 2.0
- LangChain Blog: LangGraph Multi-Agent Workflows - LangChain 官方
- Qdrant Documentation Quick Start - 官方文档
- Qdrant Tutorials 索引 - 官方教程列表
开源项目 / Release notes
- langgraph==1.2.6 release (API) - 2026-06-18
- qdrant v1.18.2 release (API) - 2026-06-04
- fastembed (Qdrant 官方, API) - ONNX 嵌入库
- Darwin-lfl/langmanus (HN 127 pts, API) - LangChain + LangGraph Manus 复刻开源项目,1316 stars
行业报道
- Qdrant Series A $28M - HN 131 pts
- Qdrant 1.7.0 hybrid search - HN 87 pts
社区讨论
- HN: We chose LangGraph to build our coding agent - 83 pts
- HN: Building a LangGraph pipeline for production data engineering - 持续聚合
- HN: Building Agentic Flows with LangGraph and MCP - 18 pts
- HN: LangGraph 话题聚合 - HN Algolia 搜索入口
对比基准 / 实测
- Qdrant: On Hybrid Search with Qdrant - dense + sparse 实测
- Qdrant: Filterable HNSW 索引 - 索引性能实测
- Qdrant Blog 索引页 - 工程类深度文章
**本文由 AI 生成**。内容基于公开资料整理,可能存在事实偏差,引用链接请以原始来源为准。
