Nếu DSPy tuyệt vời như vậy thì tại sao không có ai sử dụng?
AI/ML·Hacker News·1 lượt xem

Nếu DSPy tuyệt vời như vậy thì tại sao không có ai sử dụng?

If DSPy is so great, why isn't anyone using it?

AI Summary

Dù DSPy hứa hẹn sẽ đơn giản hóa quá trình kỹ thuật AI và mang lại lợi ích trong việc thử nghiệm các model mới cũng như khả năng bảo trì, việc áp dụng nó vẫn còn khá hạn chế so với các framework phổ biến như LangChain. Nguyên nhân chính là do rào cản học tập ban đầu (steep learning curve) và các trừu tượng (abstractions) còn xa lạ. Nhiều developer cuối cùng lại tự xây dựng các giải pháp "cây nhà lá vườn" (ad-hoc), kém hiệu quả hơn, mô phỏng lại các mẫu (patterns) của DSPy theo thời gian. Bài học rút ra cho các developer là: mặc dù DSPy có vẻ phức tạp lúc đầu, việc đầu tư thời gian để làm quen với các trừu tượng của nó có thể giúp bạn tránh được nhiều "đau đầu" về sau và xây dựng các hệ thống AI mạnh mẽ, dễ bảo trì hơn trong dài hạn, thay vì rơi vào cái bẫy "tự chế DSPy" kém tối ưu.

Đối với một framework hứa hẹn giải quyết những thách thức lớn nhất trong kỹ thuật AI, khoảng cách này thật đáng ngờ. Tuy nhiên, các công ty...

Đối với một khuôn khổ hứa hẹn giải quyết những thách thức lớn nhất trong kỹ thuật AI, khoảng cách này thật đáng ngờ. Tuy nhiên, các công ty sử dụng Dspy luôn báo cáo những lợi ích giống nhau.

Họ có thể thử nghiệm một mô hình mới một cách nhanh chóng, ngay cả khi lời nhắc hiện tại của họ không truyền tải tốt. Hệ thống của họ dễ bảo trì hơn. Họ đang tập trung vào bối cảnh hơn là hệ thống ống nước.

Vậy tại sao không có nhiều người sử dụng nó?

Vấn đề của DSPy không phải là nó sai. Điều đó thật khó khăn. Những điều trừu tượng không quen thuộc và buộc bạn phải suy nghĩ khác đi một chút. Và điều bạn muốn lúc này không phải là nghĩ khác đi; bạn chỉ muốn nỗi đau biến mất.

Nhưng tôi vẫn tiếp tục chứng kiến điều tương tự xảy ra: cuối cùng mọi người triển khai một phiên bản Dspy tệ hơn. Tôi muốn nói đùa rằng hiện nay đã có Luật Khattab (dựa trên Luật Greenspun về Nói Nói Nói Nói Chung):

Bất kỳ hệ thống AI đủ phức tạp nào đều chứa một phần triển khai đặc biệt, được chỉ định không chính thức, có lỗi của một nửa DSPy.

Dù sao thì bạn cũng sẽ xây dựng những mẫu này. Bạn sẽ chỉ làm điều đó tệ hơn sau rất nhiều thời gian và phải trải qua rất nhiều đau đớn.

Sự phát triển của mọi hệ thống AI

Hãy cùng tìm hiểu xem hầu như mọi nhóm đều triển khai “Dspy tại nhà” của riêng họ như thế nào. Chúng tôi sẽ sử dụng tác vụ trích xuất có cấu trúc đơn giản làm ví dụ xuyên suốt. Tuy nhiên, đừng để sự đơn giản của ví dụ này đánh lừa bạn; những mô hình này chỉ trở nên quan trọng hơn khi hệ thống trở nên phức tạp hơn.

Giai đoạn 1: Gửi hàng

Giả sử bạn cần trích xuất tên công ty từ một số văn bản, bạn có thể bắt đầu với API OpenAI:

từ openai nhập OpenAI

client = OpenAI()

def extract_company(text: str) -> str:

