Pi Agent vs LangGraph:从人机交互、企业 RAG 到持久化工作流的完整选型指南

最近我一直在研究 Pi、OpenCode、Codex 这类 Coding Agent。它们已经具备模型调用、工具执行、会话管理、流式输出和扩展机制,甚至可以在执行过程中向用户提出结构化问题,等待用户选择后继续运行。

这很容易引出两个问题:

  1. Pi Agent 已经可以嵌入应用、注册工具、保存会话,它能不能直接做企业 RAG?
  2. 如果 Pi 可以做这些事情,LangGraph 还有什么是它做不了的?

我最终得到的结论是:

Pi Agent 与 LangGraph 不是简单的竞品关系。Pi 更接近一个可嵌入、可扩展的模型驱动 Agent Harness;LangGraph 更接近一个以显式状态和持久化执行为核心的工作流运行时。

两者都能完成工具调用,也都有状态,但它们把不同问题放在了架构中心。

一、先建立共同基础:Agent Loop 到底做了什么

不管是 Pi、OpenCode 还是 Codex,最小 Agent 都离不开下面这个反馈循环:

text 复制代码
用户输入
  → Agent 把消息和工具描述发送给模型
  → 模型输出文本或 tool_call
  → Agent 根据工具名找到执行函数
  → 验证参数并执行工具
  → 把 tool_result 写入 Context
  → 再次调用模型
  → 直到没有新的工具调用

模型本身不能直接读取本地文件、数据库或者企业知识库。它只是生成一个结构化的行动请求,例如:

json 复制代码
{
  "type": "function_call",
  "call_id": "call_42",
  "name": "kb_search",
  "arguments": {
    "query": "差旅报销需要哪些材料?"
  }
}

Agent Runtime 收到以后,调用真正的检索服务,再把结果写成对应的工具返回:

json 复制代码
{
  "type": "function_call_output",
  "call_id": "call_42",
  "output": {
    "results": [
      {
        "title": "员工差旅报销制度",
        "content": "报销时需要提交......",
        "source": "https://knowledge.example/policy/42"
      }
    ]
  }
}

模型下一轮能够回答,是因为工具结果重新进入了 Context。

因此,一个 Coding Agent 的核心并不是"模型会写代码",而是它建立了模型与外部环境之间持续反馈的闭环。

二、Agent 为什么能暂停并询问用户

OpenCode 或 Pi 在执行过程中弹出问题,让用户从几个选项中选择,本质上仍然是一次工具调用。

模型可能输出:

json 复制代码
{
  "name": "ask_user",
  "call_id": "question_123",
  "arguments": {
    "question": "你希望采用哪种实现?",
    "options": [
      {
        "label": "方案 A",
        "description": "改动较少,兼容现有实现"
      },
      {
        "label": "方案 B",
        "description": "重构成本较高,但边界更清晰"
      }
    ]
  }
}

接下来不是模型服务一直保持连接等待用户,而是 Agent Runtime 保存等待状态:

text 复制代码
模型调用 ask_user
      │
      ▼
Runtime 创建 pending[question_123]
      │
      ▼
向 TUI / Desktop / Web UI 发送问题事件
      │
      ▼
用户选择方案 B
      │
      ▼
前端回传 answer(question_123, "方案 B")
      │
      ▼
Runtime 完成等待,将答案作为 tool_result 返回模型

OpenCode 的方式

OpenCode 核心中存在 question 工具。其 Question Service 会创建 Question ID 和一个 Deferred,把问题放入 Pending Map,发布 Asked 事件,然后等待 Reply。客户端回传答案后,对应的 Deferred 被完成,Agent 才继续运行。

Pi 的方式

Pi 扩展可以调用 ctx.ui.select()confirm()input()editor(),也可以通过 pi.registerTool() 注册一个模型可调用的 question 工具。

在交互式终端中,Pi 自己渲染界面;在 RPC 模式中,Pi 只发送 JSON 请求,由外部客户端负责展示。

三、RPC 模式解决的是什么问题

RPC 是 Remote Procedure Call。这里的"远程"可以只是本机中的两个进程,并不一定经过公网。

Pi 使用普通 TUI 时:

text 复制代码
Pi Runtime + 终端渲染 + 键盘输入

Pi 使用 RPC 模式时:

text 复制代码
Pi 后台进程
   │ JSON 请求和事件
   ▼
桌面应用 / VS Code 插件 / 企业 Web 后端

例如 Pi 发出:

