用AI写了一个命理应用

AI coding正在侵蚀每一个从事软件行业从业者,如果还在坚持古法编程的老登,AI抛弃你,真的连一声招呼都不会打,因为AI的生产力已经完全让人没有还手之力。

仅仅会写代码已经变得很难有竞争力,做UI,APP,运维,服务端,前端,产品这些以前都是一个产品团队不可或缺的岗位,但是现在AI真的可以让以上岗位减少很多。悲观点说,AI会减少很多岗位,但乐观说,会放大以前个人能力无法匹及的高度。

很久没有写技术文章,今天以一个AI应用从0到1,如果算总开发时长,从设计到开发,再到服务端,再到运维部署,应该差不多两天时间。因本身工作原因,断断续续,时间维度拉满两周。

此时好奇,做了一个什么应用,简单来说就是拍一张自拍照,然后根据面像分析你的,事业,财运,情感等信息。

需求来源

首先我看到的一个应用,引起了我的注意,我想制作一个跟他相关的内容,但不需要那么复杂的功能,因此我使用stitch,使用自然语言,就可以帮你输出比较精美的设计原型。

我给stitch的提示词是这样的根据http://cs.wmcweb.cn这个网站,我想设计一个面像分析的页面

很块它给我生成了这样的一个页面 设计功能上好像满足,但是我并不太满意,因此我继续让他给我修改

调色需要传统一些,并且设计Home页面,需要中英文多语言

界面已经OK了,也非常有设计感,内容也非常符合我想要的效果

代码生成

因为使用的是stitch,所以配合Antigravity官方出的编码IDE,内置gemin模型claude sonnet4.6模型,我只需要把stitch的链接复制到antigravity中就可以给我按照设计稿要求写代码了,不过你可以告诉它,你需要使用什么技术栈,比如vue或者是react,需求越是明确,生成的代码质量要求就越高,比我我使用的是vite+react+swr,同时我要求它帮我基于fetch与swr封装请求的hook,以及需要的全局组件,比如你的UI库使用的是shadcn ui

代码部分生成的比较快,基本不用自己修改,即使不满足,只需要在编辑器告诉如何修改就行

前端部分从设计到真正编码,整个页面还原,过去可能需要1-5天不等,现在只需要十几分钟就可以把设计稿精准还原,而且生成的代码质量也非常高。

看到这里,那句经典老梗,前端已死在此刻不是一句玩笑话。

后端部分

由于这个应用有登陆注册功能,所以需要一个后端服务来写用户接口。因此我选择一个更快,更熟悉的技术栈,因此后端使用的是hono框架,数据库使用的是prisma+supabase

AI生成的后端代码也非常强,你让生成的接口,基本从schema数据表字段,到接口路由设计,基本非常完善的给你生成,我们以登陆注册为例子

这是Hono启动路由服务的唯一入口

js 复制代码
// app.js
import './load-env.js'
import { serve } from '@hono/node-server'
import { getEnv } from './lib/env.js'
import { assertDatabaseConnection } from './lib/prisma.js'
import { app } from './app.js'

const { PORT } = getEnv()

void assertDatabaseConnection().catch((error) => {
  console.warn('[startup] database is unavailable; service will start without DB readiness')
  console.error(error)
})

serve(
  {
    fetch: app.fetch,
    port: PORT,
  },
  (info) => {
    console.log(`Listening on http://localhost:${info.port}`)
  },
)

app.js注册了各个路由

js 复制代码
import { Hono } from 'hono'
import { bodyLimit } from 'hono/body-limit'
import { cors } from 'hono/cors'
import { logger } from 'hono/logger'
import { secureHeaders } from 'hono/secure-headers'
import { getEnv } from './lib/env.js'
import { prisma } from './lib/prisma.js'
import { ApiErrorCode, fail, ok } from './lib/response.js'
import { auth } from './routes/auth/index.js'

const app = new Hono()

