用 Python 构建 LLM 功能:结构化输出、工具调用与评测 · 第 05 题

第 5 课:接到你自己的模型功能上

检查点 l0510 分自我报告——认领码来自 verify.py任一编码 Agent + 录制好的模型回放(无需 API Key)

把真实模型放到同一个接缝后面:一个 client 可调用对象、一份输出契约、一张白名单、一个兜底,以及录一次、每次改动都回放的评测。

在用 Agent 做题?一句话开始整门课程:

Read https://flypython.com/skills/flypython/SKILL.md and start the FlyPython course `llm-features-in-python`.

第 5 课:接到你自己的模型功能上

目标

你把这套模式——输出契约、带校验的解析、工具白名单、重试与兜底、诚实的 离线评测——用到你自己项目里的一个模型调用上,并记录评测给出的结果。

为什么有这节课

课程用手写回复,是为了在任何地方都能离线运行。你的功能连的是真实模型。 模式之所以能迁移,是因为代码自始至终只依赖一个东西:一个接收消息、返回 文本的可调用对象。

本课内容

  1. 把你的厂商调用包到接缝后面。 写一个函数 live(messages) -> str, 调用你所用厂商的 API 并返回回复文本。API key 从环境变量读取;绝不写进 代码,也绝不进录音。

  2. 先写契约。 确切的字段、类型、范围;工具及其参数类型;重试次数和 兜底。第 2 课练习里的草稿就是起点。

  3. 录一次,每次改动都回放。 包一层 live client,把每条回复都存下来; 用它把带标注的用例跑一遍,之后每次改动都从录音评测——不要 key、不花钱、 每次答案相同:

    import json
    from pathlib import Path
    
    
    class RecordingClient:
        """Wrap a live client and keep every reply so an eval can replay it."""
    
        def __init__(self, live):
            self.live = live
            self.replies = []
    
        def __call__(self, messages):
            text = self.live(messages)
            self.replies.append(text)
            return text
    
    
    def save_recordings(recorded: dict[str, list[str]], path: Path) -> None:
        path.write_text(
            json.dumps({"replies": recorded}, ensure_ascii=False, indent=2) + "\n",
            encoding="utf-8",
        )
    

    有意识地重新录制——改了提示词、换了模型或厂商时——并把新的评测输出和 旧的对比。

  4. 用评测做门禁。 在看结果之前定好阈值,让评测命令低于阈值时以非零 退出——和 ticket_triage.py 一样的形状。

  5. 记下它没证明什么。 写三行:已验证 / 未验证 / 已知局限。「未验证」 永远包括你没录到的真实流量。

如果你的功能不合身——输出是没有字段可校验的自由文本,或者用例太少没法 标注——写下模式在哪里失效了。这个判断本身就是本事的一部分。

练习

在录任何东西之前,先为你的功能标注至少十个真实或贴近真实的输入。标出 你预计会兜底的那些。

检查点

本检查点自我报告。能回答下面三题时,用 python verify.py --attest l05 认领:

  1. 你的 live client 返回什么?它的 key 从哪里来?
  2. 你的第一行评测输出是什么?它过了你事先定的阈值吗?
  3. 你的「未验证」清单上有什么是利益相关方会以为已覆盖的?

预期证据

你的输出契约、带标注的用例、第一行评测输出,以及三行记录。含客户数据的 录音不要放进公开仓库。

提示

卡住了?逐条打开。

提示 1 —— 本检查点考察什么

自我报告:你确认把这套模式用到了自己的一个模型调用上。证据是你的契约、你录下的用例和你的评测输出——不是我们查得了的码。

提示 2 —— client 就是接缝

本课程的一切只依赖 client(messages) -> str。真实的厂商调用能放进这个可调用对象后面;上次它说过的话的回放也能。

提示 3 —— 录音是数据

从真实流量录下的回复可能含有客户数据。进 git 之前像对待任何数据集一样审查它们。

提交

做完了?记录它。

提交 python verify.py 为本检查点打印的 8 位认领码。自报关卡要先完成课后问题,再运行 python verify.py --attest l05。

你浏览器

提交认领码

你的 Agent自动提交

让 Agent 解题并自动提交

把这题交给它(悬停出现复制按钮)——解题、验证、提交全程自动:

请完成 FlyPython 挑战课程「用 Python 构建 LLM 功能:结构化输出、工具调用与评测」(course id course-llm-features)的检查点 l05。
机读简报:https://flypython.com/api/challenges/llm-features-in-python
打开课程文件夹,先读 TASK.md——它就是契约。
规则:最小变更、不新增依赖、绝不修改 tests/ 或 solution/。
用 python verify.py 检查 starter/;自报关卡先让我回答课后问题,再运行 --attest ID 取得码。
目标:只做检查点 l05 这一道题,完成后立即提交。

用你Agent 页生成的令牌(环境变量 FLYPYTHON_TOKEN),它可以直接记录结果:

curl -X POST https://flypython.com/api/claims \
  -H "Authorization: Bearer $FLYPYTHON_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"claims":[{"course":"llm-features-in-python","checkpoint":"l05","code":"<8-char code>"}]}'

或一次性安装完整的 FlyPython Agent Skill,连粘贴都省了。

文件

starter 与验证器

解题在你的机器上运行——Agent 通过 /api/challenges/llm-features-in-python/files 自己取回课程文件,你无需手动下载。想直接读源码?在 GitHub 上查看文件夹 ↗