跳转至

产品分析

服务器负责每个已连接客户端的分析交付、选择退出和身份识别。客户端不加载 PostHog 浏览器 SDK。客户端使用事件需要经过身份验证的连接,因此未连接就访问托管应用不计为产品使用。

安装与所有者

distinct_id 遵循每个版本一直使用的规则:优先使用 Codex 工作区的哈希值,其次使用 Claude 机器 id,再次使用安装的匿名 id。当有人登录时它可能会改变,而且一个 Codex Team 共享同一个 id,但保留这一规则意味着 PostHog 的图表和历史记录永远不会中断。不要更改它;应改为添加一个新字段。

当服务器能够保存其状态时,每个事件还会携带 installId:即状态目录中随机 id 的哈希值,该值在安装期间永远不会改变。如果该文件无法写入,事件仍会像以前一样在 distinct_id 下发出。用它来统计安装数。安装归属于谁是一个独立的事实,通过 install.owner_observed 发送。所有者在我们自己的存储中于查询时解析,因此规则可以更改并适用于所有历史数据。

所有者来源,按强度从高到低排列:T3 Connect,然后是 OpenAI 和 Claude 个人 id,最后是客户端设备。服务器只报告它自己能读取到的信息:关联的 Connect 账户和提供商登录信息。连接的客户端报告其已登录的 Connect 账户及其设备,这将从同一部手机、浏览器或桌面打开的所有环境关联起来。使用 OpenAI 的 user_id 声明,而不是 Codex 的 account_id(即整个 Team 共享的 ChatGPT 工作区)或令牌的 sub(每种登录方式一个)。两个 Connect 账户永远不会是同一个人,无论它们共享哪些较弱的 id。

每个 id 都在两侧使用同一个辅助函数进行 SHA-256 哈希处理,因此 Connect 账户在客户端和服务器上的哈希结果相同。服务器只接受来自客户端的哈希值。

归因边界

客户端维度归属于事件的 WebSocket 连接。服务器全局的“当前客户端”会错误归因同时进行的 Web、桌面和移动端使用。提供商执行有自己的事件,因为一个轮次可能比发起请求的连接存活得更久。

保持客户端和服务器维度分开。桌面主机可以为手机或远程浏览器提供服务,而直接连接可以跨越网络。较旧的客户端会省略元数据。缺失的客户端值必须保持未知状态,而不是从服务器属性中回填。遗留的 clientType 属性描述服务器的运行方式;对于连接的客户端请使用 surface。

解读事件

使用 client.turn.requested 进行活跃使用报告。没有连接事件,因为 T3 Connect 会话每小时过期,每次重新连接都会再次计数。如果一条命令的 id 已被接受,那么它就是重试,因此不会再次记录任何内容。同一身份在一个时间段内可能出现在多个客户端组中;将这些组相加会重复计算用户。

提供商的发送次数和完成次数不必匹配。provider.turn.completed 表示一个提供商轮次,segment 说明是什么启动了它:运行的首次尝试(initial)、steering_restart、提供商的 continuation(例如 Codex 目标轮次)或 native_child 子代理。createdBy、creationSource、scheduled 和 subagent 描述运行起始消息,childKind 将原生子代理与 T3 管理的子线程区分开来。使用此事件进行逐轮次测量,而不是用于统计请求数。

provider.request.completed 表示一次运行,在该运行所执行的服务器进程中结束时记录。它每个根轮次只添加一次,因此续接、转向和重放的提供商事件不会增加行。requestKind: "user" 统计人们请求的内容。原生子代理轮次在根轮次之外单独汇总(childUsageStatus、childInputTokens);T3 管理的子线程将其自己的请求报告为 t3_child。在该运行结束时仍在运行的子代理不会在之后被添加,摘要会设置 childrenRunning。服务器重启会丢失正在进行的运行的摘要。重启后继续的运行通过 restartContinuation 和 lifecycleObserved: false 报告其自身的使用情况;它无法恢复原始请求的计数或类型。提供商会话从未打开的运行没有摘要,被提供商拒绝的启动会报告 providerTurns: 0。在转向重启启动期间到达的 Stop 会结束运行且不生成摘要。收集是尽力而为的,不会扫描或回填提供商历史。

