Skip to content
文章目录
GitHub Star

从 Chat 到 Copilot,再到 Agent:AI 系统的底层架构究竟发生了什么变化? ​

为什么一个能回答问题的大模型,接入编辑器就成为 Copilot,再接上工具与执行循环就能承担 Agent 任务?如果还希望它长期工作,又需要增加什么?

很多介绍把这些变化描述成 AI 越来越智能、越来越自主。但从工程实现看,更值得研究的是:这几个阶段未必需要不同的大模型,持续扩展的主要是模型周围的软件系统。

最初,应用负责组装输入,模型生成输出。随后,应用把工作环境变成上下文,让模型提出可审阅的修改。再往后,模型的输出开始参与决定程序下一步调用什么工具;实际执行结果回到模型输入,形成观察与行动循环。任务跨越会话和时间之后,还需要调度、持久化、恢复、记忆以及重新检查授权。

本文用一项基金资料研究任务,沿着 Chat → Copilot → Agent → 长期助手 四种典型工作方式解释架构增量。这不是严格的产品代际:现代 ChatGPT 与 GitHub Copilot 都能在同一产品中组合多种方式。我们关心的是,每扩展一份任务责任,底层多出了哪些机制,为什么不能只靠更强的 Prompt 解决。

一、Chat:一次模型调用,最重要的是本轮输入 ​

用户问:“红利低波基金为什么会下跌?”

一个最简模型应用如下:

text
用户问题 → 应用组装 Messages → Model API → 生成回答 → 用户

教学伪代码:

javascript
const response = await model.generate({
  messages: [
    { role: "system", content: instructions },
    { role: "user", content: question }
  ]
});
return response.text;

模型可以解释利率、估值、红利策略和波动的关系,却不一定知道用户持有哪只基金,更不一定读取了当天的市场信息。训练得到的模型参数与本次推理实际收到的上下文是两回事。一次普通推理不会自动修改模型权重;在典型 API 应用中,连续对话也需要应用维护、选择并再次传递相关历史。

所以 Chat 应用的核心工程工作是 Prompt 与消息组织、历史管理、流式交付、超时处理,以及上下文预算控制。

即使加入检索增强生成(RAG),也未必改变执行控制权:

text
问题 → 固定检索逻辑 → 资料 + Prompt → 模型 → 回答

数据库和搜索结果增加了知识来源,但检索几次、查哪个库、何时结束,仍然可能完全由代码预先决定。此时关键问题是:模型看到了什么,能否根据这些输入生成有用且适用的回答?

二、Copilot:把工作环境转化为 Context,把建议接回工作对象 ​

把同一个模型放进 IDE,情况就不同了。用户不再需要复制整个文件解释问题;应用可以按需收集光标位置、选区、相关文件、符号定义、诊断信息和项目约束。

一个典型的编辑器辅助路径是:

text
编辑器事件 / 用户指令
     ↓
环境感知:文件、选区、诊断、代码索引
     ↓
相关性选择、上下文裁剪与预算分配
     ↓
Model
     ↓
补全 / Patch / 修改建议
     ↓
预览 → 用户采纳或拒绝 → 更新工作对象

这带来两个独立的架构增量。

第一,Prompt 变成了环境驱动的上下文工程。 用户当前正在做什么,未必已经完整写进聊天框。系统需要从真实工作环境选取相关信息,而不是盲目塞入整个仓库。语法树、LSP、全文检索、向量检索都可以参与,但没有一种是所有 Copilot 的必备组件。

第二,生成内容可以作用于具体工作对象。 模型不再只返回解释,还可以产生补全、结构化编辑或 Patch。宿主应用负责预览、应用与撤销。以 GitHub Copilot 的编辑和 Agent 模式为例,同一产品可以提供不同程度的用户主导与自主执行,不能把 Copilot 和 Agent 当成互斥技术类别。

