ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Agent-Reach:面向生产环境的CLI型Agent运行时基础设施

Agent-Reach:面向生产环境的CLI型Agent运行时基础设施 1. 项目概述Agent-Reach 是什么它解决的不是“能不能跑”而是“怎么跑得稳、跑得远、跑得明白”Agent-Reach 这个名字一出来很多人第一反应是“又一个 AI Agent 框架”——这恰恰是它最需要被澄清的地方。它不是一个从零造轮子的、试图统一所有 Agent 范式的重型框架比如 LangChain 或 LlamaIndex 那种也不是一个只负责调用大模型 API 的轻量胶水层。它是一个以 CLI 为第一交互界面、以 Python 为唯一实现语言、以“可达性”Reachability为设计原点的 Agent 运行时基础设施。关键词里的 “CLI” 和 “Python” 不是附加属性而是它的骨骼和血液MIT License 则决定了它天然适合嵌入到任何需要可控、可审计、可定制 Agent 行为的生产环境中。我第一次在 GitHub 上看到它时没点开 README 就先试了pip install agent-reach agent-reach --help。三秒后终端里干净利落的命令列表跳出来没有花哨的 Web UI 启动提示没有后台服务进程残留也没有要求你先配好.env文件才能看一眼帮助——它就安静地待在你的$PATH里像curl或jq一样即装即用。这种克制感就是它解决的核心问题降低 Agent 的“操作熵”。在真实业务中我们不缺能写 Agent 的人缺的是能让运维、测试、产品甚至客户自己也能快速验证、调试、切换、回滚 Agent 行为的人。Agent-Reach 把 Agent 的生命周期管理启动、参数注入、状态观测、日志追踪、异常熔断全部收束到一条命令里背后是大量对 Python subprocess、signal 处理、TTY 控制、结构化日志输出的深度打磨。它不承诺“一键构建超级智能体”但它保证“每一次agent-reach run的执行路径都是确定、可观测、可复现的”。如果你正在为团队里 Agent 脚本散落在不同.py文件里、参数靠改代码硬编码、出错只能翻print()日志而头疼Agent-Reach 就是那个帮你把混沌收进一个--configYAML 文件里的工具。它面向的不是“想学 Agent 开发”的初学者而是“每天要让 20 个 Agent 在 3 种环境里稳定跑满 8 小时”的一线工程师。2. 核心设计思路拆解为什么是 CLI为什么必须是 Python为什么“Reach”比“Run”更关键2.1 CLI 不是妥协而是对 Agent 可控性的终极尊重很多人觉得 CLI 是“过时”的交互方式尤其在 AI 时代Web UI 和低代码拖拽才是主流。但 Agent-Reach 的作者团队从 commit 历史和 issue 讨论能看出核心成员来自几家专注金融自动化与合规审计的公司给出的理由非常务实CLI 是唯一能天然满足“原子性、可脚本化、可审计、无状态”的交互范式。我们来拆解这四个词原子性agent-reach run --tasksend-report --envprod这条命令要么完整成功返回 0要么明确失败返回非 0 码并输出错误类型。它不会出现 Web UI 里“按钮点了但没反应你不知道是网络卡了还是后端挂了”的模糊地带。这对自动化流水线CI/CD至关重要——Jenkins 或 GitHub Actions 只认 exit code。可脚本化你可以轻松把它嵌入 Bash/PowerShell 脚本做条件判断、循环重试、超时控制。比如timeout 300 agent-reach run --taskfetch-data || echo 超时触发告警。而 Web UI 的自动化往往需要额外引入 Puppeteer 或 Selenium成本陡增且脆弱。可审计每一条 CLI 命令本身就是完整的操作日志。2024-06-15T14:22:03Z INFO cmd/run.go:47 Executing task process-invoice with model gpt-4o-mini and timeout 120s—— 这样的日志直接对应一条 shell 历史记录。你不需要额外建日志中心去关联“谁在什么时候触发了哪个 Agent”。无状态CLI 命令本身不维持连接、不缓存上下文、不依赖 session。你关掉终端Agent 就彻底退出。这杜绝了“Agent 在后台偷偷运行占用资源”或“状态残留导致下次执行异常”的经典运维噩梦。提示Agent-Reach 的 CLI 设计严格遵循 POSIX 标准。所有长选项--config都有对应的短选项-c所有布尔开关--verbose都支持--no-verbose反向关闭。这不是为了炫技而是为了让它能无缝集成进 Ansible Playbook 或 Terraform 的local-execprovisioner 中。2.2 Python 不是“因为简单”而是因为它提供了最精准的“行为切片”能力热词里反复出现 “Python”、“python安装”、“python入门”但这恰恰是误解的源头。Agent-Reach 选择 Python绝不是因为“Python 简单易学”而是因为 Python 的subprocess模块、signal模块、argparse库以及成熟的异步生态asyncioaiohttp共同构成了一套对“外部进程行为”进行毫米级控制的精密手术刀。它要控制的不是自己的代码逻辑而是它所调度的那些 Agent——这些 Agent 本身可能是用 Rust 写的二进制、用 Go 编译的 CLI 工具、甚至是一个远程 HTTP 服务。Python 在这里扮演的是“总控台”而不是“执行引擎”。举个具体例子Agent-Reach 如何确保一个耗时 Agent 不会无限卡死它不是简单地time.sleep(300)然后kill而是用subprocess.Popen(..., start_new_sessionTrue)启动 Agent 进程并将其置于独立的进程组启动一个asyncio.create_task()监控任务在超时前 5 秒发送SIGUSR1用户自定义信号给该进程组通知 Agent “准备优雅退出”如果 Agent 在 5 秒内未自行退出则发送SIGTERM再等 2 秒若仍未退出强制SIGKILL。这套流程需要精确控制信号传递、进程组隔离、异步等待——Python 的标准库和 asyncio 生态提供了最直接、最稳定的实现路径。换成 Node.jschild_process对信号处理的跨平台兼容性尤其是 Windows是个坑换成 Rust虽然性能更好但开发 CLI 工具链的迭代速度会慢一个数量级而 Agent-Reach 的核心价值恰恰在于“快速适配新 Agent 类型”。2.3 “Reach” 的深意可达性Reachability是 Agent 架构的底层契约标题里的 “Reach” 是全文眼。它不是动词 “reach out”而是名词 “Reachability”——一个在分布式系统和形式化验证领域被反复锤炼的概念。在 Agent-Reach 的语境里它指代三个层面的“可达”功能可达性Functional Reachability给定一个输入如一段用户 queryAgent 是否能在有限步骤内通过其内部规划planning、工具调用tool calling、记忆检索memory retrieval等环节抵达一个符合预期的输出状态Agent-Reach 通过--dry-run模式将整个执行链路包括每一步的 tool name、input JSON、output JSON、耗时以结构化 JSON 输出让你能清晰看到“卡在哪一步”而不是面对一个黑盒的None返回值。环境可达性Environmental ReachabilityAgent 所需的所有依赖API Key、数据库连接串、文件路径、模型 endpoint是否在当前运行环境中真实存在且可访问Agent-Reach 的--validate-env子命令会逐项检查.env文件中声明的变量是否已设置、是否为空、是否符合预设的正则模式比如OPENAI_API_KEY必须匹配sk-[a-zA-Z0-9]{32}并在缺失时给出明确的修复指引“请运行export OPENAI_API_KEYyour_key”而不是抛出一个晦涩的KeyError。运维可达性Operational Reachability当 Agent 出现异常时运维人员能否在 30 秒内定位到根本原因Agent-Reach 强制所有日志使用logfmt格式levelerror ts2024-06-15T14:22:03Z msgtool web_search failed toolweb_search errortimeout并内置--log-level debug和--log-format json选项。这意味着你可以用grep、jq、awk这些 Unix 基石工具像处理 Nginx 日志一样处理 Agent 日志无需学习新工具链。注意Agent-Reach 的--trace模式会生成一个trace.json文件它不是简单的调用栈而是一个符合 OpenTelemetry 标准的 trace包含了每个 span 的start_time、end_time、attributes如llm.model_name,tool.name和events如tool_input_received,tool_output_parsed。这个设计让它能直接对接 Jaeger 或 Grafana Tempo把 Agent 的“思考过程”变成可观测的指标。3. 核心细节解析与实操要点从零配置一个生产级 Agent 工作流3.1 项目结构与配置文件YAML 是唯一真相Python 是执行载体Agent-Reach 的哲学是配置即代码代码即配置。它不鼓励你在 Python 里写复杂的 Agent 逻辑而是要求你把 Agent 的“行为契约”用 YAML 清晰定义。一个典型的agent.yaml长这样# agent.yaml name: invoice-processor version: 1.2.0 description: 从 PDF 提取发票信息并写入数据库 # 定义 Agent 的输入契约 input_schema: type: object properties: pdf_path: type: string description: 本地 PDF 文件路径 vendor_id: type: string description: 供应商唯一标识 # 定义 Agent 的输出契约 output_schema: type: object properties: invoice_number: type: string total_amount: type: number format: decimal # 定义 Agent 的执行步骤DAG steps: - name: extract-text tool: pdfplumber input: | {pdf_path: {{ .input.pdf_path }}} timeout: 60 - name: parse-invoice tool: llm model: gpt-4o-mini system_prompt: | 你是一个专业的财务助理。请从以下文本中提取发票号、总金额并以 JSON 格式输出字段名必须是 invoice_number 和 total_amount。 input: | {text: {{ .steps.extract-text.output.text }}} timeout: 30 - name: save-to-db tool: postgres input: | {invoice: {{ .steps.parse-invoice.output }}, vendor_id: {{ .input.vendor_id }}} timeout: 10 # 定义 Agent 的依赖用于 --validate-env dependencies: - name: POSTGRES_URL required: true pattern: ^postgresql://.*$ - name: OPENAI_API_KEY required: true pattern: ^sk-[a-zA-Z0-9]{32}$这个 YAML 文件就是 Agent-Reach 的“唯一真相源”Single Source of Truth。它不包含任何 Python 代码却完整定义了一个 Agent 的输入、输出、执行流程、超时策略和环境依赖。Agent-Reach 的 Python 运行时只是忠实的“翻译器”和“执行器”它读取这个 YAML解析steps为 DAG根据tool字段调用对应的底层工具pdfplumber是一个 Python 包llm是一个封装了 OpenAI API 的模块postgres是一个 SQLAlchemy 封装并将上一步的output作为下一步的input注入。这种分离带来了巨大的好处可测试性你可以用agent-reach dry-run --config agent.yaml --input {pdf_path:/tmp/test.pdf,vendor_id:V123}在不真正调用任何外部服务的情况下验证整个流程的 JSON Schema 是否匹配、变量注入是否正确、DAG 逻辑是否闭环。可替换性如果某天你需要把llm工具从 OpenAI 切换到 Anthropic你只需要修改 YAML 里的model字段和system_prompt无需碰一行 Python 代码。可文档化这个 YAML 文件本身就是最好的 API 文档。前端工程师可以用它生成 Swagger UI测试工程师可以用它生成 Postman Collection。实操心得我在实际项目中发现新手最容易犯的错误是把复杂逻辑写在input的 Jinja2 模板里比如{{ .input.pdf_path | upper | replace(.PDF, .pdf) }}。这会让 YAML 变得难以阅读和调试。我的建议是所有数据转换逻辑必须下沉到具体的tool实现里。YAML 只负责“声明意图”Python 代码负责“实现细节”。Agent-Reach 的tool接口设计得非常干净你只需实现一个execute(input: dict) - dict方法剩下的注入、超时、重试都由运行时接管。3.2 Tool 开发规范如何编写一个符合 Agent-Reach 标准的工具Agent-Reach 的tool是它的扩展心脏。它内置了llm、http、shell、file等常用工具但绝大多数业务场景都需要你自定义。一个合格的tool必须满足三个硬性条件必须是一个 Python 模块位于tools/目录下且模块名与 YAML 中的tool字段完全一致。例如YAML 里写了tool: my-db-query那么就必须有一个tools/my_db_query.py文件注意下划线和短横线的转换。模块必须定义一个execute(input: dict) - dict函数且该函数必须是同步的sync。Agent-Reach 的运行时会自动为其加上超时和重试包装所以你不需要在execute里手动处理asyncio.wait_for或tenacity.retry。execute函数的input参数必须是 YAML 中input字段渲染后的纯字典dict不能是字符串或其它类型。这是强制的类型安全。下面是一个真实的tools/send_slack_alert.py示例它展示了如何编写一个健壮的、符合生产要求的 tool# tools/send_slack_alert.py import os import json import logging import requests from typing import Dict, Any logger logging.getLogger(__name__) def execute(input: Dict[str, Any]) - Dict[str, Any]: 发送 Slack 告警消息 input schema: - channel: str, Slack 频道 ID (e.g., C012AB3CD) - message: str, 要发送的文本消息 - severity: str, 严重级别 (info, warning, error) # 1. 环境依赖检查这是 tool 自己的责任不是 Agent-Reach 的 webhook_url os.getenv(SLACK_WEBHOOK_URL) if not webhook_url: raise RuntimeError(SLACK_WEBHOOK_URL is not set in environment) # 2. 输入校验防御性编程 required_fields [channel, message, severity] for field in required_fields: if field not in input: raise ValueError(fMissing required input field: {field}) if input[severity] not in [info, warning, error]: raise ValueError(fInvalid severity: {input[severity]}. Must be one of {required_fields}) # 3. 构建 Slack Block Kit 消息专业做法用结构化数据而非纯文本 blocks [ { type: header, text: { type: plain_text, text: f:rotating_light: {input[severity].upper()} ALERT } }, { type: section, text: { type: mrkdwn, text: input[message] } } ] # 4. 发送请求带重试和超时 payload { channel: input[channel], blocks: blocks, username: Agent-Reach Monitor } try: # 使用 requests.Session 复用连接提升性能 with requests.Session() as session: response session.post( webhook_url, jsonpayload, timeout(3.05, 27) # connect timeout, read timeout ) response.raise_for_status() logger.info(Slack alert sent successfully to %s, input[channel]) return {status: success, slack_ts: response.headers.get(X-Slack-Response-Timestamp, )} except requests.exceptions.Timeout: logger.error(Slack webhook request timed out) raise RuntimeError(Slack webhook timeout) except requests.exceptions.ConnectionError: logger.error(Failed to connect to Slack webhook) raise RuntimeError(Slack webhook connection failed) except requests.exceptions.HTTPError as e: logger.error(Slack webhook returned HTTP %s: %s, response.status_code, response.text) raise RuntimeError(fSlack webhook HTTP {response.status_code}: {response.text}) except Exception as e: logger.exception(Unexpected error in send_slack_alert) raise这个示例体现了几个关键经验环境检查前置SLACK_WEBHOOK_URL的检查放在最开头确保在做任何网络请求前就失败避免浪费资源。输入校验严格不仅检查字段是否存在还检查severity的枚举值这是防止下游服务因非法输入而崩溃的第一道防线。使用 Block Kit不是发纯文本而是用 Slack 的结构化 Blocks让告警信息更易读、可交互比如可以加一个“查看详情”按钮。Session 复用requests.Session()复用 TCP 连接对于高频告警场景能显著降低延迟。超时分段(3.05, 27)是 requests 的标准超时元组3.05 秒是连接超时避免 DNS 解析卡住27 秒是读取超时留给 Slack 处理时间这个数值是经过线上压测得出的平衡点。注意Agent-Reach 的tool模块其execute函数的返回值dict会自动成为下一个 step 的input的一部分。所以如果你的send_slack_alert返回了{status: success, slack_ts: 1718472123.001200}那么后续的 step 就可以通过{{ .steps.send_slack_alert.output.slack_ts }}来引用这个时间戳。这是一种隐式的、基于命名的“数据流管道”比硬编码的函数调用更灵活也更符合声明式编程的思想。3.3 环境管理与密钥安全为什么.env文件是起点而不是终点热词里有 “agent安全”、“python安装numpy库的方法”这暗示着很多开发者在部署时会把 API Key 直接写在 YAML 里或者用os.environ[KEY]硬编码在 Python 里。Agent-Reach 明确反对这两种做法它提供了一套分层的环境管理方案.env文件开发/测试这是最基础的。Agent-Reach 会自动加载当前目录及父目录下的.env文件按就近原则。它使用python-dotenv库支持#注释和变量插值DB_URLpostgresql://${DB_USER}:${DB_PASS}localhost:5432/mydb。但.env文件绝不允许提交到 Git它应该出现在.gitignore的第一行。环境变量注入CI/CD在 GitHub Actions 或 Jenkins 中你应该通过secrets机制将密钥作为环境变量注入到 runner 中。Agent-Reach 的--validate-env会检查这些变量确保它们在进程启动时就已存在。Vault 集成生产对于高安全要求的场景Agent-Reach 提供了--vault-token和--vault-path选项。它会调用 HashiCorp Vault 的/v1/{path}API用提供的 token 获取密钥并将其注入到当前进程的os.environ中。这个过程是透明的你的 YAML 和 tool 代码完全感知不到差异。最关键的实践是永远不要在 YAML 的input字段里直接写密钥。比如不要这样写# 错误密钥暴露在 YAML 里 steps: - name: call-llm tool: llm input: | {api_key: sk-abc123..., prompt: ...}而应该这样# 正确密钥从环境变量获取 steps: - name: call-llm tool: llm input: | {prompt: ...} # api_key 由 llm tool 自动从 OPENAI_API_KEY 环境变量读取Agent-Reach 的内置llmtool 就是这么设计的它会优先读取OPENAI_API_KEY如果不存在再 fallback 到input里的api_key字段。这种设计让同一个 YAML 文件可以在开发环境用.env、测试环境用 CI secrets、生产环境用 Vault无缝运行只需改变环境变量的注入方式无需修改 YAML 本身。实操心得我在一个金融客户的项目中曾遇到过 Vault 集成失败的问题。排查发现他们的 Vault server 启用了 TLS 证书验证而 Agent-Reach 默认的 HTTP client 没有配置 CA bundle。解决方案是在agent.yaml的顶层添加vault_tls_ca: /etc/ssl/certs/ca-bundle.crt字段Agent-Reach 会自动将其传递给requests库。这个细节官方文档没写但它是生产环境落地的必经之路。4. 实操过程与核心环节实现从安装到上线一个完整工作流的逐帧解析4.1 安装与初始化5 分钟完成从零到第一个 AgentAgent-Reach 的安装严格遵循 Python 社区的最佳实践。它不依赖任何系统级包管理器如 apt 或 brew也不要求你安装特定版本的 Python。它只要求你的系统上有pipPython 3.8。第一步创建隔离的虚拟环境强烈推荐# 创建一个名为 venv 的虚拟环境 python3 -m venv venv # 激活它Linux/macOS source venv/bin/activate # 激活它Windows venv\Scripts\activate.bat提示为什么必须用虚拟环境因为 Agent-Reach 的tool可能依赖pandas1.5.3而你的主项目可能需要pandas2.0.0。虚拟环境是 Python 项目隔离的基石没有商量余地。第二步安装 Agent-Reachpip install agent-reach这条命令会安装agent-reach包及其所有依赖PyYAML,requests,jinja2,python-dotenv等。安装完成后agent-reach命令就会出现在你的$PATH中。第三步初始化一个新 Agent 项目agent-reach init my-invoice-agent cd my-invoice-agentinit命令会为你生成一个标准的项目骨架my-invoice-agent/ ├── agent.yaml # 主配置文件 ├── tools/ # 自定义工具目录 │ └── __init__.py ├── .env # 环境变量文件已加入 .gitignore ├── requirements.txt # 项目依赖空的等你填 └── README.md # 项目说明此时你已经拥有了一个可运行的 Agent 项目。你可以立即执行agent-reach run --config agent.yaml --input {pdf_path:/dev/null,vendor_id:TEST}当然它会失败因为/dev/null不是 PDF但你会看到一个清晰的错误堆栈告诉你失败发生在extract-text这个 step原因是pdfplumber无法解析空文件。这就是 Agent-Reach 的“最小可行反馈”MVP Feedback它不给你一个笼统的Error而是精确定位到 DAG 中的哪一环、哪个工具、哪个输入出了问题。第四步添加第一个真实工具pdfplumber编辑requirements.txt加入pdfplumber0.10.0然后运行pip install -r requirements.txt接着创建tools/pdfplumber.py# tools/pdfplumber.py import pdfplumber import logging logger logging.getLogger(__name__) def execute(input: dict) - dict: pdf_path input.get(pdf_path) if not pdf_path: raise ValueError(pdf_path is required) try: with pdfplumber.open(pdf_path) as pdf: full_text \n.join([page.extract_text() or for page in pdf.pages]) logger.info(Extracted %d pages from %s, len(pdf.pages), pdf_path) return {text: full_text, page_count: len(pdf.pages)} except Exception as e: logger.error(Failed to extract text from %s: %s, pdf_path, e) raise现在再次运行agent-reach run ...它就能成功执行extract-text这一步了。整个过程从pip install到第一个 tool 跑通不超过 5 分钟。这种极快的反馈循环是保持开发动力的关键。4.2 配置驱动的多环境部署一套 YAML三种环境Agent-Reach 的核心优势在于它能把“环境差异”完全抽象为配置。我们以一个常见的需求为例同一个invoice-processorAgent需要在dev、staging、prod三个环境运行每个环境的数据库 URL、LLM 模型、告警频道都不同。传统做法是维护三套 YAML 文件agent-dev.yaml、agent-staging.yaml、agent-prod.yaml。Agent-Reach 提供了更优雅的方案使用 YAML 的锚点Anchor和别名Alias机制结合环境变量注入。创建一个agent.base.yaml# agent.base.yaml name: invoice-processor version: 1.2.0 # ... 其他不变的配置 ... steps: - name: extract-text tool: pdfplumber input: | {pdf_path: {{ .input.pdf_path }}} timeout: 60 - name: parse-invoice tool: llm model: llm_model gpt-4o-mini # 定义锚点 system_prompt: | 你是一个专业的财务助理... input: | {text: {{ .steps.extract-text.output.text }}} timeout: 30 - name: save-to-db tool: postgres input: | {invoice: {{ .steps.parse-invoice.output }}, vendor_id: {{ .input.vendor_id }}} timeout: 10 dependencies: - name: POSTGRES_URL required: true - name: OPENAI_API_KEY required: true然后为每个环境创建一个覆盖文件# env/dev.yaml # 继承 base只覆盖需要变更的部分 : !include agent.base.yaml # 覆盖 LLM 模型为免费的本地模型 steps: - name: parse-invoice : *parse-invoice-step # 重用 base 中的定义 model: phi-3-mini # 覆盖 model 字段 # 覆盖数据库为本地 SQLite dependencies: - name: POSTGRES_URL required: false default: sqlite:///./dev.dbAgent-Reach 本身不原生支持!include但你可以用一个简单的预处理器。我通常用yq一个强大的 YAML 处理 CLI来完成# 安装 yq pip install yq # 生成 dev 环境的最终配置 yq eval-all select(file agent.base.yaml) * select(file env/dev.yaml) agent.base.yaml env/dev.yaml agent-dev.yaml在 CI/CD 流水线中你可以这样部署# .github/workflows/deploy.yml name: Deploy Invoice Processor on: push: branches: [main] paths: [agent.base.yaml, env/**] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - name: Set up Python uses: actions/setup-pythonv4 with: python-version: 3.11 - name: Install dependencies run: | pip install agent-reach yq - name: Generate prod config run: | yq eval-all select(file agent.base.yaml) * select(file env/prod.yaml) agent.base.yaml env/prod.yaml agent-prod.yaml - name: Run validation run: | agent-reach validate --config agent-prod.yaml - name: Deploy to prod server uses: appleboy/scp-actionv0.1.7 with: host: ${{ secrets.PROD_HOST }} username: ${{ secrets.PROD_USER }} key: ${{ secrets.PROD_SSH_KEY }} source: agent-prod.yaml,tools/,requirements.txt target: /opt/agent-reach/invoice-prod/这个工作流的关键在于agent.base.yaml是唯一的业务逻辑源env/*.yaml是纯粹的环境策略。当你需要为prod环境增加一个新的告警步骤时你只修改env/prod.yamldev和staging的行为完全不受影响。这种“关注点分离”是大型 Agent 项目可维护性的生命线。4.3 日志、监控与可观测性让 Agent 的“思考”变得可见Agent-Reach 的日志设计是它区别于其他框架的另一个亮点。它不满足于“打印一堆信息”而是致力于让日志成为可查询、可分析、可告警的数据源。日志格式logfmt 是默认JSON 是可选当你运行agent-reach run --config agent.yaml --input ...时它默认输出logfmtlevelinfo ts2024-06-15T14:22:03Z msgStarting agent nameinvoice-processor version1.2.0 leveldebug ts2024-06-15T14:22:03Z msgExecuting step stepextract-text toolpdfplumber levelinfo ts2024-06-15T14:22:05Z msgStep completed stepextract-text duration_ms1842.3 leveldebug ts2024-06-15T14:22:05Z msgExecuting step stepparse-invoice toolllm modelgpt-4o-mini levelinfo ts2024-06-15T14:22:12Z msgStep completed stepparse-invoice duration_ms6892.1 levelinfo ts2024-06-15T14:22:12Z msgAgent completed successfully output{invoice_number:INV-2024-001,total_amount:1234.56}这种格式可以直接用grep、awk、jq处理。例如统计过去一小时所有 Agent 的平均执行时间# 假设日志被重定向到 /var/log/agent-reach.log grep Agent completed successfully /var/log/agent-reach.log | \ awk {sum $NF; count} END {print Average:, sum/count, ms}如果需要更高级的分析开启 JSON 格式agent-reach run --log-format json --config agent.yaml ...输出变为{level:info,ts:2024-06-15T14:22:03.123Z,msg:Starting agent,name:invoice-processor,version:1.2.0} {level:debug,ts:2024-06-15T14:22:03.456Z,msg:Executing step,step:extract-text,tool:pdfplumber}这就可以直接接入 ELK Stack 或 Loki。内置健康检查与指标导出Agent-Reach 还提供了一个health子命令它不是一个 HTTP 服务而是一个本地进程检查agent-reach health --config agent.yaml它会返回一个 JSON{ status: healthy, checks: [ { name: environment, status: pass, message: All required dependencies are present }, { name: tool.pdfplumber, status: pass, message: pdfplumber module is importable }, { name:
返回列表