粘贴线上报错原文,拿回结构化诊断结论
30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/13 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add ax2/dsh-py-doctor该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
是什么
dsh 原生插件 · dev
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 19 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🟢 扫描:未发现敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描未发现敏感能力:最多只发网络请求、读取自身元数据或只读文件,未发现执行命令、文件写入或敏感信息读取。
扫描于 2026/11/1(0 天前) · 范围 全包扫描(包内未声明入口) · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-llm@deepseek-ai/dsh-tools@deepseek-ai/dsh-util-values@deepseek-ai/schemastery给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 结构化诊断结论
- 覆盖迁移与SQL检查
README
由 DeepSeek 最新模型翻译生成dsh-py-doctor
离线、确定性的 Python / Django 生产报错诊断工具集,为 DeepSeek Harness 提供 6 个工具。
Deterministic, offline Python/Django production-report diagnostics for DeepSeek Harness.
把线上报错原文粘进来,拿回结构化结论:异常类型、调用链、N+1 查询、未执行的 migration、check --deploy 项、Celery 任务堆积。
一句话:纯本地、零网络、有界、可复现。 本插件不执行 Python、不起子进程、不读文件、不连网络、不看时钟、不用随机数——每个工具都是输入的纯函数;输入超预算就拒绝(不截断),看不懂的行如实列进 unknown_lines(不静默丢弃)。
快速开始
dsh plugin --profile web add dsh-py-doctor
装完重启应用(bundle 列表是启动时读的)。想一次装齐四个插件(含 deterministic-tools / jvm-doctor / win-native)用 @ax2zicode/dsh-dev-toolbox;别和单独安装混用。
家族总览:zicode.com/software 是四个插件、合装包与桌面软件的统一入口。
展开完整文档(README 剩余 1 节)
dsh-py-doctor
离线、确定性的 Python / Django 生产报错诊断工具集,为 DeepSeek Harness 提供 6 个工具。
Deterministic, offline Python/Django production-report diagnostics for DeepSeek Harness.
把线上报错原文粘进来,拿回结构化结论:异常类型、调用链、N+1 查询、未执行的 migration、check --deploy 项、Celery 任务堆积。
一句话:纯本地、零网络、有界、可复现。 本插件不执行 Python、不起子进程、不读文件、不连网络、不看时钟、不用随机数——每个工具都是输入的纯函数;输入超预算就拒绝(不截断),看不懂的行如实列进 unknown_lines(不静默丢弃)。
快速开始
dsh plugin --profile web add dsh-py-doctor
装完重启应用(bundle 列表是启动时读的)。想一次装齐四个插件(含 deterministic-tools / jvm-doctor / win-native)用 @ax2zicode/dsh-dev-toolbox;别和单独安装混用。
家族总览:zicode.com/software 是四个插件、合装包与桌面软件的统一入口。
15 秒看效果 —— 把 traceback 贴进去,模型调用 python_traceback,拿回(实测输出):
exception_type: KeyError message: 'user_id'
deepest_frame: svc.py:42 in handle
cause_hint: The mapping has no key 'user_id'; production data is usually
missing the key that test data always has.
coverage: 3/3 lines, 0 unknown, confidence 1 (parser tb-1)
为什么不让模型自己写 pwsh? 它读得懂 traceback,但给不了这个:
- 覆盖率:未识别的行(unknown_lines)逐条列出,而不是被静默丢掉;
- 一次就对:__cause__ / __context__ 链、SyntaxError 的 caret 行列、[Previous line repeated N more times] 都有 75 个测试盯着;
- 不吃幻觉:pytest / migrations / checks / celery 的每个数字都能追溯到原文行。
相邻插件:dsh-deterministic-tools · dsh-jvm-doctor · dsh-win-native · dsh-dev-toolbox
中文说明
它解决什么问题
线上事故发生时的典型流程是:从日志里复制一段 traceback / pytest 输出 / showmigrations 结果粘到对话里,然后靠人眼找关键行。
这个过程有三个常见失败:抄错行号、漏掉后面真正的根因、把「看不懂的日志」当成「已经看懂了」。
dsh-py-doctor 只做一件事:把这六类已知语法的报告文本解析成结构化 JSON,并且如实报告它读懂了多少。
为什么坚持离线
- 可复现:同一段输入永远得到同一份输出。没有时钟、没有随机、没有网络,所以结论可以进 issue、进 CI、进复盘文档。
- 可审计:工具不接触你的服务器,不需要 settings.py、不需要数据库连接串、不需要 -A proj。粘文本就够了。
- 不失真:不在本地跑一遍 Django 来「确认」,就不会引入第二套环境差异。
- 无副作用:绝不 migrate、绝不发查询、绝不重启 worker。
安装
npm(推荐):
dsh plugin --profile web add dsh-py-doctor # 装进 profile
预构建 tarball(与 npm 上是同一份产物,无需构建步骤):
dsh plugin --profile web add https://github.com/ax2/dsh-py-doctor/releases/latest/download/dsh-py-doctor.tgz
要固定版本就把 latest/download/dsh-py-doctor.tgz 换成 download/v<version>/dsh-py-doctor-<version>.tgz。
包内 cordis.patch.yml 会往 profile 的 bundle 列表里插入一行 id: py-doctor,DSH 加载 profile 时即注册这 6 个工具。
本地开发时不必发布,直接挂载构建产物:
pnpm install && pnpm build
dsh --profile web --patch ./cordis.local-overlay.yml --dump-config # 先验证层合成
dsh --profile web --patch ./cordis.local-overlay.yml # 再启动
cordis.local-overlay.yml
- insert:
- id: py-doctor-local
name: 'D:/dsh/dsh-py-doctor/lib/index.js'
分发使用预构建产物(lib/),没有 postinstall / prepare 脚本。
六个工具
所有工具都在 python 组内,参数都是 text(报错原文,必填,内联粘贴)。返回值统一为回执信封:
{ "result": { "...": "..." }, "meta": { "bytesIn": 412, "bytesOut": 987, "truncated": false, "notes": ["parse coverage 100.0% ..."] } }
| 工具 | 读什么 | 不读什么 |
| python_traceback | CPython traceback:异常类型/模块/消息、帧链、__cause__/__context__ 链、SyntaxError 的插入符号(caret)行号与列、[Previous line repeated N more times]、project 与 site-packages 帧、常见异常的根因提示 | 非 traceback 的散文;截断的 Traceback (most recent call last 会被判为未识别 |
| pytest_summary | pytest 计数(passed/failed/errors/skipped/xfailed/xpassed/warnings/deselected)、耗时、FAILURES/ERRORS 段落与 E 断言摘要、short test summary info、--durations 最慢用例 | 本次运行没打印的段落(在 warnings 里点名,不猜测) |
| django_migrations | showmigrations 缩进列表、--plan 平铺列表、app (database) 库横幅、(no migrations)、每 app 已应用/未应用与总数、plan_needed | --plan 没有勾选框,所以不会把任何一条说成"已应用" |
| django_sql_n_plus_one | 按归一化语句分组重复查询(归一化会折叠空白、把字符串/数字/%s/参数元组换成 ?),给出 N+1 候选、次数、动词、表名、一条原始样例 | 归一化是有损的(只差常量的语句会合并),所以样例永远保留;不发任何查询 |
| django_checks | manage.py check / check --deploy:每条 finding 的级别、诊断 id(fields.W161)、消息、HINT、尽力提取的对象、各级计数、?: 部署清单项、System check identified ... 汇总 | 汇总数字与解析出的 finding 数不一致时,两边都报出来,不替任何一边圆场 |
| celery_report | inspect active/reserved/ping/stats:worker 名、任务条目与直方图、reserved 段、worker_count 之类的事实键 | 纯 inspect active 无法与 inspect reserved 区分,只有显式 'reserved': 段才会计入 reserved_tasks |
例:python_traceback
输入(节选):
Traceback (most recent call last):
File "/srv/app/shop/views.py", line 12, in post
return self.helper(request)
File "/usr/local/lib/python3.12/site-packages/django/db/models/query.py", line 448, in get
raise self.model.DoesNotExist(
shop.models.Order.DoesNotExist: Order matching query does not exist.
输出(节选,json 已裁剪):
{
"result": {
"exception_type": "DoesNotExist",
"exception_module": "shop.models.Order",
"exception_message": "Order matching query does not exist.",
"frames": [
{ "file": "/srv/app/shop/views.py", "line": 12, "function": "post", "origin": "project" },
{ "file": "/usr/local/lib/python3.12/site-packages/django/db/models/query.py", "line": 448, "function": "get", "origin": "installed" }
],
"deepest_project_frame": { "file": "/srv/app/shop/views.py", "line": 12, "function": "post" },
"coverage": { "total_lines": 6, "parsed_lines": 6, "unknown_count": 0, "confidence": 1, "parser_version": "tb-1" }
},json
"meta": { "bytesIn": 313, "bytesOut": 1692, "truncated": false, "notes": ["parse coverage 100.0% (6/6 recognized lines, 0 unknown, parser tb-1)"] }
例:django_sql_n_plus_one
输入:
(0.004) SELECT "shop_product"."id" FROM "shop_product" WHERE "shop_product"."order_id" = 11 LIMIT 21; args=(11,)
(0.001) SELECT "shop_product"."id" FROM "shop_product" WHERE "shop_product"."order_id" = 12 LIMIT 21; args=(12,)
(0.001) SELECT "shop_product"."id" FROM "shop_product" WHERE "shop_product"."order_id" = 13 LIMIT 21; args=(13,)
输出(节选):candidates[0] 为
json
{
"normalized": "SELECT \"shop_product\".\"id\" FROM \"shop_product\" WHERE \"shop_product\".\"order_id\" = ? LIMIT ?",
"count": 3,
"verb": "SELECT",
"tables": ["shop_product"],
"example": "SELECT \"shop_product\".\"id\" FROM \"shop_product\" WHERE \"shop_product\".\"order_id\" = 11 LIMIT 21; args=(11,)",
"first_line": 1,
"lines": [1, 2, 3],
"n_plus_one": true
}
诚实回执(coverage receipt)
每份结果都带 coverage:
| 字段 | 含义 |
| total_lines | 提交文本的物理行数 |
| parsed_lines | 被某条语法规则认领的行数 |
| unknown_count | 非空、且没有任何规则认领的行数 |
| unknown_lines | 最多 8 条未识别行样例(每条最长 200 字符 + 省略号),带行号 |
| unknown_truncated | 是否还有更多未识别行没放进样例 |
| confidence | parsed / (parsed + unknown),保留 3 位小数;空行不计入分母;空输入视为 1 |
| parser_version | 语法版本号(tb-1、pytest-1、migrations-1、sql-1、checks-1、celery-1) |
结论:confidence 不是「我有多确定」,而是「你粘进来的实质内容我读懂了多大比例」。
未识别的行不会消失,它们出现在 unknown_lines 里,并让 confidence 掉下来。
例:把 * worker 7 restarting after SIGKILL 插到某个 frame 的 File "..." 行和它的源码行之间,
它会以 { line: 3, text: " worker 7 restarting after SIGKILL " } 出现在 unknown_lines[0],
后面的真实源码行同样被判为未识别(源码行必须紧跟自己的 frame 行,且带 CPython 的四空格缩进), confidence 从 1 掉到 0.6——它绝不会被当成 frame 的源码吸收掉。
预算与拒绝
apply(ctx, config) 接受以下配置(全部可选,含默认值;DSH 从 profile 的插件配置传入,也就是挂在 py-doctor 这个 id 下的那段对象):
| 字段 | 默认 | 作用 |
| maxInputBytes | 262144 | 硬上限:超过就抛 INPUT_TOO_LARGE,不回半个结果 |
| maxFrames | 200 | traceback 帧数上限(同时修正 deepest_frame 指针) |
| maxFailures | 100 | pytest 失败/错误/摘要条目上限 |
| maxFindings | 200 | check finding 上限 |
| maxQueryGroups | 500 | 归一化 SQL 分组上限 |
| maxTaskEntries | 500 | Celery 任务条目上限 |
| minRepeats | 3 | N+1 判定阈值(django_sql_n_plus_one 还可用 min_repeats 参数按次覆盖,最小 2) |
| toolPrefix | "" | 工具名前缀,py → py__python_traceback |
| only | [] | 只注册列出的工具名,空表示全部 |
结构化输入超预算的行为是拒绝而不是截断:BoundedInputError(code: "INPUT_TOO_LARGE")会说明实测字节数、上限、以及「没有截断也没有部分处理」。
列表类结果超上限则截断并标注:meta.truncated === true,meta.notes 写明是哪个上限,渲染文本会出现 [bounded] input=…B output=…B 尾注。
参数类型不对(例如 min_repeats: "lots")由工具参数 schema 直接拒绝(INVALID_ARGS),不会静默降级成默认值。
路线图
- 0.1.0(当前):六个解析工具 + 诚实回执 + 预算拒绝 + 75 个测试(含刻意截断/乱码样例)。
- 0.2.0:Django explain/EXPLAIN ANALYZE 输出解析(离线读文本,仍不连库);pytest --tb=long 的源码位置精确化;pip check / pipdeptree 依赖冲突解析。
- 0.3.0:跨报告关联(traceback 的 file:line 与 pytest 失败位置对齐);gunicorn/uwsgi worker 崩溃日志;opentelemetry span dump 的最小可用解析。
- 不做:执行 Python、连数据库、连网络、读文件系统、调用 manage.py。这些交给别的工具,代价是环境不可复现。
开发 bash
pnpm install
pnpm typecheck # tsc -p tsconfig.json --noEmit
pnpm test # node --test --experimental-strip-types test/.test.ts
pnpm build # tsc -p tsconfig.build.json → lib/
- 源码只用 Node 的 strip-only TypeScript 子集:没有 enum、没有 namespace、没有构造函数参数属性、没有装饰器;相对导入必须带 .ts 后缀。
- src/core/.ts 是纯解析器(一模块一报告族),src/tools.ts 只做参数/回执/预算装配。
- 测试用例数 ≥ 工具数,并且断言精确数字(行号、计数、confidence 三位小数),不用 truthy 糊过去。
许可
MIT,版权归 ax2。
这是什么
dsh-py-doctor 注册六个 DeepSeek Harness 工具,把粘贴进来的 Python/Django 生产输出转成结构化 JSON。每个工具都是输入的纯函数:不执行 Python、不起子进程、不碰文件系统、不连网络、不读时钟、不引入随机性。
| 工具 | 输入 | 结构化结果 |
| python_traceback | CPython traceback 文本 | 异常类型/模块/消息、帧链、链式起因、SyntaxError 的插入符行列、省略的递归、项目帧与已安装帧、根因提示 |
| pytest_summary | pytest -q -ra --durations 输出 | 计数器总计、耗时、失败/错误段落(含 file:line 与 E 摘录)、短摘要条目、最慢测试 |
| django_migrations | manage.py showmigrations / --plan | 各 app 已应用与未应用的名称、计数、需要 plan 的 app、(no migrations) 的 app、plan_needed |
| django_sql_n_plus_one | connection.queries dump、debug-toolbar SQL 面板、-v2 查询日志 | 归一化后的语句分组、N+1 候选(含次数、动词、表、首行与一条原始示例) |
| django_checks | manage.py check / check --deploy | 每个问题一条发现,含级别、诊断 id、消息、提示、尽力还原的对象、按严重度计数、deploy 条目、摘要行 |
| celery_report | celery inspect active/reserved/ping/stats | worker 及其任务列表、任务直方图、reserved 任务、标量事实 |
为什么只做离线
为了可复现、可审计。同一段粘贴永远产出同一份 JSON,所以诊断结果可以直接贴进 issue、CI 日志或事后复盘。不需要你的 settings.py、数据库 URL 或 -A proj;也不会因为问了个问题就顺手迁移、查询或重启 worker。代价说得很明白:这个插件永远不会靠跑你的代码来验证猜想。
示例:python_traceback
输入:
Traceback (most recent call last):
File "/srv/app/shop/views.py", line 12, in post
return self.helper(request)
File "/usr/local/lib/python3.12/site-packages/django/db/models/query.py", line 448, in get
raise self.model.DoesNotExist(
shop.models.Order.DoesNotExist: Order matching query does not exist.
输出(已裁剪): json {
"result": {
"exception_type": "DoesNotExist",
"exception_module": "shop.models.Order",
"exception_message": "Order matching query does not exist.",
"deepest_project_frame": { "file": "/srv/app/shop/views.py", "line": 12, "function": "post" },
"coverage": { "total_lines": 6, "parsed_lines": 6, "unknown_count": 0, "confidence": 1, "parser_version": "tb-1" }
},
"meta": { "bytesIn": 313, "bytesOut": 1692, "truncated": false, "notes": ["parse coverage 100.0% (6/6 recognized lines, 0 unknown, parser tb-1)"] }
}
每个工具都返回这个 { result, meta } 信封。meta.notes 开头永远是覆盖率回执;任何被裁剪的内容都会在渲染文本里追加 [bounded] / [note] 页脚,而不是悄悄缩小载荷。
安装
dsh plugin --profile web add dsh-py-doctor # npm
或者固定使用预构建的 tarball(同一个产物,用于离线安装): https://github.com/ax2/dsh-py-doctor/releases/latest/download/dsh-py-doctor.tgz(或 download/v<version>/dsh-py-doctor-<version>.tgz 来固定版本)
端到端验证通过:把已发布的包从 npm 安装到一个临时配置档,然后让真实模型跑一轮,对三行 traceback 调用 python_traceback,返回了 exception_type、帧列表和 100% 解析覆盖率(session-b5681b93)。
打包的 cordis.patch.yml 插入一行 bundle(id: py-doctor),所以加载配置档就会注册全部六个工具。本地可以跳过发布,用 dsh --profile web --patch ./cordis.local-overlay.yml 挂载构建产物,其中 overlay 插入 { id: py-doctor-local, name: 'D:/dsh/dsh-py-doctor/lib/index.js' }。分发使用预构建的 lib/;没有 postinstall 或 prepare 脚本。
示例:一次拒绝
输入超过 maxInputBytes 会被拒绝,绝不部分解析:
BoundedInputError: report is 300000 UTF-8 bytes, above the configured limit of 262144 bytes.
Split the report and call the tool again; nothing was truncated or partially processed.
覆盖率回执
confidence 不是对诊断的置信度;它是语法规则认领的实质性输入行占比:parsed / (parsed + unknown),四舍五入到三位小数,空行不计入分母,空输入报告为 1。无法识别的行列在 unknown_lines 里(最多 8 个样本,每个最多 200 个字符,带行号),并会拉低这个数值。没有任何内容被悄悄丢弃:把 worker 7 restarting after SIGKILL 粘到某帧的 File "..." 行和它的源码行之间,它会被报告为
unknown_lines[0] = { line: 3, text: " worker 7 restarting after SIGKILL " } —— 它下面真正的源码行也会被报告为无法识别,因为源码行必须紧跟在它的帧下面,保持 CPython 的四空格缩进 —— 而 confidence 会从 1 降到 0.6。它绝不会被当作该帧的源码吸收。
配置
apply(ctx, config) 接受这些可选字段,由 DSH 从配置档传入
插件 id 下的配置:
maxInputBytes: 262144 # hard ceiling; over-budget input is refused
maxFrames: 200
maxFailures: 100
maxFindings: 200
maxQueryGroups: 500
maxTaskEntries: 500
minRepeats: 3
toolPrefix: '' # 'py' registers py__python_traceback, ...
only: [] # ['celery_report'] registers just that tool
maxInputBytes 是拒绝阈值。列表上限(maxFrames、maxFailures、maxFindings、maxQueryGroups、maxTaskEntries)会截断内容,并设置 meta.truncated = true,同时附上一条具名说明。maxOutputBytes 保留在配置里,只为接口兼容;结构化结果实际受列表上限和输入预算约束,所以它目前只是一个声明了却没用上的上限。
路线图
- 0.1.0:六个解析器、回执信封、预算拒绝、75 个测试,其中包含故意截断和乱码的测试夹具。
- 0.2.0:解析 EXPLAIN 文本(仍然离线),为 --tb=long 提供精确的源码位置,解析 pip check / pipdeptree 冲突。
- 0.3.0:跨报告关联(把 traceback 的 file:line 与 pytest 失败位置对上)、gunicorn/uwsgi worker 崩溃日志、最小化的 OpenTelemetry span dump。
- 永不:执行 Python、连接数据库、访问网络、访问文件系统、调用 manage.py。
开发
pnpm install
pnpm typecheck # tsc -p tsconfig.json --noEmit
pnpm test # node --test --experimental-strip-types test/.test.ts
pnpm build # tsc -p tsconfig.build.json → lib/
源码只使用 Node 的 strip-only TypeScript 子集(不用 enum,不用 namespace,不用构造函数参数属性,不用装饰器),相对导入一律带 .ts 后缀。src/core/*.ts 里每个报告族各放一个纯解析器;src/tools.ts 只负责接参数、回执和预算。测试断言精确数值,而不是真假值,测试套件的规模至少与工具数量相当。
许可证
MIT,版权归 ax2 所有。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
ax2/dsh-py-doctor
粘贴线上报错原文,拿回结构化诊断结论
相关插件 · 开发 / 工程
隐私简历生成器reactive-resume/reactive-resume
Reactive Resume 已迁至 GitHub 上的…
★ 45,125已汉化MCP
71.7
AI 架构文档生成器sopaco/deepwiki-rs
🚀 Litho 已进化为 Terrain —— 给你的 AI 智能体一张会呼吸的代码库地图。
★ 3,157已汉化DSH
70.8
长时任务执行闭环AMAP-ML/LongHorizon-Harness
面向 Computer-Use Agent 的 Loop Engineering
★ 1,764已汉化DSH
70.5
AI 编程纪律方法包GanyuanRan/Aegis
让 AI 编程 agent 变得可信:少返工、更安全、说“完成”前先给证据。
★ 1,384已汉化DSH
69.6
多代理编排运行时Enderfga/claw-orchestrator
面向编程智能体的运行时。把 Claude Code、Codex、Antigravity、Grok…
★ 586已汉化MCP
69.4
记忆进化插件csyangwen/dsh-memory-evolve
dsh-memory-evolve 使用场景指南
★ 461已汉化DSH
67.9