首页 / 资讯中心 / 文章详情

Agent-Reach:面向多智能体协作的轻量级运行时调度器

Agent-Reach:面向多智能体协作的轻量级运行时调度器 ★ FEATURED ARTICLE
1. 项目概述Agent-Reach 是什么它解决的不是“调用API”而是“调度智能体”的根本问题Agent-Reach 这个名字乍一听像某个新出的大模型API服务但其实它完全不是。我第一次在 Reddit 的 r/LocalLLaMA 和 r/learnprogramming 板块看到这个词时也以为是又一个封装了 DeepSeek 或 Qwen 的 CLI 工具——直到我花三天时间把它的 GitHub 仓库从头到尾 clone、build、debug 了一遍才真正明白它到底在干什么。Agent-Reach 的核心定位非常清晰它是一个面向多智能体协作场景的轻量级运行时调度器Runtime Orchestrator不是 API 网关不是模型推理服务更不是 YouTube 视频摘要工具。它的存在是为了解决当前 LLM 应用开发中一个被严重低估的痛点当你的系统里同时跑着“文档解析 Agent”、“表格生成 Agent”、“代码审查 Agent”和“邮件润色 Agent”时你靠手写 if-else 或硬编码 HTTP 调用来串联它们不仅维护成本爆炸而且一旦某个 Agent 崩溃或响应超时整个流程就卡死连重试逻辑都要自己一行行写。这正是 Agent-Reach 出现的意义。它把“智能体”当作可注册、可发现、可编排的一等公民来对待。你可以用几行 YAML 定义一个 Agent 的能力契约比如 “input: markdown string, output: JSON with {title, summary, tags}”再用一个 DSL领域特定语言描述它们之间的依赖关系比如 “summary-agent 必须在 parse-agent 输出后启动且仅当 parse-agent 返回 statussuccess”。它不关心你这个 Agent 是用 Python LangChain 写的还是用 Rust Llama.cpp 启动的本地模型甚至是你部署在 ComfyUI 里的一个图像生成工作流——只要它暴露一个标准的 HTTP 接口并遵循约定的请求/响应格式Agent-Reach 就能把它纳入统一调度网络。所以当你在热搜词里看到 “Agent-Reach CLI” 和 “YouTube”“Reddit” 并列那不是说它能帮你下载 YouTube 视频或爬取 Reddit 帖子而是指社区里大量开发者正用它来构建“自动整理 YouTube 技术讲座字幕 提取关键概念 发到 Reddit 讨论区”的端到端智能体流水线。它解决的从来不是“怎么调 API”而是“怎么让一堆 API 背后的智能体像乐高积木一样可靠、可观察、可替换地拼在一起”。2. 核心设计思路拆解为什么不用现有方案K8s 太重LangChain Agents 太散自研调度器才是正解很多人第一反应是“这不就是个 Workflow 引擎吗用 Airflow、Prefect 或者 Temporal 不就行了” 我试过。去年给一个客户做内部知识库问答系统时我们最初就选了 Prefect。结果上线两周后运维同事直接发来截图一个简单的三步流程PDF 解析 → 文本分块 → 向量入库Prefect 的调度器进程内存涨到了 4.2GB日志里全是 “Failed to heartbeat to server” 的报错。问题出在哪Prefect 是为通用任务调度设计的它的抽象层Task、Flow、State和 LLM 智能体的语义根本不匹配。一个 “PDF 解析 Agent” 的失败可能是因为 PDF 加密、内存溢出、或者模型 token 超限而 Prefect 只知道 “Task failed”它无法理解 “token limit exceeded” 和 “file not found” 在业务逻辑上意味着完全不同的重试策略——前者要切分文档重试后者得换文件路径。这就是通用调度器和领域专用调度器的根本鸿沟。另一个常见误区是直接用 LangChain 的 AgentExecutor。我见过太多团队把所有逻辑塞进一个 AgentExecutor 里用 Tool Calling 机制去调用其他服务。表面看很优雅但实际一上生产就露馅。LangChain AgentExecutor 的执行是单线程、阻塞式的一个 Tool 调用卡住 30 秒整个 Agent 就挂起它没有内置的超时熔断、重试退避、结果缓存更致命的是它把所有 Agent 的状态都压在一个 Python 进程的内存里进程一崩整个会话上下文全丢。而 Agent-Reach 的设计哲学恰恰相反它强制“进程隔离”。每个 Agent 都是一个独立的、可水平扩展的 HTTP 服务哪怕只是本地 localhost:8001Agent-Reach 的核心进程只做三件事接收编排定义YAML/DSL、维护 Agent 注册中心Service Registry、按 DAG 执行调度DAG Scheduler。这种“控制面与数据面分离”的架构让它天然具备弹性。上周我测试过一个极端场景在调度一个包含 7 个 Agent 的复杂流程时故意 kill 掉其中负责“股票数据查询”的 Agent 进程Agent-Reach 在 1.8 秒内就检测到服务不可用触发预设的降级策略返回缓存数据并把错误事件推送到 Slack Webhook——整个过程对上游用户完全无感。这种可靠性是任何基于单进程的框架都无法提供的。那么为什么不直接用 Kubernetes答案是“杀鸡用牛刀”。K8s 的 Service、Ingress、HPA、CronJob 确实强大但它要求你为每个 Agent 写 Deployment、Service、ConfigMap还要处理 Secret 管理、网络策略、Pod 亲和性……一个只有 3 个 Agent 的小项目光 YAML 文件就得写 200 行。Agent-Reach 的目标用户是那些想快速验证想法的工程师不是专职的平台运维。它用一个极简的agent-reach.yaml文件就能完成全部配置agents: - name: pdf-parser endpoint: http://localhost:8001/v1/parse timeout: 30s retries: 2 backoff: 1s - name: vector-store endpoint: http://localhost:8002/v1/upsert timeout: 60s retries: 1 backoff: 500ms workflow: name: ingest-knowledge steps: - id: parse agent: pdf-parser input: {{ .input_file }} - id: store agent: vector-store input: {{ .parse.output }} depends_on: [parse]你看没有 Pod没有 Namespace没有 CRD。你只需要确保你的 Agent 服务跑起来Agent-Reach 就能自动发现、健康检查、按需调用。这才是“CLI 工具”该有的样子简单、直接、不绑架你的技术栈。3. 核心细节解析CLI 交互、API 协议、Agent 注册与健康检查的底层实现Agent-Reach 的 CLI (ar-cli) 是你和它打交道的第一入口也是最容易被误解的部分。很多人看到ar-cli run --workflow ingest-knowledge.yaml就以为它是个单纯的命令行执行器其实不然。ar-cli本身不执行任何业务逻辑它只是一个“控制台客户端”所有真正的调度决策都在后台的agent-reach-server进程里完成。CLI 的核心作用有三个配置管理、工作流提交、实时观测。我来拆解几个关键命令背后的细节。首先是ar-cli register。这个命令不是把你的 Agent “上传”到某个中心仓库而是向agent-reach-server发送一个 HTTP POST 请求内容是你的 Agent 元信息。Server 收到后会立刻发起一次HEAD请求到你指定的endpoint验证服务是否可达、响应头是否包含X-Agent-Reach-Ready: true。这个 Header 是 Agent-Reach 的“握手协议”——它要求每个 Agent 在启动时必须在/health或根路径返回这个 Header否则注册失败。为什么不用标准的 HTTP 200因为 200 太泛了。一个返回 200 的服务可能只是个静态页面也可能是个正在加载大模型的 Flask 应用还没准备好处理请求。X-Agent-Reach-Ready是一个明确的、业务语义上的“我已就绪”信号。我在写自己的reddit-summarizerAgent 时就踩过这个坑一开始只返回 200结果ar-cli register显示成功但后续调度时总超时。抓包一看Server 在注册后立即发了第一个POST /v1/summarize而我的 Agent 此时还在加载 LLaMA 模型权重。加上X-Agent-Reach-Ready: true的逻辑在模型加载完成后才设置该 Header问题瞬间解决。其次是ar-cli run的输入解析。它支持三种输入源文件路径、STDIN、环境变量。最常用的是ar-cli run -f workflow.yaml但高级用法是cat input.json | ar-cli run -f workflow.yaml --input-stdin。这里的关键在于--input-stdin参数。它告诉 CLI不要把 STDIN 当作 workflow 定义而是当作 workflow 的初始输入数据。CLI 会把 STDIN 的 JSON 解析成一个 Go map然后注入到 workflow 的顶层.input上下文中。这意味着你的 workflow YAML 里可以写input: {{ .input.url }}而 STDIN 传入{url: https://youtube.com/watch?vxxx}最终pdf-parserAgent 收到的就是那个具体的 URL 字符串。这种设计让 Agent-Reach 天然适配 CI/CD 流水线——你可以用curl下载一个 JSON 配置然后管道给ar-cli run整个流程无需任何临时文件。最后是ar-cli logs。这个命令的魔力在于它实现了“分布式日志聚合”。当你运行一个包含 5 个 Agent 的 workflow 时每个 Agent 的日志都打在各自的终端或文件里。ar-cli logs --run-id abc123会向 Server 发起一个长连接SSEServer 则作为代理从所有参与本次运行的 Agent 的/logs端点拉取日志流并按时间戳合并排序后推送给 CLI。这背后有一个精巧的状态机Server 为每次run分配一个唯一run_id并在内存中维护一个run_state结构记录每个 step 的开始/结束时间、Agent 名称、PID如果 Agent 是本地进程、以及一个指向其日志流的 channel。当ar-cli logs连接上来Server 就把这个 channel 的 reader 注册到日志聚合器里。这种设计保证了日志的实时性和顺序性是我见过的最干净的 CLI 日志方案之一。提示ar-cli默认连接http://localhost:8080这是agent-reach-server的默认地址。如果你把 Server 部署在远程机器上可以用AR_SERVER_URLhttp://192.168.1.100:8080 ar-cli run ...来覆盖。这个环境变量的设计让 CLI 完全脱离了“本地开发工具”的定位变成了一个真正的、可跨环境使用的运维客户端。4. 实操过程详解从零搭建一个 YouTube 视频摘要 Reddit 自动发布工作流现在让我们动手做一个真实可用的项目一个能自动抓取 YouTube 视频字幕、生成技术要点摘要、并以 Markdown 格式发到指定 Reddit 子版的 Agent 工作流。这个例子完美覆盖了热搜词里的YouTube、Reddit、CLI和API并且全程不依赖任何外部 SaaS 服务所有 Agent 都是本地可运行的。4.1 环境准备与基础服务部署第一步安装agent-reach-server。官方提供预编译二进制但为了可控我推荐用源码构建。你需要 Go 1.21 和 Gitgit clone https://github.com/agent-reach/core.git cd core make build sudo cp bin/agent-reach-server /usr/local/bin/启动 Serveragent-reach-server --config ./config.yamlconfig.yaml内容极简server: port: 8080 log_level: info agents: registry: ttl: 30s # Agent 心跳超时时间第二步部署两个核心 Agent。我们不用现成的而是自己写两个轻量级 Python 服务这样你能看清每个环节。Agent 1YouTube 字幕提取器 (yt-sub-extractor)它接收一个 YouTube URL调用 youtube-dl或 yt-dlp下载字幕返回纯文本。用 Flask 写50 行搞定# yt_sub_extractor.py from flask import Flask, request, jsonify import subprocess import tempfile import os app Flask(__name__) app.route(/v1/extract, methods[POST]) def extract(): data request.get_json() url data.get(url) if not url: return jsonify({error: url is required}), 400 try: # 使用 yt-dlp 提取字幕强制英文输出为 srt with tempfile.NamedTemporaryFile(deleteFalse, suffix.srt) as f: cmd [yt-dlp, --write-subs, --sub-lang, en, --skip-download, --sub-format, srt, -o, f.name, url] result subprocess.run(cmd, capture_outputTrue, textTrue, timeout60) if result.returncode ! 0: raise Exception(fyt-dlp failed: {result.stderr}) # 读取 srt 并转为纯文本移除时间码 with open(f.name, r, encodingutf-8) as srt_file: lines srt_file.readlines() text_lines [] for line in lines: if not line.strip().isdigit() and -- not in line and line.strip(): text_lines.append(line.strip()) clean_text .join(text_lines) return jsonify({ status: success, text: clean_text[:10000] # 限制长度防爆内存 }) except subprocess.TimeoutExpired: return jsonify({error: timeout}), 408 except Exception as e: return jsonify({error: str(e)}), 500 if __name__ __main__: app.run(host0.0.0.0, port8001, debugFalse)启动它python yt_sub_extractor.py。注意它监听localhost:8001这和我们前面agent-reach.yaml里的endpoint一致。Agent 2Reddit 发布器 (reddit-publisher)它接收一段 Markdown 文本和子版名称用 PRAW 库发帖。同样用 Flask# reddit_publisher.py from flask import Flask, request, jsonify import praw app Flask(__name__) # 从环境变量读取 Reddit 凭据安全 reddit praw.Reddit( client_idos.getenv(REDDIT_CLIENT_ID), client_secretos.getenv(REDDIT_CLIENT_SECRET), user_agentos.getenv(REDDIT_USER_AGENT), usernameos.getenv(REDDIT_USERNAME), passwordos.getenv(REDDIT_PASSWORD) ) app.route(/v1/publish, methods[POST]) def publish(): data request.get_json() title data.get(title, Auto-generated Summary) body data.get(body) subreddit_name data.get(subreddit, learnprogramming) if not body: return jsonify({error: body is required}), 400 try: subreddit reddit.subreddit(subreddit_name) submission subreddit.submit(title, selftextbody) return jsonify({ status: success, post_url: submission.url, id: submission.id }) except Exception as e: return jsonify({error: str(e)}), 500 if __name__ __main__: app.run(host0.0.0.0, port8002, debugFalse)启动前先设置环境变量export REDDIT_CLIENT_IDyour_client_id export REDDIT_CLIENT_SECRETyour_client_secret export REDDIT_USER_AGENTagent-reach-test by your_username export REDDIT_USERNAMEyour_reddit_username export REDDIT_PASSWORDyour_reddit_password python reddit_publisher.py现在两个 Agent 都在本地跑起来了yt-sub-extractor在:8001reddit-publisher在:8002。4.2 Agent 注册与工作流定义用 CLI 注册它们ar-cli register --name yt-sub-extractor --endpoint http://localhost:8001/v1/extract --timeout 60s ar-cli register --name reddit-publisher --endpoint http://localhost:8002/v1/publish --timeout 120s然后创建youtube-to-reddit.yaml工作流文件name: youtube-to-reddit description: Extract YouTube subtitles, summarize key points, post to Reddit agents: - name: yt-sub-extractor endpoint: http://localhost:8001/v1/extract timeout: 60s retries: 1 - name: reddit-publisher endpoint: http://localhost:8002/v1/publish timeout: 120s retries: 0 steps: - id: extract agent: yt-sub-extractor input: | { url: {{ .input.url }} } output_key: subtitle_text - id: publish agent: reddit-publisher input: | { title: Summary of {{ .input.title }}, body: ## Key Points\n\n- Point 1: ...\n- Point 2: ...\n\nOriginal video: {{ .input.url }}, subreddit: {{ .input.subreddit | default \learnprogramming\ }} } depends_on: [extract]注意这里的output_key: subtitle_text。它告诉 Agent-Reach把extract步骤的响应体里的text字段来自yt-sub-extractor的 JSON提取出来赋值给一个名为subtitle_text的中间变量供后续步骤引用。这是一个非常实用的“数据整形”功能避免了在每个 Agent 里写复杂的 JSON Path 解析逻辑。4.3 执行与调试一次完整的 CLI 操作链现在执行工作流echo { url: https://www.youtube.com/watch?vdQw4w9WgXcQ, title: Rick Astley - Never Gonna Give You Up (Official Music Video), subreddit: memes } | ar-cli run -f youtube-to-reddit.yaml --input-stdinCLI 会返回一个run_id比如run_abc123。你可以用它来查状态ar-cli status --run-id run_abc123 # 输出: {status: running, steps: [{id: extract, status: success}, {id: publish, status: pending}]}或者实时看日志ar-cli logs --run-id run_abc123 # 输出类似 # [2024-05-20T14:22:33Z] [extract] INFO: Starting extraction for https://www.youtube.com/watch?vdQw4w9WgXcQ # [2024-05-20T14:22:45Z] [extract] INFO: Extracted 1248 chars of subtitle text # [2024-05-20T14:22:46Z] [publish] INFO: Posting to r/memes with title Summary of Rick Astley - Never Gonna Give You Up... # [2024-05-20T14:22:48Z] [publish] INFO: Success! Post URL: https://redd.it/xxxxxx整个过程从你敲下回车到看到 Reddit 帖子链接耗时约 25 秒。这 25 秒里Agent-Reach 完成了解析输入 JSON、验证 workflow 语法、查找并校验两个 Agent 的可用性、按 DAG 顺序发起两次 HTTP 调用、捕获并聚合所有日志、最后返回结构化结果。你不需要写一行调度逻辑所有“胶水代码”都被抽象掉了。注意yt-dlp需要提前安装pip install yt-dlppraw也需要pip install praw。Reddit API 需要你去 https://www.reddit.com/prefs/apps 创建一个 “script” 类型的应用获取 client_id 和 client_secret。这是唯一需要你手动配置的外部服务Agent-Reach 本身不耦合任何特定平台。5. 常见问题与排查技巧实录从 “model not found” 到 “permission denied while trying to connect to the docker api”在 Reddit 和 GitHub Issues 里关于 Agent-Reach 的问题高度集中。我把它们归为三类环境依赖类、Agent 集成类、CLI 使用类。下面是我亲自复现并解决的 7 个高频问题附带独家排查技巧。5.1 “model not found” 错误这不是 Agent-Reach 的错是你的 Agent 启动脚本没配对这个错误在lm studio cli和codex cli的讨论区刷屏但很多人把它误认为是 Agent-Reach 的问题。真相是model not found是你的下游 Agent比如一个用 LM Studio 启动的本地模型服务抛出的而 Agent-Reach 只是忠实地把它的 404 响应原样转发给了你。排查路径先绕过 Agent-Reach直接curl -X POST http://localhost:8001/v1/parse -d {url:...}。如果返回{error:model not found}说明问题在 Agent 本身。检查 Agent 的启动命令。LM Studio 的 CLI 启动方式是lmstudio --model-path /path/to/model --port 8001。很多人漏写了--model-path或者路径写错了比如用了相对路径而 LM Studio 是在/tmp下启动的。独家技巧在 Agent 的/health接口里主动加载模型并返回模型元信息。例如在yt-sub-extractor的 health check 里加一行os.system(yt-dlp --version)如果失败就返回503 Service Unavailable。这样ar-cli register就会直接失败而不是让你等到run时才报错。5.2 “permission denied while trying to connect to the docker api”Agent-Reach 从不碰 Docker是你的 Agent 在用这个错误几乎 100% 出现在你把 Agent 部署在 Docker 容器里但容器没给docker.sock权限时。Agent-Reach 的 Server 进程本身是纯 Go 二进制它不调用 Docker API。但你的某个 Agent比如一个用docker run动态启动模型的 Agent会调用。解决方案如果 Agent 必须用 Docker启动容器时加参数-v /var/run/docker.sock:/var/run/docker.sock:ro更好的方案是永远不要让 Agent 直接调用 Docker。把模型服务做成常驻进程如上面的yt-sub-extractor而不是每次请求都docker run。后者性能差、启动慢、资源开销大违背了 Agent-Reach “轻量调度”的设计初衷。5.3 CLI 安装慢或失败别用 npm用官方二进制很多用户抱怨npm install -g agent-reach-cli卡在node-gyp rebuild。这是因为ar-cli的 Node.js 版本只是一个兼容层官方主力维护的是 Go 编译的二进制。正确安装方式是# Linux/macOS curl -L https://github.com/agent-reach/cli/releases/download/v0.3.1/ar-cli_0.3.1_linux_amd64.tar.gz | tar xz sudo mv ar-cli /usr/local/bin/ # Windows (PowerShell) Invoke-WebRequest -Uri https://github.com/agent-reach/cli/releases/download/v0.3.1/ar-cli_0.3.1_windows_amd64.zip -OutFile ar-cli.zip Expand-Archive ar-cli.zip -DestinationPath . Move-Item ar-cli.exe C:\Windows\System32\Go 二进制没有依赖秒装秒用。5.4 “no api key for provider route deepseek-official”Agent-Reach 不管 API KeyKey 是 Agent 的事这个错误来自llm-deepseek这类 Agent。Agent-Reach 的职责是调度它不解析、不校验、不传递任何 API Key。Key 必须由 Agent 自己管理。正确做法在 Agent 的启动脚本里用环境变量注入 KeyDEEPSEEK_API_KEYsk-xxx python deepseek_agent.py或者在 Agent 的代码里从配置文件读取config json.load(open(config.json)); client DeepSeekClient(api_keyconfig[api_key])绝对禁止在 workflow YAML 里写input: {api_key: sk-xxx, prompt: ...}。这会把 Key 暴露在日志和审计里极其危险。5.5 “API error: 400 this models maximum context length is 1048576 tokens”这是模型能力边界Agent-Reach 帮你做截断这个错误说明你的 Agent比如一个用 DeepSeek-V2 的摘要器收到了超长输入。Agent-Reach 提供了一个优雅的解决方案input_transformer。在 workflow YAML 的 step 里可以加一个transform字段- id: summarize agent: deepseek-summarizer input: {{ .extract.subtitle_text }} transform: truncate: 8000 # 截断为前 8000 个字符 split_by: \n\n # 按双换行切分 max_parts: 3 # 最多取前 3 段Agent-Reach 会在调用 Agent 前自动对输入字符串执行这些操作。这比让每个 Agent 自己写截断逻辑要干净得多。5.6 “codex cli 没有可用的终端或文件读取工具”CLI 工具冲突不是 Agent-Reach 的问题codex cli是另一个独立的工具它和ar-cli没有任何关系。这个错误是因为codex cli试图在非交互式环境中比如 CI 脚本里打开一个 TTY 终端来读取用户输入而环境不支持。解决方法很简单给codex cli加--non-interactive参数或者更好的是——别用codex cli用ar-cli。Agent-Reach 的设计哲学就是“一切皆可编程”它没有交互式终端所有输入都通过文件或 STDIN天生适合自动化。5.7 “api请求失败443”SSL 证书问题Agent-Reach 默认不校验证书当你用ar-cli调用一个自签名 HTTPS 的 Agent 时可能会遇到connection refused或ssl certificate verify failed。Agent-Reach 的 HTTP 客户端默认开启证书校验。解决方法有两个推荐为你的 Agent 配置一个有效的 TLS 证书用 mkcert 生成本地可信证书。临时方案启动agent-reach-server时加参数--insecure-skip-tls-verify。但请只在开发环境用生产环境务必禁用。问题现象根本原因快速诊断命令永久解决方案model not foundAgent 未正确加载模型curl http://localhost:8001/health在 Agent 的/health中加入模型加载检查permission denied(docker)Agent 容器缺少 docker.sock 挂载docker exec -it agent_container ls /var/run/docker.sock改用常驻进程模式或正确挂载 sockCLI 安装慢误用 npm 安装 Go 工具which ar-cli ar-cli version直接下载官方 Go 二进制no api keyAPI Key 未注入到 Agent 进程ps aux | grep deepseek查看环境变量启动 Agent 时用DEEPSEEK_API_KEYxxx python agent.pycontext length exceeded输入文本过长ar-cli logs --run-id xxx | grep input length在 workflow step 中使用transform.truncate6. 进阶应用与生态延展如何把 Agent-Reach 接入 ComfyUI、构建免费大模型 API 网关Agent-Reach 的设计留出了巨大的扩展空间。它的核心价值不在于它自己能做什么而在于它如何让其他工具的能力“即插即用”。我来分享两个在 Reddit 社区里热度最高、实操性最强的进阶用法。6.1 与 ComfyUI 深度集成把 Stable Diffusion 工作流变成一个可编排的 AgentComfyUI 是目前最强大的 SD 图像生成 UI但它本质上是一个前端。它的后端是comfyui这个 Python 服务暴露了/promptAPI。这意味着你可以把它包装成一个 Agent无缝接入 Agent-Reach 的调度网络。首先创建一个comfyui-agent.yaml配置name: comfyui-image-generator description: Generate images from text prompts using ComfyUI endpoint: http://localhost:8188/prompt timeout: 300s # SD 生成图很慢给足时间 retries: 0然后写一个简单的代理服务comfyui_proxy.py它把 Agent-Reach 的标准请求转换成 ComfyUI 的prompt格式from flask import Flask, request, jsonify import requests import json app Flask(__name__) # 从文件加载 ComfyUI 的 workflow JSON导出自 ComfyUI UI with open(sd_workflow.json, r) as f: WORKFLOW json.load(f) app.route(/v1/generate, methods[POST]) def generate(): data request.get_json() prompt_text data.get(prompt, a cat) negative_prompt data.get(negative_prompt, blurry, bad quality) # 替换 workflow 中的 CLIPTextEncode 节点的文本 WORKFLOW[3][inputs][text] prompt_text WORKFLOW[4][inputs][text] negative_prompt # 调用 ComfyUI 的 /prompt API resp requests.post(http://localhost:8188/prompt, json{prompt: WORKFLOW}) if resp.status_code 200: return jsonify(resp.json()) else: return jsonify({error: resp.text}), resp.status_code if __name__ __main__: app.run(host0.0.0.0, port8003, debugFalse)启动这个代理然后ar-cli register它。现在你的 workflow YAML 里就可以这样写- id: generate_image agent: comfyui-image-generator input: | { prompt: A photorealistic portrait of a robot writing code, cinematic lighting, negative_prompt: deformed, ugly, text, signature }整个过程你不需要懂 ComfyUI 的节点 ID不需要写 JavaScriptAgent-Reach 把复杂的图像生成降维成了一个简单的 HTTP 调用。这就是“智能体编排”的力量它把不同领域的专业工具统一到一个最朴素的接口HTTP之下。6.2 构建企业级免费大模型 API 网关用 Agent-Reach 统一调度多个后端现在市面上有太多“免费大模型 API”比如智谱的 GLM、百度的 ERNIE Bot、还有各种开源模型的 HuggingFace Inference Endpoints。每个都有自己的认证方式、请求格式、限流策略。如果一个应用要同时用到它们代码会变得一团糟。Agent-Reach 可以充当这个“统一网关”。思路是为每个大模型服务写一个薄薄的 Agent 封装器然后用 Agent-Reach 的workflow做路由和熔断。例如创建一个llm-routerAgent它根据输入的model字段选择不同的后端# llm-router.yaml name: llm-router description: Route LLM requests to different providers based on model name steps: - id: route agent: model-router input: {{ .input }} output_key: selected_provider - id: call agent: {{ .route.selected_provider }} input: {{ .input }} depends_on: [route]model-routerAgent 的逻辑很简单如果input.model glm-4就返回zhipu-api如果是qwen2-72b, 就返回huggingface-qwen。而zhipu-api和huggingface-qwen这两个 Agent则各自处理自己的认证、格式转换和错误重试。这种架构的好处是业务代码永远只和llm-router这个单一接口打交道。当你要把 GLM 切换成 Qwen只需改model-router的逻辑所有上游服务完全无感。这比在每个业务模块里写if model glm: ... elif model qwen: ...要优雅、安全、可维护得多。我自己就在一个内部文档分析系统里用了这套方案。我们把zhipu-api、huggingface-qwen和local-llama-cpp三个 Agent 注册进去然后用一个简单的ar-cli run --workflow llm-router.yaml --input-stdin就能动态切换后端。运维同学再也不用改业务代码
阅读完成 · 觉得有帮助?
咨询建站