Repository navigation
Add agent scope observation and advice tools - #4
Conversation
Scaxlibur
left a comment
There was a problem hiding this comment.
这组功能方向合理,但当前实现同时存在仪器状态边界和测量正确性问题。尤其是 fetch_waveform=true 会实际改变示波器状态,却仍被暴露为只读工具;多通道关系、expectation 和相位结果也可能给出具有误导性的结论。因此建议先修复以下问题,再合并本 PR。
| fetched_waveforms: dict[int, WaveformData], | ||
| ) -> dict[str, Any]: | ||
| service.require_high_impedance(channel, allow_50ohm=allow_50ohm) | ||
| waveform = service.fetch_waveform(channel=channel) |
There was a problem hiding this comment.
[P1] scope.observe(fetch_waveform=true) 最终会调用 ScopeService.fetch_waveform()。对于默认使用 dmax 的 DS1000Z/DS1104Z,该路径会发送 :STOP,同时可能启用通道并修改 waveform source/mode/format,而且当前不会恢复原采集状态。因此一次被描述为“只读”的调用可能让正在运行的示波器停下来。
这里却同时返回 read_only=true,/tools 描述也声称不会改变仪器状态,instrument_state_effects 还漏掉了 acquisition stop。建议将 waveform fetch 拆成明确标记为 mutating 的工具并要求显式确认;如果仍保留在 scope.observe,则必须修正工具元数据、文档和完整状态影响说明,并设计失败路径下可证明的状态恢复。
| expectations=normalized_expectations, | ||
| expectation_results=expectation_results, | ||
| ) | ||
| for observed_channel in observed_channels |
There was a problem hiding this comment.
[P1] 当前每个通道分别调用 fetch_waveform(),而每次调用还会单独打开 instrument session。示波器处于运行状态时,CH1 和 CH2 可能来自不同 acquisition,但代码仍会计算相位、延迟、相关性和交点,这些结果不能被当作同步测量。
此外,MCP 使用 ThreadingHTTPServer,多个请求还可能同时争用同一台仪器的全局 waveform source。建议在一个持久 session 内冻结或执行一次 acquisition 后批量读取全部通道,并按 instrument resource 序列化访问。若无法证明波形来自同一次 acquisition,应返回 warning,并跳过需要同步性的关系分析。
| elif "warn" in statuses: | ||
| status = "warn" | ||
| else: | ||
| status = "pass" |
There was a problem hiding this comment.
[P1] 当 expectation 字段无效、拼写错误或越界时,当前解析逻辑会静默忽略该字段;如果最终没有生成任何 check,这里仍会返回 status="pass"。例如 {"frequency_hz": "typo"}、{"vpp_v": -1} 或拼错的 {"frequncy_hz": 1000} 都会得到 pass, checks=[]。
MCP 发布的 JSON Schema 并未在服务端真正执行,不能依赖客户端自动遵守。建议在运行时完整校验字段名、类型、有限性和取值范围,遇到无效输入直接返回 ConfigError;如果没有任何可执行检查,状态至少应为 skipped 或 error,不能是 pass。
| } | ||
| pearson = float(np.mean(left * right)) | ||
| correlation = np.correlate(right, left, mode="full") / left.size | ||
| index = int(np.argmax(np.abs(correlation))) |
There was a problem hiding this comment.
[P2] 当前按互相关绝对值选择峰值,随后只根据 lag 计算相位,因此会丢失相关性的正负号。对于 right = -left 的同频正弦,实际结果为 correlation -1、lag 0,最终报告相位 0°,但正确结果应为 180°。
建议明确相位正负约定,并在相关峰为负时处理额外的 180° 相移,或者改用频域基波相位差。测试也应断言具体角度,而不只是检查结果“不是 None”,至少覆盖 0°、±90° 和 180°。
| diffs = np.diff(centered) | ||
| if diffs.size < 3: | ||
| return None | ||
| signs = np.sign(diffs) |
There was a problem hiding this comment.
[P2] 这里直接根据相邻样本差分的符号变化寻找局部极值,对真实示波器噪声和量化误差非常敏感。验证中,30% symmetry、1 Vpp 的三角波加入 1 mV 噪声后被估计为约 5.56%,加入 5 mV 后变成约 50%。目前的理想无噪声测试无法暴露这个问题。
建议先进行受控平滑或滞回处理,并利用期望频率限制相邻周期/极值间距;也可以改为按完整周期做鲁棒斜率或峰谷拟合。请增加包含噪声、量化台阶和轻微过冲的测试样本,避免 expectation 在真实波形上随机 pass/fail。
| def _summary_frequency(summary: dict[str, Any] | None) -> float | None: | ||
| if summary is None: | ||
| return None | ||
| value = summary.get("frequency_estimate_hz") |
There was a problem hiding this comment.
[P2] _summary_frequency() 当前只检查频率是否为正,没有检查 quality_warnings。因此即使 summary 已标记 low_cycle_count,该低置信估计仍会优先于用户提供的 expectation,并被用于生成 scope focus --time-range 建议。
建议复用 relationships 中已有的 trusted-frequency 判断:发现 low_cycle_count 等置信度告警时,优先回退到 expectation;没有可靠 expectation 时则不要生成基于该频率的时基建议,并在结果中明确说明原因。
Address the PR #4 review by separating the mutating waveform path from the read-only MCP surface: - `scope.observe` / `scope.advise` no longer read waveforms; both stay strictly read-only and are described as such in the tool metadata - add an explicit `scope observe --fetch-waveform` CLI path (experimental) for waveform summaries, expectation checks and relationships - skip correlation, intersections and phase when the channels are not from one acquisition, and say so instead of reporting noisy numbers - validate expectation fields strictly (name, type, finiteness, range) and report `skipped` when no check is executable - derive phase from the fundamental instead of the cross-correlation peak lag - make triangle symmetry estimation robust to noise, quantization and overshoot - withhold timebase advice when the measured frequency is low confidence
- list the current MCP tools with their read-only boundary and point at `GET /tools` as the canonical source - mark the new CLI command and MCP tools as experimental (implemented on the development line, not yet part of a release) - record `scope observe` side effects, the `--expect` TOML example and the fact that cross-acquisition timing relationships are not reported
3d57a60 to
e212170
Compare
|
感谢复审。这个 PR 已按意见重做,并 rebase 到当前 下面按你 6 条 inline 意见逐条说明。因为做了 rebase + 重写,原有 inline comment 会被 GitHub 标成 outdated,以本评论为准。 1. [P1]
|
|
当前版本已将 MCP 观察与显式波形采集分开,并跳过逐通道采集之间的相位、延迟等时序分析。这些边界处理合理。复审
本次验证基于隔离工作树,全量测试结果为 2526 passed、4 skipped、221 subtests passed,变更代码的 Ruff 检查通过。以上问题通过 fake service、实际命令解析器或合成信号复现;未连接真实仪器,不涉及新的硬件验收结论。 |
|
已在
验证:
没有连接真实仪器,也没有新增硬件验收结论。 |
Adds scope observation and advice through MCP without waveform reads, plus an explicit CLI waveform-report path. Sequential channel reads declare that they are not from one acquisition and omit phase, delay, correlation, and intersection results. Advice is returned for the operator to execute explicitly.
The CLI validates advice targets before loading configuration or constructing instrument services. Generated focus commands use the current CHANNEL=V_PER_DIV syntax and --hide-others flag. Expectation summaries retain unavailable channels and report incomplete acceptance instead of pass. The synchronized analysis helper jointly fits a constant and fundamental sine/cosine terms so DC offsets do not bias phase in non-integer-cycle windows.
Validation includes fake-service tests proving invalid targets cause no instrument I/O, parsing generated recommendations through the real CLI, missing-channel acceptance tests, and a 4.5-cycle / 1 kHz / 90-degree synthetic pair with a 5 V offset. Focused and related integration tests: 258 passed, 3 subtests passed. Ruff, scoped strict documentation audit, generated Reference drift check, and strict MkDocs build pass. No real instruments were accessed.
The full Windows Python 3.12 suite with CI extras and PYTHONUTF8=1 produced 2569 passed, 4 skipped, 221 subtests passed, and one failure in test_windows_job_rejects_allocation. That failure reproduced on unchanged master (44506c4): OpenBLAS exited while allocating memory under the worker limit before Python could report MemoryError. With OPENBLAS_NUM_THREADS=1, the master test passed and the feature branch's entire test_analysis_execution.py module passed (17 passed, 3 skipped). No source changes were made for this environment condition.