json 复制代码
{
  "type": "extension_ui_request",
  "id": "uuid-1",
  "method": "select",
  "title": "选择处理方式",
  "options": ["直接回答", "转人工复核"]
}

客户端选择后返回:

json 复制代码
{
  "type": "extension_ui_response",
  "id": "uuid-1",
  "value": "转人工复核"
}

RPC 让 Agent Runtime 与界面解耦。同一个 Pi 后端可以连接终端、桌面软件、编辑器插件或者企业自己的网页。

但需要注意:当前进程中的 UI 等待,和能够跨进程重启、跨天恢复的持久化审批,不是同一种能力。这一点正是 Pi 与 LangGraph 的重要边界之一。

四、Pi 如何实现企业知识库 RAG

Pi 不是向量数据库,也不应该承担所有文档解析和权限管理。更合理的架构是:

text 复制代码
Pi:对话、推理和工具调度
RAG 服务:文档解析、索引、权限、检索和重排
身份系统:用户、租户、组织和角色
业务系统:工单、ERP、CRM、审批等真实数据与副作用

4.1 离线知识摄取

text 复制代码
企业网盘 / Wiki / PDF / Word / 数据库
  → 连接器同步
  → 文本、标题、表格和 OCR 解析
  → 按语义和标题结构分块
  → 补充文档元数据和 ACL
  → 生成 Embedding
  → 建立关键词与向量索引

一个企业 Chunk 不应该只有文本和向量,还应保存:

json 复制代码
{
  "chunkId": "expense-policy#3.2",
  "documentId": "expense-policy",
  "title": "员工差旅报销制度",
  "content": "......",
  "source": "https://knowledge.example/expense-policy",
  "tenantId": "tenant-a",
  "allowedGroups": ["all-employees"],
  "department": "finance",
  "version": "2026-08",
  "updatedAt": "2026-08-20T10:00:00+08:00"
}

4.2 在线问答

text 复制代码
用户问题
  → Pi 调用 kb_search
  → RAG 服务读取可信登录态
  → ACL 权限过滤
  → 关键词+向量混合检索
  → Reranker 重排
  → 返回少量证据片段和来源
  → Pi 根据证据生成回答与引用

在 Pi 中可以注册一个自定义工具。下面是简化示例:

ts 复制代码
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { Type } from "typebox";