function normalizeCorsOrigin(o: string) {
  return o.trim().replace(/\/+$/, '')
}

const corsAllowed =
  getEnv()
    .CORS_ORIGINS?.split(',')
    .map((s) => normalizeCorsOrigin(s))
    .filter(Boolean) ?? []
// 浏览器规定:credentials 为 true 时不能用 Allow-Origin: *。无白名单时关闭 credentials,用 * 兼容未配 CORS_ORIGINS 的场景。
const corsCredentials = corsAllowed.length > 0

app.use(logger())
app.use(secureHeaders())
app.use(
  cors({
    origin: (origin) => {
      if (corsAllowed.length === 0) {
        return '*'
      }
      if (!origin) {
        return '*'
      }
      const reqOrigin = normalizeCorsOrigin(origin)
      return corsAllowed.includes(reqOrigin) ? origin : null
    },
    allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],
    allowHeaders: ['Authorization', 'Content-Type', 'Accept'],
    credentials: corsCredentials,
    maxAge: 600,
  }),
)

app.use(
  '/auth/*',
  bodyLimit({
    maxSize: 32 * 1024,
  }),
)

app.get('/health', (c) => c.json(ok({ status: 'ok' })))

app.get('/health/db', async (c) => {
  try {
    await prisma.$queryRaw`SELECT 1`
    return c.json(ok({ status: 'ok' }))
  } catch (error) {
    const message = error instanceof Error ? error.message : 'database unavailable'
    return c.json(fail(ApiErrorCode.INTERNAL_ERROR, message), 503)
  }
})

app.route('/auth', auth)

app.notFound((c) => c.json(fail(ApiErrorCode.NOT_FOUND, '资源不存在'), 404))

app.onError((err, c) => {
  console.error(err)
  return c.json(fail(ApiErrorCode.INTERNAL_ERROR, '服务器内部错误'), 500)
})

export { app }

在真正业务注册的路由接口

js 复制代码
import { OpenAPIHono } from '@hono/zod-openapi'
import { ApiErrorCode, fail } from '../../lib/response.js'
import type { AppEnv } from '../../types.js'
import { forgotPasswordHandler, forgotPasswordRoute } from './forgot-password.js'
import { inviteRecordsHandler, inviteRecordsRoute } from './invite-records.js'
import { loginHandler, loginRoute } from './login.js'
import { meHandler, meRoute } from './me.js'
import { registerHandler, registerRoute } from './register.js'
import { resetPasswordHandler, resetPasswordRoute } from './reset-password.js'

const authApp = new OpenAPIHono<AppEnv>({
  defaultHook: (result, c) => {
    if (!result.success) {
      const issue = result.error.issues[0]
      return c.json(fail(ApiErrorCode.VALIDATION_FAILED, issue?.message ?? '请求参数无效'), 400)
    }
  },
})



export const auth = authApp
  .openapi(registerRoute, registerHandler)
  .openapi(loginRoute, loginHandler)
  .openapi(forgotPasswordRoute, forgotPasswordHandler)
  .openapi(resetPasswordRoute, resetPasswordHandler)
  .openapi(meRoute, meHandler)
  .openapi(inviteRecordsRoute, inviteRecordsHandler)

在登陆接口,我们可以看到loginRoute

js 复制代码
import { createRoute, type RouteHandler } from '@hono/zod-openapi'
import { ApiErrorCode, fail, ok } from '../../lib/response.js'
import { getSupabaseAdmin } from '../../lib/supabase-admin.js'
import { prisma } from '../../lib/prisma.js'
import { ensureUserInviteCode } from '../../lib/invite-code.js'
import {
  isValidUsername,
  normalizeEmail,
  normalizeUsername,
} from '../../lib/username.js'
import type { AppEnv } from '../../types.js'
import {
  bindInviteCodeForUser,
  InviteCodeAlreadyUsedError,
  INVITE_REWARD_POINTS,
  SelfInviteCodeError,
} from './invite-service.js'
import { InvalidInviteCodeError } from './register-service.js'
import { failureEnvelopeSchema, loginRequestSchema, loginResponseSchema } from './schemas.js'

