刷到一位 PDD 老哥发的帖子,问现在还有没有古法编程,说感觉在需求明确的情况下,AI 一天就能完成他过去一周的工作量。

一年前,的确还是纯手工模式,从建表语句、实体类、数据库读写接口到参数校验,遇到不熟的报错还要去问搜索引擎。现在打开 Claude Code、Codex,只要把需求讲清楚,的确很快就搞定了。
尤其是 Opus 5.5,实在是太好用了,我最近也是在想办法搞第二个账号,有兄弟擅长搞这个可以联系我,付费请教一下。
说到 PDD,平时在公开场合很少看到它高调宣传通用大模型,但在主站电商和跨境业务 Temu 背后,从多模态商品理解、搜索推荐、跨境多语言智能客服,到商家选品和供应链需求预测,大模型和 Agent 早就嵌进了主干业务流程。
尤其在电商交易与履约场景下,让 Agent 调用外部工具去锁定库存、核销优惠券、创建订单时,怎么在海量并发和网络异常下做到一笔都不算错,是个挑战。

从招聘信息来看,PDD 同期的 AI Infra 岗位涉及分布式训练与推理、GPU 集群调度、MoE 优化、量化加速、高并发低延迟服务,以及弹性扩缩容。这表明 PDD 正在建设支撑大模型业务的基础设施。
接下来,继续上硬菜,大家可以把前几篇关联起来一起看,基本上面试中碰到类似的问题,就都能搞定了。
content
01、Agent中的Skill机制了解多少?
“在 Agent 架构里,工具(Tool)和技能(Skill)承担着完全不同的职责。工具提供的是原子的动手能力,比如读取文件、执行终端命令、抓取网页;而 Skill 是一份结构化的操作手册与工作规范,用来教大模型在遇到特定复杂场景时,按什么顺序、遵守什么安全边界去组合调用这些工具。”
“PaiCLI 的 Skill 设计了从低到高的三级来源,依次是安装程序内部的内置目录、用户主目录下的全局目录,以及当前代码库下的项目级目录,同名 Skill 按优先级整体覆盖。”

Skill渐进式加载是如何实现的?为什么需要这种设计?
“渐进式加载(Progressive Disclosure)在实现上把一份完整的 Skill 拆分成了索引、正文和参考文档三个梯度,按任务推进的实际需要逐步放进上下文。
会话刚启动组装系统提示词时,加载器只扫描已启用 Skill 的头部元数据,把名称和描述提取出来拼成索引目录,几乎不占上下文空间。”
“当大模型根据用户输入判断需要启用某项技能时,会主动调用 Skill 加载工具读取完整的指令正文。
由于普通工具的返回结果外层带有不可信的数据标签,模型不会严格照着执行,所以正文既不改写顶层系统提示词(避免破坏前缀缓存),也不放进普通工具结果里,而是在同一轮工具结果之后,向对话历史追加一条带有内部注入标记的独立用户消息。
为了防止多轮对话加载太多技能撑爆窗口,系统会扫描当前对话历史去重和控制总预算,已经在历史里的同名 Skill 不再重复注入,超出预算则拒绝加载并提示先压缩会话。”
02、你怎么理解Agent和普通大模型调用的区别?
“普通的大模型调用是一次无状态的文本映射。调用方把提示词发过去,大模型生成一段回复,交互就结束了,模型不知道自己的结论在真实环境里能不能跑通,也没有机会根据报错去修正。”
“而 Agent 是一个以大模型为内核、具备自主控制与环境反馈的目标驱动运行时。
调用方只给出最终目标,程序把目标交给‘推理思考、执行动作、观察环境反馈、决定下一步’的 ReAct。
只要目标还没完成,Agent 就会根据工具返回的结果自己推进下一轮决策,直到目标达成并通过外部环境的确定性验证。”

