Back to "使用协议缓冲支持 LLMApi: @ gRPC mock API"

This is a viewer only at the moment see the article on how this works.

To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk

This is a preview from the server running through my markdig pipeline

AI AI-Article API ASP.NET Core gRPC LLM mockllmapi Nuget Protobuf

使用协议缓冲支持 LLMApi: @ gRPC mock API

Thursday, 06 November 2025

一. 导言导言 导言 导言 导言

这是 GRPC Mock API 在 LLMApi. 中支持的文档

这是GitHub .的现场直播,

Nuget 元数 Nuget 元数

你可以找到 吉特Hub在这里 所有公共域等 ... *

gRPC 用协议缓冲支持模拟 API

LLMock API 现在提供全面的 gRPC 支持@, @ 允许您动态模拟 GRPC 服务, 不写入任何服务执行@ .}上传 .proto {,和模拟服务器可以处理其余的-}根据您的 Protobuf 信件定义产生符合现实的反应 .}

概览概览概览

GRPC的特征支持两种相辅相成的办法 :

  1. Json 胜过 HTTP 用于浏览器@-基测试和快速原型设计
  2. 《议定书》二进制缓冲 真正的GRPC客户进行类似测试

两种方法都使用相同的上传 .proto 和 LLM - 生成响应@, 给予您如何测试 @. 的灵活性

graph TD
    A[Upload .proto File] --> B[Proto Parser]
    B --> C[Service Definitions Stored]
    C --> D{Client Request Type?}
    D -->|JSON| E[JSON Endpoint]
    D -->|Binary Protobuf| F[Binary Endpoint]
    E --> G[LLM Generates Response]
    F --> G
    G --> H{Output Format?}
    H -->|JSON| I[Return JSON]
    H -->|Binary| J[Serialize to Protobuf]
    J --> K[Return Binary Response]

快速启动

1. 上传一个 Proto 文件

定义您的 GRPC 服务 .proto 备忘文件@: @%

syntax = "proto3";

package userservice;

service UserService {
  rpc GetUser (GetUserRequest) returns (User);
  rpc ListUsers (ListUsersRequest) returns (UserList);
  rpc CreateUser (CreateUserRequest) returns (User);
}

message GetUserRequest {
  int32 user_id = 1;
}

message ListUsersRequest {
  int32 page = 1;
  int32 page_size = 2;
  optional string filter = 3;
}

message CreateUserRequest {
  string name = 1;
  string email = 2;
  optional string phone = 3;
}

message User {
  int32 id = 1;
  string name = 2;
  string email = 3;
  optional string phone = 4;
  string created_at = 5;
  bool is_active = 6;
}

message UserList {
  repeated User users = 1;
  int32 total_count = 2;
  int32 page = 3;
}

上传此 proto 文件到模拟服务器@ :

# Upload via plain text body
curl -X POST http://localhost:5116/api/grpc-protos \
  -H "Content-Type: text/plain" \
  --data-binary "@user_service.proto"

# Or upload as multipart form
curl -X POST http://localhost:5116/api/grpc-protos \
  -F "file=@user_service.proto"

回复显示了您的服务结构@: @%

{
  "message": "Proto definition uploaded successfully",
  "name": "user_service.proto",
  "package": "userservice",
  "services": [
    {
      "name": "UserService",
      "methods": [
        {
          "name": "GetUser",
          "type": "Unary",
          "input": "GetUserRequest",
          "output": "User"
        },
        {
          "name": "ListUsers",
          "type": "Unary",
          "input": "ListUsersRequest",
          "output": "UserList"
        },
        {
          "name": "CreateUser",
          "type": "Unary",
          "input": "CreateUserRequest",
          "output": "User"
        }
      ]
    }
  ]
}

-=YTET -伊甸园字幕组=- 翻译:

快速测试和浏览器@-基客户端 @,使用 JSON 终点@MS K2

# Get a user (JSON request/response)
curl -X POST http://localhost:5116/api/grpc/UserService/GetUser \
  -H "Content-Type: application/json" \
  -d '{"user_id": 12345}'

LLM 产生符合您原型定义的现实响应@: @%

