课程Apache Doris 黑客松自主安排进度 · 随时开始 · 无需报名

赛道 A · 任务 A4

Agent 链路 分析工具

AI Agent 输出的 JSON 结构可能随每次发布而变化。将其存入 VARIANT,像查询普通列一样访问。

  • 60–120 分钟
  • 进阶任务
  • 任意语言 · CLI、Notebook 或网页
  • 欢迎使用 AI 工具

遇到问题? 可在 #dev 提问,频道位于 Apache Doris Slack。维护者和其他参与者会提供帮助。

1

准备环境

了解构建目标、Doris 如何简化实现,并启动集群。

构建目标

Agent 的 JSON 结构复杂,也能直接查询。

LLM 调用、工具调用、错误和最终回答各有不同字段,新版本还会加入新字段。Doris 的 VARIANT 会自动将这些 JSON 路径转为有类型的列,让您通过普通 SQL 过滤、搜索和聚合,无需迁移 Schema。

构建链路分析工具,数据包含 1,000 个 AI Agent 会话,约 20,000 个事件:

  • ,提供 会话列表 ,显示事件数、错误数、Token 数和延迟;
  • 一个 会话时间线,点击会话即可逐步查看 Agent 行为;
  • 工具与模型统计,包括 p95 延迟、错误率和 Token 用量;
  • JSON 内部检索,找出所有提到 timeout 的工具错误。

随后回答: 13:00 部署 Agent v2 后,效果变好还是变差?

界面草图待构建的界面 · 线框图,非实际截图

草图位于代码面板顶部

Doris 为何适合这个项目

  • 无需预定义 Schema 的写入时建模。 VARIANT 为每条 JSON 路径推断类型,并将常用路径存为真正的列式子列,因此 payload['latency_ms'] 只需读取一列,无需逐份解析文档。

  • 新字段自动出现。 当 v2 事件新增 cost_usd时,下一次导入就会出现对应子列,无需执行 ALTER TABLE.

  • JSON 内部检索。 VARIANT 列的倒排索引支持对每条文本路径检索,语法为 MATCH_*.

代码面板:表定义中的索引语句

开始之前

  • docker pull apache/doris:all-in-one-4.1.3
  • docker run -d --name doris -p 9030:9030 -p 8030:8030 -p 8040:8040 apache/doris:all-in-one-4.1.3
  • docker exec -it doris mysql -uroot -h127.0.0.1 -P9030
  • curl -LO https://github.com/morningman/demo-env/releases/download/for-hackathon/doris-hackathon-glasgow-2026.zip && unzip doris-hackathon-glasgow-2026.zip && cd doris-hackathon-glasgow-2026
主机
127.0.0.1
端口
9030
用户
root无密码
数据库
hackathon

数据

hackathon.agent_events :每个 Agent 事件一行,事件正文存于 VARIANT 列:

数据表hackathon.agent_events · sql
CREATE TABLE agent_events (  session_id  VARCHAR(40)  NOT NULL,  ts          DATETIME(3)  NOT NULL,  event_id    BIGINT       NOT NULL,  event_type  VARCHAR(32)  NOT NULL,   -- user_message / llm_call / tool_call / error / final_answer  payload     VARIANT      NOT NULL,  INDEX idx_payload (payload) USING INVERTED PROPERTIES ("parser" = "english"))DUPLICATE KEY(session_id, ts)DISTRIBUTED BY HASH(session_id) BUCKETS 1PROPERTIES ("replication_num" = "1", "storage_format" = "V3");

示例 Payload,注意它们的结构差异:

示例 Payloadjson
{"text": "Why did checkout fail at 11:40?", "lang": "en", "agent_version": "v1"}{"model": "model-large", "usage": {"input_tokens": 812, "output_tokens": 96}, "latency_ms": 1430, "agent_version": "v1"}{"tool": "sql_query", "args": {"sql": "SELECT ..."}, "latency_ms": 37, "status": "ok", "agent_version": "v1"}{"tool": "http_get", "args": {"url": "..."}, "latency_ms": 3012, "status": "error", "agent_version": "v1", "error": {"type": "Timeout", "message": "read timeout after 3000 ms calling https://api.internal/orders"}}

13:00 或之后开始的会话运行 Agent v2,Payload 中标明 "agent_version": "v2",v2 的 LLM 调用还新增 cache_hit 标记。里程碑 5 会进一步导入表中从未出现过的新字段。

代码面板 → 建表:完整表定义

借助 AI 构建

推荐与 AI 编程助手协作完成任务。 Doris 4.x 的搜索与 AI 能力较新,可能晚于多数模型的训练数据。在让助手编写 SQL 前,请先提供正确上下文:

  1. 将下方 上下文提示词 粘贴给编程助手。

  2. 让助手阅读本页列出的 参考文档 以及入门包中的 AGENTS.md 文件。许多编程助手会自动读取该文件。

  3. 将 SQL 接入代码前,要求助手先在您的实际集群中运行每条语句。

  4. 还可以连接 Doris MCP Server ,参见 任务 A2,让助手自行检查 Schema 和测试查询。

