来源:互联网 更新时间:2026-08-26 07:38
过去几周,我一直在沿着 Agent 的运行链路学习。

最开始,我分不清 LLM 和 Runtime;后来又陆续学习了 Tool Calling、错误恢复、RAG、Workflow、Checkpoint、MCP、Eval、Guardrails、Trace,以及上一篇文章中的生产化保护。
如果单独问我这些概念,我大多已经能解释:
但前几天有一道题让我很难受:
我发现自己做不到。
不是完全不会,而是不够快,也不够直观。脑中有很多正确的局部知识,但它们还没有连成一条可以随时重建的链路。
所以今天我没有继续学习新名词,而是把前面几周的内容放进同一个 Demo,看看一个任务究竟怎样从“用户说了一句话”,走到“系统真的完成了动作”。
今天的 Demo 处理这样一个任务:
查询 Runtime 回滚知识→ 告诉我当前学到第几章→ 发送学习总结
这句话看起来不复杂,却包含了三种性质完全不同的需求:
如果只描述成“把问题交给 LLM,LLM 需要时调用工具”,很多关键边界都会被藏起来。
知识从哪里来?当前进度是不是真的?模型凭什么能发送?用户有没有授权?最后怎样证明它没有伪造来源,也没有偷偷执行?
我开始沿着这几个问题,一段一段把链路接起来。
第一步是查询 Runtime 回滚知识。
Demo 中的最小检索器命中知识后,会同时返回 context 和 sources:
return {status: "found",context: top.document.content,sources: [top.document.sourceId]};
以前我更关注 context,因为那是 LLM 最终用来生成回答的内容。
今天我才真正把 sources 放回完整链路中理解:它不是为了让回答看起来更像一篇论文,而是检索阶段留下的证据。
如果只把 context 交给模型,再让模型自己补引用,它完全可能生成一个本次根本没有命中的来源。回答内容也许是对的,但系统无法证明引用是真的。
因此,Runtime 应该把本次检索得到的 sources 当成引用白名单:最终答案只能引用这次真正命中的来源。
这时我才意识到,RAG 的输出其实服务两个对象:
context → 给 LLM 生成回答sources → 给 Runtime、Trace 和 Eval 验证证据
第二个需求是查询当前学习进度。
它和前面的知识检索不同。课程进度会变化,而且属于某个具体用户。即使知识库里存在一条“当前学习到 L27”的旧记录,也不能证明它现在仍然正确。
所以这一步需要调用 get_learning_progress,从真实状态中读取结果。
这让我重新确认了 RAG 和 Tool 的分界:
这个 Tool 可以是 Runtime 中的本地函数,也可以由 MCP Server 提供。实现方式会变化,但职责关系不会变化:LLM 只能提出调用意图,真正的白名单检查、参数校验、权限判断和执行都在 Runtime。
Demo 还故意测试了一个未注册的 delete_account。它会被 Runtime 直接拒绝,而不是靠 Prompt 提醒模型“请不要删除账户”。
第三个需求是发送学习总结。
读取进度不会改变外部世界,发送却会产生真实副作用。于是 Runtime 在真正调用发送工具以前增加了一道人工确认门:
if (runtimeContext.userConfirmed !== true) {return {status: "needs_confirmation",tool: toolCall.name};}const delivery = await dependencies.sendLearningSummary(toolCall.arguments);
这段代码让我重新思考了一个看似普通的参数:userConfirmed 应该由谁管理?
它不能放在模型生成的 toolCall.arguments 中。
如果模型可以自己生成 userConfirmed=true,那就相当于它既申请执行,又替用户批准执行。用户实际上没有确认,模型却可能因为误判或提示注入越过边界。
因此,模型只能说“我想发送”,不能说“用户已经授权我发送”。
授权必须来自 Runtime 记录的真实交互:
模型提出发送→ Runtime 发现尚未确认→ 返回 needs_confirmation→ 用户真实确认→ Runtime 才调用发送工具
这也让我更具体地理解了为什么 Prompt 只是软约束。
Prompt 可以要求模型“发送前先询问用户”,但它不能百分之百保证模型永远照做。只有 Runtime 在调用外部工具前执行判断,才能保证未授权的副作用不会发生。
链路能够执行以后,还要回答另一个问题:怎样证明它执行正确?
我一开始的说法是“把预期行为都记录下来”。后来才发现,这句话把 Eval 和 Trace 混在了一起。
它们保存的不是同一种东西:
Eval 保存 expected:这条案例原本应该怎样流转Trace 保存 actual:这次任务实际上怎样流转评测器比较两者:判断通过、失败或退化
例如,Eval 可以预先规定:
Trace 则记录本次真实命中的来源 ID、工具调用、权限与确认决策、脱敏后的工具状态和最终回答。
这里还有一个安全边界:真实 Token、密码、完整敏感参数不应该为了“方便评测”又被写进 Eval 或 Trace。安全测试可以使用专门的合成 canary,但不能把真实秘密复制进公共证据链。
今天真正需要我亲手补全的代码并不多:检查整个 Trace 中是否出现合成敏感 canary。
我第一次直接写成:
const secretSafe = !actualTrace.includes(expected.syntheticCanaries);
但 actualTrace 是对象,不是字符串;syntheticCanaries 又是数组,也不能一次交给 includes。
第二次,我先序列化 Trace,再使用 some,却在回调里多写了一次取反:
const secretSafe = !expected.syntheticCanaries.some((canary) => !serializedTrace.includes(canary));
这段代码会把逻辑颠倒:没有出现的 canary 反而可能让安全检查失败,真正出现的 canary 却可能被判为安全。
正确的思路应该先判断“是否存在任一泄露”,再对整体结果取反:
const serializedTrace = JSON.stringify(actualTrace);const secretSafe = !expected.syntheticCanaries.some((canary) => serializedTrace.includes(canary));
我把布尔关系改对以后运行测试,又遇到了:
ReferenceError: serializedTrace is not defined
因为我使用了这个变量,却漏写了前面的声明。
补上以后,阶段测试终于变成 8/8 通过。完整链路接好以后,最终测试结果是:
10 tests10 pass0 fail
这几次错误让我意识到:能说出“敏感信息不能泄露”,不等于已经能写出正确、可验证的安全判断。
端到端 Demo 会用同一个任务运行两次:第一次没有人工确认,第二次已经确认。
输出结果是:
确认前:send_learning_summary = needs_confirmation确认后:send_learning_summary = successsimulatedSendCount = 1
我第一次看到 simulatedSendCount=1 时,实话实说,仅看代码我并不相信。
因为调用关系分散在不同位置:Demo 中的模拟函数通过闭包保存计数,Runtime 又在另一个文件中判断人工确认。
沿着真正的副作用调用点重新走一遍以后,关系才清楚:
这段代码把一个很重要的区别暴露了出来:
如果系统真的在发送邮件、创建订单或扣款,还需要继续记录工具结果、外部操作 ID、幂等键以及 sideEffectCommitted,才能判断动作究竟有没有发生。
为了避免自己只是记住了学习助手 Demo,我又把它迁移到另一个场景:
查一下公司的电脑采购规则→ 看看当前库存和价格→ 如果合适,替我下单 10 台
我给出的处理方式是:
工具名称和业务数据都变了,但 Agent 的职责边界没有变。
这次迁移也让我第一次感觉到,前面那些分散的概念正在变成一套可以复用的设计顺序。
今天以后,如果再让我从头梳理一个 Agent,我会先沿着下面这条线追问:
用户发起输入后,Runtime 会先确认任务身份与租户边界;接着由 RAG 检索相关知识,并把 sources 一并保留下来;随后,LLM 只会基于被允许的上下文给出回答,或发起 Tool Call;再往下,Runtime 会继续核验 Schema、白名单、权限以及参数是否合规;一旦涉及高风险动作,就必须等待真实人工确认;确认通过后,Tool 执行并返回结构化结果;与此同时,Runtime 会保存脱敏后的 Trace;然后,LLM 再根据工具结果生成最终回答;评测器则会对比 Eval expected 与 Trace actual;最后,再结合错误类型、副作用状态和幂等信息,决定是重试、转入人工介入,还是直接终止。
不过,这并不是所有 Agent 都得原样照搬的一套固定模板。
纯问答任务可能没有 Tool,确定性 Workflow 也可能不让 LLM 自由规划,某些 MCP Server 只需要提供 Resource。
但这条顺序至少能让我持续追问五件事:
信息从哪里来?谁做出决策?谁真正执行?硬边界在哪里?什么证据能证明它真的发生了?
相比再记住一个新的框架名称,这五个问题对我更有用。
本文对应的完整案例:
AI 学习助手整合 Demo
运行测试:
node --test
运行端到端演示:
node demo.mjs
实际核验结果:
10 tests10 pass0 fail
这个 Demo 并没有接入真实的 LLM、向量数据库、MCP Server 或邮件服务,而是用关键词检索加本地模拟依赖来跑通流程,再把结构化任务直接交给 Runtime 处理。目的很明确:不是追求完整线上能力,而是把 RAG、工具白名单、人工确认、Trace 和 Eval 这些边界清清楚楚地摊开,让它们既看得见,也测得到。
它不能被描述为一套可以直接上线的生产 Agent。
过去几周,我一直在逐个理解 Agent 的零件。
直到今天我才意识到,真正缺少的不是另一个新概念,而是随时从用户输入出发,把这些零件重新放回完整任务的能力。
我现在对“学会一个 Agent 概念”的理解也发生了一点变化:
下一步,我不准备继续给这条链路增加新零件。
我要先把这个 Demo 整理成别人十分钟内能够理解并运行的交付物,再尝试脱离笔记,把整条链路独立复述出来。
腾讯ima怎么把微信内容一键导入知识库?
腾讯ima怎么创建共享知识库?
Celestia价格预测2026-2032:TIA币能否引领山寨币上涨行情?历史价格回顾
比特币(BTC)核心周期指标复刻历史走势 价格或跌破5.8万美元关键支撑位
比特币 2025 年价格预测:BTC 的未来走势
新浪互联网热点小时报丨2026年07月26日16时_今日实时互联网热点速递
新浪机器学习热点小时报丨2026年07月25日18时_今日实时机器学习热点速递
WorkBuddy微信版怎么获得积分?
新浪人工智能热点小时报丨2026年07月30日18时_今日实时人工智能热点速递
5000元起的鼠标哪个最值得入手?
腾讯ima知识库怎么分类管理?
短剧《史上最强洪荒修为》剧情介绍
海尔消毒柜自动消毒如何中止
男生高性价比充电头?
博世壁挂炉关闭暖气怎么操作
车载冰箱重置到出厂设置几步?
Windy卫星云图怎么看?云层变化识别技巧
5000-6000元鼠标有什么推荐?
管线机怎么接云米净水器
笔记本移动电源推荐哪款?
手机号码测吉凶
本站所有软件,都由网友上传,如有侵犯你的版权,请发邮件haolingcc@hotmail.com 联系删除。 版权所有 Copyright@2012-2013 haoling.cc