{
  "id": 12345,
  "name": "Sarah Chen",
  "email": "[email protected]",
  "phone": "+1-555-0142",
  "created_at": "2024-03-15T10:30:00Z",
  "is_active": true
}

3._呼叫方法 @-_Binary 协议缓冲

使用真正的 gRPC 线性协议进行类似测试@: @

# Create a binary Protobuf request (example using protoc)
echo '{"user_id": 12345}' | \
  protoc --encode=userservice.GetUserRequest user_service.proto > request.bin

# Send binary request, get binary response
curl -X POST http://localhost:5116/api/grpc/proto/UserService/GetUser \
  -H "Content-Type: application/grpc+proto" \
  --data-binary "@request.bin" \
  --output response.bin

# Decode binary response
protoc --decode=userservice.User user_service.proto < response.bin

产出=:

id: 12345
name: "Sarah Chen"
email: "[email protected]"
phone: "+1-555-0142"
created_at: "2024-03-15T10:30:00Z"
is_active: true

如何运作

Proto 文件分析

上传时 .proto MIME Server 解析此文件以提取 @:}

  • 服务定义
  • RPC 方法签名
  • 信件类型定义
  • 外地类型和数目
sequenceDiagram
    participant Client
    participant ProtoManager
    participant ProtoParser
    participant Storage

    Client->>ProtoManager: Upload user_service.proto
    ProtoManager->>ProtoParser: Parse(content)
    ProtoParser->>ProtoParser: Extract syntax/package
    ProtoParser->>ProtoParser: Parse services
    ProtoParser->>ProtoParser: Parse messages
    ProtoParser->>ProtoManager: Return ProtoDefinition
    ProtoManager->>Storage: Store in ConcurrentDictionary
    ProtoManager->>Client: Return success + metadata

解析器使用regex-基提取来识别原元素@:

// Service extraction
var serviceRegex = new Regex(
    @"service\s+([a-zA-Z0-9_]+)\s*\{([^}]+)\}",
    RegexOptions.Singleline);

// Method extraction
var methodRegex = new Regex(
    @"rpc\s+([a-zA-Z0-9_]+)\s*\(\s*(stream\s+)?([a-zA-Z0-9_.]+)\s*\)" +
    @"\s*returns\s*\(\s*(stream\s+)?([a-zA-Z0-9_.]+)\s*\)");

// Message extraction
var messageRegex = new Regex(
    @"message\s+([a-zA-Z0-9_]+)\s*\{([^}]+)\}",
    RegexOptions.Singleline);

处理流程请求

JSON 结束点

sequenceDiagram
    participant Client
    participant Endpoint
    participant GrpcHandler
    participant ProtoManager
    participant LLM

    Client->>Endpoint: POST /api/grpc/UserService/GetUser<br/>(JSON body)
    Endpoint->>ProtoManager: FindMethod(UserService, GetUser)
    ProtoManager->>Endpoint: Return method definition
    Endpoint->>GrpcHandler: HandleUnaryCall(service, method, json)
    GrpcHandler->>ProtoManager: GetMessage(User)
    ProtoManager->>GrpcHandler: Return message schema
    GrpcHandler->>GrpcHandler: Build LLM prompt with schema
    GrpcHandler->>LLM: Generate response for User message
    LLM->>GrpcHandler: Return JSON response
    GrpcHandler->>Endpoint: Extract and return JSON
    Endpoint->>Client: JSON response

操作器为 LLM: 建立详细提示

var prompt = $@"You are a gRPC service mock. Generate realistic data for this response.

Service: {serviceName}
Method: {methodName}
Request: {requestJson}

Generate a response matching this structure:
{jsonShape}

Return ONLY valid JSON matching the structure above. Be creative with realistic values.";

二进先质预库终点

