本章概要 在多模态智能体系统中,Trace(轨迹) 是连接运行时(Inference)与训练时(Training)的唯一血脉。它不仅是调试的依据,更是构建“数据飞轮”的核心资产。 许多团队的痛点在于:线上跑了数万次任务,但因为 Log 格式混乱、缺乏证据对齐、多模态数据丢失,导致无法利用这些数据反哺模型。 本章将提供一套工业级、标准化的 Trace Schema 设计,并详解如何构建从“原始日志”到“SFT/DPO 训练数据”的 ETL 流水线。 核心产出:
- 全景 Trace 协议:支持文本、图像、工具、反思、用的统一 JSON 结构。
- 证据锚点(Grounding):解决多模态幻觉的坐标级对齐方案。
- 数据清洗流水线:从 PII 脱敏到质量打分的七道工序。
- 偏好数据集构建:自动化构造 Chosen/Rejected 样本的策略。
在深入 JSON 字段之前,我们需要理解一条 Trace 在系统中的流动。
[Runtime: Agent Execution]
│
▼
(RAW TRACE) <-- 包含冗余信息、Base64图片、原始HTML、未脱敏敏感词
│
▼
[ETL Pipeline: Cleaning & Formatting]
│
├── 1. 图片上传至 S3 (替换 Base64 为 URL)
├── 2. 敏感信息 (PII) 掩码处理
├── 3. 工具输出截断/摘要 (Canonicalization)
└── 4. 结构化校验 (Schema Validation)
│
▼
(GOLDEN TRACE) <-- 存入数据湖 (Data Lake),用于检索与回放
│
├── 分支 A: 行为克隆 (SFT Data Generation)
└── 分支 B: 偏好对齐 (DPO Pair Construction)
这是一套兼容 OpenAI Chat 格式但扩展了 Agent 特性(如思考链、引用、执行状态)的 Schema。
{
"trace_id": "req_550e8400-e29b", // 全局唯一请求 ID
"session_id": "sess_a1b2c3d4", // 会话 ID (用于多轮上下文)
"user_id": "user_12345", // 用户标识 (用于权限/个性化)
"timestamp_start": "2023-10-27T10:00:00Z",
"timestamp_end": "2023-10-27T10:00:15Z",
"duration_ms": 15000,
"status": "success", // success | failure | timeout
// 环境与配置快照 (这对复现 Bug 至关重要)
"meta": {
"model_name": "gpt-4-vision-preview",
"temperature": 0.1,
"system_prompt_version": "v3.1.2_finance_analyst",
"tools_schema_hash": "a8f9c2...", // 工具定的哈希值,防止工具变了 Log 没变
"environment": "production"
},
// 核心交互步骤
"steps": [ ... ],
// 最终产出与评测
"outcome": { ... }
}
步骤必须是一个有序列表,严格还原时间线。我们采用 role + content + metadata 的结构。
{
"step_index": 0,
"role": "user",
"timestamp": "...",
"content": [
{
"type": "text",
"text": "请分析这张合同中的付款条款,并检查是否合规。"
},
{
"type": "image_url",
"image_url": {
"url": "https://s3.bucket/path/to/img_01.jpg", // 这里的 URL 必须是持久化的
"detail": "high"
},
"metadata": {
"original_filename": "contract_scan.jpg",
"ocr_cache_key": "ocr_img_01" // 关联 OCR 预处理结果
}
}
]
}
是 Agent 的“大脑”活动。必须区分 思考 (Thought) 和 调用 (Call)。
{
"step_index": 1,
"role": "assistant",
"content": null, // 对于 Tool Call 步骤,content 通常为空或包含 CoT
// 显式的思维链 (CoT)
"thought": "用户上传了合同图片。我首先需要调用 OCR 工具提取文本,然后使用关键词搜索'付款条款'。",
"tool_calls": [
{
"id": "call_ocr_123",
"type": "function",
"function": {
"name": "document_ocr",
"arguments": "{\"image_id\": \"img_01\", \"mode\": \"dense_text\"}"
}
}
]
}
关键点:
thought字段是蒸馏小模型(SLM)的核心。小模型往往缺乏规划能力,通过学习大模型的thought,可以显著提升其推理能力。
记录环境的真实反馈。
{
"step_index": 2,
"role": "tool",
"tool_call_id": "call_ocr_123", // 必须对应上面的 call_id
"name": "document_ocr",
// 原始输出,可能非常长。训练时需要截断,但 Trace 中建议保留全量 (或存链接)
"content": "{\"full_text\": \"合同编号:HB-2023... 本合同付款方式如下:...\", \"pages\": 1}",
// 执行状态元数据
"metadata": {
"status": "ok", // ok | error
"latency_ms": 1200,
"is_truncated": false // 标记内容是否因过长被截断
}
}
如果工具报错,Trace 应如实记录,这构成了“负样本”或“修正样本”。
// Step 3: Assistant 收到错误后的反应
{
"role": "assistant",
"thought": "OCR 提取成功,现在我尝试在文本中搜索关键词。哎呀,我之前的搜索参数格式好像错了,我需要修正参数。",
"tool_calls": [...]
}
为了解决幻觉,Answer 必须“钉”在源文档上。我们不应只存储文本,应存储“带坐标的引用”。
在 outcome 字段中:
"outcome": {
"final_answer": "根据合同第 3 页,付款账期为验收后 30 天 [1]。",
"citations": [
{
"id": 1,
"source_doc_id": "doc_contract_001",
"quote_text": "乙方应在验收合格后 30 个工作日内支付款项", // 原文片段
"semantic_similarity": 0.98, // 验证模型打分
// 视觉定位 (Visual Grounding)
"location": {
"page_index": 2, // 0-indexed
"bbox": [100, 450, 600, 500], // [x1, y1, x2, y2]
"highlight_color": "yellow" // 前端渲染用
}
}
]
}
Rule of Thumb: 如果你的 Agent 是处理 PDF 的,必须存储 bbox。没有 bbox 的引用无法用于训练“多模态高亮”功能,也难以人工验证准确性。
有了上面的 Trace,我们如何生成训练数据?
目标:教会模型“如何正确使用工具”和“遵循格式”。
过滤逻辑 (The Filter Funnel):
status == "success" 的 Trace。thought 字段为空的样本(无法学习推理过程)。格式转换:
将 Trace 打平为 User -> Assistant (Thought + Call) -> Tool -> Assistant (Answer) 的线性对话格式。
目标:教会模型“什么更好”,减少幻觉,提升安全性。需要构造 (Prompt, Chosen, Rejected) 三元组。
利用模型生成的错误 Trace。
对于同一个 Prompt,让模型生成 N=4 个不同的回答路径。
不要把垃圾喂给模型。以下是建议的 ETL 清洗步骤:
| 步骤 | 动作名称 | 详细操作与规则 |
|---|---|---|
| 1 | 去重 (Dedup) | 计算 User Prompt 的 MinHash。对于重复度 > 0.9 的请求,只保留 Outcome 评分最高的一条。 |
| 2 | 脱敏 (Scrub) | Regex 替换:Email, Phone, IP Address, API Keys (sk-…)。 |
实体替换:将具体人名替换为 [PERSON],公司名替换为 [ORG](视任务而定,有时需要保留)。 |
|||
| 3 | 毒性检测 (Detox) | 使用轻量级分类器(如 Deberta-v3-small)扫描 user_input 和 final_answer。剔除色情、暴力、仇恨言论。 |
|
| 4 | 语言一致性 | 剔除中英文夹杂严重、乱码比例过高的文本。 | |
| 5 | 代码/JSON 校验 | 提取所有 JSON 和 Code Block,尝试解析 (JSON.parse / AST parse)。无法解析的视为“格式错误样本”,作为 Negative Sample 或丢弃。 | |
| 6 | 引用验证 | 检查 Trace 中的引用片段是否存在于源文档中。如果 quote_text 在原文找不到,标记为“幻觉样本”。 |
|
| 7 | 多模态对齐检查 | 检查 image_url 是否有效。如果是死链,该条数据必须丢弃,否则模型会学习到“无视图像”的行为。 |
User 和 Final Answer 的简单日志,请手动补充中间的 Thought 和 Tool Call 步骤,使其构成一个合法的 Chain-of-Thought Trace。任务:“查询 Google 股价并计算其市盈率。”```
sk- 开头的 OpenAI Key 和 11 位手机号替换为 [SECRET]。NameError。将运行报错后的 Trace 设为 Rejected。请分析这种成数据的优缺点。[1],但对应的 citations 列表里只有 source_id,没有具体的 text_span 或 bbox。[1],但指向的内容往往是随机的页面,造成“看起来有理有据的胡说八道”。assert len(citation.bbox) == 4。summary 字段。训练时使用 summary,但保留原始 content 用于审计。file_name 改为 filename),但历史 Trace 还是旧的。tool_version。在构建数据集时,必须编写 Adapter 将旧 Trace 迁移到新 Schema,或者丢弃旧版本数据的工具调用部分。