惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

云风的 BLOG
云风的 BLOG
C
Cyber Attacks, Cyber Crime and Cyber Security
Recent Announcements
Recent Announcements
爱范儿
爱范儿
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Security Latest
Security Latest
J
Java Code Geeks
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Cisco Talos Blog
Cisco Talos Blog
Apple Machine Learning Research
Apple Machine Learning Research
C
Check Point Blog
T
Threat Research - Cisco Blogs
I
Intezer
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
WordPress大学
WordPress大学
Engineering at Meta
Engineering at Meta
腾讯CDC
Google DeepMind News
Google DeepMind News
Project Zero
Project Zero
T
Tenable Blog
V
Visual Studio Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
Spread Privacy
Spread Privacy
GbyAI
GbyAI
T
Tailwind CSS Blog
P
Palo Alto Networks Blog
Microsoft Security Blog
Microsoft Security Blog
Scott Helme
Scott Helme
Hugging Face - Blog
Hugging Face - Blog
NISL@THU
NISL@THU
Blog — PlanetScale
Blog — PlanetScale
G
GRAHAM CLULEY
K
Kaspersky official blog
T
The Exploit Database - CXSecurity.com
S
Schneier on Security
P
Proofpoint News Feed
S
SegmentFault 最新的问题
P
Proofpoint News Feed
P
Privacy & Cybersecurity Law Blog
The Hacker News
The Hacker News
博客园 - 【当耐特】
Cyberwarzone
Cyberwarzone
L
LangChain Blog
Stack Overflow Blog
Stack Overflow Blog
V
Vulnerabilities – Threatpost
H
Help Net Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Last Week in AI
Last Week in AI
博客园 - 叶小钗

博客园_首页

