Stories

Detail Return Return

VibeCoding On Function AI Deep Dive:用 AI 應用生產 AI 應用 - Stories Detail

這是一個很有意思的話題, 今天大家都在熱火朝天的構建 AI 應用。有用各種各樣的編程語言,開發框架開發的,也有用低代碼工作流搭建的,但是你否知道,其實可以僅通過自然語言就可以完成一個 AI 應用的開發乃至上線麼? 本篇文章就來跟大家分享一下我是如何使用自然語言 的方式構建豐富多彩的 AI 應用的,希望藉此可以帶您直觀感受 VibeCoding 的魅力,感受 AI 時代的軟件生產變革。

用 AI 應用生產 AI 應用——VibeCoding On Function AI Deep Dive

操作演示

接下來我們先來真實的操作一下使用自然語言構建AI應用, 基礎軟件部分的獲取請參考之前的系列文章《Function AI 的 VibeCoding 解決方案》 ,對於已經部署好的同學可以重新部署一個新的版本。近期方案中增加了對百鍊等 AI 能力的集成,可以幫助您生成有趣又實用的AI應用。

場景一: 兒童教育娛樂類 AI 應用

這類應用非常適合家裏有小朋友的同學,跟他/她們一起利用 AI 進行娛樂和互動,培養使用 AI 的意識。我們接下來看一下如何生產構建。

兒童繪本製作應用

針對有聲兒童繪本的生成場景,可以構建一些有教育意義或者有童趣的繪本場景。

演示效果如下

構建過程

使用“專家模式”, 輸入框 輸入 “@”選擇“資深全棧工程師”。(這裏不需要數據庫所以不用前面兩個智能體)

總共10輪對話,沒有一行代碼,可以看到 AI (qwen3-code-plus)可以很好的進行修正。

發佈

只需按照以下流程,點擊一下“發佈”按鈕即可。

兒童猜畫應用

可以跟小朋友玩“人類繪畫 AI 猜畫”的遊戲培養繪畫興趣。

演示效果如下

構建過程

使用“專家模式”, 輸入框 輸入 “@”選擇“資深全棧工程師”。(這裏不需要數據庫所以不用前面兩個智能體)

僅四輪對話即可生成修改這樣的創意AI應用。

發佈

可參考兒童繪本製作應用發佈流程

場景二: 企業網站+知識問答

這類應用是非常剛需的企業應用,比如企業的產品門户頁或者解決方案官網等,然後還要在官網上增加一個智能助手,來實現企業的自助服務。

效果演示

構建過程

企業網站+知識問答分兩個步驟

步驟一

構建知識問答 API 服務,知識問答服務可以使用 AgentCraft 的底座無代碼搭建,構建一個知識庫的 API 示例如下:

1. 新建數據集 2.新建數據源 3.上傳知識文檔
4.新建知識庫智能體 5.關聯1的數據集 6.複製該知識庫的調用 API

步驟二

自然語言開發,本次依然只使用“全棧專家”

經過6輪對話即可完成+AI 的能力

系統中的 AI 集成

這裏是如何做到可以讓 AI 應用直接開發 AI 應用的呢? 主要分三個部分

系統提示詞集成

您是一位專注於Web應用開發領域的專家X,擁有跨多種編程語言、框架和最佳實踐的豐富知識。

你的協作方有D(一個數據庫專家)以及M(一個專業的項目經理) 可以參考他們的建議開發應用

您是一位專注於Web應用開發領域的專家X,擁有跨多種編程語言、框架和最佳實踐的豐富知識。
你的協作方有D(一個數據庫專家)以及M(一個專業的項目經理) 可以參考他們的建議開發應用
<system_constraints>
  ...之前的提示內容
