Back to "LLMApi: 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 LLM LLMApi mockllmapi Nuget

LLMApi: API 背景

Wednesday, 05 November 2025

Onte: THis 文章主要是作为我的金块软件包的一部分产生的人工智能, 作为发行文件的文档@.# It'}非常有趣 所以我把它放在这里 但是如果这是个问题 请忽略它 @.

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

当建立和测试应用程序“,”时,传统模拟API的最大挑战之一是其无国籍性质 .}每个请求都返回完全随机的数据,与先前的呼叫没有关系。 如果您用 ID #123,}来获取一个用户, 然后拿回他们的订单,}那里#'}这不能保证命令会引用同一个用户 IDQ._

AIPI 背景 给您的模拟API一个记忆来解决这个问题@. @%

Nuget 元数 Nuget 元数

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

问题: 无国籍混乱

传统模拟API为每项请求独立生成数据

sequenceDiagram
    participant Client
    participant MockAPI
    participant LLM

    Client->>MockAPI: GET /users/1
    MockAPI->>LLM: Generate user data
    LLM-->>MockAPI: {"id": 42, "name": "Alice"}
    MockAPI-->>Client: User data

    Client->>MockAPI: GET /orders?userId=42
    MockAPI->>LLM: Generate order data
    LLM-->>MockAPI: {"userId": 99, ...}
    MockAPI-->>Client: Order data (userId mismatch!)

注意问题@? @% 用户有 ID @ 42,} 但是命令是用 UnitedId MS K2\ 返回的

解答@:上下文内存

模拟的API在相关请求中保持了共同的背景*:

sequenceDiagram
    participant Client
    participant MockAPI
    participant Context as Context Manager
    participant LLM

    Client->>MockAPI: GET /users/1?context=session-1
    MockAPI->>Context: Get history for "session-1"
    Context-->>MockAPI: (empty - first call)
    MockAPI->>LLM: Generate user (no context)
    LLM-->>MockAPI: {"id": 42, "name": "Alice"}
    MockAPI->>Context: Store: GET /users/1 → {"id": 42, ...}
    MockAPI-->>Client: User data

    Client->>MockAPI: GET /orders?context=session-1
    MockAPI->>Context: Get history for "session-1"
    Context-->>MockAPI: Previous call: user with id=42, name=Alice
    MockAPI->>LLM: Generate order (with context history)
    LLM-->>MockAPI: {"userId": 42, "customerName": "Alice", ...}
    MockAPI->>Context: Store: GET /orders → {"userId": 42, ...}
    MockAPI-->>Client: Order data (consistent!)

现在LLM看到先前的用户呼叫并生成命令, 引用相同的用户编号和名称@.}数据形成一个一致的故事 .

如何运作

建筑结构架构

上下文系统由三个主要部分组成:

graph TD
    A[HTTP Request] --> B[ContextExtractor]
    B --> C{Context Name?}
    C -->|Yes| D[OpenApiContextManager]
    C -->|No| E[Generate without context]
    D --> F[Retrieve Context History]
    F --> G[PromptBuilder]
    E --> G
    G --> H[LLM]
    H --> I[Response]
    I --> J{Context Name?}
    J -->|Yes| K[Store in Context]
    J -->|No| L[Return Response]
    K --> L

1. 上下文Extrator “-”从请求中提取上下文名 2. OpenApicon Text 管理器 - 管理上下文存储和检索 3. 快速建筑 - 包括用 LLM 提示的上下文历史

内装储存

上下文被存储在 - memory 中, 使用线索@ MS K1 safe ConcurrentDictionary:

public class OpenApiContextManager
{
    private readonly ConcurrentDictionary<string, ApiContext> _contexts;
    private const int MaxRecentCalls = 15;
    private const int SummarizeThreshold = 20;

