Pi Agent 系统提示词实战:替换默认编程助手人设,构建 DataAgent

我是安徽最忧郁程序员无隅

目录

前言

用 Pi Agent SDK 做企业数据分析助手时,模型可能仍按"编程助手"的习惯回答:谈文件、命令和代码,却没有先核对业务数据。问题往往在系统提示词的基础人设。本文以 Pi Agent v0.87.1 为准,沿着"看清提示词来源 → 替换人设 → 按用户装配"的顺序,做出一个简化的 DataAgent,并说明提示词与真实数据权限的边界。

一、为什么要替换默认人设

Pi Agent 的默认系统提示词把模型定义为编程助手,适合读文件、执行命令、改代码。企业数据分析场景期待的行为却不同:面对"上月销售额下降了 15%,为什么",助手应该先辨认这个数字是否可靠、比较口径是否一致,再提出可验证的原因。如果直接给出"某产品销量下滑"这样的确定结论,就把猜测当成了事实。

系统提示词会影响模型如何理解自己的职责,因此替换基础人设是定制垂直 Agent 的第一步 。它能约束回答方式,却不能凭空提供真实销售数据,也不能替代数据库的访问控制。Pi v0.87.1 的提示词构建源码可以看到默认编程助手前缀和自定义前缀的分支。

二、系统提示词怎样进入 Session

替换之前,先分清"基础人设"和其他来源。下面这张图按 Pi v0.87.1 的构建顺序概括五个主要部分;图中的箭头表示段落组合顺序 ,不是五个运行步骤。构建逻辑、资源加载逻辑

第一段是基础人设。资源加载器先找可用的自定义内容:代码传入的 systemPromptOverride 优先;没有覆盖时,可使用显式 systemPromptSource,或自动发现的项目级 .pi/SYSTEM.md、全局 SYSTEM.md。这些都没有时,构建器才使用默认编程助手前缀。项目级文件只有项目被信任时才参与自动发现;全局文件会影响使用同一全局配置目录的会话。因此,多项目并行开发时,优先考虑代码覆盖或项目级文件。资源加载器源码

后面几段各有职责:

部分 常见来源 应检查什么
追加规则 .pi/APPEND_SYSTEM.md、全局同名文件,或代码覆盖 是否混入了与业务角色冲突的规则
项目上下文 工作目录及其父目录、全局配置目录中的 AGENTS.md / CLAUDE.md 是否带入了代码仓库的开发指令
技能摘要 已加载的技能 只有启用 read 或 bash 等可读取技能文件的工具时才会加入
工作目录 Loader 的 cwd 模型是否需要知道目录;路径是否适合暴露

这里最容易误解的是"覆盖"二字。systemPromptOverride 改的是基础人设 ;追加规则、项目上下文、技能和工作目录仍按各自条件构建。若要做职责清晰的业务 Agent,应该检查实际加载了哪些来源,而不是假定覆盖后整份系统提示词只剩自己写的两句话。系统提示词源码

三、用 systemPromptOverride 定义 DataAgent

下面是一个最小的 SDK 示例。运行前需要有可用模型;示例用 noTools: "all" 关闭工具,先单独观察提示词对回答方式的影响。保存为 04a-replace-prompt.ts,在已安装 @earendil-works/pi-coding-agent@0.87.1 和 tsx 的项目中运行 npx tsx 04a-replace-prompt.ts。官方自定义提示词示例

typescript 复制代码
import {
  createAgentSession,
  DefaultResourceLoader,
  getAgentDir,
  ModelRuntime,
  SessionManager,
} from "@earendil-works/pi-coding-agent";

const runtime = await ModelRuntime.create();
const model = (await runtime.getAvailable())[0];
if (!model) throw new Error("请先配置可用模型");

const loader = new DefaultResourceLoader({
  cwd: process.cwd(),
  agentDir: getAgentDir(),
  systemPromptOverride: () => `你是企业数据分析助手。
用户提供的数字未经核实;没有数据就不下确定结论。
最多列出三个可能原因,每个原因附一个验证方法。`,
  appendSystemPromptOverride: () => [],
});
await loader.reload();

const { session } = await createAgentSession({
  model,
  modelRuntime: runtime,
  resourceLoader: loader,
  sessionManager: SessionManager.inMemory(),
  noTools: "all",
});

try {
  session.subscribe((event) => {
    if (event.type === "message_update" &&
        event.assistantMessageEvent.type === "text_delta") {
      process.stdout.write(event.assistantMessageEvent.delta);
    }
  });
  await session.prompt("上月销售额下降了 15%,可能的原因有哪些?");
  console.log();
} finally {
  session.dispose();
}

理解这段代码,抓住三处数据流即可。systemPromptOverride 返回新的基础人设;appendSystemPromptOverride: () => [] 把 Loader 发现的追加规则清空;resourceLoader: loader 把这份配置交给 Session。reload() 先完成资源加载,随后创建会话。资源加载器源码、SDK 说明

