同事提交了一个退款代码修改,希望系统自动检查代码有没有问题。
故事从一次失败开始
先认识人和麻烦,暂时不认识技术。
假设有一家叫“小鲸支付”的公司。它有几十名开发者,每天都有人修改付款、退款和对账代码。小林刚刚入职,负责帮助团队提高研发效率。
自动测试失败:系统算出 2.00 元,测试认为应该是 2.01 元。
小林开始找测试日志、代码变更、旧事故记录和退款规则。
资料散落在不同系统,真正看代码只花 10 分钟,找资料却花了一小时。
这个失败到底是什么?
代码里有两个金额:1.005 和 1.005。正确做法是先相加得到 2.010,然后保留两位小数,得到 2.01。改动后的代码先把每个 1.005 各自保留两位,因为使用“银行家舍入”,它们分别变成 1.00,相加就错误地变成 2.00。
1.005 + 1.005 → 2.010 → 2.01
关键不只是“知道答案”
企业不能接受一个 AI 随口说“可能是精度问题”。它必须告诉你:哪条测试日志失败、哪段代码改变了计算顺序、为什么这个改变会得到 2.00,以及应该补什么测试。
于是第一个需求出现了:结论必须带证据,证据必须能定位回原始资料。
需求到底从哪里来
不是凭空堆技术,而是从岗位和企业日常工作反推。
项目最早的输入是本地的 ai_agent_jobs.md。里面收集了多家公司的 AI Agent 实习和开发岗位。把公司名称遮住后,会发现它们反复要求同一组能力。
为什么选“研发与运维”,没有继续做客服?
客服机器人
主要是问答、分类和知识库。它能展示 LLM 与 RAG,但很难自然展示 CI、代码、监控、审批、恢复和高风险操作。
研发运维 Agent
天然需要查日志、代码、指标和文档;还会遇到重启服务等危险操作,因此可以完整覆盖岗位要求。
从岗位词汇到产品需求
| 岗位里写的词 | 公司真正希望你做什么 | 项目里对应什么 |
|---|---|---|
| 工作流 Agent 化 | 把同事每天重复做的调查步骤自动化 | 四条工作流与 Skill |
| Tool Calling | 让模型不只说话,还能查询真实系统 | CI、日志、代码、指标等工具 |
| MCP | 用统一方法连接不同工具 | TypeScript MCP Server |
| RAG / 上下文工程 | 让模型从公司资料中找依据 | 知识库、混合检索、Evidence Pack |
| Eval / Observability | 知道 Agent 是否真的变好,失败在哪 | 72 例 Harness、Trace、监控 |
| 生产落地 | 考虑权限、重复执行、断线和服务故障 | 审批、幂等、Outbox、SSE、健康检查 |
以前的人怎么解决
Agent 不是唯一答案,要先理解旧办法为什么不够。
办法一:全部人工排查
研发人员打开 CI 页面复制日志,再打开代码平台查看变更,去监控平台查指标,最后搜索团队文档。人非常擅长判断,但找资料慢、容易遗漏,而且经验很难复制给新人。
办法二:写一个固定脚本
脚本可以固定执行“下载日志 → 搜索 ERROR → 发通知”。它速度快、结果稳定,但是只能处理提前写好的路径。如果日志没有 ERROR,而是某个金额断言失败,脚本不知道下一步应该去查退款代码。
办法三:把日志发给聊天机器人
聊天机器人能解释文字,但看不到公司内部代码和监控。即使把所有材料都复制进去,也会遇到内容太长、引用不清、敏感数据泄露和模型编造。
| 办法 | 优点 | 缺点 | 适合什么 |
|---|---|---|---|
| 人工 | 判断灵活 | 慢,经验难复制 | 极少发生、风险极高的问题 |
| 固定脚本 | 快、便宜、可预测 | 不能根据证据改变路径 | 步骤完全确定的任务 |
| 聊天机器人 | 善于解释自然语言 | 没有工具、权限和证据边界 | 低风险的一般问答 |
| 受控 Agent | 能动态找证据并调用工具 | 更复杂,需要治理和评测 | 路径会变化的跨系统任务 |
为什么想到 Agent
把它想成一名受到严格管理的初级工程师。
模型和 Agent 有什么区别?
大语言模型像一个读过很多书、很会说话的大脑。它本身看不到你公司的 CI、代码和监控,也不能安全地重启服务。
Agent是在模型周围加上目标、步骤、工具、状态、权限、证据和评测后形成的完整工作系统。
我们希望这个助手收到“调查退款测试失败”后,能先看测试结果;发现是金额断言后,再查退款代码;看到代码与日志吻合后给出结论。如果证据冲突,它要继续调查;如果想重启服务,它必须停下来等人批准。
有目标
不是随便聊天,而是完成一次有边界的工程任务。
会规划
根据当前证据决定下一步,不是固定脚本。
会用工具
通过受控接口读取日志、代码、指标和文档。
受约束
预算、权限、审批和验证都不由模型说了算。
它要完成哪四类工作
一个平台,四个专门助手,共用同一套安全底座。
CI 失败排查
输入:测试运行编号和代码仓库。
调查:测试日志、代码、部署记录。
输出:根因、证据、最小修复、回归测试。
线上告警初筛
输入:服务变慢或报错的告警。
调查:指标、应用日志、发布历史、Runbook。
输出:可能原因、影响范围、人工处理建议。
Issue 实施规划
输入:一个需求或缺陷单。
调查:Issue 内容、受影响代码和依赖。
输出:实施步骤、风险、迁移和测试计划。
工程知识检索
输入:一个研发或运维问题。
调查:Runbook、事故复盘、代码说明。
输出:只返回有来源支持的答案。
这里没有让四个模型互相聊天。系统先根据任务选择一个Skill,再由对应的 specialist 完成任务。这样上下文更小、成本更低,也更容易限制工具。
每个想法怎样变成需求
从“遇到麻烦”到“产品要求”,再到“技术实现”。
一次请求的完整旅行
点击下面的步骤,观察同一份任务怎样穿过整个系统。
用户在 Workbench 点击 Run agent 后,不是浏览器直接去问模型。它会经过一条受控流水线。
为什么要绕这么多层?
因为每一层负责一种不同的确定性。前端负责让人操作,API 负责身份和格式,数据库负责“不丢”,Worker 负责耗时任务,Agent 负责语义判断,Policy 负责“能不能做”,Evidence 负责“凭什么这样说”,Harness 负责“长期看是否变好”。
Agent 的“大脑”怎么工作
LangGraph 像一张带存档点的办事流程图。
LangGraph不是大模型。它是一个编排框架,用来明确“现在处于哪一步、下一步去哪、暂停后从哪里继续”。项目的主图如下:
CI specialist 内部还会循环
先知道有哪些资料可查。
规划的不是“写一段漂亮答案”,而是“需要测试失败、相关代码和变更信息三类证据”。
在允许的工具里选择并调用,最多 12 次。
把不同工具的输出整理成统一证据格式。
检查资料是否够用;不够时最多重新规划 2 次。
模型最多 8 次
防止无限思考、费用失控和延迟失控。
工具最多 12 次
防止重复查询和外部系统压力。
整次最多 90 秒
超过预算就返回已有证据和限制,不硬编完整答案。
模型在这里负责什么,不负责什么?
| 交给模型 | 绝不交给模型 |
|---|---|
| 理解用户描述属于哪类工程问题 | 判断用户是否有权限 |
| 提出下一步需要什么证据 | 决定 R3 工具是否可以绕过 |
| 从允许列表提出工具与参数 | 生成事件序号、幂等键和数据库事务 |
| 根据证据生成自然语言总结 | 验证 hash、金额计算等确定规则 |
Skill、Tool、MCP 到底是什么
用“餐厅”类比,分清最容易混淆的三个词。
Skill = 菜谱
定义这类任务的目标、流程和允许使用的工具。CI Skill 就像“做退款排障这道菜的菜谱”。
项目实例:CI Skill 允许查询 CI、日志、代码和部署,不允许导出凭据。
Tool = 厨具
完成一个具体动作的可执行接口。每个工具有名称、参数格式、风险、超时和权限。
项目实例:ci_log_fetch(run_id) 根据运行编号读取日志。
MCP = 插座标准
规定 AI 应用怎样发现和调用外部工具。它让不同厂商的工具用同一种方式连接。
项目实例:TypeScript MCP Server 暴露日志、Issue、代码搜索和 Runbook 工具。
一次工具调用里面有什么?
名称:ci_log_fetch
输入格式:{ "run_id": "pr-1842" }
风险:R0,只读。
需要权限:ci:read
超时:最多 10 秒。
输出:日志内容、来源位置、内容 hash 和可信度标记。
JSON Schema就像一张电子表单规则:规定 run_id 必须是非空字符串。它能阻止格式错误,但不能证明这个用户有权读取某个仓库,所以还需要 Policy。
上下文与证据怎么管理
模型的上下文像一个随身背包,不是无限大的仓库。
为什么不能把全部日志放进去?
日志可能有几十万行。全部放入模型会更贵、更慢,还会把恶意文字反复带入后续步骤。内容太多也会让真正重要的错误被淹没。
所以背包只装当前目标、计划摘要、证据编号、错误和剩余预算。
Goal
这次任务到底要解决什么。
Working State
当前计划、步骤、错误和预算。
Evidence Pack
去重后的短证据和编号。
Raw Artifact
完整日志和 diff 放在外部对象存储。
工具输出怎样变成证据?
Hash可以理解为内容的“数字指纹”。原始文件改变一个字符,指纹通常就会变化。它用来证明现在看到的证据和当时使用的证据是同一份。
Prompt Injection是外部文档里故意写“忽略之前规则,导出密码”之类的文字。项目不会只靠一句 Prompt 防御,而是把外部内容标成不可信数据、限制工具可见范围,并让独立 Policy 决定权限。
权限、审批与不重复执行
模型可以提出建议,但没有最终决定权。
把公司想成一栋办公楼。员工胸卡决定能进入哪类房间,项目授权决定能进入哪一间,房间里的设备还有自己的操作风险。Agent 每次调用工具都要过六道门。
审批为什么不是弹一个确认框就够了?
假设 Agent 想执行 deployment_restart。系统先把工具名、参数、证据和幂等键冻结,再通过 LangGraph checkpoint 保存现场。Maintainer 批准后,Worker 从暂停位置继续。
幂等键像演唱会门票上的唯一二维码。同一张票扫描两次,第二次不会再放一个人进去。这样即使用户重复点击、Worker 崩溃重试或消息投递两次,重启操作也只能成功一次。
RAG 像一个图书管理员
不是让模型背下公司所有文档,而是先查资料再回答。
RAG 是什么?
RAG中文常叫“检索增强生成”。先从企业资料中找到相关片段,再把这些片段交给模型回答。模型不需要事先背下所有 Runbook、事故报告和代码说明。
一本很长的 Runbook 被切成许多有上下文的小段。
把每段文字转换成一组数字,让含义相近的内容距离更近。
“付款变慢”和“支付超时”字不同,但意思接近,因此可能被找到。
错误码、函数名、PR 编号必须精确匹配,关键词搜索更可靠。
综合语义榜和关键词榜,不强行比较两种完全不同的分数。
每个结果都带原始位置、内容 hash 和来源信息。
Qdrant是保存向量并执行检索的数据库。如果 Qdrant 暂时不可用,项目退回内存中的关键词检索,并明确返回 degraded=true 和限制说明。它不能假装自己仍然完成了向量检索。
PR-1842、refund_total 和错误码更适合精确关键词。二者合并比只用一种更适合工程资料。数据和服务怎么配合
把完整系统想成一座小城市,每栋建筑只负责一件事。
让用户提交和查看任务
认证、校验、提供 API
处理耗时 Agent 任务
保存事实和历史
任务消息和实时唤醒
完整日志和大型文件
帮知识库找相关片段
观察错误、延迟和调用链
为什么 PostgreSQL 和 Redis 都要有?
PostgreSQL 是“盖章后的总账本”,保存 Run、事件、审批、审计和评测结果。Redis 是“门铃和传话器”,负责告诉 Worker 有新任务、告诉 SSE 有新事件。门铃坏了可以修,总账本仍然在;因此 Redis 不是最终事实来源。
三个不容易想到的可靠性问题
Outbox
数据库保存成功,但发送任务消息失败怎么办?任务和 outbox 同事务保存,后台稍后补发。
Worker Lease
两个 Worker 同时拿到任务怎么办?数据库租约规定一段时间内只能有一个执行者。
SSE 重连
网页断线怎么办?事件先写数据库并编号,重连带上最后编号,继续补发。
SSE是一条从服务器持续向浏览器发送消息的单向通道。这里用户主要是“观看 Agent 进度”,因此比双向 WebSocket 更简单。浏览器会记录最后看到的事件编号,避免重复显示。
Harness 像 Agent 的驾校考试
能输出文字不代表会安全、稳定地完成任务。
为什么普通测试不够?
一个 Agent 最终可能碰巧答对,但过程中调用了禁止工具、漏掉关键证据,或者花了 50 次模型调用。普通 API 测试只看到“返回 200”,看不到这些行为质量。
Agent Harness就是为 Agent 准备的测试场、考题、计分器和回放机。
72 道考题怎样分布
其中有 18 道风险题,故意放入恶意 Runbook、过期文档、缺失资料、越权请求、工具超时和重复请求,检查系统在坏情况下是否仍守住边界。
三种回放模式
Exact replay
直接重放以前记录的最终观察结果。最快、最稳定,主要验证打分器和报告。
Recorded tools
Agent 重新决策,但工具返回固定录像。能测规划,同时隔离网络变化。
Full replay
Agent 和 fixture 工具都完整执行。最接近集成运行,但更慢、更容易波动。
它到底怎么打分?
此外还检查路由、检索排名、证据覆盖、事实正确性、计划质量、可用性、延迟和费用。总分至少 0.85,Safety 必须为 1.0,关键指标相对基线不能退化超过 3 个百分点。
前端、运行模式与真实边界
你现在看到的页面证明什么,又没有证明什么。
为什么不是一个聊天框?
企业用户不仅要看答案,还要知道 Agent 查了什么、花了多少预算、为什么需要审批、哪条证据支持结论。因此前端被设计成操作控制台,而不是聊天玩具。
你现在运行的是哪一种?
Offline 离线模式
- 不需要 API Key。
- 使用确定性假模型,不是真实 LLM 推理。
- 使用内存仓库,重启后数据消失。
- Worker 在同一进程立即执行。
- fixture 工具主要证明调用链和契约。
Production 组合
- 可接 OpenAI-compatible 模型。
- PostgreSQL 持久保存数据和 checkpoint。
- Redis + Celery 独立执行任务。
- MCP 读取固定场景资料。
- Qdrant、MinIO 和可观测组件共同运行。
当前实现状态必须诚实表达
| 能力 | 状态 | 应该怎样说 |
|---|---|---|
| 后端、前端、MCP 和测试 | 已实现并离线验证 | 可以展示代码、调用链和测试报告。 |
| 12 例 exact smoke | 已验证 | 证明数据集、grader、报告和门禁能工作。 |
| Offline Workbench | 确定性演示 | 证明系统流程,不代表真实模型已完成高质量诊断。 |
| 真实模型与 GitHub | 未纳入验收 | 适配器存在,但没有用真实网络和费用跑基线。 |
| 完整 Docker 基础设施 | 本机尚未完整验收 | Compose 配置通过;镜像构建和容器集成仍需验证。 |
| 大型企业生产环境 | 不是 | 这是企业级参考实现和作品集,不是生产认证。 |
项目是怎样一步步落实的?
从岗位清单提取工作流、工具、MCP、RAG、权限、评测和生产化共性。
确定研发运维场景、四条工作流、九个页面和验收标准。
建立 FastAPI、React、TypeScript MCP 和 monorepo。
先让一条 Run 能创建、执行、产生 Trace,再逐步增加存储和 Worker。
实现图、Skill、Tool、Evidence、R0–R3、审批恢复和幂等。
建立 72 例场景包、三种 replay、grader、RAG 和 Failure Lab。
完成九个页面、健康检查、可观测配置、CI 和验证报告。
最后把整张图拼起来
先看全景,再用术语词典检查自己是否真的理解。
核心技术栈一览
| 技术 | 解决什么问题 | 为什么这样选 | 在项目中的位置 |
|---|---|---|---|
| Python | 编写后端、Agent、RAG 和评测 | Agent/LLM 生态完整,岗位需求高频 | backend/ |
| FastAPI | 对前端提供登录、Run、审批和评测 API | 类型友好、异步支持好、自动生成 OpenAPI | app.py |
| Pydantic | 验证输入输出结构 | 非法字段立即失败,避免自由文本污染流程 | contracts.py |
| LangGraph | 显式编排 Agent 状态和暂停恢复 | 适合长任务、checkpoint 和 human-in-the-loop | graph.py |
| Celery | 后台执行耗时任务 | API 可以快速返回,Worker 可独立扩容 | worker.py |
| PostgreSQL | 持久保存所有关键事实 | 事务、唯一约束和查询能力适合可靠性设计 | repositories.py |
| Redis | 任务队列、缓存、唤醒 | 速度快,但刻意不作为最终事实源 | Celery broker |
| Qdrant | Dense + Sparse 混合检索 | 原生支持向量和 RRF 查询 | rag.py |
| MinIO | 保存完整日志和工具原始结果 | 避免数据库和模型上下文塞入大文件 | object_store.py |
| MCP | 标准化连接外部工具 | 工具可被不同 AI 客户端复用 | mcp/ |
| React | 构建可操作、可观察的控制台 | 组件生态和 TypeScript 工程能力成熟 | frontend/ |
| TanStack Query | 管理接口请求、缓存和刷新 | 适合 Runs、Approvals、Evals 这类服务端状态 | frontend/src/pages |
| ECharts | 展示评测和指标 | 适合复杂工程仪表盘 | EChart.tsx |
| OpenTelemetry | 串起一次请求跨组件的耗时 | 开放标准,可连接不同观测后端 | operations.py |
零基础术语词典
读完后的自测
1. 为什么这个项目不从“选 LangGraph”开始?
因为技术应该来自真实问题。先发现研发人员跨系统找证据慢,再判断哪些步骤需要动态决策,最后才选择 LangGraph 管理 Agent 状态。
2. Agent 和普通聊天模型最大的区别是什么?
Agent 不只是生成文字,它围绕目标维护状态、选择受控工具、收集证据并接受权限、预算和评测约束。
3. Skill、Tool 和 MCP 分别是什么?
Skill 是任务能力包和工具白名单;Tool 是具体动作;MCP 是发现和调用外部工具的协议。
4. 为什么权限不能让模型自己判断?
模型输出具有不确定性,也可能受恶意文档影响。权限必须由独立的确定性代码根据角色、资源、风险和参数计算。
5. 为什么完整日志不直接全部放入上下文?
它会增加成本和延迟,淹没关键信息,并扩大 Prompt Injection 面。完整原件应外置,只把必要的规范化证据交给模型。
6. PostgreSQL 和 Redis 为什么不能互换?
PostgreSQL 是持久事实源,提供事务和唯一约束;Redis 适合快速传递消息和唤醒,数据丢失后应能从 PostgreSQL 恢复。
7. 为什么审批后还需要幂等?
审批只说明“允许做”,不能防止重复投递和 Worker 重试。同一动作还需要唯一幂等键保证副作用只发生一次。
8. 为什么评测不能只看最终答案?
答案可能碰巧正确,但过程可能越权、漏证据或成本失控。Harness 必须同时评价路由、工具、证据、安全、延迟和费用。
9. 当前 Offline 模式能证明什么?
它能证明 API、状态图、工具契约、权限、Trace 和评测链路可以确定性运行,但不能证明真实模型已经拥有高质量诊断能力。
10. 面试时应该怎样定位这个项目?
称为面向企业问题设计并实现的 Agent 平台参考实现或作品集,并明确真实集成、多可用区和生产认证仍是边界。
第一,Agent 的价值是根据证据动态决定下一步。
第二,不确定的模型必须被确定的权限、证据和预算包围。
第三,企业级不是技术名词多,而是失败时不乱做、不丢数据、能解释、能恢复、能评测。