أنشئ وحدة تحكم TypeScript يقترح فيها OpenAI سير عمل مقيّداً للحوادث، ويراجع المشغّل سياق النموذج بدقة، ولا ينفّذ الخادم إلا خطة مخزنة تمت الموافقة عليها صراحةً.
ما الذي ستنشئه
ينشئ هذا الشرح تطبيقاً صغيراً باستخدام Next.js App Router لأتمتة سير العمل المعتمدة من البشر. يقدّم المشغّل تفاصيل الحادث ويختار ملاحظات دليل الإجراءات التي تصبح سياقاً للنموذج. يرسل مسار خادم هذا الكائن الصريح إلى OpenAI، ويحلّل JSON المُعاد، ويتحقق منه باستخدام Zod، ثم يخزن مقترحاً. لا يتم تنفيذ أي شيء عند توليد الخطة.
يقتصر المقترح عمداً على إجراءين: create_task، الذي يسجل مهمة محلية لأغراض هذا العرض، وsend_webhook، الذي يرسل حدثاً محدداً مسبقاً إلى وجهة HTTPS واحدة مهيأة. لا يستطيع النموذج ابتكار نوع إجراء آخر أو اختيار URL. لا يحتوي طلب الموافقة إلا على معرّف الخطة؛ ويعيد الخادم تحميل الخطة المخزنة والمعتمدة قبل تنفيذها.
تتضمن موارد المطورين الحالية من OpenAI إرشادات حول GPT-٥.٦ وResponses API وwebhooks وحالة المحادثة والبث والمعالجة في الخلفية وأنماط الوكلاء المتعددين. يبقى هذا المثال محدوداً عن قصد: إذ يستخدم عميل OpenAI JavaScript على الخادم للتخطيط، ويحافظ على سياسة الآثار الجانبية ضمن كود التطبيق. راجع الوثائق الرسمية قبل إضافة أي من هذه الإمكانات الأوسع.
المتطلبات المسبقة
- تثبيت حديث لإصدار Node.js LTS وnpm.
- مفتاح OpenAI API مخزن حصراً في متغير بيئة على الخادم.
- معرفة عملية بـ TypeScript وReact وNext.js Route Handlers.
- عنوان HTTPS webhook تتحكم به، إذا أردت اختبار تسليم الـ webhook.
الخطوة ١: إنشاء مشروع Next.js
أنشئ مشروع App Router وثبّت OpenAI SDK وZod. يُستخدم Zod لإجراء فحوصات وقت التشغيل، لأن أنواع TypeScript لا تتحقق من أجسام HTTP أو مخرجات النموذج في وقت التشغيل.
npx create-next-app@latest ai-workflow-console --typescript --eslint --app --src-dir --import-alias "@/*"
cd ai-workflow-console
npm install openai zod
mkdir -p src/lib src/app/api/plans src/app/api/plans/[id]/executeأنشئ .env.local. لا تكشف مفتاح API باستخدام بادئة NEXT_PUBLIC_، ولا تستورد OpenAI SDK إلى Client Component.
OPENAI_API_KEY=replace-with-your-server-side-key
OPENAI_MODEL=gpt-5.6
ALLOWED_WEBHOOK_HOSTS=hooks.example.com
WEBHOOK_URL=https://hooks.example.com/incident-events
WEBHOOK_SHARED_SECRET=replace-with-a-long-random-value
MAX_WORKFLOW_ACTIONS=3عنوان الـ webhook هو إعداد للتطبيق، وليس مخرجاً للنموذج. وتوفر قائمة السماح فحصاً ثانياً للتأكد من أن العنوان المهيأ يشير إلى مضيف متوقع.
الخطوة ٢: تعريف عقد سير العمل
أنشئ src/lib/workflow.ts. يحد مخطط الطلب من مدخلات المشغّل. ومخطط الإجراءات هو discriminated union، لذلك يجب أن يطابق كل إجراء شكلاً معتمداً واحداً. تُنشأ معرّفات الخطة والطوابع الزمنية والحالة بواسطة كود خادم موثوق، بدلاً من قبولها من النموذج.
import { z } from "zod";
const configuredMaxActions = Number(process.env.MAX_WORKFLOW_ACTIONS ?? "3");
const maxActions = Number.isInteger(configuredMaxActions) && configuredMaxActions > 0
? configuredMaxActions
: 3;
export const workflowRequestSchema = z.object({
incident: z.string().trim().min(20).max(4000),
service: z.string().trim().min(2).max(100),
urgency: z.enum(["low", "medium", "high", "critical"]),
selectedRunbookNotes: z.array(z.string().trim().min(1).max(800)).max(5),
});
export const workflowActionSchema = z.discriminatedUnion("type", [
z.object({
type: z.literal("create_task"),
title: z.string().trim().min(5).max(180),
description: z.string().trim().min(10).max(2000),
assigneeTeam: z.enum(["platform", "application", "security", "support"]),
}),
z.object({
type: z.literal("send_webhook"),
event: z.enum([
"incident.plan_approved",
"incident.escalation_requested",
"incident.status_update",
]),
message: z.string().trim().min(5).max(1000),
}),
]);
export const modelPlanSchema = z.object({
summary: z.string().trim().min(20).max(1200),
reasoning: z.string().trim().min(20).max(2000),
confidence: z.enum(["low", "medium", "high"]),
warnings: z.array(z.string().trim().min(1).max(300)).max(8),
actions: z.array(workflowActionSchema).min(1).max(maxActions),
});
export const workflowPlanSchema = modelPlanSchema.extend({
id: z.string().uuid(),
createdAt: z.string().datetime(),
status: z.enum(["proposed", "executing", "executed", "failed"]),
});
export type WorkflowAction = z.infer<typeof workflowActionSchema>;
export type WorkflowPlan = z.infer<typeof workflowPlanSchema>;
export function parseModelJson(content: string | null): unknown {
if (!content) throw new Error("The model returned an empty response.");
try {
return JSON.parse(content);
} catch {
throw new Error("The model did not return valid JSON.");
}
}
export function getWebhookUrl(): URL {
const rawUrl = process.env.WEBHOOK_URL;
if (!rawUrl) throw new Error("WEBHOOK_URL is required.");
const url = new URL(rawUrl);
if (url.protocol !== "https:") {
throw new Error("WEBHOOK_URL must use HTTPS.");
}
const allowedHosts = new Set(
(process.env.ALLOWED_WEBHOOK_HOSTS ?? "")
.split(",")
.map((value) => value.trim().toLowerCase())
.filter(Boolean),
);
if (!allowedHosts.has(url.hostname.toLowerCase())) {
throw new Error("WEBHOOK_URL hostname is not allowlisted.");
}
return url;
}المخطط هو حدّ الإنفاذ. يمكن للـ Prompt أن يطلب من النموذج توخي الحذر، لكن على الخادم رغم ذلك رفض الإجراءات غير المعروفة والقيم غير الصحيحة والحقول كبيرة الحجم. ويتجنب هذا المثال أيضاً حقل وجهة يتحكم به النموذج بالكامل.
الخطوة ٣: تخزين الخطط المقترحة محلياً
أنشئ src/lib/plan-store.ts. يجعل هذا التخزين داخل الذاكرة دورة الحياة قابلة للتشغيل في عملية تطوير محلية واحدة. وهو ليس تخزيناً دائماً ويجب استبداله قبل النشر الفعلي.
import type { WorkflowPlan } from "@/lib/workflow";
const plans = new Map<string, WorkflowPlan>();
export function savePlan(plan: WorkflowPlan): WorkflowPlan {
plans.set(plan.id, plan);
return plan;
}
export function findPlan(id: string): WorkflowPlan | undefined {
return plans.get(id);
}
export function updatePlan(
id: string,
update: (plan: WorkflowPlan) => WorkflowPlan,
): WorkflowPlan | undefined {
const existing = plans.get(id);
if (!existing) return undefined;
const next = update(existing);
plans.set(id, next);
return next;
}الخطوة ٤: توليد مقترح AI مقيّد
أنشئ src/app/api/plans/route.ts. ينشئ المسار visibleContext بصورة صريحة ويعيد الكائن نفسه إلى المتصفح. ويطلب من النموذج JSON، ثم يتحقق من JSON قبل تخزين خطة مقترحة. تُرفض مخرجات النموذج غير الصحيحة بدلاً من تنفيذها.
import { NextRequest } from "next/server";
import { OpenAI } from "openai";
import { ZodError } from "zod";
import { savePlan } from "@/lib/plan-store";
import {
modelPlanSchema,
parseModelJson,
workflowRequestSchema,
workflowPlanSchema,
} from "@/lib/workflow";export const runtime = "nodejs";const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });export async function...تابع القراءة
سجل دخولك مجاناً لقراءة المقال كاملاً والوصول إلى أدوات الذكاء الاصطناعي.
تسجيل الدخول / إنشاء حساب