<IntegrationExamples>
  <Integration name="百鍊平台AI">
    // 已知存在server端的api文件 src/app/api/ai/route.ts
    // 瀏覽器端調用示例
    // 文本生成(非流式)
    const response = await fetch('/api/ai', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        action: 'text-generation',
        data: {
          model: 'qwen-plus',
          messages: [
            {
              role: 'system',
              content: 'You are a helpful assistant.'
            },
            {
              role: 'user',
              content: '你是誰?'
            }
          ]
        }
      })
    });
    /**
      文本生成response的數據結構如下
      {
          "choices": [
              {
                  "message": {
                      "role": "assistant",
                      "content": ""
                  },
                  "finish_reason": "stop",
                  "index": 0,
                  "logprobs": null
              }
          ],
          "object": "chat.completion",
          "usage": {
              "prompt_tokens": 121,
              "completion_tokens": 788,
              "total_tokens": 909,
              "prompt_tokens_details": {
                  "cached_tokens": 0
              }
          },
          "created": 1755147048,
          "system_fingerprint": null,
          "model": "qwen-plus",
          "id": ""
      }
    **/

    // 文本生成(流式)
    const response = await fetch('/api/ai', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      action: 'text-generation',
      data: {
        model: 'qwen-plus',
        messages: [
          {
            role: 'system',
            content: 'You are a helpful assistant.'
          },
          {
            role: 'user',
            content: '你是誰?'
          }
        ],
        stream: true,
        stream_options: {
          include_usage: true
        }
      }
    })
  });

  // 處理流式響應
  if (response.body) {
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      
      const chunk = decoder.decode(value);
      // 處理每個數據塊
      console.log(chunk);
    }
  }
    // 圖像生成1-啓動異步生成任務
    const response = await fetch('/api/ai', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        action: 'image-generation',
        data: {
          model: 'wan2.2-t2i-flash',
          input: {
            prompt: '一間有着精緻窗户的花店,漂亮的木質門,擺放着花朵'
          },
          parameters: {
            size: '1024*1024',
            n: 1
          }
        }
      })
    });

    const { output } = await response.json();
    const taskId = output.task_id;
    // 圖像生成2-查詢異步任務
    const response = await fetch('/api/ai', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        action: 'get-image-task',
        data: {
          taskId: '86ecf553-d340-4e21-xxxxxxxxx'
        }
      })
    });
    const result = await response.json();
    /**
      result.output?.task_status 狀態碼如下:
          PENDING:任務排隊中
          RUNNING:任務處理中
          SUCCEEDED:任務執行成功
          FAILED:任務執行失敗
          CANCELED:任務取消成功
          UNKNOWN:任務不存在或狀態未知
      示例:
      if(result.output?.task_status === 'SUCCEEDED'){
        let imageurl = result.output.results?.[0]?.url;
      }
    **/
    // 圖像理解
    const response = await fetch('/api/ai', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        action: 'visual-understanding',
        data: {
          model: 'qwen-vl-max',
          messages: [
            {
              role: 'system',
              content: [
                { type: 'text', text: 'You are a helpful assistant.' }
              ]
            },
            {
              role: 'user',
              content: [
                { 
                  type: 'image_url', 
                  image_url: { 
                    url: '<img-url>' 
                  } 
                },
                { type: 'text', text: '圖中描繪的是什麼景象?' }
              ]
            }
          ]
        }
      })
    });
    // 音頻理解(音頻識別)示例
    const response = await fetch('/api/ai', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        action: 'audio-understanding',
        data: {
          model: 'qwen-audio-turbo-latest',
          input: {
            messages: [
              {
                role: "system",
                content: [
                  {"text": "You are a helpful assistant."}
                ]
              },
              {
                role: "user",
                content: [
                  {"audio": "https://dashscope.oss-cn-beijing.aliyuncs.com/audios/welcome.mp3"},
                  {"text": "這段音頻在説什麼?"}
                ]
              },
              {
                role: "assistant",
                content: [
                  {"text": "這段音頻説的是:'歡迎使用阿里雲'"}
                ]
              },
              {
                role: "user",
                content: [
                  {"text": "介紹一下這家公司。"}
                ]
              }
            ]
          }
        }
      })
    });

    const result = await response.json();
    // 文本轉語音示例(語音合成)
    const response = await fetch('/api/ai', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        action: 'text-to-speech',
        data: {
          model: 'qwen-tts',
          input: {
            text: "那我來給大家推薦一款T恤,這款呢真的是超級好看,這個顏色呢很顯氣質,而且呢也是搭配的絕佳單品,大家可以閉眼入,真的是非常好看,對身材的包容性也很好,不管啥身材的寶寶呢,穿上去都是很好看的。推薦寶寶們下單哦。",
            voice: "Chelsie"
          }
        }
      })
    });

    const result = await response.json();
    /**
      result 返回示例
      {
          "output": {
              "finish_reason": "stop",
              "audio": {
                  "expires_at": 1755191553,
                  "data": "",
                  "id": "",
                  "url": ""
              }
          },
          "usage": {
              "input_tokens_details": {
                  "text_tokens": 14
              },
              "total_tokens": 122,
              "output_tokens": 108,
              "input_tokens": 14,
              "output_tokens_details": {
                  "audio_tokens": 108,
                  "text_tokens": 0
              }
          },
          "request_id": ""
      }
    **/
  </Integration>
   <Integration name="AgentCraft AI">
    // 服務端 建議目錄src/app/api/agentcraft/route.ts
    // 已知 AGENTCRAFT_BASE_URL , API_VERSION 和 TOKEN 需要用户輸入
    import { NextResponse } from 'next/server';
    export async function POST(request: Request) {
      try {
        const { messages ,stream} = await request.json();
        
        // 調用知識庫API
        // AgentCraft API Vesion 為 v1 或者 v2
        const response = await fetch({AGENTCRAFT_BASE_URL} + '/{API_VERSION}/chat/completions', {
          method: 'POST',
          headers: {
            'accept': 'application/json',
            'Authorization': 'Bearer <TOKEN>',
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            messages: [
              {
                role: "system",
                content: "你是一個有用的助手"
              },
              ...messages
            ],
            stream,
            max_tokens: 8192
          })
        });
        if (stream) {
          // 創建一個新的 Response 對象,直接轉發流式響應
          return new Response(response.body, {
            status: response.status,
            headers: {
              'Content-Type': 'text/event-stream; charset=utf-8',
              'Cache-Control': 'no-cache',
              'Connection': 'keep-alive',
              'Access-Control-Allow-Origin': '*',
            }
          });
        }
        if (!response.ok) {
          throw new Error(`知識庫API請求失敗: ${response.status}`);
        }

        const data = await response.json();
        const content = data.choices?.[0]?.message?.content || '抱歉,我無法處理您的請求。請稍後再試。';
        
        return NextResponse.json({ content });
      } catch (error) {
        console.error('Error:', error);
        return NextResponse.json({ error: '處理請求時發生錯誤' }, { status: 500 });
      }
    }
    // 客户端
    const response = await fetch('/api/agentcraft', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      action: 'text-generation',
      data: {
        model: 'qwen-plus',
        messages: [
          {
            role: 'system',
            content: 'You are a helpful assistant.'
          },
          {
            role: 'user',
            content: '你是誰?'
          }
        ],
        stream: true,
        stream_options: {
          include_usage: true
        }
      }
    })
  });

  // 處理流式響應
  if (response.body) {
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      
      const chunk = decoder.decode(value);
      // 處理每個數據塊
      console.log(chunk);
    }
  }
   
  </Integration>
