为什么我在 Laravel AI SDK 之上构建了业务内容层

发布: (2026年3月14日 GMT+8 06:53)
9 分钟阅读
原文: Dev.to

Source: Dev.to

在业务应用中直接调用原始 LLM 的问题

下面是使用 laravel/ai 直接生成付款提醒的示例:

$ai = app(\Laravel\Ai\Contracts\Ai::class);

$response = $ai->text(
    "You are a professional business assistant. Generate a payment reminder 
     email for a client. The invoice number is #1042. It is 30 days overdue. 
     The amount is 1500 EUR. The client name is Jean Martin. 
     Our company is Acme Corp.

     Return a JSON object with: subject, message, call_to_action.
     Do not invent any information not provided above.
     Use a firm but professional tone.
     Language: French."
);

// Now parse the response...
// Hope it returned valid JSON...
// Hope it didn't invent an amount...
// Hope the tone is right...

它可以工作……但也会出问题。

为什么这种做法在生产环境中会失效

  • 硬编码上下文 – 提示中包含所有数据,缺乏可复用的结构。
  • 输出解析脆弱 – 模型有时会返回普通文本而不是 JSON。
  • 防止幻觉仅是建议 – 模型仍可能捏造数据。
  • 语气、语言、受众 – 必须为每一次调用手动指定。
  • 没有日志 – 你无法记录生成内容、时间或对应的租户。

所有这些都会在每个项目和每个功能中被重复重写。

我想要的效果

一个处理业务关注点的层,这样我只需要描述 什么 我想要的:

$response = BusinessAssistant::generate(new AssistantRequestData(
    task: AssistantTask::Email,
    preset: 'payment_reminder',
    goal: 'Invoice #1042, 30 days overdue, second reminder',
    language: 'fr',
    tone: Tone::Direct,
    context: [
        'company'  => true,
        'customer' => ['id' => 42],
        'billing'  => ['invoice_id' => 99],
    ],
));

echo $response->subject;        // "Rappel : Facture #1042 en attente de règlement"
echo $response->message;        // Full professional email body
echo $response->call_to_action; // "Procéder au règlement"

无需编写提示。无需解析输出。无需设置幻觉防护。

架构

引擎是一个 合同管道。每一步都是一个接口,因此您可以在不触及其他部分的情况下替换任意层。

AssistantRequestData


RequestValidator        — validates input fields


PresetRepository        — resolves the matching preset


ContextResolver         — calls your ContextProviders


ContextSanitizer        — strips sensitive keys, limits depth


PromptBuilder           — assembles system + user prompts


TextGenerator           — calls laravel/ai SDK


OutputNormalizer        — parses structured JSON response


GenerationLogger        — records to assistant_generations (best‑effort)


AssistantResponseData

关键设计决策: 引擎永远不知道您的数据模型 —— 它接收普通数组,您决定放入什么。

ContextProviders — 你的数据库与引擎之间的桥梁

与其在提示中硬编码数据,你可以编写简单的提供者类:

final class CustomerContextProvider implements ContextProvider
{
    public function key(): string
    {
        return 'customer';
    }

    public function provide(AssistantRequestData $request, array $input = []): array
    {
        $customer = Customer::find($input['id']);

        return [
            'name'  => $customer->full_name,
            'email' => $customer->email,
            'plan'  => $customer->plan,
            'since' => $customer->created_at->format('Y'),
        ];
    }
}

在配置文件中注册一次提供者;每次生成调用都会自动注入正确的数据。
引擎会对结果进行清理,剥离任何敏感键,确保在进入提示之前已被过滤。

防幻觉 — 结构化强制

在商业应用中,AI 最大的问题是模型 inventes 数据。
例子:一个付款提醒错误地捏造金额(€2,340 而不是实际的 €1,500)。

解决方案: 通过设计让幻觉不可能出现。如果上下文中不存在该数据,模型就无法使用它。三层机制强制实现:

  1. ContextSanitizer – 删除任何不应暴露的内容。
  2. 预设系统提示约束 – 限制模型可以输出的内容。
  3. OutputNormalizer 验证 – 确保最终的 JSON 符合预期的模式。

14 个预设 — 包含内容