除了工具调用,生产级Agent还多了哪些核心能力?
“工具调用相当于给模型装上了手脚,要把单次调用升级成能在生产环境稳定交付的 Agent,顺着任务执行的生命周期往下看,还有四块核心能力。”
“面对跨模块、多步骤的复杂任务,靠模型走一步看一步很容易迷失方向,这就要求 Agent 具备任务规划与拓扑调度能力。
在 PaiCLI 里,除了默认的 ReAct 模式,我们还设计了先规划后执行的 Plan-and-Execute 模式。
规划器先把任务拆解成带依赖关系的 JSON 任务图,执行前由 Java 代码校验节点唯一性与依赖,并用深度优先搜索(DFS)做有向无环图环检测。
校验通过后按拓扑排序分批并行调度;一旦某个子任务失败且整体完成度未过半,系统会携带已完成的证据和失败原因自动重新规划。”
“当多步任务运行起来后,工具返回的海量结果或日志很快会把上下文窗口撑爆,跨会话后模型还会失忆,所以 Agent 必须具备长短期记忆与上下文压缩能力。
短期记忆绑定的是当前会话的消息列表,每次调用模型前会自动执行渐进式压缩,超大的工具输出会自动落盘并在上下文里只留首尾预览。
上下文达到阈值时会将较早的旧工具结果替换为占位符(保留调用 ID 维持配对),逼近窗口上限时保留最近几轮对话,把更早的历史压缩成包含结构化摘要。
长期记忆则负责跨会话持久化项目规范和用户偏好,写入时拦截新旧事实冲突,长时间未核实的记忆在检索时自动打上可能已过时的标记。”

“在长周期的自主执行里,模型难免会写错语法,这就需要 Agent 具备环境感知的自检能力。
在 PaiCLI 里,只要模型修改了 Java 源码,后置钩子会立刻调用语法树解析器做静态的语法检查,把语法错误在下一轮调用模型前主动注入上下文,让模型当场修好。
如果模型连续调用同一个工具且参数完全一致,或者连续出现同一类错误,系统会先注入一次反思提醒模型改变思路;如果继续停留在相同的动作签名上,预算守卫就会判定 Agent 处于停滞状态,立即收回工具调用的权限,发起最后一次不带工具的输出收尾报告。”
“一旦让 Agent 读写磁盘、执行脚本、访问网络,安全风险就会成倍放大,因此生产级 Agent 还多了安全围栏、人机审批与状态回滚能力。
PaiCLI 先由策略根据用户本轮原话做网址授权,阻断提示词注入;接着把终端命令交给审查模型做前置预审(异常或超时一律拒绝),连续被拦才转人工确认;随后经过 JSON Schema 参数校验、路径检查与沙箱隔离。
每轮执行前后,系统还会用 JGit 在外部独立仓库里自动打快照,改坏代码时随时还原工作区。”
03、如果Agent调用外部服务超时了,你的超时时间怎么设置?
“在 Agent 里设置超时时间,必须区分‘调用大模型推理接口’和‘调用外部工具’这两类不同的负载,并把单次调用的分段超时与调用过程的全局剩余时间结合起来。”
“针对大模型推理接口,因为长上下文预填充耗时较长,以及深度思考模型在输出首字前有较长的推理期,我们把 HTTP 超时拆分成了连接超时、流式读取间隔超时和整次调用总超时。
连接超时设得较短,连不上直接失败;读取超时会卡在流式传输中两次收到数据包之间的最大空闲间隔,面对思考模型需要适当放宽,避免思考期间被误判为假死;为了防止服务端负载过高、隔很久才输出一个字把线程占死,外层必须再加一道覆盖整次调用的总超时。”

