FDE PulseViệc làm FDE đang mở 434Mới đăng 7 ngày qua 27Chủ đề nổi bật: Đào tạo kỹ năng FDE tại Đông Nam Á

Tờ báo của nghề Forward Deployed Engineer

Bách khoa

Dựng repo portfolio FDE: agent đơn giản, bộ eval từ lỗi thật, README và video 3 phút

Demo chạy đẹp chỉ chứng minh agent đúng được một lần. Repo đáng gửi đi phải cho thấy agent hỏng ở đâu và hỏng thường xuyên đến mức nào.

Đồ hoạVòng lặp từ log đến pass^k
  1. 1Ghi log mọi lần chạyMỗi lần chạy một dòng JSONL: input, các lần gọi tool, verdict cuối
  2. 2Đọc log, lập danh sách lỗiMỗi lỗi kèm đường dẫn tới file log, ví dụ đọc sai số 1.200.000
  3. 3Biến lỗi thành eval case20-50 case, kiểm tra bằng assertion pytest trước, đọc transcript để soát grader
  4. 4Đo pass^kĐúng 80% mỗi lần thì pass^3 = 0,8 × 0,8 × 0,8 = 51,2%
  5. 5Sửa agent, chạy lạiCase còn đỏ là danh sách việc tiếp theo, ghi vào README
  6. ↻ Lặp lại từ bước 1

Mỗi lỗi đọc được trong log trở thành một eval case, và pass^k cho biết agent có đáng tin qua nhiều lần chạy hay không.

Đồ hoạ: FDE Times

Tóm tắt nhanh

  • Một dự án làm sâu, có case study, thắng nhiều demo bóng bẩy; chọn kịch bản doanh nghiệp thật với dữ liệu bẩn.
  • Giữ vòng lặp agent đơn giản và dễ đọc, đầu tư vào mô tả tool, ghi log mọi lần chạy ngay từ đầu.
  • Bộ eval nên bắt đầu từ lỗi thật, dùng assertion rẻ trước, báo cáo pass^k và đọc transcript để kiểm tra grader.
Chia sẻLinkedInFacebookX

Giả sử agent của bạn trả lời đúng 80% số lần chạy. Nghe có vẻ ổn, cho đến khi bạn tính xác suất nó đúng cả ba lần liên tiếp: 0,8 × 0,8 × 0,8 = 51,2%.

Vì thế, một repo portfolio FDE không nên dừng ở một demo chạy đẹp. Đó chỉ là một lần thử. Repo đáng gửi đi phải cho người xem thấy agent hỏng ở đâu, hỏng bao nhiêu lần và bạn đã xử lý từng lỗi ra sao. Cách đo dựa trên những gì Anthropic, OpenAI và Hamel Husain khuyên khi xây eval cho hệ thống AI.

Hướng dẫn trên blog của FDE Academy, một đơn vị đào tạo, nói thẳng rằng một dự án đã triển khai, có case study viết thành bài, có sức nặng hơn tám demo được trau chuốt.

Đây là lời khuyên chứ chưa phải quy luật, nhưng lý lẽ khá dễ hiểu: hệ thống chạy được trên dữ liệu thật cho thấy nhiều kỹ năng hơn tám prototype chạy trên dữ liệu sạch.

Dưới đây là năm bước để dựng một repo như vậy. Code trong bài là bản phác thảo rút gọn: hàm gọi model để trống để bạn tự gắn SDK mình dùng.

Bước 1: Chọn bài toán nào đủ “doanh nghiệp”?

Cũng theo hướng dẫn của FDE Academy, bạn nên chọn một kịch bản doanh nghiệp thực tế, chỉ làm MVP thay vì theo đuổi cả tầm nhìn, và dùng dữ liệu bẩn, thật hoặc giống thật. Điều kiện cuối cùng là thứ phân biệt portfolio FDE với bài tập khóa học.

Thử hình dung một công ty phân phối nhận hóa đơn nhà cung cấp qua email. Có file PDF scan bị nghiêng, có hóa đơn ghi “VND”, có hóa đơn ghi “đ”, có mã số thuế bị gõ thiếu số. MVP chỉ làm một việc: agent đọc hóa đơn, đối chiếu với đơn đặt hàng, rồi trả về “khớp”, “lệch” kèm lý do, hoặc “cần người kiểm tra”.

invoice-agent/
  agent/loop.py        # vòng lặp lõi
  agent/tools.py       # tool + mô tả
  data/raw/            # hóa đơn bẩn
  logs/                # mỗi lần chạy một file JSONL
  evals/cases.jsonl    # bộ case
  evals/test_basic.py  # assertion kiểu pytest
  README.md

