Cách sửa lỗi LangChain OutputParserException: Could not parse LLM output

intermediate🧠 AI Tools2026-05-17| Python 3.9+, LangChain v0.1.0+, OpenAI/Anthropic/Ollama API

Error Message

OutputParserException: Could not parse LLM output
#langchain#python#json#llm-development

Lỗi

Nếu bạn đã dành hơn một giờ để xây dựng ứng dụng với LangChain, có lẽ bạn đã gặp phải bức tường gây ức chế này. Bạn mong đợi nhận được một đối tượng Python sạch sẽ, nhưng thay vào đó, console của bạn lại hiện ra một loạt văn bản màu đỏ:

OutputParserException: Could not parse LLM output

Điều này xảy ra khi Mô hình Ngôn ngữ Lớn (LLM) trở nên "nhiều lời". Thay vì trả về một đối tượng JSON thô, nó có thể bao bọc dữ liệu trong các câu dẫn thoại hoặc các khối mã markdown mà trình phân tích cú pháp (parser) của bạn không biết cách xử lý.

Tại sao điều này lại xảy ra

LLM được thiết kế để trở thành những trợ lý hữu ích, chứ không phải là các công cụ xuất dữ liệu cứng nhắc. Ngay cả khi bạn yêu cầu rõ ràng "chỉ JSON", các mô hình thường thất bại theo những cách có thể dự đoán được. Trong thử nghiệm của chúng tôi với Llama 3, chúng tôi nhận thấy rằng nếu không có kỹ thuật nhắc (prompting) nghiêm ngặt, các mô hình sẽ không trả về được JSON hợp lệ khoảng 15-20% thời gian. Các nguyên nhân phổ biến bao gồm:

  • Tiền tố hội thoại: "Chắc chắn rồi! Đây là dữ liệu bạn yêu cầu: { ... }"
  • Định dạng Markdown: Bao bọc câu trả lời trong các khối mã json ... .
  • Lỗi cú pháp: Thiếu dấu phẩy ở cuối hoặc dấu ngoặc kép không được thoát (unescaped) trong chuỗi.

Các bước khắc phục

1. Kiểm tra đầu ra thô (Raw Output)

Bạn không thể sửa những gì bạn không thấy. Trước khi bắt đầu tinh chỉnh prompt, hãy nắm bắt chính xác chuỗi ký tự mà LLM đã gửi về. Bao bọc chain của bạn trong một khối try-except để tìm ra nguyên nhân.

from langchain_core.exceptions import OutputParserException

try:
    response = chain.invoke({"input": "Get user data for John Doe"})
except OutputParserException as e:
    # Điều này cho phép bạn thấy chính xác những gì LLM đã tạo ra
    print(f"The LLM sent this back: {e.llm_output}")
    raise e

Kiểm tra e.llm_output là cách nhanh nhất để biết liệu mô hình đang bị ảo giác (hallucinating) về schema hay chỉ đơn giản là thêm các thẻ markdown không cần thiết.

2. Chèn hướng dẫn định dạng (Format Instructions)

Đừng để LLM phải đoán cấu trúc. Các parser của LangChain đi kèm với một phương thức tích hợp để tạo ra các yêu cầu kỹ thuật chính xác cho mô hình. Nếu prompt của bạn không bao gồm những hướng dẫn này, mô hình về cơ bản sẽ hoạt động một cách mù quáng.

from langchain.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field

class UserInfo(BaseModel):
    name: str = Field(description="User's name")
    age: int = Field(description="User's age")

parser = PydanticOutputParser(pydantic_object=UserInfo)

# parser.get_format_instructions() tạo ra JSON schema cụ thể
prompt = PromptTemplate(
    template="Answer the query.\n{format_instructions}\n{query}\n",
    input_variables=["query"],
    partial_variables={"format_instructions": parser.get_format_instructions()},
)

3. Chuyển sang JsonOutputParser

PydanticOutputParser rất nghiêm ngặt. Nếu LLM bao gồm các dấu ngoặc ngược (triple backticks), nó thường thất bại. Nếu bạn gặp phải vấn đề này, hãy chuyển sang JsonOutputParser. Nó mạnh mẽ hơn đáng kể và thường có thể tự động loại bỏ các lớp bao bọc markdown mà không gây lỗi.

from langchain_core.output_parsers import JsonOutputParser

# Parser này "dễ dãi" hơn với các khối markdown
parser = JsonOutputParser(pydantic_object=UserInfo)
chain = prompt | model | parser

4. Triển khai OutputFixingParser

Đôi khi LLM mắc một lỗi nhỏ có thể sửa được, chẳng hạn như quên dấu đóng ngoặc nhọn }. Thay vì để ứng dụng bị lỗi, hãy sử dụng OutputFixingParser. Nó sẽ bắt lỗi và gửi đầu ra không hợp lệ đó quay lại LLM cùng với các hướng dẫn để sửa lại. Mặc dù điều này tạo thêm một lần gọi API thứ hai, nhưng nó có thể đẩy tỷ lệ thành công của bạn lên gần 100%.

from langchain.output_parsers import OutputFixingParser
from langchain_openai import ChatOpenAI

# Nếu lần chạy đầu tiên thất bại, mã này sẽ gửi lại cho GPT-4 để sửa cú pháp
new_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI(model="gpt-4o"))

Xác minh kết quả

Kiểm tra chain của bạn với một truy vấn mơ hồ. Một giải pháp thành công sẽ trả về một đối tượng Pydantic sạch sẽ, ngay cả khi mô hình cố gắng tỏ ra hữu ích bằng cách thêm văn bản bổ sung.

result = chain.invoke({"query": "I'm John, and I just turned 30!"})
print(type(result)) 
# Kết quả mong đợi: <class '__main__.UserInfo'>
print(result.age)
# Kết quả mong đợi: 30

Mẹo chuyên nghiệp cho môi trường Production

  • Bắt buộc Temperature bằng 0: Luôn đặt temperature=0 cho các tác vụ có cấu trúc. Ngay cả một sự gia tăng nhỏ lên 0.7 cũng có thể làm tăng hiện tượng ảo giác định dạng lên 30% ở các mô hình nhỏ hơn.
  • Sử dụng Native Tool Calling: Nếu bạn đang sử dụng OpenAI, Anthropic hoặc Gemini, hãy ngừng sử dụng các parser thủ công. Sử dụng model.with_structured_output(UserInfo). Nó sử dụng API gốc của mô hình cho tool calling, điều này đáng tin cậy hơn nhiều so với việc phân tích cú pháp dựa trên văn bản.
  • Kiểm tra tính hợp lệ của JSON: Nếu bạn đang tự viết prompt thủ công, hãy sử dụng các công cụ như JSON Formatter & Validator. Nó giúp đảm bảo các ví dụ few-shot của bạn không có lỗi cú pháp tiềm ẩn có thể làm LLM bối rối.
  • Ví dụ Few-Shot: Đối với các mô hình nhỏ hơn như Llama 3 (8B) hoặc Mistral, hãy đưa hai ví dụ về JSON mong đợi vào prompt của bạn. Điều này thường hiệu quả hơn bất kỳ cài đặt parser nào.

Related Error Notes