Electric Agents Walkthrough 实战指南:用 Hono 从零搭建可扩展的多 Agent 系统
2026/9/15 10:44:35 网站建设 项目流程

Electric Agents Walkthrough 实战指南:用 Hono 从零搭建可扩展的多 Agent 系统

【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric

本指南以仓库内examples/agents-walkthrough示例为核心,逐步讲解如何把一个仅有Hello Hono!的裸 Web 应用,演进成一个具备"LLM 决策 + 持久化状态驱动确定性流程"能力的多 Agent 系统。读完本文,你将掌握 Electric Agents 的实体注册、运行时 Webhook 接线、子 Agent 派生(ctx.spawn)、消息路由(ctx.send/ctx.sleep)、持久化状态集合(ctx.state)以及跨实体观察(ctx.observe)等核心能力,并理解"混合控制流"这一让 Agent 系统既灵活又可靠的关键设计。

示例是什么:一份可对照官方向导逐行演进的参考实现

examples/agents-walkthrough是官方 Walkthrough 向导 的配套参考代码。该向导的目标是从"新建或已有的 Web/移动应用"出发,一步步把它变成动态的多 Agent 系统。示例仓库通过 6 份源码文件记录了完整的演进过程:

文件对应向导阶段核心内容
src/index0.ts起点裸 Hono 应用,只返回Hello Hono!
src/index1.tsStep 1定义assistant实体并接入运行时
src/index2.tsStep 2manager在 handler 里命令式ctx.spawn子 Agent
src/index3.tsStep 3用工具调用(tool call)派生子 Agent
src/index4.tsStep 4judge实体编排双方辩论(纯提示词驱动)
src/index5.tsStep 5混合控制流:持久化状态 + 命令式流程

其中默认的 src/index.ts 是index5.ts的拷贝,即向导最后一节"混合控制流"的成品形态——你可以直接以它为起点运行、研究。

运行示例:三步起一个本地多 Agent 环境

前置依赖

与 Quickstart 一致,需要:

  • Node.js 18+(含 pnpm)
  • Docker(本地开发服务器跑在容器里)
  • Anthropic API Key

安装与启动

examples/agents-walkthrough目录下执行:

pnpm install pnpm dev

package.json中的dev脚本为:

"dev": "tsx watch --env-file=.env src/index.ts"

也就是说,示例通过tsx watch以 Node 直接运行 TypeScript 源码,并通过--env-file=.env加载环境变量——你需要先在该目录创建.env文件并写入:

ANTHROPIC_API_KEY="sk-ant-..."

先启动 Agents 运行时服务器

示例本身只是一个 Web 应用,真正的 Agent 运行环境(Postgres、Electric 与 Electric Agents 服务器,内含 Durable Streams 服务器与 Agents UI)由独立的开发服务器提供,通过以下命令启动:

pnpx electric-ax@latest agents start

启动成功后输出类似:

Electric Agents dev environment is up. Server + UI: http://localhost:4437 Docker project: electric-agents

注意这里用的是agents start而非agents quickstart,因此不会预装hortonworker等默认实体,而是得到一个干净运行时,正好用于从零定义自己的 Agent 实体。

可以用 CLI 验证运行时是否就绪:

pnpx electric-ax@latest agents types

此时应显示一个空的"Built-in agents"列表。

用 Caddy 代理到 HTTP/2(本地开发建议)

向导建议在宿主机安装 Caddy 并执行caddy trust,然后在示例目录放置 Caddyfile:

{ log default { level ERROR } } localhost:4438 { reverse_proxy localhost:4437 { flush_interval -1 } encode gzip header { Cache-Control "no-cache, no-transform" X-Accel-Buffering "no" } }

随后执行caddy start,将https://localhost:4438代理到http://localhost:4437,让浏览器以 HTTP/2 连接 Electric,避免本地开发时的 shape/SSE 连接性能问题。

关键常量与依赖

三份演进文件中都硬编码了以下常量(生产环境应改为环境变量注入):

const PORT = 3000 const SERVE_URL = `http://localhost:${PORT}` const ELECTRIC_AGENTS_URL = `http://localhost:4437` const MODEL = `claude-sonnet-4-6`

依赖方面,示例仅使用四个包(见 package.json):

  • @electric-ax/agents-runtime:运行时核心(EntityRegistry、RuntimeHandler、ctx上下文)
  • hono+@hono/node-server:Web 框架与 Node 服务器
  • @sinclair/typebox:为工具参数提供运行时 schema 与类型推导