PresetDescription
email专业商务邮件
reply情境化客户回复
payment_reminder逾期发票提醒
appointment_confirmation预约详情 + 确认
support_reply富有同理心的支持回复
follow_up会后跟进
reminder通用提醒
announcement公司/产品公告
promotion商业促销邮件
social_post可发布的社交媒体帖子
internal_note内部团队备忘录
summary文档或交互摘要
customer_onboarding欢迎/入职沟通
feedback_request请求客户反馈

(随着产品演进,欢迎随时添加更多预设。)

TL;DR

  • 将原始 laravel/ai 调用包装在 pipeline 中,以处理验证、预设解析、上下文注入、清理、提示构建、生成、规范化以及日志记录。
  • 使用 ContextProviders 以可复用、可测试的方式从数据库获取数据。
  • 通过绝不暴露未明确提供的数据来强制执行 anti‑hallucination
  • 为每种常见业务生成定义 presets,以保持提示的 DRY(不要重复自己)和可维护性。

有了这种结构,你就不必在每个项目中重复编写相同的脚手架,并能获得可靠、可审计的 AI 驱动助手,以满足所有业务逻辑生成需求。

概览

  • stomer_summary – 为客服提供的客户简报
  • rewrite – 文本改写

实际示例

SaaS 计费 – 第二次付款提醒

BusinessAssistant::generate(new AssistantRequestData(
    task: AssistantTask::Email,
    preset: 'payment_reminder',
    goal: 'Second reminder. Invoice INV-2024-0112, 30 days overdue.',
    tone: Tone::Direct,
    language: 'fr',
    context: [
        'company'  => true,
        'customer' => ['id' => 14],
        'billing'  => ['invoice_id' => 5501],
    ],
));

驾校 – 课程确认

BusinessAssistant::generate(new AssistantRequestData(
    task: AssistantTask::Email,
    preset: 'appointment_confirmation',
    goal: 'Confirm driving lesson. Remind student to bring permit.',
    tone: Tone::Friendly,
    language: 'fr',
    context: [
        'company'     => true,
        'customer'    => ['id' => 88],
        'appointment' => ['lesson_id' => 334],
    ],
));

CRM 支持 – 计费争议

BusinessAssistant::generate(new AssistantRequestData(
    task: AssistantTask::Reply,
    preset: 'support_reply',
    goal: 'Client was billed twice. Acknowledge, apologize, confirm investigation.',
    tone: Tone::Reassuring,
    language: 'en',
    context: [
        'company'   => true,
        'customer'  => ['id' => 42],
        'documents' => ['ticket_id' => 1091],
    ],
));

提供商灵活性

只需在 .env 中更改一次,即可切换提供商——无需修改代码:

# Anthropic Claude
BUSINESS_ASSISTANT_PROVIDER=anthropic
BUSINESS_ASSISTANT_MODEL=claude-haiku-4-5-20251001

# OpenAI
BUSINESS_ASSISTANT_PROVIDER=openai
BUSINESS_ASSISTANT_MODEL=gpt-4o-mini

# Local Ollama
BUSINESS_ASSISTANT_PROVIDER=ollama
BUSINESS_ASSISTANT_MODEL=qwen2.5:3b

多租户支持

内置于多租户 ERP 中,租户作用域为一等公民:

$request = new AssistantRequestData(
    task: AssistantTask::Email,
    goal: '...',
    userIdentifier:   (string) auth()->id(),
    tenantIdentifier: (string) $tenant->id,
);

每一次生成都会记录到 assistant_generations,并带有租户和用户标识——可用于配额跟踪和租户级别的报告。

在不调用 LLM 的情况下调试

预览完整提示而不进行 API 调用:

$prompt = BusinessAssistant::preview($request);

echo $prompt->systemPrompt; // full system instructions
echo $prompt->userPrompt;   // user prompt with injected context

安装

composer require fsdev/laravel-business-assistant
php artisan vendor:publish --tag=business-assistant-config
php artisan migrate
php artisan business-assistant:doctor
php artisan business-assistant:demo

对此保持诚实

  • 商业软件包(非 MIT)。
  • 终身发布 – Laravel 12,laravel/ai ~0.2.6。
  • 一次性购买,无法保证更新。
  • 不是 laravel/ai 或 Prism 的替代品——它位于其之上,处理它们刻意不涉及的业务层。

payhip.com/b/TkFob — €49 个人版 / €149 机构版

欢迎在评论中提出关于架构或预设系统的问题。

由 Fsdev 构建 — tematahotoa.tini@gmail.com

0 浏览
Back to Blog

相关文章

阅读更多 »