踩坑全记录:LangChain4j + Qdrant 从「id 为空」到「text 为 null」一次踩个够

踩坑全记录:LangChain4j + Qdrant 从「id 为空」到「text 为 null」一次踩个够

关键词:LangChain4j、Qdrant、embeddingId、TextSegment、payload、text 字段、Python 灌库、Java 查询、NullPointerException


一、开场白

整个技术栈:

  • 离线脚本 :Python 生成向量 → 写入 Qdrant
  • 在线服务 :Spring Boot + LangChain4j 读取向量做语义检索

短短两天连续踩中三个坑:

  1. 查询直接抛 IllegalArgumentException: embeddingId cannot be null or blank
  2. 修复 id 后又出现 NullPointerException: embedded() is null
  3. metadata 字段报错

下面按时间线复盘,给出根因 + 解决方案 + 可复用代码,帮大家一次排完雷。


二、坑①:embeddingId 为 null

现象

Java 一搜索就报错:

txt 复制代码
java.lang.IllegalArgumentException: embeddingId cannot be null or blank
	at dev.langchain4j.store.embedding.EmbeddingMatch.<init>(EmbeddingMatch.java:32)

根因

Python 端写入 PointStruct 时给id赋值整型,导致在JAVA中查询出的整型ID和要求的类型不匹配,从而导致id为null,而 LangChain4j 强制做非空校验。

解决方案

使用字符串类型的UUID,重构向量库集合。

python 复制代码
from qdrant_client.models import PointStruct
import uuid

point = PointStruct(
    id=str(uuid.uuid4()),  # 必须非空
    vector=embedding,
    payload=pl
)

三、坑②:TextSegment 反序列化失败 → embedded() 为 null

现象

id 修复后查询不再抛异常,但一调用:match.embedded().text() 直接 NPE:

java 复制代码
java.lang.NullPointerException: Cannot invoke "dev.langchain4j.data.segment.TextSegment.text()" 
because the return value of "dev.langchain4j.store.embedding.EmbeddingMatch.embedded()" is null

根因

LangChain4j 把 payload["text"] 字段的值拿出来,用 Jackson 反序列化成 TextSegment。 如果该字段是任意 JSON 字符串而不是下面两种形式之一,就会反序列化失败:

我们当时为了"保留完整字段",直接把整个 item 序列化后塞进 text:

python 复制代码
pl = {"text": json.dumps(item, ensure_ascii=False), ...}

LangChain4j 不认,直接返回 null。

解决方案

text 字段只存纯文本

python 复制代码
pl = {
    "text": item.get("phenomena", ""),  # 纯文本
    "metadata": {
        "source": "blob",
        "blobType": "text/plain",
        "loc": {"lines": {"from": 0, "to": 0}},
    }
}

四、坑③:metadata报错

现象

上个问题修改完以后,又出现了一个问题:

java 复制代码
java.lang.IllegalArgumentException: The metadata key 'metadata' has the value '{loc_lines_to=0, loc_lines_from=0, source=blob, blobType=text/plain}', which is of the unsupported type 'java.util.HashMap'. Currently, the supported types are: [class java.lang.String, class java.util.UUID, int, class java.lang.Integer, long, class java.lang.Long, float, class java.lang.Float, double, class java.lang.Double]
	at dev.langchain4j.internal.Exceptions.illegalArgument(Exceptions.java:23) ~[langchain4j-core-1.0.1.jar:na]

根因

metadata不支持HashMap类型,而我插入到Qdrant的metadata字段是一个字典。

python 复制代码
    "metadata": {
        "source": "blob",
        "blobType": "text/plain",
        "loc": {"lines": {"from": 0, "to": 0}},
    }

解决方案

把metadata中的字段全部摊平到payload中。

python 复制代码
pl = {
    "text": "event_source:...,phenomena:...",
    "source": "blob",            # 平铺
    "blobType": "text/plain",
    "loc_lines_from": 0,         # 基本类型
    "loc_lines_to": 0
}
相关推荐
FreeCode3 小时前
LangChain1.0智能体开发:MCP
后端·langchain·agent
DO_Community9 小时前
在 DigitalOcean GPU 云服务上使用 LangChain 构建Serverless AI 应用
人工智能·langchain·serverless
FreeCode10 小时前
LangChain1.0智能体开发:上下文工程
后端·langchain·agent
“负拾捌”1 天前
LangChain 中 ChatPromptTemplate 的几种使用方式
python·langchain·prompt
学历真的很重要1 天前
LangChain V1.0 Messages 详细指南
开发语言·后端·语言模型·面试·langchain·职场发展·langgraph
CV视觉1 天前
AI 实战篇:用 LangGraph 串联 RAG+MCP Server,打造能直接操控 Jira 的智能体
人工智能·深度学习·机器学习·自然语言处理·langchain·prompt·jira
FreeCode1 天前
LangChain1.0智能体开发:运行时(Runtime)
人工智能·langchain·agent
FreeCode1 天前
LangChain1.0智能体开发:安全防护机制
人工智能·langchain·agent
玲小珑1 天前
LangChain.js 完全开发手册(十八)AI 应用安全与伦理实践
前端·langchain·ai编程
兴趣使然黄小黄2 天前
【AI-agent】LangChain开发智能体工具流程
人工智能·microsoft·langchain