上下文提示词粘贴给编程助手
I'm building an agent trace explorer on Apache Doris 4.1 for a hackathon.Connection: MySQL protocol, 127.0.0.1:9030, user root, empty password, database `hackathon`.Use a plain MySQL driver and raw SQL.Table `agent_events`: session_id, ts DATETIME(3), event_id, event_type(user_message / llm_call / tool_call / error / final_answer), payload VARIANT(inverted index, english parser). Payload shapes differ by event_type. Every payload hasagent_version: "v1" before 13:00, "v2" from 13:00; v2 llm_calls add cache_hit.Doris SQL rules:1. Read JSON paths as payload['a']['b']. CAST to a concrete type before comparing,   sorting or aggregating: CAST(payload['latency_ms'] AS DOUBLE).2. VARIANT cannot be a key, a sort key or a join key.3. Text search inside JSON: payload['error']['message'] MATCH_ANY 'timeout'. Never LIKE.4. Percentiles: percentile_approx(expr, 0.95).5. `SET describe_extend_variant_column = true; DESC agent_events;` lists inferred subcolumns.6. To insert JSON yourself, CAST the text: CAST('{"a": 1}' AS JSON).Build: sessions list, session timeline, tool/model stats, and JSON search.Run every SQL statement against the live cluster first.

AI 编程助手容易踩到的 Doris 问题

TrapWhat to do instead
未做类型转换就比较 VARIANT 路径CAST(payload['latency_ms'] AS INT);VARIANT 不能直接用作 Key 列或关联列
期望通过 DESC 列出 JSON 路径请先执行 SET describe_extend_variant_column = true; ,随后 DESC 会显示每个自动推断的子列及其类型
使用 LIKE '%term%' 进行文本检索col MATCH_ANY 'a b' (OR)、 MATCH_ALL (AND)、 MATCH_PHRASE 'a b' ,这些运算符会使用倒排索引
使用 ORM建议使用普通 MySQL 驱动和原生 SQL,ORM 可能生成 Doris 不支持的语句
2

开始构建

6 个里程碑, M0 → M5。代码面板会跟随您阅读的步骤。

  1. 里程碑 010 分钟

    导入并检查数据

    在入门包目录中执行:

    M0 · 导入bash
    docker exec -i doris mysql -uroot -h127.0.0.1 -P9030 < seed/a4_agent_events.sql

    随后在 SQL Shell 中执行:

    M0 · 检查sql
    USE hackathon;SET describe_extend_variant_column = true;DESC agent_events;     -- see the subcolumns Doris inferred: payload.tool, payload.usage.input_tokens, ...
    检查点

    导入结果应显示 1,000 个会话和 20,401 个事件; DESC 会列出约 20 条 payload.* 路径,每条均有自动推断的类型。

  2. 里程碑 115 分钟

    查询 JSON 路径

    M1 · 查询 JSON 路径sql
    SELECT CAST(payload['tool'] AS STRING) AS tool, COUNT(*) AS callsFROM agent_eventsWHERE event_type = 'tool_call'GROUP BY toolORDER BY calls DESC;
    检查点

    共有五种工具, sql_query 调用最多,共 3,506 次。

  3. 里程碑 215 分钟

    聚合自动推断的子列

    M2 · 聚合自动推断的子列sql
    SELECT CAST(payload['tool'] AS STRING) AS tool,       COUNT(*) AS calls,       percentile_approx(CAST(payload['latency_ms'] AS DOUBLE), 0.95) AS p95_ms,       SUM(CASE WHEN CAST(payload['status'] AS STRING) = 'error' THEN 1 ELSE 0 END) AS errorsFROM agent_eventsWHERE event_type = 'tool_call'GROUP BY toolORDER BY p95_ms DESC;
    检查点

    python_exec 的 p95 最高,约 2.1 秒; http_get 失败次数最多,共 425 次。

  4. 里程碑 310 分钟

    检索 JSON 内部文本

    M3 · 检索 JSON 内部文本sql
    SELECT session_id, ts, CAST(payload['error']['message'] AS STRING) AS error_messageFROM agent_eventsWHERE payload['error']['message'] MATCH_ANY 'timeout'ORDER BY tsLIMIT 20;
    检查点

    共有 398 个事件提到 timeout。按小时统计,这是判断 v2 影响的第一条线索。

  5. 里程碑 420 分钟

    会话时间线

    M4 · 会话时间线sql
    SELECT ts, event_type,       CAST(payload['tool'] AS STRING)      AS tool,       CAST(payload['status'] AS STRING)    AS status,       CAST(payload['latency_ms'] AS INT)   AS latency_ms,       CAST(payload['text'] AS STRING)      AS textFROM agent_eventsWHERE session_id = 's-0042'ORDER BY ts;

    围绕这些查询构建界面:会话列表 → 时间线 → 统计。

    检查点

    会话 s-0042 包含 25 个事件:提问、LLM 与工具调用,其中一次 sql_query调用失败后重试,最后生成回答。

  6. 里程碑 510 分钟

    观察 Schema 演进

    M5 · 导入结构变化批次bash
    docker exec -i doris mysql -uroot -h127.0.0.1 -P9030 < a4/drift_batch.sql   # events with new fields
    M5 · 查询新字段sql
    SELECT CAST(payload['agent_version'] AS STRING) AS version,       COUNT(*) AS llm_calls,       ROUND(SUM(CAST(payload['cost_usd'] AS DOUBLE)), 2) AS cost_usdFROM agent_eventsWHERE event_type = 'llm_call'GROUP BY versionORDER BY version;

    再次运行 DESC agent_events ,新路径已经出现,全程没有执行 ALTER TABLE 。

    检查点

    还会出现第三个版本, v2.1,只有它的 LLM 调用包含 cost_usd,而 DESC 现在会列出 payload.cost_usd 和 payload.retries.