Plist 二进制格式 Milvus 和 PGVector,哪个更好? OpenClaw 已过时?在 VS Code 中运行 Hermes Agent! 第30篇文章:一个大三计科生的自白 Manim如何在数学公式中完美显示中文? Docker 部署 RocketMQ 5 并发编程核心概念辨析 C#事务处理最佳实践:别再让“主表存了、明细丢了”的破事发生 CLI 是什么?为什么大厂突然集体卷命令行? 【从0到1构建一个ClaudeAgent】协作-自主Agent UIImageView 设置图片不生效的原因排查 最小二乘问题详解20:无先验约束下的增量式SFM自由网平差 痞子衡嵌入式:大话双核i.MXRT1180之XIP应用里借助MU实现可靠Flash IAP的方法 AI Chat 封装, SemanticKerne.AiProvider.Unified 已发布 Windows下右键编辑js文件无法打开记事本——在注册表中使用环境变量 在后台服务中使用 Scoped 服务,为什么总是报错? H200 安装驱动并使用sglang启动模型 wireshark 抓包Trap上报告警内容 我用 AI 辅助开发了一系列小工具(2):图片压缩工具 [A Primer On MC and CC] 2.1 Memory Consistency 1 - 指令重排序和 SC 模型 Oracle数据库SCN推进技术详解与实践指南 玩转控件:封装个带图片的Label控件 Claude Code 4.7 真正该升级的不是模型,而是你的工作流 前端小白一句话,AI 帮我做了个颜值拉满的桌面媒体播放器。当代码不再是门槛,一句话编程就是现实。 5. WorkBuddy: 小龙虾的灵魂三件套,让你的小龙虾不只是工具 SQLite 分片方案实战:三种分片策略的深度对比 告别简陋 UI!一款基于 Fluent Design 和基于 WinUI 的开源免费、现代化的 Avalonia UI 控件库 关于二进制排列组合枚举的总结 AI开发-python-LangGraph框架(3-27-LangGraph从零实现大模型智能决策工作流) ElasticSearch主分片和副本分片概念详解 【002】HTTPS 粗解:证书、TLS 握手与对后端配置的影响 Hermes Agent 一周暴涨五万 Star,但我劝你别急着追 明明连接的是Redis的DB0,为什么能查到DB3的数据? 【从0到1构建一个ClaudeAgent】协作-Agent团队 熟悉电子元器件之后,电子小白下一步该怎么走? MAF快速入门(23)通过C#类定义Skills .NET 高级开发 | 手写一个对象映射框架 FastAPI数据库ORM怎么选?我肝了三个Demo后,终于不再纠结了 mysqldump 参数拾遗:在遗忘与铭记之间 C# .NET 周刊|2026年3月5期 Claude code入门 - 陈彦斌 一文学习入门 ThingsBoard 开源物联网平台 GitHub 热门项目 | 2026年04月16日 如何为GIT设置全局勾子,为每次提交追加信息 Number.isFinite和isFinite与isNaN()和Number.isNaN的区别 PortSwigger SQL注入LAB2 推荐一个测试人必备的Skills,从功能到性能全搞定(附详细实操和安装下载方式) 筑基期:掌握Odoo基础核心知识点02(Odoo XML 开发方式详解) GLM模型这么火,咱们用vllm也咧一个呗! 深入理解 AbortController:从底层原理到跨语言设计哲学 字符串学习笔记 多租户系统框架的基础模块设计和分析设计 Apache SeaTunnel Zeta 为什么能做到“又快又稳”? AI开发-python-LangGraph框架(3-26-LangGraph基本概念及第一个简单样例) Vue 3 组件通信,别只会用 Props 和 Emits 了,这几个狠活儿你得看看 ElasticSearch7.X版本配置密码 用Manim实现动态交点计算--从一个动点问题说起 团结引擎+Addressable+Instant Game打包抖音小游戏 function call 实战:让 LLM 自动判断 pod 异常、调用日志工具并完成故障分析 bubseek —— 让 Agent 的足迹,变成团队的洞察 通过 C# 读取并导出 PDF 书签 如何用 GitHub Actions 实现 Steam 自动化发布 【从0到1构建一个ClaudeAgent】并发-后台任务 .NET 高级开发 | 定制 ASP.NET Core 框架 电子小白:什么是运算放大器(运放) zero2Agent:面向大厂面试的 Agent 工程教程,从概念到生产的完整学习路线 堆上的ORW HC32F460 USB CDC通信异常:非对齐访问异常排查 20260413-Hyperbridge 攻击事件:发生在默克尔山上的验证绕过 那些喊着AI 要淘汰你的人,正在靠你的焦虑赚大钱! 深度学习进阶(八)Swin Transformer 最小二乘问题详解19:带先验约束的增量式SFM优化与实现 SnapTranslate 3.0 正式发布:全局划词翻译 + 完整英语学习闭环,一站式搞定查词、记词、复习 工作的意义、工作的困难认知再思考 .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 开了 TUN 模式还是直连?90% 的人都踩过这个坑 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术
将 Pi Agent 接入 HagiCode 的实践之路
Newbe36524 · 2026-06-08 · via 博客园_首页

将 Pi Agent 接入 HagiCode 的实践之路

本文分享我们在 HagiCode 项目中将 Pi agent 作为一等工作流入口接入的实践经验,包括架构设计、核心组件实现和前后端适配细节。

背景

其实一切都要从那个问题说起:在 HagiCode Mono 项目中,虽然 repos/Hagicode.Libs 已经实现了可复用的 PiProvider,可是 repos/hagicode-corerepos/web 还没有将 Pi 提升为项目级一等 Agent CLI。这就像你有了一双好鞋,却还没系好鞋带,虽然能走路,但总觉得差点什么。

现有的 PiProvider 位于 HagiCode.Libs/src/HagiCode.Libs.Providers/Pi/PiProvider.cs,它实现了基于行分隔 JSON(--mode json --print)的 CLI 通信协议,支持会话管理、工具调用和流式输出。这部分代码写得很好,只是它还躺在那里,没有被唤醒。

这种状况造成了一个断层:Pi 的底层能力是完整的,但项目级的接入链路(从用户配置到执行监控)是缺失的。这就像画了一幅好画,却没挂在墙上让人欣赏。所以需要将 Pi 作为新的活跃 provider PiCli 接入整个系统,使其成为与其他 Agent CLI 一等的工作流入口。

毕竟,我们想要的是完整的体验,而不是零散的片段。

关于 HagiCode

本文分享的方案来自我们在 HagiCode 项目中的实践经验。HagiCode 是一个智能代码助手项目,在开发过程中我们需要整合多种 AI 能力提供商。本文所述的 Pi agent 接入方案,正是我们在实践中总结出来的一套可复用的集成模式,对于类似的多 provider 集成场景具有参考价值。项目的 GitHub 地址是 github.com/HagiCode-org/site