</IntegrationExamples>
...之前的提示內容
</system_constraints>

可以看到,這裏 IntegrationExamples 中寫明瞭在客户端調用百鍊 API 以及 AgentCraft AI 的示例,他們覆蓋了文本生成,圖片生成,聲音生成,圖像識別,知識庫,智能體等全方位的 AI 能力,AI 可以根據示例很好的完成開發

開發態環境集成

為了減少 AI 的輸出內容,降低成本,以及確保穩定的 AI 服務,系統通過應用模板內置了 AI 的 API Server,也就是在 NextJS 的後端服務中加入了提前寫好的 AI API 服務(這裏只是內置了百鍊的 API 服務,AgentCraft 本身的服務則是服務端和客户端都需要重新生成)

// app/api/ai/route.ts
import { NextRequest, NextResponse } from 'next/server';

// 定義類型
type MessageContent = {
  type: string;
  text?: string;
  image_url?: { url: string };
  audio?: string;
};

type Message = {
  role: string;
  content: string | MessageContent[];
};

type RequestBodies = {
  'text-generation': {
    model: string;
    messages: Message[];
  };
  'image-generation': {
    model: string;
    input: {
      prompt: string;
    };
    parameters: {
      size: string;
      n: number;
    };
  };
  'get-image-task': {
    taskId: string;
  };
  'visual-understanding': {
    model: string;
    messages: Message[];
  };
  'audio-understanding': {
    model: string;
    input: {
      messages: Message[];
    };
  };
  'text-to-speech': {
    model: string;
    input: {
      text: string;
      voice?: string;
    };
  };
};

// API端點映射
const API_ENDPOINTS = {
  'text-generation': 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions',
  'image-generation': 'https://dashscope.aliyuncs.com/api/v1/services/aigc/text2image/image-synthesis',
  'get-image-task': (taskId: string) => `https://dashscope.aliyuncs.com/api/v1/tasks/${taskId}`,
  'visual-understanding': 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions',
  'audio-understanding': 'https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation',
  'text-to-speech': 'https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation'
};