sequenceDiagram
    participant Client
    participant Endpoint
    participant GrpcHandler
    participant ProtobufHandler
    participant LLM

    Client->>Endpoint: POST /api/grpc/proto/UserService/GetUser<br/>(Binary Protobuf)
    Endpoint->>GrpcHandler: HandleUnaryCallBinary(service, method, bytes)
    GrpcHandler->>ProtobufHandler: CreateJsonTemplate(inputMessage)
    ProtobufHandler->>GrpcHandler: Return JSON template
    GrpcHandler->>LLM: Generate response (same as JSON flow)
    LLM->>GrpcHandler: Return JSON response
    GrpcHandler->>ProtobufHandler: SerializeFromJson(json, outputMessage)
    ProtobufHandler->>ProtobufHandler: Write Protobuf binary format
    ProtobufHandler->>GrpcHandler: Return binary bytes
    GrpcHandler->>Endpoint: Return binary Protobuf
    Endpoint->>Client: Binary response (application/grpc+proto)

议定书缓冲序列化

缩略 DynamicProtobufHandler 使用字段定义将 JSON 转换为二进制 Protobuf 格式@: @%

public byte[] SerializeFromJson(
    string json,
    ProtoMessage messageDefinition,
    List<ProtoMessage> allMessages)
{
    var jsonDoc = JsonDocument.Parse(json);
    using var stream = new MemoryStream();
    using var writer = new CodedOutputStream(stream);

    // Write each field according to proto definition
    foreach (var field in messageDefinition.Fields.OrderBy(f => f.Number))
    {
        if (!jsonDoc.RootElement.TryGetProperty(field.Name, out var fieldValue))
            continue; // Skip missing fields

        WriteField(writer, field, fieldValue, allMessages);
    }

    writer.Flush();
    return stream.ToArray();
}

电线类型由字段类型确定:}

private WireFormat.WireType GetWireType(string fieldType)
{
    return fieldType switch
    {
        "string" or "bytes" => WireFormat.WireType.LengthDelimited,
        "int32" or "int64" or "uint32" or "uint64" or
        "sint32" or "sint64" or "bool" => WireFormat.WireType.Varint,
        "fixed32" or "sfixed32" or "float" => WireFormat.WireType.Fixed32,
        "fixed64" or "sfixed64" or "double" => WireFormat.WireType.Fixed64,
        _ => WireFormat.WireType.LengthDelimited // Complex/nested types
    };
}

AIPI管理

GRPC的特征包括全面管理API, 用于处理原型定义的工作。

列出全部方案

curl http://localhost:5116/api/grpc-protos

回应::

{
  "definitions": [
    {
      "name": "user_service.proto",
      "package": "userservice",
      "syntax": "proto3",
      "uploadedAt": "2025-01-05T20:30:00Z",
      "serviceCount": 1,
      "messageCount": 5,
      "services": ["UserService"]
    }
  ],
  "count": 1
}

获取 Proto 细节

curl http://localhost:5116/api/grpc-protos/user_service.proto

返回完整细节, 包括所有服务@, 方法 @ , message @ MPK2 和字段定义@ MS K3

删除原生体

curl -X DELETE http://localhost:5116/api/grpc-protos/user_service.proto

清除全部蛋列

curl -X DELETE http://localhost:5116/api/grpc-protos

API 端点参考

原方案管理终点

“ 方法”“ ”“终点”“ ”插图:“ ”
POST /api/grpc-protos 上传 proto file MS K2palin text 或多部分形式)
GET /api/grpc-protos @ 列出所有上传的原型定义@
GET /api/grpc-protos/{name} 获取一个特定方案的细节
DELETE /api/grpc-protos/{name} 删去一个特定的原型定义 @
DELETE /api/grpc-protos 清除所有原型定义 @

gRPC 服务呼叫终点

“ 方法”“ ”“终点”“ ”插图:“ ”
POST /api/grpc/{service}/{method} 以JSON请求的 /回应 MSC2
POST /api/grpc/proto/{service}/{method} 配有二进制预托布夫请求的 Invoke 方法@/}回应 @

高级先进示例

复杂内嵌密信件

syntax = "proto3";

package orderservice;

service OrderService {
  rpc CreateOrder (OrderRequest) returns (Order);
}

message OrderRequest {
  string customer_id = 1;
  repeated OrderItem items = 2;
  Address shipping_address = 3;
  PaymentInfo payment = 4;
}

message OrderItem {
  string product_id = 1;
  int32 quantity = 2;
  double unit_price = 3;
}