观察回答时,重点看它是否把"下降 15%"当作用户提供、尚待核实的前提,是否区分可能原因与已证实原因,是否给每个原因提供数据验证路径。即使回答符合这些要求,也只验证了回答方式;没有真实业务数据,就无法验证原因是否正确。 示例关闭了工具,因此也不会调用数据库或把技能摘要加入系统提示词。

如果人设是固定文本,也可以把它放在项目的 .pi/SYSTEM.md。这适合静态角色说明。需要按用户、部门或会话状态生成不同内容时,代码覆盖更直接,因为返回值可以在创建会话前由程序拼装。

四、按用户装配提示词,并守住权限边界

同一个数据分析助手服务销售部和财务部时,人设与工作规则大体相同,用户身份和允许讨论的数据范围却不同。把稳定内容放在文件中,把动态信息从已认证的服务端上下文取出,最后组合成一份提示词。这张图上半部分表示提示词的两条输入支路;下半部分是独立的数据访问链路。

例如,prompts/analyst/ 下放三份文本:persona.md 写"你是谁",rules.md 写分析规则,output-format.md 写回答格式。读取文件并取得当前用户后,关键拼装代码可以写成:

typescript 复制代码
import { readFile } from "node:fs/promises";
import { join } from "node:path";

const dir = join(process.cwd(), "prompts", "analyst");
const [persona, rules, outputFormat] = await Promise.all([
  readFile(join(dir, "persona.md"), "utf8"),
  readFile(join(dir, "rules.md"), "utf8"),
  readFile(join(dir, "output-format.md"), "utf8"),
]);

// user 必须由服务端认证与权限系统提供;这里仅展示拼装位置。
const user = { department: "销售部", dataScope: "本部门销售数据" };
const fullPrompt = [
  persona,
  `## 当前用户\n部门:${user.department}\n数据范围:${user.dataScope}`,
  rules,
  outputFormat,
].join("\n\n");

const loader = new DefaultResourceLoader({
  cwd: process.cwd(),
  agentDir: getAgentDir(),
  systemPromptOverride: () => fullPrompt,
  appendSystemPromptOverride: () => [],
});
await loader.reload();

这里的 Promise.all 让三份静态文件并行读取;fullPrompt 则把它们与当前用户信息组合起来。示例中的 user 是演示数据。真实服务中,应在认证后取得用户身份及授权范围,并为该用户的请求构建对应会话;不要把前一位用户的提示词或会话状态复用到下一位用户。

"只讨论本部门数据"写进提示词,属于模型行为约束。 当 Agent 能调用数据工具时,服务端仍须根据认证身份校验查询条件,并让数据工具只返回被授权的数据。模型可能误解或忽略文字规则,权限判断应发生在真正读取数据之前。提示词可以解释边界,实际的数据访问必须由程序执行。

最后看一个可选细节。Pi v0.87.1 将工作目录放在结构化的 cwd 段中。如果业务 Agent 不需要向模型展示目录值,可以在 before_agent_start 钩子中把本轮的 event.systemPromptOptions.cwd 设为空字符串;这会清空目录值,但可能留下空的 <cwd> 段 。它也不会改变工具实际使用的工作目录,后者仍由 Loader 的 cwd 决定。原材料中针对 v0.83 整段字符串做正则替换的示例,不应直接照搬到这个版本。系统提示词构建源码、扩展事件源码

到这里,DataAgent 已有自己的角色说明,也能组合不同用户的上下文。下一步若要让它分析真实销售数据,需要给 Session 接入受控的数据工具,并在工具层落实查询权限。

参考资料: Pi Agent v0.87.1 SDK 文档;系统提示词构建源码;资源加载器源码。

相关推荐
Summer-Bright3 小时前
深度 | 壁仞1.74亿中标智算中心:国产GPU从能用跨进商用,但4.5亿的大单却因凑不齐三家废标了
数据库·ai·国产gpu
樱花落木兰3 小时前
SpringBoot + ECharts 后台数据统计报表模块实战
java·javascript·spring boot·ai·log4j·github·echarts
玩AI的奶茶3 小时前
配一次环境像装修一次房:哪些云 GPU 平台能把它留下来?
人工智能·ai·gpu算力·token·算力租赁
LucianaiB3 小时前
用 HarmonyOS 做一张会写诗的月夜明信片:追月的完整开发复盘
华为·ai·harmonyos·skill
敲代码的小霖4 小时前
NovaNova Studio开源免费漫剧短剧生成平台
ai·开源软件·视频生成·图片生成·ai短剧·无线画布
土星云SaturnCloud4 小时前
边缘计算 + AI 视频存管一体机:快递末端网点分拣提效与安全管控实战方案
服务器·人工智能·ai·边缘计算
2601_965742225 小时前
短视频脚本创作方法分享:本地生活类账号的起步思路
大数据·人工智能·算法·ai·新媒体运营·生活
小杉泽6 小时前
工具返回值二次提示注入:Agent 未确认外发攻击链的红队复现与修复
ai·ai安全
GISer_Jing6 小时前
前端Agent架构师指南:从零搭建智能前端Agent
前端·ai·langchain