export const loginRoute = createRoute({
  method: 'post',
  path: '/login',
  tags: ['认证'],
  summary: '登录',
  request: {
    body: {
      content: { 'application/json': { schema: loginRequestSchema } },
      required: true,
    },
  },
  responses: {
    200: {
      description: '登录成功',
      content: { 'application/json': { schema: loginResponseSchema } },
    },
    400: {
      description: '邀请码无效、已使用或填写了自己的邀请码',
      content: { 'application/json': { schema: failureEnvelopeSchema } },
    },
    401: {
      description: '凭证无效或密码错误',
      content: { 'application/json': { schema: failureEnvelopeSchema } },
    },
  },
})

export const loginHandler: RouteHandler<typeof loginRoute, AppEnv> = async (c) => {
  const { identifier: rawId, password, inviteCode: pendingInviteCode } = c.req.valid('json')
  const trimmed = rawId.trim()

  let email: string | null = null
  if (trimmed.includes('@')) {
    email = normalizeEmail(trimmed)
  } else {
    const username = normalizeUsername(trimmed)
    if (!isValidUsername(username)) {
      return c.json(fail(ApiErrorCode.INVALID_CREDENTIALS, '凭证无效'), 401)
    }
    const profile = await prisma.userProfile.findUnique({ where: { username } })
    email = profile?.email ?? null
  }

  if (!email) {
    return c.json(fail(ApiErrorCode.INVALID_CREDENTIALS, '邮箱或密码错误'), 401)
  }

  const supabase = getSupabaseAdmin()
  const { data, error } = await supabase.auth.signInWithPassword({ email, password })

  if (error || !data.session || !data.user) {
    return c.json(fail(ApiErrorCode.INVALID_CREDENTIALS, '邮箱或密码错误'), 401)
  }

  let profile = await prisma.userProfile.findUnique({ where: { id: data.user.id } })

  if (pendingInviteCode && profile) {
    try {
      const bindResult = await bindInviteCodeForUser(
        { inviteeId: profile.id, inviteCode: pendingInviteCode },
        {
          getInviteeProfile: async (inviteeId) =>
            prisma.userProfile.findUnique({
              where: { id: inviteeId },
              select: { id: true, invitedById: true },
            }),
          findInviterByCode: async (inviteCode) =>
            prisma.userProfile.findUnique({
              where: { inviteCode },
              select: { id: true },
            }),
          applyInviteBinding: async ({ inviteeId, inviterId }) => {
            await prisma.$transaction(async (tx) => {
              await tx.userProfile.update({
                where: { id: inviteeId },
                data: {
                  invitedById: inviterId,
                  points: { increment: INVITE_REWARD_POINTS },
                },
              })

              await tx.userProfile.update({
                where: { id: inviterId },
                data: { points: { increment: INVITE_REWARD_POINTS } },
              })

              await tx.inviteRecord.create({
                data: {
                  inviterId,
                  inviteeId,
                  inviterRewardPoints: INVITE_REWARD_POINTS,
                  inviteeRewardPoints: INVITE_REWARD_POINTS,
                },
              })
            })
          },
        },
      )

      if (bindResult.applied) {
        profile = await prisma.userProfile.findUnique({ where: { id: data.user.id } })
      }
    } catch (error) {
      if (error instanceof InvalidInviteCodeError) {
        return c.json(fail(ApiErrorCode.VALIDATION_FAILED, '邀请码无效'), 400)
      }
      if (error instanceof SelfInviteCodeError) {
        return c.json(fail(ApiErrorCode.SELF_INVITE_CODE, '不能填写自己的邀请码'), 400)
      }
      if (error instanceof InviteCodeAlreadyUsedError) {
        return c.json(fail(ApiErrorCode.INVITE_CODE_ALREADY_USED, '当前账号已绑定过邀请码'), 400)
      }
      throw error
    }
  }

  const inviteCode = profile ? await ensureUserInviteCode(profile.id) : null

  return c.json(
    ok(
      {
        user: {
          id: data.user.id,
          email: data.user.email ?? profile?.email ?? email,
          username: profile?.username ?? null,
          points: profile?.points ?? 0,
          inviteCode,
        },
        session: {
          access_token: data.session.access_token,
          refresh_token: data.session.refresh_token,
          expires_in: data.session.expires_in,
          expires_at: data.session.expires_at,
          token_type: data.session.token_type,
        },
      },
      '登录成功',
    ),
    200,
  )
}