3

完成并提交

完成清单,展示成果,领取徽章。

完成标准

您的检查清单

提交并领取徽章

参与 → 提交 → 领取徽章。

  1. 请将成果放到以 您的 GitHub ID命名的目录中:包括代码和 README,说明项目功能、运行方式、使用的 Doris 能力,并附一张截图或 GIF。

  2. 提交 Pull Request ,将成果添加到 morningman/demo-env ,目录为 doris-hackathon-glasgow-2026/<your-github-id>/。可以先 Fork 后推送,或使用 GitHub 的 Add file → Upload files(添加文件 → 上传文件)。无需填写其他内容。

  3. 分享成果 到 #dev ( Apache Doris Slack):附上 Pull Request 或仓库链接,以及截图或简短演示。问题交流、成果提交和徽章领取都在该频道处理。

每位参与任务的开发者都可获得 Apache Doris 贡献者徽章,无需先有 PR 合入 Doris。任务没有截止日期,可按自己的节奏完成。可以组队,也可独立参与;请将每位成员的 GitHub ID 写入 README.

进阶目标

  • 使用自己的链路。 导出您使用的 AI 编程助手本地会话日志(JSONL),导入 Doris,每行一个 CAST('…' AS JSON) 。数据存储在本地 Doris 实例中。

  • Schema Template。 通过 VARIANT<'latency_ms': INT, 'tool': STRING> 在表的副本中固定热点路径,比较 DESC 输出和查询行为。请使用 INSERT … SELECT …, CAST(payload AS JSON)填充数据,普通 VARIANT 不能直接转换为带模板的 VARIANT。

  • 让助手探索数据。 连接 Doris MCP Server,参见任务 A2,让助手找出表现最差的会话。

  • 使用 SQL 对错误分类 ,需自行提供 API Key: AI_CLASSIFY(CAST(payload['error']['message'] AS STRING), ['timeout', 'auth', 'bad input', 'other'])。参阅 LLM SQL 函数.

故障排查与参考资料

SymptomFix
docker: command not found 出现在 macOS 上启动 Docker Desktop;若已运行,请为 CLI 创建链接: sudo ln -s /Applications/Docker.app/Contents/Resources/bin/docker /usr/local/bin/docker
error getting credentials 出现在拉取镜像时请移除 credsStore 字段,所在文件为 ~/.docker/config.json (仅适用于本地开发)
port is already allocated9030、8030 或 8040 已被其他程序占用,常见原因是另一个 Doris 实例。先查看运行中的容器(docker ps),再停止冲突的服务;也可映射其他主机端口,例如 -p 19030:9030,然后连接 19030
The container name "/doris" is already in use此前已启动过该容器,可执行: docker start doris。如需从头开始,请执行 docker rm -f doris ,此操作会删除容器数据
容器退出,或始终未变为 (healthy)请查看 docker logs doris。通常是内存不足,请在 Docker Desktop 的 Settings → Resources 中分配至少 6 GB。Apple Silicon 设备不要添加 --platform linux/amd64
permission denied: ./doris.sh解压工具可能丢失了可执行权限,请执行: chmod +x doris.sh,或运行 bash doris.sh start
Current database is not set请先执行 USE hackathon; ,或在连接时使用 -Dhackathon
score() function requires WHERE clause with MATCH function, ORDER BY and LIMIT请添加 MATCH_* 谓词、 ORDER BY score() DESC 以及 LIMIT,并保持 score() 不被其他表达式包裹,参见前文说明
超过 10 分钟仍未解决可在 #dev 频道提问,位于 Apache Doris Slack

参考资料

VARIANT 数据类型VARIANT SQL 参考全文检索LLM SQL 函数

Apache Doris 黑客松

全部任务

返回课程
  1. A160–120 分钟混合检索应用查看说明
  2. A245–90 分钟通过 MCP 询问 Doris查看说明
  3. A360–120 分钟日志检索工具查看说明
  4. A460–120 分钟Agent 链路分析工具当前步骤
  5. B30–60 分钟赛道 B · 从文档到演示查看说明