message Address {
  string street = 1;
  string city = 2;
  string state = 3;
  string postal_code = 4;
  string country = 5;
}

message PaymentInfo {
  string method = 1;
  string last_four_digits = 2;
}

message Order {
  string order_id = 1;
  string customer_id = 2;
  repeated OrderItem items = 3;
  Address shipping_address = 4;
  string status = 5;
  double total_amount = 6;
  string created_at = 7;
}

用嵌套的 JSON : 调用

curl -X POST http://localhost:5116/api/grpc/OrderService/CreateOrder \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "CUST-12345",
    "items": [
      {
        "product_id": "PROD-001",
        "quantity": 2,
        "unit_price": 29.99
      },
      {
        "product_id": "PROD-042",
        "quantity": 1,
        "unit_price": 149.99
      }
    ],
    "shipping_address": {
      "street": "123 Main Street",
      "city": "San Francisco",
      "state": "CA",
      "postal_code": "94102",
      "country": "USA"
    },
    "payment": {
      "method": "credit_card",
      "last_four_digits": "4242"
    }
  }'

LLM 生成一个符合现实的顺序反应, 所有嵌套田都聚集了 .

重复字段和阵列

原型解析器自动处理重复字段@: @%

message ProductList {
  repeated Product products = 1;
  int32 total_count = 2;
}

message Product {
  string id = 1;
  string name = 2;
  double price = 3;
  repeated string tags = 4;
}

用多个嵌套阵列响应 @ :

{
  "products": [
    {
      "id": "PROD-001",
      "name": "Wireless Mouse",
      "price": 29.99,
      "tags": ["electronics", "peripherals", "wireless"]
    },
    {
      "id": "PROD-002",
      "name": "Mechanical Keyboard",
      "price": 149.99,
      "tags": ["electronics", "peripherals", "gaming"]
    }
  ],
  "total_count": 47
}

配置配置

添加 gRPC 支持到您的 ASP.NET 核心应用程序@:

using mostlylucid.mockllmapi;

var builder = WebApplication.CreateBuilder(args);

// Add LLMock API services (includes gRPC)
builder.Services.AddLLMockApi(builder.Configuration);

var app = builder.Build();

// Map proto management endpoints
app.MapLLMockGrpcManagement("/api/grpc-protos");

// Map gRPC service call endpoints (both JSON and binary)
app.MapLLMockGrpc("/api/grpc");

app.Run();

缩略 AddLLMockApi() 方法自动注册@: @%

  • ProtoDefinitionManager - 管理器已上传原型定义
  • ProtoParser - Parses .proto 文件
  • DynamicProtobufHandler - 手持二进制预言序列化
  • GrpcRequestHandler GRPC 方法调用

现有限制

仅不状态调用

当前执行支持 仅使用未结 RPC 调用 @(_simple request@-_response\ ).}串流方法已解析但尚未实施

service DataService {
  // Supported
  rpc GetData (Request) returns (Response);

  // Not yet supported
  rpc StreamData (Request) returns (stream Response);
  rpc UploadData (stream Request) returns (Response);
  rpc BidirectionalStream (stream Request) returns (stream Response);
}

试图调用流方法返回错误@:

{
  "error": "Method StreamData is not a unary call. Type: ServerStreaming"
}

简化的Protobuf 剖析

二进制 Protobuf 实施简化@: @%

  • 请求解析: 目前使用 JSON 模板, 而不是解析实际的二进制Protobuf request 用于产生符合现实的反应, 但 <'t > 验证收到的双进制数据@.}

  • 应对措施的序列序号“:”正确将JSON按电线类型和字段号“.”与二进制Protobuf格式相联。

完整请求解析需要额外的复杂度才能处理变量 @ -}长编码@ MS K1} 嵌套信件 @ I, 和 proto3 默认=.}

Proto 文件格式支持

解析器支持共同的 proto @ 3 特性, 但有限制@ MS K1

已支持@ : @

  • 基本字段类型 @_string@,}( Int32,) int64, _#int 32,( VintMS K4) iint{64,}\ boll,} 浮點 , 双MSKO8 bytees @ MS K9}
  • 重复字段
  • 任择字段
  • 嵌套信件
  • 具有单元方法的服务