以上代码真的很长,很难相信在没有AI之前,这些代码是古法编程的味道,手打每一行代码都显得尤为稀缺与珍贵,而如今,AI生成以上代码,只需1-2分钟即可,你只需要验证接口是否满足你的功能即可。

如果你写好了后端接口,此时前端与联调这些接口,那么如何对接接口呢

你只需要在前端项目里告诉AI,根据后端生成的api路由,帮我对接后端的API接口就行

简单来看下对接接口业务,这是登陆界面

jsx 复制代码
import React, { useState } from 'react';
import toast from 'react-hot-toast';
import { Lock, User } from 'lucide-react';
import { useLanguage } from '../../contexts/LanguageContext';
import { useForgotPasswordApi } from '../../services';

interface LoginViewProps {
    handleLogin: (body: any) => Promise<any>;
    loading: boolean;
    setView: (view: 'login' | 'register') => void;
}

export const LoginView: React.FC<LoginViewProps> = ({ handleLogin, loading, setView }) => {
    const { t } = useLanguage();
    const [identifier, setIdentifier] = useState('');
    const [password, setPassword] = useState('');

    const forgotPasswordApi = useForgotPasswordApi({
        onSuccess: (res) => toast.success(res.message || t('profile.reset_link_sent')),
        onError: (err: any) => toast.error(err.message || t('profile.reset_link_failed'))
    });

    const onSubmit = (e: React.FormEvent) => {
        e.preventDefault();
        handleLogin({ identifier, password });
    };

    const handleForgotPassword = () => {
        if (!identifier || !identifier.includes('@')) {
            toast.error(t('profile.forgot_password_invalid_email'));
            return;
        }
        forgotPasswordApi.trigger({ email: identifier });
    };

    return (
        <div className="w-full max-w-md animate-in fade-in slide-in-from-bottom-4 duration-700">
            <div className="bg-white/80 dark:bg-[#1d1c16]/80 backdrop-blur-xl p-8 md:p-12 shadow-[0_20px_50px_rgba(29,28,22,0.1)] border border-outline-variant/10 rounded-sm">
                <div className="text-center mb-10">
                    <h2 className="font-headline text-3xl font-bold text-on-surface mb-2 tracking-tight">{t('profile.login')}</h2>
                    <p className="font-body text-sm text-on-surface-variant/70 tracking-wide">
                        {t('profile.login_subtitle')}
                    </p>
                </div>

                <form className="space-y-8" onSubmit={onSubmit}>
                    <div className="relative group">
                        <label className="block font-label text-[10px] uppercase tracking-widest text-secondary font-bold mb-1 opacity-70">
                            {t('profile.phone')} / {t('profile.email')}
                        </label>
                        <div className="flex items-center border-b border-outline-variant/30 group-focus-within:border-secondary transition-all duration-500 py-2">
                            <User className="text-on-surface-variant/40 mr-3" size={18} strokeWidth={1.75} />
                            <input
                                className="w-full bg-transparent border-none focus:ring-0 focus:outline-none text-on-surface placeholder:text-on-surface-variant/20 font-body text-sm"
                                placeholder={t('profile.identifier_placeholder')}
                                type="text"
                                value={identifier}
                                onChange={(e) => setIdentifier(e.target.value)}
                                required
                                disabled={loading}
                            />
                        </div>
                    </div>

                    <div className="relative group">
                        <label className="block font-label text-[10px] uppercase tracking-widest text-secondary font-bold mb-1 opacity-70">
                            {t('profile.password')} / PASSWORD
                        </label>
                        <div className="flex items-center border-b border-outline-variant/30 group-focus-within:border-secondary transition-all duration-500 py-2">
                            <Lock className="text-on-surface-variant/40 mr-3" size={18} strokeWidth={1.75} />
                            <input
                                className="w-full bg-transparent border-none focus:ring-0 focus:outline-none text-on-surface placeholder:text-on-surface-variant/20 font-body text-sm"
                                placeholder={t('profile.password_placeholder')}
                                type="password"
                                value={password}
                                onChange={(e) => setPassword(e.target.value)}
                                required
                                disabled={loading}
                            />
                        </div>
                    </div>

                    <div className="flex justify-end">
                        <button
                            type="button"
                            onClick={handleForgotPassword}
                            disabled={forgotPasswordApi.loading}
                            className="text-[11px] font-label text-secondary tracking-wider hover:underline opacity-80 uppercase"
                        >
                            {forgotPasswordApi.loading ? t('profile.sending') : t('profile.forgot_password')}
                        </button>
                    </div>

                    <div className="pt-4">
                        <button
                            className={`w-full bg-[#8f000d] text-white py-4 rounded-sm font-bold tracking-[0.2em] hover:bg-[#a2000f] active:scale-[0.98] transition-all duration-300 shadow-xl shadow-[#8f000d]/10 uppercase text-xs ${loading ? 'opacity-50 cursor-not-allowed' : ''}`}
                            type="submit"
                            disabled={loading}
                        >
                            {loading ? t('profile.logging_in') : t('profile.login_now')}
                        </button>
                    </div>
                </form>

                <div className="mt-3 border-t border-outline-variant/10 text-center">
                    <p className="font-body text-xs text-on-surface-variant/50">
                        {t('profile.no_account')}
                        <button
                            onClick={() => setView('register')}
                            className="text-secondary font-bold hover:underline ml-2 uppercase tracking-wide"
                        >
                            {t('profile.go_register')}
                        </button>
                    </p>
                </div>
            </div>
        </div>
    );
};

