每日 AI 学习笔记|Day 6:Embedding 与相似度计算(面向测开)
Agent: 叮~您的【每日 AI 学习笔记】已送达!今天是 Day 6:Embedding(向量表示)与相似度计算(面向测开)。
Agent: 叮~您的【每日 AI 学习笔记】已送达!今天是 Day 6:Embedding(向量表示)与相似度计算(面向测开)。
致: 小AI (Eileen) - 资深测试开发工程师 核心领域: ArkClaw AI Agent 产品质量保障 / Ginkgo 后端自动化 / Playwright E2E 方案
今天的早报分两部分:
⚠️ 本文为补发内容。当前脚本会基于补发时可获取到的实时数据源生成内容,不保证完全还原该日期当天的 GitHub Trending / Feed 快照。
~/.codex/config.toml file.~/.gemini/settings.json file.以下片段用于说明思路(按你们的框架/路由替换即可):
package api_test
import (
"net/http"
"github.com/onsi/ginkgo/v2"
"github.com/onsi/gomega"
)
var _ = ginkgo.Describe("Tool API Contract", func() {
ginkgo.It("should return stable JSON schema for success", func() {
resp, err := http.Get("http://localhost:8080/api/tool/foo?x=1")
gomega.Expect(err).ToNot(gomega.HaveOccurred())
gomega.Expect(resp.StatusCode).To(gomega.Equal(http.StatusOK))
// TODO: 读取 body 做 JSON Schema 校验 / 字段断言
})
})
import { test, expect } from '@playwright/test';
test('chat streaming should be stable', async ({ page }) => {
await page.goto('https://your-console.example.com');
// TODO: 登录
await page.getByRole('textbox', { name: '输入' }).fill('解释一下这个项目的核心能力');
await page.getByRole('button', { name: '发送' }).click();
// 关键:对流式输出做“最终一致性”断言
await expect(page.getByTestId('assistant-message').last()).toContainText('核心');
});
ai_agent_quality/ 目录,沉淀:评测集、对话回放用例、golden snapshots。AI Builders Digest — 2026-04-15
⚠️ 本次 Follow Builders 的部分 feed 拉取失败(可能是网络原因)。以下为错误摘要:
- Could not fetch tweet feed
- Could not fetch blog feed
Generated through the Follow Builders skill: https://github.com/zarazhangrui/follow-builders
报告编纂者: 小AI 所属: 资深 AI 趋势研究与测试工程视角
今天的早报分两部分:
⚠️ 本文为补发内容。当前脚本会基于补发时可获取到的实时数据源生成内容,不保证完全还原该日期当天的 GitHub Trending / Feed 快照。
~/.codex/config.toml file.~/.gemini/settings.json file.以下片段用于说明思路(按你们的框架/路由替换即可):
package api_test
import (
"net/http"
"github.com/onsi/ginkgo/v2"
"github.com/onsi/gomega"
)
var _ = ginkgo.Describe("Tool API Contract", func() {
ginkgo.It("should return stable JSON schema for success", func() {
resp, err := http.Get("http://localhost:8080/api/tool/foo?x=1")
gomega.Expect(err).ToNot(gomega.HaveOccurred())
gomega.Expect(resp.StatusCode).To(gomega.Equal(http.StatusOK))
// TODO: 读取 body 做 JSON Schema 校验 / 字段断言
})
})
import { test, expect } from '@playwright/test';
test('chat streaming should be stable', async ({ page }) => {
await page.goto('https://your-console.example.com');
// TODO: 登录
await page.getByRole('textbox', { name: '输入' }).fill('解释一下这个项目的核心能力');
await page.getByRole('button', { name: '发送' }).click();
// 关键:对流式输出做“最终一致性”断言
await expect(page.getByTestId('assistant-message').last()).toContainText('核心');
});
ai_agent_quality/ 目录,沉淀:评测集、对话回放用例、golden snapshots。AI Builders Digest — 2026-04-14
⚠️ 本次 Follow Builders 的部分 feed 拉取失败(可能是网络原因)。以下为错误摘要:
- Could not fetch tweet feed
- Could not fetch blog feed
Generated through the Follow Builders skill: https://github.com/zarazhangrui/follow-builders
Agent: 今天推进到 Day 5:如何评测 Prompt 的稳定性?(已完成 Day 1~Day 4)。
学习计划来源:
AI_QA_Learning_Plan.md
进度判断:已完成 Day 1(LLM Basics)/ Day 2(Prompt Engineering)/ Day 3(ToT & ReAct),因此今天推进至 Day 4。
今日主题:让大模型“像接口一样”稳定输出:结构化输出约束(JSON Mode 与 Regex Constraint)
在传统软件里,最稳定、最可测的交互通常长这样:
但 LLM 天生输出自由文本,常见问题包括:
expected 变成 expectation,steps 变成 step_list"true"P3)所以对测开而言,结构化约束的意义是:
把 LLM 从“写作文”拉回“写接口响应”。
当输出可解析、可校验,你才能:
JSON Mode(不同平台叫法不同)通常指:
它解决的是:
但要注意:JSON Mode 通常只能保证“语法合法”,并不保证:
因此工程上常见组合是:
如果平台支持 Function Calling(工具调用) 或 JSON Schema 输出约束,它们的核心价值是:
对 QA 的启发是:
你可以把 LLM 的输出当作一个“外部依赖接口”,给它定义契约(Contract),然后像测接口一样测它。
常见测试点:
Regex Constraint 可以理解为:
适用场景举例:
TC-\d{4}^[A-Z_]+${ 开头、以 } 结尾(最小可行版本)Regex 的边界:
工程上推荐使用:
今天我们把目标定得非常具体:
让大模型输出标准 JSON 测试用例,并且像接口一样被自动化校验。
你可以把它直接落成三类资产:
prompts/:Prompt 模板(像代码一样版本化)schemas/:输出 Schema(合同)tests/:合同测试(contract tests),作为 CI 门禁实践目标:
- 让模型输出“只包含 JSON”
- 用 Pydantic 校验结构、枚举、长度
- 若失败:自动触发一次“修复回合”(可选)
# file: case_schema.py
from __future__ import annotations
from typing import Dict, List, Literal, Optional
from pydantic import BaseModel, Field
Priority = Literal["P0", "P1", "P2"]
Category = Literal["happy_path", "boundary", "negative", "auth", "idempotency", "concurrency"]
class APIInfo(BaseModel):
name: str = Field(..., min_length=1)
method: Literal["GET", "POST", "PUT", "DELETE"]
path: str = Field(..., pattern=r"^/.*")
class Request(BaseModel):
headers: Dict[str, str] = Field(default_factory=dict)
query: Dict[str, object] = Field(default_factory=dict)
body: Dict[str, object] = Field(default_factory=dict)
class Expected(BaseModel):
http_status: int = Field(..., ge=100, le=599)
body_contains: List[str] = Field(default_factory=list)
error_code: Optional[str] = Field(default=None, pattern=r"^[A-Z_]+$")
class TestCase(BaseModel):
id: str = Field(..., pattern=r"^TC-\d{4}$")
title: str = Field(..., min_length=4)
priority: Priority
category: Category
precondition: str = ""
steps: List[str] = Field(..., min_length=2, max_length=30)
request: Request
expected: Expected
class CaseGenOutput(BaseModel):
api: APIInfo
testcases: List[TestCase] = Field(..., min_length=6)
为什么先写 Schema(而不是先写 Prompt)?
你是一名资深测试开发工程师(Test Dev)。
【任务】
根据输入的 API 契约信息,生成接口测试用例。
【强制输出格式】
1) 你只能输出 JSON(纯 JSON 文本),禁止输出 Markdown、代码块标记、解释性文字。
2) JSON 顶层必须只有两个字段:api、testcases。
3) 每条用例必须包含字段:id、title、priority、category、precondition、steps、request、expected。
4) 字段约束:
- id 必须符合:TC-\d{4}
- priority 只能是:P0/P1/P2
- category 只能是:happy_path/boundary/negative/auth/idempotency/concurrency
- steps 必须是数组,元素是字符串
- expected.http_status 必须是 100~599
5) 用例必须覆盖:happy_path、boundary、negative、auth、idempotency。
【输入】
{{API_CONTRACT_JSON}}
这里已经混合使用了两类约束:
id 必须 TC-\d{4}现实里最常见的失败不是“完全乱写”,而是 JSON 语法合法,但字段缺失/类型不对,或枚举写错(P3)。
因此推荐:校验失败 → 让模型根据错误信息修复输出。
# file: generate_and_validate.py
import json
from case_schema import CaseGenOutput
from llm_client import call_llm_json
def validate_or_raise(output_str: str) -> CaseGenOutput:
data = json.loads(output_str)
return CaseGenOutput.model_validate(data)
def repair_prompt(bad_json: str, err: str) -> str:
return f"""你之前输出的 JSON 不符合合同,请你只修复 JSON 本身,不要输出任何解释性文字。
【校验错误】\n{err}
【待修复 JSON】\n{bad_json}
【输出要求】
- 只能输出修复后的 JSON(纯 JSON 文本)
- 必须保持顶层字段 api/testcases
"""
def generate_cases(api_contract_json: str, base_prompt: str, max_repair: int = 1) -> CaseGenOutput:
prompt = base_prompt.replace("{{API_CONTRACT_JSON}}", api_contract_json)
out = call_llm_json(prompt)
for _ in range(max_repair + 1):
try:
return validate_or_raise(out)
except Exception as e:
out = call_llm_json(repair_prompt(out, str(e)))
raise RuntimeError("unreachable")
QA 点评:为什么这是“工程化”的关键一步?
如果你们后端主要是 Go,建议至少做两层:
// file: casegen/contract_test.go
package casegen
import (
"encoding/json"
"os"
"testing"
)
type Output struct {
API struct {
Name string `json:"name"`
Method string `json:"method"`
Path string `json:"path"`
} `json:"api"`
Testcases []struct {
ID string `json:"id"`
Priority string `json:"priority"`
Category string `json:"category"`
Expected struct {
HTTPStatus int `json:"http_status"`
} `json:"expected"`
} `json:"testcases"`
}
func TestCaseGenContract(t *testing.T) {
b, _ := os.ReadFile("../snapshots/day4_casegen.json")
var out Output
json.Unmarshal(b, &out)
if len(out.Testcases) < 6 {
t.Fatalf("want >= 6 cases, got %d", len(out.Testcases))
}
// ... 补充自定义枚举与范围断言 ...
}
常见现象:模型输出 Here is the JSON: + JSON,或者用 ```json 包裹。
对策(从轻到重):
{ 到最后一个 }把 LLM 输出质量做成可观测指标:
json_parse_success_rate:JSON 解析成功率schema_valid_rate:Schema 校验成功率repair_needed_rate:需要修复回合的比例(越低越好)required_category_coverage_rate:必选类别覆盖率(明日预告 Day 5:如何评测 Prompt 的稳定性?构建一个 Python/Go 的批量 Prompt 自动化测试脚本,让“回归”真正跑起来。)
日期:2026-04-12(周日)
学习计划来源:learning-plan.md
进度判断:已完成 Day 2,今日推进至 Day 3。
定义:在 CoT(思维链)的基础上,ToT 允许模型在每一步推理时生成多个分支(候选项),并通过评估函数对这些分支进行打分或筛选,最终搜索出一条最优路径。
为什么需要 ToT?
QA 视角的启发: 在为 ArkClaw 设计跨组件的集成测试场景时,往往有多种数据准备或前置状态流转的路径。使用 ToT,可以让模型先列出所有可能的前置路径,再从中挑选一条执行成本最低或覆盖最全的路径来生成最终用例。
定义:ReAct 将大模型的**内部推理(Reasoning)与外部环境交互(Acting)**交替进行。
ReAct 的工程意义: 这是从“单向输出模型”向“自主智能体(Agent)”跨越的关键一步!它让大模型不再只依赖训练数据,而是可以动态获取实时信息来修正自己的判断。
测开/QA 的应用场景:
假设我们要测试 ArkClaw 的一个复杂特性:“只有当实例处于 Running 状态,且用户具备 admin 权限时,才能触发挂起(Suspend)操作”。
为了验证大模型在不同 Prompt 范式下的表现,我们设计一个极简的对比评测脚本。这个脚本会分别用 Zero-shot 和包含 CoT/ToT 思路的 Prompt 去请求 LLM,并校验输出的质量。
# file: evaluate_prompt_paradigms.py
import json
import pytest
from pydantic import BaseModel, Field
class TestScenario(BaseModel):
scenario_name: str
steps: list[str] = Field(..., min_items=3, description="至少需要包含创建、授权、操作三个步骤")
is_valid: bool = Field(True)
# 模拟评测函数(实际中你会调用大模型 API)
def generate_scenario(prompt_type: str) -> str:
# 这里 mock 了 LLM 的返回
if prompt_type == "zero_shot":
return json.dumps({
"scenario_name": "挂起实例",
"steps": ["调用 suspend 接口"],
"is_valid": False
})
elif prompt_type == "cot":
return json.dumps({
"scenario_name": "挂起实例全链路",
"steps": ["调用 create", "调用 start", "调用 suspend"], # 漏了授权
"is_valid": False
})
elif prompt_type == "tot_react":
return json.dumps({
"scenario_name": "严谨的挂起实例测试",
"steps": ["创建实例", "分配 admin 权限", "启动实例", "验证 running 状态", "执行挂起"],
"is_valid": True
})
return "{}"
@pytest.mark.parametrize("paradigm, expected_valid", [
("zero_shot", False),
("cot", False),
("tot_react", True)
])
def test_paradigm_effectiveness(paradigm, expected_valid):
output_str = generate_scenario(paradigm)
data = json.loads(output_str)
scenario = TestScenario(**data)
# 断言是否成功覆盖了前置的鉴权与状态依赖
has_auth = any("权限" in step or "auth" in step.lower() for step in scenario.steps)
assert scenario.is_valid == expected_valid
if expected_valid:
assert has_auth, "高级范式必须能推导出隐含的权限依赖步骤!"
QA 点评:在搭建企业级 AI 测试基建时,我们就是用这种对比框架,来挑选性价比最高(Token 消耗 vs 准确率)的 Prompt 范式作为生产环境的基线。
Action 集合?作为测开,如何对这些 Skill 进行独立的“契约测试”?(明日预告:结构化输出约束(JSON Mode 与 Regex Constraint),让大模型的输出像普通接口一样稳定!)
面向人群:资深测试开发工程师(AI Agent 产品质量保障 / 后端自动化测试 / Golang Ginkgo + Python Playwright)。
数据来源:使用内置技能
github-ai-qa-analyzer抓取 GitHub Trending(daily)并补全仓库信息,取 AI 相关 Top 6。
今天的 Trending AI 项目呈现出两个很“测开友好”的信号:
| # | 项目 | 归类 | 特色/核心优势(偏客观事实) | 对测试开发的直接启发(可落地) |
|---|---|---|---|---|
| 1 | NousResearch/hermes-agent | AI Agent / 编排框架 | 强调持久化自主 Agent,可在多平台(聊天工具/CLI 等)交互;支持切换模型、工具输出流、日志与配置校验等(见仓库 README/Docs 摘要) | 把 Agent 当“服务”测:Trace/Log/配置校验是可测性前置;端到端要覆盖跨渠道一致性、会话连续性、任务中断与恢复 |
| 2 | microsoft/markitdown | AI 工具(文档→Markdown)/ 可作为 Agent 工具链组件 | 支持多格式转 Markdown;提供 MCP server(让 LLM/Agent 通过标准协议调用转换能力);接口从“文件路径”升级到“file-like stream”(减少临时文件) | 为 RAG/评测集建设提供“输入标准化”组件;对转换结果做 golden + 回归;对 MCP 工具做 contract test(URI 协议、权限边界、异常码) |
| 3 | coleam00/Archon | AI Agent / 编排框架(流程 Harness) | 明确主张:用 YAML 把开发流程拆成阶段(Plan/Implement/Test/Review/PR),把 AI 放进可控节点;可组合确定性节点(bash/tests/git)+ AI 节点 | 把“验证门禁”写进流程:每次 Agent 改代码必须跑测试/静态检查;测开可以把自己的一套质量门禁沉淀成可复用 workflow |
| 4 | forrestchang/andrej-karpathy-skills | 规则/知识库(CLAUDE.md 指南) | 以一份 CLAUDE.md 约束 LLM 编码行为:显式假设、多种解释、简单优先、外科手术式改动、目标驱动并验证 | 把“LLM 写代码的质量要求”产品化:把测试作为 success criteria;把 review checklist 标准化,减少“不可测的变化” |
| 5 | multica-ai/multica | Managed Agents 平台 | 强调“Agents as Teammates”:任务队列、认领/执行/完成/失败生命周期;WebSocket 进度流;Skills 复用;本地 daemon + 云/自建 runtime | 测试重点从“单次对话正确”转向“任务运营正确”:状态机/事件流一致性、失败可恢复、权限隔离、审计日志 |
| 6 | shanraisshan/claude-code-best-practice | Agent 工程方法论/模板库 | 总结 Claude Code 的 Commands/Agents/Skills/Hooks 等工程化用法,强调“Research→Plan→Execute→Review→Ship”的收敛结构 | 对测开很像“测试策略模板库”:可以沉淀为团队内部的 Agent 工作流规范(含验证步骤/回归策略/产物格式) |
注:以上“特色/优势”来自脚本抓取的 description、README 摘要与公开文档片段;不做超出原文的功能承诺。
测开含义:
测开含义:
测开含义:
把这些写进 CLAUDE.md / Agent workflow,会直接提升可测性与可回归性。
从这些项目抽取出的共性做法:
落地建议(适配你当前技术栈):
把一个 Agent 系统拆成 5 层,测试策略就不会散:
用这套分层去看今天的项目:
评审一个 AI Agent/平台项目(或你们自研系统)时,建议直接问:
ai_agent_quality/
datasets/
eval_cases.jsonl # 问题-期望-断言规则
replays/
golden/ # 回放基线(依赖已固定)
latest/ # 本次构建回放
contracts/
tool_schemas/ # 工具入参/出参 JSON Schema
reports/
diff/ # 差分报告(golden vs latest)
围绕“任务生命周期”断言 UI:
如果你希望我把这份报告再进一步“贴近你们团队的现状”,你可以补充两点信息:
- 你们当前 Agent 产品形态(B 端控制台 / C 端聊天 / API 服务 / 混合)
- 你们目前最痛的质量问题(例如:幻觉、工具误用、RAG 引用不准、长链路不稳定、权限边界等) 我可以据此把第 3、4 节改成更具体的“你们项目下一周可以落地的任务拆分”。