计数涵盖主代理。otherInputTokens 和 otherOutputTokens 是提供商自己的账本在该轮次中记录的主代理之外的用量:即 Claude 的按进程 modelUsage 增长,涵盖原生子代理、压缩和辅助调用。它们需要来自同一进程的基线,因此在基线未知或账本倒退时保持缺失,而在轮次之间结束的后台工作会计入下一个轮次。Claude 子代理没有自己的轮次,因此这永远不会与子轮次重叠。

model、effort 和 serviceTier 是运行所选的值。serviceTier 为 standard、flex、fast 或 ultrafast,来自 Codex 的层级选项或 Claude 的快速模式;当选择未设置时该字段缺失。observedModel 和 mixedModels 仅在提供商报告了被计入工作的模型时出现(Codex 线程设置和重路由、Claude 根消息、OpenCode 步骤)。没有 reportVersion 的 mixedModels: false 从未被检查。模型标签来自捆绑的模型清单以及 Cursor 和 Grok 目录,也涵盖路由 id 如 anthropic/claude-opus-5-5;effort 值来自封闭列表,因此用户配置的名称不会出现。

状态和计数器回答不同的问题。usageReported: false 表示适配器未附加任何用量;如果一个 harness 的每一行都显示该值,那么它是不受支持的,而不是空闲的。partial 保留无法确定整个轮次总计的有效计数,例如未附带报告就结束的 OpenCode 步骤、OpenCode 流重新连接或中断的片段。显式的零会被发送,未知计数保持缺失。localCommand 标记提供商本地的命令,例如 Claude 的 /compact,其结果计数器不是模型工作。推理 token 是输出 token 的子集。

基于这些事件构建的图表应显示“每次实测提供方完成的输出Token数”,按匹配的提供方、观测到的模型、努力程度、交互模式和终结状态进行对比,并按工具链、来源和状态展示符合条件与实测的计数,以便未知模型和不支持的适配器保留在分母中。输出/输入比率应使用合计总数相除;对每轮比率求平均值会让小输入轮次占据主导。没有 reportVersion 的行将其缺失字段保持为未知;缺失的来源绝不被视为个人。

feature.used 统计启动某个功能的 WebSocket 请求。RPC 在请求成功后由 RPC 授权中间件观测;分发的命令由分发处理器记录,该处理器能够区分重试。功能映射对方法和命令进行白名单管理,并且仅从封闭的合约枚举中获取变体,因此路径、ID 和文本永远不会进入分析数据。共享线程的访客没有 WebSocket 连接,因此访客共享服务自行记录他们的加入和消息,不带有 surface 字段。

Agent 工具事件报告驱动类型,绝不报告实例 ID:用户会为实例命名,因此实例 ID 可能识别出账户或雇主。提供方维度仅在模型是供应商目录中的非自定义条目时才报告该模型。OpenCode、Pi 和 ACP Agent 从用户配置(如本地 Ollama 标签)中列出模型,因此这些模型不会被报告。交接设置来自工具参数中的封闭枚举和布尔值;prompt、标题和 ID 永远不会被读取。线程 ID 仅用于查找两侧的线程,永远不会离开服务器,这也是工具事件不携带每线程序号的原因。对多个线程的交接(如 create_threads)会为每个目标记录一次 mcp.tool.invoked,每个事件都重复包含该调用的结果和耗时,因此事件计数不等于调用次数。

交付

服务器将批次发送到位于 ingest.t3.codes 的摄取端点,该端点会归档每个事件并将其中一部分转发给 PostHog。发送可能在端点已存储批次后失败,因此每次重试都是一份副本。交付在记录每个事件时为其生成 uuid(端点会拒绝没有 uuid 的事件),在发送失败后执行退避,并在几次尝试后丢弃批次。如果没有这些限制,某个卡住的批次会连续数天被每秒发送一次。

收集边界

将分析数据负载限制为产品元数据和标准化测量值。不要发送 prompt、身份验证材料、原始提供方数据负载、用户指定的设备名称或对话标识符。客户端元数据为尽力而为;无效值不得拒绝连接。PostHog 用户画像保持禁用。

开发运行器服务器和 CI 归档冒烟测试会关闭遥测,这也会停止中继追踪,因为每个都会计为一次新安装。设置 T3CODE_TELEMETRY_ENABLED=true 以从开发服务器测试分析或中继追踪。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 t3/t3code