一、概述
1.1 背景
Agent 客户端需要一套轻量、低侵入的性能追踪体系,支持:
- 关键路径耗时测量
- 跨平台统一 API(iOS Swift / Android Kotlin)
- 远端配置控制(开关、采样率)
- 数据上报与可视化
1.2 设计目标
| 目标 | 说明 |
|---|---|
| 低侵入 | 一行代码埋点,不污染业务逻辑 |
| 低开销 | 对主线程影响 < 1ms,内存增长可控 |
| 跨平台 | iOS/Android API 一致,数据格式统一 |
| 可配置 | 远端开关、采样率、追踪深度可动态调整 |
| 鲁棒性 | 上报失败不丢数据、崩溃不影响业务、异常自动降级 |
二、架构设计
scss
┌─────────────────────────────────────────────────────────────────┐
│ Business Layer │
│ trace("api_call") { ... } │
└─────────────────────────────┬───────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────┐
│ Trace SDK (Core) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ TraceBuilder │ │ SpanRecorder │ │ ConfigManager│ │
│ │ (API 层) │ │ (采集层) │ │ (配置层) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ ThreadSafeQ │ │ BufferPool │ │ CrashHandler │ │
│ │ (队列) │ │ (缓冲池) │ │ (崩溃保护) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────┬───────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────┐
│ Exporter Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ DebugExporter│ │ RemoteExporter│ │ OfflineCache │ │
│ │ (调试输出) │ │ (上报服务) │ │ (离线缓存) │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────┬───────────────────────────────────┘
▼
┌─────────────────────────────────────────────────────────────────┐
│ Backend Services │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ Config Server │ │ Analytics Svr │ │
│ │ (配置中心) │ │ (数据分析) │ │
│ └────────────────┘ └────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
三、核心概念
3.1 数据模型
yaml
Trace
├── traceId: String # 唯一标识,全链路追踪
├── name: String # 追踪名称
├── startTime: Long # 开始时间戳 (ns)
├── endTime: Long # 结束时间戳 (ns)
├── duration: Long # 耗时 (ns)
├── status: Status # SUCCESS / FAILURE / TIMEOUT
├── tags: Map<String, String> # 业务标签
├── events: List<Event> # 内部事件
└── parentSpanId: String? # 父 Span,支持嵌套
Event
├── name: String
├── timestamp: Long
└── attributes: Map<String, Any>
3.2 追踪类型
| 类型 | 说明 | 示例 |
|---|---|---|
| 同步追踪 | trace("api") { ... } | API 调用、页面渲染 |
| 异步追踪 | traceAsync("stream").start()...end() | 流式响应、长任务 |
| 嵌套追踪 | trace 内部再 trace | 请求 → 序列化 → 网络传输 |
四、API 设计
4.1 Android (Kotlin)
javascript
// 基础用法
trace("api_call") {
tags("endpoint" to "/chat", "method" to "POST")
apiClient.send(request)
}
// 带结果的追踪
val response = trace("api_call") {
tags("endpoint" to "/chat")
result = apiClient.send(request)
result
}
// 异步追踪
val span = traceAsync("stream_response") {
tags("model" to "gpt-4")
}
stream.collect { chunk ->
span.addEvent("chunk_received", mapOf("size" to chunk.size))
}
span.end()
// 嵌套追踪
trace("request_flow") {
trace("serialize") {
serializer.encode(request)
}
trace("network") {
httpClient.post(url, body)
}
}
4.2 iOS (Swift)
javascript
// 基础用法
trace("api_call") {
$0.tags(["endpoint": "/chat", "method": "POST"])
try apiClient.send(request)
}
// 带结果的追踪
let response = trace("api_call") { span in
span.tags(["endpoint": "/chat"])
return try apiClient.send(request)
}
// 异步追踪
let span = traceAsync("stream_response") { $0.tags(["model": "gpt-4"]) }
for try await chunk in stream {
span.addEvent("chunk_received", ["size": chunk.count])
}
span.end()
// 嵌套追踪
trace("request_flow") { _ in
trace("serialize") { _ in serializer.encode(request) }
trace("network") { _ in try httpClient.post(url, body) }
}
4.3 API 统一规范
| 特性 | Android | iOS |
|---|---|---|
| 同步追踪 | trace(name) { ... } |
trace(name) { ... } |
| 异步追踪 | traceAsync(name) { ... } |
traceAsync(name) { ... } |
| 添加标签 | tags("k" to "v") |
tags(["k": "v"]) |
| 添加事件 | span.addEvent(name, attrs) |
span.addEvent(name, attrs) |
| 标记状态 | span.setStatus(Status.SUCCESS) |
span.setStatus(.success) |
五、核心模块设计
5.1 TraceBuilder(API 层)
职责:提供简洁的 trace API,管理 Span 生命周期。
css
设计要点:
├── 线程安全:支持多线程并发调用
├── 嵌套检测:ThreadLocal 记录当前 Span 栈
├── 自动采样:根据采样率决定是否采集
└── 异常捕获:业务异常自动标记 FAILURE
Android 实现(伪代码) :
kotlin
object TraceSDK {
private val spanStack = ThreadLocal<MutableList<Span>>()
inline fun <T> trace(name: String, block: TraceScope.() -> T): T {
if (!ConfigManager.isEnabled(name)) {
return TraceScope.NOOP.run(block)
}
val span = SpanBuilder(name)
.setParent(spanStack.get()?.lastOrNull())
.setStartTime(System.nanoTime())
.build()
spanStack.getOrSet { mutableListOf() }.add(span)
return try {
val result = TraceScope(span).run(block)
span.setStatus(Status.SUCCESS)
result
} catch (e: Exception) {
span.setStatus(Status.FAILURE).setError(e)
throw e
} finally {
spanStack.get()?.remove(span)
span.end()
SpanRecorder.record(span)
}
}
}
5.2 SpanRecorder(采集层)
职责:采集、聚合、缓冲 Span 数据。
css
数据流:
Span 结束 → 校验 → 写入 RingBuffer → 后台线程消费 → 聚合/上报
设计要点:
├── RingBuffer:无锁环形缓冲,容量可配(默认 10000 条)
├── 采样率:按 name 配置,0.01~1.0
├── 聚合窗口:相同 name 的 Span 合并统计(P50/P99/Max/Min)
└── 异常隔离:采集线程独立,不影响业务线程
5.3 ConfigManager(配置层)
职责:管理远端配置,支持动态调整。
配置结构:
json
{
"version": "1.0.3",
"global": {
"enabled": true,
"sampleRate": 0.1,
"maxSpansPerSession": 500
},
"traces": {
"api_call": {
"enabled": true,
"sampleRate": 0.5,
"maxDurationMs": 30000
},
"ui_render": {
"enabled": true,
"sampleRate": 0.01
},
"debug_trace": {
"enabled": false
}
},
"export": {
"batchSize": 100,
"flushIntervalMs": 30000,
"maxRetries": 3
}
}
配置拉取策略:
markdown
App 启动 → 拉取远端配置
├── 成功 → 缓存本地,更新内存
└── 失败 → 使用本地缓存(过期则用默认配置)
定期轮询 → 每 5 分钟检查配置版本
├── 版本变化 → 拉取新配置
└── 版本相同 → 跳过
5.4 Exporter(上报层)
职责:数据上报,支持多种导出方式。
arduino
Exporter 类型:
├── DebugExporter:调试模式,输出到 Logcat / Console
├── RemoteExporter:上报到服务端
│ ├── 批量上报(默认 100 条/批)
│ ├── 指数退避重试
│ └── 压缩传输(gzip)
└── OfflineCache:离线缓存
├── 上报失败 → 写入本地 SQLite
└── 下次成功时回补
上报数据格式:
json
{
"deviceId": "xxx",
"sessionId": "xxx",
"appVersion": "2.1.0",
"os": "android",
"osVersion": "14",
"timestamp": 1712540000000,
"spans": [
{
"traceId": "abc123",
"name": "api_call",
"durationNs": 123456789,
"status": "SUCCESS",
"tags": {"endpoint": "/chat"},
"events": []
}
],
"aggregations": [
{
"name": "api_call",
"count": 100,
"p50": 95000000,
"p99": 150000000,
"max": 200000000,
"errorRate": 0.02
}
]
}
5.5 CrashHandler(崩溃保护)
职责:确保 Trace SDK 不导致 App 崩溃,崩溃时保存数据。
arduino
保护机制:
├── 所有公开 API 用 try-catch 包裹
│ └── 异常时静默降级(NoOp 实现)
├── 内部线程异常捕获
│ └── 记录错误日志,不影响业务
└── App 崩溃时
└── 保存当前 Span 到磁盘,下次启动上报
六、鲁棒性设计
6.1 性能开销控制
| 场景 | 目标 | 实现 |
|---|---|---|
| 禁用 trace | 0 开销 | 编译期注解剔除 / 运行时快速返回 |
| 单次 trace | < 0.5ms | 无锁 RingBuffer,预分配内存 |
| 内存占用 | < 5MB | RingBuffer 容量限制,定期清理 |
| CPU 占用 | < 1% | 后台线程异步处理,不阻塞主线程 |
6.2 降级策略
erlang
降级场景:
├── 内存不足(> 80%)→ 降低采样率或暂停采集
├── CPU 过载(> 90%)→ 暂停采集
├── 上报连续失败(> 5 次)→ 切换离线模式
├── 配置拉取失败 → 使用本地缓存
└── 内部异常 → 降级为 NoOp 实现
6.3 数据安全
bash
├── 敏感数据过滤:自动脱敏 tags 中的 token/password
├── 数据压缩:上报前 gzip 压缩
├── 传输加密:HTTPS + 证书校验
└── 本地加密:SQLite 数据加密
七、集成指南
7.1 Android 集成
arduino
// build.gradle
implementation "com.company:trace-sdk:1.0.0"
ini
// Application.onCreate()
TraceSDK.init(
config = TraceConfig(
appId = "your-app-id",
configUrl = "https://config.example.com/trace",
reportUrl = "https://analytics.example.com/trace"
)
)
7.2 iOS 集成
php
// Package.swift
dependencies: [
.package(url: "https://github.com/company/trace-sdk-ios", from: "1.0.0")
]
less
// AppDelegate
TraceSDK.initialize(
config: TraceConfig(
appId: "your-app-id",
configUrl: "https://config.example.com/trace",
reportUrl: "https://analytics.example.com/trace"
)
)
7.3 调试模式
arduino
// Android
TraceSDK.setDebugMode(true) // 输出到 Logcat
// iOS
TraceSDK.setDebugMode(true) // 输出到 Console
八、监控面板
8.1 核心指标
| 指标 | 说明 | 告警阈值 |
|---|---|---|
| P99 延迟 | 99% 请求的耗时 | > 3s |
| 错误率 | 失败占比 | > 5% |
| 采样率 | 实际采样比例 | < 配置值的 50% |
| 上报成功率 | 数据上报成功占比 | < 90% |
| SDK 内存占用 | Trace SDK 内存使用 | > 10MB |
8.2 数据看板
- 实时监控:P50/P99 延迟曲线、QPS、错误率
- 场景分析:按 trace name 分组统计
- 版本对比:不同 App 版本的性能对比
- 设备分布:按机型、系统版本分组
九、扩展性
9.1 自定义 Exporter
kotlin
class MyExporter : SpanExporter {
override fun export(spans: List<Span>): Boolean {
// 自定义上报逻辑
return true
}
}
TraceSDK.registerExporter(MyExporter())
9.2 自定义 Sampler
kotlin
class MySampler : Sampler {
override fun shouldSample(name: String, attrs: Map<String, Any>): Boolean {
// 自定义采样逻辑,如只采样 VIP 用户
return attrs["user_type"] == "vip"
}
}
TraceSDK.setSampler(MySampler())
9.3 插件扩展
less
// 自动追踪 OkHttp 请求
TracePlugin.install(OkHttpTracePlugin())
// 自动追踪 Retrofit
TracePlugin.install(RetrofitTracePlugin())
// 自动追踪 Jetpack Compose 渲染
TracePlugin.install(ComposeTracePlugin())
十、实施计划
Phase 1:核心 SDK(2 周)
- Android Kotlin 核心实现
- iOS Swift 核心实现
- 基础 API 设计
- 单元测试
Phase 2:配置与上报(1 周)
- 远端配置拉取
- 数据上报模块
- 离线缓存
Phase 3:集成与优化(1 周)
- 性能优化
- 崩溃保护
- 示例代码
- 接入文档
Phase 4:监控面板(2 周)
- 数据接收服务
- 实时监控面板
- 告警配置
十一、附录
A. 命名规范
bash
trace name 格式:模块_动作
示例:
├── api_call # API 调用
├── api_chat_stream # API 流式聊天
├── ui_page_render # 页面渲染
├── ui_dialog_show # 弹窗显示
├── db_query # 数据库查询
├── cache_read # 缓存读取
└── tool_invoke # Agent 工具调用
B. 版本兼容
| 平台 | 最低版本 |
|---|---|
| Android | API 21+ (Android 5.0) |
| iOS | iOS 13+ |
C. 参考资料
十二、场景实战:Agent 目标生成 Benchmark
12.1 场景描述
用户输入:Goal / Prompt(例如:"帮我生成一份周报大纲")
Agent (Server) 处理:
- 理解用户意图
- 规划生成步骤
- 调用工具/模型
- 生成结果列表(任意组合)
Benchmark 需求:
- 追踪整个生成过程的耗时、各阶段耗时
- 评估生成结果的质量(与预期对比)
- 支持批量跑测试用例,输出报告
12.2 客户端埋点设计
javascript
// 用户提交 goal
fun submitGoal(goal: String, prompt: String): Result<List<String>> {
return trace("agent_goal_generate") {
// 标记输入
tags(
"goal" to goal,
"prompt_length" to prompt.length,
"timestamp" to System.currentTimeMillis()
)
// 阶段1:发送请求
val requestId = trace("request_send") {
tags("goal" to goal)
apiClient.submitGoal(goal, prompt)
}
// 阶段2:等待响应(可能流式)
val response = trace("response_wait") {
tags("request_id" to requestId)
apiClient.waitForResponse(requestId)
}
// 阶段3:解析结果
val result = trace("result_parse") {
tags("response_size" to response.size)
parser.parse(response)
}
// 阶段4:质量评估(如果有预期结果)
if (expectedResults != null) {
trace("quality_evaluate") {
tags(
"expected_count" to expectedResults.size,
"actual_count" to result.size
)
evaluator.evaluate(result, expectedResults)
}
}
// 标记最终结果
addEvent("completed", mapOf(
"result_count" to result.size,
"success" to true
))
result
}
}
12.3 Benchmark 用例设计
用例结构:
kotlin
data class BenchmarkCase(
val id: String,
val goal: String,
val prompt: String,
val expectedResults: ExpectedResult?, // 可选
val constraints: Constraints // 超时、重试等
)
data class ExpectedResult(
val items: List<String>? = null, // 精确匹配
val keywords: List<String>? = null, // 关键词匹配
val countRange: IntRange? = null, // 数量范围
val schema: JsonSchema? = null // 结构校验
)
data class Constraints(
val timeoutMs: Long = 30000,
val maxRetries: Int = 3,
val temperature: Float? = null // 固定随机性
)
测试用例示例:
ini
val benchmarkCases = listOf(
// 用例1:周报大纲生成
BenchmarkCase(
id = "weekly_report_outline",
goal = "生成周报大纲",
prompt = "本周完成了 A/B/C 三个项目,下周计划 D/E",
expectedResults = ExpectedResult(
countRange = 3..5,
keywords = listOf("本周", "下周", "项目")
),
constraints = Constraints(timeoutMs = 10000, temperature = 0.0f)
),
// 用例2:代码审查清单
BenchmarkCase(
id = "code_review_checklist",
goal = "生成代码审查清单",
prompt = "Python 后端项目,关注性能和安全",
expectedResults = ExpectedResult(
countRange = 5..10,
keywords = listOf("性能", "安全", "Python")
),
constraints = Constraints(temperature = 0.0f)
),
// 用例3:无预期结果,只测耗时
BenchmarkCase(
id = "creative_writing",
goal = "创意写作",
prompt = "写一个科幻短篇的开头",
expectedResults = null,
constraints = Constraints(timeoutMs = 15000)
)
)
12.4 Benchmark Runner 设计
kotlin
class AgentBenchmarkRunner(
private val traceSDK: TraceSDK,
private val reporter: BenchmarkReporter
) {
/**
* 运行单个用例
*/
suspend fun runCase(case: BenchmarkCase): BenchmarkResult {
// 初始化 Trace 追踪整个 benchmark
return trace("benchmark_case") {
tags(
"case_id" to case.id,
"goal" to case.goal
)
// 多次运行取平均
val iterations = mutableListOf<IterationResult>()
repeat(case.constraints.maxRetries.coerceAtLeast(1)) { iteration ->
val iterResult = trace("iteration_${iteration}") {
tags("iteration" to iteration)
runSingleIteration(case)
}
iterations.add(iterResult)
}
// 聚合结果
val result = BenchmarkResult(
caseId = case.id,
iterations = iterations,
avgDurationMs = iterations.map { it.durationMs }.average().toLong(),
successRate = iterations.count { it.success }.toDouble() / iterations.size,
qualityScore = calculateQualityScore(iterations)
)
addEvent("benchmark_completed", mapOf(
"avg_duration_ms" to result.avgDurationMs,
"success_rate" to result.successRate,
"quality_score" to result.qualityScore
))
result
}
}
/**
* 批量运行
*/
suspend fun runSuite(cases: List<BenchmarkCase>): SuiteResult {
return trace("benchmark_suite") {
tags("case_count" to cases.size)
val results = cases.map { case ->
runCase(case)
}
SuiteResult(
results = results,
totalDurationMs = results.sumOf { it.avgDurationMs },
overallSuccessRate = results.map { it.successRate }.average(),
reportUrl = reporter.generateReport(results)
)
}
}
private suspend fun runSingleIteration(case: BenchmarkCase): IterationResult {
val startTime = System.currentTimeMillis()
return try {
val result = submitGoal(case.goal, case.prompt)
val duration = System.currentTimeMillis() - startTime
// 质量评估
val quality = case.expectedResults?.let { expected ->
evaluateQuality(result, expected)
} ?: QualityScore.NA
IterationResult(
success = true,
durationMs = duration,
qualityScore = quality,
actualResult = result
)
} catch (e: Exception) {
IterationResult(
success = false,
durationMs = System.currentTimeMillis() - startTime,
error = e.message
)
}
}
}
12.5 质量评估实现
kotlin
interface QualityEvaluator {
fun evaluate(actual: List<String>, expected: ExpectedResult): QualityScore
}
class DefaultQualityEvaluator : QualityEvaluator {
override fun evaluate(actual: List<String>, expected: ExpectedResult): QualityScore {
var score = 0.0
var total = 0.0
// 1. 数量匹配(权重 30%)
expected.countRange?.let { range ->
total += 30
if (actual.size in range) score += 30
}
// 2. 关键词覆盖(权重 40%)
expected.keywords?.let { keywords ->
total += 40
val coverage = keywords.count { keyword ->
actual.any { it.contains(keyword, ignoreCase = true) }
}.toDouble() / keywords.size
score += 40 * coverage
}
// 3. 精确匹配(权重 30%)
expected.items?.let { items ->
total += 30
val matchRate = actual.intersect(items.toSet()).size.toDouble() / items.size
score += 30 * matchRate
}
return QualityScore(
totalScore = if (total > 0) score / total * 100 else 100.0,
breakdown = mapOf(
"count_match" to (expected.countRange?.let { actual.size in it } ?: true),
"keyword_coverage" to (expected.keywords?.let { kws ->
kws.count { kw -> actual.any { it.contains(kw, ignoreCase = true) } }.toDouble() / kws.size
} ?: 1.0),
"exact_match" to (expected.items?.let { items ->
actual.intersect(items.toSet()).size.toDouble() / items.size
} ?: 1.0)
)
)
}
}
12.6 输出报告
单用例报告:
yaml
┌─────────────────────────────────────────────────────────┐
│ Benchmark Report: weekly_report_outline │
├─────────────────────────────────────────────────────────┤
│ Goal: 生成周报大纲 │
│ Prompt: 本周完成了 A/B/C 三个项目... │
├─────────────────────────────────────────────────────────┤
│ 性能指标 │
│ - 平均耗时: 1,234 ms │
│ - P50: 1,100 ms │
│ - P99: 2,500 ms │
│ - 成功率: 95% │
├─────────────────────────────────────────────────────────┤
│ 质量指标 │
│ - 总分: 87/100 │
│ - 数量匹配: ✓ (实际 4 条, 预期 3-5 条) │
│ - 关键词覆盖: 75% (缺少 "项目") │
│ - 精确匹配: N/A │
├─────────────────────────────────────────────────────────┤
│ Trace 详情 │
│ - agent_goal_generate: 1,234 ms │
│ - request_send: 50 ms │
│ - response_wait: 1,100 ms │
│ - result_parse: 30 ms │
│ - quality_evaluate: 54 ms │
└─────────────────────────────────────────────────────────┘
批量报告:
yaml
┌──────────────────────────────────────────────────────────────┐
│ Benchmark Suite Report │
├──────────────────────────────────────────────────────────────┤
│ Summary │
│ - 用例数: 10 │
│ - 总耗时: 12.5 s │
│ - 平均成功率: 92% │
│ - 平均质量分: 85/100 │
├──────────────────────────────────────────────────────────────┤
│ Top Slow Cases │
│ 1. creative_writing: 3,200 ms │
│ 2. code_review_checklist: 2,100 ms │
│ 3. weekly_report_outline: 1,234 ms │
├──────────────────────────────────────────────────────────────┤
│ Quality Issues │
│ - creative_writing: 关键词覆盖率仅 50% │
│ - api_doc_generate: 数量超出预期范围 │
└──────────────────────────────────────────────────────────────┘
12.7 集成到 CI/CD
yaml
# .github/workflows/benchmark.yml
name: Agent Benchmark
on:
pull_request:
branches: [main]
schedule:
- cron: '0 2 * * *' # 每天凌晨 2 点
jobs:
benchmark:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Run Android Benchmark
run: |
./gradlew :app:connectedBenchmarkAndroidTest
- name: Run iOS Benchmark
run: |
xcodebuild test -scheme Benchmark -destination 'platform=iOS Simulator,name=iPhone 15'
- name: Upload Report
uses: actions/upload-artifact@v3
with:
name: benchmark-report
path: build/benchmark/
- name: Check Regression
run: |
python scripts/check_regression.py \
--baseline .benchmark/baseline.json \
--current build/benchmark/result.json \
--threshold 10 # 性能退化超过 10% 则失败
12.8 关键设计点总结
| 需求 | 设计 |
|---|---|
| 追踪生成过程 | trace("") {} 嵌套,各阶段自动记录耗时 |
| 评估生成质量 | QualityEvaluator 接口,支持数量/关键词/精确匹配 |
| 批量测试用例 | BenchmarkRunner.runSuite() 统一执行 |
| 多次运行取平均 | 单用例内 repeat 多次迭代 |
| 可重复性 | temperature=0 固定随机性,固定测试数据 |
| CI 集成 | Gradle/Xcode 命令行执行,回归检测脚本 |
| 报告输出 | 控制台 + HTML + JSON 多格式 |
答案:可以实现。 这套 Trace Benchmark 框架天然支持任意流程的追踪和评估,只需:
- 在关键节点加
trace("") {}埋点 - 定义
BenchmarkCase测试用例 - 用
BenchmarkRunner批量执行 - 配置质量评估逻辑(可选)
核心优势:一套 API 同时搞定性能追踪 + 质量评估 + 批量测试 + 报告输出。