首页
/ screenshot-to-code 的 Agent 指令实践:Poetry 环境、测试校验与本地服务启动规范

screenshot-to-code 的 Agent 指令实践:Poetry 环境、测试校验与本地服务启动规范

2026-09-04 11:35:20作者:虞亚竹Luna

本文以截图转代码项目 screenshot-to-code 中的 CLAUDE.md(与 AGENTS.md 内容一致的 AI Agent 项目指令文档)为核心,逐条解读其定义的 Python 虚拟环境约定、后端测试与类型检查策略、前端 lint 规则、Prompt 代码风格约定,以及 Cursor Cloud 云环境下的依赖安装与服务启动方式。读完本文,你既能按文档完整跑通该项目的本地开发与验证闭环,也能理解每条指令背后对应的 pyproject.tomlpytest.ini 等真实配置,并把这套"给 Agent 写开发规约"的思路复用到自己的仓库中。

文档定位:CLAUDE.md 在仓库中是什么

CLAUDE.md 是一份面向 AI 编码助手(Claude Code 等 Agent)的"项目级操作手册",仓库根目录下的 AGENTS.md 与其内容完全一致,供不同 Agent 框架读取。它回答的不是"这个仓库做什么"(那是 README.md 的职责),而是三个更工程化的问题:

  1. 环境怎么用——Python 命令必须走哪个虚拟环境、依赖如何安装;
  2. 改动后如何验证——每次代码变更必须跑哪些测试、类型检查、lint,通过标准是什么;
  3. 哪些坑要绕开——端口、环境变量、工具链的隐含行为。

这种文档的价值在于:把原本只存在于维护者脑子里的隐性约定显性化,让 Agent(或新加入的开发者)无需试错即可正确操作仓库。下文按原文档章节顺序逐条展开,并给出每条指令在仓库源码中的落点。

Python 环境:一律使用 backend 的 Poetry 虚拟环境

原文档的 Python 环境约定是:

  • 所有 Python 命令必须使用 backend 的 Poetry 虚拟环境(backend-py3.10);
  • 首选调用方式为 cd backend && poetry run <command>
  • 若需要手动激活,用 cd backend && backend/poetry env activate(实际写法为 cd backend && poetry env activate)查看当前环境对应的虚拟环境路径,再执行它打印出的 source .../bin/activate 命令。

这三条规则背后的依据可以直接在仓库中核对:

  • 后端是一个非可打包的 Poetry 项目。backend/pyproject.toml 中声明 package-mode = false,依赖 Python 版本约束为 python = "^3.10",核心运行时依赖包括 fastapiuvicornwebsocketsopenaianthropicgoogle-genaiplaywright 等,开发依赖(dev group)则固定为 pytestpyrightpytest-asyncio 三个工具。
  • 由于依赖只安装在该虚拟环境里,poetry run 是保证命令与项目锁文件(backend/poetry.lock)所解析版本一致的最安全方式——它自动进入正确环境,避免了系统 Python 缺包或版本漂移。
  • poetry env activate 的作用是查询当前项目虚拟环境的激活命令。在 Cursor Cloud 这类非交互环境中,shell 不一定加载了 .bashrc,手动 source 一个记错的固定路径很容易失败,而通过 poetry env activate 让 Poetry 自己输出当前解析出的路径,是更健壮的做法。

这里有一个文档专门点出的"反直觉"细节,值得单独说明:

虚拟环境目录名虽然是 backend-...-py3.10,但实际解析到的 Python 是 3.12,而不是 3.10。因为 pyproject.toml^3.10 表示 >=3.10,<4.0,3.12 完全满足该约束。日常操作无需关心具体小版本,统一 poetry run 即可。

这条说明提醒我们:Poetry 的 caret 约束是"向后兼容到主版本"的语义,环境名中带的小版本号只是创建环境时的快照,不代表版本上限。

测试与类型检查策略:每次变更后的强制验证闭环

原文档的 Testing policy 给出了两条"每次代码变更后必须执行"的规则和一条通过标准:

