前端工程师转型AI应用开发:7天掌握Prompt工程、Agent与RAG实战

📅 2026/8/18 9:41:35
前端工程师转型AI应用开发:7天掌握Prompt工程、Agent与RAG实战
前端工程师的焦虑这两年肉眼可见。一边是“前端已死”的论调不绝于耳另一边是AI大模型应用开发岗位的薪资水涨船高。很多前端同学想转型但面对“大模型”、“Agent”、“RAG”这些新名词感觉无从下手仿佛要重新学一遍计算机。这篇文章要解决的核心问题就是一个具备前端开发经验的同学如何最高效地切入AI大模型应用开发领域将你已有的技能JavaScript/TypeScript、工程化、API调用、UI构建转化为新赛道的优势而不是从零开始。我的核心判断是前端转AI应用开发最大的优势在于“最后一公里”的实现能力最大的误区是去死磕底层算法。7天不是让你成为AI科学家而是让你掌握一套能立刻上手的、以工程化思维构建AI应用的方法论。本文将围绕Prompt工程、Agent开发、RAG增强、模型微调这四个核心实践点提供一条清晰的、可执行的、全程干货的学习路线帮你踩准风口拓宽高薪就业赛道。1. 为什么前端工程师转AI应用开发有天然优势在深入技术细节前我们先破除一个迷思转型AI不等于重学Python和PyTorch。AI大模型应用开发本质上是在构建一种新型的、智能化的软件。这个“构建”过程前端工程师再熟悉不过。你的现有技能正是AI应用落地的关键交互与体验设计大模型输出不稳定如何设计流式输出、加载状态、错误反馈和重试机制这是前端最擅长的领域。一个优秀的AI产品一半的功劳在于交互设计。工程化与架构模块化、组件化、状态管理、构建打包。开发一个复杂的AI Agent应用其代码组织复杂度不亚于一个大型前端SPA。你的工程化经验能避免项目迅速变成“屎山”。API消费与集成前端天天和HTTP API、WebSocket打交道。调用大模型API如OpenAI、通义千问、DeepSeek与调用后端接口在技术上没有本质区别你甚至更懂得如何处理异步、超时和降级。TypeScript类型安全大模型的输入输出本质上是非结构化的文本。用TypeScript定义清晰的Prompt模板、函数调用Function Calling的Schema、Agent工具Tool的输入输出类型能极大提升开发效率和代码可靠性。你需要补强的是新的“领域知识”而非“编程知识”Prompt Engineering如何与模型“对话”以获得稳定、高质量的输出。这更像是一种新的“查询语言”设计。Agent设计模式如何让模型具备使用工具、规划任务、记忆上下文的能力。这类似于设计一个状态机或工作流引擎。RAG检索增强生成如何让模型访问私有、最新的知识库。这需要你理解向量数据库、文本分块和嵌入Embedding的基本概念。模型微调Fine-tuning如何用特定数据让通用模型更擅长某个垂直领域。你需要了解数据准备和训练流程但不必深究损失函数。接下来我们以7天为周期将这四个核心领域拆解为可执行的学习任务。2. 环境准备搭建你的AI应用开发工作台工欲善其事必先利其器。前端同学请留在你熟悉的环境里不要盲目切换。核心环境Node.js TypeScriptNode.js建议使用LTS版本如18.x, 20.x。这是运行各种AI相关JavaScript库的基础。TypeScript强烈推荐。AI应用开发中清晰的类型定义是抵御“模型幻觉”和接口混乱的第一道防线。包管理器npm,yarn,pnpm皆可。IDEVS Code 相关插件如 OpenAI、TypeScript 等。关键依赖库我们将主要使用LangChain.js和OpenAI SDK。LangChain是一个强大的框架它将Prompt、Agent、RAG等概念抽象成了可组合的模块极大降低了开发复杂度。初始化一个项目并安装核心依赖# 1. 创建项目目录 mkdir ai-frontend-dev cd ai-frontend-dev # 2. 初始化npm项目按提示操作 npm init -y # 3. 初始化TypeScript配置 npx tsc --init # 4. 安装核心依赖 npm install langchain langchain/core npm install openai # 或其他模型提供商SDK如 ai-sdk/openai npm install -D typescript ts-node types/node nodemon # 5. 安装向量数据库客户端以Chroma为例本地运行 npm install chromadb # 或安装连接器以Pinecone云服务为例 # npm install pinecone-database/pinecone获取API密钥你需要一个或多个大模型的API密钥。对于学习和原型开发可以考虑OpenAI最主流文档和生态最全。国内平台如通义千问、DeepSeek、智谱AI等访问速度和成本可能更有优势。 将API密钥存储在环境变量中永远不要提交到代码仓库。# .env 文件 OPENAI_API_KEYsk-your-key-here DEEPSEEK_API_KEYyour-deepseek-key-here3. Day 1-2吃透Prompt Engineering——与模型高效对话Prompt Engineering不是“咒语学”而是通过结构化、清晰的指令约束和引导模型输出使其满足程序化调用的需求。3.1 从“聊天”到“工程”Prompt的核心要素一个工程化的Prompt通常包含角色Role设定模型的角色如“你是一个资深前端技术专家”。指令Instruction明确的任务要求。上下文Context提供必要的背景信息。输入数据Input Data需要模型处理的具体内容。输出格式Output Format规定返回的数据结构JSON、XML、Markdown等。错误示例模糊不清// 不好的Prompt过于开放输出不可控 const badPrompt 帮我优化一下这段代码。;正确示例结构化、可解析// 好的Prompt角色清晰、指令明确、格式固定 const goodPrompt 你是一个经验丰富的TypeScript和React代码审查员。 请严格遵循以下步骤分析我提供的代码 1. **代码功能**用一句话总结这段代码的目的。 2. **潜在问题**列出不超过3个可能存在的性能、可读性或类型安全问题。 3. **优化建议**针对每个问题提供具体的代码修改建议。 请将分析结果以如下JSON格式返回 { summary: string, issues: [{type: string, description: string}], suggestions: [{forIssue: string, code: string}] } 需要分析的代码 \\\typescript ${userCode} \\\ ;3.2 使用LangChain实现Prompt模板化手动拼接字符串很麻烦。LangChain提供了ChatPromptTemplate支持变量插值和消息角色管理。// prompt-template.ts import { ChatPromptTemplate } from langchain/core/prompts; import { ChatOpenAI } from langchain/openai; // 1. 定义Prompt模板 const codeReviewPrompt ChatPromptTemplate.fromMessages([ [system, 你是一个经验丰富的{language}代码审查员。], [human, 请分析以下代码 {code} 请提供 1. 功能总结。 2. 潜在问题。 3. 优化建议。 用JSON格式回复。], ]); // 2. 准备变量 const variables { language: TypeScript, code: function add(a: any, b: any): any { return a b; }, }; // 3. 格式化Prompt并调用模型 const model new ChatOpenAI({ apiKey: process.env.OPENAI_API_KEY, modelName: gpt-4o-mini, // 根据成本选择模型 temperature: 0.2, // 降低随机性使输出更稳定 }); async function main() { const formattedPrompt await codeReviewPrompt.formatMessages(variables); const response await model.invoke(formattedPrompt); console.log(response.content); // 输出将是结构化的文本可以尝试解析为JSON } main().catch(console.error);关键技巧temperature控制创造性。做确定性的任务代码分析、数据提取时调低0-0.3需要创意时调高0.7-1.0。max_tokens限制生成长度控制成本。少样本提示Few-shot在Prompt中提供几个输入输出的例子能显著提升模型在特定任务上的表现。4. Day 3-4掌握Agent开发——让模型学会使用工具Agent是大模型应用的核心范式。它让模型从一个“问答机”变成了一个可以自主规划、调用工具、持续执行的智能体。对于前端开发者可以把它理解为一个由大模型驱动的、超级智能的“状态机”或“工作流引擎”。4.1 Agent的核心三要素工具ToolsAgent可以调用的函数。这可以是任何东西计算器、搜索引擎API、数据库查询、甚至操作浏览器Playwright或操作系统的函数。这是前端开发者最能发挥价值的地方你可以把任何现有系统封装成Tool。模型LLM负责理解指令、规划步骤、决定调用哪个工具。代理Agent协调模型和工具运行的逻辑框架。LangChain提供了多种Agent类型如ReAct Agent、Plan-and-Execute Agent。4.2 实战创建一个能查询天气和进行计算的Agent假设我们有两个工具一个模拟的天气查询工具一个数学计算工具。// agent-demo.ts import { ChatOpenAI } from langchain/openai; import { DynamicStructuredTool } from langchain/core/tools; import { z } from zod; // 用于定义严格的输入模式 import { AgentExecutor, createReactAgent } from langchain/agents; // 1. 定义工具 - 天气查询模拟 const weatherTool new DynamicStructuredTool({ name: get_weather, description: 根据城市名称获取当前天气信息。, schema: z.object({ city: z.string().describe(城市名称例如北京、上海), }), func: async ({ city }) { // 这里应该调用真实的天气API例如和风天气 console.log([工具调用] 查询城市${city}); // 模拟返回 return ${city}的天气是晴天温度25度。; }, }); // 2. 定义工具 - 数学计算 const calculatorTool new DynamicStructuredTool({ name: calculator, description: 执行数学计算。支持加()、减(-)、乘(*)、除(/)。, schema: z.object({ expression: z.string().describe(数学表达式例如3 5 * 2), }), func: async ({ expression }) { console.log([工具调用] 计算表达式${expression}); // 警告实际项目中切勿使用eval此处仅作演示。应使用安全的数学表达式解析库。 try { const result eval(expression); // 仅为演示生产环境禁用eval return 计算结果${expression} ${result}; } catch (error) { return 计算错误${error.message}; } }, }); // 3. 初始化模型 const model new ChatOpenAI({ modelName: gpt-4o-mini, temperature: 0, }); // 4. 创建ReAct Agent const agent createReactAgent({ llm: model, tools: [weatherTool, calculatorTool], }); // 5. 创建执行器 const agentExecutor new AgentExecutor({ agent, tools: [weatherTool, calculatorTool], verbose: true, // 打印详细的执行步骤便于调试 }); // 6. 运行Agent async function runAgent() { const question 北京的温度加上上海的温度是多少假设北京25度上海28度。; console.log(用户问题${question}); const result await agentExecutor.invoke({ input: question, }); console.log(\n--- 最终答案 ---); console.log(result.output); } runAgent().catch(console.error);运行上述代码你会看到类似以下的输出用户问题北京的温度加上上海的温度是多少假设北京25度上海28度。 [Agent思考] 我需要先获取北京和上海的温度然后把它们加起来。 [工具调用] 查询城市北京 [工具调用] 查询城市上海 [Agent思考] 我得到了北京25度上海28度。现在需要计算它们的和。 [工具调用] 计算表达式25 28 --- 最终答案 --- 北京的温度是25度上海的温度是28度它们的和是53度。这个例子展示了Agent的核心魅力理解复杂意图模型能拆解“A温度加B温度”这个模糊请求。规划与执行它规划出“先查北京天气 - 再查上海天气 - 最后计算总和”的步骤。工具调用按顺序调用了我们定义的两个工具。整合答案将工具返回的结果整合成自然语言回复。前端开发者的机会你可以把调用内部业务系统API、操作UI测试脚本、生成前端组件代码等任务都封装成Tool让AI Agent帮你自动化完成复杂的开发流程。5. Day 5-6构建RAG系统——让模型拥有“私有知识”大模型的训练数据有截止日期且不了解你的私有数据公司文档、个人笔记、代码库。RAGRetrieval-Augmented Generation检索增强生成解决了这个问题。其流程是提问 - 从知识库检索相关文档 - 将文档作为上下文注入Prompt - 生成答案。5.1 RAG核心流程与前端关联文档加载与分块将PDF、Word、Markdown、网页等文件加载为文本并切割成大小合适的“块”Chunk。这类似于处理文件上传和文本解析。向量化Embedding使用嵌入模型将文本块转换为高维向量一组数字。语义相似的文本其向量在空间中也接近。这是核心的AI概念但作为应用开发者你只需会调用API。向量存储将向量和对应的文本块存入向量数据库如Chroma、Pinecone、Weaviate。这类似于操作一个特殊的、支持相似性搜索的数据库。检索与生成用户提问时将问题也向量化在向量数据库中搜索最相似的文本块将它们作为上下文和问题一起送给大模型生成答案。5.2 实战用LangChain和Chroma构建本地知识库问答// rag-demo.ts import { ChatOpenAI, OpenAIEmbeddings } from langchain/openai; import { MemoryVectorStore } from langchain/vectorstores/memory; import { RecursiveCharacterTextSplitter } from langchain/text_splitter; import { Document } from langchain/core/documents; // 1. 准备模拟的私有知识例如你的项目文档 const privateKnowledge 项目“AI助手”的技术栈 - 前端Next.js 15 (App Router), TypeScript, Tailwind CSS, Shadcn/ui组件库。 - 状态管理使用Zustand因为其API简单且与React并发特性兼容性好。 - 后端Node.js Express提供RESTful API。大模型交互通过LangChain.js处理。 - 数据库PostgreSQL用于存储用户数据ChromaDB用于存储文档向量。 - 部署前端部署在Vercel后端和数据库部署在AWS ECS。 核心功能 1. 用户上传PDF/Word文档系统自动解析并存入知识库。 2. 用户可通过自然语言提问系统基于知识库回答。 3. 支持多轮对话上下文长度限制为10轮。 ; // 2. 文档分块防止超出模型上下文长度 const textSplitter new RecursiveCharacterTextSplitter({ chunkSize: 500, // 每个块的最大字符数 chunkOverlap: 50, // 块之间的重叠字符保持语义连贯 }); const docs await textSplitter.splitText(privateKnowledge); const documentObjects docs.map((doc, i) new Document({ pageContent: doc, metadata: { source: internal-doc, chunkId: i } })); // 3. 初始化嵌入模型和向量存储 const embeddings new OpenAIEmbeddings(); const vectorStore await MemoryVectorStore.fromDocuments(documentObjects, embeddings); // 4. 初始化聊天模型 const model new ChatOpenAI({ modelName: gpt-4o-mini, temperature: 0 }); // 5. 检索增强的问答函数 async function askWithRAG(question: string) { // 5.1 检索相关文档块 const relevantDocs await vectorStore.similaritySearch(question, 3); // 返回最相似的3个块 const context relevantDocs.map(doc doc.pageContent).join(\n---\n); // 5.2 构建增强后的Prompt const prompt 请严格根据以下提供的上下文信息来回答问题。如果上下文没有提供足够信息请直接说“根据已知信息无法回答此问题”。 上下文信息 ${context} 问题${question} 请给出准确、简洁的答案; // 5.3 调用模型 const response await model.invoke(prompt); return response.content; } // 6. 测试 async function main() { const questions [ 这个项目的前端用了什么框架, 为什么选择Zustand做状态管理, 知识库是用什么存储的, 项目部署在哪里 // 这个问题上下文中有部分信息 ]; for (const q of questions) { console.log(\nQ: ${q}); const answer await askWithRAG(q); console.log(A: ${answer}); } } main().catch(console.error);运行结果示例Q: 这个项目的前端用了什么框架 A: 根据上下文信息项目的前端使用了 Next.js 15 (App Router), TypeScript, Tailwind CSS, 以及 Shadcn/ui 组件库。 Q: 为什么选择Zustand做状态管理 A: 根据上下文信息选择Zustand是因为其API简单且与React并发特性兼容性好。 Q: 知识库是用什么存储的 A: 根据上下文信息知识库文档向量是使用 ChromaDB 存储的。关键要点分块大小需要权衡。块太大会包含无关信息太小会丢失上下文。通常500-1000字符是个好的起点。检索数量返回多少个相关块k值需要实验。太少可能信息不足太多可能引入噪声并增加token消耗。Prompt设计必须明确指令模型“基于上下文回答”否则它可能忽略上下文用自己的知识胡编乱造这称为“幻觉”。6. Day 7初探模型微调——让模型更“懂”你当Prompt Engineering和RAG都无法满足你对模型行为的精准控制时例如需要特定的回复风格、复杂的格式要求、或对私有领域知识有极深的理解就需要考虑微调Fine-tuning。6.1 微调是什么前端需要掌握到什么程度微调不是训练一个新模型而是在预训练大模型的基础上用你的特定数据问答对、指令对进行额外训练让模型适应你的任务。前端开发者的定位你不需要研究训练算法但需要懂得何时需要微调任务极其独特、风格固定、RAG效果不佳时。如何准备数据这是微调成功的关键也是你可以主要参与的部分。如何使用微调后的模型就像调用普通API一样。6.2 微调数据准备实战以OpenAI格式为例微调数据通常是一个JSONL文件每行是一个JSON对象代表一个训练样本。// 示例训练一个“前端代码审查助手”的微调数据 (fine-tuning-data.jsonl) // 这是一个高度简化的示例实际需要数百至数千条高质量数据。 {messages: [{role: system, content: 你是一个严谨的前端代码审查助手专门审查TypeScript和React代码。你的回复必须直接指出问题并提供具体的修改代码。}, {role: user, content: 审查这段代码\ntypescript\nfunction Component({ data }: any) {\n return div{data.name}/div;\n}\n}, {role: assistant, content: **问题**\n1. 未定义组件Props类型使用any导致类型安全丢失。\n\n**建议修改为**\ntypescript\ninterface ComponentProps {\n data: { name: string };\n}\n\nfunction Component({ data }: ComponentProps) {\n return div{data.name}/div;\n}\n}]} {messages: [{role: system, content: 你是一个严谨的前端代码审查助手专门审查TypeScript和React代码。你的回复必须直接指出问题并提供具体的修改代码。}, {role: user, content: 审查这段代码\ntypescript\nuseEffect(() {\n fetch(/api/data).then(res res.json()).then(setData);\n}, []);\n}, {role: assistant, content: **问题**\n1. 未处理fetch可能发生的错误导致应用静默失败。\n\n**建议修改为**\ntypescript\nuseEffect(() {\n fetch(/api/data)\n .then(res {\n if (!res.ok) throw new Error(HTTP error! status: ${res.status});\n return res.json();\n })\n .then(setData)\n .catch(error console.error(Fetch failed:, error));\n}, []);\n}]}数据准备的核心原则高质量指令清晰回答准确、有用。一致性所有样本遵循相同的任务格式和风格。多样性覆盖任务可能的各种输入情况。数量通常需要几百到几千条。OpenAI的gpt-3.5-turbo微调可能从50-100条高质量数据开始就能看到效果。6.3 使用OpenAI API进行微调命令行示例前端同学可以将此视为一个“构建步骤”通常由后端或算法同事完成但了解流程至关重要。# 1. 安装OpenAI CLI (如果尚未安装) # pip install --upgrade openai # 2. 设置API密钥 export OPENAI_API_KEYyour-key-here # 3. 上传训练文件 openai files create \ -f fine-tuning-data.jsonl \ -p fine-tune # 命令会返回一个文件ID如 file-abc123 # 4. 创建微调任务 openai fine_tuning.jobs create \ -t file-abc123 \ -m gpt-3.5-turbo-1106 \ # 选择基础模型 --suffix frontend-code-reviewer # 给模型起个后缀名 # 5. 查看任务状态 openai fine_tuning.jobs list # 或跟踪特定任务 openai fine_tuning.jobs retrieve -i ftjob-xyz789 # 6. 任务完成后你会得到一个新的模型名如 ft:gpt-3.5-turbo-1106:your-org:frontend-code-reviewer:abc123 # 7. 像使用普通模型一样使用它在LangChain.js中使用微调后的模型import { ChatOpenAI } from langchain/openai; const fineTunedModel new ChatOpenAI({ modelName: ft:gpt-3.5-turbo-1106:your-org:frontend-code-reviewer:abc123, // 你的微调模型名 temperature: 0.1, }); // 后续使用方式与普通模型完全一致7. 常见问题与排查思路在学习和实践过程中你一定会遇到各种问题。下表列出了典型问题及解决方案问题现象可能原因排查方式解决方案调用API超时或无响应网络问题API密钥错误或额度不足模型服务区域限制。1. 检查网络连接。2. 在平台控制台检查API密钥状态和余额。3. 查看SDK错误信息。1. 使用稳定的网络环境。2. 更换或充值API密钥。3. 确认SDK中配置的baseURL或区域是否正确国内平台尤其注意。模型输出不符合预期胡言乱语temperature参数过高Prompt指令不清晰模型上下文混乱。1. 检查temperature值尝试调低如0.2。2. 逐行检查Prompt确保指令明确格式要求严格。3. 检查是否在对话中混入了无关消息。1. 对确定性任务使用低temperature。2. 使用结构化Prompt模板加入“请严格按照以下格式输出”等强约束。3. 管理好对话历史及时清理或总结过长上下文。Agent陷入循环或调用错误工具工具描述不清晰Agent类型选择不当模型能力有限。1. 查看verbosetrue的日志看Agent的思考过程。2. 检查每个Tool的name和description是否准确描述了其功能。1. 优化Tool的描述使其精准、无歧义。2. 尝试不同的Agent类型如Plan-and-Execute。3. 在Prompt中明确限制Agent的步骤次数。RAG返回无关内容文本分块不合理检索的k值不合适嵌入模型不匹配。1. 检查检索到的文本块是否与问题相关。2. 调整分块大小chunkSize和重叠chunkOverlap。3. 尝试不同的k值如2, 5, 10。1. 优化分块策略尝试按段落、标题或句子分割。2. 使用更先进的检索方法如Multi-Query Retriever或Contextual Compression。3. 确保使用的嵌入模型与任务语言匹配。Token消耗过快成本高输入上下文过长Prompt冗余RAG返回块过多。1. 计算输入文本的token数可用tiktoken库。2. 审查Prompt删除不必要的描述。3. 检查RAG检索的块数量和大小。1. 对长文本进行摘要后再输入。2. 精简Prompt使用更高效的指令。3. 减少RAG的k值或对检索到的块进行二次压缩。TypeScript类型报错LangChain版本更新导致API变化类型定义不完整。1. 查看官方文档和迁移指南。2. 检查types包是否安装。1. 锁定稳定的依赖版本。2. 使用as any临时绕过并关注社区issue。3. 为自定义Tool和组件编写明确的类型接口。8. 最佳实践与工程化建议将AI能力集成到前端工程中需要遵循软件工程的最佳实践。环境隔离与密钥管理永远不要在客户端代码中硬编码API密钥。所有模型调用应通过你自己的后端代理服务进行。使用环境变量管理不同环境开发、测试、生产的密钥和配置。// 后端服务中 import { Configuration, OpenAIApi } from openai; const configuration new Configuration({ apiKey: process.env.OPENAI_API_KEY_SECRET, // 从安全的环境变量读取 }); const openai new OpenAIApi(configuration);限流、重试与降级对模型API调用实施限流防止意外流量导致巨额账单。实现指数退避重试机制处理网络抖动或服务暂时不可用。设计降级方案例如当AI服务不可用时返回静态提示或切换至更简单的规则引擎。日志与监控记录所有Prompt、Completion、Token使用量和耗时。这对调试、优化成本和理解用户需求至关重要。监控AI服务的错误率和延迟设置告警。Prompt版本化管理将Prompt模板视为代码。使用配置文件、数据库或专门的Prompt管理工具来存储和管理它们并实现版本控制。前端用户体验优化流式输出使用Server-Sent Events (SSE) 或 WebSocket 实现打字机效果提升响应感。中间状态清晰展示“思考中”、“调用工具中”、“生成中”等状态。错误友好将模型或网络的错误信息转化为用户能理解的提示。安全过滤对模型的输出进行内容安全过滤防止生成不当内容。9. 总结从前端到AI应用开发者的路径回顾这7天的路线你的学习曲线应该是从使用Prompt到编排Agent再到增强RAG最后到定制微调。这条路径让你始终站在应用层用工程化的思维解决问题而不是陷入理论的深渊。你的核心竞争力不再是单一的框架使用而是AI Native 的交互设计能力理解大模型的特性设计出能弥补其不确定性的优秀用户体验。复杂智能工作流的架构能力将业务需求拆解为可由Agent、Tools、RAG协同完成的自动化流程。工程化与集成的能力将AI能力安全、稳定、高效地集成到现有产品体系中。下一步行动建议动手做一个项目从你工作中找一个重复性高、规则模糊的任务如根据需求生成UI组件草图、自动化编写Jest测试用例、分析用户反馈并分类尝试用LangChain实现一个原型。深入一个方向对RAG感兴趣就深入研究向量数据库优化和高级检索技术对Agent感兴趣就学习工作流引擎如LangGraph来构建更复杂的多Agent系统。关注生态AI前端生态在飞速发展关注Vercel AI SDK、LangChain.js、OpenAI等核心库的更新以及Next.js等框架对AI的原生支持。前端领域远未“已死”它正在与AI深度融合进化出更强大的形态。转型不是抛弃过去而是用你已有的利剑去开拓一个更广阔的疆域。现在就从运行本文的第一个示例代码开始吧。