phản hồi = client.chat.completions.create(

model="gpt-5.2",

tin nhắn=[{"vai trò": "người dùng" , "nội dung": f"Trích xuất tên công ty từ: {văn bản>"}]

)

return reply.choices[0].message.content

Về cơ bản nó hoạt động. Vậy là bạn gửi nó và cuộc sống vẫn tốt đẹp.

Giai đoạn 2: “Chúng tôi có thể điều chỉnh lời nhắc mà không cần triển khai không?”

Nhưng chắc chắn, Product sẽ muốn lặp lại nhanh hơn. Triển khai lại cho mỗi lần thay đổi nhanh chóng là quá khó chịu. Vì vậy bạn quyết định lưu trữ lời nhắc trong cơ sở dữ liệu:

từ openai import OpenAI

from myapp.config import get_prompt

client = OpenAI()

def extract_company(text : str) -> str:

prompt_template = get_prompt("extract_company")

nhắc = nhắc_template.format(text=text)

phản hồi = client.chat.completions.create(

model="gpt-5.2",

tin nhắn=[{ "vai trò": "người dùng", "nội dung": nhắc}]

)

return reply.choices[0].message.content

Bây giờ bạn đã có một bảng nhắc nhở, một giao diện người dùng quản trị nhỏ để chỉnh sửa. Và tất nhiên là bạn phải thêm lịch sử phiên bản sau khi ai đó phá sản vào thứ Ba tuần trước.

Giai đoạn 3: “Nó liên tục trả về các định dạng rác”

Bạn nhận thấy mô hình đôi khi trả về "Công ty: Acme Corp" thay vì chỉ "Acme Corp". Vì vậy, bạn thêm kết quả đầu ra có cấu trúc:

từ openai nhập OpenAI

từ pydantic nhậpBaseModel

client = OpenAI()

lớp CompanyExtraction(BaseModel):

tên công ty: str

sự tự tin: float

def extract_company(text: str) -> CompanyExtraction:

prompt_template = get_prompt("extract_company_v2")

phản hồi = client.chat.completions.parse(

model ="gpt-5.2",

tin nhắn=[{"vai trò": "người dùng", "nội dung": nhắc_template.format(văn bản= text)}],

response_format=CompanyExtraction,

)

return reply.choices[0].message

Bây giờ bạn đã nhập dữ liệu đầu vào và đầu ra và có độ tin cậy cao hơn là hệ thống đang thực hiện những gì cần làm.

Giai đoạn 4: “Chúng ta cần xử lý thất bại”

Sau khi chạy một thời gian, bạn sẽ nhận thấy các lỗi tạm thời như lỗi 529 hoặc các trường hợp hiếm gặp khi phân tích cú pháp không thành công. Vì vậy bạn thêm lần thử lại:

từ openai nhập OpenAI

từ độ bền nhập thử lại, stop_after_attempt, wait_exponential

client = OpenAI()

@retry(dừng= stop_after_attempt(3), chờ=wait_exponential(min=1, max=10))

def extract_company(text: str) -> CompanyExtraction:

prompt_template = get_prompt("extract_company_v2")

response = client.beta.chat.completions.parse(

mô hình= "gpt-4o",

tin nhắn=[{"vai trò": "người dùng", "nội dung": nhắc_template.format(text=text)}],

response_format=CompanyExtraction,

)

return reply.choices[0].message.parsed

Giờ đây, mỗi cuộc gọi đều có khả năng phục hồi tốt hơn một chút. Tuy nhiên, trên thực tế, bạn có thể chuyển sang một nhà cung cấp khác vì việc thử lại một dịch vụ quá tải trả lại kết quả 529 là công thức dẫn đến… lỗi 529 khác.

Giai đoạn 5: “Bây giờ chúng tôi cần RAG”

Cuối cùng, bạn có thể bắt đầu phân tích cú pháp các tên công ty bí truyền hơn và mô hình có thể không đủ tốt để nhận dạng một thực thể là tên công ty. Vì vậy, bạn muốn thêm RAG dựa trên thông tin công ty đã biết để giúp cải thiện việc trích xuất:

từ openai nhập OpenAI

client = OpenAI()

def extract_company_with_context(text: str) -> CompanyExtraction:

# Bước 1: Viết truy vấn RAG

query_prompt_template = get_prompt("extract_company_query_writer")

query_prompt = query_prompt_template.format(text)

query_response = client.chat.completions.create(

model="gpt-5.2",

tin nhắn=[{ "vai trò": "người dùng", "nội dung": query_prompt}]

)

truy vấn =Response.choices[0 ].message.content

query_embedding = embed(query)

tài liệu = vector_db.search(query_embedding, top_k=5)

bối cảnh = " \n".join([d.content for d trong docs])

# Bước 2: Trích xuất theo ngữ cảnh

prompt_template = get_prompt("extract_company_with_rag")

nhắc nhở =nhắc_template.format(văn bản=văn bản, bối cảnh=bối cảnh)

phản hồi = client.chat.completions.parse(

model="gpt-5.2" ,

tin nhắn=[{"vai trò": "người dùng", "nội dung": nhắc}],

response_format=CompanyExtraction,

)

return reply.choices[0].message

Bây giờ chúng ta có hai lời nhắc: một để tạo truy vấn và một để tạo phân tích cú pháp công ty. Và chúng tôi cũng đã giới thiệu các tham số khác như k. Điều đáng chú ý là không phải tất cả các tham số này đều độc lập. Vì tài liệu đã truy xuất được đưa vào lời nhắc cuối cùng nên mọi thay đổi ở đây đều ảnh hưởng đến hiệu suất tổng thể.

Giai đoạn 6: “Làm sao chúng tôi biết liệu điều này có trở nên tốt hơn hay không?”

Bạn liên tục thay đổi cả hai lời nhắc, mô hình nhúng, k và bất kỳ tham số nào bạn có thể sử dụng để sửa lỗi khi chúng được báo cáo. Nhưng bạn không bao giờ chắc chắn liệu thay đổi của mình có khắc phục được hoàn toàn vấn đề hay không. Và bạn không bao giờ chắc chắn liệu những thay đổi của mình có vi phạm điều gì khác hay không. Vì vậy, cuối cùng bạn nhận ra rằng mình cần những “đánh giá” mà mọi người đang nói đến:

def đánh giá(tập dữ liệu: danh sách[dict]) -> dict:

kết quả = []

cho ví dụ trong tập dữ liệu:

dự đoán = extract_company_with_context(example["text"])

results.append({

"đúng": dự đoán.tên công ty == ví dụ["dự kiến"],

"sự tự tin": dự đoán.sự tự tin

})