架构设计

Pi agent 对接采用了 thin adapter 模式,而不是在 core 层重新实现 Pi 进程协议。这个设计决策其实也没什么复杂的,就是想了想,何必重复造轮子呢?

毕竟:

  1. 避免重复实现PiProvider 中的参数构建、进程启动、JSON 解析和错误处理逻辑已经很完整,重复实现会制造两套行为源和两套测试矩阵。这也罢了,但维护起来会很麻烦。
  2. 保持一致性:与 Kimi、Gemini、Reasonix、DeepAgents 等现有 CLI 的接入方式保持一致,都是通过 thin adapter 委托给 libs 层的实现。大家都这么做,跟着走就是了。
  3. 关注点分离hagicode-core 专注于运行时契约和业务逻辑,进程细节交给 HagiCode.Libs 处理。各司其职,岂不美哉?

这种设计让 HagiCode 在保持核心层简洁的同时,能够快速集成新的 AI 能力提供商。毕竟,简洁是美,效率是钱。

核心组件实现

Provider 枚举和 Factory

hagicode-core/src/PCode.Models/AIProviderType.cs 中新增了 PiCli = 13 枚举值:

public enum AIProviderType
{
    ClaudeCodeCli = 0,
    // ... 其他 provider
    PiCli = 13,
}

这个枚举值是 provider 身份的根源,会影响 OpenAPI 生成的 PCode_Models_AIProviderType.ts 前端枚举、AIProviderFactory 的创建分支,以及 Provider 解析和活跃 provider 判断逻辑。在 AIProviderFactory 中注册新的创建分支:

case AIProviderType.PiCli:
    provider = new PiCliProvider(
        logger,
        configuration,
        providerFactory.GetRequiredService<ICliProvider<PiOptions>>(),
        providerFactory.GetService<IAgentCliRuntimeEnvironmentResolver>());
    break;

其实这些代码也没什么特别的,就是一个枚举加一个 switch case 而已。只是它们很重要,就像乐谱上的音符,一个个加起来才能演奏出完整的曲子。

Thin Adapter 实现

PiCliProvider.cs 是核心的 thin adapter,它实现了 IAIProviderIVersionedAIProviderIAsyncDisposable 接口。通过构造函数接收 ICliProvider<PiOptions>(来自 HagiCode.Libs),将 AIRequest / ProviderConfiguration 映射到 PiOptions,然后委托执行、ping、版本查询等操作给底层 provider。

关键是要处理 Pi 特有的 JSON 事件流,包括 assistant.thoughtassistantterminal.completed 等事件。这些事件在流式输出过程中需要被正确解析和转换为系统的标准格式。这有点像翻译,把一种语言翻译成另一种语言,意思要传达到位才行。

主职业预设

main-professions.yaml 中增加了 profession-pi 主职业条目:

- Id: "profession-pi"
  Name: "Pi"
  Family: "pi"
  Summary: "hero.professionCopy.primary.pi.summary"
  Icon: "executor-avatar:Pi"
  SourceLabel: "hero.professionCopy.sources.aiProvidersPiCli"
  ProviderType: "PiCli"
  SortOrder: 59
  DefaultEnabled: true
  DefaultParameters:
    binary: "pi"
    provider: "omniroute"
    thinking: "balanced"

这确保了后端快照与前端 fallback 目录有一致的 Pi 身份,可以通过现有 Hero 编辑器管理 Pi 配置,而且 Pi 的加入不会破坏现有主职业条目的可消费性。毕竟,我们不想因为新增一个功能就把原来的东西弄乱了,那样就因小失大了。

监控注册表

AgentCliMonitoringRegistry 需要增加 Pi 的监控 descriptor,使系统能够解析可执行路径、展示品牌名、进行健康探测,并在状态栏和健康详情中显示 Pi 状态:

new AgentCliMonitoringDescriptor(
    CliId: "pi",
    DisplayName: "Pi",
    ProviderType: AIProviderType.PiCli,
    DisplayOrder: 13,
    Strategy: AgentCliMonitoringStrategy.Grain,
    NotConfiguredMessage: "Pi CLI is not configured or executable not found.",
    EnabledPaths: [],
    ExecutablePathConfigPaths: ["Hero:PrimaryProfessions:Pi:ExecutablePath"],
    DefaultExecutablePath: "pi")