Step 1:从裸 Hono 到第一个 Agent 实体

注册实体:createEntityRegistryregistry.define

向导从src/index.ts中的最小 Hono 应用起步。要接入 Electric Agents,先导入运行时 shim:

import { createEntityRegistry, createRuntimeHandler, } from '@electric-ax/agents-runtime'

createEntityRegistry()(实现在 packages/agents-runtime/src/define-entity.ts)创建一个实体注册表,所有 Agent 类型都通过它定义。最简单的实体——一个通用助手——只需三块内容:

registry.define(`assistant`, { description: `A general-purpose AI assistant`, async handler(ctx) { ctx.useAgent({ systemPrompt: `You are a helpful assistant.`, model: MODEL, tools: [], }) await ctx.agent.run() }, })

handler(ctx)是实体的入口:ctx.useAgent({...})配置本次运行使用的模型、系统提示词与工具;await ctx.agent.run()把控制权交给 LLM 完成一轮对话。这个助手没有任何工具,只能聊天回复。

运行时接线:createRuntimeHandler与 Webhook

接下来创建运行时处理器,并把它挂到 Hono 路由上:

const runtime = createRuntimeHandler({ baseUrl: ELECTRIC_AGENTS_URL, serveEndpoint: `${SERVE_URL}/electric-agents`, registry, }) app.post(`/electric-agents`, (c) => { return runtime.handleWebhookRequest(c.req.raw) })

createRuntimeHandler(实现在 packages/agents-runtime/src/create-handler.ts)接收三个配置:baseUrl指向 Electric Agents 服务器、serveEndpoint是当前应用暴露给运行时的回调地址、registry是上面定义的实体注册表。runtime.handleWebhookRequest把运行时的 Webhook 通知转交给对应实体处理。

这里有个值得理解的通信机制:Agent 之间、Agent 与运行时之间的实际消息都通过 Durable Streams 传输(使用内置的 StreamDB 集合),通知系统负责"唤醒"(wake)Agent 告诉它有新数据可消费。这样 Agent 在无事件时可以休眠、缩容到零。

注册实体类型:registerTypes

最后在服务器启动回调中注册实体类型,让运行时服务器知道本应用提供哪些 Agent:

serve( { fetch: app.fetch, port: PORT, }, (info) => { console.log(`Server is running on http://localhost:${info.port}`) runtime.registerTypes().catch(console.error) } )

启动后日志会出现INFO: [agent-runtime] Registered entity type: assistant,再执行pnpx electric-ax@latest agents types就能看到:

http://host.docker.internal:3000/electric-agents NAME DESCRIPTION ─────────────────────── ──────────────────────────────────────── assistant A general-purpose AI assistant Built-in agents NAME DESCRIPTION ─────────────────────── ────────────────────────────────────────

打开https://localhost:4438(注意走 Caddy 代理的 HTTPS 端口),点击 "New session" 即可在实体列表里看到assistant,直接新建会话与它聊天:

Step 2:命令式派生——第一个多 Agent 系统

这一阶段故意使用"朴素"方式:定义一个manager实体,每收到一条用户消息就在 handler 里命令式地派生一个子 Agent。

先扩展assistant,让它支持通过ctx.args传入自定义systemPrompt(即派生时动态指定行为),并增加一个生成实体 ID 的辅助函数:

registry.define(`assistant`, { description: `A general-purpose AI assistant`, async handler(ctx) { ctx.useAgent({ systemPrompt: (ctx.args.systemPrompt as string) || `You are a helpful assistant.`, model: MODEL, tools: [], }) await ctx.agent.run() }, }) const genId = () => Math.random().toString()

再定义manager实体:

registry.define(`manager`, { description: `A manager agent that delegates work to assistants`, async handler(ctx, wake) { if (wake.type === `inbox`) { await ctx.spawn( `assistant`, genId(), { systemPrompt: `Reverse the user message.`, }, { initialMessage: (wake.payload as { text: string }).text, wake: { on: `runFinished`, includeResponse: true }, } ) } ctx.useAgent({ systemPrompt: (ctx.args.systemPrompt as string) || `You are a manager agent.`, model: MODEL, tools: [], }) await ctx.agent.run() }, })