    public void AddToContext(
        string contextName,
        string method,
        string path,
        string? requestBody,
        string responseBody)
    {
        var context = _contexts.GetOrAdd(contextName, _ => new ApiContext
        {
            Name = contextName,
            CreatedAt = DateTimeOffset.UtcNow,
            RecentCalls = new List<RequestSummary>(),
            SharedData = new Dictionary<string, string>(),
            TotalCalls = 0
        });

        context.RecentCalls.Add(new RequestSummary
        {
            Timestamp = DateTimeOffset.UtcNow,
            Method = method,
            Path = path,
            RequestBody = requestBody,
            ResponseBody = responseBody
        });

        ExtractSharedData(context, responseBody);

        if (context.RecentCalls.Count > MaxRecentCalls)
        {
            SummarizeOldCalls(context);
        }
    }
}

自动自动汇总

为了防止环境无限增长和超过LLM象征性限制,当计数超过Q15:时,系统自动对旧电话进行汇总。

graph LR
    A[20+ Calls] --> B[Keep 15 Most Recent]
    A --> C[Summarize Older Calls]
    B --> D[Full Request/Response]
    C --> E[Summary: 'GET /users - called 5 times']
    D --> F[Included in LLM Prompt]
    E --> F
private void SummarizeOldCalls(ApiContext context)
{
    var toSummarize = context.RecentCalls
        .Take(context.RecentCalls.Count - MaxRecentCalls)
        .ToList();

    var summary = new StringBuilder();
    summary.AppendLine($"Earlier calls ({toSummarize.Count}):");

    var groupedByPath = toSummarize
        .GroupBy(c => $"{c.Method} {c.Path.Split('?')[0]}");

    foreach (var group in groupedByPath)
    {
        summary.AppendLine($"  {group.Key} - called {group.Count()} time(s)");
    }

    context.ContextSummary = summary.ToString();
    context.RecentCalls.RemoveRange(0, toSummarize.Count);
}

共享数据提取

上下文管理器自动从回复中提取通用标识符,以方便获取@: @%

private void ExtractSharedData(ApiContext context, string responseBody)
{
    using var doc = JsonDocument.Parse(responseBody);
    var root = doc.RootElement;

    if (root.ValueKind == JsonValueKind.Array && root.GetArrayLength() > 0)
    {
        var firstItem = root[0];
        ExtractValueIfExists(context, firstItem, "id", "lastId");
        ExtractValueIfExists(context, firstItem, "userId", "lastUserId");
        ExtractValueIfExists(context, firstItem, "name", "lastName");
        ExtractValueIfExists(context, firstItem, "email", "lastEmail");
    }
    else if (root.ValueKind == JsonValueKind.Object)
    {
        ExtractValueIfExists(context, root, "id", "lastId");
        ExtractValueIfExists(context, root, "userId", "lastUserId");
        ExtractValueIfExists(context, root, "name", "lastName");
        // ... more common patterns
    }
}

这样系统就可以跟踪最新的用户 ID\ , 命令 ID,Q 等 {.,} 在上下文历史中提供@.}

使用上下文

具体背景的三种方式

您可以以三种不同的方式通过上下文名@ , @ 使用此优先顺序@ MPK1} {

1. 查詢參數 最高优先级的)

GET /api/mock/users?context=my-session
GET /api/mock/users?api-context=my-session

2. HTTP 页眉

GET /api/mock/users
X-Api-Context: my-session

3. 求援机构

POST /api/mock/orders
Content-Type: application/json

{
  "context": "my-session",
  "shape": {"orderId": 0, "userId": 0}
}

支持的端点类型

二、背景情况在 全部 端点类型 @: @%

REST APPS

GET /api/mock/users/123?context=session-1

流通APPS

GET /api/mock/stream/stock-prices?context=trading-session
Accept: text/event-stream

图QL

POST /graphql?context=my-app
Content-Type: application/json

{
  "query": "{ users { id name } }"
}

信号@(_via 配置 @)

{
  "mostlylucid.mockllmapi": {
    "HubContexts": [
      {
        "Name": "stock-ticker",
        "Description": "Real-time stock prices",
        "ApiContextName": "stocks-session",
        "Shape": "{\"symbol\":\"string\",\"price\":0}"
      }
    ]
  }
}

世界使用案例

使用 case @ 1: E-商业流动

用一致的用户和订单数据模拟完整的购物经验@:

### 1. Create user
POST /api/mock/users?context=checkout-flow
{
  "shape": {
    "userId": 0,
    "name": "string",
    "email": "string",
    "address": {"street": "string", "city": "string"}
  }
}