监控系统就像仪表盘,告诉你车子跑得怎么样。Pi 的状态一目了然,这样用户就能知道一切是否正常。

前端适配

执行器类型适配

前端需要更新 executorTypeAdapter.ts,添加 Pi 的类型识别逻辑:

const PI_IDS = new Set<string>([
  PCode_Models_AIProviderType.PI_CLI,
  'Pi',
  'PiCli',
  'pi',
  'picli',
  'pi-cli',
]);

export function isPi(value: string): boolean {
  const normalized = normalize(value);
  const normalizedLower = normalized.toLowerCase();
  return PI_IDS.has(normalized)
    || normalizedLower.includes('pi-cli')
    || normalizedLower.includes('picli')
    || normalizedLower === 'pi';
}

这就像给 Pi 起了好几个名字,不管你怎么叫它,它都知道你是在叫它。毕竟,叫什么名字不重要,重要的是知道你是谁。

Fallback Hero 目录

hero.ts 中添加 Pi 的 fallback 条目,确保即使后端数据未加载,前端也能正常显示 Pi 配置:

{
  id: "profession-pi",
  name: "Pi",
  family: "pi",
  summary: "hero.professionCopy.primary.pi.summary",
  icon: "executor-avatar:Pi",
  sourceLabel: "hero.professionCopy.sources.aiProvidersPiCli",
  providerType: AIProviderType.PI_CLI,
  sortOrder: 59,
  isReadOnly: true,
  managedParameterKeys: {
    // 首版支持的参数 key
  },
  defaultParameters: {
    binary: "pi",
    provider: "omniroute",
    thinking: "balanced",
  },
}

Fallback 就像备用计划,万一后端挂了或者数据没加载出来,前端也能正常工作。毕竟,谁也不想到时候手忙脚乱。

本地化文案和表单