此时你会发现,已经帮你对接完登陆接口,并且还给你抽象成了独立的api方法调用

在父组件引入的方法是下面这样的

jsx 复制代码
import { useLoginApi, useRegisterApi, useGetProfileApi } from '../services';
...
const loginApi = useLoginApi({
    onSuccess: (res) => {
        applyAuthState(res);
        toast.success('登录成功');
    },
    onError: (err: any) => {
        console.error('Login Error:', err);
        toast.error(err.message || 'Login failed');
    }
});
...
<LoginView
    handleLogin={loginApi.trigger}
    loading={loginApi.loading}
    setView={setView}
/>

在services中封装的api是这样的

js 复制代码
import { useFetch, useMutation, type MutationOptions } from "../hooks";
/**
 * Hook to perform user login
 * Expects { identifier, password }
 */
export const useLoginApi = (options: MutationOptions<UserResponse> = {}) => {
  return useMutation<LoginBody, UserResponse>(
    ApiPath.user.login,
    "POST",
    options
  );
};

而我们发现useMutation是我让AI帮我封装的一个post请求,这个hook封装也非常完善

js 复制代码
import useSWR, { type SWRConfiguration, mutate as globalMutate } from "swr";
import { useState, useCallback, useMemo, useRef } from "react";
import { httpClient, BusinessError } from "./httpClient";
/**
 * Custom Mutation Hook (POST/PUT/DELETE) using native fetch-based HttpClient
 * Correctly standardizes error handling to BusinessError from backend/lib/response.ts.
 */