### Response: {"userId": 42, "name": "Alice", ...}

### 2. Create cart (will reference same user)
POST /api/mock/cart?context=checkout-flow
{
  "shape": {
    "cartId": 0,
    "userId": 0,
    "items": [{"productId": 0, "quantity": 0}]
  }
}

### Response: {"cartId": 123, "userId": 42, ...}

### 3. Create order (consistent user and cart)
POST /api/mock/orders?context=checkout-flow
{
  "shape": {
    "orderId": 0,
    "userId": 0,
    "cartId": 0,
    "total": 0
  }
}

### Response: {"orderId": 789, "userId": 42, "cartId": 123, ...}

使用 case {2:} 股票价格模拟

产生现实的股票价格波动,而不是随机值@: @%

### First call - establishes baseline
GET /api/mock/stocks?context=market-data
    &shape={"symbol":"string","price":0,"volume":0}

### Response: {"symbol": "ACME", "price": 145.50, "volume": 10000}

### Second call - price changes realistically
GET /api/mock/stocks?context=market-data
    &shape={"symbol":"string","price":0,"volume":0}

### Response: {"symbol": "ACME", "price": 146.20, "volume": 12000}
### Notice: Same symbol, price increased by $0.70 (realistic)

### Third call - continues the trend
GET /api/mock/stocks?context=market-data
    &shape={"symbol":"string","price":0,"volume":0}

### Response: {"symbol": "ACME", "price": 145.80, "volume": 11500}
### Notice: Price fluctuates but stays in realistic range

如果没有上下文“,” ,每通电话都会返回一个完全随机的符号和价格$@.。

使用 case @ 3: 游戏状态进步

音轨播放器通过游戏会话进展@: @%

### Start game
POST /api/mock/game/start?context=game-session-123
{
  "shape": {
    "playerId": 0,
    "level": 0,
    "health": 0,
    "score": 0,
    "inventory": []
  }
}

### Response: {"playerId": 42, "level": 1, "health": 100, "score": 0}

### Complete quest
POST /api/mock/game/quest?context=game-session-123
{
  "shape": {
    "playerId": 0,
    "level": 0,
    "score": 0,
    "reward": {"item": "string", "value": 0}
  }
}

### Response: {"playerId": 42, "level": 2, "score": 500,
###           "reward": {"item": "Sword", "value": 100}}
### Notice: Same player, level increased, score increased

### Get stats
GET /api/mock/game/player?context=game-session-123
    &shape={"playerId":0,"level":0,"health":0,"score":0}

### Response: {"playerId": 42, "level": 2, "health": 100, "score": 500}
### Notice: Consistent with quest completion

API 内部管理

列出所有上下文

GET /api/openapi/contexts

### Response:
{
  "contexts": [
    {
      "name": "session-1",
      "totalCalls": 5,
      "recentCallCount": 5,
      "sharedDataCount": 3,
      "createdAt": "2025-01-15T10:00:00Z",
      "lastUsedAt": "2025-01-15T10:05:00Z",
      "hasSummary": false
    }
  ],
  "count": 1
}

获取上下文细节

GET /api/openapi/contexts/session-1

### Response shows full context including:
### - All recent calls with timestamps
### - Extracted shared data (IDs, names, emails)
### - Summary of older calls (if any)

清除特定上下文

DELETE /api/openapi/contexts/session-1

清除全部上下文

DELETE /api/openapi/contexts

实施细节

请求处理器整合

