我到现在还记得那次需求评审会后的“对账现场”。产品改了一版 7000 字的 PRD,研发组长照着文档目录手写了 38 条任务,两天后需求文档又改了三个字段,任务表跟文档各说各话,最后几个人凑在一起逐条核对“这条到底还做不做、验收标准以哪版为准”。PingCraft 这个项目,最初就是冲着消除这种“文档-任务漂移”去的。简单说,它是一套把需求文档翻译成可追踪工作项的 Agent 管线,用语言模型做语义理解,用工程手段保证每一步都可校验、可回滚。如果你在搞 Agent 应用落地,或者在做研发效能工具、项目管理自动化,这篇文章里的拆解思路、设计取舍和踩坑记录,应该能提供一些参考。
1. 为什么需要一套“需求转工作项”的 Agent 管线
1.1 需求与工作项之间的“翻译损耗”
需求评审会上大家看着同一份文档,但散会后每个人带走的理解并不一致。产品经理脑子里想的是“用户在登录失败时要得到清晰反馈”,研发任务写出来常常变成“优化登录错误提示”,测试用例则可能完全没覆盖这个场景。这种损耗不是某个人的责任心问题,而是手工维护方式的结构性缺陷:需求文档是自然语言,工作项是结构化条目,两者之间本来就需要一次翻译。
我在团队里观察过很多次,手工拆需求时最容易丢三样东西:
- 验收标准被压缩成功能描述,测试阶段才重新补细节;
- 需求之间的依赖关系被隐去,排期后期才发现阻塞;
- 需求变更记录被抹平,没人知道某个任务对应的是文档的哪一版描述。
PingCraft 想解决的,就是让这次“翻译”不依赖个人状态,而是由 Agent 按统一协议完成,并且把翻译过程的中间产物全部保留下来。
1.2 为什么普通脚本和规则引擎做不了这件事
如果只是把文档里“需求”两个字后面的句子提取出来,用正则也能做个七七八八。但真实需求文档的表述方式极其发散,比如这一句:
“当用户连续输错三次密码后,页面需要在 3 秒内提示账户暂时锁定,并明确告知 15 分钟后再试。”
规则脚本很难判断“连续输错三次”是触发条件,“提示账户暂时锁定”是业务规则,“15 分钟后再试”是操作引导。这三个信息在任务卡片里应该分别落到前置条件、功能行为和辅助提示栏位中。Agent 的价值不在于比你更懂业务,而在于它能稳定地把这类复合语义拆解成结构化要素,并且每次处理都保持同样的逻辑。
但这里的重点不是“LLM 很强”,而是“LLM 不可靠”。所以我在设计 PingCraft 时一开始就定了一个原则:Agent 负责理解,工程负责校验。
1.3 PingCraft 想解决的三个具体问题
第一个是拆得准。需求拆成的工作项要覆盖完整,验收标准不能漏,依赖关系不能被丢掉。第二个是跟得住。从需求文档的某一段原文,到拆解出来的需求单元,再到项目管理工具里的工作项,最后到代码提交记录,这条链路要能一路回溯。第三个是改得动。需求文档更新后,系统要能指出哪些旧工作项受影响、哪些验收标准被替换,而不是让团队重新手工对账。
这三个问题分别对应了三条技术线:抽取与生成、血缘与锚点、变更与影响分析。接下来的章节,我会按这三个方向展开。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. PingCraft 的整体架构:一颗“会拆解”的大脑加两条“守纪律”的流水线
2.1 架构总览:Agent 只出草案,执行器才落库
PingCraft 整体上分为三层,我习惯用一张职责表来概括:
| 层级 | 主要模块 | 职责 |
|---|---|---|
| 输入层 | 文档解析器、切片器 | 把 Markdown、docx、Confluence 内容归一化成带锚点的干净文本 |
| 智能层 | 解读 Agent、拆解 Agent | 做语义理解,输出结构化需求单元和工作项草案 |
| 执行层 | 校验服务、写库执行器、Webhook 监听器 | 做格式校验、字段补全、幂等写入、状态回写 |
一个容易让人困惑的点是:为什么不让 Agent 直接调用 Jira 或 Tapd 的 API 创建任务?那样看起来链路更短。我踩过这个坑之后才想明白:Agent 擅长的是“不确定中找出路”,写数据库这件事恰恰要求“绝对确定且可回滚”。让 Agent 直接改项目管理工具,一旦抽取结果产生幻觉,测试任务、脏数据、错误状态会直接污染团队协作页面,清理成本远高于重建成本。
所以在 PingCraft 里,智能层永远只生成结构化草案,写操作统一由执行器完成。执行器可以配置成两种模式:半自动模式(草案进入人工确认队列)和自动模式(校验通过后直接创建)。即便在自动模式下,执行器也会保留完整的操作审计日志,所有 API 调用都走独立的最小权限令牌。
2.2 两个 Agent 的分工:解读不拆解,拆解不解读
一开始我也尝试过用一个 Supervisor Agent 包办所有事情,让它“读懂文档并拆好任务”。结果发现两个动作对上下文的要求是矛盾的:读懂整篇文档需要全局视野,拆好任务又必须聚焦到局部细节,混在一起很容易顾此失彼。
PingCraft 最终的方案是把工作拆给两个 Agent:
- 解读 Agent 的产出是一棵“需求单元树”。文档进来后,它会先识别 Epic、Feature、User Story 这种层级关系,为每一段需求提取摘要、验收标准、约束条件和依赖关系。
- 拆解 Agent 不直接接触原始文档,它拿到的输入是解读 Agent 产出的需求单元树,再基于一套“拆解策略模板”把需求单元映射成可执行的工作项,包括任务标题、描述、优先级建议、估时区间等。
两段式设计的核心好处是可测试性。解读错了还是拆解错了,通过对比中间层输出就能快速定位,不用把整个链路的日志翻个底朝天。
2.3 左右两条流水线:生成校验同构,文档代码双向同步
标题里说的“两条守纪律的流水线”,一条是生成线,一条是追踪线。
生成线负责干活:文档进,结构化草案出;草案先过校验器,再进人工确认或自动执行。追踪线负责记录:工作项创建成功后,所有血缘信息会被写入索引库,同时向代码仓库注册 Webhook。开发提交代码时如果在 commit message 里写明了工作项 ID,后端监听器会解析这些 ID,把提交记录关联到工作项,并触发状态流转。
这两条流水线互不阻塞。生成线不用等追踪线,追踪线也不会反过来修改需求文档。你只需要保证它们共用一个索引库和一套 ID 生成规则。
3. 从需求文档到结构化工作项:核心抽取与校验链路
3.1 文档预处理与切片策略:避免整篇文本暴力灌入
PingCraft 接到的第一篇真实需求文档是一份 80 多页的 Confluence 页面,直接丢给 Agent 之后,它沉默了五分钟然后返回了一个空数组。排查日志才发现,模型调用时把上下文窗口撑爆了。从那以后,所有文档都必须经过预处理层。
预处理分三步:
- 格式归一化,把 docx、PDF、Confluence HTML 统一转成带标题层级的干净 Markdown;
- 按标题层级切块,构建文档骨架树,每个叶子块控制在 800 字以内;
- 为每个块生成稳定锚点,锚点由“标题内容转 slug + 块内容哈希”拼接而成。
切片不能简单用固定字符数切断,那会破坏语义单元。我的做法是优先按 H2/H3 标题切割,碰到过长小节再按段落边界二次拆分。每个切片都要保留它在原文档中的路径信息,例如 #login-module > ##error-handling > paragraph-004,这样后续做溯源时能精确定位。
3.2 “需求单元”结构化输出协议:先定 Schema,再谈生成
要让后续校验可行,Agent 的输出必须严格受控。PingCraft 定义了一套内部 JSON Schema,核心结构如下:
json复制{
"doc_id": "PRD-20250115-A",
"doc_title": "登录模块改版",
"doc_version": "3.2",
"requirement_units": [
{
"id": "RU-001",
"type": "user_story",
"summary": "用户提交无效凭证时应立即看到明确错误提示",
"acceptance_criteria": [
"当用户输入错误的用户名或密码时,登录页在3秒内显示错误提示",
"错误提示内容需明确说明是用户名错误还是密码错误",
"连续输错三次后,页面提示账户暂时锁定并显示15分钟重试时间"
],
"source_anchor": "#login-module > ##error-handling > paragraph-004",
"constraints": ["不得引入第三方验证码服务"],
"dependencies": []
}
]
}
我看到过不少 Agent 项目把输出设计成“一大段 Markdown 自由文本”,理由是 LLM 擅长写作。但对自动化工件来说,自由文本意味着后续脚本没法可靠解析。JSON Schema 即便让提示词更啰嗦,也值得,因为它让输出变得可校验、可版本化、可 diff。
3.3 幻觉防护:每条抽取结果都要“逐条溯源”
需求抽取场景的幻觉很隐蔽,它不是让 Agent 编造一个不存在的功能,而是让它把文档里没有明确写出的细节,合理补全到验收标准里。补全得好叫“合理推断”,补全得不好就是“凭空捏造”。
PingCraft 的校验器用了一个非常笨但有效的方法:闭卷自检。Agent 输出每条验收标准时,都必须附带 evidence 字段,里面引用原文片段。校验器拿到 evidence 后,会去切片文本里做一轮模糊匹配。匹配不上的结果不会直接被丢弃,而是进入“人工仲裁清单”,由配置的确认人在界面上决定是采纳、修改还是删除。
我实测下来,这个机制能把明显的幻觉拦截掉八成左右。剩下的两成是原文本身表述含糊、怎么引用都有道理的,那本来也不该由一个 AI 来替业务方拍板。
3.4 从需求单元到工作项的映射矩阵
需求单元不直接等于工作项。一篇 PRD 里既有用户故事,也有业务规则、埋点需求、非功能约束,它们对应的工作项类型不同,落到项目管理系统里的模板也不同。PingCraft 用了一张映射矩阵来控制这个转换:
| 需求单元类型 | 典型示例 | 工作项类型 | 必填补充字段 |
|---|---|---|---|
| User Story | 用户能修改头像 | Story / Task | 验收标准、依赖需求 |
| Bug Report | 并发请求导致订单重复 | Bug | 复现步骤、影响范围 |
| Non-functional Requirement | 接口响应时间小于 300ms | Task + 技术方案链接 | 性能指标、验收方式 |
| 数据/埋点需求 | 注册流程增加埋点事件 | Task | 埋点参数、事件名 |
| 业务规则 | 优惠券过期前需发通知 | Rule / Task | 触发条件、执行时机 |
映射完成后,每条工作项都会被赋予一组血缘字段:来源需求单元 ID、文档版本号、原文锚点、父工作项 ID。这些字段是后续可追踪性的地基,我建议你在设计阶段就把它放进 Schema,而不是等建完任务再回头补。
拆解粒度方面,我的经验是“以验收标准为最小检查原子”。一个需求单元如果包含五条验收标准,通常拆成 1 到 3 个工作项,不要拆到“把按钮文案改成四个字”这种像素级粒度,否则 Agent 的拆解结果会给研发团队带来巨大的维护噪音。
4. 可追踪性不是靠备注:双向关联和溯源图的落地实现
4.1 一个需求版本对应一套工作项快照
可追踪的前提是快照。如果需求文档一直在改,Agent 的拆解结果也跟着漂,那“追踪”就无从谈起。PingCraft 的做法是:文档每提交一个新版本,Agent 会对该版本做一次全量拆解,生成一套“该版本下的工作项快照”。
这样设计带来一个直观的好处:你能像看 Git 历史一样,对比两个版本之间工作项的增删改。比如文档从 v3.1 升到 v3.2,你可以在界面上看到:
| 变更类型 | 需求单元 | 工作项 | 状态 |
|---|---|---|---|
| 新增 | RU-012 增加短信验证码登录 | T-104 接入短信验证服务 | 待创建 |
| 修改 | RU-005 锁定策略阈值 3 次改为 5 次 | T-102 登录错误锁定逻辑 | 待确认 |
| 删除 | RU-002 支持邮箱快速注册 | T-096 邮箱注册流程 | 建议关闭 |
这套 diff 机制是“改得动”目标的核心实现,有了它,需求变更影响分析才不是一句口号。
4.2 稳定锚点:不要拿文档章节编号做 ID
我先踩过的坑,是拿“3.2.1”这种章节编号直接做锚点。第一次跑通没问题,可一旦有人在文档前面插入一个新章节,所有后续编号整体后移,旧任务指向的内容就全错了。
稳定锚点方案拆开看是两件事:标题内容 slug 化,同时带上块哈希。3.2.1 会变成 #login-error-message,因为标题文字通常不会被随意改写;块哈希用于处理同一标题下内容反复变化的情况。校验器在重建索引时,如果发现某个旧锚点在新版本中不存在,不会直接报错,而是把关联工作项标记为“需要人工确认引用位置”,避免静默断链。
4.3 工作项里的“血缘字段”设计
工作项在 Jira、Tapd、Worktile 这类系统里创建后,默认不会理解自己是从哪来的。PingCraft 会在创建时把血缘信息写入描述区或自定义字段,格式类似:
text复制[p-craft] source_doc=PRD-20250115-A
[p-craft] source_version=3.2
[p-craft] requirement_unit=RU-005
[p-craft] source_anchor=#login-module > ##error-handling > paragraph-004
不要小看这几行签名。当研发在任务卡片上看到它时,可以一键跳回需求文档的原始段落;当需求变更时,脚本也能通过它批量定位受影响任务。代码侧同样要遵守约定:commit message 里带 T-102 这样的工作项 ID,Webhook 监听器会把它解析为“T-102 有代码提交”,再按项目规范触发状态流转。
这样形成的一条链路是:需求文档锚点 → 需求单元 ID → 工作项 ID → commit → 上线记录。每一步都有据可查,才是“可追踪工作项”的真正含义。
4.4 变更影响分析的正确做法
很多团队做需求变更,靠的是产品经理在群里吼一嗓子。PingCraft 想做的是把影响范围显式化。
当新版本需求文档进入系统,后台会先执行两件事:
- 用 diff 算法找出文档切片级别的差异;
- 把这些差异映射回需求单元和工作项,生成影响报告。
这里最需要克制的是“不要自动改工作项状态”。我见过一些自动化方案会在检测到需求变化后直接给任务追加评论或变更状态,结果误报率很高,团队很快就对通知麻木了。PingCraft 的策略是把影响报告放进人工确认队列,由需求负责人勾选“接受变更”“忽略”“重新拆解”后才执行后续动作。自动化的目标应该是减少决策成本,而不是替人做决策。
5. 工程化过程中的关键排障:从 Agent 静默失联到索引错位
5.1 故障一:长文档导致上下文超限,Agent 静默返回空结果
这是上线后最先遇到的事故。现象是偶发空响应,没有任何报错信息,流水线在智能层安静地中断。一开始怀疑是模型服务不稳定,后来在日志里翻到关键线索:请求 content length 超出限额,被模型服务端截断了。
排查出来的原因是预处理切片没有覆盖所有类型。文档里一个 H2 小节内部有十几个并列段落,切块策略认为它“还是一个块”,结果单块体积超过了模型上下文窗口。
修复方案有两层:第一层是把切块逻辑改为递归细分,任何超过 600 字的小节都继续按段落拆分;第二层是加显式检测,Agent 返回空数组或截断标记时,调用方不再静默跳过,而是把该分片标记为失败并入队列重试,连续失败两次则告警。
经验是:一次给 Agent 喂整篇文档是最省事的写法,也是线上事故率最高的写法。Agent 项目必须把输入长度视为一等公民。
5.2 故障二:需求改版后,旧任务新任务指向同一段文字
某次文档调整把一个“注册流程”章节从第 2 节挪到了第 4 节。按章节序号锚点,旧任务和新任务重新索引后都指向了 4.2 的注册流程文本,但这两条任务的需求上下文其实完全不一样。团队在评审时发现怎么两张卡片引用的是同一个锚点,才把问题暴露出来。
排查链路是这样的:先看索引重建日志,发现新旧锚点字符串完全一致;再看锚点生成规则,确认是“按标题序号切块”的老逻辑,而章节序号在文档层级变化时不具备稳定性。最终我们把锚点切换为“标题内容 slug + 块哈希”的稳定方案,并在崩溃期间加入一致性校验任务,每天扫描一次是否有两个工作项引用了完全相同的锚点,若有则自动进入人工仲裁。
5.3 故障三:Agent 输出 JSON 偶尔不合法,流水线中断
这个故障不算稀奇,但差点让我放弃“纯文本输出 + 解析器”的方案。LLM 返回的内容里偶尔会带 Markdown 代码块包裹、JSON 行尾注释、甚至直接混入一段解释性文字,json.loads 必然报错,流水线就会被卡住。
我最终的解法是三层兜底:
- 先用正则剥掉任何代码栅栏标记和多余的文字前缀;
- 再用 JSON5 兼容解析器处理行尾注释和宽松格式;
- 最后再调用一次“结构化输出通道”,让模型直接把结果以受约束的 function call 参数返回。
加上这三层之后,解析失败率从约 10% 降到了 1% 以下。剩余的 1% 大多是模型确实输出残缺的结果,这时宁可失败,也不要拿残缺草案库。
5.4 故障四:Agent 写操作权限过大,险些污染历史数据
在自动模式下,我给 Agent 申请过一个项目管理员级令牌,想着它要创建任务、修改状态、关联依赖,权限大点省事。结果在一次测试中,Agent 对一批已有任务批量更新了 summary,险些把历史记录全部改乱,最终依靠审计日志一条条回滚才恢复。
这个教训后来变成了硬性规范:Agent 令牌只赋予“创建任务”“更新自定义字段”这类最小权限,严禁授予“删除任务”“批量修改”“管理项目配置”权限。所有写操作统一走执行器队列,由执行器进行幂等校验并写入审计日志。要让 Agent 犯错可以被追溯、可以被撤销,而不是所有失败都变成不可挽回的脏数据。
6. 实际效果、局限性与后续演进
6.1 小样本实测:效率提升确实存在,但别神话
目前 PingCraft 在团队内测里跑过 4 份真实需求文档,累计约 3 万字。人工核对的结果是:Agent 拆出的工作项约 190 条,其中验收标准能做到“原文可溯源”的匹配率约 92%;人工从零整理这些需求大约需要 6 到 8 小时,而用 Agent 生成再加人工修正,整体控制在 1.5 到 2 小时内。样本量不大,只能当做一个趋势参考。
真正让我觉得值得的,不是省了多少小时,而是“遗漏变少了”。以前手工拆需求,偶尔会漏掉一条测试人员很在意的验收标准;现在 Agent 拆完后,校验器会把这些标准逐条挂在需求单元下,漏没漏一眼就能看出来。
6.2 它做不到什么:Agent 不是需求评审的替代品
有一段时期,团队里有人指望 PingCraft 能直接判断需求优先级、裁定业务冲突,这是不可能的。Agent 只能根据你给的模板和规则给出建议,它不理解业务价值,也不懂市场压力。
实测中我发现它最明显的短板是:面对文档内部自相矛盾的内容,Agent 只会把两个矛盾点都列出来标记为“冲突”,不会也无法裁决“业务方到底想要哪个”。另外,跨团队的复杂依赖、外部系统的排期约束,这类信息通常不在需求文档里,Agent 再聪明也看不到。所以 PingCraft 从设计上就把人工确认队列放在最核心的位置,它解决的是“拆解的体力活”和“追踪的记账活”,而不是“拍板的决策活”。
6.3 后续想继续做的方向
我的个人计划是在两个方向上继续深入。第一个方向是让 Agent 在拆解工作项的同时,自动生成一版测试用例草稿,放到测试任务里人工完善,进一步缩短从需求到测试用例的距离。第二个方向是增强变更影响分析,当需求文档改版后,可以自动列出关联的代码模块、涉及的历史 commit,以及建议回归的测试范围。
就我自己的体会而言,做 Agent 项目能不能真正落地,关键不在模型聪明程度,而在工程侧的护栏:输入要不要切片、输出要不要校验、写操作要不要审计、锚点要不要稳定、状态变更要不要人确认。这些看似很“不 AI”的工程细节,决定了一个 Agent 原型能不能走成被团队天天使用的工具。拆解可以是 Agent 干的,决策必须人来确认,这条线我会一直守着。
