mcpField
A
ai-agent

ai-agent

github.com/rivet-devAgent 工作流441.2k 次安装1 天前更新
代码仓库

关于 ai-agent

这是用于构建 AI Agent 后端的 RivetKit 技能,提供持久化对话、队列消息处理、流式响应和沙箱编码 Agent 示例,适合实现对话型 Agent 的开发者。

主要功能

  1. 01每段对话使用一个 Rivet Actor
  2. 02持久化对话状态
  3. 03按序处理消息队列
  4. 04广播流式响应
  5. 05提供沙箱编码 Agent 变体

适用场景

  1. 01构建具有独立对话记忆的聊天 Agent
  2. 02按序处理每段对话中的消息
  3. 03在隔离沙箱中创建编码 Agent

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/rivet-dev/skills --skill ai-agent

安装后在 Claude Code 中输入/ai-agent确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

BASE_SKILL.md
index.json
openapi.json
reference/actors/
access-control.md
actions.md
actor-runtime-socket.md
appearance.md
authentication.md
communicating-between-actors.md
connections.md
debugging.md
design-patterns.md
destroy.md
errors.md
events.md
fetch-and-websocket-handler.md
helper-types.md
http-api.md
input.md
inspector-tabs.md
keys.md
kv.md
lifecycle.md
limits.md
metadata.md
queues.md
reference/actors/quickstart/
backend.md
cloudflare.md
effect.md
next-js.md

详细介绍

AI Agent

重要:在开始任何操作之前,必须先阅读此技能目录中的 BASE_SKILL.md。其中包含有关调试、错误处理、状态管理、部署和项目设置的重要指导。这些规则和模式适用于所有 RivetKit 工作。以下内容均假设你已阅读并理解该文件。

可运行示例

如需参考实现,请阅读以下模板中的原始可运行示例代码:

使用 RivetKit 构建 AI Agent 后端的模式:每段对话对应一个 Rivet Actor,由它管理自己的记忆、消息队列和流式输出。

起始代码

从 GitHub 上的一个可运行示例开始并对其进行调整。除非特别指出某个变体,否则下文介绍的是旗舰示例 ai-agent。

变体起始代码适用场景
队列驱动的 AI SDK AgentGitHub你需要一个流式聊天 Agent,其中每段对话都有自己的持久记忆,并且每次处理一条消息。
沙箱编码 AgentGitHubAgent 需要通过 Docker、Daytona 或 E2B,在隔离的 沙箱中运行编码 Agent(默认使用 Codex)。
持久流 Agent(实验性)GitHub你希望通过持久流而非 Actor 状态和事件,实现可重放且在重启后仍安全可靠的提示词和响应传递。

对话记忆

每段对话使用一个 Actor,并以对话 ID 或 Agent ID 为键(参见Actor 键)。Agent Actor 的持久化状态就是对话记忆:在 ai-agent 示例中,messages 和 status 存储在 JSON Actor 状态中,并且在休眠和重启后仍会保留,无需外部数据库。每次调用模型时,都会根据 c.state.messages 和系统提示词重新构建提示词,因此记忆和推理输入使用的是同一份数据。

变体记忆存储位置持久化状态字段
ai-agentJSON Actor 状态messages、status
sandbox-coding-agentJSON Actor 状态和沙箱 ACP 会话messages、status、sessionId
experimental-durable-streams-ai-agent持久流;Actor 仅存储对话 ID 和读取游标conversationId、promptStreamOffset

消息处理

在 ai-agent 示例中,客户端通过 agent.connection.send("message", { text, sender }) 将用户输入推送到 Agent 的 message队列中。这是队列推送,而非 action 调用。Actor 的 run 钩子(参见生命周期)通过 for await (const queued of c.queue.iter()) 按顺序消费队列。

按顺序消费队列可保证每段对话的并发安全:每个 Actor 同一时间最多只有一次模型调用在执行,无需额外加锁。status 字段(模型调用进行中时为 thinking)仅用于向 UI 传递状态;真正的锁是运行循环。循环还会在令牌流中检查 c.aborted,以便在关闭时正常退出。

变体消息入口顺序处理保证
ai-agent通过 connection.send 推送到 message 队列run 钩子通过 c.queue.iter() 每次取出一条排队消息。
sandbox-coding-agentsendMessage action,不使用队列每次调用都会等待沙箱往返完成,然后再广播结果。
experimental-durable-streams-ai-agent在 onWake 中通过长轮询读取持久提示词流每个数据块的 promptStreamOffset 都会持久化,因此重启后可继续处理,而不会重复处理提示词。

流式响应