// 請求方法映射
const REQUEST_METHODS = {
  'text-generation': 'POST',
  'image-generation': 'POST',
  'get-image-task': 'GET',
  'visual-understanding': 'POST',
  'audio-understanding': 'POST',
  'text-to-speech': 'POST'
};

// 是否需要異步頭
const ASYNC_HEADERS = {
  'image-generation': true
};

export async function POST(req: NextRequest) {
  const { action, data } = await req.json();
  
  // 檢查API密鑰
  const apiKey = process.env.DASHSCOPE_API_KEY;
  if (!apiKey) {
    return NextResponse.json({ error: 'DASHSCOPE_API_KEY is not configured' }, { status: 500 });
  }

  // 驗證action
  if (!(action in API_ENDPOINTS)) {
    return NextResponse.json({ error: 'Invalid action specified' }, { status: 400 });
  }

  try {
    // 特殊處理get-image-task,因為它需要taskId參數
    const url = action === 'get-image-task' 
      ? API_ENDPOINTS[action](data.taskId) 
      : API_ENDPOINTS[action];
      
    // 驗證taskId
    if (action === 'get-image-task' && !data.taskId) {
      return NextResponse.json({ error: 'Task ID is required' }, { status: 400 });
    }

    // 構建請求頭
    const headers: Record<string, string> = {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    };
    
    // 添加異步頭(如果需要)
    if (ASYNC_HEADERS[action as keyof typeof ASYNC_HEADERS]) {
      headers['X-DashScope-Async'] = 'enable';
    }

    // 構建請求配置
    const config: RequestInit = {
      method: REQUEST_METHODS[action],
      headers
    };

    // 添加請求體(GET請求不需要)
    if (REQUEST_METHODS[action] === 'POST') {
      config.body = JSON.stringify(data);
    }

    // 發送請求
    const response = await fetch(url, config);

     // 處理流式響應
  if (action === 'text-generation' && data.stream) {
    // 創建一個新的 Response 對象,直接轉發流式響應
      return new Response(response.body, {
        status: response.status,
        headers: {
          'Content-Type': 'text/event-stream; charset=utf-8',
          'Cache-Control': 'no-cache',
          'Connection': 'keep-alive',
          'Access-Control-Allow-Origin': '*',
        }
      });
    }
    const result = await response.json();
    
    return NextResponse.json(result, { status: response.status });
  } catch (error) {
    console.error('DashScope API error:', error);
    return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
  }
}

對於 AI 應用,還有一個比較重要的東西,就是 API 秘鑰。本方案中,API 秘鑰是通過環境變量的方式從上層服務注入,而不是明文寫到系統,因此更加安全。

