Interactive workflows

人、agent 和 live KLayout 一起工作

让人和 agent 在同一个 live KLayout 上协作的一组交互能力:SEND 选择记忆一个 agent 控制多个 KLayout跨会话搬运8082 端口 klive 兼容显示,以及把整段会话录成可回放脚本。以下每一项都是普通工具,除插件外无需任何特殊配置。

一份目录,两张脸

klink 的控制面有两张脸:Python client KLinkClient,以及 MCP server 暴露的同名工具。二者都来自 live plugin 的 method registry,不维护一份会漂移的手写清单。全部工具的功能、参数与示例见 MCP 工具参考;本页讲的是把这些工具串起来的交互流程

from klink import KLinkClient
with KLinkClient() as c:
    print([m["name"] for m in c.methods()["methods"]])

SEND 选择记忆 —— “这块区域”到底指哪

人和 agent 协作最大的摩擦,是“我说的‘这块’是哪块”。klink 用 SEND 解决它:你在 KLayout 里选中几何,点插件工具栏的 SEND(或 agent 调 selection.send_context),这次选择就被记成一个稳定 id(如 sel_0006),存进 session 级记忆 .klink/sessions/<id>/interaction_context.jsonl。从此“刚发的”“这里”“那一个”都能解析到精确几何,而不是截图

工具用途
interaction.selection.recent最近若干次 SEND(默认最新 5,按顺序不按时间)。
interaction.selection.latest最新一次 SEND。
interaction.selection.get按 id 读精确记录。
interaction.selection.label给重要选择加名字/描述。
interaction.context同时返回 live 选择 + 最近 SEND 记忆。

关键区别:selection.get当前 live 选择interaction.*明确 SEND 过的持久记忆。因为从 SEND 到那句引用它的话,中间可能隔了好几分钟的版图操作,所以记忆按序号/数量解析,而不是按时间。用 interaction.context 可以同时拿到“当前选择”和“最近 SEND”,让 agent 判断用户指的是哪个。

两个刻意的设计取舍:一是用显式 SEND,而不是被动监听每次点选——只有用户主动发出的选择才记一条 sel_000N,过滤掉探索性点击和误选的噪音;二是记忆放在插件外部(桥侧),插件只保持“此刻”的零层事实(selection.get 和事件流),会话级记忆、id 分配、语言解析都在 MCP 桥的 interaction.*,按会话持久化到磁盘 JSONL。

SEND 是持久的、不丢的。 插件在广播前就用单调递增序号把每次 SEND 写进 journal,所以即使 SEND 时没有 agent 在监听也不会丢——桥下次连上时会从 journal 补齐并去重。

示例:把我刚发的两块连起来。

# 用户:选中 A → SEND;再选中 B → SEND
interaction.selection.recent limit=2      # → [sel_0007(B), sel_0006(A)]
interaction.selection.label id="sel_0006" label="probe pad"
# agent 用这两个 id 去 port.mark / structdevice.declare_nets,不靠截图猜坐标

一个 agent 控制多个 KLayout

每个 KLayout 窗口启动时绑定一个端口(第一个空闲的 87658799)并注册为一个 session。一个 MCP 桥可以同时驱动全部这些 session——它们是平等 peer,没有“工作端口”或“LVS 端口”的特殊角色,你总是显式说要哪个。

klayout-8765真实工作版图
klayout-8766scratch / 测试
klayout-8767参考 / 对比
一个 MCP 桥按需切换目标
工具用途
klink.session_list枚举正在运行的 session。
klink.session_label给某个 session 打人类 label / 别名。
klink.session_resolve把 label / 别名 / active cell / top cell 解析成 session id。
klink.session_use把桥的主 RPC 目标切到某个 session。
klink.session_status看某个 session 的记录。
klink.session_list
klink.session_label session_id="klayout-8766" label="scratch" aliases=["test"]
klink.session_resolve query="scratch"     # → klayout-8766
klink.session_use session_id="klayout-8766"

实践建议:同时开着真实工作版图和 demo/测试窗口时,先给每个窗口打 label,agent 就能用“scratch”这种名字而不是端口号来指代,破坏性操作也不会误伤工作 tab。

跨会话搬运 —— 两阶段、确认安全

在窗口之间搬几何是两阶段的:先 prepare,对目标 session dry-run 通过后,再 commit 才真正写入。这样在写进目标窗口之前就能发现“搬错窗口”“包内容不对”。

选择源几何源 KLayout 里 SEND 或指定 cell/selection。
prepare构建包并对目标 session dry-run。
检查报告确认目标、cell、layer、shape/instance 统计。
commit确认后才写入目标窗口。
klink.transfer_prepare source_session="klayout-8765" target_session="klayout-8766" \
    copy_mode="flat_selection" target_cell="IMPORTED"     # dry-run 内建
