screenshot-to-code 后端开发实战:Poetry 工具链、Pytest 测试与 Prompt 摘要调试
本文围绕 screenshot-to-code 仓库 backend/README.md 中给出的三条后端开发工作流展开:用 poetry run pyright 运行类型检查、用 poetry run pytest 运行测试,以及用 utils.py 里的 print_prompt_summary 快速可视化 LLM prompt。读完本文,你可以在本仓库的后端环境中完整跑起类型检查与测试套件,并能对发送给模型的 prompt 消息列表做摘要化检视,定位截图转代码流程中的提示词组装问题。
后端技术栈与环境基线
在动手之前,先明确这套开发工作流所依赖的环境。后端是 FastAPI 应用,包管理使用 Poetry,相关声明集中在 backend/pyproject.toml:
- Python 版本约束为
^3.10,核心依赖包括fastapi、uvicorn、openai、anthropic、google-genai、playwright等; - 开发依赖组中声明了
pytest = "^7.4.3"、pyright = "^1.1.352"、pytest-asyncio = "^0.21",这正是 README 中两条poetry run命令背后可调用的工具; - 项目声明
package-mode = false,即 Poetry 只负责依赖管理与虚拟环境,后端代码本身不作为可安装包分发。
应用入口在 backend/main.py:它先调用 load_dotenv() 加载环境变量,再创建 FastAPI 实例并挂载 generate_code、screenshot、evals 等路由。backend/config.py 则集中读取 OPENAI_API_KEY、ANTHROPIC_API_KEY、GEMINI_API_KEY、REPLICATE_API_KEY 等环境变量,并定义 IS_DEBUG_ENABLED、DEBUG_DIR 等调试开关——这些变量通常写入 backend/.env(仓库 README 的 Getting Started 章节有完整的环境变量配置示例)。
运行类型检查:poetry run pyright
backend/README.md 的第一条命令是:
poetry run pyright
它通过 Poetry 虚拟环境中安装的 pyright 对后端 Python 代码做静态类型检查。检查行为由 backend/pyrightconfig.json 控制,内容简短但信息量完整:
{
"exclude": ["image_generation.py"],
"typeCheckingMode": "basic",
"reportMissingTypeStubs": "none",
"reportUnknownVariableType": "warning"
}
逐项解读:
"typeCheckingMode": "basic":采用基础检查级别,只报告高置信度的类型错误,而不是 strict 模式下的全量诊断,适合以动效为主、快速迭代的应用型项目;"exclude": ["image_generation.py"]:显式排除该文件,从源码结构看它是较早引入的图像生成模块,被排除在类型检查之外;"reportMissingTypeStubs": "none":对第三方库缺少类型存根(stub)的情况不报错,避免moviepy、pillow-heif这类依赖的 stub 缺失干扰开发流;"reportUnknownVariableType": "warning":允许Unknown变量存在但给出警告,属于一种渐进式收紧类型质量的策略。
实际使用时,建议先完成 poetry install 并进入后端目录(或激活 Poetry 环境)再执行该命令;命令在 backend 目录下执行时,pyright 会自动读取同级的 pyrightconfig.json。
运行测试:poetry run pytest 与测试约定
README 的第二条命令是:
poetry run pytest
测试的执行规则定义在 backend/pytest.ini:
[pytest]
testpaths = tests
python_files = test_*.py
python_classes = Test*
python_functions = test_*
addopts = -v --tb=short
asyncio_mode = auto
这份配置约定了:
- 测试只从
backend/tests目录收集(testpaths = tests),该目录下有 40 余个测试文件,覆盖 agent 引擎(test_agent_engine.py)、各家模型 provider(test_anthropic_provider_config.py、test_gemini_provider_session.py、test_openai_provider_session.py)、工具运行时(test_agent_tool_runtime.py)、资产提取(test_asset_extraction.py)、评测系统(test_eval_runner.py、test_eval_sessions.py)等模块; addopts = -v --tb=short:默认以详细模式运行并输出精简的失败堆栈,无需每次手动传参;asyncio_mode = auto:配合pytest-asyncio,让async def test_*用例被自动识别为异步测试,无需逐个加@pytest.mark.asyncio标记。
例如针对 prompt 摘要功能的测试 backend/tests/test_prompt_summary.py 就是一个典型样例:它构造包含纯文本和 text/image_url 混合 content 的消息列表,断言 format_prompt_summary 的输出中包含 "SYSTEM: lorem ipsum" 与 "[2 images]",并捕获 stdout 验证 print_prompt_summary 输出的方框字符与标题。运行 poetry run pytest 时,这一整组用例都会按上述约定被收集并执行。
Prompt 摘要工具:print_prompt_summary 的用法与实现
backend/README.md 的核心内容是“Prompt Summary”一节:
Use
print_prompt_summaryfromutils.pyto quickly visualize prompts:
from utils import print_prompt_summary
print_prompt_summary(prompt_messages)
这个工具面向的场景很具体:screenshot-to-code 后端在生成代码前会把系统提示词、用户输入、截图(以 image_url 形式内嵌)等组装成 List[ChatCompletionMessageParam] 消息列表,列表往往很长且含大量 base64 数据,直接打印既冗长又看不清结构。print_prompt_summary 就是为此设计的“快速检视”入口。
其实现位于 backend/utils.py,核心逻辑分两层:
- 摘要格式化(format_prompt_summary):遍历每条消息,读取
role;若content是列表,则累加所有text块、统计image_url块的数量;若content是字符串则直接取用。默认truncate=True时,超过 40 个字符的文本会被截断为前 40 字符加省略号,图像则以+ [N images]后缀标注。 - 方框打印(
print_prompt_summary):根据各行长度计算框宽(截断模式下上限 80 列,完整模式下上限 120 列,下限 20 列),对超长行按词换行,最终输出带┌─…─┐边框、居中标题为PROMPT SUMMARY的等宽框体。
因此一段实际输出形如:
┌──────────────────────────────────────────────┐
│ PROMPT SUMMARY │
├──────────────────────────────────────────────┤
│ SYSTEM: You are an expert web developer... │
│ USER: Convert this screenshot to HTML + [1 │
│ images] │
└──────────────────────────────────────────────┘
utils.py 中还提供了与摘要互补的两个工具,调试 prompt 时可以按信息粒度选用:
pprint_prompt:深拷贝消息列表后经truncate_data_strings把每个长字符串截为 40 字符(附... (N chars)),再以indent=4打印 JSON,适合查看消息结构(但比摘要更原始);print_prompt_preview(配合 format_prompt_preview):按消息顺序编号输出,每条消息预览默认最多 280 字符,超出的部分保留“头部一半 + 尾部四分之一”并以... [collapsed N chars] ...标记,媒体内容统一标注为[N media],适合在不打印 base64 的前提下看清每条提示词的要点。
调试建议:在 llm.py 或各 provider 的调用点附近临时插入 print_prompt_summary(messages),确认角色顺序、文本截断位置与图像数量是否符合预期;若要核对完整提示词内容,改用 print_prompt_preview 或直接查看 PROMPT_REPORTS_ENABLED 开启后的 /evals/prompt-reports 报告(该开关的语义见 backend/config.py)。
小结
backend/README.md 虽然简短,但它定义了本仓库后端开发的三件基础武器:poetry run pyright(配合 backend/pyrightconfig.json 的 basic 模式做类型把关)、poetry run pytest(配合 backend/pytest.ini 的自动异步模式与统一收集规则跑全量测试),以及 backend/utils.py 中的 prompt 摘要工具链(print_prompt_summary / print_prompt_preview / pprint_prompt)。把这三者串起来,就构成了在 screenshot-to-code 后端中“改代码 → 查类型 → 跑测试 → 检视 prompt”的完整调试闭环。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00