ในบทความนี้
In this post
1. ปัญหาทางวิศวกรรม
เป้าหมายบทนี้
กำหนดจำนวน call จำนวนแก้ร่าง และเวลาให้ชัด แยก retry ของ inference จาก action ที่เกิดผลจริง
loop แบบ 'ลองใหม่จนกว่าจะผ่าน' ที่ไม่มีเพดานเปลี่ยนความไม่แน่ใจเป็นต้นทุนและเวลาที่คุมไม่ได้ อีกทั้งอาจเรียนรู้ให้เอาใจ evaluator มากกว่าแก้งาน กำหนดงบร่วมก่อน call แรก companion ตั้งตัวอย่างไว้ห้า logical provider calls แก้ candidate ได้หนึ่งครั้ง และจำกัดเวลาเล็กสำหรับออฟไลน์ เป็นค่าประกอบการสอน ไม่ใช่ SLO production adapter จริงมี HTTP timeout ชัดและงบ workflow ที่ยาวกว่า
นับ operation ให้ตรง รอบปกติมี decide, generate, judge ถ้า behavior ผิดจะข้าม judge แล้วแก้ candidate หนึ่งครั้ง ดังนั้น wrong-then-correct ใช้สี่ logical calls และสอง attempts ถ้าคุณภาพไม่ผ่านซ้ำจะใช้ครบห้า call แล้ว review ตัวนับนี้วัด interface ของ provider ไม่ใช่จำนวน HTTP FixtureProvider ไม่มี network ส่วน JevProvider ใช้ร่าง local และยิง HTTP เฉพาะ decision ห้ามนำจำนวน logical call ไปอ้างเป็น token usage หรือต้นทุน
2. ขอบเขตที่ต้องออกแบบ
transport retry กับ semantic repair แก้คนละปัญหา 429 ชั่วคราวอาจเหมาะกับ backoff ที่มีขอบเขตตามสัญญา provider [1] ส่วนคำอธิบายที่ถูก schema แต่ไม่พออาจต้องสร้าง candidate ใหม่ adapter ในคอร์สเลือก review เมื่อ transport พลาดและยังไม่ได้ทำ auto retry shell ตรวจเวลาก่อนและหลัง call แต่หยุด call ที่ block กลางทางไม่ได้ production ต้องมี cancellation ส่ง remaining deadline, jitter, retry limit และ reconciliation เมื่อไม่รู้ผล ต้องบอกข้อจำกัดก่อนเรียกว่า hard deadline
3. อ่าน implementation
ส่วนโค้ดจาก companion เพื่ออ่านประกอบ ใช้คำสั่งในหัวข้อ 5 เพื่อรันตัวอย่างที่ครบ dependency
from workbench.runtime import run, request, candidate, FixtureProvider
wrong = candidate("def discount_cents(price, percent):\n return price - percent\n")
result = run(request(), FixtureProvider(candidates=[wrong, candidate()]),
max_calls=5, max_revisions=1, seconds=2)
print(result["state"], result["attempts"], result["calls"])
การแก้ตาม feedback เป็น pattern ที่มีเหตุผล และมีงาน Reflexion เป็นตัวอย่างวิจัย [2] แต่ต้องวัดผลกับงานจริง candidate ที่แก้แล้วต้องผ่าน output และ behavior ใหม่ พร้อม quality verdict ที่ผูกใหม่ ใช้ approval เดิมไม่ได้ ห้ามนำ loop นี้ไปใช้กับ PR การจ่ายเงิน หรือ deploy แบบตรง ๆ เพราะ timeout หลัง server ทำสำเร็จต้องตรวจสถานะหรือใช้ idempotency แล็บไม่มีผลภายนอก จึงตรวจบทเรียนที่แคบกว่าได้ชัด: แก้ภายในงบแล้วผ่านหนึ่งครั้ง และหยุดให้เห็นเมื่อพลาดต่อเนื่อง
4. เปรียบเทียบผลที่ได้
| เส้นทาง | ผลที่สังเกตได้ |
|---|---|
| ก่อนเพิ่มด่านนี้ | วนแก้และใช้ทรัพยากรจน evaluator ยอมผ่าน |
| หลังเพิ่มด่านนี้ | แก้ได้หนึ่งครั้ง ถ้ายังไม่ผ่านจบที่ review |
ผลต่อไปนี้มาจาก fixture ที่กำหนดคำตอบไว้เพื่อตรวจสถาปัตยกรรม ไม่ใช่ผลวัดความแม่น ความเร็ว หรือต้นทุนของ Jev จริง
{
"bounded_repair": "accepted_draft",
"attempts": 2,
"calls": 4,
"no_budget": "review"
}
5. รัน ทำให้พัง และอธิบาย
Part 13 code · Implementation · Tests: test_bounded_repair · Exercise
git clone https://github.com/Anirach/ai-core-engineering-workbench.git
cd ai-core-engineering-workbench
git checkout 18cdfcd4156d3d02acb8badf3b3a0a823113e0ed
python3 -m workbench.lesson 13
python3 -m unittest tests.test_boundaries.BoundaryTests.test_bounded_repair -vลองทำด้วยตัวเอง
ตั้ง max_calls เป็นศูนย์ แล้วจำลอง quality failure ถาวร ตรวจว่าหยุดแน่นอนและไม่ส่งร่างที่ไม่ผ่านในสถานะยอมรับ
สิ่งที่ต้องส่ง: input ที่ลอง สถานะและเหตุผลที่ได้ และคำอธิบายว่าด่านใดเป็นผู้รับผิดชอบ ห้ามแก้ expected result เพียงเพื่อให้ test ผ่าน
6. แหล่งอ้างอิงและขอบเขต
เอกสารต้นทางและข้อจำกัด
ตรวจเอกสาร 2 พฤศจิกายน 2026 ตัวอย่างและ threshold เป็นการออกแบบเพื่อการสอน การอ้าง [1], [2] ตรงกับลำดับข้างล่าง ยังไม่ได้วัด live API
- TypeSafe, Request rules and errors429/529 and bounded transport backoff.
- Shinn et al., Reflexion (2023)Feedback-driven revision as research context, not a guarantee of improvement.
1. The engineering problem
Learning outcome
Make call count, revision count and elapsed time explicit; never retry an external effect as though it were inference.
An unbounded 'try again until it passes' loop converts uncertainty into uncontrolled cost and latency. It can also overfit an evaluator rather than improve the task. Define a shared budget before the first provider call. The companion defaults to five logical provider calls, at most one candidate revision, and a small elapsed-time limit for offline execution. These are teaching values, not production SLOs. A live decision adapter uses explicit HTTP timeouts and a longer workflow budget.
Count operations honestly. The first pass uses decide, generate and judge. A behavior failure can skip the judge and request one new candidate, so wrong-then-correct uses four logical calls and two candidate attempts. A persistent quality failure consumes all five logical calls and ends in review. The call counter measures the provider interface, not HTTP traffic: FixtureProvider has no network, while JevProvider supplies a local draft and makes HTTP requests only for decisions. Do not publish logical-call counts as token usage or cost.
2. The boundary to design
Transport retry and semantic repair solve different problems. A temporary 429 may justify bounded backoff according to the provider's error contract [1]. A valid but inadequate explanation may justify a new candidate. The tutorial adapter fails to review rather than implementing automatic transport retries. Its shell checks time before and after calls; it does not preempt a blocking call. A production implementation needs cancellation, remaining-deadline propagation, jitter, retry limits and reconciliation for ambiguous results. State those limitations before calling the mechanism a hard deadline.
3. Read the implementation
Implementation excerpt from the companion. Run the complete lesson below with its imports and fixtures.
from workbench.runtime import run, request, candidate, FixtureProvider
wrong = candidate("def discount_cents(price, percent):\n return price - percent\n")
result = run(request(), FixtureProvider(candidates=[wrong, candidate()]),
max_calls=5, max_revisions=1, seconds=2)
print(result["state"], result["attempts"], result["calls"])
Feedback-driven revision is a plausible workflow pattern, illustrated by Reflexion research [2], but improvement must be measured for the task. A repair must re-enter output and behavior checks and receive a newly bound quality verdict. It cannot reuse old approval. Never apply the same loop blindly to a PR, payment or deployment action: a timeout after the server committed requires a status check or idempotency mechanism. Our draft-only lab avoids effects entirely, making the narrower outcome easy to verify: bounded repair succeeds once; persistent failure terminates visibly.
4. Compare the outcomes
| Approach | Observable outcome |
|---|---|
| Before this control | Repair loops keep spending until a judge approves. |
| After this control | One revision succeeds or the workflow stops at review. |
The following output comes from scripted fixtures that verify architecture behavior. It is not a measurement of live Jev accuracy, latency, or cost.
{
"bounded_repair": "accepted_draft",
"attempts": 2,
"calls": 4,
"no_budget": "review"
}
5. Run, break, and explain
Part 13 code · Implementation · Tests: test_bounded_repair · Exercise
git clone https://github.com/Anirach/ai-core-engineering-workbench.git
cd ai-core-engineering-workbench
git checkout 18cdfcd4156d3d02acb8badf3b3a0a823113e0ed
python3 -m workbench.lesson 13
python3 -m unittest tests.test_boundaries.BoundaryTests.test_bounded_repair -vYour turn
Set max_calls to zero, then force a permanent quality failure. Verify finite termination and that rejected drafts are not returned as accepted.
Keep three artifacts: the input you tried, the resulting state and reason, and an explanation of which boundary owns that result. Do not change an expected result merely to make a test pass.
6. Sources and limits
Primary sources and evidence limits
Sources checked 2 November 2026. Examples and thresholds are teaching designs. Inline [1], [2] follow the order below. Live API performance has not been measured.
- TypeSafe, Request rules and errors429/529 and bounded transport backoff.
- Shinn et al., Reflexion (2023)Feedback-driven revision as research context, not a guarantee of improvement.