Kiểm tra: bạn viết được phạm vi MVP trong một câu. Nếu câu đó dùng chữ “và” hơn hai lần thì nên cắt bớt.

Bước 2: Vì sao vòng lặp lõi phải đọc được trong năm phút?

Trong bài “Building effective agents”, Anthropic khuyên tìm giải pháp đơn giản nhất có thể và chỉ thêm độ phức tạp khi thật sự cần. Họ cũng cảnh báo rằng framework thường thêm các lớp trừu tượng che khuất prompt và response bên dưới. Với portfolio, đây là lỗi nặng: người review mở repo mà không tìm thấy prompt thì không đánh giá được cách bạn tư duy.

# agent/loop.py — phác thảo rút gọn
def run(invoice_text, po, call_model, tools, log):
    messages = [system_prompt(), user_msg(invoice_text, po)]
    for step in range(8):                  # giới hạn số bước
        reply = call_model(messages, tools)
        log.write(step, messages, reply)   # ghi lại mọi thứ
        if reply.tool_call is None:
            return parse_verdict(reply)
        result = tools[reply.tool_call.name](**reply.tool_call.args)
        messages += [reply, tool_result(result)]
    return {"verdict": "needs_review", "reason": "hết số bước"}

Phần đáng đầu tư công sức là tool. Anthropic gọi phần này là agent-computer interface và khuyên thiết kế nó cẩn thận: viết tài liệu tool kỹ lưỡng và kiểm thử. Áp dụng vào repo này, docstring của mỗi tool cần nói rõ định dạng đầu vào, khi nào trả về rỗng và kèm ví dụ.

def lookup_po(po_number: str) -> dict:
    """Tra đơn đặt hàng theo mã PO.
    po_number: dạng 'PO-' + 6 chữ số, ví dụ 'PO-004512'.
    Trả về {} nếu không tìm thấy; KHÔNG đoán mã gần đúng."""

Kiểm tra: đưa loop.py cho một người chưa từng thấy repo. Sau năm phút đọc, họ kể lại được agent làm gì.

Bước 3: Ghi log trước khi viết eval

Tài liệu “Evaluation best practices” của OpenAI khuyên ghi log mọi thứ ngay trong lúc phát triển, để sau này lấy log ra làm eval case. Trong bài “Your AI Product Needs Evals”, Hamel Husain còn yêu cầu gỡ bỏ mọi trở ngại khi xem dữ liệu. Nếu xem một lần chạy mà phải mở ba file và cuộn mỏi tay, bạn sẽ sớm bỏ thói quen xem.

Cách rẻ nhất là mỗi lần chạy ghi một dòng JSONL gồm input, từng lần gọi tool và verdict cuối. Sau đó viết một script nhỏ in từng lần chạy ra terminal cho dễ đọc.

Chạy agent 20-30 lần trên data/raw/ rồi đọc hết. Rất có thể bạn sẽ gặp những lỗi không lường trước, chẳng hạn agent hiểu “1.200.000” là một triệu hai trăm nghìn hay là 1,2.

Kiểm tra: bạn có một danh sách lỗi thật do chính bạn ghi lại, mỗi lỗi kèm đường dẫn tới file log.

Bước 4: Bộ eval bắt đầu từ lỗi, không từ lý thuyết

Anthropic định nghĩa eval rất gọn: đưa cho hệ thống AI một input, rồi dùng logic chấm điểm trên output để đo xem nó có thành công không. Theo họ, 20-50 task đơn giản lấy từ lỗi thật đã là điểm khởi đầu tốt. Danh sách lỗi ở bước 3 chính là nguyên liệu cho bộ eval.

{"id": "c07", "invoice": "data/raw/inv_07.pdf", "po": "PO-004512", "expect": "mismatch", "must_mention": "số lượng"}

Husain gợi ý lớp đầu tiên nên là các assertion nhanh và rẻ, giống như bạn vẫn viết trong pytest. Việc nào code tự kiểm tra được thì cứ để code làm, chỉ nhờ model chấm những phần code chịu thua.

# evals/test_basic.py — phác thảo
@pytest.mark.parametrize("case", load_cases("evals/cases.jsonl"))
def test_verdict(case):
    out = run_case(case)
    assert out["verdict"] == case["expect"]
    assert case["must_mention"] in out["reason"]
pytest evals/ -q

Theo Anthropic, eval cho agent thường kết hợp ba loại grader: dựa trên code, dựa trên model và do con người chấm. Với repo portfolio, lớp code cần thật chắc. Thêm một grader dựa trên model để chấm xem lý do agent đưa ra có hợp lý không, và ghi rõ trong README phần nào bạn tự chấm tay.

