I am passionate about adopting new technologies and thrive in dynamic environments.
Quyết định kiến trúc tốt nhất không phải cái fanciest. Nó là cái giải quyết bài toán với phức tạp tối thiểu, mà vẫn cho tôi thấy được mọi thứ, vẫn cho tôi kiểm soát được.

Mùng ba Tết, rảnh rỗi quá. Tôi ngồi nhìn bốn con chat bot của mình vừa dựng trước tết.
Con bot tên Nhỏ đọc Telegram giao việc cho các con khác, Thằng Nhật xử lý các công việc PM, rồi thêm thằng Thần Tài theo dõi crypto đưa ra nhận định, Thằng Zũn code rồi review code luôn =)).
Mỗi con có cái sổ "memory" riêng (ai xài clawbot rồi thì hiểu, méo giải thích thêm). Nhưng chúng nó không biết gì về nhau. Khi Zũn cần biết tôi đã làm gì về Dow Theory, nó phải tìm lại từ
đầu.
Lúc đó tôi đang ăn dở cái bánh chưng, uống trà san tuyết mà sếp Đặng Trung Kiêntặng, suy tính chuyện này. Nếu có một cái memory chung, thằng nào cũng có thể hỏi được, thì sẽ tốt hơn chứ? Idea này dễ mắc bẫy lắm, nhưng hôm nay tôi quyết định thử =)) vì đang rảnh vãi đái.
Lần mò một hồi thì tôi thấy có một công cụ tên Letta, nó được thiết kế chính xác cho việc này—một cái "agent operating system" với semantic memory. Tôi mở cái macbook, mở telegram "ê Nhỏ, nghiên cứu cho anh cái này nha em yêu...."
Bảy tiếng Mổng 3 rảnh rỗi của tôi, toàn bộ dành cho cái của nợ Letta.
Đến cuối ngày, tôi xóa nó :v.
Đây là story về tại sao - và ai muốn ngựa ngựa như tôi thì thôi - dừng nhé :v.
Nói trước là bài này khá là dài đấy, ai đọc được thì cứ đọc, không đọc được thì bỏ qua, rảnh quá nên xàm thôi. Ok, vô việc nha.
Lúc đầu toi thấy Letta có những thứ bắt mắt. Nó dùng vector embeddings cho memory, nghĩa là nó không chỉ match chữ mà thực sự hiểu ý nghĩa. Nó lưu memory bên ngoài, vậy nếu con bot restart, memory vẫn còn. Nó có HTTP API, vậy tính ra là thằng nào cũng có thể gọi được. Nó tự động index memory, không phải setup phức tạp.
Cảm giác như mọi thứ như bình rượu mơ mà Đinh Quốc Hântặng vậy, ngọt xớt luôn.
Setup cũng dễ. Mất 30p để deploy container. Mất 2 tiếng nữa để cấu hình embedding (thực ra là code thêm cho thằng 9router vụ embeddings api, PR được merge rồi đấy, đừng có đùa), chuyển từ Letta's default sang Gemini embeddings chất lượng cao hơn. Mất 1 tiếng nhập memory từ 8 file. Mất 30 phút setup cron. Sau vài tiếng, mọi thứ chạy ổn định. Không lỗi gì. Kỹ thuật hoàn hảo.
Tôi khoái cảnh này lắm =)), nhưng đời đ' như là mơ.
Để viết theo kiểu truyện đọc cho nó cuốn nhờ :v
Chap: Câu Hỏi Mà Không Ai Trả Lời =((
- Tôi hỏi con bot: "Ê mày, Dow Theory là cái gì?"
Cái thằng bot hắn trả lời đúng. Giải thích chi tiết, kỹ thuật chính xác. Mọi thứ có vẻ là hợp lý vkl. Nhưng tôi hỏi tiếp:
- "Mày lấy cái info này từ đâu? Từ memory files tao import vào, hay từ cái kiến thức training data của mày?"
- Hắn không trả lời.
Tôi hỏi lại thêm mấy lần nữa, hỏi cách khác—"Mày lên memory để lấy thông tin không, hay là tự từ trong đầu mày?" Hắn vẫn không biết nói rõ. Hắn chỉ biết trả lời câu hỏi, không biết giải thích thế nào hắn biết câu trả lời.
Letta API cũng không giúp được. Nó chỉ trả lại cái text mà bot nói. Không có danh sách cái memory nào được sử dụng. Không có điểm số relevance. Không có bất kỳ dấu hiệu nào là nó lên memory để lấy thông tin. Con bot tự quyết định cái gì quan trọng, cách nó viết câu trả lời, có trích dẫn hay không. Tôi không thấy gì trong quá trình đó. Toàn màu shit đen thuiiii/

Từ góc nhìn thiết kế phần mềm, đây là elegant—con bot hoạt động độc lập, không cần sự can thiệp của tôi. Từ góc nhìn của tôi, đây là một cơn ác mộng. Rõ ràng là góc nhìn từ một thằng "cựu senior tech leader của Viettel Software" tôi không thể tin tưởng cái gì tôi không thấy được.
Tôi cố gắng sửa nó ba cách......
Chap 2 : Cố gắng mần chi để rồi chia li - sai bét nhoè luôn
- Cách thứ nhất: tôi thêm instruction vào system prompt—"Hãy luôn nêu nguồn [Từ memory/file]." Tôi hy vọng con bot sẽ nghe lời, sẽ follow instruction. Nhưng đéo anh ẹm, hắn lại làm theo cách của nó =)) mẹ sư, hắn bỏ qua instruction một cách mất dạy. 30 phút burn - cmn chứ :v.
- Cách thứ hai: tôi yêu cầu con bot trả lời dạng JSON với trường sources. Con bot mà tôi dùng (gpt-4o-mini) không hỗ trợ cái này. Chỉ GPT-4 Turbo mới có, nhưng cái đó đắt gấp 3 lần. 30 phút khác burn (cái ni thì chấp nhận do mình ngu chọn sai model ).
- Cách thứ ba: tôi thử dùng model Gemini để tiết kiệm token. Nhưng Letta cấu hình khác nhau cho Gemini vs OpenAI. Nó trả về lỗi 502, không setup được. 30 phút nữa mất.
- Cách thứ tư tôi nghĩ: bỏ qua HTTP, gọi thư viện Letta trực tiếp để skip network latency. Nhưng lúc này tôi dừng lại. Tôi nhận ra là vấn đề không phải ở cách implement chi tiết. Vấn đề nằm sâu hơn —> kiến trúc của nó sai cơ bản.
![Có thể là đồ họa về văn bản cho biết 'Timeline cố gắng fix: Ảnh 2 L1 : Attempt 1 System Prompt Citation Instruction: "ALWAYS cite [Source: memory memory/file.md]" /file.md]" file. Result: Model ignores instruction Effort: 30 phút L2: Attempt 2 Structured Output (JSON) Request: {answer: "..." sources: [...] Result: X gpt-40-mini không support Need: GPT-4 Turbo (expensive) Effort: 30 phút L3: Attempt 3 Model Downgrade Switch: gpt-40-mini- o-mini Gemini (cheaper) Result: X HTTP 502 (config incompatible) Issue: Letta provider format mismatch Effort: 30 phút Conclusion: Root Cause: Architecture mismatch NOT implementation problem x Cannot fix with more engineering effort'](https://scontent.fhan15-1.fna.fbcdn.net/v/t39.30808-6/638546260_4007420046058126_6239000246438950932_n.jpg?_nc_cat=101&ccb=1-7&_nc_sid=13d280&_nc_eui2=AeHV1BIVb5xw6YmiEtYyX8OvOX05l6ZfCno5fTmXpl8Ken48RTYuzFVSqznzGA7CUOhtUpdWpq2uG4UKvD5tsjzR&_nc_ohc=PFfSZ3S5FfEQ7kNvwGmFxa7&_nc_oc=AdlIuSfk12ZVaye7tkqffcbmbUxWAmTodRr3FCX5arj-yKcr-XPC53RW_7hUK9dvDLzengIfqUxE6Ddz0qcXhsdp&_nc_zt=23&_nc_ht=scontent.fhan15-1.fna&_nc_gid=Hj9dJQ_Ui4vlQGRVbxOt8g&oh=00_Afvqk-dgaD6XVE9dEzFzb_Www_G_ZYnXuWxLfRCjRgk8ZA&oe=69A247CE)
Chap 3: Nhìn Nhận Sự Thực
Có một điều phải công nhận là Letta hoạt động tốt. Nó tìm memory đúng. Embedding chất lượng. System chạy ổn định. Từ góc nhìn kỹ thuật cái đó là thành công—deployment mượt, configuration đúng, không crash, tất cả feature hoạt động.
Nhưng từ góc nhìn công việc, nó không giải quyết được cái mà tôi cần. Tôi cần phải thấy—tôi cần phải biết con bot lấy info từ đâu, tôi cần xác minh nó sử dụng memory hay chỉ dùng kiến thức có sẵn. Tôi cần kiểm soát—tôi cần quyết định cái info nào được cho con bot biết, cái gì thì không. Letta không cho tôi bất cứ cái nào cả.
Letta thiết kế cho sự tự chủ của bot. Bot hoạt động độc lập, tự quyết định mọi thứ, không cần tôi can thiệp. Đó là điều tốt trong một số trường hợp. Nhưng ở đây, tôi không cần bot tự chủ. Tôi cần nó minh bạch, cần nó nói rõ nó đang làm gì.
Đối với tôi khi phải chọn giữa hai, minh bạch luôn thắng vì nó ảnh hưởng đến sự tin tưởng. Và tin tưởng là tất cả. Dữ liệu không minh bạch thì có ý nghĩa chi mô.
Thế là xong, tôi yêu cầu con Nhỏ xoá hếtttt
Tôi xóa Letta hoàn toàn. Cron job bị xóa. Script bị xóa. Container bị xóa. Không còn dấu vết.
Điều đáng chú ý là tôi không cố gắng "sửa" nó thêm nữa, không burn thêm 14 tiếng cố fix. Khi vấn đề ở kiến trúc cơ bản, thêm effort không giúp được gì. Đó chỉ là waste time. Sunk cost fallacy là cái bẫy mà rất nhiều người rơi vào mà tôi thấy nhiều anh em bị vậy, cứ cố gắng vì đã invest rồi. Tôi không muốn rơi vào sâu thêm tí nào nữa :v 7 tiếng là quá đủ rồi kk.
Thế thì, cũng phải có tổng kết bài học chứ nhề :v
Chap 4: Qua đây thì ta học được thêm cái chi ?
- Thứ nhất: Tự chủ và Minh Bạch Xung Đột
Letta thiết kế để con bot có tự chủ. Hắn tự quyết định cái gì quan trọng, cách trả lời, có cite source hay không. Đó là đẹp từ góc nhìn code. Nhưng cái tự chủ này che giấu mọi thứ. Khi tôi cần thấy đang xảy ra cái gì, tự chủ trở thành vấn đề, không phải feature.
- Thứ hai: Tính Minh Bạch Không Thương Lượng Được
Trước khi dùng cái gì mới, hỏi một câu đơn giản: "Tôi sẽ thấy được nó đang làm gì không?" Nếu câu trả lời là "nó hoạt động nhưng bạn không thấy chi tiết," đó là cảnh báo đỏ. Nhất là trong AI, cái "thấy được" quan trọng nhất vì nó ảnh hưởng đến khả năng tôi debug, tin tưởng, và xác minh kết quả. Nếu bạn không thấy, bạn không thể kiểm soát. Nếu không kiểm soát, bạn không thể tin.
- Thứ ba: Đơn Giản Luôn Thắng
Một hàm gọi mà trả về kết quả rõ ràng lại thắng một kiến trúc phức tạp với nhiều tầng. Khi hai cách giải quyết cùng bài toán, cái đơn giản luôn win. Chi phí bảo trì cái đơn giản là gần bằng không. Chi phí của cái phức tạp là vô hạn.
- Thứ tư: YAGNI Cũng Áp Dụng Cho Kiến Trúc
Tôi cài Letta vì tôi nghĩ 2 con bot Zũn và Nhật sẽ cần query memory của tôi qua HTTP. Cái use case tương lai đó. Nhưng tương lai không đến.
Tôi xây kiến trúc cho cái tôi tưởng tượng, không phải cái tôi cần ngay hôm nay. Đó là sai lầm. Nếu cái gì không cần hôm nay, đừng xây hôm nay. Ngày mai sẽ có yêu cầu khác, bạn không biết yêu cầu đó sẽ là cái gì.
Thứ năm: Sunk Cost Không Phải Lý Do
Tôi đã mất 7 tiếng. Tôi có thể spend thêm 14 tiếng nữa để cố. Nhưng khi kiến trúc sai, tiền sửa là lãng phí. Thừa nhận thua lỗi, đi tiếp. Đó là quyết định chuyên nghiệp. Nó khó, nhưng đó là điều đúng. Đây là thời gian của tôi chứ nếu mà đi làm thì chắc công ty đuổi moẹ tôi mất.
Cái này xảy ra thường xuyên. Code đẹp. Kiến trúc sạch. Hệ thống làm đúng cái tôi bảo nó làm. Nhưng tôi bảo nó làm sai thứ. Spec hỏi sai câu hỏi.
Quyết định kiến trúc tốt nhất không phải cái fanciest. Nó là cái giải quyết bài toán với phức tạp tối thiểu, mà vẫn cho tôi thấy được mọi thứ, vẫn cho tôi kiểm soát được.
Đôi khi, quyết định chuyên nghiệp nhất là nói "không" với công nghệ hay nhưng không phù hợp.
Letta không thất bại vì nó tồi. Nó thất bại vì tôi hỏi nó giải quyết sai bài toán.
Đó không phải lỗi kỹ thuật. Đó là lỗi suy luận của tôi, do tôi ngu :v
Cũng khuya rồi, hết tết rồi.
Chúc mọi người năm mới sức khoẻ, an khang thịnh vượng.
Để thêm vài cái tag cho hắn viral tí, Khai phím đầu năm mà ít like là hơi buồn