抓取每次模型调用的原始 HTTP 请求与响应
29.5/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/9/26 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/wpeng77/dsh-llm-trace.git状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 40 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 4 处,展示前 4 条)
- 读取本地文件lib/index.js:458
return readFileSync(PAGE_PATH, 'utf8') - 读取本地文件lib/index.js:476
const body = readFileSync(ASSET_DIR + name) - 发起网络请求lib/client.js:210
return fetch(path).then( - 写入剪贴板lib/client.js:518
navigator.clipboard.writeText(text).then(
扫描于 2026/10/31(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 抓取原始HTTP请求响应
- 按会话归属
- 本地回环查看页展示
DeepSeek Harness 的线路级 LLM 检查器:抓取每次模型服务商调用的原始 HTTP 请求与响应体,按会话归属,展示在 Conversation View 标签页和本地回环查看页里。
README
由 DeepSeek 最新模型翻译生成dsh-llm-trace
一个 DeepSeek Harness 插件,用于捕获模型提供方调用的原始 HTTP 请求和响应体,并将其显示在对话视图标签页和回环查看器页面上。
为什么存在
dsh-context 读取持久会话日志,因此它显示的是循环所组装出的提供方中立请求(系统提示、工具 schema、消息、工具结果)以及提供方报告的 token 实际值。它无法显示线上载荷:即 POST 到提供方端点的确切 JSON 以及返回的确切字节。这个缺口正是本插件所填补的。
llm/stream 瀑布流对于载荷而言是错误的接缝。它交给监听器的是提供方中立的 GenerateOptions 和一个 StreamChunk 可迭代对象;线上 JSON 是在它之下构建的,位于适配器内部(@earendil-works/pi-ai → 官方 openai SDK → globalThis.fetch)。因此,线上层只能通过包装 globalThis.fetch 来触及。
安装
dsh plugin --profile web add dsh-llm-trace
或者直接从 GitHub 安装:
dsh plugin --profile web add github:wpeng77/dsh-llm-trace
然后用 dsh web 启动 Web UI。
展开完整文档(README 剩余 1 节)
dsh-llm-trace
一个 DeepSeek Harness 插件,用于捕获模型提供方调用的原始 HTTP 请求和响应体,并将其显示在对话视图标签页和回环查看器页面上。
为什么存在
dsh-context 读取持久会话日志,因此它显示的是循环所组装出的提供方中立请求(系统提示、工具 schema、消息、工具结果)以及提供方报告的 token 实际值。它无法显示线上载荷:即 POST 到提供方端点的确切 JSON 以及返回的确切字节。这个缺口正是本插件所填补的。
llm/stream 瀑布流对于载荷而言是错误的接缝。它交给监听器的是提供方中立的 GenerateOptions 和一个 StreamChunk 可迭代对象;线上 JSON 是在它之下构建的,位于适配器内部(@earendil-works/pi-ai → 官方 openai SDK → globalThis.fetch)。因此,线上层只能通过包装 globalThis.fetch 来触及。
安装
dsh plugin --profile web add dsh-llm-trace
或者直接从 GitHub 安装:
dsh plugin --profile web add github:wpeng77/dsh-llm-trace
然后用 dsh web 启动 Web UI。无需构建步骤:该插件是纯 ESM,不附带打包器输出,也不声明安装时脚本。
使用它
对话视图标签页
每个会话中,Chat 旁边都会出现一个 LLM Trace 标签页。它是会话作用域的:宿主会将每个捕获到的 fetch 归属于引发它的模型调用,因此其他会话或其他子代理的流量绝不会出现在此标签页中。
sessionId 是 conversation.view 条目上的一个普通 prop,组件在同一源上读取查看器自己的 JSON 端点——不涉及 Remote API,也不涉及生成的客户端程序集。
标签页打开时,编辑器会被隐藏,就像 Context 标签页所做的那样。编辑器座位是对话滚动容器内视图区域的同级元素,因此 shell 没有暴露针对它的按视图控制;该 bundle 改为基于视图根安装了一条 :has() 规则。待处理的审批、问题或计划审查仍保持可见,因为那些是代理被阻塞等待的答复,而不是聊天编辑器。
HTTP 查看器
相同的数据由 Web 宿主提供,因此不需要第二个端口:
http://127.0.0.1:3080/llm-trace
| 端点 | 返回内容 |
| GET /llm-trace | 查看器文档,从 lib/page.html 读取。 |
| GET /llm-trace/api/list | 最新优先的摘要、保留统计、客户端行诊断以及已见会话 id。接受 ?session=。 |
| GET /llm-trace/api/exchange?id= | 一次交换,包含标头和正文。 |
此页面不是会话作用域的:它显示该进程所做的每一次提供方调用,当子代理或标题生成器是嫌疑对象时,这正是你想要的。
两个界面都会经过 Web 宿主的 Host/Origin 防护和浏览器会话 cookie 检查。
请求体以树形展开一个真实的请求主要就是一个数组。一次实测捕获为 3,653,601 字节,分布在 8,787 个 JSON 节点中,其中仅 messages 一项就有 3,602,024 字节——占 98.6%——包含在 973 个条目里。把它当作格式化后的文本阅读,意味着要滚动很长一段距离才能了解到一个事实。
因此,请求体会渲染为一棵可折叠的树,默认折叠到顶层:
▼ root Object(6) · model: "deepseek-v4.1-flash" 3.7 MiB ├ model "deepseek-v4.1-flash" 21 B ├ messages ▸ Array(973) 3.4 MiB ├ stream true 4 B ├ stream_options ▸ Object(1) 23 B ├ max_tokens 384000 6 B └ tools ▸ Array(65) 62.7 KiB
- 大小是实测的,不是估算的。 一次自底向上的遍历会为每个节点计算其紧凑序列化后的大小,因此根节点的数值与捕获到的请求体完全一致。
- 只有展开的节点才会渲染。 默认视图是七行;一个折叠的多兆字节子树只占一行。超过 500 个子节点的容器会输出一行“more”,这会提高该容器的上限,而不是把其余节点全部实例化。
- 预览是通用的。 容器会显示其子节点数量以及第一个短字符串字段,按位置而非键名来选择,因此即使这个插件从未见过的结构也仍然能读出些内容。
- 一切都遵循主题。 该标签页不携带固定颜色:显示展开值的文本块继承树其余部分所使用的同一面板背景和标签颜色,因此它在浅色主题和深色主题下都保持清晰可读。test/e2e.mjs 会测量渲染后的对比度,低于 WCAG AA 即失败。
- 长字符串会展开为完整文本。 预览是 72 个字符的摘要;点击它会渲染整个值,包括所有换行符,因此消息正文或工具描述可以就地阅读,而不是无法辨认。渲染的文本上限为 32 KiB 并会注明这一点——Copy 始终拥有完整的值。展开的块刻意没有内部滚动条:滚动由窗格负责,点击标题会再次将其折叠。
- Tree / Raw 切换回字面字节,而无法解析的请求体(截断的捕获)会回退到原始模式并附上说明。
为什么响应体会显得极其庞大
提供方会每个 token 流式传输一个 SSE 块,而每个块都会重复整个 JSON 信封:
data: {"choices":[{"delta":{"content":"","reasoning_content":"The","role":"assistant"},"index":0},
"created":...,"id":"chatcmpl-...","model":"...","object":"chat.completion.chunk","usage":null}
每个分块的信封大约花费 230 字节——id 42、object 23、model 21、created 10、usage:null 4、index/role 框架 64——而实际携带的 token 只有几个字节。在一个实测的 276,186 字节的推理与工具调用流上,分解如下:
| 组件 | 字节数 | 占比 |
| delta.reasoning_content | 1,184 | 0.4% |
| delta.content | 118 | 0.0% |
| 工具调用参数 | 2,218 | 0.8% |
| usage 块 | ~370 | 0.1% |
| 每分块信封,重复 1,030 次 | ~272,300 | 98.6% |
因此,响应面板默认显示一个组装后的视图,它拼接推理和内容增量,按流索引重新组装工具调用参数,并打印结束原因和用量。同一个流渲染后为 3,524 字节——占原始正文的 1.3%。字面字节保留在一个开关之后。
配置
每个字段都是可选的。标签页和页面共享同一份配置;标签页的挂载路径是 lib/client.js 顶部的常量 BASE。
| 字段 | 默认值 | 含义 |
| path | /llm-trace | 挂载路径;绝对路径,无尾随斜杠。更改它还需要编辑 lib/client.js 中的 BASE。 |
| match | ['/chat/completions', '/v1/messages', '/v1/responses', '/v1/completions', '/responses'] | 用于选择提供商调用的 URL 子字符串,不区分大小写匹配。 |
| matchAll | false | 无论 match 如何,捕获每个请求。 |
| redactHeaders | ['authorization', 'api-key', 'x-api-key', 'proxy-authorization', 'cookie', 'set-cookie'] | 存储为 的请求头名称。设为 [] 可原样保留。 |
| maxRequestBodyBytes | 8 MiB | 保留的请求正文前缀。 |
| maxResponseBodyBytes | 32 MiB | 保留的响应正文前缀。 |
| maxRetained | 500 | 在驱逐最旧记录之前保留的交换数。 |
| maxJournalBytes | 256 MiB | 所有交换中保留的正文总字节数。 |
从 profile 补丁中设置它们:
- insert:
- id: llm-trace
name: 'dsh-llm-trace'
config:
match: ['model.example.com']
maxRetained: 2000
设计
- 只有匹配的 URL 才走捕获路径。 其他所有 fetch 调用都被原样转发,因此无关流量永远不会被观察到,也不产生任何开销。
- 调用方永远不会被延迟。 响应正文从 Response.clone() 读取,因此原始 Response 在原始 fetch 解析后立即返回。ReadableStream.tee 保持两个分支独立,这正是让流式 SSE 正文能够继续流式传输的原因。
- 正文是有界的,而非被选择的。 捕获保留一个前缀,并在达到配置的限制时将交换标记为截断,然后取消自己的分支,这样 tee 缓冲区就不会无限制增长。
- 会话归属依赖 AsyncLocalStorage。 llm/stream 携带 options.sessionId,而适配器的网络请求发生在返回的流被拉取时。监听器在每次拉取时都在 sessionScope.run(sessionId, …) 内运行,这使得该 id 可以从适配器下方的 fetch 包装器中读取。交错的子代理调用保持正确,因为每次拉取都会安装自己的作用域。
- 保留策略是一个受计数和字节双重限制的环形缓冲区。 最旧优先的逐出策略让内存在长会话中保持平稳。
- 标签页的视图根是绝对定位的。 Conversation 外壳的视图区域带有 min-height: auto,因此流内视图会按其内容调整尺寸,将外壳的滚动主体推到视口之外,并使外壳同时滚动两个窗格。将根移出流会打破这条固有尺寸链,这正是让列表和详情窗格各自拥有一个滚动器的原因。test/e2e.mjs 对此进行了断言:两个自滚动窗格且外壳无溢出。
- 两个浏览器界面共享同一份实现。 树逻辑和 SSE 组装器位于 lib/browser/ 中,宿主在 /llm-trace/assets/ 下提供它们,查看器文档和 Conversation View 包都通过 import() 加载。资源路由是一个封闭的允许列表,而不是路径拼接,因为由名称派生的路径会让调用者走出目录。
- 查看器文档和客户端包按请求读取。 编辑其中任何一个都会生效,而无需重新加载宿主模块。
- 包装器在处置时同步恢复,因此实时配置文件重载不会留下陈旧的包装器。
- 该标签页不包含构建步骤。 lib/client.js 是手写的,采用 dsh-client-modules 所提供的 window.__ModuleLoader__.load 封装形式:它只依赖平台 react 种子,并使用 React.createElement 而非 JSX,因此不涉及打包器、tsdown 预设和模块图声明。
已知限制与推迟的工作
- 请求体中的机密信息未被脱敏。 标头脱敏覆盖了凭据标头;请求体仍然携带完整的系统提示、每个工具模式以及代理读取的任何文件内容。这两个界面都位于 Web 宿主的回环绑定及其浏览器会话 cookie 检查之后,这是唯一的访问控制。
- path 未与客户端共享。 该标签页获取的是一个常量,因此非默认挂载路径需要在 lib/client.js 中进行相应编辑。
- 包装器是进程全局的且依赖顺序。 @deepseek-ai/dsh-experimental-inspector 包装同一个全局对象;同时运行两者会嵌套包装器,并捕获每个交换两次。
- 在此插件激活之前缓存的 fetch 引用不会被观察到。 dsh-llm-pi-ai 按请求构造其提供方客户端,因此它被覆盖;另一个在加载时缓存该引用的适配器则不会被覆盖。
- 在循环之外进行的调用不携带会话 id。 手动构建的、不带 sessionId 的 llm.stream() 调用会被捕获,但只会出现在 HTTP 查看器中。
- 二进制正文仅按字节计数。
- 组装视图仅解码 OpenAI 风格的 SSE。 使用不同流式封装格式的提供方会回退到原始视图,而原始视图始终可用。
开发
npm test # 共享树逻辑 + 宿主冒烟测试 + 浏览器打包单元测试
test/e2e.mjs 是唯一覆盖完整路径的检查。它需要一个正在运行的 dsh web 以及宿主打印的启动令牌,通过 CDP 驱动无头 chromium,打开一个会话,断言该标签页存在,点击它,打开最大的已捕获响应,读回组装视图,并检查窗格和编辑器布局:
TOKEN=$(journalctl -u dsh-web --no-pager \
| grep -o 'http://127.0.0.1:3080/?token=[A-Za-z0-9_-]' | tail -1 | sed 's/.token=//')
node test/e2e.mjs "$TOKEN"
该令牌用于生成宿主的浏览器会话 cookie,而每个路由都需要它;没有它,查看器会返回 401,检查便无法运行。
将工作树加载到正在运行的宿主中
sync.sh 将此树发布到一个修订目录,并将某个 profile 补丁行重新指向它,因此对宿主代码的编辑无需重启 dsh web 即可生效。它之所以存在,是因为 Node 的 ESM 模块缓存以解析后的 realpath 为键,而 Cordis profile 重载不会使其失效。
有两个约束塑造了它,而它们的方向相反:
1. Loader 行名称必须随修订版本变化,因为正是这一点打破了模块缓存。
2. 被取代的修订版本永远不会被删除,因为 dsh-client-modules 在首次扫描时对客户端打包进行快照,并且仅通过捕获路径上的 HMR 监视重新读取它——被删除的目录会使该监视永久处于脏状态,并在任何地方都没有错误的情况下冻结所服务的打包。
lib/page.html 和 lib/client.js 是符号链接而非复制,因此编辑其中任何一个都会在下次浏览器刷新时生效,永远不需要 sync.sh。
许可证
Apache-2.0。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
wpeng77/dsh-llm-trace
抓取每次模型调用的原始 HTTP 请求与响应
相关插件 · 模型接入
API 中继安全审计toby-bridges/api-relay-audit
面向 AI API 中转与 LLM 代理的本地安全审计。
★ 897已汉化DSH
69.4
免费搜索插件DDDMUC/dsh-free-search
DeepSeek Harness 免费搜索插件 —— 无需 API key,零成本,多引擎可切换。 一个给…
★ 761已汉化DSH
68.7
免费联网搜索liustack/modsearch
在官方 App 里模型能联网,切到 API 就不能了。ModSearch 把联网补回来:网页搜索、X…
★ 863已汉化DSH
68.5
OpenCode 免费模型FishBottle7/opencode2dsh
在 DSHDeepSeek Harness里原生使用 OpenCode Zen 的免费匿名模型。
★ 379已汉化DSH
67.8
AI 模型网关tingly-dev/tingly-box
Tingly Box Web UI 演示
★ 373已汉化DSH
67.4
WorkBuddy 账号池XDTrees/dsh-xdpool
把你能白嫖的模型额度接进 DSH 同一个池:WorkBuddy 多账号自动容错、十三家扫码登录、76…
★ 359已汉化DSH
67.1