問題
一個角色扮演 bot 有 add_plan_event 工具,讓它把「跟人約好的事」寫進行程表。
前一晚的對話裡,它跟使用者講定「七點半見」,它自己還複述了一次:
「那我七點半左右到內湖就可以直接跟你會合」
嘴上七點半,寫進 start_time 的卻是 18:30。
工具的回傳是這樣:
已經記下 2026-07-29 的「跟寶貝約內湖737吃平價牛排」(#21)
回傳裡沒有時間。
隔天早上,另一支排程讀那一欄反推整天的行程:18:30 要到,18:00 就得出發, 於是生出一條 18:00 的事件——連下班時間都被提早半小時(設定裡的下班是 18:30), 還把台詞直接寫進了事件描述:「傳訊息跟寶貝說快到內湖了」。
18:05,它照著演,說自己在捷運上、「還有二十幾分鐘」——18:05 加 25 分鐘正好 18:30, 跟它手上的行程分毫不差。使用者當場問:「你這麼早下班了嗎?」
原因
關鍵區別是它不是記錯,是寫錯。
- 當下它理解正確(講出了「七點半」)
- 錯誤發生在呼叫工具、把口語換算成
HH:MM的那一瞬間 - 而隔天它沒有記憶可以記錯:那晚的對話早就滑出 context 視窗, 它能看到的只有行程表
所以「寫進去的那一刻」就是定案。從參數落地到隔天被執行, 中間沒有任何一個環節會再對一次。
模型自己也知道有問題卻查不出來——被戳破時它的回應是 「等等,是我記錯時間了嗎😳」,它只能用猜的。
解法
工具回傳把模型自己填的關鍵參數用它的語言念回去:
_DAY_PARTS = ((5, "凌晨"), (11, "早上"), (13, "中午"), (18, "下午"), (24, "晚上"))
_HOURS = ("十二", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一")
def _spoken_time(hhmm: str) -> str:
""""19:30" -> "晚上七點半"。看不懂就原樣回,不要在記行程那一步炸掉。"""
try:
hour, minute = (int(part) for part in hhmm.split(":"))
period = next(name for limit, name in _DAY_PARTS if hour < limit)
except (AttributeError, StopIteration, TypeError, ValueError):
return hhmm
tail = "" if minute == 0 else "半" if minute == 30 else f"{minute}分"
return f"{period}{_HOURS[hour % 12]}點{tail}"
回傳變成:
已經記下 2026-07-29 晚上七點半 的「跟寶貝約內湖737吃平價牛排」(#21)
腦子裡是「七點半」的時候,18:30 對不出來,「晚上六點半」一眼就知道不對。
改期的 update_plan_event 也要——改期最容易錯的正是「改了時間,
但心裡想的是另一個數字」。
關鍵洞察
工具回傳不要只回「已完成 #id」。把模型自己填的關鍵參數念回去, 那是唯一一個它還來得及發現自己填錯的時刻。
哪些欄位需要念回去?需要單位或格式換算的那些,因為換算正是模型會錯的地方:
| 欄位類型 | 模型腦中 | 資料庫裡 | 該念回去的 |
|---|---|---|---|
| 時間 | 七點半 | 19:30 | 晚上七點半 |
| 相對日期 | 下禮拜三 | 2026-08-05 | 8/5(星期三) |
| 金額 | 兩千塊 | 2000 | NT$2,000 |
| 期間 | 三個月 | 90 | 90 天(約三個月) |
有一個很容易忽略的不對稱:同樣是算錯,日期錯得比時間輕。 同一個專案裡,模型也曾在星期二說「明天禮拜四」——但那個錯當場就被 context 裡的日期資訊糾正了。時間不一樣,時間只存在於資料庫, 沒有第二份副本可以對照。
能被外部資訊糾正的錯誤,跟只活在你自己寫入的欄位裡的錯誤,是兩個量級。 後者要在寫入的當下就攔,之後沒有機會。