这段代码展示了两个关键点:

  1. wake.type === 'inbox'handler的第二个参数wake是唤醒事件。用户消息来自 inbox 流,其wake.type'inbox';而子 Agent 完成一轮运行触发的通知,wake.type'wake'。这里只对用户消息做处理。
  2. ctx.spawn(type, id, args, opts):派生一个指定类型的子实体。args会被透传给子实体的ctx.args(此处用于注入systemPrompt);opts.initialMessage是发给子实体的首条消息;opts.wake指定"子实体运行完成(runFinished)时唤醒父实体,并在唤醒载荷里带上其回复(includeResponse: true)"。

在实际运行中,你会在 UI 左侧菜单看到 "manager + 1",展开能看到派生的子 Agent。但向导刻意指出一个问题:manager 收到了子 Agent 的响应通知,却"不理解"它——它不知道是自己派生了这个子 Agent、也不知道回复对应自己的指令。因为子 Agent 是在命令式代码里派生的,没有以工具调用的形式记录在会话上下文中,LLM 看不到这层因果:

Step 3:工具调用派生——让 LLM 看到并理解子 Agent

问题根源在于:派生动作发生在"会话上下文之外"的代码里。解法是把派生封装成工具调用,让 manager 的会话日志完整记录"spawn 了一个 assistant 去反转消息"这件事。

先安装类型辅助库并导入:

pnpm add @sinclair/typebox
import { Type, type Static } from '@sinclair/typebox'

定义spawn_assistant工具。工具的parameters用 TypeBox 声明 LLM 需要生成的入参;ctx.spawn移入execute;工具返回值包含文本响应、结构化details(携带entityUrl)以及terminate: true(结束本轮):

const taskParameters = Type.Object({ task: Type.String({ description: `The task for the assistant.` }), }) type TaskParams = Static<typeof taskParameters> function createSpawnAssistantTool(ctx: HandlerContext) { return { name: `spawn_assistant`, label: `Spawn Assistant`, description: `Spawn an assistant sub-agent to perform a task.`, parameters: taskParameters, execute: async (_toolCallId: string, params: unknown) => { const { task } = params as TaskParams const { entityUrl } = await ctx.spawn( `assistant`, genId(), {}, { initialMessage: task, wake: { on: `runFinished`, includeResponse: true }, } ) return { content: [ { type: `text` as const, text: `Assistant dispatched at ${entityUrl}.`, }, ], details: { entityUrl }, terminate: true, } }, } }

随后把 manager 简化:删除命令式的ctx.spawn,改为在系统提示词中描述决策规则,并把工具放进tools数组(见 src/index3.ts):

registry.define(`manager`, { description: `A manager agent that delegates work to an assistant`, async handler(ctx) { ctx.useAgent({ systemPrompt: ` When given a user message that is a single word, spawn an assistant to reverse the user message. When asked direct questions, answer them yourself. `, model: MODEL, tools: [createSpawnAssistantTool(ctx)], }) await ctx.agent.run() }, })

现在向 manager 发消息,它会自主决定何时调用spawn_assistant;由于工具调用记录在会话日志里,manager 能"理解"子 Agent 的存在与来源。向导建议的验证方式是直接问它:

who reversed this message? how did that happen/work?

它能够解释刚才发生了什么——这正是"工具调用上下文可见性"带来的能力提升。

Step 4:多 Agent 辩论——纯提示词编排的局限

Judge 实体与三层派生

下一步定义一个更复杂的实体:judge,它要派生两个子 Agent 分别为正反方辩护,最后给出裁决。除 manager 外,manager 又通过spawn_judge工具派生 judge(src/index4.ts),形成 manager → judge → assistant×2 的三层派生链。

judge的核心工作几乎全部写在系统提示词里,同时获得createSpawnAssistantTool(ctx)用于派生两名辩手。manager 的系统提示词也相应扩展:

registry.define(`manager`, { description: `A manager agent that delegates work to an assistant`, async handler(ctx) { ctx.useAgent({ systemPrompt: ` When asked to debate a topic, spawn a Judge with the debate topic. When given a user message that is a single word, spawn an assistant to reverse the user message. When asked direct questions, answer them yourself. `, model: MODEL, tools: [createSpawnAssistantTool(ctx), createSpawnJudgeTool(ctx)], }) await ctx.agent.run() }, })

在 UI 中新建 manager 会话并下达例如 "Debate 996 vs 4-day-week" 的指令,可以看到它派生 judge,judge 再派生两名 assistant。

"Make no mistakes":提示词兜底的脆弱性

