
Agent 項目做久了你會發(fā)現(xiàn)一個很反直覺的現(xiàn)象模型能力越來越強(qiáng)但系統(tǒng)反而比傳統(tǒng)程序更難被信任。傳統(tǒng)代碼寫錯了運(yùn)行時會報錯你能立刻定位可一個 Agent 如果理解錯了任務(wù)、調(diào)錯了工具、把中間步驟帶偏它通常不會停下來報錯而是會把錯誤延續(xù)到最后一環(huán)給你一份“看起來完全合理”的結(jié)果。這幾年很多團(tuán)隊從 Demo 走向生產(chǎn)最大的攔路虎已經(jīng)不再是“模型不聽話”而是“不知道它什么時候不聽話”。這正是 Agentic AI 驗證框架存在的根本原因。社區(qū)里有一句被反復(fù)引用的話Only believe what you can validate。翻譯過來就是只相信你能驗證的東西。這句話聽起來像一條原則實(shí)際上是一條工程底線。它意味著在設(shè)計一個智能體系統(tǒng)時我們不應(yīng)該先問“模型會不會做對”而應(yīng)該先問“如果它做錯了系統(tǒng)能不能在造成損失之前發(fā)現(xiàn)”。這篇文章會把這條原則拆成一個可落地的驗證框架講清楚四件事驗證框架到底驗證什么它和傳統(tǒng)測試有什么不同怎么用 Python 實(shí)現(xiàn)一個最小可用的驗證管線以及在生產(chǎn)環(huán)境里有哪些躲不開的坑。如果你正準(zhǔn)備把 Agent 從“能跑通 Demo”推向“敢接真實(shí)業(yè)務(wù)”這篇文章應(yīng)該能給你一套可以直接動手的檢驗清單。1. 智能體 AI 的信任問題為什么“能跑”不等于“可信”傳統(tǒng)軟件工程里“能跑”和“可信”之間只差一層測試。單元測試覆蓋函數(shù)邏輯集成測試覆蓋模塊協(xié)作回歸測試保證歷史功能不退化。這套體系有一個前提程序的行為是確定的輸入相同輸出就相同。LLM 應(yīng)用打破了這個前提。同一個 Prompt模型可能給出不同答案同一個任務(wù)在不同上下文里可能選擇完全不同的工具和路徑。更麻煩的是LLM 總是以自信的口吻輸出結(jié)果。一個錯誤的中間結(jié)論在它嘴里聽起來和正確結(jié)論沒有任何區(qū)別。Agentic AI 把這個問題進(jìn)一步放大。普通聊天機(jī)器人輸出一段文本錯了最多是誤導(dǎo)而 Agent 會調(diào)用工具、訪問數(shù)據(jù)庫、修改配置、發(fā)送消息。每一步動作都有真實(shí)影響鏈路越長錯誤被放大的倍數(shù)就越高。實(shí)踐中很常見的一類失敗案例是這樣的Agent 被要求“統(tǒng)計本月銷售額并生成周報”第一輪調(diào)用數(shù)據(jù)庫查詢時把“本月”錯誤理解成“上個月”后續(xù)所有步驟都在這個錯誤數(shù)據(jù)上繼續(xù)計算最終生成的周報格式專業(yè)、措辭完整但數(shù)字全錯。如果沒有一個驗證環(huán)節(jié)去核對查詢時間范圍這個錯誤根本不會被發(fā)現(xiàn)。這就是“能跑不等于可信”的真實(shí)含義。Demo 階段我們關(guān)心模型能不能完成任務(wù)生產(chǎn)階段我們更關(guān)心它錯的時候系統(tǒng)能不能兜住。驗證框架的價值不在提高單次任務(wù)的成功率而在降低錯誤造成的損失。從行業(yè)趨勢看verification framework驗證框架已經(jīng)成為 Agentic AI 工程化討論里的高頻詞。越來越多團(tuán)隊意識到與其把全部精力押在“讓模型更強(qiáng)”上不如先建立一套“即使模型錯了也能被發(fā)現(xiàn)”的機(jī)制。這就是這篇文章標(biāo)題那句話的工程意義只相信你能驗證的而不是相信模型看起來很自信的輸出。2. 驗證框架的核心概念與設(shè)計原則2.1 驗證、評測與測試的區(qū)別先把三個容易混淆的詞說清楚。測試Testing是傳統(tǒng)軟件工程的概念圍繞確定性代碼展開核心是斷言給定輸入期望輸出是什么。評測Evaluation更常用于 LLM 應(yīng)用關(guān)注的是模型的整體能力指標(biāo)比如在一個評測集上回答正確的比例、工具調(diào)用的成功率。驗證Verification介于兩者之間它針對的是“單次運(yùn)行”是否合規(guī)。驗證不關(guān)心模型在 100 個任務(wù)里平均表現(xiàn)如何它關(guān)心的是當(dāng)前這 1 個任務(wù)每一步行為是否在允許范圍內(nèi)最終結(jié)果是否滿足可檢查的條件??梢杂靡粋€表格快速對比維度傳統(tǒng)測試LLM 評測Agentic AI 驗證對象確定性函數(shù)模型能力一次任務(wù)執(zhí)行的完整鏈路核心問題輸出是否符合預(yù)期平均正確率有多高這一次執(zhí)行是否合規(guī)、可回溯判斷方式斷言指標(biāo)策略 規(guī)則 多元校驗失敗處理修復(fù)代碼調(diào)優(yōu)模型拒絕執(zhí)行、回滾、人工介入關(guān)注點(diǎn)正確性能力風(fēng)險驗證框架要做的事就是把“這一次執(zhí)行”中所有可檢查的環(huán)節(jié)都變成檢查點(diǎn)。2.2 三層驗證輸入、過程、輸出一個 Agent 從接收任務(wù)到產(chǎn)出結(jié)果大致會經(jīng)歷三個階段。驗證框架應(yīng)該在這三個階段分別設(shè)卡。第一層是輸入驗證。任務(wù)描述本身可能包含歧義、越權(quán)指令或者惡意注入。比如“刪除 2020 年之前的測試數(shù)據(jù)”這句話在測試環(huán)境里沒問題在生產(chǎn)庫里就是高風(fēng)險操作。輸入層要明確任務(wù)的邊界這個 Agent 能做什么、不能做什么、可以訪問哪些數(shù)據(jù)源。第二層是過程驗證。Agent 在完成任務(wù)過程中會發(fā)起工具調(diào)用、查詢、寫操作。過程層要校驗每一次調(diào)用的工具名是否在白名單內(nèi)、參數(shù)是否符合規(guī)范、操作對象是否在授權(quán)范圍內(nèi)。這是防止“模型中途跑偏”最關(guān)鍵的一層也是傳統(tǒng)測試很少覆蓋的部分。第三層是輸出驗證。最終返回給用戶的結(jié)果不能只要“看起來對”。要檢查結(jié)構(gòu)是否完整、關(guān)鍵字段是否缺失、數(shù)值是否在合理范圍、結(jié)論是否符合事實(shí)。輸出層可以組合確定性校驗和 LLM-as-judge 這類語義校驗。三層驗證缺一不可。只做輸入校驗攔不住中途跑偏只做輸出校驗發(fā)現(xiàn)錯誤時已經(jīng)造成損失只做過程校驗又可能放過格式正確但內(nèi)容錯誤的最終結(jié)果。2.3 “只相信你能驗證的”到底指什么這句話不是否定模型能力而是給工程系統(tǒng)劃定信任邊界。在一個 Agent 系統(tǒng)里不是所有東西都值得無條件信任模型的自然語言解釋不可以直接信任因為模型可能編造理由。工具返回的數(shù)據(jù)也要標(biāo)記來源和可信等級因為上游可能被污染??梢孕湃蔚氖瞧跫s、白名單、可執(zhí)行的規(guī)則、可回放的日志、可在沙箱里驗證的結(jié)果。換句話說驗證框架的本質(zhì)是把信任從“模型的回答”轉(zhuǎn)移到“系統(tǒng)能檢查的事實(shí)”上。這也是我在整個文章里反復(fù)強(qiáng)調(diào)的觀點(diǎn)對 Agentic AI 而言可驗證性比準(zhǔn)確性更接近工程底線。3. 驗證框架的整體架構(gòu)與關(guān)鍵組件一個完整的驗證框架不一定很復(fù)雜但它至少要包含五個組件。第一個是契約定義模塊。它負(fù)責(zé)描述任務(wù)允許做什么包括允許使用的工具列表、每個工具的參數(shù) JSON Schema、任務(wù)的最大步數(shù)、輸出結(jié)果的必需字段。契約是驗證的基礎(chǔ)沒有契約驗證就失去了參照物。第二個是工具調(diào)用校驗器。它在 Agent 每次發(fā)起工具調(diào)用之前攔截請求檢查工具名是否在白名單內(nèi)參數(shù)是否滿足 JSON Schema參數(shù)值是否滿足額外的業(yè)務(wù)規(guī)則。例如金額字段不能為負(fù)數(shù)、日期字段必須在合理區(qū)間內(nèi)、表達(dá)式里不能包含可執(zhí)行代碼。第三個是軌跡記錄器。它把每次工具調(diào)用的完整信息記錄下來包括調(diào)用序號、工具名、參數(shù)、校驗結(jié)果、返回值摘要、時間戳。這是“可回溯”的基礎(chǔ)也是出問題之后定位根因的關(guān)鍵。第四個是輸出校驗器。它負(fù)責(zé)檢查最終結(jié)果。先做確定性檢查必需字段是否存在、字段類型是否正確、數(shù)值是否在允許范圍內(nèi)再做語義檢查是否回答了用戶的目標(biāo)是否存在事實(shí)性矛盾。語義檢查可以交給一個獨(dú)立的 LLM但要注意不能完全依賴 LLM 判斷一定要有確定性檢查兜底。第五個是策略與人工審批接口。對于高風(fēng)險動作比如發(fā)送郵件、刪除數(shù)據(jù)、修改配置驗證框架不應(yīng)該直接放行而應(yīng)該觸發(fā)人工審批流程。這個接口要能暫停執(zhí)行、等待反饋、恢復(fù)或者終止。這五個組件組合起來就是一個典型的 Agentic AI verification framework。它不參與模型的推理過程只是在推理過程的外圍加了一道過濾網(wǎng)。這里有一個值得強(qiáng)調(diào)的設(shè)計原則驗證框架必須與 Agent 主流程解耦。驗證邏輯不應(yīng)該散落在 Agent 的業(yè)務(wù)代碼里而應(yīng)該作為獨(dú)立的中間件或攔截器存在。這樣當(dāng)驗證規(guī)則變化時不需要改 Agent 本身當(dāng) Agent 模型升級時驗證規(guī)則也不需要推倒重來。4. 環(huán)境準(zhǔn)備與前置條件本文的代碼示例使用 Python 實(shí)現(xiàn)核心依賴只有三個pydantic 用于定義數(shù)據(jù)契約jsonschema 用于校驗參數(shù)結(jié)構(gòu)以及標(biāo)準(zhǔn)庫 json 和 dataclasses。如果你要跑完整示例還需要一個可用的 Python 3.9 環(huán)境。安裝依賴pip install pydantic jsonschemapydantic 的版本請以實(shí)際安裝為準(zhǔn)本文只用到 BaseModel 和 Field屬于非?;A(chǔ)的功能不需要特殊版本。jsonschema 同理我們只用了 validate 函數(shù)。代碼結(jié)構(gòu)建議如下agent_verifier/ ├── __init__.py ├── contracts.py # 數(shù)據(jù)契約定義 ├── validators.py # 工具調(diào)用校驗 ├── tracer.py # 軌跡記錄 ├── output_checker.py # 輸出校驗 └── pipeline.py # 驗證管線組裝 demo.py # 演示入口如果你打算把這套框架接入已有的 Agent 項目還需要額外考慮兩件事。第一你的 Agent 框架是否提供中間件或鉤子機(jī)制。目前主流的 Agent 框架大多支持在工具調(diào)用前插入自定義邏輯如果不支持可以考慮用代理模式包裝工具執(zhí)行函數(shù)。第二LLM 的調(diào)用入口。輸出層的語義檢查需要調(diào)用 LLM你需要準(zhǔn)備好 API Key 或本地模型的調(diào)用封裝。為了先跑通流程示例代碼里把 LLM-judge 設(shè)計成可選回調(diào)不傳也不會影響確定性校驗。5. 最小可用的驗證框架代碼實(shí)現(xiàn)按照從內(nèi)到外的順序先用一個最小示例跑通驗證流程。這個示例的重點(diǎn)不是功能齊全而是幫助你建立“驗證點(diǎn)”的直覺在哪些位置該攔住、在哪些位置該記錄、在哪些位置該復(fù)核。5.1 定義任務(wù)與工具的“契約”契約是一切驗證的前提。先定義工具規(guī)格和任務(wù)規(guī)格# 文件路徑agent_verifier/contracts.py from typing import Any from pydantic import BaseModel, Field class ToolSpec(BaseModel): 工具契約描述一個工具允許怎么被調(diào)用。 name: str description: str parameters_schema: dict Field(default_factorydict) # JSON Schema class TaskSpec(BaseModel): 任務(wù)契約描述一次 Agent 任務(wù)的邊界。 task_id: str goal: str allowed_tools: list[str] Field(default_factorylist) expected_output_keys: list[str] Field(default_factorylist) max_steps: int 5這里的 ToolSpec 是給校驗器用的“參照物”。參數(shù)必須用 JSON Schema 描述因為這是當(dāng)前 Agent 工具調(diào)用最常見的表達(dá)方式。TaskSpec 里的 allowed_tools 決定 Agent 能碰哪些工具expected_output_keys 決定最終結(jié)果至少包含哪些字段。5.2 工具調(diào)用校驗器工具調(diào)用校驗器負(fù)責(zé)在 Agent 每次調(diào)用工具之前“攔一道”# 文件路徑agent_verifier/validators.py import json from jsonschema import validate, ValidationError as JsonSchemaError from typing import Any from .contracts import ToolSpec class ToolCallValidator: 校驗 Agent 的每一次工具調(diào)用是否合規(guī)。 def __init__(self, tool_specs: dict[str, ToolSpec]): self.tool_specs tool_specs def validate(self, call: dict[str, Any]) - list[str]: errors [] tool_name call.get(name, ) if tool_name not in self.tool_specs: errors.append(f工具 {tool_name} 不在白名單中) return errors spec self.tool_specs[tool_name] args call.get(arguments, {}) if isinstance(args, str): try: args json.loads(args) except json.JSONDecodeError as e: errors.append(farguments 不是合法 JSON: {e}) return errors if spec.parameters_schema: try: validate(instanceargs, schemaspec.parameters_schema) except JsonSchemaError as e: errors.append(f工具 {tool_name} 參數(shù)校驗失敗: {e.message}) return errors校驗順序有三個層次。第一層查工具名白名單這是最粗粒度但最重要的一道防線能直接攔截“調(diào)了不該調(diào)的工具”這類問題。第二層做 JSON 解析因為很多 Agent 框架會把參數(shù)以字符串形式傳給工具層必須先把字符串還原成對象。第三層做 JSON Schema 校驗確保參數(shù)結(jié)構(gòu)、字段類型、取值范圍都符合契約。這里真正容易踩坑的地方是很多團(tuán)隊只做第一層白名單校驗忽略了參數(shù)合法性。結(jié)果就是 Agent 確實(shí)只用了允許的工具但傳了一個超出業(yè)務(wù)邊界的參數(shù)照樣造成問題。5.3 執(zhí)行軌跡記錄器軌跡記錄器的職責(zé)是把所有經(jīng)過驗證的調(diào)用留痕# 文件路徑agent_verifier/tracer.py from dataclasses import dataclass, field from datetime import datetime, timezone from typing import Any dataclass class TraceStep: step_index: int action: str tool_name: str tool_args: dict field(default_factorydict) decision: str approved # approved | rejected | requires_human reason: str observation: str timestamp: str field(default_factorylambda: datetime.now(timezone.utc).isoformat()) class TraceRecorder: def __init__(self): self.steps: list[TraceStep] [] def record(self, step: TraceStep): self.steps.append(step) def to_dict(self) - list[dict]: return [vars(s) for s in self.steps]很多團(tuán)隊在出問題后才想起查日志但 Agent 系統(tǒng)的日志如果只記錄“最終回答”根本看不出中間步驟是怎么走的。軌跡記錄器記錄的是“決策過程”哪一步被通過了哪一步被拒絕了因為什么被拒絕。這才是 Agent 審計的基礎(chǔ)。5.4 輸出結(jié)果驗證器輸出校驗器負(fù)責(zé)檢查最終結(jié)果采用“確定性檢查優(yōu)先、語義檢查兜底”的策略# 文件路徑agent_verifier/output_checker.py from typing import Any, Callable class OutputChecker: 結(jié)果驗證先做確定性檢查再做語義檢查。 def __init__(self, required_keys: list[str], llm_judge: Callable[[str, str], dict] | None None): self.required_keys required_keys self.llm_judge llm_judge # 可選的 LLM-as-judge 回調(diào) def check(self, result: dict[str, Any], task_goal: str) - list[str]: errors [] # 1. 結(jié)構(gòu)檢查關(guān)鍵字段必須存在 missing [k for k in self.required_keys if k not in result] if missing: errors.append(f結(jié)果缺少必需字段: {missing}) # 2. 類型與空值檢查 for k in self.required_keys: v result.get(k) if v is None or (isinstance(v, str) and not v.strip()): errors.append(f字段 {k} 為空) # 3. 語義檢查交給 LLM-judge前一步有錯時不再執(zhí)行 if self.llm_judge is not None and not errors: judge_result self.llm_judge(task_goal, str(result)) if not judge_result.get(pass, False): errors.append(f語義檢查未通過: {judge_result.get(reason, unknown)}) return errors輸出校驗最容易犯的錯誤是“只讓模型判模型”。如果最終的語義檢查也完全依賴同一個 LLM那就等于讓“可能出錯的模型”來評判“可能出錯的模型”錯誤很容易被掩蓋。所以這里的設(shè)計原則是能用規(guī)則判斷的絕不用模型語義檢查只在確定性檢查通過之后才執(zhí)行。5.5 組合成驗證管線并運(yùn)行最后把這些組件組合成一條驗證管線# 文件路徑agent_verifier/pipeline.py from typing import Any from .validators import ToolCallValidator from .tracer import TraceRecorder, TraceStep from .output_checker import OutputChecker class VerificationPipeline: def __init__(self, tool_validator: ToolCallValidator, output_checker: OutputChecker, tracer: TraceRecorder): self.tool_validator tool_validator self.output_checker output_checker self.tracer tracer def verify_tool_call(self, index: int, call: dict[str, Any]) - tuple[bool, list[str]]: errors self.tool_validator.validate(call) approved not errors step TraceStep( step_indexindex, actiontool_call, tool_namecall.get(name, ), tool_argscall.get(arguments, {}), decisionapproved if approved else rejected, reason; .join(errors), ) self.tracer.record(step) return approved, errors def verify_final_output(self, result: dict[str, Any], goal: str) - list[str]: return self.output_checker.check(result, goal) def get_report(self) - dict[str, Any]: return {steps: self.tracer.to_dict()}演示入口如下# 文件路徑demo.py import json from agent_verifier.contracts import ToolSpec from agent_verifier.validators import ToolCallValidator from agent_verifier.tracer import TraceRecorder from agent_verifier.output_checker import OutputChecker from agent_verifier.pipeline import VerificationPipeline def build_pipeline(): # 定義一個只允許計算和查詢天氣的工具集 tool_specs { calculator: ToolSpec( namecalculator, description執(zhí)行四則運(yùn)算, parameters_schema{ type: object, properties: { expression: {type: string, pattern: ^[0-9\\-*/(). ]$}, }, required: [expression], additionalProperties: False, }, ), get_weather: ToolSpec( nameget_weather, description查詢城市天氣, parameters_schema{ type: object, properties: {city: {type: string, minLength: 1}}, required: [city], additionalProperties: False, }, ), } return VerificationPipeline( tool_validatorToolCallValidator(tool_specs), output_checkerOutputChecker(required_keys[summary, detail]), tracerTraceRecorder(), ) if __name__ __main__: pipeline build_pipeline() # 模擬一個 Agent 發(fā)出的工具調(diào)用參數(shù)里混進(jìn)了非法字符 bad_call {name: calculator, arguments: {expression: 11; rm -rf /}} ok, errors pipeline.verify_tool_call(1, bad_call) print(bad_call approved:, ok) print(errors:, errors) # 模擬一個正常調(diào)用 good_call {name: get_weather, arguments: {city: 北京}} ok, errors pipeline.verify_tool_call(2, good_call) print(good_call approved:, ok) print(errors:, errors) # 校驗最終結(jié)果 result {summary: 北京天氣晴朗, detail: 氣溫 5-15 度} errors pipeline.verify_final_output(result, 查詢北京天氣) print(final output errors:, errors) print(json.dumps(pipeline.get_report(), ensure_asciiFalse, indent2))這段 demo 有兩個關(guān)鍵設(shè)計。第一個是 calculator 工具的 parameters_schema 使用了正則表達(dá)式^[0-9\-*/(). ]$它只允許數(shù)字、運(yùn)算符、括號和空格出現(xiàn)在表達(dá)式里。這樣一來“11; rm -rf /”這類包含分號和命令字符的輸入就會被 schema 校驗直接攔下。第二個是 get_weather 的 city 字段要求 minLength 為 1防止模型傳一個空字符串。在實(shí)際 Agent 主循環(huán)中這個管線的接入方式并不復(fù)雜。當(dāng)模型決定調(diào)用工具時先調(diào)用 verify_tool_call如果返回 approved 為 False就不執(zhí)行工具而是把錯誤信息回傳給模型讓模型重新決策如果 approved 為 True執(zhí)行工具后把結(jié)果寫入 observation再繼續(xù)下一輪。6. 運(yùn)行效果與驗證方法運(yùn)行演示腳本python demo.py預(yù)期輸出大致如下具體報錯文案可能隨 jsonschema 版本略有差異bad_call approved: False errors: [工具 calculator 參數(shù)校驗失敗: 11; rm -rf / does not match ^[0-9\\-*/(). ]$] good_call approved: True errors: [] final output errors: [] { steps: [ { step_index: 1, action: tool_call, tool_name: calculator, tool_args: {expression: 11; rm -rf /}, decision: rejected, reason: 工具 calculator 參數(shù)校驗失敗: ..., observation: , timestamp: 2025-01-01T12:00:0000:00 }, { step_index: 2, action: tool_call, tool_name: get_weather, tool_args: {city: 北京}, decision: approved, reason: , observation: , timestamp: 2025-01-01T12:00:0100:00 } ] }如何判斷驗證框架起作用了核心看三點(diǎn)第一非法調(diào)用被拒絕。bad_call 的 decision 是 rejectedreason 字段清楚寫明了拒絕原因。如果這里顯示 approved說明 schema 寫錯了需要回去檢查正則表達(dá)式。第二正常調(diào)用被放行。good_call 的 decision 是 approved說明白名單和參數(shù)校驗沒有誤傷正常請求。如果這里被拒絕多半是 schema 里 additionalProperties 設(shè)為 false 后模型返回了未聲明字段。第三執(zhí)行軌跡可回放。get_report 返回的 steps 數(shù)組應(yīng)該包含每一步的完整信息。你在接入自己的 Agent 時應(yīng)該讓 observation 字段記錄工具返回值的摘要這樣復(fù)盤時可以還原整個執(zhí)行過程。為了讓框架更抗風(fēng)險建議補(bǔ)充自動化測試。一個簡單的 pytest 用例是這樣# 文件路徑test_pipeline.py from demo import build_pipeline def test_reject_unknown_tool(): pipeline build_pipeline() ok, errors pipeline.verify_tool_call(1, {name: execute_shell, arguments: {}}) assert ok is False assert 白名單 in errors[0] def test_reject_invalid_expression(): pipeline build_pipeline() ok, errors pipeline.verify_tool_call(2, {name: calculator, arguments: {expression: 11; rm -rf /}}) assert ok is False assert 參數(shù)校驗失敗 in errors[0] def test_accept_valid_call(): pipeline build_pipeline() ok, errors pipeline.verify_tool_call(3, {name: get_weather, arguments: {city: 北京}}) assert ok is True assert errors []運(yùn)行測試pip install pytest pytest test_pipeline.py -v把“該攔的能攔住、該放的能放行”固化成測試用例是驗證框架本身不被改壞的基礎(chǔ)。很多項目前期驗證邏輯寫得很嚴(yán)后來為了修某個 bug 順手放寬了規(guī)則結(jié)果整個防線失效原因就是沒有測試兜底。7. 智能體驗證的常見問題與排查思路驗證框架接入真實(shí)項目后問題通常不是“框架不工作”而是“規(guī)則寫錯、位置掛錯、誤判太多”。下面整理了五個高頻問題問題現(xiàn)象可能原因排查方式解決方案正常工具調(diào)用也被拒絕JSON Schema 定義過嚴(yán)例如把可選字段設(shè)成了必填或 additionalPropertiesfalse 導(dǎo)致未聲明字段無法通過打印實(shí)際 arguments與 schema 逐字段核對用 additionalPropertiesfalse 時確認(rèn)所有模型可能返回的字段都已聲明非法調(diào)用被放行校驗器沒有掛在真正的執(zhí)行入口Agent 繞過了包裝器直接調(diào)用工具函數(shù)檢查日志中是否有未經(jīng)過 Pipeline 的工具執(zhí)行記錄在工具注冊層統(tǒng)一攔截而不是在 Agent 決策層判斷最終結(jié)果校驗誤報語義檢查用同一個 LLM 判斷對同類表述過于敏感查看 judge 回調(diào)返回的 reason 字段確定性規(guī)則優(yōu)先LLM-judge 只作為補(bǔ)充且使用獨(dú)立模型驗證框架拖慢執(zhí)行速度每次工具調(diào)用都觸發(fā) LLM 語義檢查在管線里記錄各環(huán)節(jié)耗時確定性校驗全部走本地LLM 校驗只用于最終結(jié)果Agent 升級后驗證規(guī)則失效模型版本變化導(dǎo)致返回字段名或工具名改變對比升級前后的調(diào)用日志契約文件納入版本管理Agent 升級時同步走發(fā)布流程這里重點(diǎn)說第一個問題。很多新手第一次寫 JSON Schema 時習(xí)慣把所有字段都放進(jìn) required結(jié)果模型稍有不規(guī)范就觸發(fā)校驗失敗。正確做法是 required 只放真正必要的字段可選字段用 optional 或直接不聲明。正則表達(dá)式更要謹(jǐn)慎寧可寬松一點(diǎn)配合業(yè)務(wù)層再做檢查也不要寫一個過于嚴(yán)格的正則導(dǎo)致“所有輸入都被拒”。第二個問題非常隱蔽。如果 Agent 框架本身支持多級工具調(diào)用或者某個工具函數(shù)被別的模塊直接引用校驗器可能只攔截了主鏈路其他路徑仍然繞過了驗證。排查時可以先在日志里搜索 pipeline 的調(diào)用記錄再對照工具實(shí)際執(zhí)行日志找出“沒走管線但執(zhí)行了”的調(diào)用。8. 生產(chǎn)環(huán)境最佳實(shí)踐與工程建議代碼層面的驗證框架只是起點(diǎn)。真正讓框架產(chǎn)生價值的是生產(chǎn)環(huán)境里的策略管理、風(fēng)險分級和運(yùn)維配套。8.1 把驗證策略寫成策略即代碼驗證規(guī)則不應(yīng)該散落在 Python 代碼的 if 分支里而應(yīng)該寫成獨(dú)立的策略文件納入版本管理。推薦用 YAML 描述策略例如# 文件路徑config/policy.yaml policy: max_steps: 10 allowlist: - calculator - get_weather deny_actions: - execute_shell - send_email human_approval: - action: send_email condition: 收件人數(shù)量 5 output_checks: required_fields: - summary - detail這樣做的收益是規(guī)則變更可以走代碼評審不需要改 Agent 業(yè)務(wù)代碼審計時可以直接看策略文件而不是在幾百行代碼里找判斷邏輯測試環(huán)境和生產(chǎn)環(huán)境可以共用一套策略模板只通過配置區(qū)分閾值。8.2 風(fēng)險分級與人工審批不是所有錯誤都需要同等對待。按影響范圍給動作分級是生產(chǎn)環(huán)境最重要的工程決策之一。只讀操作比如查詢天氣、檢索文檔可以在規(guī)則校驗通過后直接放行但參數(shù)校驗仍然要嚴(yán)格。有副作用但可回滾的操作比如寫入測試表、調(diào)用可逆 API可以自動執(zhí)行但要記錄完整軌跡。不可回滾或高風(fēng)險操作比如刪除數(shù)據(jù)、發(fā)送真實(shí)郵件、修改線上配置必須觸發(fā)人工審批。人工審批接口要設(shè)計成異步的Agent 執(zhí)行到這一步時暫停等待而不是直接超時失敗。這要求驗證框架的狀態(tài)是可持久化的至少要把當(dāng)前執(zhí)行上下文序列化保存審批通過后從斷點(diǎn)恢復(fù)。實(shí)現(xiàn)時可以在 TraceStep 的 decision 字段上增加 requires_human 狀態(tài)審批通過后把 decision 改為 approved再繼續(xù)執(zhí)行。8.3 驗證強(qiáng)度與成本、延遲的平衡驗證不是越嚴(yán)越好。每多一道校驗就多一分延遲和成本。尤其是 LLM-as-judge 這類語義檢查一次調(diào)用就是一個 Token 消耗如果每一步都做賬單會很難看。推薦的配置是過程層全部使用確定性校驗不調(diào) LLM最終輸出層先做確定性結(jié)構(gòu)檢查通過后再調(diào)用獨(dú)立 LLM 做語義檢查對于低風(fēng)險任務(wù)可以連語義檢查都跳過只保留結(jié)構(gòu)校驗。還可以把校驗做成采樣策略生產(chǎn)環(huán)境對 100% 請求做確定性校驗對 10% 請求做語義抽檢這樣可以控制成本同時保留發(fā)現(xiàn)語義問題的能力。8.4 可觀測性與問題復(fù)盤驗證框架本身要可觀測。建議為每個驗證事件輸出結(jié)構(gòu)化日志包含任務(wù) ID、步驟序號、工具名、決策結(jié)果、拒絕原因、耗時。這樣當(dāng) Agent 出現(xiàn)異常時你可以在追蹤系統(tǒng)里一鍵拉出完整鏈路。復(fù)盤時最有效的做法是“錯誤樣本庫”。每次驗證攔截到一個非法調(diào)用就把這條調(diào)用連同上下文存下來定期分類。這些樣本是調(diào)優(yōu)驗證規(guī)則的第一手素材比你自己拍腦袋想邊界條件要準(zhǔn)確得多。它們還可以用來構(gòu)造回歸測試集防止規(guī)則被誤改。9. 總結(jié)與后續(xù)學(xué)習(xí)方向這篇文章從“只相信你能驗證的”這句原則出發(fā)拆解了 Agentic AI 驗證框架的完整落地路徑。核心結(jié)論有三點(diǎn)驗證框架的價值不在提高模型正確率而在降低錯誤造成的損失驗證必須覆蓋輸入、過程、輸出三層而不是只在最終結(jié)果處兜底驗證邏輯要與 Agent 主流程解耦用契約、策略、軌跡和測試把它變成一套獨(dú)立的工程基礎(chǔ)設(shè)施。如果你正在自己的項目里實(shí)踐建議的下一步是先不要追求功能完備把 5.5 節(jié)的管線接進(jìn)你現(xiàn)有的 Agent跑通“攔截一次非法調(diào)用”的最小閉環(huán)然后給驗證框架補(bǔ)核心測試用例確保規(guī)則不會被隨手改壞之后再考慮策略文件化、人工審批和采樣校驗。一個值得繼續(xù)深入的方向是把驗證框架與 Agent 框架的官方中間件機(jī)制結(jié)合。很多框架本身就支持在工具調(diào)用前后插入攔截邏輯把這套驗證管線封裝成一個插件可以大幅降低業(yè)務(wù)代碼的侵入。另一個方向是為驗證框架本身建立評測集也就是“驗證的驗證”已知某些調(diào)用是壞的某些調(diào)用是好的驗證框架必須全部判斷正確。這也是從工具走向工程體系的必經(jīng)之路。最后提醒一句驗證框架不是安全保險箱它只能攔住你定義過的風(fēng)險。真正可靠的系統(tǒng)永遠(yuǎn)需要“規(guī)則兜底 人工兜底 錯誤復(fù)盤”三者配合。先把能驗證的每一環(huán)都驗證起來再談讓 Agent 走得更遠(yuǎn)。