jd-opensource/joyagent-jdgenie · error · RuntimeException

向量生成失败!

Error message

向量生成失败!

What it means

VectorService.recall throws this when embeddingService.getVector(query) returns a null or empty vector, meaning the embedding model/service failed to produce an embedding for the query text. The recall cannot proceed without a vector to search with.

Solutions

  1. Check embedding service health and its logs for the failing request (URL, auth, payload).
  2. Validate embeddingService config (endpoint URL, API key, model name) is correct for the environment.
  3. Inspect getVector: it likely swallows errors and returns empty — make it throw with the upstream status/body so the root cause is visible.
  4. Add retry with backoff for transient embedding-service failures before giving up.
  5. Truncate/validate query length against the embedding model's token limit.

Example fix

// before
List<Float> vector = embeddingService.getVector(req.getQuery());
if (CollectionUtils.isEmpty(vector)) {
    throw new RuntimeException("向量生成失败!");
}
// after
List<Float> vector = embeddingService.getVector(req.getQuery());
if (CollectionUtils.isEmpty(vector)) {
    log.error("embedding failed, queryLen={}, req={}", req.getQuery().length(), JSONObject.toJSONString(req));
    throw new RuntimeException("向量生成失败! query=" + req.getQuery());
}
Defensive patterns

Strategy: retry

Validate before calling

// java (caller): sanity-check embedding availability indirectly
// ensure query is non-blank and within token limits before calling
if (StringUtils.isBlank(query) || query.length() > MAX_QUERY_LEN) {
    throw new IllegalArgumentException("query empty or too long for embedding model");
}

Try / catch

try {
    return vectorService.vectorRecall(req);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("向量生成失败")) {
        // embedding service degraded: retry once, then fall back to keyword search
        return fallbackKeywordSearch(req.getQuery());
    }
    throw e;
}

Prevention

When it happens

Trigger: getVector returns empty because the embedding HTTP call failed or returned an unexpected body; query text is in a language/format the model rejects; embedding service credentials/URL misconfigured so the empty-vector branch is hit.

Common situations: Embedding service down or returning 4xx/5xx consumed as empty result; embedding API key expired; query exceeds model token limit and service silently returns nothing; model name changed after an upgrade.

Related errors


AI-assisted analysis of jd-opensource/joyagent-jdgenie@2417e0b8b6 (2026-09-08). Data as JSON: /api/errors/2df0239548c28d47. Report an issue: GitHub.

Appendix: source

Thrown at genie-backend/src/main/java/com/jd/genie/service/VectorService.java:80

            log.error("vectorRecall error: req:{}", JSONObject.toJSONString(req), e);
            if (future != null) {
                try {
                    future.cancel(true);
                } catch (Exception e1) {
                    log.error(e1.getMessage(), e1);
                }
            }
        }

        return new ArrayList<>();
    }

    private List<Map<String, Object>> recall(VectorRecallReq req) {
        try {
            List<Float> vector = embeddingService.getVector(req.getQuery());
            if (CollectionUtils.isEmpty(vector)) {
                log.error("vectorRecall error: vector is empty, req:{}", JSONObject.toJSONString(req));
                throw new RuntimeException("向量生成失败!");
            }

            Points.Filter filter = null;
            if (Objects.nonNull(req.getKeywordFilterMap()) && !req.getKeywordFilterMap().isEmpty()) {
                Points.Filter.Builder filterBuilder = Points.Filter.newBuilder();
                req.getKeywordFilterMap().forEach((k, v) -> {
                    if (v instanceof String) {
                        filterBuilder.addMust(matchKeyword(k, (String) v));
                    } else if (v instanceof Long) {
                        filterBuilder.addMust(match(k, (long) v));
                    } else if (v instanceof Integer) {
                        filterBuilder.addMust(match(k, (int) v));
                    } else if (v instanceof Boolean) {
                        filterBuilder.addMust(match(k, (boolean) v));
                    } else if (v instanceof List) {
                        List<Object> list = (List<Object>) v;
                        if (CollectionUtils.isNotEmpty(list)) {
                            Object type = list.get(0);

View on GitHub (pinned to 2417e0b8b6)