尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

AI编程Agent工程实践:从Devin到最小实现

AI编程Agent工程实践:从Devin到最小实现 AI 编程 Agent 赛道近来最受关注的公司是 Cognition——它打造的 Devin 被描述为“AI 软件工程师”。一条公开融资消息称该公司正在洽谈新一轮融资估值中枢可能达到 400 亿美元$40B量级。融资数字本身会随谈判变化正式口径应以官方公告为准但这件事给工程界带来一个值得讨论的信号AI 编程不再只是编辑器里的自动补全而是变成能自己读 Issue、改代码、跑测试、提交变更的 Agent 系统。本文从 Cognition 与 Devin 的能力定位出发不评价资本故事只拆解 AI 编程 Agent 的任务闭环、控制循环、工具调用和工程落地方式并给出一个最小可运行的 Agent 骨架帮助想接入这类能力的团队了解该准备什么、会踩哪些坑。1. 先建立共识AI 编程 Agent 解决的不是“帮你补代码”1.1 从代码补全到任务执行差了一个执行闭环很多团队一开始会把 AI 编程 Agent 和编辑器里的 AI 代码补全助手当成同一类产品。实际上它们解决的是两个层次的问题。代码补全工具的核心能力是“根据当前上下文预测下一段代码”。它假设人类仍然负责理解需求、编写正确流程、运行测试、修复失败AI 只负责减少重复输入。它的边界很清晰模型不执行命令不检查运行结果也不对最终改动是否符合预期负责。AI 编程 Agent 的核心能力则是“把一个软件任务从头到尾做出来”。它会先读取 Issue 描述浏览仓库结构定位相关文件修改代码运行测试看到测试失败后又继续分析日志、调整实现直到任务完成或明确报告失败。两者之间最关键的差距不是参数规模而是执行闭环。Agent 能看见自己动作的结果再根据结果决定下一步动作。这个“行动——反馈——再行动”的循环才是它被称为 Agent 的根本原因。用一句话概括补全工具给你一段函数Agent 给你一个跑通验证的变更。1.2 Devin 式任务流可以拆成五步根据 Cognition 对外公开的产品演示和 Devin 的产品定位一个 AI 编程 Agent 处理真实软件任务时路径大致可以拆成五个环节理解任务。先读 Issue 描述、仓库文档、相关模块代码搞清楚“要改什么”和“为什么改”。拆解计划。把大任务拆成子任务决定先看哪个文件、先跑哪条命令而不是直接开始写代码。执行动作。调用工具完成实际操作包括文件读取、关键词搜索、运行 shell 命令、编辑文件。验证结果。运行测试、lint、类型检查读取输出判断改动是否正确。汇报交付。生成 diff总结自己改了哪些文件、是否通过验证以及遗留问题。这五步不是线性走完的。真实场景中Agent 会在“执行动作”和“验证结果”之间反复循环测试失败了就回到代码修改阶段日志看不懂就再搜索相关配置。整个流程更像一个带反馈的控制系统。1.3 为什么资本关注这类产品而工程界更应该关注什么资本关注 AI 编程 Agent是因为它代表软件研发自动化方向如果 Agent 能稳定完成初级工程师的一部分重复工作软件团队的产出模型会被重估。这也是 Cognition 这类公司估值快速上升的背景之一。工程界关注的重点应该不同。团队真正要回答的问题包括Agent 能否理解项目的历史约定能否在受限环境内安全执行命令能否不破坏现有测试如何评测它是否真的完成了任务如果它失败了日志能不能支撑排查所以“估值多少”不决定“能不能用”。融资热度说明市场在押注方向但具体到代码仓库里一个 Agent 是否值得接入取决于它的控制循环、工具权限、上下文管理和评测机制是否可靠。2. Agent 的核心机制控制循环、工具调用和沙箱2.1 Agent 的本质是模型外套一个循环把视觉上的“智能”剥开AI 编程 Agent 的骨架其实很简单一个 LLM 负责推理一个循环负责反复调用它一组工具负责执行动作。伪代码如下while not done: response llm(messages, tools) if response 没有请求调用工具: done true else: for tool_call in response.tool_calls: result execute(tool_call) messages.append(tool_result)这个循环必须存在是因为模型本身无法执行代码。它只能根据当前对话历史输出“我想运行 pytest”这样的意图。真正去运行 pytest、读取输出、把输出塞回上下文必须由代码完成。这里有一个常见误解很多人以为把大段日志直接返回给模型模型就能表现更好。实际上工具结果会占用上下文窗口如果输出太乱、太长模型反而会丢失重点。好的 Agent 骨架不仅要执行工具还要负责控制信息的质量和长度。2.2 工具调用把自然语言意图转成结构化命令为了让模型可以操作外部环境通常使用 Function Calling也叫 Tool Calling机制。模型不再直接输出一段自由文本而是输出一个结构化的 JSON描述要调用的函数名和参数。例如模型可能输出{ name: run_command, arguments: { command: pytest tests/test_demo.py } }代码拿到这个 JSON 后会先校验函数名是否在白名单里再解析参数最后执行命令。这种设计的好处是模型输出与代码执行解耦。调用方可以拦截、记录、限制危险命令。审计日志能清楚记录模型每一步想做什么。多模型可以复用同一套工具执行层只需保证模型支持 Function Calling。最小工具集建议只保留四个read_file、write_file、list_files、run_command。工具太多会加重模型的决策负担经常出现选错工具、参数拼错的问题。2.3 沙箱环境为什么不可省略让 Agent 在不加限制的本地环境里执行 shell 命令是一件危险的事。它可能误删文件、安装不兼容依赖、改写全局配置甚至执行不可逆操作。由于模型是概率输出任何一条命令都可能出错。沙箱的作用是限制“破坏半径”。常见做法包括使用 Docker 容器任务结束后直接销毁。使用临时目录作为工作区禁止访问目录之外的文件。在 CI 环境中运行每次任务从干净镜像重新构建。为 Agent 创建独立系统用户限制权限。说白了Agent 是在“猜测”下一步该做什么它不需要被信任环境需要被设计成“即使猜错了也坏不了大事”。2.4 SWE-bench 类评测能说明什么、不能说明什么SWE-bench 是当前讨论 AI 编程 Agent 时绕不开的评测基准。它从真实 GitHub 仓库中提取 Issue、代码和测试补丁要求模型根据 Issue 生成补丁再通过隐藏测试来判断是否解决。这类评测的价值在于它比“让模型写一个排序算法”更接近真实工程。它要求模型理解已有代码库、定位问题、修改正确位置并且最终要通过测试。但它不能说明全部问题。真实软件任务还包括代码审查、跨仓库依赖、历史上下文、风格兼容、测试不充分的场景。模型在 SWE-bench 上拿高分不代表它能独立完成一个生产级 Pull Request。落地建议是不要只信公共基准。团队应该把自己仓库过去 20 个真实合并的 PR 做成回归集去掉答案后定期跑一次看 Agent 在自己业务场景下的真实趋势。3. 最小骨架一个能读 Issue、改文件、跑测试的编程 Agent到这里进入实践环节。下面实现一个最小 Agent 骨架。它不追求产品化目的是让你看清“控制循环 工具调用 沙箱”是怎么组合在一起的。示例使用 OpenAI-compatible 接口因为很多模型服务都提供兼容端点切换成本低。实际落地时要根据自己的模型服务调整base_url和MODEL_NAME。3.1 准备环境建议使用 Python 3.9 或更高版本。先创建项目目录和虚拟环境mkdir agent-demo cd agent-demo python -m venv venv source venv/bin/activate pip install openai python-dotenv然后创建.env文件写入模型服务信息API_KEYyour-api-key API_BASEhttps://your-openai-compatible-endpoint MODEL_NAMEgpt-4o-mini这里的API_BASE取决于你使用的服务。本地部署的模型服务如果兼容 OpenAI 接口也可以直接填本地地址。出于安全考虑不要把这个文件提交到 Git。3.2 项目结构agent-demo/ ├── .env ├── requirements.txt ├── demo_agent.py ├── issue.txt └── workspace/workspace是 Agent 的沙箱目录。所有命令都限制在这个目录里执行Agent 只能修改它。3.3 核心实现控制循环新建demo_agent.pyimport os import json import subprocess from openai import OpenAI from dotenv import load_dotenv load_dotenv() client OpenAI( api_keyos.getenv(API_KEY), base_urlos.getenv(API_BASE), ) MODEL os.getenv(MODEL_NAME, gpt-4o-mini) WORKSPACE os.path.abspath(workspace) MAX_ITERATIONS 8 TOOLS [ { type: function, function: { name: run_command, description: 在项目工作区中执行 shell 命令适合运行测试、查看文件等, parameters: { type: object, properties: { command: { type: string, description: 要执行的 shell 命令 } }, required: [command] } } } ] def execute_command(command: str) - str: try: result subprocess.run( command, shellTrue, cwdWORKSPACE, capture_outputTrue, textTrue, timeout30, ) return ( fexit_code{result.returncode}\n fstdout:\n{result.stdout}\n fstderr:\n{result.stderr} ) except subprocess.TimeoutExpired: return command timed out after 30s def run_agent(issue_text: str): messages [ { role: system, content: ( 你是运行在沙箱中的编程 Agent。 你的任务是完成用户给出的软件任务。 只能通过 run_command 工具查看文件和执行命令。 不要删除重要文件。执行有限次数后如果仍无法完成请说明原因。 ), }, { role: user, content: f工作目录{WORKSPACE}\n任务\n{issue_text}, }, ] for step in range(MAX_ITERATIONS): response client.chat.completions.create( modelMODEL, messagesmessages, toolsTOOLS, tool_choiceauto, temperature0.2, ) message response.choices[0].message messages.append(message) if not message.tool_calls: print(最终回复, message.content) return for tool_call in message.tool_calls: if tool_call.function.name ! run_command: continue args json.loads(tool_call.function.arguments or {}) command args.get(command, ) print(fstep {step}: 执行 {command}) result_text execute_command(command) messages.append( { role: tool, tool_call_id: tool_call.id, content: result_text, } ) print(达到最大迭代次数任务未在约束内完成。) if __name__ __main__: issue open(issue.txt, encodingutf-8).read() run_agent(issue)关键点有三个。第一tool_choiceauto让模型自己决定是调用工具还是直接输出最终回复。测试时可以把值改成{type: function, function: {name: run_command}}强制模型每一步都调用工具便于观察循环是否正常。第二temperature0.2。编程任务追求确定性过高的随机性会让模型输出不稳定命令。第三工具消息必须带上tool_call_id否则接口会报错。这是 OpenAI-compatible Function Calling 的硬性要求。3.4 准备一个最小任务在issue.txt中写一个可验证的任务在 workspace 中创建 greet.py包含函数 greet(name: str) - str返回 Hello, name!。 再创建 test_greet.py使用 pytest 验证 greet(world) 返回 Hello, world!。 最后运行 pytest确保测试通过。workspace目录保持为空让 Agent 从零开始创建文件。3.5 运行验证执行python demo_agent.py正常运行时控制台会输出类似下面的日志step 0: 执行 ls -la step 1: 执行 cat greet.py EOF ... step 2: 执行 cat test_greet.py EOF ... step 3: 执行 pytest -q 最终回复 任务完成。greet.py 和 test_greet.py 已创建pytest 通过。如果模型不支持 Function Calling它可能不会生成tool_calls而是直接输出“我应该先创建文件”这类叙述。此时需要换成支持 Function Calling 的模型或调整提示词。这个示例能跑通之后可以把run_command工具替换成更安全的内部 API比如只允许执行白名单命令的工具。这样才能往生产环境方向走。4. 参数、权限和生产部署从能跑到敢上线4.1 影响 Agent 行为的关键参数同一个 Agent 骨架换一组参数行为会截然不同。下面是落地时必须关注的参数。参数含义初始推荐值调大影响调小影响temperature输出随机性0 到 0.3更灵活但代码不稳定更稳定但容易机械重复max_iterations最大循环次数5 到 15完成率更高但成本增大成本低但可能半途而废timeout单条命令超时30 到 120 秒容忍慢测试更快发现问题但易误伤max_tokens单次模型输出上限1000 到 2000支持长工具调用参数输出可能被截断context 长度消息历史加工具输出按模型上限能保留更多上下文早期信息易被遗忘这些数值不是精确标准。模型版本、任务复杂度、仓库大小都会影响最优值。建议先用小任务调试再扩大到真实 Issue。4.2 学习环境与生产环境的差异本地演示重在跑通循环。生产环境则要额外考虑权限、审计、回滚和网络隔离。场景Agent 权限文件系统外部网络审计要求本地演示可执行任意 shell 命令临时目录不限制低CI 流水线只允许构建和测试命令每次重建工作区依赖源白名单中生产操作只读代码加审批制写操作权限边界严格禁止或白名单必须审计不要把本地演示的 Agent 直接部署到生产服务器上。本地环境为了调试方便允许了shellTrue这在生产环境是不可接受的。4.3 权限模型最小授权和审计一个稳妥的做法是把 Agent 当作“只能产生变更”的角色而不是“直接执行变更”的角色。推荐流程如下Agent 在沙箱中读取代码、编写补丁、运行测试。Agent 生成 diff 或提交 Pull Request。人在 Pull Request Review 阶段审查改动。只有人工批准后CI 才能合并并部署。这种模式既保留 Agent 的自动化价值又把最终风险控制权交给人。如果一定要让 Agent 直接执行写操作至少要做到命令白名单只允许pytest、npm test、go test、git diff等安全命令。禁止危险命令拒绝rm -rf、DROP TABLE、sudo、网络下载脚本后直接执行。操作日志记录每次工具调用的参数、工作目录、耗时和结果摘要。操作回滚代码改动必须可回滚环境销毁后必须能重建。4.4 成本与并发控制Agent 的成本不只是每次调用的 token 费用更重要的是“循环次数 × 每次工具返回”。一条超长的 pytest 输出会塞进下一轮请求导致 token 消耗非线性增长。控制成本可以从几个方向入手限制MAX_ITERATIONS防止模型陷入死循环。截断工具输出默认只保留最近 2000 到 5000 个字符。使用长期记忆或摘要避免历史消息无限膨胀。启用 Prompt Caching减少重复前缀的计费。限制并发 Agent 数量避免同一时间多个 Agent 同时写一个仓库。成本监控同样重要。建议每条任务记录模型名、输入 token、输出 token、迭代次数、耗时、是否成功。这样既能定位高成本任务也能评估 ROI。5. 实际接入时最容易踩的五个坑5.1 Agent 陷入循环反复执行同一条命令现象Agent 不断执行pytest或pip install每次结果相同但它仍然继续重复。原因模型没有看到新的信息却仍然选择再试一次。缺少循环上限和重复动作检测。解决方式设置MAX_ITERATIONS如果连续两次执行完全相同的命令直接终止并报告“该动作已重复执行需要人工介入”。5.2 修改文件后不重新读取基于旧代码继续操作现象Agent 写入文件后没有重新读取就继续生成新代码最终提交的内容和它自己的假设不一致。原因很多模型不知道文件写入是否成功也不知道写入后的完整内容。解决方式文件写入工具返回修改后的文件路径、文件长度和关键 diff 片段让模型基于实际内容继续。5.3 工具输出太长上下文爆炸现象Agent 跑完测试后把 10000 行日志全部塞给模型后续回答质量明显下降。原因上下文窗口被无意义日志占满关键错误信息被淹没。解决方式工具层截断输出。测试日志保留最后 50 到 100 行并格式化出错误摘要例如“失败用例 2 个test_login、test_pay”。5.4 本地可以部署到线上就失败现象Agent 在本地能完成任务换到 CI 或服务器后经常因为路径、环境变量、依赖版本不同而失败。原因开发环境与运行环境不一致。解决方式用容器固定环境镜像Agent 启动时输出系统信息、Python 版本和工作目录把 Agent 任务放进 CI 的同环境运行。5.5 公共评测集高分自建场景不达标现象模型在 SWE-bench 等基准上表现很好到自己仓库里却连最简单的需求都处理不稳定。原因公共评测分布和真实业务代码差异较大真实 Issue 往往包含大量隐式上下文。解决方式用自己仓库的已办 Issue 和对应 PR 构建回归集离线去除答案后定期跑持续观察趋势。6. 可复用清单和扩展方向6.1 接入前检查清单在正式评估 AI 编程 Agent 之前先确认这些问题模型是否支持 Function Calling 或 Tool Calling。沙箱是否隔离Agent 能否访问工作区之外的文件。是否配置了命令白名单是否可以拦截危险命令。是否设置了最大迭代次数和单条命令超时。工具输出是否有截断策略。是否记录每次工具调用的审计日志。是否配置了成本上限token 超限后能否停止任务。是否有失败回滚方案代码变更能否安全撤销。这条清单可以打印出来作为 Agent 上线前的强制检查项。6.2 发布前检查清单Agent 通过演示不等于可以发布。上线前还要确认Pull Request 是否必须经过人工 Review。Agent 是否能报告自己“无法完成”而不是静默失败。测试是否覆盖关键路径不只是看 Agent 是否结束了循环。生产环境是否有监控任务失败能否及时告警。操作是否可回滚日志是否完整保存。6.3 从单 Agent 到多 Agent 协作如果任务太复杂单个 Agent 往往既要做规划、又要写代码、又要验证容易上下文混乱。可以拆成两个角色规划 Agent只负责阅读 Issue、拆解任务、生成执行计划不执行代码。执行 Agent按计划逐步调用工具修改代码和运行测试。多 Agent 会带来消息传递、状态同步、成本翻倍等问题建议先单 Agent 跑通再考虑拆分。6.4 面向 Java 生态的扩展如果项目技术栈是 Java 和 Spring Boot可以关注 Spring AI。它提供了统一的 ChatClient 接口和 Function Calling 抽象适合把 Agent 能力嵌入现有业务服务。但要注意Spring AI 解决的只是接入层。沙箱、权限、审计、成本控制这些工程问题仍然需要自己设计。6.5 本地部署模型时的调整如果要求数据不出域可以选择本地部署模型。本地部署的推理成本更低、隐私控制更强但有两个额外问题要处理模型必须输出稳定的结构化 tool call。开源模型有时需要写专门的 prompt 模板或约束格式。上下文长度有限时工具输出必须压缩得更激进否则早期任务信息很快被挤掉。本地部署不是“换个模型地址”这么简单建议先在小模型上跑通最小骨架确认工具调用格式没问题再上真实任务。融资新闻会继续更新但 AI 编程 Agent 的工程问题不会因为估值变化而消失。沿着控制循环、工具调用、沙箱、权限、评测和成本这六条线去设计团队才能真正把演示变成可维护的生产能力。新手可以先运行最小 Agent 骨架理解消息循环和工具返回机制再逐步加入日志、权限和回归评测。这条路不长但每一步都需要用工程标准去验证。
返回列表