基金应用也类似:用户打开某只基金的持仓页,选中两条净值曲线,AI 根据当前基金、日期和指标解释差异。用户仍然主导页面与操作流程,模型提供嵌入式帮助。

Chat → Copilot 的主要变化是模型的工作视野与输出落点,而不一定是模型取得了下一步执行的决定权。

三、Agent:模型开始参与决定下一步,执行控制权随之重新划分 ​

现在用户要求:“比较两只基金的披露持仓,计算重叠情况,附上来源并保存报告。”

如果流程完全确定,普通程序足够:

text
读取 A → 读取 B → 校验口径 → 计算 → 生成报告

即使每一步都调用模型,也仍然可以是一条预定义的 AI 工作流。

问题在于,开放研究往往在运行后才暴露条件:两份材料统计时点不同,一份仅披露前十大持仓,另一份包含更多项目。此时要补查同期披露、改变比较方法,还是只给出限定范围的结论?模型可以根据新观察提出不同的后续行动。

因此,Agent 新增了一条反馈路径:

text
用户目标
   ↓
Runtime 组装本轮工作上下文
   ↓
Model 输出结构化动作提案
   ↓
Runtime / Tool Host 校验授权、参数、预算
   ├─ 不允许:拒绝并记录观察
   └─ 允许:实际调用工具
                ↓
           工具结果 / Observation
                ↓
      回到模型判断:继续 / 求助 / 结束

Anthropic《Building effective agents》用预定义代码路径和由模型动态主导工具使用的过程,区分 Workflow 与 Agent。这是理解控制权的有用坐标,但二者可以组合使用。

1. 工具调用首先是提案,不是权限 ​

与其让模型输出“我要搜索基金数据”再做字符串解析,更合适的是明确工具名称、参数和返回结构。例如教学协议:

json
{
  "kind": "calls",
  "calls": [
    {
      "id": "call-001",
      "name": "search_documents",
      "arguments": {
        "fundId": "fund-a",
        "documentType": "holding-disclosure"
      }
    }
  ]
}

这只是模型提出的动作,不证明工具已经执行,更不意味着模型可以自行扩张资源范围。

Runtime 必须确认工具是否存在、参数是否满足契约、资料是否获准、资源与执行预算是否足够。真正的动作由 Tool Host 执行;未授权访问不能通过换工具或改 Prompt 绕过。

2. Observation 必须成为下一轮判断的条件 ​

假设读取成功,返回的事实是:

json
{
  "callId": "call-001",
  "status": "succeeded",
  "observation": {
    "asOfDate": "2026-06-30",
    "coverage": "top-ten-holdings"
  }
}

工具成功,只能说明取得了这份资料。模型还需要发现:它不是当前完整持仓。如果模型据此改变研究方案,观察才真正进入了执行决策。如果仍然按原顺序输出“完整组合重叠率”,工具调用再多也不能证明研究质量。

Agent Loop 的关键不在循环次数,而在新的真实观察可以改变后续动作。

四、真正的 Runtime:为什么不能只写一个 while 循环? ​

最小循环并不难写:

javascript
// 教学伪代码:刻意省略持久化、未知效果和恢复
while (!done) {
  const proposal = await model.next(buildContext(state));
  if (proposal.kind === "final") break;
  for (const call of proposal.calls) {
    const decision = policy.check(call);
    const result = decision.allowed
      ? await toolHost.execute(call)
      : { status: "rejected", reason: decision.reason };
    state.addObservation(result);
  }
}

难点在真实调用的生命期。可以对照 Open ETF Agent v0.24 的固定 Runtime 源码。

该实现中,gateway.next() 返回模型提案,validateProposal() 校验结构,createToolHost() 建立工具宿主,host.execute() 执行工具。Runtime 还控制轮次、工具预算、执行期限,以及持久化的运行状态。

这并不是给循环随意增加模块,而是区分原本容易被混淆的执行事实。

派发、执行完成、结果消费不是一回事 ​

