[Bug]: try_parse_json_object turns backslash escapes into spaces when valid JSON comes in a code fence or after a sentence
Maintainer thường phản hồi trong vòng 5 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 74/100
Hướng nghiên cứu
Bắt đầu từ packages/graphrag/graphrag/query/llm/text_utils.py tại try_parse_json_object, nơi đoạn cắt từ { đầu tiên đến } cuối cùng đi qua bước dọn dẹp dấu gạch chéo ngược bằng .replace trước bất kỳ kiểm tra tính hợp lệ nào. Chạy script tái tạo trong issue để xác nhận line1\nline2 trả về line1 nline2, và kiểm tra xem GlobalSearch._parse_search_response trong search.py của tìm kiếm toàn cục có cùng lỗi hay không. Hoàn thành khi JSON hợp lệ đã cắt giữ nguyên các ký tự escape, đầu vào không hợp lệ vẫn đi qua bước dọn dẹp cũ và json_repair, và một test hồi quy bao phủ các phản hồi có hàng rào mã và có tiền tố.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Do you need to file an issue?
- I have searched the existing issues and this bug is not already filed.
- My model is hosted on OpenAI or Azure. If not, please look at the "model providers" issue and don't file a new one here.
- I believe this is a legitimate bug, not just a question. If this is a question, please use the Discussions area.
Describe the bug
try_parse_json_object in packages/graphrag/graphrag/query/llm/text_utils.py first calls json.loads on the whole response. If the model wraps valid JSON in a markdown fence or puts a sentence before it, that call fails. The function then cuts out the text from the first { to the last } and runs a cleanup chain on it. One step of that chain is .replace("\\", " "). It runs before anything checks whether the cut-out text is already valid JSON.
So every escape inside a string value is broken, even though the cut-out text was valid:
\nbecomes a space and the letter n.line1\nline2comes back asline1 nline2.\"becomes a space and a quote.He said \"hi\" todaycomes back asHe said "hi " today.\\becomes two spaces.C:\\data\\x.txtcomes back asC: data x.txt.\t,\rand\u00e9are broken the same way.
The same JSON without the fence parses correctly, because the first json.loads succeeds.
This function parses model output in three query paths:
- the global search map step,
GlobalSearch._parse_search_response(thedescriptiontext of each key point) rate_relevancyin dynamic community selection- DRIFT,
DriftAction.search(theresponsetext andfollow_up_queries)
Map and DRIFT answers are markdown, so they often contain \n. A fenced map response is a real case: #1173 shows gemma2 on ollama returning the map response inside a ```json fence. Also, #2625 shows that response_format_json_object=True does not reach the model on main, and it reports that Qwen and Mistral on vLLM sometimes answer with prose around the JSON. I did not find a trace from OpenAI or Azure, so this mostly affects local and other non-JSON-mode providers.
Back in #801 a maintainer review asked for a json.loads check first, so valid JSON would skip the string cleanup (done in #834). That check only covers the whole response. It does not cover the object cut out of a fenced or prefixed response.
Steps to reproduce
No model is needed. With graphrag installed from main:
import json
from graphrag.query.llm.text_utils import try_parse_json_object
from graphrag.query.structured_search.global_search.search import GlobalSearch
BS = "\\"
raw = "```json\n" + '{"d": "line1' + BS + 'nline2"}' + "\n```"
expected = json.loads(raw[raw.index("{") : raw.rindex("}") + 1])
_, got = try_parse_json_object(raw, verbose=False)
print("expected:", repr(expected))
print("got: ", repr(got))
map_raw = (
"```json\n"
+ '{"points": [{"description": "first line' + BS + 'nsecond line, said '
+ BS + '"ok' + BS + '"", "score": 80}]}'
+ "\n```"
)
print(GlobalSearch._parse_search_response(None, map_raw))
Expected Behavior
When the cut-out object is already valid JSON, it should be returned as parsed. The cleanup and json_repair should only run when it is not valid.
Expected output:
expected: {'d': 'line1\nline2'}
got: {'d': 'line1\nline2'}
[{'answer': 'first line\nsecond line, said "ok"', 'score': 80}]
GraphRAG Config Used
# Not needed. The reproduction calls the parser directly and uses no settings file.
Logs and screenshots
Output on main:
expected: {'d': 'line1\nline2'}
got: {'d': 'line1 nline2'}
[{'answer': 'first line nsecond line, said "ok "', 'score': 80}]
Additional Information
- GraphRAG Version: 3.3.0 (main at 34b2b67)
- Operating System: Windows 11
- Python Version: 3.13
- Related Issues: #1173 (fenced map response from gemma2 on ollama, fixed the regex then). #2625 (JSON mode is not sent to the model). Point 2 of #2625 also shows the backslash cleanup splitting single-quoted follow-up queries at
\'. That input is not valid JSON, so the fix below does not change it. - I have a small fix with a regression test. After the cut-out step it tries
json.loadsand returns the result when it is a non-empty dict. Everything else still goes through the old cleanup path. I will open a PR that references this issue.
Validated with Claude Opus 5.5.
- Ngôn ngữ chính
- Python
- Star
- 36.6k
- Fork
- 3.9k
- Merge trung bình
- 4 ngày 11 giờ
- Pull request đã merge (30 ngày)
- 1
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của microsoft/graphrag
-
[Bug]: response_format_json_object=True is silently dropped, so JSON mode never reaches the modelĐang mởbug triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
microsoft/graphrag#2625 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 5 ngày
-
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 95/100
Maintainer thường phản hồi trong vòng 5 ngày
-
[Bug]: JsonCache.get() crashes with unhandled AttributeError on non-dict or invalid envelope JSON payloadsCó thể làm lại được Pull request cho issue này đã bị đóng mà không được merge. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
microsoft/graphrag#2614 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 5 ngày
-
[Bug]: JSONLinesFileReader drops rows containing U+2028, U+2029 or U+0085 (uses str.splitlines)Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
microsoft/graphrag#2594 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 5 ngày
-
[Bug]: TokenChunker never terminates when chunking overlap >= size (no validation of size/overlap)Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
microsoft/graphrag#2593 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 5 ngày
Tất cả issue của microsoft/graphrag
Issue tương tự
-
bug
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 78/100
splunk/security_content#4418 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[Bug / Enhancement]: Improve teleop_robot CLI with configurable timeout, robust input validation, and clean ROS shutdownCó thể đã có người làm @muskan-creates352 đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 3 ngày
-
bug(pipelines): shortcode stripping deletes text between a {{< >}} shortcode and the next {{% %}}Có thể đã có người làm @Ashborne-lab đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
kubeflow/docs-agent#293 ·
Maintainer thường phản hồi trong vòng 3 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
Imbad0202/academic-research-skills#1093 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Input: placeholder drawn in the text colour when the empty Input is focused but not yet editedĐang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
pierreaubert/gpui-toolkit#114 ·
Maintainer thường phản hồi trong vòng 1 ngày