locales/*/common/{hero,settings}.yml 中增加 Pi 相关的翻译,并在 HeroCliEquipmentForm.tsx 中为 Pi 新增配置字段区块,支持 binary、provider、thinking、sessionDirectory 和工具/会话开关字段。

首版 Pi 只暴露最小必要字段,复杂功能如工具 allowlist/denylist 和环境变量编辑器被明确延后到后续变更。毕竟,一口吃不成胖子,慢慢来比较快。

配置示例

后端配置

appsettings.yml 中配置 Pi 参数:

Hero:
  PrimaryProfessions:
    Pi:
      ExecutablePath: /usr/local/bin/pi
      Provider: omniroute
      Thinking: balanced
      SessionDirectory: ~/.pi/sessions
      NoSession: false
      DisableAllTools: false
      DisableBuiltinTools: false

前端配置

在 Hero 编辑器中配置 Pi profession:

{
  id: "my-pi-profession",
  name: "My Pi Profession",
  family: "pi",
  providerType: AIProviderType.PI_CLI,
  primaryModel: {
    provider: "PiCli",
    model: "glm-4.7",
    providerSettings: {
      provider: "omniroute",
      thinking: "balanced",
      sessionDirectory: "/Users/username/.pi/sessions",
      noSession: false,
      disableAllTools: false,
      disableBuiltinTools: false,
    },
  },
}

配置文件就像菜谱,照着做就能做出好菜。只是有时候,就算照着菜谱,也会把菜做糊......不过这次的配置倒是很清晰,应该没什么问题。

验证和测试

后端验证

在测试中验证主职业预设:

var snapshot = await presetProvider.GetSnapshotAsync();
var piProfession = snapshot.FindById("profession-pi");
piProfession.ShouldNotBeNull();
piProfession.ProviderType.ShouldBe(AIProviderType.PiCli);
piProfession.Family.ShouldBe("pi");

还需要验证 Pi 可用性和健康检查:

# 检查 Pi 可执行文件
which pi
pi --version

# 验证后端 provider 注册
curl http://localhost:35168/api/health/agent-cli/pi

测试就像考试,考过了才能说明真的会了。只是有时候,考试过了也未必真的懂了,不过至少说明你能做对题。

前端验证

// 验证类型解析和显示名称
expect(resolveExecutorVisualType('pi-cli')).toBe('Pi');
expect(resolveExecutorVisualType(PCode_Models_AIProviderType.PI_CLI)).toBe('Pi');
expect(resolveExecutorDisplayName('PiCli')).toBe('Pi');

// 验证 fallback 目录
const piFallback = findFallbackProfessionById('profession-pi');
expect(piFallback?.providerType).toBe(AIProviderType.PI_CLI);

这些测试用例覆盖了主要的逻辑路径,确保 Pi 能被正确识别和显示。毕竟,展示给用户的东西,不能出差错。

常见问题排查

Pi 可执行文件找不到

如果健康检查返回 "Pi executable was not found.",需要检查 PATH 中是否有 pi,或确认配置的路径是否正确。解决方法是确保 pi 已安装并在 PATH 中,或在 appsettings.yml 中配置正确的 ExecutablePath

这就像找不到家门钥匙,得想想是不是放错地方了。其实解决办法也挺简单的,要么把钥匙放回原来的地方,要么换把新锁。

配置字段不识别

如果启动时抛出 "PiCli runtime settings [...] are not supported" 错误,检查是否只使用了首版支持的配置字段。首版支持的字段包括:providerthinkingsessionDirectorynoSessiondisableAllToolsdisableBuiltinTools

有时候就是贪心,想要的功能太多,结果系统不支持。其实首版的功能已经够用了,贪多嚼不烂。

前端无法选择 Pi

如果 Hero 编辑器中没有 Pi 选项,检查是否已运行 npm run generate:api 重新生成前端枚举,hero.ts 中是否有 profession-pi 条目,以及本地化文案是否正确添加。

排查问题就像找丢失的物品,得一步步来。毕竟,瞎找是找不到的,得有逻辑地找。

最佳实践

  1. 使用 thin adapter 模式:不要在 core 层重新实现进程协议,委托给 libs 层的 provider。这样可以避免重复实现,保持代码一致性。毕竟,重复造轮子不仅累,还容易出问题。

  2. 保持命名一致性:前后端使用统一的命名约定,避免混淆。Provider 枚举用 PiCli,CLI ID 用 "pi",显示名称用 "Pi"。名字取得好,沟通成本就低。

  3. 优先使用预设:首版应基于 profession-pi 预设,而不是要求用户手工配置。这样可以让用户快速上手,减少配置复杂度。用户喜欢简单的事情,复杂的让他们来找我。

  4. 关注错误信息:确保错误信息清晰、可操作,帮助用户快速定位问题。错误信息写得清楚,用户就不会因为一个错误就抓狂。

  5. 版本兼容性:考虑到 AIProviderType 枚举值的序列化稳定性,变更需要谨慎处理。AIProviderType.PiCli = 13 的枚举值不能轻易修改。毕竟,改了这个值,可能会破坏向后兼容性,那就麻烦了。

总结

通过 thin adapter 模式,我们成功将 Pi agent 接入 HagiCode 系统,使其成为与其他 Agent CLI 一等的工作流入口。这套方案的核心优势在于:

  • 避免了重复实现,复用了 libs 层已有的 PiProvider
  • 与现有 provider 保持一致的接入方式,降低了维护成本
  • 实现了从用户配置到执行监控的完整链路

HagiCode 的这次实践证明,thin adapter 模式是集成 AI 能力提供商的有效方案。它让我们能够快速支持新的 agent,同时保持系统的稳定性和可维护性。

其实做技术就是这样,找到一个好的模式,然后复用它。这样既能快速前进,又不会迷失方向。就像走路,找到了一条好路,就一直走下去,只是偶尔也会停下来看看风景......

如果你也在做多 provider 的 AI 能力集成,希望这套方案能给你一些启发。如果你对 HagiCode 项目感兴趣,欢迎来 GitHub 交流。毕竟,技术这东西,多交流才有进步。

参考资料

总结

围绕“将 Pi Agent 接入 HagiCode 的实践之路”,更稳妥的推进方式是先把关键配置、依赖边界和落地路径逐步跑通,再补齐优化细节。

当目标、步骤和验收点都明确之后,这类方案通常就能更顺畅地进入实际交付。

原文与版权说明

感谢您的阅读,如果您觉得本文有用,欢迎点赞、收藏和分享支持。
本内容采用人工智能辅助协作,最终内容由作者审核并确认。