“针对外部工具调用,同样按工具形态划定边界。
单条终端命令超时后先强制终止子进程树再回收资源;当大模型并发调用多个只读工具时,整批工具共用一个批次截止时间,到点只取消未执行完的慢工具,已执行完的结果按原始顺序返回。
在多步串行流程里,为了防止单步没超时、加起来却把外层接口拖超时,还需要在请求入口生成全局截止时间(Deadline)。
每一步发起调用前,取‘组件自身超时’与‘全局剩余时间’中的较小值作为实际超时。一旦剩余时间不足以支撑下一轮重排序或工具调用,系统就主动跳过重排序,或向大模型注入收尾指令直接给出回答。”
04、在电商场景下,Agent如何保证库存扣减的准确性?
“在电商场景里让 Agent 参与交易履约,前提是划清大模型与确定性交易代码之间的职责边界。
大模型擅长意图理解、商品筛选和工具编排,但输出带有概率性,绝对不能让大模型去计算剩余库存,也不能直接更新库存表。
库存扣减的准确性,必须靠‘Agent 工具层的职责拆分与实时查询’加上‘高并发原子预占与乐观锁兜底’来共同保证。”
“用户在多轮对话里聊了几轮款式和优惠券后,大模型可能把 SKU 编码记错,而且规划阶段查到的‘有货’状态,等到用户拍板时可能早就抢光了。
所以在封装 MCP 工具时,我们把‘商品搜索、实时价格与库存查询、创建订单并锁定库存’拆分成了各自独立的工具;在下单工具触发扣减前,工具执行层的 Java 代码会绕开模型,拿着 SKU 和数量去库存服务做实时复核,并经过用户确认(HITL)授权后才进入扣减流程。”

“进入扣减阶段后,为了避免高并发直接占满数据库行锁或者先查询再扣减引发超卖,工程上采用‘下单预占锁库、Redis Lua 脚本原子预扣、消息队列异步落库加数据库乐观锁兜底、超时未支付自动释放’的方案。
下单工具收到确认请求时,先做库存预占。
扣减请求先发往 Redis,通过 Lua 脚本在单线程里原子执行三步判断,检查幂等流水是否已执行、判断可用库存、够扣就直接扣减并写入预占记录,从根源上消除并发超卖。
Redis 预扣成功后,通过消息队列异步同步到 MySQL 库存表,把可用库存减掉、预占库存加上,更新语句的过滤条件带上‘可用库存大于等于购买数量’的乐观锁判断。
同时往延迟队列发送一条到期消息;用户在规定时间内完成支付则正式核销,超时未支付或取消订单则由延迟消费者按预占流水号触发回滚,把数据库和 Redis 里的库存原路加回。”
Agent调用扣减库存与下单工具时,幂等怎么设计?
“在 Agent 里,大模型在 ReAct 循环中可能因为没解析对上一步的返回格式,或者上下文压缩折叠了已执行记录,结果在同一个购买意图下紧接着又发起了一轮新的下单工具调用。
如果直接拿每次调用生成的工具调用 ID 当幂等键,只能防住单次 HTTP 网络重试,拦不住模型在下一轮对话里换个新的工具调用 ID 重复扣减库存。”

“为了把网络重试和模型跨轮次重复调用同时拦住,我们设计了‘意图级幂等令牌(Intent Token)’配合‘Redis 加数据库流水表唯一索引’的双层防重机制。
当用户表达购买意愿、生成待确认订单卡片时,由确定性的 Java 会话状态机根据‘用户 ID + 会话 ID + 购买意图版本号 + SKU 编码 + 购买数量’做哈希,生成唯一的幂等令牌绑定在会话状态里。
工具执行阶段,不管大模型调用了一次还是连续两轮调用了两次下单工具,拦截器都会强制带上这枚令牌去请求库存服务。
只有当用户明确说出‘再来一单’或修改了选购商品,状态机才会签发新令牌。”
“库存服务拿到幂等令牌后,先在 Redis Lua 脚本里做前置原子拦截,若状态键已存在则直接返回首次缓存结果。
落盘 MySQL 时,建立专门的库存扣减流水表,对‘业务幂等令牌 + SKU 编码’建联合唯一索引,在同一个本地事务里先插入扣减流水再执行库存条件扣减。
哪怕极端情况下 Redis 主从切换丢了键,重复请求落到 MySQL 时也会违反唯一索引而抛异常回滚,配合订单状态机限制只有‘待锁库’才能流转到‘已锁库’,确保同一购买意图只扣一次库存。”
05、你们的Agent怎么处理分布式事务?
“在包含工具调用和多步编排的 Agent 里处理分布式事务,需要把边界分成‘Agent 跨工具多步编排’和‘单个工具内部的后端微服务’分别选型。
跨工具的长周期任务编排走由确定性代码托管的 Saga 补偿模式(本地文件修改+独立仓库快照回滚),高并发交易工具走 TCC 预留模式,跨存储数据的同步与异步解耦则走本地消息表(Transactional Outbox)加可靠消息最终一致性。
无论哪一层,事务状态与回滚补偿都必须由确定性的 Java 代码驱动,不能让大模型自己写回滚逻辑。”

