模拟
简单的 OpenAI 兼容 Mock API 服务器 。 可用于AI应用的确定性测试.
导言
为依赖LLM的AI应用程序创建集成测试可能由于成本,反应结构的复杂性和LLM的非定型性质而具有挑战性. Mock LLM作为响应用户消息的简单"echo"服务器运行.
服务器可以配置,以根据输入提供不同的响应,可用于测试出错场景,不同的有效载荷等. 它目前的目的是嘲笑 OpenAI 补全 API 但是可以被扩展为在未来模拟列表模型API,响应API,A2A apis等.
快速启动
安装和运行 :
npm install -g mock-llm
mock-llm
Mock-LLM运行于端口6556(即拨号-打纸码6556)上,以避免与 普通端口).
或用多克语:
docker run -p 6556:6556 ghcr.io/dwmkerr/mock-llm
或者说 使用赫尔姆 为库伯涅茨的部署.
用卷发测试. 接收请求的默认规则是用用户的精确消息回复:
curl -X POST http://localhost:6556/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4",
"messages": [{"role": "user", "content": "Hello"}]
}'
回应:
{
"id": "chatcmpl-1234567890",
"object": "chat.completion",
"model": "gpt-4",
"choices": [{
"message": {
"role": "assistant",
"content": "Hello"
},
"finish_reason": "stop"
}]
}
Mock LLM还拥有基本支持 A2A(代理)协议 用于测试代理消息、任务和同步操作.
配置
答复的配置使用a yaml 文件已装入 mock-llm.yaml 在当前工作目录中。 规则按顺序评估——最后一场比赛获胜.
默认配置与上次用户消息相呼应并提供一个 /v1/models 结束点 :
rules:
# Default echo rule
- path: "/v1/chat/completions"
method: "POST"
# The JMESPath expression '@' always matches.
match: "@"
response:
status: 200
content: |
{
"id": "chatcmpl-{{timestamp}}",
"object": "chat.completion",
"model": "{{jmes request body.model}}",
"choices": [{
"message": {
"role": "assistant",
"content": "{{jmes request body.messages[-1].content}}"
},
"finish_reason": "stop"
}]
}
# List models endpoint
- path: "/v1/models"
method: "GET"
response:
status: 200
content: |
{
"object": "list",
"data": [{"id": "gpt-5.2", "object": "model", "owned_by": "openai"}]
}
每个规则都支持这些字段:
path- 匹配请求路径的正则表达式method- 匹配的HTTP方法(GET、POST等)。 如果没有指定, 请匹配所有方法match- JMESPath 表达式,以匹配请求内容(可选)sequence- 按请求顺序匹配(可选)response- 对返回的反应(状况和内容)
自定义响应
耶稣会 是JSON的查询语言,用于匹配收到的请求并提取答复值.
此返回一个固定信件 hello 模拟 401 错误 error-401模拟 v1/models数字 :
rules:
# Fixed message when input contains 'hello':
- path: "/v1/chat/completions"
match: "contains(body.messages[-1].content, 'hello')"
response:
status: 200
content: |
{
"choices": [{
"message": {
"role": "assistant",
"content": "Hi there! How can I help you today?"
},
"finish_reason": "stop"
}]
}
# Realistic OpenAI 401 if the input contains `error-401`:
- path: "/v1/chat/completions"
match: "contains(body.messages[-1].content, 'error-401')"
response:
status: 401
content: |
{
"error": {
"message": "Incorrect API key provided.",
"type": "invalid_request_error",
"param": null,
"code": "invalid_api_key"
}
}
# List models endpoint
- path: "/v1/models"
# The JMESPath expression '@' always matches.
match: "@"
response:
status: 200
# Return a set of models.
content: |
{
"data": [
{"id": "gpt-4", "object": "model"},
{"id": "gpt-3.5-turbo", "object": "model"}
]
}
正在装入配置文件
这个 --config 参数可用于非默认位置 :
# Use the '--config' parameter directly...
mock-llm --config /tmp/myconfig.yaml
# ...mount a config file from the working directory for mock-llm in docker.
docker run -v $(pwd)/mock-llm.yaml:/app/mock-llm.yaml -p 6556:6556 ghcr.io/dwmkerr/mock-llm
更新配置
配置可以在运行时通过 /config 结束点 : GET 返回当前配置( JSON 默认, YAML 为) Accept: application/x-yaml, (中文(简体) ), POST 替换它, PATCH 合并更新, DELETE 重置为默认值 。 两者 POST 财务报告和审定财务报表 PATCH 接受 JSON (Content-Type: application/json)或YAML(Content-Type: application/x-yaml) (中文(简体) ).
健康和准备情况检查
curl http://localhost:6556/health
# {"status":"healthy"}
curl http://localhost:6556/ready
# {"status":"ready"}
模板变量
可在响应内容模板中找到 :
{{jmes request <query>}}- 使用 耶稣会数字 :request.body- 请求机构(例如,body.model, (中文(简体) ),body.messages[-1].content(中文(简体) )request.headers- HTTP头,小写(例如,headers.authorization(中文(简体) )request.method- HTTP方法(例如,POST(中文(简体) )request.path- 请求路径(例如,/v1/chat/completions(中文(简体) )request.query- 查询参数(例如,query.apikey(中文(简体) )
{{timestamp}}- 当前时间(以毫秒计)
对象和阵列自动为JSON-字符串. 原始物归原位.
"model": "{{jmes request body.model}}" // "gpt-4"
"message": {{jmes request body.messages[0]}} // {"role":"system","content":"..."}
"auth": "{{jmes request headers.authorization}}" // "Bearer sk-..."
"apikey": "{{jmes request query.apikey}}" // "test-123"
顺序答复
用于测试多回合交互, 如工具调用, 使用 sequence 根据请求顺序返回不同回复:
rules:
# First request: trigger tool call
- path: "/v1/chat/completions"
sequence: 0
response:
status: 200
content: '{"choices":[{"message":{"tool_calls":[{"function":{"name":"get_weather"}}]},"finish_reason":"tool_calls"}]}'
# Second request: return final answer
- path: "/v1/chat/completions"
sequence: 1
response:
status: 200
content: '{"choices":[{"message":{"content":"The weather is 72°F"},"finish_reason":"stop"}]}'
规则可以使用 match, (中文(简体) ), sequence两者或两者均:
match | sequence | 行为 |
|---|---|---|
| 没有 | 没有 | 匹配所有请求( 囊括全部) |
| 对 | 没有 | 仅基于内容的匹配 |
| 没有 | 对 | 仅基于顺序的匹配 |
| 对 | 对 | 必须满足两个条件 |
每个路径跟踪序列计数器,并通过 DELETE /config中标规则有 sequence 属性,所以倒置规则(不包含 sequence)可以处理活性探测器而无需消耗序列号.
流线配置
Mock-LLM 在客户端发送时支持流化响应 stream: true 在他们的要求。 流程行为在全球配置 :
streaming:
chunkSize: 50 # characters per chunk (default: 50)
chunkIntervalMs: 50 # milliseconds between chunks (default: 50)
rules:
- path: "/v1/chat/completions"
match: "@"
# etc...
当客户端请求流线时, Mock- LLM 返回服务器- Sent Events( SSE) 使用 Content-Type: text/event-stream数字 :
const stream = await client.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello' }],
stream: true // Enables streaming
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content || '');
}
这有助于确定对流协议的响应。 错误条件也可以测试 - 错误答复按 OpenAI 流线规格。 。 。 .
MCP(模式背景协议)
Mock-LLM 显示支持测试 MCP 协议的 MCP 服务器和工具,详情载于 MCP 文档。 。 。 .
MCP OAuth 模拟
Mock-LLM也可以在其MCP端点前模拟一款OAuth 2.1授权服务器,因此可以测试由OAuth保护的MCP服务器端到端而不依赖于真实的IDP. 它服务于 RFC 8414 / RFC 9728 发现, RFC 7591 动态客户端注册, 授权代码 + PKCE, 以及刷新-托肯流, 外加一组用于测试管弦的小型控制端点. 见 MCP OAuth 文档。 。 。 .
A2A(代理议定书代理人)
Mock-LLM 曝光支持测试 A2A 协议的 A2A 服务器和工具,详情见 A2A 文档。 。 。 .
与赫尔姆一起部署到库伯涅茨
# Install from OCI registry
helm install mock-llm oci://ghcr.io/dwmkerr/charts/mock-llm --version 0.1.8
# Install with Ark resources enabled
# Requires Ark to be installed: https://github.com/mckinsey/agents-at-scale-ark
helm install mock-llm oci://ghcr.io/dwmkerr/charts/mock-llm --version 0.1.8 \
--set ark.model.enabled=true \
--set ark.a2a.enabled=true \
--set ark.mcp.enabled=true
# Verify deployment
kubectl get deployment mock-llm
kubectl get service mock-llm
# Port forward and test
kubectl port-forward svc/mock-llm 6556:6556 &
curl -X POST http://localhost:6556/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4", "messages": [{"role": "user", "content": "Hello"}]}'
通过值自定义配置 。 雅姆尔:
# Optional additional mock-llm configuration.
config:
rules:
- path: "/v1/chat/completions"
match: "contains(messages[-1].content, 'hello')"
response:
status: 200
content: |
{
"choices": [{
"message": {
"role": "assistant",
"content": "Hi there!"
},
"finish_reason": "stop"
}]
}
# Or use existing ConfigMap (must contain key 'mock-llm.yaml')
# existingConfigMap: "my-custom-config"
见 完整赫尔姆文档 用于高级配置,方舟集成等.
实例
任何可兼容的OpenAI API SDK都可以被使用Mock LLM. 对于节点.js:
const OpenAI = require('openai');
const client = new OpenAI({
apiKey: 'mock-key',
baseURL: 'http://localhost:6556/v1'
});
const response = await client.chat.completions.create({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello' }]
});
console.log(response.choices[0].message.content);
// "Hello"
而为彼道:
from openai import OpenAI
client = OpenAI(
api_key='mock-key',
base_url='http://localhost:6556/v1'
)
response = client.chat.completions.create(
model='gpt-4',
messages=[{'role': 'user', 'content': 'Hello'}]
)
print(response.choices[0].message.content)
# "Hello"
开发者指南
安装依赖并开始活重载 :
npm install
npm run dev
林特或运行测试 :
npm run lint
npm run test
运行端到端 样本 套接字组 :
npm run test:samples
测试和检查本地运行的 MCP 服务器 :
npm run local:inspect
使用 Minikube 进行测试
docker build -t mock-llm:local .
minikube image load mock-llm:local
helm install mock-llm ./chart \
--set image.repository=mock-llm \
--set image.tag=local \
--set image.pullPolicy=Never
用于链锯试验(例如: 方舟:
minikube image load mock-llm:local
chainsaw test ./tests/my-test \
--values image.repository=mock-llm,image.tag=local,image.pullPolicy=Never
样本
下面的每一个样本都以一个极小的脚本形式出现,显示:
- 如何为特定情景配置模拟语言
- 如何运行情景
- 如何验证结果
这些可以作为你自己测试的参考. 每个样本也作为项目建设管道的一部分运行.
| 样本 | 说明 |
|---|---|
| 01 - echo - message.sh (英语) | 请求LLM回复. |
| 02-error-401.sh (英语) | 校验错误处理方案 . |
| 03-system-message-in-conversation.sh (原始内容存档于2017-03-30) | 在对话中测试系统处理消息. |
| 04头-验证.sh | 测试自定义的 HTTP 头验证 . |
| 05 - a2a - 倒计时 - agent.sh | 测试 A2A 屏蔽任务操作 . |
| 06-a2a-echo-agent.sh (英语) | 测试 A2A 信件处理 . |
| 07-a2a-message-context.sh (英语) | 测试 A2A 消息背景和历史 . |
| 08-mcp-echo-tool.sh (英语) | 测试 MCP 工具引用 . |
| 09-token-usage.sh (英语) | 测试符使用跟踪. |
| 10 mcp - 检查头.sh | 测试MCP头检查. |
| 11阶-工具调用.sh | 测试工具调用流量的相继响应. |
| 12-list-models.sh (英语) | 测试GET/v1/型号终点. |
| 14mcp-oauth -发现.sh | 测试 OAuth 401挑战 + RFC 9728 / RFC 8414 关于被保护的MCP端点的发现元数据. |
| 15-mcp-oauth-pkce-flow.sh (英语) | 测试完整 OAuth 2.1 授权码 + PKCE 流量(DCR,授权,令牌交换,认证的MCP初始化). |
| 16mcp -oauth - 新鲜。sh | 测试刷新式赠款,刷新式旋转,以及 /oauth/revoke + 键 /oauth/expire 控制端点. |
下面的每个样本都与现实世界的确定性整合测试有关 方舟 用于 mock-llm 特性。 这些测试可以作为您自己测试的参考.
| 测试 | 说明 |
|---|---|
| 代理- 默认模式 | 基本LLM查询和回复. |
| 模式-海关负责人 | 将自定义信头传递给模型. |
| 查询参数- ref | 来自 CifigMaps 和 secrets 的动态快速解析 . |
| 查询脚本用户 | 跟踪和报告使用量. |
| a2a-特工发现 | A2A特工发现和服务器准备. |
| a2a -- 信息查询 | A2A消息处理. |
| a2a-阻断-任务完成 | A2A 屏蔽任务成功完成 . |
| a2a 阻塞任务失败 | A2A 屏蔽任务处理出错 . |
| mcp - 发现 | MCP服务器和工具的发现. |
| mcp -- -- 头部 -- -- 传播(PR # 311) | MCP头从代理和查询传播. |
| 代理工具 | 工具调用代理的序列响应. |
贡献者
感谢(emoji 密钥:
戴夫·克尔 💻 📖 🚇 🚧 |
卢卡·罗马尼奥利 💻 |
丹尼尔 💻 |
马特·考格 💻 |
本项目遵循 全部贡献者 规格。 任何捐助都值得欢迎.