🎯 课程主题
掌握 LangGraph Store 的 search() 检索方法,涵盖三种检索模式:基于 namespace 前缀匹配、基于 value 字段过滤(filter)、以及基于语义搜索(query + 嵌入模型)。
📝 核心知识点
1. search() 方法参数
| 参数 | 类型 | 说明 |
|---|---|---|
namespace_prefix | tuple[str, ...] | namespace 前缀,支持部分匹配(传部分元组元素即可) |
filter | dict[str, Any] | None | 按 value 中的键值对进行精确过滤 |
query | str | None | 语义搜索字符串(需配合 embedding/index 配置) |
limit | int | 返回结果的最大条数(类似 SQL LIMIT) |
offset | int | 偏移量,跳过前 N 条记录 |
refresh_ttl | bool | 是否刷新存活时间 |
注意:
filter和query二选一即可,也可都不填(仅按 namespace_prefix 检索)。
2. 三种检索模式对比
| 模式 | 核心参数 | 原理 | 典型场景 |
|---|---|---|---|
| 前缀搜索 | namespace_prefix | 按 namespace 元组前缀匹配 | 按用户/业务线快速定位 |
| 过滤搜索 | filter | 基于 value 中的键值对精确匹配 | 按字段值条件筛选(如"爱好=跑步") |
| 语义搜索 | query | 将 value 文本向量化后做相似度检索 | 模糊/语义相关查询(如"数电模电"匹配到"模电数电") |
3. 语义搜索的前置配置
语义搜索需要在 Store 初始化时配置 index 参数 — 一个 IndexConfig 对象:
| 配置项 | 说明 |
|---|---|
embed | 嵌入函数/嵌入模型,将文本转为向量 |
dims | 向量维度,需与嵌入模型输出维度一致 |
fields | 需要向量化的字段列表;"$" 表示整体 value;可指定具体字段名如 "courses" |
每个 fields 中的元素都会独立生成一个嵌入向量,用于后续语义检索。
4. 返回值
search() 返回一个 list[Item],语义搜索模式下结果按相似度分数从高到低排序。
🏗️ 架构与工作流
search()
│
┌─────────────┼─────────────┐
▼ ▼ ▼
namespace_prefix filter query
(前缀匹配) (value字段) (语义向量)
│ │ │
└─────────────┼─────────────┘
▼
filter 过滤: {"food": "sports"}
或
query 语义: "数电模电"
│
▼
list[Item] (按相似度排序)
语义搜索流程
put(value) → embed(value) → 存入向量索引
│
search(query="数电模电") → embed(query) → 向量相似度计算 → 排序返回
💻 代码实战
2.1 基于 namespace 前缀搜索
from langgraph.store.memory import InMemoryStore
store = InMemoryStore()
# 存入多组数据(不同 namespace)
store.put(namespace=("users", "bob", "memories"), key="m1", value={"info": "Bob 喜欢跑步"})
store.put(namespace=("users", "bob", "memories"), key="m2", value={"info": "Bob 喜欢游泳"})
store.put(namespace=("users", "alice", "memories"), key="m1", value={"info": "Alice 喜欢阅读"})
# 前缀搜索:匹配 ("users",) 开头的所有条目
results = list(store.search(namespace_prefix=("users",)))
# 返回 3 条
# 更精确的前缀:匹配 ("users", "bob") 开头的
results = list(store.search(namespace_prefix=("users", "bob")))
# 返回 2 条
2.2 基于 filter 过滤搜索
# filter 按 value 中的键值对过滤
results = list(store.search(
namespace_prefix=("users",),
filter={"food": "sports"}
))
# 返回 value 中包含 "food": "sports" 的条目
# 换个过滤条件 — 没匹配就返回空列表
results = list(store.search(
namespace_prefix=("users",),
filter={"food": "跑步一"}
))
# 返回 [](空列表,for 循环不执行)
2.3 语义搜索(自定义嵌入函数演示)
from langgraph.store.memory import InMemoryStore
# 自定义简单嵌入函数(演示用,实际生产应使用真实嵌入模型)
def simple_embed(text: str) -> list[float]:
return [1.0] * 6 # 六维全1向量
store = InMemoryStore(
index={
"dims": 6, # 向量维度
"embed": simple_embed, # 嵌入函数
"fields": ["$", "courses"], # 向量化字段
}
)
# 存入数据
store.put(
namespace=("users", "alice", "memories"),
key="k1",
value={"info": "Alice 擅长模电数电", "courses": "模电数电"}
)
store.put(
namespace=("users", "bob", "memories"),
key="k2",
value={"info": "Bob 擅长编程", "courses": "Python"}
)
# 语义搜索
results = list(store.search(
namespace_prefix=("users",),
query="数电模电" # 语义相似搜索,不需要精确匹配
))
# 返回与"数电模电"语义最相似的条目(按相似度降序)
2.4 语义搜索(真实嵌入模型)
from langchain.chat_models import init_embeddings
from langgraph.store.memory import InMemoryStore
# 初始化嵌入模型(以 OpenAI 为例)
embed_model = init_embeddings(
model="text-embedding-3-large", # 维度 3072
api_key="your-api-key",
base_url="https://api.openai.com/v1"
)
store = InMemoryStore(
index={
"dims": 3072, # 与模型输出维度匹配
"embed": embed_model,
"fields": ["$"],
}
)
# 存入数据后...
results = list(store.search(
namespace_prefix=("users",),
query="数电模电"
))
# 每条结果带有相似度评分,按评分降序排列
⚠️ 常见问题与避坑指南
- search() 返回生成器:
store.search()返回的是可迭代对象,若需要列表用list()包裹,或直接for item in store.search(...)遍历。 - filter 是按 value 字典的键值对匹配:
filter={"food": "sports"}匹配的是 value 中{"food": "sports", ...}这样的条目,不是模糊匹配。 - 语义搜索必须有嵌入模型:query 参数依赖 index 配置中的 embed 函数,否则无法进行向量化检索。
- dims 必须与嵌入模型输出维度一致:OpenAI
text-embedding-3-large是 3072 维,填写错误会导致写入/检索失败。 - 语义搜索是相似度排序:返回结果非精确匹配,可能包含低相关度的条目;生产环境建议配合
limit或分数阈值过滤。 - 自定义嵌入函数仅用于演示:实际开发中务必使用真实的嵌入模型(如 OpenAI 嵌入 API),否则语义搜索无实际意义。
💡 个人总结与延伸
search()是 Store 中最灵活的数据检索方法,三种模式可单独或组合使用。filter相当于数据库的WHERE子句,query相当于向量数据库的相似度搜索 — LangGraph 在 Store 层面统一了这两种范式。fields: ["$"]表示对 value 整体做向量化,fields: ["$", "courses"]表示同时对整体和courses字段独立向量化,为后续的多粒度语义检索提供支持。- 语义搜索的具体原理(嵌入模型、向量化、相似度计算)将在后续 RAG 章节中详细展开。