纯提示词编排的问题很快暴露:LLM 的行为是非确定性的。向导指出,运行结果会逐次变化——judge 和 manager 常常在参数还没真正返回时就开始"脑补"辩论结果。为此向导在 judge 提示词中加入了一组"防幻觉"注意事项:

Notes: - You are an impartial judge. - Use the assistants to gather the two sides. - Wait for **all** of the assistants to return **full** responses. Don't respond to partial / in-progress responses. - Do not generate/hallucinate the argument yourself. You must wait for the assistants to fully respond and then synthesize their responses. Don't anticipate or make them up. - Wait until the debate is fully finished before reporting back to the parent agent.

这些约束对较强模型往往有效,但 LLM 永远存在小概率不遵循指令。当流程变得更复杂(例如向导设想的"双方先陈述论点、再把对方论点交给对方反驳、最后裁决"的三阶段辩论),仅靠更长、更细的提示词极易"脱轨"(go off-piste)。

向导随后画出了目标辩论时序图:manager 下发 topic 后,judge 进入 phase 1(arguing,双方陈述论点),phase 2(critiquing,双方互相反驳),phase 3(verdict,judge 总结裁决并回传给 manager)。这是引入Step 5 混合控制流的动机——与其把每一步都押在 LLM 的提示词理解上,不如把"何时该做什么"变成由持久化状态驱动的确定性代码。

Step 5:混合控制流——状态机化的可靠多 Agent 编排

这是示例的成品形态(即默认 src/index.ts),也是向导的核心章节。思路是:让 LLM 做它擅长的事(理解语义、撰写辩题摘要、写出裁决),让代码 + 持久化状态做它擅长的事(控制流程何时推进、等待谁、向谁转发)

具体分四步改造:

1. 定义start_debate工具:把"派生两名辩手"变成确定性的工具调用

const startDebateParameters = Type.Object({ topic: Type.String({ description: `Short topic line, e.g. "996 vs 4-day work week".`, }), aBrief: Type.String({ description: `Brief for the A debater: topic, side, ask for their concise argument and points.`, }), bBrief: Type.String({ description: `Brief for the B debater: same shape.` }), }) type StartDebateParams = Static<typeof startDebateParameters> function createStartDebateTool(ctx: HandlerContext<any, any, any, any>) { return { name: `start_debate`, label: `Start Debate`, description: `Spawn the two debaters with their opening briefs. Call exactly once.`, parameters: startDebateParameters, execute: async (_id: string, params: unknown) => { const { topic, aBrief, bBrief } = params as StartDebateParams const [a, b] = await Promise.all([ ctx.spawn( `assistant`, genId(), {}, { initialMessage: aBrief, wake: { on: `runFinished`, includeResponse: true }, } ), ctx.spawn( `assistant`, genId(), {}, { initialMessage: bBrief, wake: { on: `runFinished`, includeResponse: true }, } ), ]) ctx.state.debate.insert({ key: `current`, topic, aUrl: a.entityUrl, bUrl: b.entityUrl, phase: `arguing`, arguments: {}, rebuttals: {}, }) return { content: [{ type: `text` as const, text: `Debate started.` }], details: {}, terminate: true, } }, } } const rebut = (arg: string) => `Your opponent argued:\n\n${arg}\n\nRebut their argument(s).`

注意:LLM 仍负责撰写双方的 brief(aBrief/bBrief,这是语义判断);但"派生两个子 Agent 并记录初始状态"变成了确定性代码。ctx.state.debate.insert({...})把辩论状态(双方entityUrl、当前phase、论点与反驳记录)写入实体的持久化状态。

2. 声明debate持久化集合

judge实体的定义上增加state配置。Electric Agents 底层使用 TanStack DB,集合(collection)是核心响应式数据抽象;这里用passthrough直接透传自定义的Debate类型 schema,并以key为主键:

