1. 为什么编码代理需要一副“辅助轮”先讲一个我自己的场景。前阵子团队同时积压了七八个 GitHub Issue我图省事把每个 Issue 都丢给一个编码 Agent 去处理。最开始十几分钟还挺顺利Agent 在仓库里翻来翻去定位文件、改代码、跑测试一个个 PR 被自动创建出来。但我点开 diff 一看就傻眼了有一个 Agent 为了“修复”一个日志级别的小问题顺手把无关模块的代码风格给重写了另一个 Agent 在尝试改配置文件时把测试环境的参数带进了生产配置里。代码本身没有语法错误但整个 PR 根本没法审。这就是当前 AI 编码代理落地时最典型的问题模型能力已经够强但自主性和失控只隔着一层窗户纸。让 Agent 完全自由发挥它会在不合适的文件里动不合适的代码给 Agent 每一步都加人工确认又等于把编码代理用成了自动补全插件失去了省人力的意义。Trellis 这个开源框架解决的就是这个矛盾。它来自 Salesforce 研究院定位是给大规模 AI 代理工作流做编排、追踪和策略控制。如果用一句话概括它的价值Trellis 不会替代码代理写代码但它知道代理在哪个阶段该做什么、做完之后发生了什么、哪些动作不允许发生。就像给刚上路的新手司机加了一副辅助轮——方向还是司机自己打但不会一头冲进沟里。在 AI 编程这个新范式里我们习惯了讨论模型选型、上下文窗口、提示词工程但真正决定一套代理系统能否上生产的往往是它周围这些“不性感”的配套设施。Trellis 补的正是这块短板。适合谁看如果你在用 Cursor、Trae、Copilot 这类工具时觉得“单文件补全很强但让 Agent 完整跑一个任务心里没底”或者你想自己搭建一条从 Issue 到 PR 的自动化流水线又或者你在维护多个 Agent 并行作业被互相踩文件、无审计记录、无法回滚这些问题折磨过——这篇文章就是写给你的。2. Trellis 的核心设计把隐式决策变成显式工作流2.1 它到底是个什么东西很多人第一次听到 Trellis会以为它又是一个类似 LangGraph 或者 AutoGen 那种“帮你写 Agent 逻辑”的框架。实际上 Trellis 的定位比这更底层也更克制。它是一套代理工作流的定义、编排和治理基础设施。拆开讲Trellis 包含这样几个核心部分Trellis Workflows用声明式的方式定义代理要执行的任务流程比如“分析 Issue - 定位相关代码 - 生成补丁 - 运行测试 - 创建 PR”每一步依赖什么前置条件、失败之后走哪个分支都在工作流定义里写清楚。Trellis Orchestrator按照工作流的依赖关系调度代理执行。支持单机直跑也支持部署成分布式服务通过 gRPC 通信可以横向扩容。Trellis Policy给代理套上行为约束的规则引擎。比如“只能改 src 目录下的文件”“不得触碰数据库配置”“禁止执行删除操作”这些规则会在代理的每个工具调用前后被检查。Trellis Trace运行时追踪系统。代理的每次工具调用、每轮 LLM 交互、每个中间状态都会被记录下来可以重放、可以回滚、可以审计。这个组合拳打出来效果就很明显了原先你在一个 Agent 框架里写“让代理去改代码”行为是隐式的、不可控的而在 Trellis 里你写的是“在满足这些前置条件之后允许代理执行这组操作”行为是显式的、可验证的。本质上是把一个“有智能的黑盒”变成了“一个有边界、有仪表盘、有方向盘的智能体”。2.2 为什么说它是“辅助轮”而不是“方向盘”我见过不少团队把 Trellis 用反了。他们觉得 Trellis 既然能编排工作流那干脆把业务逻辑也塞进去让 Trellis 替代理做决策。这是理解上的偏差。举个例子你让代理判断“这个 Issue 是前端样式问题还是后端接口问题”这属于方向盘的范畴应该交给模型但“前端样式修改完成后必须先跑一遍 ESLint 才能生成 PR”这是路线约束属于辅助轮的范畴。Trellis 的价值在于把后者这种流程性的、可验证的、不依赖模型判断的规则固化下来而不是去抢模型的活。打个比方一台没有辅助轮的高级公路车理论上骑得最快但新手保持不了平衡一台带辅助轮的童车速度上不去但不会摔。Trellis 这套辅助轮设计的巧妙之处在于它做了可拆卸设计——等你跑熟了、积累够了信任度完全可以去掉部分策略约束逐步放权。2.3 对比 LangGraph 等编排工具它有什么不同这里插一段横向对比帮大家建立坐标系。LangGraph 也是做 Agent 工作流编排的但它的核心关注点是图结构与状态流转你定义节点、边条件、状态修饰符图引擎负责按拓扑序执行。Trellis 同样基于有向无环图来做编排但它多出了两个明显的差异化能力一是内置了策略执行引擎可以在代理工具调用层面对行为做拦截二是追踪系统是内建的一等公民每一次运行都产生可回放的事件流而不只是图层面的状态快照。简单说LangGraph 给你的是“画图的画布”Trellis 给你的是“画图工具 安全帽 行车记录仪”。如果你只是在一个脚本里串几个 LLM 调用LangGraph 很顺手但如果你在管一组真正会修改代码、会执行命令、会操作文件的编码代理Trellis 的治理能力会让生产环境的安全审查轻松很多。3. 动手实践从中等复杂度的 PR 自动修复场景说起3.1 环境准备Trellis 目前提供 Python 和 TypeScript 两种语言的客户端服务端可以用 Docker 运行。我日常主要写 Python所以下面的示例以 Python 为主。安装很简单pip install trellis[workflows,orchestrator,policy,trace]如果你用的是 TypeScript 栈对应的是npm install trellisorg/sdk。需要注意一点Trellis 的 Python 版本要求 3.10 及以上因为内部用了不少新语法特性。我最初在 3.9 环境里安装直接报语法错误白白浪费了十几分钟。服务端我用 Docker 起一个单机实例docker run -p 8100:8100 -p 8200:8200 -v ./trellis_data:/data salesforce/trellis:latest8100 端口是管理 API8200 是 gRPC 端点。第一次起服务我看到日志里出现Trellis runtime listening on 0.0.0.0:8100心里才踏实下来。3.2 定义你的第一个工作流工作流是 Trellis 里最基本的概念。一个工作流由若干个步骤Step组成步骤之间通过依赖关系连接。依赖关系分成两种requires表示“前置步骤必须成功完成”on_failure表示“前置步骤失败后走这个分支”。这是 Trellis 语法里最核心的两个关键词。直接看代码。下面这个工作流是我在生产环境里真实用过的简化版——收到一个 Bug Issue 后自动完成分析、定位、修复和提 PR 的全过程from trellis.workflows import Workflow, step from trellis.workflows import StepContext step(nameread_issue) def read_issue(ctx: StepContext): 读取 GitHub Issue 内容 issue ctx.tools.github.get_issue(numberctx.params[issue_number]) ctx.state[issue_body] issue.body ctx.state[issue_title] issue.title return {status: success, files_created: []} step(namelocate_code, requires[read_issue]) def locate_code(ctx: StepContext): 在仓库中定位与该 Issue 相关的代码文件 result ctx.agent.run( task根据 Issue 描述在代码仓库中找出最可能需要修改的核心文件, contextctx.state[issue_title] \n ctx.state[issue_body] ) ctx.state[target_files] result.relevant_files return {status: success, files_created: []} step(namepatch_code, requires[locate_code], policypatch_policy) def patch_code(ctx: StepContext): 让代理生成代码修改方案 patch ctx.agent.run( task对目标文件生成最小化的修改确保只解决 Issue 描述的问题, context{files: ctx.state[target_files]} ) ctx.state[patch_content] patch.diff return {status: success, files_created: []} step(namerun_tests, requires[patch_code], on_failurenotify_human) def run_tests(ctx: StepContext): 在隔离沙箱中运行测试 result ctx.tools.shell.run(pytest --tbshort, timeout300) if result.exit_code ! 0: return {status: failed, reason: result.stderr[-500:]} return {status: success} step(namecreate_pr, requires[run_tests]) def create_pr(ctx: StepContext): 创建 Pull Request ctx.tools.github.create_pr( titlefAuto fix: {ctx.state[issue_title]}, body由 Trellis 工作流自动生成, diffctx.state[patch_content] ) return {status: success} workflow Workflow( nameauto_bug_fix, steps[read_issue, locate_code, patch_code, run_tests, create_pr], edges[ (read_issue, locate_code), (locate_code, patch_code), (patch_code, run_tests), (run_tests, create_pr) ] ) # 注册到编排器 workflow.register()写完这个工作流我最大的感受是它本质上把以前散落在提示词里的流程约束全部抽成了结构化的代码。以前我们让 Agent 跑任务只能反复在 prompt 里强调“别乱改文件”“跑完测试再提 PR”模型时灵时不灵现在这些约束变成了工作流的前置条件和顺序关系模型压根没有机会不按流程来。3.3 提交运行任务工作流注册好之后就能通过编排器提交一个具体的运行实例from trellis.orchestrator import TrellisOrchestrator orch TrellisOrchestrator(addresslocalhost:8200) run_id orch.run( workflow_nameauto_bug_fix, params{ issue_number: 1287 } ) # 等待运行完成 result orch.wait_for_completion(run_id, timeout600) print(result.status, result.trace_url)这里有一个细节值得注意params是传给工作流的初始参数但工作流各步骤之间的数据传递走的是ctx.state这个状态对象不是靠函数返回值。这意味着 Trellis 对工作流的每个中间状态都有完整的快照。如果你的某个步骤执行到一半崩了可以基于最近一个成功状态重放而不需要从头再跑一遍。3.4 为什么这个场景适合从 Trellis 入门我特意选了“Issue 自动修复 PR 创建”这个场景来演示因为它把编码代理最核心的几个痛点全踩中了代理需要读取外部数据GitHub Issue、需要调用代码模型能力定位与修改、需要执行命令跑测试、需要对外部系统产生副作用创建 PR。这四类操作如果没有任何编排和治理代理很容易在某一环失控。Trellis 对这个场景的适配是天然的外部读取对应工作流的输入参数和初始状态代码修改对应步骤内的代理调用并由策略约束命令执行可以限制在沙箱环境里副作用操作作为工作流的终结点天然要求前面的步骤全部成功。这套逻辑顺下来一个能用、可控的自动化编码流程就搭出来了。4. 核心机制拆解策略引擎和追踪系统的工作逻辑4.1 策略引擎它如何拦截“不该做的事”Trellis 的策略引擎是我认为它区别于大部分 Agent 框架的关键模块。编码代理在执行任务时本质是一连串的工具调用读写文件、执行命令、调用 API。Trellis 在工具调用层插入了策略检查点每次调用前先过一遍策略规则符合就放行不符合就拦截并记录。策略用起来很简单核心是定义允许和拒绝的规则。我贴一段实际用过的“补丁策略”name: patch_policy description: 限制代理只能修改位于 src/ 下的源码文件禁止触碰配置文件和构建产物 rules: - id: disallow_config_modification type: deny resource: file action: write condition: path_match: - config/* - *.env* - docker-compose*.yml - id: allow_src_only type: allow resource: file action: write condition: path_prefix: src/ - id: forbid_expensive_commands type: deny resource: shell action: exec condition: command_match: - rm -rf* - git reset --hard*这段配置的意思很直白写文件时先检查是不是命中config/或者.env之类的路径命中就拒绝如果写的是src/目录下的文件则允许执行 shell 命令时带rm -rf或者git reset --hard的直接拦下。策略的匹配顺序是 deny 优先。也就是说哪怕某条命令同时命中了一个 allow 规则和一个 deny 规则最终执行结果也是被拒绝。这个设计在安全上很保守——代理可能会找出规则之间的漏洞deny 优先能最大程度避免“看起来能过但实际危险”的情况。我自己第一次调试策略时犯过一个低级错误我把 allow 规则写在 deny 规则前面以为规则会按顺序短路判断结果代理每次修改src/文件都被拦截原因是 Trellis 的策略引擎会先收集所有匹配规则deny 优先再判断。查了半小时文档才反应过来这里真的值得提前避坑。4.2 追踪系统每次运行都有“行车记录仪”Trellis 的另一个重量级能力是运行时追踪。有了追踪你在出问题时不用再对着 Agent 的终端输出猜它干了什么而是能看到完整的执行轨迹。追踪系统记录的数据粒度很细每个步骤的开始、结束时间和最终状态每次 LLM 调用的输入、输出、token 消耗每次工具调用的参数和返回值每次策略检查的匹配结果放行还是拦截工作流状态对象的变化历史这些数据汇集成一个事件流Trellis 会为每次运行生成一个独立的追踪 ID。你可以通过 CLI 拉取追踪数据trellis trace view --run-id run_id输出会包含全链路的事件序列。我在实际排查问题时的标准操作是工作流失败后先看trace view找到第一个返回非成功状态的步骤再展开那个步骤的 LLM 调用和工具调用基本上问题定位不需要超过五分钟。更实用的是追踪数据还能用来做回归分析和成本控制。我有一次发现某个工作流的 token 消耗异常高翻了追踪记录才发现是代理在一个定位步骤里反复读取同一个大文件七八次每次读都把整个文件内容塞进上下文。后来我在策略里加了一条规则禁止在同一步骤内重复调用文件读取工具token 消耗直接降了 40%。4.3 状态机制快照与回滚的底层支撑工作流的每一步执行完毕Trellis 都会把当前的ctx.state序列化保存为快照。快照的存在让两个能力变成可能一是失败恢复二是基于历史状态的分支调试。失败恢复的逻辑是这样的假设工作流跑到了第六步才失败前五步的状态和结果都已经固化成快照了。你修复了第六步的问题后可以让工作流从第五步的结尾重新开始执行而不必重跑前五步。对于涉及大量外部调用尤其是花费 token 的 LLM 调用的流程这个能力省下的成本非常可观。分支调试则更偏开发阶段。我在调试一个新工作流时经常故意让它在某一步失败然后用trellis workflow replay --step patch_code --from run_id把前面的状态加载回来只重跑patch_code这一步观察不同参数下的效果。这比每次从零跑完整流程要高效一个数量级。5. 从原型到生产我在实际落地过程中踩过的坑5.1 坑一把工作流定义当成代码库来维护第一次写 Trellis 工作流时我下意识地按写微服务的思路来组织代码每个步骤单独建一个模块工作流定义文件里引用各个模块。结果发现步骤之间的状态传递变得很别扭——ctx.state里的键分散在不同模块里光靠读代码很难理清运行时的数据流。后来我调整了组织方式把同一个业务场景的步骤放进同一个文件状态键的命名也统一加前缀比如bug_fix.target_files、bug_fix.patch_content。虽然文件会变长但可读性好了很多。调试时一眼就能看出状态在哪个步骤被写入、被消费。5.2 坑二策略规则设得太松或太紧策略规则的设计是一个持续调优的过程而且两边的坑我都踩过。太松的表现是代理确实不会去删库了但它会创建一个全新的文件放在根目录而不是业务代码目录下整个 PR 还是没法用太紧的表现是代理每次想写文件都被策略拦截在工作流里反复重试最后因为达到最大重试次数而失败任务完全卡死。我的经验是策略规则应该按步骤维度配置而不是全局统一。在“定位代码”步骤代理只需要读权限我就只给它读文件的策略在“生成补丁”步骤才放开指定目录的写权限。另外规则里一定要保留“通知人类”的兜底分支代理被策略拦截多次后应该走人工审查而不是无限重试。Trellis 的on_failure参数就是干这个用的。5.3 坑三低估了追踪数据的存储成本Trellis 的追踪功能很方便方便到你几乎不想关掉它。但追踪数据是有存储成本的尤其是在高频运行工作流时事件流的增长速度可能远超预期。我有一次让一组工作流每十分钟跑一轮跑了一天后发现存储空间被吃掉几个 GB。解决方案并不复杂Trellis 支持在配置里设置追踪数据的保留时间和采样率。我把默认的“全量追踪”改成了“保留最近一百次运行的全量追踪”再开放一个采样参数trace_ratio0.3对性能测试类工作流只记录部分运行实例。正式生产时这种做法既保证了排查问题的可用数据量又不会让存储成本失控。5.4 坑四分布式部署时的环境隔离问题Trellis 支持分布式部署但当多个工作流实例在多台机器上并行跑时代理执行的代码实际上是在各自的容器或沙箱里跑的。有一次我碰到一个诡异的问题两个工作流实例明明没有共用文件路径却出现文件互相覆盖的现象。排查了半天发现是我在配置沙箱时没有给每个运行实例分配独立的挂载卷导致多个实例写到了同一块宿主目录。后来我在编排器的运行参数里加了workspace/tmp/trellis/{run_id}把每个实例的工作目录隔离成独立沙箱问题立即消失。这个经验也说明分布式环境下工作目录、临时文件、缓存目录都要做好运行级别的隔离否则代理之间的互相干扰会让你的自动化流程变得极不稳定。6. 和 LangGraph、CrewAI、AutoGen 对比后我的选型结论很多朋友问我说现在做 AI 编码代理编排工具到底该选哪个。我把 LangGraph、CrewAI、AutoGen 和 Trellis 放在一起跑了几个场景下面是我的实测对比。维度TrellisLangGraphCrewAIAutoGen核心定位工作流编排 治理图状态编排角色协作框架多代理会话框架策略约束内建策略引擎工具调用级拦截需自己实现弱靠 prompt 约定弱靠 prompt 约定运行追踪内建追踪系统全链路事件流有状态快照但追踪粒度较粗第三方方案第三方方案擅长场景编码代理、运维自动化、需要审计的场景状态复杂的图结构业务流程角色分工明确的内容生产多方交互、深度对话推理学习曲线中等中等平缓平缓生产级治理能力强中弱弱这么说可能比较抽象举一个具体例子。我在一个自动化代码审查流程里需要做这样一个控制代理只能给 PR 添加 comment不能强行修改 PR 的 title 和 branch。在 Trellis 里这是一条策略规则的事在 LangGraph 里我需要自己在节点代码里拦截对应的工具调用写起来也不算难但每加一个约束就要加一段逻辑久了工作流代码里会混进大量控制代码结构变得臃肿。我的选型结论是如果你的业务本质上是一个带条件分支、有明确状态流转的图流程而且不涉及高危工具操作LangGraph 灵活度高值得选如果你要编排的是多个不同角色的代理做内容协作比如写手、编辑、校对各一个代理CrewAI 的体验最顺畅如果你需要代理之间有深层对话、互相质询AutoGen 的会话机制有优势但如果你做的是 AI 编码代理代理会读写代码文件、执行命令、产生外部副作用那么 Trellis 的策略与追踪能力是当前最匹配的。毕竟编码代理最可怕的不是“能力不够”而是“做了一堆动作但没有记录、没有约束、无法回滚”。7. 一些关于使用节奏的建议文章写到这儿可以说点掏心窝的话。Trellis 确实给我的代理系统带来了实打实的变化原来我每天早上一睁眼要先看十几个 Agent 任务有没有乱来现在只需要看追踪报告里的失败记录和策略拦截记录。以前每次 Agent 出了岔子我只能从终端输出里猜它干了什么现在整个执行轨迹一目了然该回滚回滚该重放重放。但我也必须说Trellis 不是魔法它解决的是“失控”问题它不会让你的 Agent 变得更聪明。如果你的工作流本身设计得不合理、任务描述本身含糊不清辅助轮也救不了方向盘的错误。另外我的建议是不要把 Trellis 的策略体系一步到位设计得非常复杂。刚开始跑工作流时可以先把策略只设置成“禁止高危命令 禁止写保护目录”这一层让代理有足够的自由度跑通完整流程。等流程稳定了、你对代理的行为边界有了数据层面的认知再逐步收紧策略、增加规则。这个过程有点像带新人入职第一天你不会让他碰生产环境但你也不会把每一行代码怎么写都给他规定死先给边界再给自由度等对方展现出值得信赖的行为模式再逐步放权。如果你正在搭建一套 AI 编码代理的自动化体系我的建议是先拿一两个低风险、高频重复的 Issue 处理流程来试水 Trellis。把它跑稳把策略规则和追踪报告调到你满意的状态再横向扩展到更多场景。辅助轮这个东西是为了让你最终敢于拆掉辅助轮——但也只有在装过辅助轮、跑过足够多里程之后你才真正知道自己什么时候可以拆。