集成AgentKimi Code

用 Litefuse 追踪 Kimi Code

Kimi Code 是月之暗面(Moonshot AI)的终端编码 agent(kimi CLI,运行 Kimi-k2 系列模型)。Kimi Code 没有插件或 hook 机制,但它为每个会话写一份完整的事件日志——wire.jsonl。本集成是一个轮询采集器:一个零依赖(纯标准库)的单文件 Python 脚本,由 launchd(macOS)或 cron(Linux)每 30 秒运行一次,解析新增的 wire 事件,把 span 直接发往 Litefuse 的 OTLP 端点。不改 Kimi Code 源码、不装 SDK、不建虚拟环境。

采集器每个用户回合生成一条 trace:每次 LLM API 调用一个 generation、每次工具执行一个 tool observation、每次子 agent 委派一棵完整子树。

给 AI —— 自动安装

如果你此刻正在和 AI agent 对话(用 Kimi Code 本身也行),粘贴这句话,agent 会端到端完成安装:

Read https://litefuse.ai/SKILL.md and follow the instructions to install and configure Litefuse for Kimi Code.

skill 会向你索取 Litefuse API Key(没有账号会引导注册),然后就地完成全部配置。想手动一步步装,继续往下看。

采集内容

数据形式说明
用户 prompttrace input文本;含图片/视频时在 metadata 记 block 数
每次 LLM API 调用generation observationplan (n tools) #N / response / think #N,按模型行为命名;输出保留 thinking / text / toolCall 块结构
工具执行(输入+输出)tool observationtool: bash (grep) #N——名字带关键信息,完整参数在 input
子 agentAgent 工具)子树tool (1 subagent) #Nsubagent 容器 → 子 agent 自己的 plan/tool/response 步骤,从子 agent 自己的 wire.jsonl 解析;子 agent 用量汇入父 trace
Token 用量generation 的 usage_detailsAnthropic 风格 key(input / output / cache_read_input_tokens / cache_creation_input_tokens),由 Kimi 的 inputOther / output / inputCacheRead / inputCacheCreation 映射而来
模型名generation 的 model 属性kimi-code/kimi-for-coding——Litefuse 据此计算成本
首 token 延迟generation 的 completion_start_time来自 Kimi 的 llmFirstTokenLatencyMs
工具失败(isErrortool observation,level=ERROR带 status_message 预览
被取消的回合(turn.cancel根 span level=WARNINGstatus message 为 turn cancelled by user
被中断的回合根 span level=WARNINGLLM 调用从未完成的回合(如凭据过期、进程被杀)
会话分组trace session_idKimi Code 会话 id(session_<uuid>
用户身份trace user_id$LITEFUSE_USER_ID,回退到系统用户名
工作目录trace metadata(agent_cwd来自 Kimi Code 的会话索引

Trace 结构

一个含子 agent 委派的回合产出如下结构的 trace(真实示例):

Kimi Code — Turn 7                          (AGENT 根 span,携带 trace header)
├── plan (3 tools) #1                       (generation——usage、真实延迟、TTFT)
├── tool: read (overview.txt) #2
├── tool: read (events.jsonl) #3
├── tool: read (queue.jsonl) #4
├── plan (1 tool) #5
├── tool (1 subagent) #6                    (tool——父进程视角的委派)
│   └── subagent                            (AGENT 容器——从子 agent 的 wire.jsonl 解析)
│       ├── plan (1 tool) #1                (容器内编号从 #1 重计)
│       ├── tool: read (overview.txt) #2
│       ├── plan (1 tool) #3
│       ├── tool: bash (grep) #4
│       └── subagent response               (generation——子 agent 的最终回答)
└── response                                (generation——最终回答,结束回合)

设计说明:

  • 一个用户回合 = 一条 trace,只发完整回合。 采集器只发已结束的回合——最后一个 step 以 end_turn 收尾、回合被取消、或已被更新的 prompt 取代。进行中的回合原地保留、下次轮询重读,因此一个回合永远不会被劈成两条 trace,每个 span 恰好发送一次。
  • 诚实的时间语义。 Kimi 的 step.end 时间戳包含工具执行(它标记 agent step 的结束,不是 LLM 调用的结束)。采集器把 LLM 的真实时长重建为 step.begin + llmFirstTokenLatencyMs + llmStreamDurationMs,每个 tool span 则从它的 tool.call 事件计时到 tool.result 事件。权限审批的等待会表现为 generation 与 tool 之间的真实空隙——这正是实际发生的事。
  • 每个 agent 容器一个步骤计数器。 #N 是 generation 与 tool 共用的单一时间序列;每个子 agent 容器从 #1 重计。tool 的 agent_plan_step metadata 指向发起它的 generation 的 agent_step_index
  • 子 agent 子树。 Agent 工具的结果首部携带 agent_id: 标识,采集器据此定位 <session>/agents/agent-<n>/ 下子 agent 自己的 wire.jsonl。委派工具 span 包裹容器是有意设计:工具 span 时长 − 容器时长 = 委派的真实开销。解析是递归的——不过注意 Kimi Code 目前给子 agent 提供 Agent 工具,所以实践中不会出现超过两层 agent 的树。
  • 确定性 ID。 trace 与 span 的 ID 由会话 id、回合号和事件 UUID 派生——状态重置后重跑是 upsert 而不是重复。
  • 打平的 agent_* metadata。 所有集成字段以 agent_ 前缀放在 metadata 顶层(agent_step_indexagent_plan_stepagent_duration_ms……)——与其他 Litefuse agent 集成共用同一套 key,一个看板查询跨所有集成生效。
  • 回合内重建的 generation input。 wire.jsonl 不记录每次 API 调用的完整请求体,generation 的 input 由当前回合内的消息重建(metadata 标注 agent_input_scope: "turn");不含跨回合历史与 system prompt。

Trace 何时出现?

采集器每 30 秒轮询一次,且只上传已结束的回合,所以 trace 在回合给出最终回答后约 30 秒内出现——回合进行中什么都看不到。长回合要留意这一点(多子 agent 的委派可能跑好几分钟才有东西出现)。这是与 Pi 这类事件型集成的刻意差异——后者每个 observation 结束即发,而 Kimi Code 没有进程内扩展点可以做到这件事。

两个特例:中途被放弃的回合会在更新的 prompt 出现时立即发出(root 标 WARNING);闲置超过 30 分钟(可配置)的未完回合按”被中断”发出。

快速开始

前置条件

  • Python ≥ 3.8——任何 python3 都行,包括 macOS 自带的。采集器零第三方依赖:无 SDK、无虚拟环境、无 pip install。
  • 已安装 Kimi Code(存在 ~/.kimi-code/)。
  • 一个 https://litefuse.cloud 项目及其 public + secret key。

下载采集器脚本

mkdir -p ~/.kimi-code/hooks
curl -fsSL https://litefuse.ai/integrations/kimi-code/litefuse_hook.py \
  -o ~/.kimi-code/hooks/litefuse_hook.py
chmod +x ~/.kimi-code/hooks/litefuse_hook.py

同一 URL 也可以直接浏览源码——部署前欢迎先读一遍。

配置 ~/.kimi-code/litefuse.env

采集器在 launchd/cron 下以空环境运行,所以凭据放在专用 env 文件里,每次运行时读取(改完不需要重启任何东西):

cat > ~/.kimi-code/litefuse.env <<'EOF'
TRACE_TO_LITEFUSE=true
LITEFUSE_PUBLIC_KEY=pk-lf-xxx
LITEFUSE_SECRET_KEY=sk-lf-xxx
LITEFUSE_BASE_URL=https://litefuse.cloud
EOF
chmod 600 ~/.kimi-code/litefuse.env

注册定时任务

macOS(launchd)——每 30 秒运行:

cat > ~/Library/LaunchAgents/com.kimi.litefuse.plist <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key><string>com.kimi.litefuse</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/env</string>
        <string>python3</string>
        <string>$HOME/.kimi-code/hooks/litefuse_hook.py</string>
    </array>
    <key>StartInterval</key><integer>30</integer>
    <key>RunAtLoad</key><true/>
</dict>
</plist>
EOF
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.kimi.litefuse.plist

Linux(cron)——每分钟运行:

(crontab -l 2>/dev/null; echo "* * * * * python3 \$HOME/.kimi-code/hooks/litefuse_hook.py") | crontab -

验证

在 Kimi Code 里发一条消息,等回答完成再等一个轮询周期,然后看采集器日志:

tail -f ~/.kimi-code/state/litefuse_hook.log
# 预期出现:"Emitted 1 turn(s) in X.XXs -> https://litefuse.cloud"

在 Litefuse 打开项目——每个用户回合就是一条上文结构的 trace。

注意:首次运行时采集器会补齐所有既有会话,给每个历史回合各发一条 trace。想从干净状态开始的话,不要~/.kimi-code/state/litefuse_state.json(那会重发全部历史)——直接开一个新的 Kimi 会话即可。

从 v1 升级

旧版 hook 依赖 Langfuse Python SDK,并把每个回合压成 Kimi Response (step N) 式的合成 generation。v2 不需要 SDK,并遵循统一的 trace 结构:

  1. 用新脚本覆盖旧脚本(如有自定义先备份)。launchd/cron 条目可以保留——只要脚本路径不变。
  2. 保留 ~/.kimi-code/litefuse.env,原有 key 继续可用。LANGFUSE_* 名字仍作为 fallback,但 LITEFUSE_* 优先。
  3. v2 重命名了 observation(plan (n tools) #N / response 取代 Kimi Response (step N),小写 tool: bash (…) #N 取代 Tool: Bash #N),metadata 打平为 agent_* key——记得更新保存过的看板过滤器。
  4. v2 只发完整回合;如果 v1 留下了消费到一半的会话,v2 首次运行会从保存的 offset 自动重新同步。

环境变量

所有变量都放在 ~/.kimi-code/litefuse.env(或进程环境——env 文件不会覆盖已设置的变量)。LITEFUSE_* 优先;同名 LANGFUSE_* 作为生态兼容的 fallback。

变量必填说明
TRACE_TO_LITEFUSE必须为 true,否则采集器什么都不做。
LITEFUSE_PUBLIC_KEYLitefuse 项目 public key(pk-lf-...)。
LITEFUSE_SECRET_KEYLitefuse 项目 secret key(sk-lf-...)。
LITEFUSE_BASE_URL默认 https://litefuse.cloud。别名:LITEFUSE_HOST
LITEFUSE_TRACING_ENVIRONMENTtrace 的 Litefuse environment。默认 production;实验用 development
LITEFUSE_USER_ID覆盖 trace user_id。回退到系统用户名。
LITEFUSE_EXTRA_TARGETS额外目标的 JSON 数组([{"publicKey", "secretKey", "baseUrl", "environment"}]),双写多个 Litefuse 实例(如自托管 + cloud)。
KIMI_LITEFUSE_DEBUG设为 "true" 输出详细日志。
KIMI_LITEFUSE_MAX_CHARSspan input/output 截断阈值(字符数)。默认 1000000
KIMI_LITEFUSE_STALE_MINUTES未完回合判定为”被中断”的闲置分钟数。默认 30
KIMI_LITEFUSE_BATCH_BYTESOTLP 请求体分批上限。默认 800000;超限批次遇 HTTP 413 还会自动对半重试。
KIMI_LITEFUSE_STATE_DIR覆盖状态目录(~/.kimi-code/state)。主要用于测试。

Metadata 参考

所有集成字段都是带 agent_ 前缀的顶层 metadata key(跨 Litefuse agent 集成共用)。源数据中不存在的字段完全不出现,绝不用 null 占位。

Trace 根agent_turn_numberagent_session_idagent_cwdagent_modelagent_provideragent_transcript_pathagent_api_callsagent_tool_callsagent_stepsagent_duration_ms;prompt 含媒体时有 agent_image_blocks;被取消的回合有 agent_cancelled;截断标记(agent_prompt_truncated + _orig_len)。

Generationagent_turn_numberagent_step_indexagent_provideragent_stop_reasonagent_api_duration_msagent_time_to_first_token_msagent_stream_duration_msagent_tool_call_countagent_thinking_charsagent_step_uuidagent_input_scope、截断标记。

Toolagent_turn_numberagent_step_indexagent_plan_step(join 条件:tool.agent_plan_step == generation.agent_step_index)、agent_tool_name(原始大小写,如 Bash)、agent_tool_call_idagent_duration_msagent_is_error、委派时有 agent_subagent_id、截断标记。

Subagent 容器agent_subagent: trueagent_subagent_idagent_subagent_typeagent_subagent_status,以及该次运行的 agent_api_calls / agent_tool_calls / agent_steps / agent_duration_ms

工作原理

每次定时运行时脚本会:

  1. 加载 ~/.kimi-code/litefuse.env,然后从 ~/.kimi-code/session_index.jsonl 列出全部会话。
  2. 从每个会话的 agents/main/wire.jsonl 读取上次 offset 之后的新行(状态在 ~/.kimi-code/state/litefuse_state.json,以 sha256(session_id::wire_path) 为 key,文件锁保护)。
  3. turn.prompt 为边界把事件切分成回合,组装 step(step.begin / content.part / tool.call / tool.result / step.end / usage.record)。
  4. 只发已结束的回合(最终 end_turnturn.cancel、被更新的 prompt 取代、或闲置超过阈值);offset 停在任何进行中的回合之前,下次完整重读。
  5. Agent 工具的结果解析到子 agent 的 wire.jsonl,递归展开子 agent 子树。
  6. 把所有 span 以 OTLP/HTTP JSON 发到 <base_url>/api/public/otel/v1/traces(按端点请求体上限分批、413 对半重试、Basic 认证、10 秒超时)。trace header 随每个 span 携带。

采集器是 fail-open 的:任何意外错误只写 ~/.kimi-code/state/litefuse_hook.log 并以 0 退出,绝不影响 Kimi Code 本身。

排障

Litefuse 里看不到 trace。tail ~/.kimi-code/state/litefuse_hook.log。日志为空说明定时任务没在跑脚本——检查 launchctl print gui/$(id -u)/com.kimi.litefuse(或你的 crontab)。静默退出且无日志通常是 TRACE_TO_LITEFUSE 不为 true,或 ~/.kimi-code/litefuse.env 缺 key。出现 send failed: 则是 key 或网络问题。

最新一个回合不见了。 它多半还没结束——采集器只上传完整回合,然后等下一个 30 秒轮询。多子 agent 的回合可能要几分钟才出现。

某条 trace 的根标着 WARNING “interrupted”。 那个回合确实没有完成——Kimi 被杀、被重启,或 LLM 调用挂死(登录过期是典型:回合死在第一次调用上,你 /login 后重发,死掉的那次就被记录成一条独立的中断 trace)。这不是采集错误。

成本显示 0。 Litefuse 按模型名计算成本;在 Litefuse 项目的 Settings → Models 里添加与模型名匹配的价格条目(如 kimi-code/kimi-for-coding)。

手动测试采集器(使用 development environment,不污染生产数据):

LITEFUSE_TRACING_ENVIRONMENT="development" \
KIMI_LITEFUSE_DEBUG=true \
python3 ~/.kimi-code/hooks/litefuse_hook.py
tail ~/.kimi-code/state/litefuse_hook.log

相关资源

这个页面对你有帮助吗?