export default function (pi: ExtensionAPI) {
  pi.registerTool({
    name: "kb_search",
    label: "企业知识库检索",
    description:
      "搜索企业内部知识库。回答内部政策、产品和流程问题前调用。",
    parameters: Type.Object({
      query: Type.String({
        description: "完整且适合检索的问题",
      }),
      topK: Type.Optional(
        Type.Number({ minimum: 1, maximum: 10 }),
      ),
    }),

    async execute(_toolCallId, params, signal) {
      const response = await fetch(
        "https://knowledge.internal/api/search",
        {
          method: "POST",
          signal,
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${process.env.KB_SERVICE_TOKEN}`,
          },
          body: JSON.stringify({
            query: params.query,
            topK: params.topK ?? 6,
          }),
        },
      );

      if (!response.ok) {
        throw new Error(`检索失败:${response.status}`);
      }

      const data = await response.json();

      return {
        content: [
          {
            type: "text",
            text: JSON.stringify({ results: data.results }),
          },
        ],
        details: data,
      };
    },
  });
}

4.3 为什么要把 RAG 做成独立服务

这样做至少有五个好处:

  1. 检索能力可以被 Pi、网页搜索框、客服机器人等多个入口复用;
  2. 权限逻辑集中在可信服务端,而不是依赖 Prompt;
  3. 文档更新和重新索引不影响 Agent Runtime;
  4. 可以独立评测召回率、重排质量和检索延迟;
  5. 更换 Pi、LangGraph 或模型时,企业知识层不需要重做。

4.4 企业 RAG 中最容易被忽略的安全问题

不要让模型自己传入用户身份:

json 复制代码
{
  "query": "查询董事会薪酬制度",
  "userId": "admin"
}

userIdtenantId 和权限组必须来自登录态、网关或服务端 Token。否则用户可能通过 Prompt 诱导模型修改参数,实现越权检索。

权限过滤也必须发生在检索层,而不是先把所有结果返回模型,再要求模型"忽略无权内容"。只要敏感内容进入模型上下文,就已经发生了数据暴露。

五、LangGraph 与 Pi 的核心差异

如果只问"能不能写出来",Pi 扩展可以执行任意 TypeScript,理论上可以继续实现状态机、数据库、队列和恢复机制。因此,很难说某个功能在绝对意义上 Pi 永远做不了。

但工程选型应该比较的是:哪些能力由框架提供,哪些需要项目自己维护。

维度 Pi Agent LangGraph
核心抽象 Agent、Messages、Model、Tools、Events State、Nodes、Edges、Commands、Subgraphs
控制流 模型通常决定下一工具 固定边、条件边、规则或模型共同决定
工具调用 原生,Coding Agent 体验成熟 原生,但需要自行组装产品界面
自定义交互 扩展 UI、Question Tool、RPC Interrupt 返回任意可序列化信息
并行能力 可并行执行工具 原生 fan-out/fan-in、superstep、reducer
会话保存 Messages 与会话树 完整图状态 Checkpoint
失败恢复 业务级恢复需要自行实现 可从检查点恢复节点执行
长期人工等待 需要外部数据库和恢复协议 Checkpointer + interrupt 原生组合
时间旅行 会话历史分支 工作流状态检查、重放和分叉
流程强约束 Prompt 或外部代码 图拓扑直接约束
最适合 开放式工具任务、Coding、MVP 长流程、审批、故障恢复、审计

六、LangGraph 真正原生解决、Pi 需要自己补齐的能力

6.1 显式且强制的业务状态机

假设退款流程规定:

text 复制代码
身份校验
  → 订单查询
  → 规则检查
  → 金额超过阈值时人工审批
  → 执行退款
  → 写入审计

如果只给 Pi 一段 Prompt:"务必先校验,再审批,最后退款",模型仍然可能由于上下文、工具描述或异常情况跳过步骤。

LangGraph 可以把顺序直接写成图。模型只负责某个节点内部的开放式判断,不能越过不存在的边。

6.2 并行分支与确定性的状态合并

企业问题可能需要同时查询:

text 复制代码
订单系统 ─┐
设备系统 ─┼─► 汇总诊断
知识库   ─┘

Pi 可以并行执行多个工具,但 LangGraph 进一步定义了并行节点属于同一个 superstep,以及不同节点对共享状态的更新怎样通过 Reducer 合并。

这使得"并行执行"和"并行工作流状态管理"成为两个不同层次的问题。

6.3 持久化检查点与故障恢复

LangGraph 的 Checkpointer 可以在执行步骤边界保存图状态:

json 复制代码
{
  "currentStep": "human_review",
  "ticketId": "T-1001",
  "retrievedEvidence": ["chunk-1", "chunk-9"],
  "confidence": 0.63,
  "approvalStatus": "waiting"
}

如果服务重启,可以从当前 Thread 的检查点恢复,而不是重新执行已经完成的查询。

Pi 能保存会话和工具消息,但这不自动等于完整业务状态检查点。项目仍需回答:

  • 当前业务节点是什么?
  • 哪些并行任务已经成功?
  • 哪个 API 调用不能重复?
  • 恢复后应该重试、跳过还是补偿?
  • 审批结果属于哪个业务版本?

6.4 跨天 Human-in-the-loop

Pi 的 select() 很适合当前交互会话中的选择。

但是如果任务需要等待两天,期间服务可能发布、扩容或重启,仅仅在内存中等待一个 Promise 并不可靠。

LangGraph 的 interrupt() 会把图状态写入 Checkpointer,通过 thread_id 恢复。人工可以查看、批准、拒绝甚至修改状态后,再从相同流程位置继续。

6.5 时间旅行与问题排查

当一个生产 Agent 给出错误决定时,排查问题不能只看最终对话。往往需要知道:

text 复制代码
当时的状态是什么?
哪个节点修改了哪个字段?
采用了哪条条件分支?
如果修改某个状态,后续结果会怎样变化?

LangGraph 的状态历史和检查点可以支持回看、重放和分叉。Pi 的会话树适合对话历史导航,但业务工作流状态仍需应用自行建模。

七、三个选型场景

场景一:简单企业知识问答

需求:员工询问制度,系统检索知识库并返回引用。

text 复制代码
问题 → kb_search → Pi 生成带引用答案

选择:Pi + 独立 RAG 服务。

原因是流程很短,主要不确定性来自自然语言理解和检索,没有必要为了两个节点引入完整图编排。

场景二:跨系统售后工单

需求:识别问题、补齐信息、查询设备与订单、检索 SOP、判断保修、人工审批、创建派工单,流程可能持续数天。

选择:LangGraph 更合适。

这里的主要难点已经不是模型会不会调用工具,而是状态、顺序、恢复、幂等和审计。

场景三:既要可靠流程,又要开放式推理

选择:LangGraph 编排 + Pi Agent 节点。

text 复制代码
LangGraph
  ├── 权限校验节点
  ├── 订单查询节点
  ├── Pi 开放式诊断节点
  ├── 人工审批节点
  ├── 业务执行节点
  └── 审计节点

在这种结构里:

  • LangGraph 管理必须可靠的业务流程;
  • Pi 负责需要模型自主探索和多工具推理的局部任务;
  • RAG 服务继续保持独立;
  • 所有真实写操作使用幂等键并接受权限控制。

八、为什么不能只用 Prompt 控制流程

Prompt 是柔性约束,程序拓扑和权限策略才是硬约束。

适合写进 Prompt 的内容包括:

  • 回答风格;
  • 如何引用资料;
  • 什么时候建议调用某个工具;
  • 证据不足时应该怎样表达。

不应该只依赖 Prompt 的内容包括:

  • 是否允许查看某份敏感文档;
  • 是否必须经过审批;
  • 是否允许退款或创建工单;
  • 某个步骤失败后是否能够继续;
  • 恢复执行时是否会重复扣款或重复创建记录。

这些要求必须落实到权限系统、状态机、幂等机制和持久化层。

九、如何通过一个小实验做选型

不要只阅读框架介绍,可以选一条脱敏流程,同时用两种方式实现:

text 复制代码
客户报修
  → 补齐序列号
  → 查询保修
  → 检索 SOP
  → 给出处置建议
  → 人工批准
  → 创建模拟派工单

两组使用相同模型、Prompt、知识库和工具。

Pi 组

  • 用工具描述和 Prompt 引导流程;
  • 用自定义工具实现检索和模拟派工;
  • 自己补充审批状态、恢复和幂等逻辑;
  • 记录为此新增的框架外代码。

LangGraph 组

  • 把业务事实放入 Typed State;
  • 把查询、检索、审批和执行拆成节点;
  • 使用 Checkpointer 和 interrupt;
  • 在多个位置主动终止进程,验证恢复行为。

建议比较的指标

类别 指标
正确性 任务完成率、工具参数正确率、引用准确率
恢复 崩溃恢复成功率、重复副作用次数、审批续跑正确率
工程 胶水代码量、新增分支改动面、测试和调试时间
运行 P50/P95、Token、模型调用次数、基础设施成本
治理 权限拦截、审批记录、Trace 完整度、人工接管体验

正确的问题不是谁的 Demo 代码更短,而是谁在目标 SLA 和风险等级下拥有更低的完整系统成本。

十、最终结论

Pi Agent 的优势是轻量、直接、交互性强、工具扩展方便,能够快速构建 Coding Agent、内部助手和企业知识问答。

LangGraph 的优势是显式状态、确定性流程、并行汇合、持久化检查点、故障恢复、长期人工介入以及工作流级别的观察和重放。

所以:

text 复制代码
单 Agent + 开放式工具任务
    → 优先 Pi

简单 RAG 问答
    → Pi + 独立检索服务

固定步骤 + 分支 + 审批 + 恢复 + 审计
    → 优先 LangGraph

复杂业务流程中包含开放式 Agent 推理
    → LangGraph 编排 + Pi 节点

与其争论"谁会替代谁",更值得掌握的是 Agent Loop、Tool Calling、状态建模、权限、幂等、Checkpoint、Human-in-the-loop 和 RAG 检索。这些知识不会因为下一个 Agent 框架出现而失效。

相关推荐
xiaoye-duck2 小时前
《Linux 网络编程》深入传输层 UDP 协议原理:端口、报文、缓冲区与内核源码解析
linux·网络·udp
好评1242 小时前
【Linux】数据链路层
linux·运维·网络
天衍四九-2 小时前
第一章:从 LLM 到 Agent —— DeepSeek Harness 入门
网络·数据库·人工智能·python
Jae den2 小时前
网络丢包是什么?
网络
Wang's Blog3 小时前
Java框架快速入门: Spring Security+OAuth2之过滤器与过滤器链
java·开发语言·spring
谢尔登3 小时前
01_Java基础速通
java·开发语言
lemon_sjdk4 小时前
javafx-Image图像(2)
java·javafx
小七在进步4 小时前
C++入门(2)
java·jvm·c++
XR1234567884 小时前
医院无线整网高密覆盖选型深度解析
运维·网络