测试

  |   0 评论   |   0 浏览

你将学会: 不打 API 的单元测试;断言「调了哪个工具」,不断言全文。
前置: L02。
本课不需要 API key。

模型每次用词都不同,测「回复是不是这 17 个字」会反复失败。测结构:有没有调用 get_weather、最后是不是 AIMessage

create_agentbind_tools。官方 GenericFakeChatModel 没实现它,必须自己覆盖。

完整代码

from collections.abc import Callable, Sequence
from typing import Any

from langchain.agents import create_agent
from langchain.messages import AIMessage, HumanMessage
from langchain.tools import BaseTool, tool
from langchain_core.language_models.fake_chat_models import GenericFakeChatModel
from langchain_core.messages.tool import ToolCall
from langchain_core.runnables import Runnable


class AgentFakeChatModel(GenericFakeChatModel):
    def bind_tools(
        self,
        tools: Sequence[dict[str, Any] | type | Callable[..., Any] | BaseTool],
        *,
        tool_choice: str | None = None,
        **kwargs: Any,
    ) -> Runnable:
        return self


@tool
def get_weather(city: str) -> str:
    """查询某城市天气。"""
    return f"{city}: sunny, 25C"


fake = AgentFakeChatModel(messages=iter([
    AIMessage(
        content="",
        tool_calls=[
            ToolCall(name="get_weather", args={"city": "Hangzhou"}, id="call_1")
        ],
    ),
    "杭州今天晴,25°C。",
]))
agent = create_agent(model=fake, tools=[get_weather])
result = agent.invoke({"messages": [HumanMessage(content="杭州天气?")]})

called = [
    tc["name"]
    for msg in result["messages"]
    if getattr(msg, "tool_calls", None)
    for tc in msg.tool_calls
]
assert "get_weather" in called, called
assert isinstance(result["messages"][-1], AIMessage)
print("通过 =>", called, [m.type for m in result["messages"]])

没有 key 也能绿。集成测试(真模型)默认不要放进每次保存都跑的套件,见仓库 Integration-testing集成测试.py

练习

  1. 把 fake 的第一次 tool_calls 改成错误名字 get_wether,确认 assert 会失败。
  2. 加一条确定性评测:规则分类 Toxic / Not toxic(仓库 LangSmith-evaluation评测.py 前半)。

本章验收

  •  能写带 bind_tools 的 fake 并断言工具名
  •  能说出为什么不要断言模型全文

阶段 2 过关: 用你自己的 3 段笔记做问答(L05),并留下一条不打 API 的测试(本课)。

下一课:多代理