不支持@ : @

  • Enums {(}\ MSK_ parsed 但未经验证@)% 1}
  • 地图 @(}%s 尚未执行@)#
  • {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080})
  • 扩展名 @ ( @ non not plassed@ MS K1#
  • 选项和说明 @ ( @ ignored@ MS K1}%
  • 导入语句 @ (_ 尚未解析@ MS K1\ {

gRPC 服务器反射@ ( @ in process *)

标准GRPC客户期望服务器支持 gRPC 服务器反射协议.

当前状态:

  • 使用 protobuf-net.Reflection # (v3.2.52)#
  • Proto 文件被编译到 FileDescriptorSet 上传时
  • GrpcReflectionService 并管理编辑的描述词
  • 融入与融合 ProtoDefinitionManager 完整

什么工作 :

  • 动态原样编译@: @% 已上传 .proto 在运行时解析和汇编文件
  • 生成并缓存描述性存储@ : @ file DescriporSet 对象
  • 管理 API: GET /api/grpc-protos 列出所有已上传的包含全部细节的原始文件
  • 通过 HTTP /JSON全面服务发现和测试
  • Demo page:交互式UI 显示所有可用的服务和方法

什么是'? 进展中什么?

  • GRPC 标准反射端点映射grpc.reflection.v1alpha.ServerReflection 服务*)
  • 无需要求的完整 trkpcurl 整合 -proto 国旗

技术实施:

上传时 .proto 系统% :}文件@ MS K0 @ the system #

  1. 分析原质 使用基于 Regex@ - @% 的 regex ProtoParser Json/}HTTP 终点
  2. 供思考的汇编 使用 protobuf@ - @ net@ net @ MS K1 reflection_ 's FileDescriptorSet:
    var fileSet = new FileDescriptorSet { ImportPath = { "." } };
    fileSet.Add(protoName, true, new StringReader(protoContent));
    fileSet.Process(); // Compiles the .proto file
    
  3. 转换描述符 在rotobuf-net 和 GoogleMS K1Protobuff 兼容格式之间
  4. 两个代表处都存放在仓库 用于双Q-protocol 支持

目前的工作 :

# Provide proto file manually to grpcurl (always works)
grpcurl -proto yourfile.proto localhost:5116 list

# Use the JSON endpoint for testing (no grpcurl needed)
curl http://localhost:5116/api/grpc/UserService/GetUser \
  -H "Content-Type: application/json" \
  -d '{"user_id": 123}'

# Check available services via management API
curl http://localhost:5116/api/grpc-protos

# Use the interactive demo page at http://localhost:5116/Grpc

为何不完全完成@: @%

GRPC 反射协议要求@: @%

  • 绘制 ServerReflection RPC 处理反思查询的服务
  • 正确实施所有反射方法@(ListServices @,FileByFilename_,等#.)}
  • 与 ASP.NET GRPC核心服务器基础设施整合

该基金会已经到位 =-proto文件正在编译,并有描述性文件可供使用. 剩下的工作是绘制反射服务端点和确保与工具兼容性,例如用于服务发现的工具 grpcurl@.

测试战略

使用 JSON 测试浏览器

用于开发过程中的快速迭代@: @

// Fetch API in browser
async function getUser(userId) {
  const response = await fetch(`http://localhost:5116/api/grpc/UserService/GetUser`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ user_id: userId })
  });

  return await response.json();
}

const user = await getUser(12345);
console.log(user);

二进制融合测试

为了进行更符合实际的测试,

#!/bin/bash

# Generate binary request
echo '{"user_id": 12345}' | \
  protoc --encode=userservice.GetUserRequest user_service.proto > request.bin

# Call binary endpoint
curl -X POST http://localhost:5116/api/grpc/proto/UserService/GetUser \
  -H "Content-Type: application/grpc+proto" \
  --data-binary "@request.bin" \
  --output response.bin

# Decode and verify
protoc --decode=userservice.User user_service.proto < response.bin

# Clean up
rm request.bin response.bin