ai-agent actor 会为每个模型文本增量广播一个 response 事件。负载包含 messageId、每个 token 的 delta、累积的 content 和 done 标志(失败时还会包含 error),因此客户端可以追加增量,也可以使用 content 按 messageId 幂等地替换消息。示例前端按 messageId 替换,这样即使事件丢失也能正常处理。终止广播的 delta 为空,包含完整的 content,并且 done: true。

由于助手消息对象存储在 c.state.messages 中,并在流式传输期间原地修改,因此如果 actor 在流式传输中途重启,部分内容仍会保留。示例会针对每个 AI SDK 增量广播一次,不进行节流;对于高流量部署,建议将增量分批或进行节流扩展,但示例并未实现这些功能。

变体差异:sandbox-coding-agent 会在沙箱运行结束后发送一条 done: true 的 response 广播(不进行增量流式传输);experimental-durable-streams-ai-agent 会将逐 token 分块内容追加到持久化响应流,然后广播 responseComplete 或 responseError。

架构

主题摘要
拓扑agentManager["primary"] 单例目录,以及每个对话对应一个 agent[agentId] actor。
接入客户端通过 connection.send 将 AgentQueueMessage 负载推送到 agent 的 message 队列。
流式传输每个模型增量广播一次 response,并通过 done: true 发送终止广播。
记忆完整对话记录和状态保存在 JSON actor 状态中;不使用外部数据库。

管理器会创建 AgentInfo 记录,并通过actor 之间的通信预热每个 agent:createAgent 调用 c.client<typeof registry>(),然后调用 client.agent.getOrCreate([info.id]) 并等待 getStatus(),确保对话 actor 在客户端连接前已存在。沙箱变体在此拓扑上扩展了一个 codingSandbox actor,该 actor 与 agent 共用同一个键(codingSandbox.getOrCreate([c.key[0]])),因此 agent 到沙箱的映射隐含在键空间中。

Actors

  • 键:agentManager["primary"]

  • 职责:目录 actor。创建 AgentInfo 记录、列出 agent,并通过 c.client() 预热每个 agent actor。

  • 操作

    • createAgent
    • listAgents
  • 队列

    • 无
  • 状态

    • JSON
    • agents
  • 键:agent[agentId]

  • 职责:每个对话对应一个 actor。保存完整的消息历史和状态,在其 run 循环中消费排队的用户消息,通过 AI SDK 调用模型,并广播流式增量。

  • 操作

    • getHistory
    • getStatus
  • 队列

    • message
  • 事件

    • messageAdded
    • status
    • response
  • 状态

    • JSON
    • messages
    • status

生命周期

sequenceDiagram
	participant C as Client
	participant AM as agentManager
	participant A as agent
	participant LLM as Model API

	C->>AM: createAgent(name)
	AM->>A: getOrCreate([info.id]) + getStatus()
	AM-->>C: AgentInfo
	C->>A: connection.send("message", {text, sender})
	Note over A: run loop pops queue via c.queue.iter()
	A-->>C: messageAdded (user message)
	A-->>C: messageAdded (assistant placeholder)
	A-->>C: status (thinking)
	A->>LLM: streamText(system prompt + history)
	loop each text delta
		LLM-->>A: delta
		A-->>C: response {messageId, delta, content, done: false}
	end
	A-->>C: response {delta: "", content, done: true}
	A-->>C: status (idle)

安全检查清单

示例未配置身份验证,以保持精简。在公开 Agent 后端之前,请应用以下基线措施。

  • API 密钥保留在服务器端:AI SDK 会在 actor 进程中读取 OPENAI_API_KEY(或 ANTHROPIC_API_KEY)。密钥永远不会发送到浏览器;客户端只通过 RivetKit 与 actor 通信。沙箱变体会将密钥传递到沙箱环境中,绝不会发送给客户端。
  • 添加身份验证:示例没有身份验证,因此任何能够访问服务器的人都可以创建 Agent、列出 Agent,并向任何其密钥可被猜中的 Agent 发送消息。建议扩展时添加 onBeforeConnect 或 createConnState 检查,并使用作用域令牌。请参阅身份验证。
  • 验证队列负载并限制速率:示例只会跳过不含字符串 text 的请求正文。建议扩展时强制执行负载大小限制、架构验证和每连接速率限制。
  • 在服务器端确定发送者身份:示例会原样信任客户端提供的 sender 字段。请改为将发送者身份绑定到经过身份验证的连接。
  • 限制或裁剪消息历史记录:示例在每次模型调用时都会发送完整的对话记录,且不设上限。建议扩展时裁剪或总结较早的消息,以限制提示词和状态的大小。
  • 为每次对话设置成本上限:建议扩展时添加每个 Agent 的令牌预算和配额。沙箱变体会运行实际计算,因此还应强制执行每用户沙箱配额,并限制沙箱的网络出口流量。

参考索引

Actors
命令行
客户端
指南
部署
常规
自托管

评论

支持 Markdown