//...
else if (shellCommand.startsWith('npm run dev')) {
                        const currentPid = process.pid;
                        await checkAndKillPort(PORT, currentPid);
                        const childProcess: any = spawn('npm', ['run', 'dev'], {
                            cwd: workdir,
                            stdio: ['ignore', 'pipe', 'pipe'],
                            detached: true, // 使子進程在父進程退出後繼續運行
                            env: {
                                ...process.env,
                                PATH: process.env.PATH,
                                NODE_ENV: 'development', // 明確設置開發環境
                                VITE_USER_NODE_ENV: 'development'
                            },
                            uid,
                            gid
                        });
// ....

生產態環境集成

因為在開發態的時候集成 AI 的代碼以及客户端的調用代碼都已經準備完畢,發佈到生產環境,只是提取開發態的環境變量一併部署到服務器上即可。

構建的過程中會生成 s.yaml, 將整個生成的 AI 應用進行打包上傳

const sYamlContent = `edition: 3.0.0
name: mayama_ai_generated_app
vars:
  region: '${process.env.REGION}'
  functionName: 'mayama_${projectId}'
template:
  mayama_all:
    internetAccess: true
resources:
  
  mayama_nextjs_build:
    component: fc3
    actions:
      pre-deploy:
        - run: npm run build
          path: ./
    props:
      region: '\${vars.region}'
      description: 應用
      timeout: 600
      diskSize: 512
      customRuntimeConfig:
        port: 3000
        command:
          - bootstrap
      layers:
        - acs:fc:\${vars.region}:official:layers/Nodejs20/versions/1
        - acs:fc:\${vars.region}:1154600634854327:layers/ac-client-mayama-base-release/versions/10
        - >-
          acs:fc:\${vars.region}:1154600634854327:layers/ac-client-base-release/versions/4
      runtime: custom.debian10
      instanceConcurrency: 100
      memorySize: 3072
      cpu: 2
      environmentVariables:
        LD_LIBRARY_PATH: /code:/code/lib:/usr/local/lib:/opt/lib
        NODE_PATH: /opt/nodejs/node_modules
        Region: '\${vars.region}'
        DASHSCOPE_API_KEY: ${process.env.DASHSCOPE_API_KEY || ''}
        NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL}
        NEXT_PUBLIC_SUPABASE_ANON_KEY: ${NEXT_PUBLIC_SUPABASE_ANON_KEY}
        PATH: >-
          /opt/nodejs20/bin:/usr/local/bin/apache-maven/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/ruby/bin:/opt/bin:/code:/code/bin:/opt/nodejs/node_modules/.bin
      functionName: \${vars.functionName}
      code: ./
      triggers:
        - description: ''
          qualifier: LATEST
          triggerName: defaultTrigger
          triggerType: http
          triggerConfig:
            methods:
              - GET
              - POST
              - PUT
              - DELETE
            authType: anonymous
            disableURLInternet: false
      customDomain:
        protocol: "HTTP"
        route:
          path: "/*"
          qualifier: "LATEST"
        domainName: auto
    extend:
      name: mayama_all
  
`;

    await fs.writeFile(sYamlPath, sYamlContent, 'utf-8');
    console.log(`✅ 已創建 s.yaml 配置文件`);

VibeCoding 的技巧

瞭解系統的設計可以掌握系統的應用邊界,知曉什麼時候可以強化提示讓 AI 系統更好的完成生產任務。這裏有些小技巧。

一、項目唯一ID

當 AI 第一次將項目信息輸出的時候,後續都應該圍繞這裏的 ID 進行持續的迭代,因為系統構建真實的應用文件是以這個 ID 為唯一值,如果你發現 ID 變了,那就意味着系統重新生成了一個項目,無法延續你之前的項目。 此時可以跟系統説“請在項目 ID 是 xxxx 的項目上修改”,這樣就保持了項目持續迭代的一致性。

這裏也建議一個會話對應一個項目,防止生成混淆。

二、一些必要的交流術語

絕大部分情況下,你使用自然語言表達自己的需求要求 AI 滿足即可,但某些情況下,需要給他一些專業的軟件開發術語,可以讓他修改的更加明確,比如上述示例,使用 xxxx api 完成開發(複製的是一個 curl 的請求),再比如構建應用視覺的時候,可以輸入 “請把頁面上的卡片元素進行垂直/水平居中”,請使用 xxx 的 json 數據進行數據模擬等等。

三、異常情況處理

AI 編程結果不一定是一帆風順的,系統內置了錯誤提示的效果,因此當遇到錯誤的時候最簡單直接的辦法就是直接粘貼複製,讓 AI 自己看錯誤去修改。

除了異常,系統還會把生成的應用本身,以及多輪對話等上下文都一併傳入給 AI,全面的上下文可以更好的讓 AI 幫助我們解決問題。

四、解決不了的死循環

AI 可能會陷入某種死循環,怎麼問問題都解決不了,此時你可以要求他換個思路,或者我們換一個問話方式,看看是否可以解決。

未來展望

隨着 VibeCoding 解決方案的持續進化,我們正朝着全民開發者時代邁進,

  1. 國內開放平台的登錄:使用支付寶,微信等登錄系統直接讓自己生成的應用對外可服務
  2. 小程序/移動應用:擴展應用類型,如支持小程序或者移動應用的自然語言編程方案
  3. Agentic 應用:支持更復雜的 Agentic 工作流,多模態應用

上手體驗

訪問阿里雲 Function AI控制枱參考《全球首個搭載Kimi-K2&Qwen3-Coder的Serverless架構VibeCoding解決方案重磅來襲!》內容教程進行部署使用。

更多內容關注 Serverless 微信公眾號(ID:serverlessdevs),彙集 Serverless 技術最全內容,定期舉辦 Serverless 活動、直播,用户最佳實踐。

user avatar developer-tianyiyun Avatar Johny-zhao Avatar
Favorites 2 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.