“在 Plan-and-Execute 模式下,一个复杂任务往往要调用多个外部工具,步骤间夹杂着大模型推理,高风险动作还要停下来等待人工确认。
如果在长流程上套用两阶段提交(2PC/XA)或跨多轮对话维持资源锁,数据库连接池和行锁很快就会被拖垮;况且很多外部工具是第三方 REST 接口或独立的 MCP 服务,根本不支持数据库全局事务协议。”
“在编排层,我们通过把每个写工具的正向动作与逆向补偿动作配对来实现确定性 Saga。
登记具有外部副作用的写工具时,要求同时声明逆向补偿接口(如‘创建工单’配对‘撤销工单’)。
任务图按拓扑排序执行时,每成功执行完一个节点,编排器就把工具名、业务主键和返回凭证持久化。
一旦后续节点失败且无法重规划,Java 编排器直接读取执行账本,按逆序依次调用前面已成功节点的补偿接口撤销副作用。
而在本地工作区连续修改多个文件时,我们在每轮执行前用 JGit 在外部独立目录的影子仓库里同步打快照,中途异常或用户撤销时直接按快照还原工作区。”
为什么在库存扣减与跨库同步场景下还要搭配TCC和本地消息表?
“因为 Saga 模式不具备隔离性。
在 Saga 里,前序节点的正向操作一执行完就直接提交了,在后续节点触发补偿之前,修改后的数据对所有并发请求完全可见。
在电商扣库存、核销优惠券、扣账户余额这类高并发场景下,缺乏隔离性会引发严重的脏读和资损,比如前一个请求刚改了状态还没回滚,另一个并发请求就基于这个中间状态把钱退了或把库存扣了。”

“为了补齐隔离性短板,在工具粒度设计上,不允许大模型把‘扣库存、核销优惠券、创建订单’拆分成三次独立的工具调用,而是聚合成一个‘提交订单’工具,并在工具内部的微服务调用上采用 TCC(Try-Confirm-Cancel)模式。
预留阶段 Try 只做资源检查和冻结,把可用库存划转到冻结库存、把优惠券改为冻结中,此时资源已被物理隔离,其他并发请求拿不到,堵死了 Saga 的并发脏读漏洞;等到全部预留成功,确认阶段 Confirm 只需把冻结状态改为已核销;任何一个微服务预留失败,取消阶段 Cancel 就立刻释放冻结资源。
每个 TCC 参与方还在本地维护了一张全局事务状态表,收到 Cancel 时如果查询不到 Try 记录就先插入占坑记录再返回(防空回滚),迟到的 Try 请求如果发现已经有了回滚记录则直接拒绝冻结,Confirm 和 Cancel 也通过状态表保证严格幂等。”
“对于不需要同步等待结果的写入或下游履约通知,则直接用本地消息表(Transactional Outbox)加可靠消息实现最终一致性。
比如在派聪明里处理文档合并后的多库同步(更新 MySQL 状态并触发 Kafka 异步解析写入 Elasticsearch),我们把‘更新文件状态为待处理’和‘往本地消息表插入待发送记录’封装成同一个 MySQL 本地事务,保证业务状态与消息记录同时落盘。
事务提交后由异步线程池投递 Kafka,哪怕网络闪断或实例重启,定时补发任务也会通过条件更新抢占租约,按指数退避持续重投;消费端再配合数据库心跳租约认领、按联合索引幂等写入。”
