Evidence Acquisition Policy
根据决策相关证据缺口、风险、获取成本与预算选择是否继续搜索、询问、观察或停止,使信息获取成为受控策略而非模型自由探索。
[!info] related notes
- 所属 MOC: agent-evals-moc、agent-moc
- 前置概念: decision-relevant-evidence-gap
- 并列概念: agent-evidence-admissibility
- 易混淆概念:
- 关系笔记: agent-safety-envelope、agent-decision-authority、agent-decision-trace
Evidence Acquisition Policy
一句话定义
Evidence Acquisition Policy 是在 Agent 已识别证据缺口后,决定是否值得继续取证、从哪里取证、最多投入多少预算,以及何时停止的控制策略。
[!important] 核心区分
Tool capability ≠ Acquisition policy。模型“想搜索”不等于系统“允许搜索”。
为什么 Acquisition 是 Policy 问题,不只是 Tool Calling 技巧
如果 Agent 只有:
search_knowledge
ask_user
measure
lookup_profile
这些只是“能做什么”。
真正的生产问题是:
什么时候值得做?
做哪一个?
最多做几次?
如果失败怎么办?
如果用户不回答怎么办?
如果搜到了不允许使用的来源怎么办?
什么时候应该停止而不是继续烧 token?
这些问题已经超出 Tool API,本质上是在设计一个有限资源下的信息获取控制器。
可以类比数据库查询优化:
SQL capability
≠
Query planner
同样:
Tool capability
≠
Acquisition planner/policy
为什么不能只给模型一个搜索工具
有 search、ask_user 或 measurement tool,只说明 Agent 有能力取证;它不等于系统已经规定:
- 什么 gap 值得取证;
- 应该搜索知识还是询问用户;
- 一次失败后能重试几次;
- 什么来源/版本允许使用;
- 什么时候收益已经低于成本;
- critical gap 无法关闭时最终怎么办。
如果这些决定全部交给 LLM,自由 tool calling 很容易演变成:
模型觉得不确定
→ 搜一堆东西
→ 上下文越来越大
→ 模型觉得差不多了
→ 自己宣布 resolved
这不是一个可审计的控制系统。
基本决策链
Accepted EvidenceGap
↓
判断 decision relevance / criticality
↓
选择 acquisition channel
├─ knowledge retrieval
├─ ask_user
├─ measurement / observation
└─ domain tool
↓
Runtime 执行真实 Tool Action
↓
EvidenceAttempt
↓
Evidence identity + admissibility validation
↓
重新评估 gap
↓
RESOLVED / continue / stop
其中“真实执行”很关键:模型不能靠一句“我已经搜索了”制造 execution fact。
Acquisition Channel 必须匹配 Gap 类型
User-information gap
例如:
“这个用户本人的肱二头肌反射是否减弱?”
合适渠道:
- ask_user;
- measurement;
- observation;
- 未来真实业务数据。
不合适渠道:
generic medical RAG
因为一般知识只能告诉你“某类患者通常如何”,不能告诉你“这个用户本人实际如何”。
External-knowledge gap
例如:
“C6 神经根受累通常与哪些感觉分布相关?”
这才适合 targeted retrieval。
[!warning] 一条非常重要的 epistemic boundary
external knowledge ≠ user fact。
Channel Selection 可以被看成一个 Capability Filter
不要一开始就把所有 tools 暴露给模型。
可以先由 gap/policy 决定:
AllowedCapabilities(Gap)
例如:
user_information
→ {ask_user, read_user_profile, measurement}
external_knowledge
→ {search_knowledge, guideline_lookup}
conflict
→ {ask_user, compare_history, human_review}
然后模型只在允许集合里做 semantic choice。
这比:
20 个 tools 全部给模型
prompt 写“请不要乱用”
更接近真正权限系统。
EvidenceAttempt:把“尝试取证”变成可审计事实
一次真正的 acquisition 应产生 typed attempt,而不是只保留 tool log。
典型字段:
EvidenceAttempt
├─ attempt_id
├─ gap_id
├─ strategy / channel
├─ query / request
├─ requested_top_k
├─ returned_evidence_ids
├─ admissibility / outcome
├─ stopping_reason
├─ latency
├─ cost / token / user burden
└─ budget_before / budget_after
这样以后可以明确回答:
- 为什么搜?
- 为哪个 gap 搜?
- 真正返回了什么?
- 为什么这些结果没有关闭 gap?
- 为什么停止?
为什么普通 Tool Log 不足以替代 EvidenceAttempt
普通 trace 可能只显示:
search_knowledge(query="C6 thumb numbness")
200 OK
但它没有表达业务语义:
这个 search 属于哪个 Gap?
当时 budget 剩多少?
返回 Evidence 是否 admissible?
是否解决了 Gap?
为什么后面没继续搜?
EvidenceAttempt 把低层 tool execution 提升成:
decision-relevant execution fact
这也是为什么它值得进入 DecisionTrace / durable audit,而不仅是 observability log。
Targeted Acquisition
成熟策略优先寻找最可能改变当前决策的下一条证据,而不是 broad retrieval:
不是:还能搜什么?
而是:哪条新证据最可能关闭当前关键 gap?
这有三个直接收益:
- 减少无意义 token 与成本;
- 减少上下文污染;
- 让每次 acquisition 都能归因到一个明确的 Gap。
例如:
G3 = “C6 是否通常影响拇指感觉?”
比起:
search("颈椎病 神经 症状 治疗 肌力 感觉 预后")
更合理的是围绕 G3 生成狭窄 query。
为什么 Broad Retrieval 会增加“看起来更聪明但更难治理”的风险
Broad query 往往返回很多主题相近但决策价值不同的内容:
定义
原因
治疗
预后
风险
运动建议
模型拿到大量 context 后可能:
- 从无关段落补出 user fact;
- 把治疗知识混进 Diagnosis;
- 因 token 太多忽略真正 critical evidence;
- 无法追踪哪一条 Evidence 是为哪个 Gap 获取的。
Targeted Retrieval 的价值不只是省 token,更重要的是建立:
Gap → Attempt → Evidence
的可解释关系。
EvidenceBudget:资源上限,不是风险证明
Evidence budget 可以限制:
- 最大检索次数;
- 每次最大 top_k;
- 最大询问轮数;
- token;
- latency;
- monetary cost;
- user burden;
- 某类高成本工具调用次数。
但必须记住:
Budget exhausted ≠ evidence sufficient,也 ≠ risk LOW。
预算耗尽只说明:
不能继续按当前方式取证
如果 critical gap 仍然 OPEN,后续应交给 SafetyEnvelope 与 DecisionAuthority 决定 ABSTAIN / ESCALATE / BLOCK,而不是把未知自动解释成安全。
为什么 Budget 需要由 Runtime 持有
如果只在 prompt 写:
“最多搜索两次”
模型仍可能:
- 第三次 tool call;
- 重试时忘记前面已消耗;
- interrupt/resume 后重新计数;
- 多个 gap 并行时各自认为还有 2 次。
Runtime-owned budget 可以做到:
before attempt: check
on attempt: decrement atomically
on exhaustion: reject future acquisition
persist usage / stopping reason
这就是:
Prompt asks
Runtime enforces
的区别。
Budget 可以有多维度,而不只是“搜索次数”
一个成熟系统可能同时有:
SearchBudget
TokenBudget
LatencyBudget
MoneyBudget
UserBurdenBudget
RiskBudget
例如:
搜索还可以继续
但用户已经被连续追问 4 次
此时 user burden 可能要求停止当前路径,转为:
degraded / save and continue later / human review
所以 acquisition optimization 是多目标问题,不是简单的 max_searches。
Run Budget 与 Per-Gap Budget
可以同时存在:
Run max_searches = 3
G1 max_searches = 2
G2 max_searches = 1
这样可以防止一个低价值 Gap 把整轮资源吃光。
更进一步可以按 criticality 分配:
critical gap
→ higher priority / reserved budget
non-critical gap
→ stop earlier
但仍然要记住:priority 只控制资源,不能把 budget 用完等价成安全。
Stopping Reason 也是一等事实
常见停止理由:
gap_resolved
budget_exhausted
source_unavailable
marginal_value_too_low
user_fact_unavailable
permission_boundary
unresolvable
停止原因应该进入 EvidenceAttempt / DecisionTrace,因为:
“为什么没继续搜?”
本身就是未来 audit / replay 需要回答的问题。
为什么 Stop 不是 Failure
很多 Agent 会陷入“只要还不确定就继续工具调用”的循环。
实际上受控停止可能是正确决策:
critical user fact 无法获取
→ stop acquisition
→ ABSTAIN
或者:
non-critical external gap
marginal value low
→ stop
→ ALLOW_DEGRADED
生产系统的目标不是“永远找出答案”,而是:
在有限资源与安全边界下,知道什么时候继续、什么时候停止、停止后允许做什么。
Marginal Value:下一次取证值不值得
可以概念化:
Expected Value of Information
≈
Probability that new evidence changes decision
×
Importance of that decision change
-
Acquisition cost/risk
不一定真的计算数学期望值,但这个心智很重要。
例如:
再搜一次可能只是多一个同义解释
→ marginal value low
确认是否存在新的进行性无力
→ 可能直接改变 ESCALATE/AUTO
→ marginal value high
这就是 decision-relevant acquisition。
Acquisition 与 Evidence Admissibility 分开
工具成功返回 Evidence,并不等于这条 Evidence 可以进入 Decision。
例如:
A2 retrieves E8
但 E8 的 source version 不符合当前 configuration 的 evidence policy,则:
retrieved = true
admissible = false
G3 remains unresolved
详见 Agent Evidence Admissibility。
这说明 acquisition loop 中至少有两类成功:
mechanical success
→ 工具成功返回结果
business success
→ 返回结果合法且足以改变/关闭当前 Gap
二者不能混为一谈。
Acquisition Failure 也要分类
ToolFailure
→ timeout / 500 / connection error
NoResult
→ tool 正常,但 0 hit
InadmissibleResult
→ 有结果,但 policy 不允许用
InsufficientResult
→ 合法结果,但不足以解决 Gap
PermissionDenied
→ Gap 不允许这个 channel
BudgetDenied
→ 资源已耗尽
这些 failure 对后续策略完全不同。
如果统一压成:
search_failed
就无法做合理 retry、degradation 和 incident analysis。
Retry 与 New Attempt 的关系
网络层 retry:
HTTP timeout
→ retry same tool request
和业务层第二次 acquisition:
A1 结果不足
→ reformulate query
→ A2
语义不同。
建议区分:
transport retry
vs
semantic acquisition attempt
否则 budget 会被混乱计算:一次语义 attempt 可能内部有 infrastructure retry,但不一定应算成两次业务搜索。
LLM、Runtime 与 Policy 的 ownership
一个成熟结构可以这样划分:
LLM
→ propose gap / targeted semantic query
→ judge semantic relevance
Runtime
→ own budget
→ execute tool
→ create EvidenceAttempt
→ record actual evidence IDs
→ enforce no-search-after-exhaustion
Policy
→ authorize channel/source/version
→ decide consequences of unresolved critical gap
因此:
Prompt constraint 只能告诉模型“应该怎么做”;Runtime enforcement 才能保证系统“不能越界做”。
Query Generation:模型可以提出,但 Runtime 要约束形状
对 external knowledge gap,LLM 很适合把自然语言 gap 变成检索 query。
但可以有结构约束:
query non-empty
max length
no user-sensitive leakage
linked gap_id required
top_k bounded
source filters controlled by policy
也就是说:
LLM owns semantics of query
Runtime owns execution envelope
不要让模型通过 query 参数偷偷扩大 source scope 或 top_k budget。
BodySense 例子
G1
kind = external_knowledge
critical = false
→ policy allows search
→ A1 retrieves E31
→ admissible + relevant
→ G1 RESOLVED
G2
kind = user_information
critical = true
→ generic search forbidden
→ measurement unavailable
→ G2 UNRESOLVED
→ stop_reason = required_user_fact_unavailable
→ DecisionAuthority = ABSTAIN
即使 Python Candidate confidence = HIGH,G2 的状态也不会因此消失。
一个完整的 Acquisition Loop 例子
G7
kind = external_knowledge
critical = true
question = “当前干预在症状加重时应该停止吗?”
Attempt A1
query = broad phrase
returned = [E10, E11]
E10 inadmissible
E11 relevant but no stop condition
→ unresolved
budget 2 → 1
Attempt A2
模型根据缺失部分 reformulate:
query = targeted stop-condition query
returned = [E20]
E20 admissible
semantic support = sufficient
→ resolved
budget 1 → 0
stop_reason = gap_resolved
这里每一步都能解释:
为什么继续?
为什么改 query?
为什么 E11 不够?
为什么最终停止?
这就是受控 acquisition,而不是“模型多搜了两次”。
与 Configuration 的关系
Evidence tool surface、budget、source policy、gap schema 都属于 behaviorally significant configuration。
例如:
C9
→ evidence-policy-v2
→ max_search = 2
C12
→ evidence-policy-v3
→ new approved source + different acquisition rule
这种变化可能改变最终 decision,因此应该形成新的 configuration identity,并重新 qualification。
为什么 Tool Schema 变化也可能是 Configuration 变化
例如 v1 tool:
search_evidence(query)
v2 tool:
acquire_evidence(EvidenceGap)
后者强制绑定:
gap identity
source kind
rationale
criticality
这不仅是 API refactor,而是改变 Agent 可执行行为边界,因此是 behavior-significant change。
与 L4 Async/RAG 的关系
Acquisition policy 假设底层 tool 能在合理时间内完成。
如果:
sync psycopg blocks event loop
local embedding blocks event loop
可能出现:
Attempt timeout
→ budget consumed
→ critical Gap unresolved
→ ABSTAIN
表面上像“证据不足”,根因却可能是 runtime resource boundary。
所以 EvidenceAttempt 应记录:
latency
error/stopping reason
这样 Failure Attribution 才能区分:
knowledge unavailable
vs
infrastructure blocked
测试 Acquisition Policy 应覆盖什么
Channel policy
user_information → generic RAG forbidden
external_knowledge → targeted search allowed
Budget
max_search=2
third search rejected by runtime
Stopping
gap resolved → no more search
budget exhausted → no more search
Admissibility
retrieved but inadmissible
→ gap remains unresolved
Retry semantics
infrastructure retry
≠ semantic attempt count
Critical consequence
critical gap unresolved after stop
→ normal AUTO forbidden
Traceability
每个 attempt 必须能关联:
gap_id
query/channel
returned evidence IDs
budget before/after
stop reason
自测题
- 为什么 Tool capability 不等于 Acquisition policy?
- Gap kind 应怎样限制可用工具集合?
- 为什么 Prompt 中写“最多两次”不足以真正 enforce budget?
- Budget exhausted 为什么不能解释为 risk LOW?
- Tool 200 OK 与 business acquisition success 有什么区别?
- Broad retrieval 为什么会增加 context pollution 和 provenance 难题?
- transport retry 与 semantic EvidenceAttempt 为什么要区分?
- 为什么 stopping reason 是审计事实?
Expected Value of Information的心智如何帮助决定是否继续搜索?- L4 的 Event Loop blocking 为什么可能最终表现成 EvidenceGap unresolved?
常见误解
- 检索越多越安全:更多上下文也可能引入噪声、冲突和错误来源。
- 模型自己最清楚何时停:高风险路径的预算和停止规则应由 runtime/policy 持有。
- 获取失败后继续 AUTO:是否还能 AUTO 取决于剩余 gap 与 SafetyEnvelope。
- Budget 用完就代表尽力了,所以可以继续:尽力程度不是安全证明。
- Tool 返回 200 就算 Evidence 成功:还要做 identity、admissibility 和 semantic usefulness 判断。
- Prompt 写了“最多搜索两次”就够了:真正的次数上限应该由 runtime 强制执行。
- 停止取证就是系统失败:受控停止 + abstain/escalate 往往是正确的 production behavior。
- 所有 retry 都应该消耗一次业务 budget:先区分 infrastructure retry 与 semantic acquisition attempt。