trả về {

"độ chính xác": tổng(r["đúng"] cho r trong kết quả) / len(kết quả),

"avg_trust": tổng(r["sự tự tin"] cho r trong kết quả) / len(kết quả)

Nhiệm vụ trích xuất dữ liệu là một trong những nhiệm vụ dễ đánh giá nhất vì luôn có câu trả lời “đúng”. Nhưng ngay cả ở đây, chúng ta cũng có thể tưởng tượng được phần nào sự phức tạp. Trước tiên, chúng ta cần đảm bảo rằng tập dữ liệu được truyền vào luôn đại diện cho dữ liệu thực của chúng ta. Và nói chung: dữ liệu của bạn sẽ thay đổi theo thời gian khi bạn có người dùng mới và những người dùng đó bắt đầu sử dụng nền tảng của bạn một cách trọn vẹn hơn. Luôn cập nhật tập dữ liệu này là một thách thức quan trọng trong việc bảo trì eval: đảm bảo eval đo lường được điều gì đó mà bạn thực sự (và vẫn) quan tâm.

Giai đoạn 7: “Thay vào đó, hãy thử Claude… ồ không”

Không thể tránh khỏi, một số công ty sẽ tung ra một mẫu mới thú vị mà ai đó sẽ muốn thử. Giả sử Anthropic phát hành một mẫu mới. Thật không may, mã của bạn chứa đầy openai.chat.completions.create, chính xác thì mã này sẽ không hoạt động với Anthropic. Lời nhắc của bạn thậm chí có thể không hoạt động tốt với mô hình mới.

Vì vậy, bạn quyết định cần phải cấu trúc lại mọi thứ:

lớp LLMModule:

def __init__(self, chữ ký: type[BaseModel], prompt_key : str):

self.signature = chữ ký

self.prompt_key = nhắc_key

def chuyển tiếp(self, **kwargs) -> BaseModel:

nhắc nhở = get_prompt(self.prompt_key).format(**kwargs)

return self._call_llm(prompt)

def _call_llm(self, prompt: str) -> BaseModel:

# Không xác định mô hình, có thử lại, phân tích cú pháp, xác thực

...

extract_company = LLMModule(

chữ ký=CompanyExtraction,

prompt_key="extract_company_v3"

)

kết quả = extract_company.forward(text= "...")

Bây giờ, bạn đã nhập được chữ ký, mô-đun có thể tổng hợp, phần phụ trợ có thể hoán đổi, logic thử lại tập trung và quản lý lời nhắc tách biệt khỏi mã ứng dụng.

Xin chúc mừng! Bạn vừa xây dựng một phiên bản Dspy tệ hơn.

Điều này trông như thế nào với DSPy

Đây là nhiệm vụ trích xuất tương tự của công ty — với RAG, đánh giá và hoán đổi mô hình — trong DSPy:

import dspy

# Một dòng để định cấu hình mô hình của bạn. Hoán đổi bất cứ lúc nào.

lm = dspy.LM("openai/gpt-5.2")

dspy.configure(lm=lm)

# Chữ ký xác định I/O đã nhập. Không cần mẫu lời nhắc.

class CompanyExtraction(dspy.Chữ ký):

"""Trích xuất tên công ty từ văn bản."""

văn bản: str = dspy.InputField()

tên công ty: str = dspy.OutputField()

sự tự tin: float = dspy.OutputField()

# Một mô-đun soạn các chữ ký vào một đường dẫn.

class CompanyExtractor( dspy.Mô-đun):

def __init__(self):

self.retrieve = dspy.Retrieve(k=5)

bản thân .extract = dspy.ChainOfThought(CompanyExtraction)

def forward(self, text):

bối cảnh = self.retrieve(text).passages

trở lại self.extract(text=text, context=context)

Vậy đó. Nhập I/O, RAG, suy luận theo chuỗi suy nghĩ, bất khả tri về mô hình. Không có bảng quản lý nhanh chóng. Không thử lại trang trí. Không có get_prompt("extract_company_v3").

Đánh giá và tối ưu hóa ngay bây giờ:

# Xác định "tốt" nghĩa là gì

def số liệu(ví dụ, pred, trace=Không có):

trở lại example.company_name.low() == pred.company_name.low()

# Đánh giá

đánh giá = dspy.Evaluate(devset=dev_set, số liệu=số liệu)

evaluate(CompanyExtractor())

# Tối ưu hóa — DSPy viết lại lời nhắc và chọn ví dụ cho bạn

trình tối ưu hóa = dspy.MIPROv2(metric=metric, tự động="trung bình")

được tối ưu hóa = Optimizer.compile(CompanyExtractor(), trainset =train_set)

Bạn có muốn thử Claude không? Một dòng:

dspy.configure(lm=dspy.LM("anthropic/claude-sonnet-4-20250514"))

đánh giá (tối ưu hóa) # cùng một quy trình, mô hình khác nhau

Không có công cụ tái cấu trúc. Không có ứng dụng khách API mới. Không có lời nhắc điều chỉnh lại bằng tay. Trình tối ưu hóa thậm chí có thể tự động tối ưu hóa lại cho mô hình mới!

Dspy đóng gói các mẫu quan trọng mà mọi hệ thống AI nghiêm túc đều cần:

Chữ ký

Đã nhập đầu vào và đầu ra. Cái gì vào, cái gì ra, với một lược đồ.

Mô-đun

Các đơn vị tổng hợp mà bạn có thể xâu chuỗi, hoán đổi và kiểm tra một cách độc lập.

Trình tối ưu hóa

Logic cải thiện lời nhắc, tách biệt khỏi logic chạy chúng.

Đây chỉ là những nguyên tắc cơ bản về công nghệ phần mềm. Tách biệt mối quan tâm. Khả năng kết hợp. Các giao diện khai báo Nhưng vì lý do nào đó, nhiều kỹ sư giỏi lại quên mất những điều này hoặc gặp khó khăn trong việc áp dụng chúng vào hệ thống AI.

Tại sao các kỹ sư giỏi lại viết mã AI tệ

🔄

Vòng phản hồi kỳ lạ

Bạn không thể bước qua lời nhắc. Đầu ra có tính xác suất. Cuối cùng khi nó hoạt động, bạn sẽ không muốn chạm vào nó.

🚀

Áp lực giao hàng

Có được bằng LLM để đi làm giống như một thành tựu. Kiến trúc sạch sẽ mang lại cảm giác sang trọng sau này.

Ranh giới không rõ ràng

Bạn vẽ ranh giới ở đâu? Lời nhắc của bạn là cả mã và dữ liệu. Chẳng có gì quen thuộc cả.

Vì vậy, các kỹ sư sẽ làm những gì có hiệu quả vào thời điểm hiện tại. Lời nhắc nội tuyến. Sao chép-dán với các chỉnh sửa. Giải pháp một lần sẽ trở thành giải pháp lâu dài.

Nhưng 6 tháng sau, họ chìm đắm trong sự phức tạp của những ý tưởng trừu tượng nửa vời của mình.

DSPy buộc bạn phải suy nghĩ trước về những điều trừu tượng này. Đó là lý do tại sao quá trình học tập có vẻ dốc. Giải pháp thay thế là khám phá các khuôn mẫu thông qua nỗi đau.

Những việc bạn thực sự nên làm

Phương án 1: Sử dụng DSPy

Chấp nhận lộ trình học tập. Đọc tài liệu. Xây dựng một vài dự án đồ chơi cho đến khi phần tóm tắt được nhấn mạnh. Sau đó sử dụng nó cho công việc thực tế.

Phương án 2: Ăn cắp ý tưởng

Không sử dụng DSPy mà hãy xây dựng theo các mẫu của nó ngay từ ngày đầu tiên. Xem bên dưới.

Nếu bạn đang ăn cắp ý tưởng, hãy xây dựng theo các mẫu sau:

Đã nhập I/O cho mọi cuộc gọi LLM. Sử dụng Pydantic. Xác định những gì vào và ra.

Tách lời nhắc khỏi mã. Buộc bạn phải nghĩ về lời nhắc như những thứ riêng biệt.

Các đơn vị có thể kết hợp. Mỗi lệnh gọi LLM phải có thể kiểm tra được, có thể mô phỏng được, có thể kết nối được.

Đánh giá cơ sở hạ tầng sớm. Ngày đầu tiên. Làm sao bạn biết liệu một thay đổi có giúp ích hay không?

Các lệnh gọi mô hình trừu tượng. Biến việc hoán đổi GPT-4 cho Claude thành một thay đổi một dòng.

Điểm

DSPy gặp vấn đề trong việc áp dụng vì nó yêu cầu bạn phải suy nghĩ khác trước khi bạn thực sự cảm thấy khó khăn khi nghĩ giống như những người khác.

Các mẫu DSPy thể hiện không phải là tùy chọn. Nếu hệ thống AI của bạn đủ phức tạp, bạn sẽ phát minh lại chúng. Câu hỏi duy nhất là bạn làm điều đó một cách cố ý hay vô tình.

Bạn không cần phải sử dụng DSPy. Nhưng bạn nên xây dựng như một người hiểu được tại sao nó tồn tại.

Nếu điều này gây được tiếng vang, hãy tiếp tục cuộc trò chuyện trên X hoặc LinkedIn!

Tác giả: sbpayne

#discussion