如何实现一个回顾智能体:工作原理
在上一篇文章中,我介绍了为什么我们要衡量工程师的时间花在哪里,以及一个小型 LLM agent(大语言模型智能体)如何帮助我们把这种衡量整合到团队的 sprint retrospective(迭代回顾)中。几个月后,我们已将这个智能体推广到各个团队,它帮助引发了过去没有发生过的一些讨论。
本文重点介绍智能体如何工作、如何接收数据,以及提示词是如何演进的。底层的数据平台,包括 DORA metrics(DORA 指标)的推导方式,将在下一篇文章中单独介绍。
概览
智能体从我们的生产力指标数据平台获取指标和活动数据,并生成一份 pre-read(会前阅读材料)形式的回顾报告,用于总结本次 sprint 并提出潜在的讨论点。
智能体不会将所有原始数据全部输入模型,而是接收三个 sprint 的指标摘要,并配备查询特定工单、merge request(合并请求)和失败发布详情的工具。
智能体设计
初始提示词
初始提示词总结了三个 sprint 的指标,并分别标记为 [BASELINE] 或 [LATEST - FOCUS SPRINT]。这些指标涵盖 Jira 交付指标和 DORA metrics:
| DORA 指标 | Jira 指标 |
|---|---|
| 部署频率 | 问题和 story point 完成率 |
| 变更前置时间(编码 + 审查 + 部署) | 已承诺范围与 sprint 中期范围对比 |
| 变更失败率 | 结转项 |
| 服务恢复时间 | 周期时间 |
所有指标都由数据平台使用确定性代码计算得出;我们不会要求模型根据原始数据自行计算。提示词对此有明确说明:“指标摘要具有权威性,不要尝试重新计算,也不要质疑其结果”。
摘要还包括一组 outlier(异常值)工单和 merge request,例如周期时间或前置时间高于第 75 百分位数的工单和合并请求,以及 focus sprint 中所有失败发布的列表。智能体被要求以这些列表作为分析的起点。工单以内嵌形式命名为 KEY (16.8d, 3.0SP),MR 则命名为 project!iid (308.7h: coding 116.3h, review 170.0h, deploy 22.4h)。
查询工具
PydanticAI agent 上注册了三个工具,允许智能体查询详情:
@agent.tool
def lookup_jira_ticket(ctx: RunContext[AgentDeps], ticket_key: str) -> str:
"""Look up a Jira ticket by its key (e.g. PROJ-1363).
Returns summary, status, assignee, story points, sprint, dates, cycle time,
and full status transition history.
"""
@agent.tool
def lookup_merge_request(ctx: RunContext[AgentDeps], query: str) -> str:
"""Search merge requests by title substring, Jira key, or MR reference (e.g. !1049).
Returns up to 10 matching MRs with title, author, dates, lead time, and release info.
"""
@agent.tool
def lookup_failure(ctx: RunContext[AgentDeps], query: str) -> str:
"""Search detected failed releases by tag, project name, evidence, or alert tiny id.
Returns up to 10 matching failures with signal (alert/revert), evidence,
resolution time, and correlated alert detail where available.
"""这些 docstring 同时充当模型进行推理时所依据的 schema(模式),而返回的数据则帮助智能体开始构建叙事。一张工单会连同完整的 status_history 以易读的链条返回(例如“进行中 → 代码审查 → 等待发布 → 已完成”),从而帮助识别哪些工单曾反复进入和离开“受阻”状态。一个 MR 会返回编码、审查和部署时间的拆分,以及交付它的发布,从而帮助识别 MR 之间的共性模式及其对发布周期的影响。
系统提示词鼓励智能体使用这些工具:“主动使用这些工具……在得出结论前先查询”。
输出结构
智能体的输出类型是普通字符串,没有结构化输出 schema,也没有后处理。唯一塑造报告内容的是提示词中的任务定义:简洁总结最新 sprint、对比基线后列出 2-4 个值得关注的趋势(“包括正面和负面趋势”),以及 3-5 个具体的讨论要点或讨论问题,并使用三个必需的标题:Sprint Summary、Notable Trends、Retrospective Talking Points。
规定 2-4 个趋势和 3-5 个讨论要点会迫使智能体进行取舍;将第三部分定义为问题而非结论,则有助于让报告保持会前阅读材料的性质,而不是变成裁决,因为我们相信团队掌握完整背景,能够自行解读这些趋势并决定如何应对。
一次典型运行
下面是一次典型智能体运行的示例。摘要中列出了 11 个工单和 MR,智能体并行进行了 11 次查询,以获取所需详情。报告通过一次 LLM 调用生成,输出是一份由三个部分组成的 markdown 报告。
这些查询为报告提供了更多细节。周期时间最长的异常值(16.8 天)最终显示跨越了两个 sprint,而其 merge request 从首次提交到发布耗时 308.7 小时(其中编码 116.3 小时、审查 170.0 小时、部署 22.4 小时)。另一个 MR 的 99.7 小时中,有 99.5 小时花在审查上。
报告指出,瓶颈在于审查延迟(中位数为 58 小时,约为前一个 sprint 的三倍),而不是部署;报告还能够指出具体的工单和 MR 供团队讨论。报告同时提醒,发布次数已从 23 次降至 6 次,而变更失败率则从 8.7% 改善为零,并询问这种流程变慢究竟是有意进行风险管理,还是变更只是排在审查之后等待处理。
整个运行过程包含两次 LLM 调用:大约 11,400 个输入 token(其中第二次调用有三分之一是缓存读取)和 2,200 个输出 token。按本文撰写时 GPT-5.4 的 API 定价计算,成本约为 0.05 美元,其中大部分来自输出 token。
实践中的 Prompt engineering(提示词工程)
不要点名工程师
在最初的原型中,智能体讨论处理较慢的工单时经常会点出工程师的姓名。为了维护无责备的回顾环境,我在提示词中加入了 guardrail(防护约束),避免这种情况。智能体被要求关注全团队层面的趋势和工作本身,而不是个人表现。
这也是我可以通过 deterministic eval(确定性评测)覆盖的内容。评测会从输入中提取每一位经办人和 MR 作者;如果其中任何人出现在输出中,评测就会失败。提示词和评测共同强制执行这条规则。
Schema 是提示词的一部分
智能体会根据你的字段名进行推理,因此命名很重要。早期版本会根据 Jira 的 status_category 字段错误判断工单状态,以及工单是否已完成。我们向工单 schema 中添加了 is_done 布尔值,使用确定性逻辑和数据结构来编码语义,从而修复了这个问题,而不是依赖模型去解释含义模糊的字段名或字段值。
结构胜过指令
提示词中从未使用“假设”一词,尽管假设正是最终产物。第三部分是讨论要点和讨论问题,而不是结论。回顾会议应由人来主导,报告格式通过自身的结构体现了这一点,而不是要求模型记住这一原则。
最初的提示词还要求生成一张展示关键指标的概览表,但模型每次都会生成格式不同的摘要。通过围绕智能体构建 Web UI,摘要表成为生成叙事旁边的一个确定性组件。如果输出中的某一部分每次都应该相同,就不要要求 LLM 来生成它。
结论
这个回顾智能体虽小但对我们的团队很有用,帮助工程团队的回顾会议激发讨论和反思。它展示了提示词工程与查询工具的结合如何打造有价值的 AI 助手,同时尊重团队协作动态并专注于可执行的洞察。
它之所以有用,很大程度上要归功于底层的指标数据平台,该平台提供了智能体进行推理所依据的权威数据。这需要谨慎选择要跟踪的指标,并决定如何根据开发工作流计算这些指标。下一篇文章中,我将深入介绍这个平台的工作方式、DORA 指标的推导过程,以及这一切如何结合起来支持我们的工程团队。
随机一篇博客