从 Chat 到 Copilot,再到 Agent:AI 系统的底层架构究竟发生了什么变化?
为什么一个能回答问题的大模型,接入编辑器就成为 Copilot,再接上工具与执行循环就能承担 Agent 任务?如果还希望它长期工作,又需要增加什么?
很多介绍把这些变化描述成 AI 越来越智能、越来越自主。但从工程实现看,更值得研究的是:这几个阶段未必需要不同的大模型,持续扩展的主要是模型周围的软件系统。
最初,应用负责组装输入,模型生成输出。随后,应用把工作环境变成上下文,让模型提出可审阅的修改。再往后,模型的输出开始参与决定程序下一步调用什么工具;实际执行结果回到模型输入,形成观察与行动循环。任务跨越会话和时间之后,还需要调度、持久化、恢复、记忆以及重新检查授权。
本文用一项基金资料研究任务,沿着 Chat → Copilot → Agent → 长期助手 四种典型工作方式解释架构增量。这不是严格的产品代际:现代 ChatGPT 与 GitHub Copilot 都能在同一产品中组合多种方式。我们关心的是,每扩展一份任务责任,底层多出了哪些机制,为什么不能只靠更强的 Prompt 解决。
一、Chat:一次模型调用,最重要的是本轮输入
用户问:“红利低波基金为什么会下跌?”
一个最简模型应用如下:
用户问题 → 应用组装 Messages → Model API → 生成回答 → 用户教学伪代码:
const response = await model.generate({
messages: [
{ role: "system", content: instructions },
{ role: "user", content: question }
]
});
return response.text;模型可以解释利率、估值、红利策略和波动的关系,却不一定知道用户持有哪只基金,更不一定读取了当天的市场信息。训练得到的模型参数与本次推理实际收到的上下文是两回事。一次普通推理不会自动修改模型权重;在典型 API 应用中,连续对话也需要应用维护、选择并再次传递相关历史。
所以 Chat 应用的核心工程工作是 Prompt 与消息组织、历史管理、流式交付、超时处理,以及上下文预算控制。
即使加入检索增强生成(RAG),也未必改变执行控制权:
问题 → 固定检索逻辑 → 资料 + Prompt → 模型 → 回答数据库和搜索结果增加了知识来源,但检索几次、查哪个库、何时结束,仍然可能完全由代码预先决定。此时关键问题是:模型看到了什么,能否根据这些输入生成有用且适用的回答?
二、Copilot:把工作环境转化为 Context,把建议接回工作对象
把同一个模型放进 IDE,情况就不同了。用户不再需要复制整个文件解释问题;应用可以按需收集光标位置、选区、相关文件、符号定义、诊断信息和项目约束。
一个典型的编辑器辅助路径是:
编辑器事件 / 用户指令
↓
环境感知:文件、选区、诊断、代码索引
↓
相关性选择、上下文裁剪与预算分配
↓
Model
↓
补全 / Patch / 修改建议
↓
预览 → 用户采纳或拒绝 → 更新工作对象这带来两个独立的架构增量。
第一,Prompt 变成了环境驱动的上下文工程。 用户当前正在做什么,未必已经完整写进聊天框。系统需要从真实工作环境选取相关信息,而不是盲目塞入整个仓库。语法树、LSP、全文检索、向量检索都可以参与,但没有一种是所有 Copilot 的必备组件。
第二,生成内容可以作用于具体工作对象。 模型不再只返回解释,还可以产生补全、结构化编辑或 Patch。宿主应用负责预览、应用与撤销。以 GitHub Copilot 的编辑和 Agent 模式为例,同一产品可以提供不同程度的用户主导与自主执行,不能把 Copilot 和 Agent 当成互斥技术类别。
基金应用也类似:用户打开某只基金的持仓页,选中两条净值曲线,AI 根据当前基金、日期和指标解释差异。用户仍然主导页面与操作流程,模型提供嵌入式帮助。
Chat → Copilot 的主要变化是模型的工作视野与输出落点,而不一定是模型取得了下一步执行的决定权。
三、Agent:模型开始参与决定下一步,执行控制权随之重新划分
现在用户要求:“比较两只基金的披露持仓,计算重叠情况,附上来源并保存报告。”
如果流程完全确定,普通程序足够:
读取 A → 读取 B → 校验口径 → 计算 → 生成报告即使每一步都调用模型,也仍然可以是一条预定义的 AI 工作流。
问题在于,开放研究往往在运行后才暴露条件:两份材料统计时点不同,一份仅披露前十大持仓,另一份包含更多项目。此时要补查同期披露、改变比较方法,还是只给出限定范围的结论?模型可以根据新观察提出不同的后续行动。
因此,Agent 新增了一条反馈路径:
用户目标
↓
Runtime 组装本轮工作上下文
↓
Model 输出结构化动作提案
↓
Runtime / Tool Host 校验授权、参数、预算
├─ 不允许:拒绝并记录观察
└─ 允许:实际调用工具
↓
工具结果 / Observation
↓
回到模型判断:继续 / 求助 / 结束Anthropic《Building effective agents》用预定义代码路径和由模型动态主导工具使用的过程,区分 Workflow 与 Agent。这是理解控制权的有用坐标,但二者可以组合使用。
1. 工具调用首先是提案,不是权限
与其让模型输出“我要搜索基金数据”再做字符串解析,更合适的是明确工具名称、参数和返回结构。例如教学协议:
{
"kind": "calls",
"calls": [
{
"id": "call-001",
"name": "search_documents",
"arguments": {
"fundId": "fund-a",
"documentType": "holding-disclosure"
}
}
]
}这只是模型提出的动作,不证明工具已经执行,更不意味着模型可以自行扩张资源范围。
Runtime 必须确认工具是否存在、参数是否满足契约、资料是否获准、资源与执行预算是否足够。真正的动作由 Tool Host 执行;未授权访问不能通过换工具或改 Prompt 绕过。
2. Observation 必须成为下一轮判断的条件
假设读取成功,返回的事实是:
{
"callId": "call-001",
"status": "succeeded",
"observation": {
"asOfDate": "2026-06-30",
"coverage": "top-ten-holdings"
}
}工具成功,只能说明取得了这份资料。模型还需要发现:它不是当前完整持仓。如果模型据此改变研究方案,观察才真正进入了执行决策。如果仍然按原顺序输出“完整组合重叠率”,工具调用再多也不能证明研究质量。
Agent Loop 的关键不在循环次数,而在新的真实观察可以改变后续动作。
四、真正的 Runtime:为什么不能只写一个 while 循环?
最小循环并不难写:
// 教学伪代码:刻意省略持久化、未知效果和恢复
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 还控制轮次、工具预算、执行期限,以及持久化的运行状态。
这并不是给循环随意增加模块,而是区分原本容易被混淆的执行事实。
派发、执行完成、结果消费不是一回事
以保存报告为例:
模型提出保存
↓
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。
如果用户变成:“持续关注基金组合,当披露与风险暴露发生值得注意的变化时提醒我”,单纯把循环运行得更久并不合适。
长期目标更合理的技术结构是:
用户长期目标 + 可撤回的授权
↓
Cron / 事件触发 / 人工请求
↓
创建一次有界 Run
↓
读取当前业务事实和必要历史
重新检查本次权限与资源
↓
Agent Runtime 执行
↓
持久化成果、回执与任务状态
↓
通知 / 等待人工决定 / 正常结束
↓
后续事件可创建下一次 Run与一次性任务相比,至少增加了三类机制。
1. 调度:谁决定什么时候发起研究?
Cron、队列或事件总线负责触发任务。它们并不证明模型的研究正确,也不应该绕过 Run 的授权和预算。一次长期目标可以由许多独立、有停止条件的 Run 共同推进,而不是让同一个模型会话永远运行。
2. 持久化与恢复:中断以后允许继续什么?
浏览器关闭、网络断开、进程崩溃并不具有相同含义。恢复必须保留原任务身份、已经发生的动作、已保存的结果和结果未知的派发,不能把每次中断都当作安全重试。
LangGraph 的持久化与 Checkpoint 文档提供了这种设计的参考,但 Checkpoint 本身也不自动保证外部写入没有重复副作用。
3. 记忆:历史存在、被召回、被采用是三步
长期助手还需要区分:
| 数据 | 例子 | 再使用时要检查什么 |
|---|---|---|
| 业务事实 | 持仓、目标配置、最新披露 | 当前性、统计口径、访问权限 |
| 执行事实 | 原报告、工具结果、文件版本 | 原始身份、结果状态、可回读性 |
| 长期记忆 | 用户偏好、纠错和关注方向 | 是否获准保存、是否适用、是否过期 |
把三类数据统统塞进一个向量数据库,并不能自动得到长期个人助手。
例如,用户上个月说过“希望提高海外资产配置”,可以作为本次研究的参考,但不能自动成为今天的交易授权。上周的报告可能有帮助,但必须保留统计日期和原始依据。普通推理也不会因为检索了旧报告就自动更新模型权重。
长期性的核心不只是记住,而是下一次能够正确使用仍然有效的事实,并在条件变化时撤回过期判断。
六、四种工作方式,底层增加了哪些能力?
| 架构维度 | Chat | Copilot | Agent | 长期助手 |
|---|---|---|---|---|
| 输入 | 用户消息、对话历史、可选 RAG | 增加实时环境和工作对象 | 增加每轮工具观察与工作上下文 | 增加跨 Run 历史、目标与事件 |
| 下一步由谁选择 | 主要是预定义应用流程 | 人与宿主组织工作 | 模型在授权内参与选择动作 | 调度决定启动,模型在每次 Run 内选择 |
| 输出 | 生成内容 | 补全、Patch、可采纳修改 | 工具操作、研究结果和持久产物 | 多次执行的成果、提醒和待决事项 |
| 新增执行机制 | 模型 API、上下文组装 | IDE/应用集成、修改应用 | Runtime、Tool Host、Loop、回执 | 调度、持久化、恢复、记忆治理 |
| 关键风险 | 幻觉、信息缺失 | 不相关上下文、错误修改 | 越权、未知副作用、错误交付 | 过期事实、权限漂移、重复工作 |
这张表表达的是典型架构切面,而不是产品等级。一个 Copilot 可以包含 Agent 模式,一个 Agent 可以没有记忆,一个严格业务工作流也可以拥有调度和持久化。
所以选型时,首先应该问:任务路径是否真正需要模型根据观察动态决定? 如果输入固定、计算确定、失败条件可枚举,一条普通程序或工作流往往更简单,也更容易测试。
只有当不确定性确实影响下一步,才值得付出 Agent Runtime 的复杂度。只有任务需要跨时间持续推进,才进一步引入长期目标与恢复体系。
七、下一步的重点不是“彻底无人化”,而是有界的持续协作
未来系统可能通过更精细的上下文装配、更稳定的工具协议、独立的专业子任务和可靠的记忆机制,承担更长、更复杂的任务。
但多 Agent 不一定比单 Agent 准确,循环更久不一定产生更多有效证据,能保存历史也不意味着真正学会了用户的偏好。
尤其在金融场景,模型可以组织研究,却不能因为报告生成成功就直接取得投资决策和交易权限。市场数据时点、指标口径、适当性与外部操作仍然需要独立约束。
因此,我不认为 Agent 演进的终点应当是“人完全退出流程”。工程上更合理的目标是:模型负责不确定路径中的判断,确定性程序负责事实与效果,用户保留目标、授权和关键决策权。
结语:从生成答案,到参与控制真实工作
Chat 阶段,软件为模型准备输入并接收生成内容。
Copilot 阶段,软件把用户的工作环境转化为上下文,并让模型建议进入真实工作对象。
Agent 阶段,模型开始根据观察参与决定执行路径;Runtime 必须接管动作校验、状态、预算、未知效果和交付。
长期助手阶段,任务跨越一次 Run,需要调度、持久化、恢复、记忆和持续授权。
真正的演进不是给同一个模型多套几层循环,而是把部分行动决策交给模型,同时让软件系统继续掌握真实的权限、执行事实与结果。
模型变强,可以让更多开放任务成为可能;系统能否可靠承接这些任务,取决于我们是否把上述职责划分清楚。
延伸阅读与代码
- Agent 开发与后台开发有什么不同:从一次请求到长期个人助手
- 投研 Agent 的关键不是多调用工具:Model、Harness 与 Loop
- 十五分钟入门 Agent
- Open ETF Agent:固定 v0.24 Runtime
- Anthropic:Building effective agents
- Anthropic:Effective context engineering for AI agents
- GitHub Copilot:Agent mode
- LangGraph:Persistence
如果这套实践对你有帮助,欢迎给 Open ETF Agent 或 Agent 工程文集 一个 Star,也欢迎交流具体的设计取舍。