大模型擅长生成文字,但文字对程序代码来说是个脆弱的边界。

让模型给一份手冲咖啡配方,每次返回的格式都可能不同:有时是Markdown列表,有时是编号列表,有时标题加粗,有时字段缺失,有时附带额外说明,有时末尾还加免责声明。聊天界面用用没问题,但你的应用需要保存结果、展示在UI上、路由工作流或传给其他系统时,"一段文字"就不够用了。你需要的是形状确定的数据。

打开网易新闻 查看精彩图片

原始大模型文本难以自动化的原因,不是看起来乱,而是应用必须猜测模型的意图。比如模型返回一段纯文本的咖啡配方,你的代码得从中提取:冲泡方法、咖啡粉量、水量、研磨度、水温、冲泡步骤。这意味着字符串解析,而字符串解析很容易崩溃。一次返回可能是"1. V60配方:用20克咖啡粉和320克水,水温94度,中细研磨",下次可能变成"### V60手冲 - 咖啡:20克 - 水:320克 - 温度:94度 - 研磨:中细"。人类读起来都懂,对软件却是两种格式。这就是原始大模型文本作为集成边界脆弱的原因。

打开网易新闻 查看精彩图片

在C#中定义输出形状,可以解决这个问题。不再要求模型返回自由格式文本,而是明确定义期望的结构:

public sealed class BrewRecipeSuggestion
{
public string BrewMethod { get; set; } = string.Empty;
public double CoffeeGrams { get; set; }
public double WaterGrams { get; set; }
public string GrindSize { get; set; } = string.Empty;
public double WaterTemperatureCelsius { get; set; }
public List Steps { get; set; } = [];
}

如果需要多个结果,可以包装在响应类型里:

打开网易新闻 查看精彩图片

public sealed class BrewRecipeResult
{
public List Recipes { get; set; } = [];
}

现在应用有了契约。模型不再只是"写个答案",而是被要求生成能映射到已知C#类型的数据。

.NET智能体框架让这件事变得干净。以前调用智能体接收纯文本:var response = await agent.RunAsync("给我三个手冲咖啡配方");现在可以请求类型化结果:AgentResponse response = await agent.RunAsync("给我三个手冲咖啡配方,包含:冲泡方法、咖啡粉克数、水克数、研磨度、摄氏水温、冲泡步骤");BrewRecipeResult result = response.Result。关键区别在于边界——应用接收的不是还需要解释的字符串,而是已经结构化的对象。