自动测试

示例 x单位测试@:

[Fact]
public async Task GrpcService_GetUser_ReturnsValidUser()
{
    // Arrange
    var protoContent = File.ReadAllText("user_service.proto");
    await _client.PostAsync("/api/grpc-protos",
        new StringContent(protoContent, Encoding.UTF8, "text/plain"));

    var request = new { user_id = 12345 };

    // Act
    var response = await _client.PostAsJsonAsync(
        "/api/grpc/UserService/GetUser", request);

    // Assert
    Assert.Equal(HttpStatusCode.OK, response.StatusCode);

    var user = await response.Content.ReadFromJsonAsync<JsonElement>();
    Assert.True(user.TryGetProperty("id", out _));
    Assert.True(user.TryGetProperty("name", out _));
    Assert.True(user.TryGetProperty("email", out _));
}

排除故障

原方案上传失败

症状上传 @ . proto 文件时出错

{
  "error": "No proto content provided"
}

解决方案:}确保您能正确发送 proto 文件内容\ :}

  • 作为纯文本@ : @ Content-Type: text/plain
  • 作为多部分表单@ : @% 1 Content-Type: multipart/form-data

未找到方法

症状:

{
  "error": "Method UserService/GetUser not found. Upload proto file first."
}

解决方案:

  1. 校验 proto 已上传@ : @ GET /api/grpc-protos
  2. 检查服务与方法名称完全匹配@(_case @-}QQQS灵敏度{)
  3. 确保方法类型为单词@ ( @ nonsing\ )

无效 JSON 对响应

症状:LLM返回错误的 JSON

模拟服务器试图将JSON从LLM 响应@,}但有时LLAM包括额外的文本或格式=.}

解决方案:

  • 重试请求@( @LULM 响应不尽相同 @)
  • 简化信件结构
  • 检查应用程序中 LLM 配置是否正确

二进制质布错误

症状\ :二进制端点返回错误或数据错误

解决方案:

  • 校验您的请求正确编码@'} protoc
  • 检查内容@- @Type 页眉是 application/grpc+proto
  • 确保原样文件与信件结构匹配

业绩考量

质子剖析

proto 文件在上传时解析一次, 并存储于内存@ . @ 以后的调用don '}\ t re @ MS K2parse:}

// Singleton storage
private readonly ConcurrentDictionary<string, ProtoDefinition> _definitions = new();

LLM 调用电话

每个 gRPC 方法调用都会触发高Q- 容量测试的 LLM 请求@. @% 1

  • 考虑对相同请求的等待答复
  • 使用上下文特征来保持一致性
  • 必要时调整LLM超时设置

二进序列化

与JSON.相比,

  • 杰森@ :_ 快速序列化@,_ 更容易调试
  • 二进二进更现实一点 小有效载荷 ,

未来增强能力

计划特点

  1. 服务器串流 -支持 returns (stream Response) 方法
  2. 客户流流量 -支持 (stream Request) returns 方法
  3. 双向双向串流 - 完整的双倍流
  4. gRPC 反射 -工具兼容性标准反射程序
  5. 请求验证 - 分析和验证收到的二进制方案请求
  6. 加强方案支持 -Enums,地图,OoneofsMS K3进口
  7. 反应缓存 - 用于确定性反应的可选缓存

捐款

找到一个错误或想要贡献@ ? @ check the GitHub 库以获取捐款指南\ MS K1}%

摘要摘要

GRPC 模拟API功能为测试GRPC服务提供了强有力的方法,而没有实施这些服务@.关键效益 @:

  • 上传 #.#proto 文件并立即获得工作模拟服务
  • 选择 JSON @ ( @ convennience@ MS K1 @ 或二进制方案 protobuf @ MPK2 @ realism_ MSC3}
  • LLM- 生成的响应符合您的邮件计划
  • 用于原型定义的全面管理 API
  • 与现有的 LLMock API 特性无缝结合

您是否正在做快速浏览器@ - @ basic 测试或建立综合整合测试套件 @ MS K2 双 JSON 和 二进制支持给予您工作的灵活性, 但是适合您的工作流程吗?

logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.