测试
你将学会: 不打 API 的单元测试;断言「调了哪个工具」,不断言全文。
前置: L02。
本课不需要 API key。
模型每次用词都不同,测「回复是不是这 17 个字」会反复失败。测结构:有没有调用 get_weather、最后是不是 AIMessage。
create_agent 会 bind_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。
练习
- 把 fake 的第一次
tool_calls改成错误名字get_wether,确认 assert 会失败。 - 加一条确定性评测:规则分类 Toxic / Not toxic(仓库
LangSmith-evaluation评测.py前半)。
本章验收
- 能写带
bind_tools的 fake 并断言工具名 - 能说出为什么不要断言模型全文
阶段 2 过关: 用你自己的 3 段笔记做问答(L05),并留下一条不打 API 的测试(本课)。
下一课:多代理
JavaWeb
Spring
MyBatis
linux
消息队列
JavaSE
工具
片段
AI
搜索
dy