# dsh-llm-call-inspector [English](README.md) | 中文 [![CI](https://github.com/striveh/dsh-llm-call-inspector/actions/workflows/ci.yml/badge.svg)](https://github.com/striveh/dsh-llm-call-inspector/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) 一个面向 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) Web 的本地、会话级 LLM 请求/响应检查器。它在聊天和“轨迹”旁新增独立的 **LLM 调用** 页面,让开发者查看每个带会话标识的标准化 `llm/stream` 调用,同时不改变模型收到的内容,也不改变调用方收到的结果。 这是社区插件,并非 DeepSeek Harness 官方发布。版本 `0.2.1` 仅支持 DeepSeek Harness `0.1.2-alpha.2`。仍使用 `0.1.0-rc.8`、`0.1.1-rc.1` 或 `0.1.1-rc.2` 的用户应锁定插件版本 `v0.2.0`。 ![LLM 调用 API 对照:在本次 DSH 捕获调用旁展示手动选择的 Anthropic 结构参考](docs/llm-calls.png) > [!WARNING] > 请求与响应正文可能包含提示词、源码、工具参数、工具结果、个人数据,或嵌入内容中的秘密。安装本插件后,Host 默认开始采集正文。请先阅读[隐私与数据处理](docs/privacy.md),再用于敏感会话。 ## 能看到什么 - 当前 DSH 会话的调用列表,最新调用在前。 - Provider、模型、用途、状态、开始时间、耗时、chunk 数量与正文采集状态。 - 搜索,以及按状态、用途筛选。 - 主从详情布局;请求、响应与 API 对照三个页签;可展开 JSON 与复制操作。 - 切换到其他页面再返回时,按会话恢复选中的调用、搜索、筛选、详情页签、逐调用手动 API 参考和列表/正文滚动位置。 - 根据本次调用的 pi-ai 协议证据提供左右语义对照,同时提供明确标注的手动参考与精确 `deepseek-official` 路由兜底,并与真正观察到的 DSH 标准化数据严格区分。 - 实时轮询、手动刷新、仅清空当前会话、错误/空状态、键盘焦点、响应式布局和中英文界面。 - 只要调用带有 `sessionId`,就能覆盖 Assistant、压缩、会话标题和其他标准化用途。 标准化请求只允许采集以下字段: `provider`、`model`、`reasoningEffort`、`messages`、`system`、`tools`、`temperature`、`maxTokens`、`stop`、`sessionId` 和 `purpose`。 响应正文是 `llm/stream` 边界观察到的有序 DSH `StreamChunk` 数组。观察器只向下游委托一次,按原顺序交还原始 chunk 对象,并原样保留下游抛错。完整 chunk 采集也会保留 JSON 兼容的适配器回放元数据,包括适配器产生的 `finish.replayState`。不依赖正文是否保留,Host 只有在终态 replay response 同时给出 `kind: pi-ai`、`version: 2`、有界的小写连字符 API id,且 provider/model 与本次调用一致时,才会暴露窄化、无正文的 `apiEvidence`。缺少证据保持 `absent`;格式异常、不匹配、getter 读取失败或冲突的归因会成为 `rejected`/`conflicted`,不会被接受为协议事实。 当前 DSH 内置图片块包含附件引用元数据,包括不透明附件 id、媒体类型、字节数、尺寸和可选显示名;插件会把这份引用作为 `messages` 的一部分采集。插件不会主动加载附件字节,也观察不到供应商侧的 base64 网络请求体。但标准化 `messages` 是整体复制的:如果某个扩展在自定义消息块里嵌入字节、base64、凭证或其他私有字段,这些内容也会进入采集边界。 ### 返回页面时如何恢复 从 **LLM 调用** 切换到聊天、“轨迹”或其他会话页面,不会丢弃当前检查上下文。DSH 会话级 view store 只保存交互状态:选中的调用 id、搜索与筛选、当前详情页签、逐调用手动 API 参考、列表滚动位置,以及最多 300 个近期“调用/页签”的正文滚动位置;权威摘要中已经不存在的调用,其滚动位置和手动选择都会被及时修剪。另有一个由插件 apply 生命周期持有、按最近最少使用淘汰的浏览器内存缓存,最多保留 4 个近期会话的最新无正文摘要和一个已选详情。因此缓存仍新鲜时,返回页面可以先直接绘制,不会强制立即再发 RPC;正常轮询会在间隔到期时继续,已过期的缓存可能在恢复显示后立即刷新。 这两层都不会使用 `localStorage`、`sessionStorage`、IndexedDB 或其他浏览器持久化存储。插件的 apply 生命周期结束时,client cache 会被清空,也可能更早淘汰较旧会话。Host 内存仍是权威保留记录。 ### API 对照 API 对照页签展示的是**语义结构投影**,不是网络抓包。左侧是实际观察到的 DSH 标准化请求与响应 chunks;右侧是根据这些标准化字段和所选 API 协议推导出的 HTTP JSON、SDK 参数或 command input 参考。无法观察适配器最终目的地时,界面只展示 endpoint 模板。 对于成功结束的 pi-ai 调用,首选归因是该次调用经过校验的 replay-v2 `apiEvidence`。协议注册表会投影以下八种由适配器报告的协议: - `openai-completions`; - `openai-responses`; - `azure-openai-responses`; - `anthropic-messages`; - `google-generative-ai`; - `google-vertex`; - `bedrock-converse-stream`; - `mistral-conversations`。 界面按主流结构家族展示,而不是按 provider route 名展示:OpenAI-compatible Chat Completions、OpenAI/Azure Responses、Anthropic Messages、Gemini Developer API/Vertex AI GenerateContent、Amazon Bedrock ConverseStream 与 Mistral Chat Completions。 Inspector 能识别适配器报告的 `openai-codex-responses` 和 `pi-messages`,但不会为它们编造投影;未知的已报告协议也会明确显示为不支持。没有可信调用级证据时,只有大小写完全匹配的 `deepseek-official` 路由可以退回到带版本边界的 DeepSeek Harness `0.1.2-alpha.2` 原生适配器参考;一旦存在有效的适配器报告证据,证据优先于该 route 兜底。 如果没有证据,或者已报告协议还没有可信投影,用户可以选择明确标注的手动结构参考。该选择只作为逐调用、会话级 view state 保存,并可跨 view 重挂载恢复;它既不改变采集事实,也不声称本次调用实际使用了该协议。除精确 DeepSeek 兜底外,route 名、模型名、前缀和 gateway 品牌都不会被猜测成协议证据。 该投影不会读取 HTTP headers 或 API key,不保留原始 SSE 帧,不能证明运行时实际适配器身份,不会复现适配器兼容默认值,也看不到隐藏的网络重试。它不会回放或发送供应商请求,因此打开页签、切换页面、选择手动参考或复制结构参考都不会新增 LLM 调用或产生额外供应商费用。只有无需适配器私有 id、签名、兼容元数据或附件字节就能物化的历史,才会生成直接请求 JSON;复杂 assistant/system/tool/reasoning 历史、图片/文件和未知扩展会明确显示不可用。模型截断后的 token 上限、Azure deployment 映射等适配器最终值使用显式 `{$unobserved, dshInput}` 标记;该标记不是可发送的 API 值。 ## 能力边界 本插件检查的是 **DSH 标准化 LLM 边界**,不是供应商网络代理。 它不会采集: - 供应商原生 HTTP 请求体或响应体; - HTTP headers、顶层 API key、终止信号或请求对象上未声明的适配器私有字段; - 原始 SSE 帧、适配器内部隐藏的网络重试或供应商侧处理; - 适配器最终解析出的 endpoint,或一次标准化调用背后的物理 HTTP 尝试次数; - 没有 `sessionId` 的 `llm/stream` 调用; - 供应商没有作为标准化 chunk 返回的隐藏推理。 排除顶层字段不等于内容脱敏。粘贴到提示词里的密钥、工具结果里返回的密钥,或插件自定义消息块内嵌的字段,仍可能被采集。 响应 chunks 会被完整保留,因此 `finish.replayState` 内的适配器私有 JSON 也可能被采集,必须按敏感内容处理。单独暴露的 `apiEvidence` 只是从 replay 元数据中提取的窄化协议归因,不是 HTTP 请求或响应字节的证据。 ## 为什么做独立页面,而不直接融合“轨迹” DeepSeek Harness `0.1.2-alpha.2` 对外提供的增量 UI 扩展点是 `conversation.view`。内置“轨迹”使用了这个扩展点,但没有公开稳定的内部行或面板扩展接口。早期插件 `v0.2.0` 面向 DSH `0.1.0-rc.8`、`0.1.1-rc.1` 与 `0.1.1-rc.2` 时也采用了相邻页面方案。 两者回答的问题也不同: - **轨迹**解释持久化的会话故事:用户、Assistant、工具事件,步骤、时序、用量与结局。 - **LLM 调用**展示每个标准化调用实例:该次调用中被采集的完整请求快照与有序响应 chunks。 因此,本插件在 order 20 注册相邻页面,不复制、不修改,也不依赖“轨迹”内部实现。将来如果“轨迹”提供稳定的跳转或内部扩展接口,可以在不改变采集所有权的前提下把两个页面连接起来。 ## 架构 ```text 带 sessionId 的 GenerateOptions | v llm/stream 透明观察器 | v 有界、按会话隔离的内存 | v Connection RPC /dsh-llm-call-inspector (DSH 认证浏览器通道) | v conversation.view / LLM 调用 ``` 一个包同时包含两个运行面: - **Host** 注入 `llm` 和 `connection`,在 `llm/stream` 前置透明观察器,持有有界内存,把经过校验的调用级 pi-ai replay-v2 协议归因提取为无正文 `apiEvidence`,并注册一个 Connection RPC channel。在 DSH `0.1.2-alpha.2` 中,该 channel 通过 Connection 的 Host/Origin 防线与浏览器 token/cookie 认证访问。 - **Client** 使用 DSH 平台包 `@deepseek-ai/dsh-client-store` 保存会话级交互状态,并使用 `@deepseek-ai/dsh-client-ui-renderer` 提供的 slot runtime;Cordis 运行时注入仍是 `connection`、`slots` 和 `locale`。它注册一个 `conversation.view`,轮询无正文摘要,只为当前选中调用读取完整正文;最多 4 个会话的 apply 生命周期缓存恢复最近摘要/详情,但不使用浏览器持久化存储。 - **Bundle** 声明 `dsh.bundle.patch` 和 Web client 导出,因此 `dsh plugin` 能通过官方 profile 机制加载两个运行面。 Host 存储不会把采集正文写入磁盘。view 卸载后,有界 client cache 可能在浏览器内存中临时保留最近选中的详情,但不会写入浏览器持久化存储。在 UI 中清空当前会话、达到单会话/会话总数/全局正文预算被淘汰、插件重载或 DSH 重启,都会让 Host 中的相关记录消失。 插件不新增网络 listener,也没有导出目标;但它不会额外强制仅 loopback。如果 DSH Web 配置允许某个可信的非 loopback host,且对应浏览器会话通过 DSH 认证,该浏览器同样可以访问此 channel 及其采集正文。除非确实需要并已妥善保护远程浏览器访问,敏感检查场景应让 DSH Web 保持仅 loopback 可访问。 ## 安装 前置条件: - DeepSeek Harness `0.1.2-alpha.2`(DSH `0.1.0-rc.8`、`0.1.1-rc.1` 或 `0.1.1-rc.2` 请改用插件 `v0.2.0`); - Node.js `22.19` 或 package engine 支持的更新版本; - `PATH` 中有 pnpm,这是 `dsh plugin` 的官方要求。 把 GitHub 仓库安装进 Web profile: ```sh dsh plugin --profile web add github:striveh/dsh-llm-call-inspector dsh --profile web --dump-config dsh web ``` 新增、更新或移除 bundle 后,需要重启正在运行的 Web profile。配置展开结果中应出现 `# == dsh-llm-call-inspector` 层。 正式使用建议锁定已经审阅的 commit: ```sh dsh plugin --profile web add github:striveh/dsh-llm-call-inspector# ``` 仓库提交了构建好的 `lib/`,并且有意不提供 `prepare` 或安装期生命周期脚本;从 GitHub 安装不需要授予 pnpm `allowBuilds` 权限。 ## 配置 Bundle 默认值如下: | 字段 | 默认值 | 含义 | |---|---:|---| | `captureBodies` | `true` | 采集白名单请求字段与有序响应 chunks。设为 `false` 时仍保留调用元数据,但两个正文都会标记为 omitted。 | | `maxCallsPerSession` | `100` | 单个会话最多保留的调用数;先淘汰最旧调用。 | | `maxSessions` | `32` | 最多保留的会话桶数量;按 LRU 淘汰。 | | `maxRequestBytes` | `524288` | 单个请求快照序列化为 JSON 后的 UTF-8 字节上限。 | | `maxResponseBytes` | `1048576` | 单个响应 chunk 数组序列化为 JSON 后的 UTF-8 字节上限。 | | `maxTotalBodyBytes` | `67108864` | 跨全部会话保留的 captured JSON 全局预算;先淘汰已结束调用,再淘汰运行中调用,同类按创建时间从旧到新。 | | `pollIntervalMs` | `750` | Host 告知当前浏览器页面的轮询间隔。 | 如需覆盖,在 `$DSH_HOME/profiles/web/cordis.patch.yml` 中添加一个更晚生效的配置行。DSH patch 会替换目标行的完整 `config`,所以下例重述全部字段: ```yaml - id: dsh-llm-call-inspector config: captureBodies: true maxCallsPerSession: 50 maxSessions: 16 maxRequestBytes: 262144 maxResponseBytes: 524288 maxTotalBodyBytes: 33554432 pollIntervalMs: 1000 ``` 正文超过上限时,插件会丢弃整个正文,并以 `size-limit` 明确标识实测字节数。正文包含不可 JSON 化的值,或关闭正文采集时,也会得到明确的 omission 状态;元数据和 chunk 数量仍然可见。 ### 仅元数据模式 如果只需要 Provider/模型、状态、耗时与 chunk 数量,可以设置 `captureBodies: false`: ```yaml - id: dsh-llm-call-inspector config: captureBodies: false maxCallsPerSession: 100 maxSessions: 32 maxRequestBytes: 524288 maxResponseBytes: 1048576 maxTotalBodyBytes: 67108864 pollIntervalMs: 750 ``` 修改配置会重载插件,并丢弃当时的内存记录。 ## 禁用或卸载 如果想保留依赖但禁用插件,请在 profile 的后续 patch 中添加以下内容并重启 Web: ```yaml - id: dsh-llm-call-inspector disabled: true ``` 如果要移除依赖及其 bundle 层: ```sh dsh plugin --profile web remove dsh-llm-call-inspector ``` 移除后重启 profile。禁用或卸载不会产生可恢复文件:本插件从未持久化这些内存记录。 ## 现有方案怎么选 这个生态变化很快;选择前请重新核对每个链接项目的最新文档。 | 方案 | 主要数据与界面 | 更适合的场景 | |---|---|---| | 内置[轨迹](https://github.com/deepseek-ai/deepseek-harness) | 原生 UI 中的持久化会话事件 | 需要理解 Agent/会话叙事、工具流、用量与结局,而不是调用正文。 | | [dsh-devtools](https://github.com/izz-BLUE/dsh-devtools) | 原生 Web 页签中的 metadata-first 运行剖析;有意不采集提示词与工具正文 | 需要性能和运行诊断,同时希望内容隐私面更小。 | | [dsh-llm-inspector](https://github.com/cdxiaodong/dsh-llm-inspector) | 推理控制、流量统计、`think` 工作流与可选审计文件;项目文档未描述原生请求详情 UI | 明确需要行为改写或文件审计能力。 | | [dsh-plugin-langfuse](https://github.com/linyp/dsh-plugin-langfuse) | 把会话事件作为 OpenTelemetry traces 导出到 Langfuse | 需要集中式、跨会话可观测性,并愿意配置外部上传。 | | **dsh-llm-call-inspector** | 本地原生主从界面,查看标准化调用正文;仅保留在有界进程内存 | 需要本地 trace、debug、教学或研究检查。 | GitHub topic 只是发现元数据,不是安全审核,也不代表官方背书。 ## 开发 ```sh pnpm install --frozen-lockfile pnpm verify pnpm pack --dry-run ``` `pnpm verify` 会执行 Host/Client 类型检查、自动测试、干净构建和只读 package 校验。package 校验覆盖公开 exports、已提交构建产物、Web loader 标识、bundle patch、DSH client 声明、文档安装命令,以及安装期生命周期脚本必须缺失。 构建后测试本地 checkout: ```sh dsh plugin --profile web add . dsh --profile web --dump-config dsh web ``` 改动约束见 [CONTRIBUTING.md](CONTRIBUTING.md),私下报告漏洞的方式见 [SECURITY.md](SECURITY.md)。 ## 兼容性 DeepSeek Harness 仍是 developer preview,不承诺预发布版本之间的插件兼容性。这里采用有意收窄、精确匹配的兼容矩阵: | 插件版本 | 支持的 DSH 版本 | |---|---| | `v0.2.1` | 仅 `0.1.2-alpha.2` | | `v0.2.0` | `0.1.0-rc.8`、`0.1.1-rc.1` 与 `0.1.1-rc.2` | DSH `0.1.2-alpha.2` 把 JSON 快照迁移到 `@deepseek-ai/dsh-util-values`,把会话 view store 迁移到 `@deepseek-ai/dsh-client-store`,并把 slot runtime 所有权迁移到 `@deepseek-ai/dsh-client-ui-renderer`;Connection handler 与浏览器认证契约也发生了变化。版本 `0.2.1` 按这些 alpha.2 接口实现,并使用 inspector RPC schema v3,因此不声明兼容早期 rc 版本。请锁定与 DSH 预发布版本匹配的插件版本。 2026-08-24,`0.2.0` release candidate 通过了相互隔离的 rc.8、rc.1、rc.2 本地 lane:每条都断言 69 个 DSH 包版本一致,并通过 8 个测试文件 / 100 项测试、Host + Client typecheck、构建、12 文件 / 6 client injection package verifier 与 dry-run pack。全新的 rc.2 Web profile 使用纯离线 fixture,在同一个 provider route 下让标题调用报告 `anthropic-messages`、assistant 调用报告 `openai-completions`;切到真实卸载 view 的“轨迹”再返回后,选中调用、搜索、API 页签和协议视图都恢复,浏览器无错误。这份历史证据只是本地离线验收,不是真实 provider wire 测试,也不能证明 `v0.2.1` 在 alpha.2 上已通过验收。请固定到经过审阅的准确 release tag 或 commit。 2026-08-31,`v0.2.1` 正式版本在 hosted CI 中通过了统一 `0.1.2-alpha.2` 依赖断言、Host + Client typecheck、8 个测试文件 / 102 项测试、构建、package verifier 与 dry-run pack。公开下载的 release asset 与本地验收包逐字节一致,全新的 alpha.2 Web profile 也完成了该公开包的安装、启动和卸载。纯离线浏览器旅程产生了 assistant 与 session-title 调用,显示 Request / Response / API 对照,并在切到“对话”再返回后保留选中调用、API 页签和手动 Anthropic 参考;浏览器没有 warning 或 error。这仍是标准化边界的离线证据,不是真实 provider wire 证明。 ## 许可证 [MIT](LICENSE)