OpenAI gọi cách làm này là eval-driven development: đánh giá sớm, đánh giá thường xuyên, và viết test riêng cho từng giai đoạn.

Con số nên đặt ở đầu README là pass^k. Anthropic phân biệt pass@k với pass^k: pass^k là xác suất cả k lần thử đều thành công. Phép tính ở đầu bài chính là pass^3 của một agent đúng 80% mỗi lần, với giả định các lần chạy độc lập nhau: 51,2%.

Thử hình dung một nhân viên kế toán dùng agent đó ba lần mỗi ngày. Khả năng cả ba lần trong ngày đều đúng chỉ hơn một nửa, nên gần như cứ hai ngày người đó sẽ gặp lỗi một lần.

Cần cẩn thận khi đọc con số này nếu bộ case còn nhỏ. Với 20 case, chỉ một case đổi kết quả là pass^k đã nhích 5 điểm phần trăm, và k càng nhỏ thì vận may của một lần chạy càng dễ làm đẹp số liệu.

Cách làm thực tế là chạy mỗi case ít nhất 3 lần, chạy lại cả bộ thêm một lượt để xem con số có nhảy nhiều không, và luôn ghi kèm số case cùng giá trị k cạnh kết quả.

Bước cuối của eval là bước hay bị bỏ qua nhất. Anthropic nhấn mạnh rằng bạn không thể biết grader có chấm đúng không nếu không đọc transcript và điểm số của nhiều lần thử. Hãy chọn ngẫu nhiên mười lần chạy được chấm “pass” và đọc lại. Grader quá dễ dãi còn nguy hiểm hơn một agent kém.

Kiểm tra: pytest chạy hết toàn bộ case, nhưng không cần tất cả đều pass. Case được lấy từ lỗi thật, nên một số case vẫn đỏ là chuyện bình thường, và chúng chính là danh sách việc cần làm tiếp. README cần ghi rõ bao nhiêu case pass trên tổng số, kèm bảng pass^3 theo từng nhóm lỗi.

Bước 5: README và video dành cho người không chạy code

GitHub Docs liệt kê những câu hỏi một README nên trả lời, bắt đầu từ việc dự án làm gì. Với repo FDE, README nên viết như một case study ngắn.

Trong đó có bài toán của khách hàng giả định, phạm vi MVP và những gì bạn cố ý bỏ qua, kết quả eval kèm pass^k, ba lỗi còn tồn tại, và cách bạn sẽ xử lý nếu có thêm hai tuần.

Phần “lỗi còn tồn tại” đáng được viết kỹ. Nó cho người đọc thấy bạn đo được và nói thẳng về giới hạn của hệ thống mình làm ra.

Video 3 phút nên làm cho người quản lý xem, không phải cho kỹ sư. Có thể chia thế này: 30 giây nêu bài toán, 90 giây chạy agent trên một hóa đơn bẩn có thật trong data/raw/, 45 giây mở kết quả eval và đọc con số pass^k, 15 giây cuối kể một lỗi chưa sửa được. Đừng quay cảnh gõ code.

Những lỗi hay gặp

Lỗi phổ biến nhất là chọn một framework nặng trước khi biết mình cần gì, để rồi prompt bị chôn dưới năm lớp class. Lỗi thứ hai là dùng dữ liệu sạch tự sinh, khiến eval toàn màu xanh mà chẳng chứng minh được gì. Lỗi thứ ba là chỉ báo cáo lần chạy tốt nhất thay vì pass^k.

Kỹ năng này dùng vào việc gì ở chỗ khách hàng?

Năm bước trên không chỉ dùng cho portfolio. Repo của bạn là nơi tập trước những thói quen đó.

Khi viết CV, đừng ghi chung chung “built AI agent”. Hãy viết một dòng có số liệu, ví dụ “dựng bộ 40 eval case từ lỗi thật, nâng pass^3 từ X lên Y”, trong đó X và Y lấy từ chính repo của bạn. Nếu JD có chữ “evaluation” hay “reliability”, hãy gửi kèm đường link repo này.

Hãy để repo trả lời trước câu hỏi mà khách hàng nào rồi cũng sẽ hỏi: agent hỏng ở đâu, và hỏng thường xuyên đến mức nào.

6 nguồn
Đọc tiếp trên lộ trình · Chặng 8: Sự nghiệpKể dự án khi phỏng vấn FDE: cách trả lời câu hỏi “bạn đã đánh đổi gì?”Câu hỏi về đánh đổi kiểm tra xem bạn có thấy mình đã bỏ lại thứ gì, vì sao bỏ, và đã giải thích chuyện đó với khách hàng ra sao.