iT邦幫忙

2026 iThome 鐵人賽

DAY 14
0

前幾天已完成 PM、Research、Creative 與 Finance Agent。不過,產生結果和檢查結果是兩件事:草案可能缺少研究依據、執行方式不清楚,或把待查證資訊寫成事實。

今天建立 Review Agent,先處理輸入格式、結構化審查結果與單元測試。它目前仍是獨立類別,尚未接進 Discord,也不會自動呼叫其他 Agent。

今天完成的內容

  • 建立 ReviewAgent
  • 定義輸入與四項檢查表
  • 限制審查狀態與問題優先順序
  • 使用 Pydantic 檢查欄位是否一致
  • 由 Python 決定能不能再修改一次
  • 使用 Fake LLM Service 測試審查流程

Review Agent 檢查什麼?

欄位 檢查內容
completeness 草案內容是否齊全
creativity 方案是否有明確做法
credibility 研究依據與待查證資訊是否分清楚
feasibility 執行方式、成本與風險是否合理

每項都要回傳通過狀態與原因,Python 不必再從一大段評論中猜測審查結果。

定義 Review 輸入

ReviewAgent.respond() 不接受任意文字,而是要求固定 JSON:

class ReviewRequest(BaseModel):
    model_config = ConfigDict(extra="forbid")

    project_id: NonEmptyText
    draft: NonEmptyText
    revision_count: RevisionCount = 0
  • project_id:草案所屬專案
  • draft:要檢查的內容
  • revision_count:已修改次數,預設為 0

修改次數只能是 0 或 1:

RevisionCount = Annotated[
    int,
    Field(strict=True, ge=0, le=1),
]

0 表示初稿還能修改一次,1 表示已修改過。輸入 2 時會在呼叫 LLM 前被拒絕。

定義審查輸出

每個檢查項目包含結果與原因:

class ChecklistItem(BaseModel):
    passed: bool
    reason: NonEmptyText

需要修改時,不能只說「內容不完整」,還要指出問題、修改方式與優先順序:

class ReviewIssue(BaseModel):
    problem: NonEmptyText
    required_change: NonEmptyText
    priority: Literal["高", "中", "低"]

完整輸出由 ReviewAnalysis 組合:

class ReviewAnalysis(BaseModel):
    status: Literal["通過", "需要修改"]
    checklist: ReviewChecklist
    issues: list[ReviewIssue]
    revision_allowed: bool

固定選項能避免同一個優先順序同時出現「重要」、「緊急」與 High 等不同寫法。

檢查欄位是否互相矛盾

JSON 格式正確,不代表內容一致。例如 status 寫「通過」,Checklist 卻有一項失敗;或狀態是「需要修改」,卻沒有列出問題。

ReviewAnalysis 使用 @model_validator(mode="after") 檢查整份資料:

狀態 Checklist Issues
通過 四項都必須通過 必須是空陣列
需要修改 至少一項未通過 至少一個問題

這些條件由 Python 強制檢查,不只依賴 Prompt。

建立 Review Agent

Review Agent 沿用 StructuredAgent[ReviewAnalysis],主要設定如下:

role = 專案品質審查員
temperature = 0.0
seed = 42
max_output_tokens = 700

審查需要較收斂的回答,因此使用 temperature=0.0。ReviewAnalysis.model_json_schema() 會把 Checklist、Issue 與固定選項轉成 JSON Schema,再交給 LLM Service。

為什麼要覆寫 respond()?

Review 比其他結構化 Agent 多兩個步驟:呼叫模型前先驗證 ReviewRequest,回覆後再重新計算 revision_allowed。

輸入錯在 revision_count 時,會回覆「修改次數只能是 0 或 1」;其他缺欄位、空字串或多餘欄位,統一視為 Review 輸入格式錯誤。驗證成功後,再把標準 JSON 交給 StructuredAgent。

修改機會由 Python 決定

模型回覆後,程式不直接採信它提供的 revision_allowed,而是重新計算:

revision_allowed = (
    result.status == "需要修改"
    and request.revision_count == 0
)

return result.model_copy(
    update={"revision_allowed": revision_allowed}
)

只有「審查需要修改」而且「目前仍是初稿」時,才允許修改一次。這是流程控制資料,交給 Python 判斷比讓模型決定更清楚。

使用 Fake LLM Service 測試

tests/test_review_agent.py 使用固定 JSON,不會啟動 Ollama。DAY 14 加入四種測試:

  1. 合理草案通過,四項 Checklist 全部成功。
  2. 不合理草案回傳問題、修改要求與優先順序。
  3. revision_count=1 時,即使仍需修改,也不能再退修。
  4. revision_count=2 會在呼叫 LLM 前被拒絕。

其中第二種案例讓 credibility 不通過,原因是成本數字缺少資料來源。因為仍是初稿,所以 revision_allowed=True。

執行測試

python -m unittest discover -s tests -v
Ran 40 tests in 0.093s

OK

完整測試共 40 項,其中 4 項直接測試 Review Agent。這是 Python 搭配 Fake Response 的結果,真實模型回覆的穩定度仍要等整合後驗證。

今天完成到哪裡?

DAY 14 完成 Review Agent 的輸入格式與結構化審查結果。草案會從完整度、創意、可信度與可行性接受檢查;跨欄位驗證會擋下矛盾資料,修改機會則由 Python 控制,最多一次。

下一篇開始處理五位 Agent 的執行順序與資料傳遞。


上一篇
DAY 13|建立 Creative 與 Finance Agent
下一篇
DAY 15|建立 Meeting Manager
系列文
AI 公司模擬器:Discord x Multi-Agent 架構實作 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言