export function useMutation<B = any, R = any>(
  url: string,
  method: "POST" | "PUT" | "DELETE" | "GET" = "POST",
  options?: MutationOptions<R>
) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<BusinessError | null>(null);

  const trigger = useCallback(
    async (body?: B): Promise<R | undefined> => {
      setLoading(true);
      setError(null);

      try {
        let result: R;
        if (method === "GET") {
          result = await httpClient.get<R>(url, { params: body as any, headers: options?.headers });
        } else if (method === "POST") {
          result = await httpClient.post<R>(url, body, { headers: options?.headers });
        } else if (method === "PUT") {
          result = await httpClient.put<R>(url, body, { headers: options?.headers });
        } else {
          result = await httpClient.delete<R>(url, { headers: options?.headers });
        }

        if (typeof options?.proxy === "function") {
          options.proxy(result);
        }

        revalidateRelatedCaches(options?.revalidateKeys);
        options?.onSuccess?.(result);
        return result;
      } catch (err: any) {
        const normalizedError = err instanceof BusinessError ? err : new BusinessError({ 
          code: 50000, 
          message: err.message || "Unknown Error" 
        });
        setError(normalizedError);
        options?.onError?.(normalizedError);
        return Promise.reject(normalizedError);
      } finally {
        setLoading(false);
      }
    },
    [url, method, options]
  );

  return { trigger, loading, error };
}

至于用到的httpClient这个api依旧也是让AI帮我封装的

js 复制代码
import { useGlobalStore } from "../store";

// Matches backend/src/lib/response.ts
export interface ApiError {
  code: number;
  message: string;
}

export interface ApiResponse<T = any> {
  success: boolean;
  data?: T;
  message?: string;
  error?: ApiError;
}

export class BusinessError extends Error {
  code: number;
  constructor(apiError: ApiError) {
    super(apiError.message);
    this.name = "BusinessError";
    this.code = apiError.code;
  }
}

interface RequestOptions extends RequestInit {
  params?: Record<string, any>;
  baseUrl?: string;
}

interface Hooks {
  beforeRequest?: (request: Request) => void | Promise<void>;
  afterResponse?: (request: Request, response: Response) => void | Promise<Response>;
}

class HttpClient {
  private baseUrl: string;
  private hooks: Hooks;

  constructor(baseUrl: string = "", hooks: Hooks = {}) {
    this.baseUrl = baseUrl;
    this.hooks = hooks;
  }

  private async request<T>(url: string, options: RequestOptions = {}): Promise<T> {
    const { params, baseUrl, ...init } = options;
    const finalBaseUrl = baseUrl ?? this.baseUrl;

    // 1. Construct URL
    let fullUrl = url.startsWith("http") ? url : `${finalBaseUrl}${url}`;
    if (params) {
      const searchParams = new URLSearchParams();
      Object.entries(params).forEach(([key, val]) => {
        if (val !== undefined && val !== null) {
          searchParams.append(key, String(val));
        }
      });
      fullUrl += (fullUrl.includes("?") ? "&" : "?") + searchParams.toString();
    }

    const request = new Request(fullUrl, {
      ...init,
      headers: {
        "Content-Type": "application/json",
        ...init.headers,
      },
    });

    // 2. Before Request Hook
    if (this.hooks.beforeRequest) {
      await this.hooks.beforeRequest(request);
    }

    let response = await fetch(request);

    // 3. After Response Hook
    if (this.hooks.afterResponse) {
      const hookedResponse = await this.hooks.afterResponse(request, response);
      if (hookedResponse) {
        response = hookedResponse;
      }
    }

    // 4. Handle JSON response with unified format
    const contentType = response.headers.get("content-type") || "";
    if (contentType.includes("application/json")) {
      const result: ApiResponse<T> = await response.json();

      if (result.success && result.data !== undefined) {
        return result.data as T;
      }

      if (!result.success && result.error) {
        throw new BusinessError(result.error);
      }

      // Fallback for non-standard success
      if (result.success) return result as T;
    }

    // 5. Handle HTTP Errors (Non-JSON or Fallback)
    if (!response.ok) {
      throw new BusinessError({
        code: response.status * 100,
        message: response.statusText || "Network Error",
      });
    }

    return (await response.text()) as any;
  }