type Debate = { key: `current` topic: string aUrl: string bUrl: string phase: `arguing` | `critiquing` | `done` arguments: { a?: string; b?: string } rebuttals: { a?: boolean; b?: boolean } }
registry.define(`judge`, { description: `Coordinates a three-phase debate: arguments, mutual rebuttals, verdict.`, state: { debate: { schema: passthrough<Debate>(), primaryKey: `key` }, }, async handler(ctx, wake) { // ... }, })

passthroughentity的实现在 packages/agents-runtime/src/entity-schema.ts 与 packages/agents-runtime/src/observation-sources.ts。

3. 重写 judge handler:状态驱动的确定性流程

完整的 judge handler 逻辑(src/index.ts 中registry.define('judge', ...))如下:

const SETUP_PROMPT = `You are a fair, concise debate judge opening a debate. Call start_debate exactly once: pick the topic line, and write a clear brief for each side: - "A" argues one case (e.g.: beneficial / pro / one side of the argument) - "B" argues the other case (e.g.: harmful / against / the other side) Each brief assigns only the topic and that side's position, then asks the debater to make a concise argument with their own three strongest points. Do NOT supply, list, or hint at any arguments yourself — the debater must devise their own. Then end your turn. Do not narrate.` const VERDICT_PROMPT = `You are a fair, concise debate judge closing a debate. Both sides have argued and critiqued each other. The full exchange is in your context. Weigh it and write your final verdict as your reply: summarise each side's strongest points, note how each critique landed, and give your impartial decision. Never argue a side. Do not narrate or preface — your reply IS the verdict, and it gets relayed to the user.` registry.define(`judge`, { description: `Coordinates a three-phase debate: arguments, mutual rebuttals, verdict.`, state: { debate: { schema: passthrough<Debate>(), primaryKey: `key` }, }, async handler(ctx, wake) { // Handle inbox messages by spawning one debate at a time. // Using the LLM to formulate the briefs for each side. if (wake.type === `inbox`) { if (ctx.state.debate.get(`current`)) { return ctx.sleep() } ctx.useAgent({ systemPrompt: SETUP_PROMPT, model: MODEL, tools: [createStartDebateTool(ctx)], }) await ctx.agent.run() return } // Ignore wake notifications unless they're from finished children // participating in the current debate. let debate = ctx.state.debate.get(`current`) if (!debate || debate.phase === `done`) { return ctx.sleep() } const finished_child = ( wake.payload as { finished_child?: FinishedChild } | undefined )?.finished_child if (!finished_child) { return ctx.sleep() } const side = finished_child.url === debate.aUrl ? `a` : finished_child.url === debate.bUrl ? `b` : null if (!side) { return ctx.sleep() } // Record this debater's contribution for the current round. if (debate.phase === `arguing`) { ctx.state.debate.update(`current`, (d) => { d.arguments[side] = finished_child.response ?? `` }) debate = ctx.state.debate.get(`current`)! // Proceed once both debaters have reported for this round. if ( debate.arguments.a !== undefined && debate.arguments.b !== undefined ) { ctx.send(debate.aUrl, rebut(debate.arguments.b)) ctx.send(debate.bUrl, rebut(debate.arguments.a)) ctx.state.debate.update(`current`, (d) => { d.phase = `critiquing` }) } return ctx.sleep() } // We're in `phase === 'critiquing'`, wait until both are in. ctx.state.debate.update(`current`, (d) => { d.rebuttals[side] = true }) debate = ctx.state.debate.get(`current`)! if (!debate.rebuttals.a || !debate.rebuttals.b) { return ctx.sleep() } // Flip the phase to 'done' and have the LLM write the verdict as its reply. ctx.state.debate.update(`current`, (d) => { d.phase = `done` }) ctx.useAgent({ systemPrompt: VERDICT_PROMPT, model: MODEL, tools: [], }) await ctx.agent.run() }, })

这段 handler 展示了混合控制流的完整形态:

  • inbox 分支:收到用户消息时,若已有进行中的辩论(ctx.state.debate.get('current')存在)则ctx.sleep()忽略,否则用SETUP_PROMPT运行 LLM,让它撰写双方 brief 并调用start_debate工具。
  • wake 分支(arguing 阶段):根据wake.payload.finished_childurl判断是哪位辩手完成,把其回复写入arguments[side]。只有当双方论点都到齐,才用ctx.send把 A 的论点发给 B 反驳、B 的论点发给 A 反驳,并把phase置为critiquing。任何单方到达都直接ctx.sleep()
  • wake 分支(critiquing 阶段):记录rebuttals[side] = true,双方反驳到齐后把phase置为done,最后用VERDICT_PROMPT运行 LLM,把裁决作为回复输出(会被回传给 manager)。

ctx.sleep()在此处的语义是"本轮无事可做,挂起等待下一个唤醒事件"——这正是 Agent 能够休眠、按需唤醒、缩容到零的机制。

4. 更新 manager:用ctx.observe观察子实体状态

最后,manager 在收到 judge 的runFinished唤醒时,不再直接采信其回复,而是用ctx.observe建立对子实体的观察,读取其持久化状态确认辩论确实结束:

registry.define(`manager`, { description: `Delegates to assistants and judges and relays their results to the user.`, async handler(ctx, wake) { if (wake.type === `wake`) { const finishedChild = ( wake.payload as { finished_child?: FinishedChild } | undefined )?.finished_child if ( finishedChild?.type === `judge` && finishedChild.run_status === `completed` ) { const judge = await ctx.observe(entity(finishedChild.url)) const debate = judge.db.collections.debate.get(`current`) as | Debate | undefined if (debate?.phase !== `done`) { return ctx.sleep() } } } ctx.useAgent({ systemPrompt: ` When asked to debate a topic, spawn a Judge with the debate topic. When given a user message that is a single word, spawn an assistant to reverse the user message. When asked direct questions, answer them yourself. `, model: MODEL, tools: [createSpawnAssistantTool(ctx), createSpawnJudgeTool(ctx)], }) await ctx.agent.run() }, })

ctx.observe(entity(url))返回对子实体的实时观察句柄,可以像访问本地数据库一样读取其集合(judge.db.collections.debate.get('current'))。这是一套非常强大的机制:Agent 之间无需预先定义 API 或通信接口,直接以内置的流和持久化状态进行订阅式协作。

5. 整场辩论的唤醒-决策矩阵

向导给出了 judge 在整场辩论中收到的全部唤醒事件,以及每个事件上的"闸门决策",直观展示为什么混合控制流下辩论不可能提前结束:

#Judge 唤醒闸门决策Judge 运行 LLM?Manager 被唤醒?Manager 运行 LLM?
1inbox尚无辩论 → 设置start_debate否(辩论未done
2A 论点arguments.b缺失 → sleep
3B 论点双方论点齐 → 转发反驳否(命令式转发)
4A 反驳rebuttals.b缺失 → sleep
5B 反驳双方反驳齐 → 裁决(写裁决)是(辩论已done,转发裁决)

关键结论:整个流程不存在让模型"提前交卷"或"脑补结果"的路径。judge 只会在论点和反驳都到齐后总结;manager 只会在辩论状态为done后转发裁决。LLM 的自由度被限定在"撰写 brief、写裁决"这类语义任务上,而流程推进完全由持久化状态决定。

这正是"混合控制流"的全部要义:让 LLM 在需要解释力、创造力的地方保持表达自由,同时用确定性状态把不可靠的部分锁死。系统的表达能力与可靠性因此可以兼得。

源码与测试:如何验证示例确实可运行

仓库为 walkthrough 示例提供了冒烟测试 test/smoke.test.ts,它用 vitest 以与pnpm dev相同的方式(tsx src/index.ts)启动默认的混合控制流成品,然后断言:

  • 服务器在 45 秒内完成启动并监听http://localhost:3000
  • 根路由返回 200 与Hello Hono!

该测试刻意连接 Electric Agents 运行时与 Anthropic API,因此不需要 Docker 或 API Key;服务器启动时registerTypes()无法触达 agents 服务器会报错被catch并记录,但 HTTP 服务器本身仍然监听——测试只验证"能启动、能服务"。运行方式:

pnpm test

此外,CHANGELOG.md 记录了该示例与@electric-ax/agents-runtime的版本跟随关系(当前示例版本 0.1.11,对应 runtime 0.6.3),可作为排查版本兼容问题的参考。

下一步探索

  • 完整向导文档:website/docs/agents/walkthrough.md,其中包含本文未逐字展开的 UI 截图与逐行演进说明。
  • 运行时 API 的实现细节可深入源码:createEntityRegistry见 packages/agents-runtime/src/define-entity.ts,createRuntimeHandler见 packages/agents-runtime/src/create-handler.ts,passthrough见 packages/agents-runtime/src/entity-schema.ts。
  • 更多通信拓扑与编排模式可参考仓库中的 agents-playground 示例 与 agents-chat-starter 示例。

对照src/index0.tssrc/index5.ts逐份阅读,是最快的内化方式——每一份文件都对应向导中的一个里程碑,最终形态就藏在src/index.ts的混合控制流里。

【免费下载链接】electricThe agent platform built on sync.项目地址: https://gitcode.com/GitHub_Trending/el/electric

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询