每个请求处理器“ (REST, 流体” “ MSSK2 图QL,信号RMS K4遵循相同的模式” “:”

public async Task<string> HandleRequestAsync(
    string method,
    string fullPathWithQuery,
    string? body,
    HttpRequest request,
    HttpContext context,
    CancellationToken cancellationToken = default)
{
    // 1. Extract context name from request
    var contextName = _contextExtractor.ExtractContextName(request, body);

    // 2. Get context history if context specified
    var contextHistory = !string.IsNullOrWhiteSpace(contextName)
        ? _contextManager.GetContextForPrompt(contextName)
        : null;

    // 3. Build prompt with context history
    var prompt = _promptBuilder.BuildPrompt(
        method, fullPathWithQuery, body, shapeInfo,
        streaming: false, contextHistory: contextHistory);

    // 4. Get response from LLM
    var response = await _llmClient.GetCompletionAsync(prompt, cancellationToken);

    // 5. Store in context if context name provided
    if (!string.IsNullOrWhiteSpace(contextName))
    {
        _contextManager.AddToContext(
            contextName, method, fullPathWithQuery, body, response);
    }

    return response;
}

LLM 提示语背景

当上下文存在时, 其历史包含在 LLM 提示\ :

TASK: Generate a varied mock API response.
RULES: Output ONLY valid JSON. No markdown, no comments.

API Context: session-1
Total calls in session: 3

Shared data to maintain consistency:
  lastId: 42
  lastName: Alice
  lastEmail: [email protected]

Recent API calls:
  [10:00:05] GET /users/42
    Response: {"id": 42, "name": "Alice", "email": "[email protected]"}
  [10:00:12] GET /orders?userId=42
    Response: {"orderId": 123, "userId": 42, "items": [...]}

Generate a response that maintains consistency with the above context.

Method: POST
Path: /shipping/123
Body: {"orderId": 123}

LLM 查看所有先前的呼叫并生成回复, 其中引用了相同IDs,}(姓名){,和其他数据{,保持一致性}MS K3

最佳做法

1. 使用描述性上下文名称

 Bad:  ?context=test1
 Good: ?context=user-checkout-flow-jan15

2. 完成时清晰的上下文

内存的上下文持续到明确清除或服务器重新启动@: @%

### After completing your test scenario
DELETE /api/openapi/contexts/user-checkout-flow-jan15

3. 相关端点的共享背景

所有相关调用均使用相同的上下文名称@: @%

GET /api/mock/users?context=demo-session
GET /api/mock/orders?context=demo-session
GET /api/mock/shipping?context=demo-session

4. 监视上下文大小

检查上下文细节以查看存储了多少个呼叫@: @%

GET /api/openapi/contexts/demo-session

如果您有许多电话, 请考虑清空并重新开始以避免快速的长度问题@ .

5. 与 OpenAPI 光谱合并

对于最大现实性来说, ,使用 OpenAPI speces 的上下文@ MS K1

### Load spec with context
POST /api/openapi/specs
{
  "name": "petstore",
  "source": "https://petstore3.swagger.io/api/v3/openapi.json",
  "basePath": "/petstore",
  "contextName": "petstore-session"
}

### All petstore endpoints will share the same context

业绩考量

内存使用

每个上下文仓库@: @%

  • 至@15}最近拨打的电话: @(#full request_)*
  • 更老的呼声摘要 @(_BARBAR_压缩#)}
  • 提取共享数据@(小字典 @)

每个上下文的典型内存kB 取决于响应大小

线索安全

OpenApiContextManager 用途 ConcurrentDictionary 对于线索“-” 安全存储“%.” ,多个请求可以安全地同时读取“MS K2”\write 上下文@.}

LLM 调制限制

上下文历史包含在每次提示@.}如果您有非常大的响应或很多调用,} 您可以使用象征性的限制@ .}自动总和有助于防止,}但对于很长的会话来说\MS K4}考虑定期清除上下文 *%.}

限制

  1. 仅使用 In- @ memory 服务器重新启动时丢失了 & - @ 上下文
  2. 无持久性 - 不适合生产数据存储
  3. 单个服务器 - 上下文@ MS K1}在多个服务器中同步 。
  4. LLM 依赖性 *- 一致性质量取决于LLM'是否有能力遵守指示

结论结论

API 背景将无国籍模拟API转换为有声无息的模拟性行动, 保持相关调用中的一致性@.}您是否测试了 e-}商业流 @,}* siming real- 时间数据 fedQ, 或构建游戏状态进化_,}背景确保您的模拟数据传递出一个连贯的故事 .}

共享数据的自动提取@,智能总结_,和所有端点类型的无缝整合使环境成为现实的API测试和发展的有力工具 @.

对于更高级的假想方案来说 , 将上下文与 OpenAPI 规格结合起来, 以创建完全@ MS K1 特效模拟 API 像真实事物一样的行为=.

logo

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