# → package_id + dry-run 报告(目标/cell/layer/统计)
klink.transfer_commit package_id="pkg_0001"

copy_modeflat_selection(默认)只拍平复制可见几何、不带层级;shallow_instance 只搬实例引用——若目标窗口缺对应子 cell,它会阻断提交而不是静默造一个空壳。目标窗口写入前什么都不会真正写进去,所以搬错目标会在 dry-run 阶段被发现。搬运中还可用 layer_map 重映射图层、translate_um 平移。

8082 端口:klive 兼容显示,完全替代 klive

插件除了 8765 的 RPC,还在 127.0.0.1:8082 起了一个 klive 协议兼容的显示服务。它是原版 klive直接替代(drop-in replacement):任何硬编码 localhost:8082 的 gdsfactory / 外部脚本——尤其是 Component.show()——无需改动就能把版图推进 KLayout。你不需要再单独装 klive。

能力说明
协议兼容逐字节兼容 klive 0.4.1 的请求/响应({"gds":…, "keep_position":…, "libraries":…, "technology":…, "lyrdb":…, "l2n":…}),并回 {"version":"0.4.1", "type":"open"|"reload", …}
c.show() 开箱即用gdsfactory 的 Component.show() 直接把组件推进 KLayout,已开则 reload、可 keep_position 保住视角。
不止 GDS随 klive 协议一并推送 lyrdb(DRC 标记)和 l2n(网表抽取),一并在浏览器里显示。
多会话转发单窗口时直接走 pya 载入;多窗口时 8082 是固定入口,把请求转发给注册的目标 session——用 klink.session_set_klive_target / session.mark_klive_target 选定哪个 KLayout 接收 c.show()
不干扰 RPC即使 8082 被占用起不来,也只影响显示;8765 的 klink RPC 完全不受影响。

示例:普通 gdsfactory 脚本,一行 c.show() 推进 KLayout。

import gdsfactory as gf
c = gf.components.mzi()
c.show()          # 走 127.0.0.1:8082 → klink 的 klive 兼容服务 → 显示在 KLayout

示例:多窗口时,先指定谁接收显示。

klink.session_set_klive_target session_id="klayout-8766"   # scratch 窗口接收 c.show()
# 之后所有 c.show() / import_gf 的显示都落到 klayout-8766
这也是 硅光流 的显示通道:photonics.import_gf 把成品 gdsfactory 脚本接管进 klink 后,后续的 photonics.reroute 也通过同一条链路刷新显示。

录制 → 可回放脚本

recorder 把一整段工作会话——手工 GUI 编辑和 agent 的 RPC 编辑一视同仁——变成可回放脚本。它不是逐条 RPC 日志,而是 replay-script 生成器:记录足以重建最终 layout 状态的动作,所以一个批量 RPC 或一段 exec.python 可能会展开成逐对象的动作。

工具用途
recorder.start开始录制(可选 output_path 指定输出)。幂等。
recorder.status是否在录、已记录多少事件/动作、输出路径。随时可调。
recorder.stop停止并写脚本,返回统计 + wrote。幂等。

停止时写出两个产物

  • <name>.py —— 基于 KLinkClient 的回放脚本,并用 # user command: 注释标出每步对应的菜单动作。
  • <name>_pya.py —— 独立 pya 版,可在没装 klink 的 KLayout 里直接跑。
recorder.status                 # 先确认没在录别人的
recorder.start
# …做一些 typed RPC 编辑 + 手工 GUI 编辑…
recorder.stop                   # 产出 .py 和 _pya.py
开始你自己的录制前先看 recorder.status,避免覆盖一个正在进行的录制。

这样一来,原本一次性的手工修改就变成了能重复运行、能改参数的脚本,agent 也能在此基础上重新生成。

Profiles 与工具发现

--profile 同时按意图(read/write/verify/escape/all)和领域(11 个 token 之一)过滤。默认 read,write,verify,escapeklink.find_tools 在任务中导航更窄的工具。完整说明见 MCP 参考 · Profiles

python -m klink.mcp --profile read,write,verify,escape   # 默认
python -m klink.mcp --profile read,device_photonics
klink.find_tools domain="routing_backends"
klink.status                                             # 解释器 / 能力 / 连接状态

Escape hatch

exec.python 可在 KLayout 内跑受控 pya 片段,适合 typed RPC 暂未覆盖的边角场景;它仍会触发 recorder + layout-diff 检测。但优先级应低于 typed RPC——后者有输入验证、结构化错误、next_action,且在 recorder 里表现为“意图”而非不透明代码。详见 MCP 参考 · Escape hatch