各位大佬,合适希望发在这里。
最近在做一个 LLM agent 运行时,叫 lipas。它关注的三件事,恰好是 现在多数 agent 框架顺手带过、没认真做的:副作用分类、调用前的预算 拦截、以及 LLM 调用的确定性回放。
仓库在这里:GitHub - lipas-otp/lipas: Layered Invariant-Preserving Agent System · GitHub
核心想法是:系统里发生的每一件事——LLM 调用、工具调用、资源消耗、 guard 拒绝——都是一条带类型的 claim,被折叠进一个只追加的 store。 工具在注册时必须声明自己的副作用类型(PURE / READ_ONLY / IDEMPOTENT_WRITE / EXTERNAL_WRITE),这个声明会被框架用来决定是否 可以重试、是否要走 guard、回放时是否安全。预算检查是在调用发出 之前做的,不是事后报警。LLM 调用回放时完全不碰网络。
落到实际场景,这意味着:
-
你可以拿一段已录制的会话,换一组更紧的预算重跑,看看在哪一步 会被拒掉。零 token 成本。
-
一个 EXTERNAL_WRITE 类型的工具(比如 send_email、charge_card), 如果 guard 说不行,它根本不会发出。这个拒绝本身也会被折叠成 一条带类型的 claim,所以审计日志里能看到"什么没发生、为什么 没发生"。
-
这个只追加的 store 是一个 join-semilattice:同一条 claim 重复投递 是 no-op,投递顺序也不影响最终状态。确定性回放之所以能"真的" 做到而不是"近似"做到,依赖的就是这个性质。
现在还做不到的(alpha 阶段,不藏着掖着):
-
只接了 Ollama。OpenAI / Anthropic 适配器在下一个 milestone。
-
单 agent。supervision tree 还没做。
-
store 是内存里的,进程重启就没了。持久化是后面的事。
-
工具回放目前是对真实世界重新执行的,只对 PURE / READ_ONLY 安全。 ToolReplayer(用录制结果替换非 PURE 工具)要等到 Phase 4。
仓库里有六个可以直接跑的例子:正常流程、预算拒绝、guard 拒绝、 单次 LLM 回放、ReAct 端到端、整段 ReAct 回放。回放那个例子有三个 变体,包括一个 strict-match 不通过被拒绝的演示。
如果各位之前做过 agent,我特别想听听你们的想法。 尤其是下面的这类问题:
- “线上那个 bug 我没法复现,因为 LLM 这次给了不一样的回答。”
- “我的预算报警是在花完钱之后才响的。”
我想知道 lipas 这个方向是不是对路,或者,是不是解错了一半的问题。
拍砖、吐槽、提问都欢迎。谢谢。