以保存报告为例:

text
模型提出保存
    ↓
proposal-sealed(提案已确认)
    ↓
tool-dispatched(工具已派发)
    ↓
result-committed(结果已提交)
    ↓
result-consumed(结果进入后续执行历史)

如果程序已经派发写入请求,却在收到回执前崩溃,外部操作可能成功、失败,也可能仍在进行。未知不等于失败;不确认效果就重放,可能造成重复副作用。

Open ETF Agent 将 model-reserved、proposal-sealed、tool-dispatched、result-committed、result-consumed 等阶段作为不同的恢复事实。它不声称能对所有外部系统提供通用的“恰好一次”保证。

这与成熟后台中的事务、幂等和故障恢复一脉相承。Agent 的新增难点在于,动作顺序可能是模型运行时才决定的,因此约束不能只写在一条固定业务流程里。

真实系统状态,也不同于模型工作上下文 ​

还有一种区别同样重要:

执行状态记录系统已经派发、取得、保存和确认的事实。

工作上下文是本轮模型实际收到的目标、历史、摘要、工具描述和来源片段。

某页原文保存在数据库中,不代表本轮模型已经看到它。摘要如果省略“仅披露前十大持仓”,模型可能沿错误的比较范围继续。需要通过上下文投影、原始引用和按需回读,在有限输入窗口中保留决定性条件。

因此,排查“Agent 为什么走了错误路径”时,不能只看用户最初的问题和最终答案,还应当能够检查当时的模型输入、工具提案、实际派发及返回结果。

执行完成,不等于成果正确 ​

在 Open ETF Agent v0.24 真实模型验证记录中,有一个具体的错引例子。

模型完成任务并保存报告,但报告中一句关于导入行数的引用指向了错误的来源。最终回复披露了错误,原报告文件却没有被修复。

这同时成立了几件事:执行机制完成、文件存在、模型意识到错误,以及用户之后仍可能打开错误版本的报告。

所以不能把工具调用成功率、Run 完成状态和研究语义质量混成同一个“Agent 成功率”。文件实际保存了什么、报告结论是否有依据、用户能否打开经过核查的版本,需要分别判断。

五、从一次 Agent 到长期助手:状态必须跨越一次运行 ​

一次性 Agent 通常由用户发起,完成或停止后结束 Run。

如果用户变成:“持续关注基金组合,当披露与风险暴露发生值得注意的变化时提醒我”,单纯把循环运行得更久并不合适。

长期目标更合理的技术结构是:

text
用户长期目标 + 可撤回的授权
          ↓
Cron / 事件触发 / 人工请求
          ↓
创建一次有界 Run
          ↓
读取当前业务事实和必要历史
重新检查本次权限与资源
          ↓
Agent Runtime 执行
          ↓
持久化成果、回执与任务状态
          ↓
通知 / 等待人工决定 / 正常结束
          ↓
后续事件可创建下一次 Run

与一次性任务相比,至少增加了三类机制。

1. 调度:谁决定什么时候发起研究? ​

Cron、队列或事件总线负责触发任务。它们并不证明模型的研究正确,也不应该绕过 Run 的授权和预算。一次长期目标可以由许多独立、有停止条件的 Run 共同推进,而不是让同一个模型会话永远运行。

2. 持久化与恢复:中断以后允许继续什么? ​

浏览器关闭、网络断开、进程崩溃并不具有相同含义。恢复必须保留原任务身份、已经发生的动作、已保存的结果和结果未知的派发,不能把每次中断都当作安全重试。

LangGraph 的持久化与 Checkpoint 文档提供了这种设计的参考,但 Checkpoint 本身也不自动保证外部写入没有重复副作用。

3. 记忆:历史存在、被召回、被采用是三步 ​

长期助手还需要区分:

