可观察轨迹:看清动作、结果和回答的来源
正在读取学习记录…
1. 一条轨迹保存什么
轨迹是按时间顺序保存的事件记录。一次查询任务可以记录:收到目标、选择工具、执行查询、取得资料、生成答复、停止。每个事件都带同一任务编号,读记录的人就能把它们串起来。
这像快递查询:你查看包裹在哪个站点、何时离开、谁签收。Agent 的轨迹关注可观察的动作和结果,帮助解释它查过什么、为什么得出这条答复、卡在哪个环节。
动作表示发出了什么请求,观察表示工具返回什么,最终回答表示用户看到什么。来源字段负责把回答连接到观察。更完整的来源可包含文档编号、段落位置和版本。
2. 从事件列表整理出一个可回查结果
想象这次助手做了三件事:请求退款政策,收到“退款7天”,把这条资料用于回答。我们按发生顺序保存三条事件。它们是本程序的过程记录,字段含义如下:
| 事件字段 | 含义 | 示例 |
|---|---|---|
run_id | 整次任务的编号 | r1,三条记录属于同一次任务 |
kind | 发生的事情 | action 发出查询、observation 收到资料、final 生成回答 |
source | 查询或引用的资料标识 | policy 表示退款政策资料 |
text | 收到的资料正文或最终回答 | 退款7天 |
先在 PowerShell 创建并进入学习目录:
mkdir "F:\学习\l3-evidence" -Force
cd "F:\学习\l3-evidence"保存下面的文件后,在这个终端运行 dir 核对文件名,再执行本节给出的运行命令。
在新目录创建 evidence.py:
先在 PowerShell 创建并进入学习目录:
mkdir "F:\学习\l3-evidence" -Force
cd "F:\学习\l3-evidence"保存下面的文件后,在这个终端运行 dir 核对文件名,再执行本节给出的运行命令。
"""沿动作、观察和回答的记录,找出回答所依据的资料。"""
import json
def summarize(events):
actions = 0
observed = {}
run_id = events[0]["run_id"] if events else None
answer = None
for event in events:
if event["run_id"] != run_id:
raise ValueError("同一轨迹包含多个任务")
if event["kind"] == "action":
actions += 1
elif event["kind"] == "observation":
# 按来源保存原文,后续回答可回查。
observed[event["source"]] = event["text"]
elif event["kind"] == "final":
if observed.get(event["source"]) != event["text"]:
raise ValueError("回答缺少对应的资料观察")
answer = {"actions": actions, "answer": event["text"], "source": event["source"]}
if answer is None:
raise ValueError("轨迹尚无回答")
return answer
if __name__ == "__main__":
events = [
{"run_id": "r1", "kind": "action", "source": "policy"},
{"run_id": "r1", "kind": "observation", "source": "policy", "text": "退款7天"},
{"run_id": "r1", "kind": "final", "source": "policy", "text": "退款7天"},
]
print(json.dumps(summarize(events), ensure_ascii=False))ls
python evidence.py输出:
{"actions": 1, "answer": "退款7天", "source": "policy"}这份汇总表示:助手发出过1次动作(actions),最终回答为“退款7天”(answer),引用的资料是退款政策(source: policy)。actions 数的是事件列表中的动作记录,source 则让你回到相应的资料事件核对正文。
代码遍历事件列表,动作增加计数,观察按来源保存原文,最终回答按来源回查。示例使用原文完全相同的短答复,因此能直接比较字符串。
run_id 是任务编号;kind 是事件类型;source 是资料来源;text 是返回或回答内容。调用多次工具时,各次动作还可以带 call_id,把请求和响应一一对应。
3. 改变来源,观察回查失败
把最后事件的来源从 policy 改为 other,运行会出现“回答缺少对应的资料观察”。恢复来源,再把最后文本改为“退款14天”,同样会失败。因为已保存观察是7天。
接着把最后事件的 run_id 改为 r2,会出现“同一轨迹包含多个任务”。这个修改说明任务编号也参与一致性检查。恢复所有改动后再运行测试。
4. 用测试保存判断规则
在同目录创建 test_evidence.py:
下面的测试检查回答能否找到对应观察,以及任务编号和资料正文是否一致。
测试代码:test_evidence.py
"""检查evidence示例的正常路径和边界结果。"""
import unittest
from evidence import summarize
class Tests(unittest.TestCase):
def test_trace(self):
events=[{"run_id":"r1","kind":"action","source":"policy"},{"run_id":"r1","kind":"observation","source":"policy","text":"退款7天"},{"run_id":"r1","kind":"final","source":"policy","text":"退款7天"}]
self.assertEqual(summarize(events),{"actions":1,"answer":"退款7天","source":"policy"})
def test_missing(self):
with self.assertRaises(ValueError): summarize([{"run_id":"r1","kind":"final","source":"policy","text":"退款7天"}])
if __name__ == "__main__":
unittest.main()python -m unittest test_evidence -v正常路径与改动后的边界都在测试中检查。若结果不同,先定位失败的断言,再回到对应的字段与分支。
5. 扩展轨迹时,先想清排查问题
| 要排查的问题 | 需要记录的字段 |
|---|---|
| 一次请求等了多久 | 开始时间、结束时间、耗时 |
| 调用了哪个工具 | 工具名、调用编号、必要参数 |
| 答复依据在哪里 | 文档编号、片段和版本 |
| 任务为何停下 | 状态和停止原因 |
| 费用为何增加 | 模型调用次数、输入输出用量 |
| 谁批准了写入 | 审批者、提案版本和回执 |
长答复通常是对原文的归纳,不能简单用字符串相等判断。可以先保存引用片段和对应句子,再人工或程序辅助核对支持关系。轨迹提供回查入口,资料质量与结论支持仍需检查。
记录也有成本:完整对话可能很大,敏感字段需要脱敏,访问权限和保留期限需要配置。优先记录排查需要的最小信息,原始资料按受控地址回查;凭据用占位符或字段删除处理。
并行工具的事件可能交错,所以任务编号与调用编号比打印先后更重要。每个调用保存起止事件,按编号聚合后再计算耗时。对照 OpenTelemetry 的追踪概念,可以进一步理解多个组件之间的关联。
模型内部思维与可观察事件有不同的数据来源。工程排查先查看真实请求、工具返回、状态变化和引用,读者能够逐项核对。总结:同一任务串事件,同一调用配响应,来源连资料,停止原因说明出口。回到 L3总览把这些部件组合成完整循环。
从事件列表读出处理过程
| 位置 | kind | source | 读者能确认什么 |
|---|---|---|---|
| 1 | action | policy | 程序发起政策查询 |
| 2 | observation | policy | 工具返回退款7天 |
| 3 | final | policy | 答复引用该次资料 |
当前程序比较短答复与原文是否相等,因此最后事件换成14天会直接失败。长答复通常包含归纳,可保存“回答句子→引用片段”的关系,再检查片段是否支持该句。
多个来源时,观察可以按来源与调用编号一起存。两个查询都叫policy,也可能使用不同过滤条件;编号能进一步区分它们。任务编号把整次运行连起来,调用编号把某次请求和响应配起来。
轨迹可以帮助复盘卡点:重复动作的参数是否一致,失败是否发生在同一来源,等待时间耗在哪里,最终回答采用哪份资料。必要的字段比单纯打印“开始、结束”更容易定位因果。敏感正文可用受控资源地址回查,用户界面展示必要片段。
课后练习展开习题收起习题
正在读取本地记录…
不调用模型,不执行代码。简答、代码和场景题仅保存答案并展示自查标准,不生成评分、徽章或认证。输入内容不会自动保存,请点击提交;不要填写个人信息或密钥。
选择题 · 先判断边界
关于“保存可观察轨迹而非索取私密思维链”,哪种做法更稳妥?
对应知识点:L3-evidence
简答题 · 解释失败
写出一个失败输入并说明记录字段。
对应知识点:L3-evidence
代码题 · 边界测试
补充正常、边界、失败三组输入和预期结果。
对应知识点:L3-evidence
场景题 · 结果未知
证据不足时如何设计状态和人工接管?
对应知识点:L3-evidence
描述会发送给本站维护者,用于修订文章,保存90天。请只填写文章问题,省略个人信息、密钥和内部资料。