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 时则不要生成基于该频率的时基建议,并在结果中明确说明原因。
Summary
scope.observe,scope.advise, anddoctor.configTODO.mdSafety
scope.adviseonly recommends and never applies changesValidation
git diff --cached --checkpytest -q tests/test_agent_advise.py tests/test_agent_observe.py tests/test_mcp_http.py tests/test_waveform_expectations.py tests/test_waveform_relationships.py: 45 passed, 1 warning, 3 subtests passedSplit context
This is split out from the original AI-agent scope PR. For the best end-to-end UX, review after the display/focus controls PR, because
scope.adviserecommends those explicit CLI commands.