
Agent 跑了 3 小时,花了 $12。
失败了,不知道哪一步跑偏;
成功了,也不知道哪一步做对。
下次换模型、改 prompt、加 tool,
效果变好还是变坏,没人说得清。
这已经不是 prompt tuning 的问题,
而是 harness engineering 的问题。
可靠性的约束结构从文本层迈向系统层,每个阶段包含前一阶段。
把 Harness 当产品框架 — 让 Agent 跑得更好
把 Harness 当考场 — 让模型在里面练得更好
· 输入一个 prompt,得到一个回答
· 好坏主要看最终输出
· 调优靠改 prompt、加示例
适合 chatbot / 单轮任务
· 多轮调用 + tool + state + context
· 要控制权限、成本、失败恢复
· 要观测每一步、评估每次改动
Eval 是产品迭代闭环
过去跟模型说怎么用工具;现在让模型在真实 Harness 里反复练,把能力练进权重。
· 工具用法靠 prompt 描述
· 上下文压缩靠外部逻辑
· 执行策略靠脚手架约束
· 模型在真实 harness 上 rollout
· 用 trace / reward 学工具调用
· 把上下文管理、执行策略练进模型
仅改 harness 可带来 10× 性能提升
来源:Cursor × Fireworks · Sequoia Podcast 2026.05
应用侧调 Agent、模型侧训模型,最后都要回答同一个问题:这次改动到底是变好了还是变差了?
· Agent 是不确定性系统,同任务同模型路径也不同
· 只看 pass / fail、只看总成本,看不出差在哪
· 一次 tool 选择、一次上下文裁剪都会改变后续所有步骤
· 不能只存终态,要存下每一步的完整过程
· 要能按步骤对比两次执行的差异
· 要能把“哪一步”定位到成本和质量上
固定同一个任务和同一个模型(deepseek-v4-pro),只替换 Agent 产品侧的 Harness:
· 成本:evot $0.02 vs claude-code $0.07(便宜 67%)
· 耗时:6m10s vs 16m34s(快 63%)
· Token:42.9K vs 133.8K(少 68%)
· 调用次数:36 vs 75(少 52%)
一次 tool 选择、一次上下文裁剪、一次错误恢复,都会改变后续所有步骤。展开 trace 后会发现,差异从 tool call 序列就开始了:
· System:行为约束、工具规则、输出格式
· User task:当前目标和约束
· Messages:历史对话、决策和 compact 摘要
· Tools:工具列表、description、JSON schema
· 工具返回:文件、命令、错误、结构化结果
{
// system instructions
"system": "You are an expert coding assistant...",
"tools": [
{ "name": "Read", "input_schema": {...} },
{ "name": "Bash", "input_schema": {...} },
{ "name": "Edit", "input_schema": {...} }
],
"messages": [
{ "role": "user", "content": "fix json parser" },
{ "role": "assistant", "tool_use": "Read" },
{ "role": "tool", "content": "...command/file/error..." }
// old messages may be compacted
],
"usage": { "input_tokens": 9200, "latency": "5.4s" }
}
· 主要记录服务调用链
· 一次请求通常秒级到分钟级
· 字段来自 SDK / instrumentation
· schema 相对稳定
· 分析重点:latency、status、error
· 一个任务可能持续几十分钟到几小时
· span 持续追加,状态会跨步骤演化
· 内容来自 prompt、messages、tool call、tool result
· LLM 返回经常不是合法 JSON,字段类型会漂移
· 分析重点:token、cost、tool choice、关键分叉点
· 单条 trace:500KB ~ 500MB
· 嵌套 3~8 层,最多 10万+ span
· 单任务执行最长可达 十几小时
· 每天 几百 TB,只能留存短期
· RL 训练模型自生成的轨迹,比线上流量再大一个量级
· 清理脏 JSON:容错解析模型和工具输出
· 拆解嵌套结构:message、tool call、tool result
· 抽取热点字段:model、tokens、cost、tool、error
· 支持检索和聚合:对比、归因、回放
· 兼容 schema 漂移:agent / tool / model 持续变化
| 需求 | 为什么重要 |
|---|---|
| JSON 原生存取 | 轨迹天然是嵌套 JSON |
| JSON 清洗与变换 | 脏 JSON、长字段、嵌套结构要在库内处理 |
| JSON 索引加速 | 海量轨迹数据快速检索 |
| JSON 内全文索引 | 根据关键词定位某次对话 |
| JSON Path RBAC | 合规要求:敏感字段按路径授权 / 脱敏 |
| 对象存储,成本低 | Agent trace 巨大,要长期存 |
| 高吞吐持续写入 | 海量用户 / Agent Swarm 并发产生 trace |
Trace 持续写入对象存储;Databend 通过 Task 消费 Stage,在库内完成入库、清洗和聚合
CREATE TABLE events (
trace_id STRING, type STRING,
input_messages VARIANT, output_messages VARIANT,
tool_definitions VARIANT,
input_tokens INT, output_tokens INT, total_cost FLOAT64,
tags VARIANT,
-- Computed Column (STORED): 写入时自动物化,查询零开销
input_summary STRING AS (substr(to_string(input_messages), 1, 500)) STORED,
output_summary STRING AS (substr(to_string(output_messages), 1, 500)) STORED, ...
) CLUSTER BY (to_yyyymmdd(start_time), trace_id);
-- 清洗脏 JSON:截断长 content,保留嵌套结构
SELECT object_insert(raw_data, 'events',
json_array_transform(raw_data:events, e -> object_insert(e, 'stringValue',
object_insert(e:stringValue, 'content', to_variant(left(
CASE WHEN json_typeof(e:stringValue:content) = 'String'
THEN e:stringValue:content::string
ELSE to_string(e:stringValue:content) END, 200)), true), true)), true) AS cleaned_data;
CREATE STREAM events_stream ON TABLE events APPEND_ONLY = TRUE;
-- 新 events 到达后,自动刷新 traces 聚合表
CREATE TASK task_refresh_traces SCHEDULE = 5 SECOND
WHEN STREAM_STATUS('events_stream') = TRUE AS
REPLACE INTO traces ON (id) SELECT trace_id, sum(input_tokens), ...;
CREATE INVERTED INDEX idx_search ON events(name, trace_name, operation_name, tags);
不要只看最终 pass / fail
原始 trace 长期保留
存下来还要查得动、算得快
加速列、全文检索、增量聚合
Eval / Replay / RL 不再各存一套
一份 trace,多种上层能力
试一下?
Databend 正在支撑头部大模型公司的数据底座
辅助 Agent 评测、轨迹归因与 RL 数据管线 · 日均几百 TB 级写入 · 全量 Agent 轨迹持久化
国内 · databend.cn
全球 · databend.com
GitHub · github.com/databendlabs/databend ★ 9.3k stars
微信公众号