# 变更后运行后端测试
cd backend && poetry run pytest

# 变更后运行类型检查
cd backend && poetry run pyright

通过标准(Type checking policy)是:被修改的文件中不允许出现新的 pyright 警告。也就是说,仓库允许存量警告存在,但禁止"带伤通过"——你动过的文件必须不引入新告警。

这条策略在仓库配置中有两处直接印证:

  • backend/pytest.ini 定义了测试发现规则与默认参数:testpaths = tests、文件模式 test_*.py、函数模式 test_*addopts = -v --tb=short(详细输出 + 短 traceback),并且 asyncio_mode = autopytest-asyncio 自动处理异步测试用例。因此 poetry run pytest 无需任何额外参数就能在 backend/tests/ 下发现全部 30 余个测试文件。
  • backend/pyrightconfig.json 将检查模式设为 basicreportMissingTypeStubs 降为 none(不强制第三方库类型桩),并排除 image_generation.py;这正是"存量告警可控、增量零告警"策略能够成立的前提——配置已经把噪声压到了合理水平。

backend/tests/ 的测试文件命名(如 test_agent_engine.pytest_openai_provider_session.pytest_asset_extraction.py)可以看出,测试覆盖 Agent 引擎、各模型 Provider 会话、资产抽取、评估系统等核心链路,这也解释了为什么文档把"改完必跑全量 pytest"定为硬性规则。

前端校验:pnpm lint 与基线告警的边界

原文档对前端只有一条命令:

cd frontend && pnpm lint

并补充了一句关键说明:如果改动同时涉及前后端,两套校验都要跑("If changes touch both, run both sets")。

结合 frontend/package.json 可以看到 lint 脚本的完整定义:

"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"

--max-warnings 0 意味着任何一条 lint 告警都会让命令以失败退出码结束。这也引出了原文档最后一条"非显然注意事项":当前 pnpm lint 会报出存量错误(例如 generateCode.ts 中的 @typescript-eslint/no-explicit-any),这些是基线问题(baseline issues),属于代码历史遗留,而不是环境装坏了。理解这条边界的意义在于:Agent 在云环境里跑 lint 失败时,应当把它归类为"已知基线",而不是反复重装依赖试图"修复环境"。

另外,frontend/package.json 通过 packageManager 字段锁定了 pnpm@10.32.1engines 要求 node >=14.18.0,依赖侧还包含 puppeteer(用于 QA 测试 test:qa 脚本)——这就解释了下一条注意事项中 pnpm install 提示忽略 esbuild/puppeteer 构建脚本的现象:该提示无害,Vite 的 dev/build 与 Jest 测试都不依赖这些 native 构建脚本。

Prompt 代码风格约定:多行提示词一律三引号

原文档的 Prompt formatting 一节规定:

  • 多行 prompt 文本优先使用三引号字符串("""...""");
  • 需要插值的多行 prompt,优先用单个三引号 f-string,而不是把字符串片段拼接起来。

这条约定针对的是后端提示词工程的典型痛点。本仓库的提示词构建集中在 backend/prompts/ 目录(pipeline.pysystem_prompt.pymessage_builder.py 以及 create/update/ 子模块),其中存在大量需要插入变量(用户请求、文件快照、设计系统等)的长文本模板。字符串拼接("a" + "b" + var + "c")在换行、缩进、引号转义上都极易出错,而单个三引号 f-string 保持了模板的整体性与可读性,也便于 Agent 在批量改写提示词时做结构化 diff。对维护者来说,这是一条低成本、高收益的风格护栏。

Hosted 分支:连接独立 SaaS 后端的发布形态

原文档用一节简短说明了 hosted 分支的存在:

hosted 版本位于 hosted 分支。该分支连接一个 SaaS 后端,位于另一个代码库 ../screenshot-to-code-saas