  public get<T = any>(url: string, options: RequestOptions = {}): Promise<T> {
    return this.request<T>(url, { ...options, method: "GET" });
  }

  public post<T = any>(url: string, body?: any, options: RequestOptions = {}): Promise<T> {
    return this.request<T>(url, {
      ...options,
      method: "POST",
      body: body ? JSON.stringify(body) : undefined,
    });
  }

  public put<T = any>(url: string, body?: any, options: RequestOptions = {}): Promise<T> {
    return this.request<T>(url, {
      ...options,
      method: "PUT",
      body: body ? JSON.stringify(body) : undefined,
    });
  }

  public delete<T = any>(url: string, options: RequestOptions = {}): Promise<T> {
    return this.request<T>(url, { ...options, method: "DELETE" });
  }
}

export const httpClient = new HttpClient(import.meta.env.VITE_API_URL || "", {
  beforeRequest: async (request) => {
    const { token } = useGlobalStore.getState();
    if (token && !request.headers.has("Authorization")) {
      request.headers.set("Authorization", `Bearer ${token}`);
    }
  },
  afterResponse: async (_request, response) => {
    if (response.status === 401) {
      useGlobalStore.getState().clearInit();
      localStorage.clear();
      // Optional: window.location.href = "/login";
    }
    return response;
  },
});

此时你看到代码,你会发现,你是不已经爱上AI写的代码了,唉,这些在以前封装,其实你自己去写,还真的不太容易。考虑的场景需要足够丰富,而且也很容易埋下未知bug。

看到这里,我觉得如果你用AI coding很久了,我相信你很难有兴趣去认真阅读代码了。不知道你有没有发现AI用久了,你大脑就慢慢正在失去自主思考,现在AI帮你思考,AI coding久了,这东西就像吸大麻,如果不用,你发现,你的生产力远远跟不上了,不管你用不用,AI都会淘汰你。

夜深了,作为一名前端程序员,留给我们的时间貌似不多了,这个岗位也许未来会消失,听着好像是一句很丧的话,并不是危言耸听,但回到开篇,AI正在重构整个软件行业,用好AI,对于个人来说,没有边界,又是机会。

如果有兴趣,数位炼金术,仅供娱乐参考吧。

相关推荐
毛骗导演2 小时前
Claude Code REPL.tsx 架构深度解析
前端·架构
Mike_jia2 小时前
AllinSSL:SSL证书自动化管理的终极利器,让HTTPS部署再无烦恼
前端
wsdswzj2 小时前
web与web服务器基础安全
服务器·前端·安全
JarvanMo2 小时前
Flutist - Flutter 模块化架构管理框架
前端
GISer_Jing2 小时前
AI Agent Skills 发现指南:前端工程化与自动化全景
前端·人工智能·自动化
心.c2 小时前
从 Function Call 到渐进式 Skill:大模型能力扩展范式的演进与落地实践
前端·人工智能·react.js·ai·react
IT_陈寒2 小时前
Vue的响应式更新把我坑惨了,原来问题出在这里
前端·人工智能·后端
Cobyte2 小时前
6.响应式系统比对:通过 Vue3 响应式库写 React 应用
前端·javascript·vue.js
Alice-YUE2 小时前
【前端面试之ai概念】大白话讲清 Agent、MCP、Skill、Function Calling、RAG
前端·人工智能·学习·aegnt