数据例子再使用时要检查什么
业务事实持仓、目标配置、最新披露当前性、统计口径、访问权限
执行事实原报告、工具结果、文件版本原始身份、结果状态、可回读性
长期记忆用户偏好、纠错和关注方向是否获准保存、是否适用、是否过期

把三类数据统统塞进一个向量数据库,并不能自动得到长期个人助手。

例如,用户上个月说过“希望提高海外资产配置”,可以作为本次研究的参考,但不能自动成为今天的交易授权。上周的报告可能有帮助,但必须保留统计日期和原始依据。普通推理也不会因为检索了旧报告就自动更新模型权重。

长期性的核心不只是记住,而是下一次能够正确使用仍然有效的事实,并在条件变化时撤回过期判断。

六、四种工作方式,底层增加了哪些能力? ​

架构维度ChatCopilotAgent长期助手
输入用户消息、对话历史、可选 RAG增加实时环境和工作对象增加每轮工具观察与工作上下文增加跨 Run 历史、目标与事件
下一步由谁选择主要是预定义应用流程人与宿主组织工作模型在授权内参与选择动作调度决定启动,模型在每次 Run 内选择
输出生成内容补全、Patch、可采纳修改工具操作、研究结果和持久产物多次执行的成果、提醒和待决事项
新增执行机制模型 API、上下文组装IDE/应用集成、修改应用Runtime、Tool Host、Loop、回执调度、持久化、恢复、记忆治理
关键风险幻觉、信息缺失不相关上下文、错误修改越权、未知副作用、错误交付过期事实、权限漂移、重复工作

这张表表达的是典型架构切面,而不是产品等级。一个 Copilot 可以包含 Agent 模式,一个 Agent 可以没有记忆,一个严格业务工作流也可以拥有调度和持久化。

所以选型时,首先应该问:任务路径是否真正需要模型根据观察动态决定? 如果输入固定、计算确定、失败条件可枚举,一条普通程序或工作流往往更简单,也更容易测试。

只有当不确定性确实影响下一步,才值得付出 Agent Runtime 的复杂度。只有任务需要跨时间持续推进,才进一步引入长期目标与恢复体系。

七、下一步的重点不是“彻底无人化”,而是有界的持续协作 ​

未来系统可能通过更精细的上下文装配、更稳定的工具协议、独立的专业子任务和可靠的记忆机制,承担更长、更复杂的任务。

但多 Agent 不一定比单 Agent 准确,循环更久不一定产生更多有效证据,能保存历史也不意味着真正学会了用户的偏好。

尤其在金融场景,模型可以组织研究,却不能因为报告生成成功就直接取得投资决策和交易权限。市场数据时点、指标口径、适当性与外部操作仍然需要独立约束。

因此,我不认为 Agent 演进的终点应当是“人完全退出流程”。工程上更合理的目标是:模型负责不确定路径中的判断,确定性程序负责事实与效果,用户保留目标、授权和关键决策权。

结语:从生成答案,到参与控制真实工作 ​

Chat 阶段,软件为模型准备输入并接收生成内容。

Copilot 阶段,软件把用户的工作环境转化为上下文,并让模型建议进入真实工作对象。

Agent 阶段,模型开始根据观察参与决定执行路径;Runtime 必须接管动作校验、状态、预算、未知效果和交付。

长期助手阶段,任务跨越一次 Run,需要调度、持久化、恢复、记忆和持续授权。

真正的演进不是给同一个模型多套几层循环,而是把部分行动决策交给模型,同时让软件系统继续掌握真实的权限、执行事实与结果。

模型变强,可以让更多开放任务成为可能;系统能否可靠承接这些任务,取决于我们是否把上述职责划分清楚。


延伸阅读与代码 ​

如果这套实践对你有帮助,欢迎给 Open ETF Agent 或 Agent 工程文集 一个 Star,也欢迎交流具体的设计取舍。

与个人博客并行:这里按问题连续阅读,博客保留时间线。 · 联系邮箱:hpoenixf@foxmail.com · 微信:hpoenixf0510