从源码结构看,这一说法有两处印证:

  • frontend/package.json 中除常规 dev/build 外,还定义了 dev-hostedvite --mode prod)与 build-hostedtsc && vite build --mode prod),即前端本身预留了托管模式的构建入口;
  • scripts/cursor-cloud-install.sh 末尾会检测同级目录 ../screenshot-to-code-saas 下的 backend/admin/ 是否存在,若存在则分别为其执行 poetry install --no-rootpnpm install

这说明 hosted 分支与自托管分支共享同一份前端代码,差异主要体现在后端连接目标与构建模式上。文档把这节放在 Agent 指令中,是为了防止 Agent 误改 hosted 相关逻辑时去错误的代码库里找实现。

Cursor Cloud 云环境:依赖自动刷新与安装脚本

原文档的 "Cursor Cloud specific instructions" 一节给出了云沙箱场景的完整操作约定:

  • 依赖在启动时自动刷新backend/poetry installfrontend/pnpm install),因此 Agent 无需手动安装依赖;
  • 环境初始化脚本为:
bash /agent/repos/screenshot-to-code/scripts/cursor-cloud-install.sh

对应仓库内的真实脚本是 scripts/cursor-cloud-install.sh,其执行逻辑值得完整过一遍:

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_ROOT"   # 先切到仓库根目录,保证与启动时的工作目录无关

curl -sSL https://install.python-poetry.org | python3 -   # 安装/更新 poetry
~/.local/bin/poetry -C backend install                      # 后端依赖
~/.local/bin/poetry -C backend run playwright install chromium || true  # Chromium(失败不阻断)
pnpm -C frontend install                                    # 前端依赖
# 若存在 ../screenshot-to-code-saas,则顺带安装其 backend 与 admin

脚本有三个可取的设计点,与文档中的注意事项一一对应:

  1. cd 到仓库根目录再安装,这正是文档所说"脚本会先切到仓库根目录,因此无论启动时工作目录在哪都能正常工作";
  2. poetry 使用全路径 ~/.local/bin/poetry 而非裸命令——因为 poetry 装在 ~/.local/bin,交互式 shell 通过 .bashrc 把它放进了 PATH,但非交互脚本(如云沙箱的执行器)不一定加载 .bashrc,裸 poetry 可能报 command not found;
  3. playwright install chromium || true 允许失败——Chromium 下载失败不阻断整体安装,因为截图预览只是可选能力。

本地服务启动:端口、WebSocket 与同源代码

文档指出服务的规范命令以 README.md 为准("see README.md for the canonical commands"),并给出了两条核心服务的启动方式:

# 后端(FastAPI + WebSocket),在 backend/ 下执行
poetry run uvicorn main:app --reload --port 7001

# 前端(Vite/React),在 frontend/ 下执行
pnpm dev   # 然后打开 http://localhost:5173

文档特别强调了三个容易踩坑的细节,均可在源码中找到对应实现:

1. Vite 只绑定 localhost,必须用 http://localhost:5173 访问。http://127.0.0.1:5173 会直接拒绝连接。这是 Vite dev server 的默认 host 行为,对 Agent 来说是一条高频卡点:自动化脚本里写 127.0.0.1 就能复现"服务明明在跑却连不上"的假故障。

2. 前端与后端走 WebSocket 通信,环境变量为 VITE_WS_BACKEND_URL 文档表述其默认值为 ws://127.0.0.1:7001,生成过程(generation)的流式输出经由该 WebSocket 推送,其余路由为普通 HTTP。从 frontend/src/config.ts 的实现可以看到更细的降级逻辑:

export const WS_BACKEND_URL =
  import.meta.env.VITE_WS_BACKEND_URL || SAME_ORIGIN_WS;

即未显式设置 VITE_WS_BACKEND_URL 时,前端会退回同源 WebSocket 地址(HTTP 协议头替换为 ws)。frontend/src/config.ts 中的注释解释了这一设计的动机:配合 Vite dev server 的代理,让应用在隧道/预览 URL 下也能工作——此时"localhost"指向的是查看者自己的机器而不是沙箱。因此在本地标准开发中按文档配置指向 ws://127.0.0.1:7001 即可,而在云端隧道场景下则依赖同源代码自动适配。docker-compose.yml 也再次提示:改后端端口时要同步修改 frontend/.env.local 中的 VITE_WS_BACKEND_URL

