Summary
BaiduYiyanChat.__init__ in rag/llm/chat_model.py does an unguarded json.loads(key). The Baidu Qianfan API requires a JSON key (the same protocol used by every other JSON-config provider: see conf/models/baidu.json for the model class). If a user pastes a plain (non-JSON) string as the Baidu API key, the constructor crashes with json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0) from inside rag/llm internals — exactly the same shape as the recently-fixed Azure (#17204 / PR #17215) and Bedrock (#17373 / PR #17377) bugs.
Affected call site
rag/llm/chat_model.py:1189 — BaiduYiyanChat.__init__ (the chat class for the Baidu Qianfan provider). One line:
key = json.loads(key) # UNGUARDED — same pattern as the pre-fix Azure / Bedrock branches
ak = key.get("yiyan_ak", "")
sk = key.get("yiyan_sk", "")
self.client = qianfan.ChatCompletion(ak=ak, sk=sk)
The downstream .get("yiyan_ak", "") / .get("yiyan_sk", "") calls would mask the AttributeError if key were a non-dict, but the raw JSONDecodeError from json.loads on a plain string is what crashes today.
Reproduction
- In the RAGFlow UI, add an LLM provider with class
BaiduYiyan (e.g. model ERNIE-4.0-8K).
- Paste a plain (non-JSON) string as the API key, e.g.
bce-v3/ALTAK-.../....
- Save. The first chat call against the provider raises
JSONDecodeError from json.loads(key) inside BaiduYiyanChat.__init__, before any network call is made.
Expected behavior
The provider should fail with a clear, actionable error — something like "BaiduYiyan requires a JSON key with yiyan_ak and yiyan_sk; see conf/models/baidu.json for the model class" — instead of a raw JSONDecodeError stack trace. The current behaviour is silent on what the user did wrong.
Why this matters
Proposed solution
Same shape as the Bedrock fix (PR #17377). Add a shared helper to rag/llm/key_utils.py:
def _resolve_qianfan_credentials(key):
"""Parse a BaiduYiyan (Baidu Qianfan) ``key`` and return it as a dict.
The BaiduYiyan / Qianfan API requires a JSON object with at least
``yiyan_ak`` and ``yiyan_sk``. See ``conf/models/baidu.json`` for the
model class.
On non-JSON input we raise a clear :class:`ModelException` pointing
at the required schema, instead of letting ``json.loads`` bubble up
as ``json.decoder.JSONDecodeError`` from inside ``rag/llm`` internals.
Mirrors ``_resolve_bedrock_credentials`` (#17373) and the Azure
fix shape (#17215 / #17204).
"""
# Same shape as _resolve_bedrock_credentials. See key_utils.py.
...
Wire it into chat_model.py:1189 in place of the bare json.loads(key).
Add a test_chat_model_qianfan_key_fallback.py mirroring the Bedrock test file: covers (a) plain string key raises a clear ModelException, (b) JSON dict with yiyan_ak and yiyan_sk parses, (c) JSON missing fields raises a clear error, (d) non-dict JSON raises a clear error, (e) end-to-end through BaiduYiyanChat.__init__.
Alternatives considered
- Silent swallow + log warning. Rejected: the operator wouldn't see the error in the chat UI; the chat would just fail with no diagnostic.
- Auto-detect a plain Baidu API key prefix (
bce-v3/...) and try to wrap it. Rejected: a plain key alone is insufficient (no yiyan_ak / yiyan_sk); the heuristic would produce a half-broken state.
- Schema validation at config-write time. Out of scope for this fix; would require a UI-side validator and a migration. The provider-init path catches the same class of errors and is where the existing Bedrock fix lives.
Scope
One call site, one new helper in key_utils.py, one new test file. No public API changes. No data-model changes. No migrations. Backward compatible: valid JSON keys behave identically to today; invalid keys now raise a ModelException with a clear message instead of a raw JSONDecodeError.
Acceptance criteria
- A plain (non-JSON) BaiduYiyan key produces a
ModelException with a message that includes the words "BaiduYiyan" or "Qianfan" and "JSON" and points at conf/models/baidu.json or the schema example.
- A valid JSON dict with
yiyan_ak and yiyan_sk continues to work (no behaviour change for happy path).
- A JSON top-level non-dict (array, string, number) produces a
ModelException, not an AttributeError from the downstream .get("yiyan_ak", "").
- The bare
json.loads(key) at chat_model.py:1189 is replaced by the helper.
- New p0 regression tests cover the four scenarios above plus the end-to-end through
BaiduYiyanChat.__init__.
ruff check + ruff format --check clean on all touched files.
Related
Summary
BaiduYiyanChat.__init__inrag/llm/chat_model.pydoes an unguardedjson.loads(key). The Baidu Qianfan API requires a JSON key (the same protocol used by every other JSON-config provider: seeconf/models/baidu.jsonfor the model class). If a user pastes a plain (non-JSON) string as the Baidu API key, the constructor crashes withjson.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)from insiderag/llminternals — exactly the same shape as the recently-fixed Azure (#17204 / PR #17215) and Bedrock (#17373 / PR #17377) bugs.Affected call site
rag/llm/chat_model.py:1189—BaiduYiyanChat.__init__(the chat class for the Baidu Qianfan provider). One line:The downstream
.get("yiyan_ak", "")/.get("yiyan_sk", "")calls would mask theAttributeErrorifkeywere a non-dict, but the rawJSONDecodeErrorfromjson.loadson a plain string is what crashes today.Reproduction
BaiduYiyan(e.g. modelERNIE-4.0-8K).bce-v3/ALTAK-.../....JSONDecodeErrorfromjson.loads(key)insideBaiduYiyanChat.__init__, before any network call is made.Expected behavior
The provider should fail with a clear, actionable error — something like "BaiduYiyan requires a JSON key with
yiyan_akandyiyan_sk; seeconf/models/baidu.jsonfor the model class" — instead of a rawJSONDecodeErrorstack trace. The current behaviour is silent on what the user did wrong.Why this matters
Proposed solution
Same shape as the Bedrock fix (PR #17377). Add a shared helper to
rag/llm/key_utils.py:Wire it into
chat_model.py:1189in place of the barejson.loads(key).Add a
test_chat_model_qianfan_key_fallback.pymirroring the Bedrock test file: covers (a) plain string key raises a clearModelException, (b) JSON dict withyiyan_akandyiyan_skparses, (c) JSON missing fields raises a clear error, (d) non-dict JSON raises a clear error, (e) end-to-end throughBaiduYiyanChat.__init__.Alternatives considered
bce-v3/...) and try to wrap it. Rejected: a plain key alone is insufficient (noyiyan_ak/yiyan_sk); the heuristic would produce a half-broken state.Scope
One call site, one new helper in
key_utils.py, one new test file. No public API changes. No data-model changes. No migrations. Backward compatible: valid JSON keys behave identically to today; invalid keys now raise aModelExceptionwith a clear message instead of a rawJSONDecodeError.Acceptance criteria
ModelExceptionwith a message that includes the words "BaiduYiyan" or "Qianfan" and "JSON" and points atconf/models/baidu.jsonor the schema example.yiyan_akandyiyan_skcontinues to work (no behaviour change for happy path).ModelException, not anAttributeErrorfrom the downstream.get("yiyan_ak", "").json.loads(key)atchat_model.py:1189is replaced by the helper.BaiduYiyanChat.__init__.ruff check+ruff format --checkclean on all touched files.Related
rag/llm/key_utils.py::_resolve_bedrock_credentials— the helper this fix mirrorsconf/models/baidu.json— the model class reference