3. 后端端口 7001 有自动避让机制。 虽然文档给出的规范命令显式指定 --port 7001,但 backend/start.py 实现了更宽松的策略:从 --port(默认 7001)开始最多探测 --max-port-attempts(默认 20)个端口,遇到占用自动顺延并打印提示("Port 7001 is in use. Starting backend on port 7002.")。在云沙箱多实例并存时,这一机制能显著减少端口冲突导致的启动失败。

环境变量与 API Key:核心能力的启动前提

原文档的 Non-obvious caveats 中,API Key 一节信息密度最高,完整内容为:

  • 截图转代码这一核心功能至少需要一个 LLM KeyOPENAI_API_KEYANTHROPIC_API_KEYGEMINI_API_KEY 三选一;
  • 设置位置二选一:写入 backend/.env改完必须重启后端),或通过应用内 Settings 对话框填写;
  • 一个 Key 都没有时,生成会快速失败并提示 "No OpenAI, Anthropic, or Gemini API key";
  • REPLICATE_API_KEY(图像生成/编辑能力)只能通过 backend/.env 配置,UI 不支持

这条消息字符串在源码中可以直接定位:backend/routes/generate_code.py 中的 throw_error 提示与文档描述逐字对应,并额外给出了补救指引("If you add it to .env, make sure to restart the backend server")。从源码结构看,_get_variant_models 接收 openai_api_keyanthropic_api_keygemini_api_key 三个可选参数来装配变体模型,也就是说三个 Key 全部缺失才会触发该失败路径——这与"三选一即可"的文档表述一致。

对 Agent 的实际意义是:云沙箱首次跑生成任务前,应先确认 Key 来源(.env 还是 Settings),并记住 .env 路径不热加载这一约束,避免"改了 .env 却以为没生效"的误判。

其他环境注意事项的逐条印证

文档末尾还列了三条云环境专属的"非显然"注意事项,逐条说明如下:

  1. Playwright Chromium 已预装,供可选的 "Screenshot preview" 工具使用,Settings 页面中显示为 "Available"。这与 scripts/cursor-cloud-install.shplaywright install chromium 的安装步骤、pyproject.tomlplaywright = "^1.61.0" 的依赖声明相互印证;后端对应实现位于 backend/preview_screenshot/playwright_backend.py
  2. pnpm install 会打印 "Ignored build scripts (esbuild, puppeteer)" 警告,这是 pnpm 出于安全默认忽略依赖包安装脚本的行为,无害,Vite 构建、dev server 和 Jest 测试都不需要批准这些构建。
  3. poetry 在非交互 shell 中可能不在 PATH(前文已述),解决方案就是统一用 ~/.local/bin/poetry 全路径或 poetry run

结语:一份 Agent 指令文档应有的形态

CLAUDE.md 展示了 AI Agent 协作场景下项目文档的完整写法:

  • 环境约束(Poetry venv + poetry run)保证依赖一致性,并用源码级解释(^3.10 语义)消除命名带来的误导;
  • 验证闭环(pytest + pyright + pnpm lint 三条命令、"改动文件零新告警"的通过标准)让 Agent 可以自主判断改动是否合格,且通过标准与 pytest.inipyrightconfig.json 的实际配置严格对齐;
  • 风格约定(三引号 f-string)针对本仓库提示词工程的真实痛点;
  • 陷阱清单(Vite 只绑 localhost、WebSocket 环境变量、Key 不热加载、lint 基线告警、pnpm 构建脚本警告)把维护者的踩坑经验显性化,避免 Agent 在同样的坑上反复试错。

这套"命令可复制、标准可验证、陷阱有出处"的写法,可以作为为任何多端(前端 + 后端)项目编写 Agent 指令文档的参考模板。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
981
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384