news 2026/10/23 1:54:00

从0开始做AI

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从0开始做AI

如果把电脑当成一个 “需要交流的伙伴”,你会发现它的 “感官” 很特别:键盘就是它的耳朵—— 我们敲进去的每一个字、每一串指令,都是在跟它 “说话”;屏幕就是它的嘴—— 它弹出的文字、图片、视频,都是在给我们 “回应”。​

可早期跟这个 “伙伴” 聊天,简直像在 “鸡同鸭讲”。人们最初对它的期待其实很简单:不用学复杂的代码,能像跟人说话一样跟它沟通,比如敲一句 “帮我算下这个月的账单”,它就能在屏幕上给出清晰的结果;或者输入 “找几首安静的歌”,它就不会乱播重金属。更进一步,人们还希望它能 “读懂上下文”—— 比如先问 “今天天气怎么样”,再问 “那适合去公园吗”,它能知道 “那” 指的是 “今天的天气”。​

这时候不妨想想:如果让你写一个AI程序,让它能读懂你的意思并给你回复,你会怎么写?天才的你可能很快开发出AI的核心代码:

Scannerscanner=newScanner(System.in);while(true){System.out.println(scanner.nextLine().replace("?","。").replace("吗",""));}

在电脑上运行,好像很快就要成功了,你非常欣喜。

但继续测试,发现这样其实并不够很好的回答所有的问题。

于是你继续发动天才的头脑。你可能会先列规则:比如看到 “天气” 就关联 “温度、是否下雨”,看到 “账单” 就关联 “收入、支出、加减计算”。

Scannerscanner=newScanner(System.in);while(true){StringuserInput=scanner.nextLine().replace("?","。").replace("吗","");userInput=userInput.replace("天气","");userInput=userInput.replace("我","你");if(userInput.equals("exit")){break;}System.out.println(userInput);}

可很快就会发现问题 —— 人说话的方式太多了:“今天外面湿漉漉的” 和 “刚下过雨” 是一个意思,但程序没见过 “湿漉漉” 这个词,就会卡住;更别说 “那适合去公园吗” 里的 “那”,要靠前面的 “天气” 才能理解,规则根本列不完。

原来,电脑的 “耳朵” 只能接收到孤立的字符,“嘴” 也只会机械输出预设内容。比如你敲 “今天下雨,记得带伞”,它能显示这句话,却看不出 “下雨” 和 “带伞” 之间的关联;你要是把句子改成 “带伞今天下雨”,它更分辨不出顺序变了,意思也变了 —— 它不懂 “序列”,不懂 “先后关系”,就像一个只能逐字念稿、却看不懂文章逻辑的人。

为此,你困扰了很久,一度觉得这就是一个开玩笑的AI,根本没可能真正理解人的意思。

在后续的学习过程中你发现,前代大佬们先造了 “神经网络”(点击学习) 这个 “学习工具”。有了这个工具,你知道程序开始慢慢理解你的意思,而不是像鹦鹉一样只会说话却不知道说的是啥,你发现AI的实现好像更具有可行性了。

把它想成电脑的 “练习本”:我们不给它列死规则,而是通过自注意力机制和多层神经网络协作,让模型自己 “摸” 出规律。

就像教孩子说话时,我们不会一条条列“规则”,而是让他在听了成千上万句话后自己总结:“下雨”常和“湿”“伞”“躲”一起出现;“开心”后面往往跟着笑脸或欢呼。神经网络也是如此——给它喂足够多的文本,它会像拼图一样,默默记住哪些词经常“结伴出现”,哪些句子结构表达相似的意思。

比如你输入“今天天气闷热,可能要下雨”,传统规则可能只抓“下雨”两个字,但神经网络会注意到“闷热”和“下雨”的关联,甚至能联想到“出门带伞”这样的潜台词。这背后,是无数个“神经元”在协作:有的负责拆分句子结构,有的专注于词与词的距离,还有的在比对过去见过的类似表达。

你开始尝试用更智能的方式实现这个AI。不再是硬编码替换词,而是引入简单的词向量模型——把每个词变成一串数字,让“下雨”和“潮湿”的数字串更接近,“开心”和“难过”的数字串差异大。

你先设计了一下思路:

  1. 当用户输入文本时,系统会先进行预处理
  2. 然后尝试从输入中提取关键词,对于未知词会通过词向量相似度找到最接近的已知词
  3. 如果找到匹配的关键词,就使用预设的回应规则生成回答
  4. 如果没有直接匹配,会尝试结合上下文信息生成回应
  5. 如果都无法匹配,则返回默认回答

于是敲出了如下代码:

importjava.util.HashMap;importjava.util.Map;importjava.util.Scanner;publicclassSimpleAIDialogue{// 词向量映射表,模拟词向量模型privatestaticMap<String,double[]>wordVectors=newHashMap<>();// 预设的回应规则privatestaticMap<String,String>responseRules=newHashMap<>();// 上下文信息,用于理解指代关系privatestaticStringcontext="";publicstaticvoidmain(String[]args){// 初始化词向量initWordVectors();// 初始化回应规则initResponseRules();System.out.println("简单AI对话系统(输入exit退出)");System.out.println("你可以问我一些天气相关的问题哦~");Scannerscanner=newScanner(System.in);while(true){System.out.print("你: ");StringuserInput=scanner.nextLine();if(userInput.equalsIgnoreCase("exit")){System.out.println("AI: 再见!");break;}// 处理用户输入并生成回应Stringresponse=generateResponse(userInput);System.out.println("AI: "+response);}scanner.close();}// 初始化词向量 - 实际应用中这通常由模型训练得到privatestaticvoidinitWordVectors(){// 天气相关词汇wordVectors.put("天气",newdouble[]{0.9,0.8,0.7,0.1});wordVectors.put("下雨",newdouble[]{0.8,0.7,0.6,0.9});wordVectors.put("雨",newdouble[]{0.85,0.75,0.65,0.85});wordVectors.put("晴天",newdouble[]{0.7,0.8,0.9,0.2});wordVectors.put("太阳",newdouble[]{0.6,0.9,0.8,0.1});wordVectors.put("多云",newdouble[]{0.8,0.7,0.8,0.3});wordVectors.put("阴天",newdouble[]{0.75,0.6,0.6,0.4});wordVectors.put("潮湿",newdouble[]{0.7,0.6,0.5,0.8});wordVectors.put("闷热",newdouble[]{0.6,0.9,0.5,0.7});wordVectors.put("温度",newdouble[]{0.85,0.85,0.7,0.2});wordVectors.put("冷",newdouble[]{0.7,0.3,0.3,0.4});wordVectors.put("热",newdouble[]{0.6,0.95,0.5,0.3});// 活动相关词汇wordVectors.put("公园",newdouble[]{0.2,0.3,0.8,0.1});wordVectors.put("散步",newdouble[]{0.1,0.2,0.7,0.2});wordVectors.put("跑步",newdouble[]{0.1,0.3,0.75,0.25});wordVectors.put("外出",newdouble[]{0.3,0.4,0.8,0.3});wordVectors.put("带伞",newdouble[]{0.4,0.3,0.2,0.95});wordVectors.put("外套",newdouble[]{0.5,0.2,0.1,0.5});}// 初始化回应规则privatestaticvoidinitResponseRules(){responseRules.put("天气","今天天气看起来不错呢!");responseRules.put("下雨","下雨了,出门记得带伞哦~");responseRules.put("晴天","真是个晴天,适合外出活动!");responseRules.put("公园","公园是个好地方,天气好的时候很适合去。");responseRules.put("带伞","是的,最好带上伞,以防万一。");responseRules.put("温度","今天温度适中,很舒服。");}// 生成回应privatestaticStringgenerateResponse(Stringinput){// 预处理输入StringprocessedInput=preprocessInput(input);// 更新上下文updateContext(processedInput);// 提取关键词String[]words=processedInput.split(" ");StringkeyWord=findMostRelevantWord(words);// 如果找到相关关键词,使用对应的回应if(keyWord!=null&&responseRules.containsKey(keyWord)){returnresponseRules.get(keyWord);}// 尝试结合上下文理解if(!context.isEmpty()){StringcontextKey=findMostRelevantWord(context.split(" "));if(contextKey!=null){return"根据"+contextKey+"的情况,我觉得"+getGeneralResponse(contextKey)+"";}}// 如果都无法匹配,返回默认回应return"我不太明白你的意思,可以换个说法吗?";}// 预处理输入:去除标点,转换为小写,分割词语privatestaticStringpreprocessInput(Stringinput){returninput.replaceAll("[^a-zA-Z0-9\u4e00-\u9fa5]"," ").toLowerCase().replaceAll("\\s+"," ");}// 更新上下文信息privatestaticvoidupdateContext(Stringinput){// 简单处理:保留最后一句话作为上下文context=input;}// 找到与已知词向量最相关的词privatestaticStringfindMostRelevantWord(String[]words){StringmostRelevant=null;doublehighestSimilarity=0;// 计算每个词与所有已知词向量的相似度for(Stringword:words){if(wordVectors.containsKey(word)){// 如果是已知词,直接作为候选if(mostRelevant==null){mostRelevant=word;}continue;}// 对于未知词,尝试找到最相似的已知词for(Map.Entry<String,double[]>entry:wordVectors.entrySet()){double[]vector=createWordVector(word);// 为未知词创建简单向量doublesim=similarity(vector,entry.getValue());if(sim>highestSimilarity&&sim>0.5){// 设置相似度阈值highestSimilarity=sim;mostRelevant=entry.getKey();}}}returnmostRelevant;}// 为未知词创建简单向量(实际应用中这通常由模型处理)privatestaticdouble[]createWordVector(Stringword){// 这里使用简单的哈希方法生成向量,实际中会更复杂double[]vector=newdouble[4];for(charc:word.toCharArray()){vector[0]+=c%100/100.0;vector[1]+=(c%10)/10.0;vector[2]+=(c%5)/5.0;vector[3]+=(c%3)/3.0;}for(inti=0;i<vector.length;i++){vector[i]=vector[i]/word.length();}returnvector;}// 计算两个向量的余弦相似度privatestaticdoublesimilarity(double[]a,double[]b){if(a.length!=b.length){return0;}doubledotProduct=0;doublenormA=0;doublenormB=0;for(inti=0;i<a.length;i++){dotProduct+=a[i]*b[i];normA+=a[i]*a[i];normB+=b[i]*b[i];}if(normA==0||normB==0){return0;}returndotProduct/(Math.sqrt(normA)*Math.sqrt(normB));}// 获取通用回应privatestaticStringgetGeneralResponse(Stringkey){if(key.contains("雨")||key.equals("潮湿")){return"最好带上雨具";}elseif(key.equals("晴天")||key.equals("太阳")){return"很适合户外活动";}elseif(key.equals("冷")){return"需要穿厚一点";}elseif(key.equals("热")){return"要注意防暑降温";}else{return"一切都很顺利";}}}

当用户输入“今天很潮湿”,程序会算出“潮湿”和“下雨”的相似度很高,进而推测用户可能在暗示天气相关的需求。这虽然简陋,却迈出了“理解”的第一步——电脑不再只认死字,开始能捕捉词语间的“隐形联系”。

试了几次之后发现,到这里已经有点意思了,翻看NLP的相关技术,发现了这个程序已经涉及到了NLP的多个核心技术:

  1. 词向量(Word Vectors)
  • 概念:词向量是将自然语言中的词语转换为数值向量的技术,目的是让计算机能够"理解"词语的语义。向量的数值分布反映了词语的含义和上下文关系。
  • 代码中的体现:
    代码通过wordVectors字典手动定义了词语的向量(如"天气" -> [0.9, 0.8, 0.7, 0.1]),模拟了真实NLP中通过模型训练得到的词向量(如Word2Vec、GloVe等)。
  • 核心思想:语义相近的词,其向量在高维空间中的距离更近。例如代码中"下雨"和"雨"的向量结构相似,体现了它们的语义关联。
  1. 文本预处理(Text Preprocessing)
  • 概念:对原始文本进行清洗和标准化,以便后续处理。常见操作包括去除噪声(如标点)、大小写转换、分词等。
  • 代码中的体现:
    preprocessInput()方法通过正则表达式去除标点符号、转为小写、合并空格,模拟了真实NLP中的文本清洗流程。
  • 作用:减少无关信息干扰,统一文本格式,让模型更专注于有意义的内容。
  1. 语义相似度计算(Semantic Similarity)
  • 概念:通过数学方法衡量两个词语或文本在语义上的关联程度,常用方法包括余弦相似度、欧氏距离等。
  • 代码中的体现:
    similarity()方法实现了余弦相似度计算:通过计算两个向量的夹角余弦值(范围[-1,1]),值越接近1表示语义越相似。例如代码中"雨"和"下雨"的向量余弦相似度会很高。
  • 应用场景:在真实NLP中用于同义词识别、文本聚类、检索等(如搜索引擎中"电脑"和"计算机"的匹配)。
  1. 关键词提取(Keyword Extraction)
  • 概念:从文本中识别出最能代表语义核心的词语,是理解用户意图的基础。
  • 代码中的体现:
    findMostRelevantWord()方法通过对比输入词与预设词向量的相似度,找出最相关的关键词(如用户输入"今天会下雨吗",会提取出"下雨"作为关键词)。
  • 核心作用:简化输入信息,聚焦关键语义,为后续生成回应提供依据。
  1. 上下文理解(Context Understanding)
  • 概念:结合对话历史(上下文)理解当前输入的含义,解决指代关系(如"它"、“那里”)和语义依赖问题。
  • 代码中的体现:
    通过context变量保存上一轮对话内容,当当前输入无法直接匹配时,会结合上下文关键词生成回应(如用户先问"天气如何",再问"需要带伞吗",系统会关联"天气"上下文)。
  • 局限与扩展:代码仅保存了最后一句上下文,真实NLP系统(如对话机器人)会通过更复杂的上下文状态跟踪(如RNN、Transformer)处理多轮对话。
  1. 规则引擎(Rule-Based Response Generation)
  • 概念:基于预设规则生成回应,是早期对话系统的主流实现方式。
  • 代码中的体现:
    responseRules字典定义了关键词与回应的映射(如"晴天"对应"适合外出活动"),generateResponse()方法根据提取的关键词匹配规则生成回答。
  • 特点:实现简单、响应快速,但灵活性差(无法处理未预设的情况),真实系统常结合机器学习模型(如Seq2Seq)增强泛化能力。
  1. 未知词处理(OOV, Out-of-Vocabulary)
  • 概念:处理词汇表中未包含的词(未知词),避免系统因遇到新词而失效。
  • 代码中的体现:
    createWordVector()方法为未知词生成临时向量(通过字符哈希计算),再与已知词向量比较相似度,实现对新词的"猜测"(如用户输入"阵雨",系统可能通过向量相似度识别为与"雨"相关)。
  • 真实场景:实际NLP中会通过子词模型(如BPE)、字符级嵌入等更 robust 的方法处理未知词。

这些技术点共同构成了一个简化的NLP pipeline(流水线):文本输入→预处理→语义解析(关键词+相似度)→结合上下文→生成回应,虽然实现简单,但完整模拟了真实对话系统的核心逻辑。

但真正的突破,来自“上下文”的理解。就像人听到“他昨天淋了雨,今天感冒了”,会自然把“他”“昨天”“今天”串联起来,神经网络通过“自注意力机制”做到了类似的事:给句子里的每个词“贴标签”,标记它和其他词的关系。

比如处理“天气很好,适合去公园吗?”,模型会重点关注“天气”和“公园”的关联,而不是孤立看待每个词。当你接着问“那需要带外套吗?”,它能通过之前的“天气很好”推断“那”指的是当前天气,进而判断“不需要带外套”。

这时候再回头看最初的代码,会发现思路已经彻底不同:从“告诉电脑该怎么做”,变成了“让电脑自己学怎么做”。你不再需要枚举“湿漉漉=下雨”“闷热=可能下雨”这样的规则,只需给模型足够的文本数据,它会像侦探一样,从海量信息中挖出人类语言的“潜规则”。

当然,这并不意味着AI真的“懂”了——它更像一个超级厉害的“模仿大师”,通过统计规律猜出最可能的回应。但正是这种“猜”的能力,让电脑的“耳朵”越来越灵,“嘴”越来越会说,从最初的“鸡同鸭讲”,慢慢变成了能聊几句的“伙伴”。

接下来,你或许会好奇:这些“神经元”具体是怎么协作的?模型是如何从“认识词”到“理解句子”的?其实,这背后藏着更多精妙的设计,比如Transformer架构的层层处理、大规模预训练的奥秘……(未完待续)

ps:
文章内容很长,大概还要持续更新一段时间。有兴趣的小伙伴可以参阅大模型系列学习内容Transformer全景解析

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 1:53:54

无名杀网页版:5分钟免费安装并开玩完整三国杀

无名杀网页版&#xff1a;5分钟免费安装并开玩完整三国杀 【免费下载链接】noname 项目地址: https://gitcode.com/GitHub_Trending/no/noname 无名杀是一个开源免费的在线三国杀网页版游戏&#xff0c;内置数百名三国武将与完整卡牌体系&#xff0c;打开浏览器即可开局…

作者头像 李华
网站建设 2026/10/23 1:53:39

旧平衡车刷 FOC 固件:完整刷机与调参指南

旧平衡车刷 FOC 固件&#xff1a;完整刷机与调参指南 【免费下载链接】hoverboard-firmware-hack-FOC With Field Oriented Control (FOC) 项目地址: https://gitcode.com/GitHub_Trending/ho/hoverboard-firmware-hack-FOC 车库角落那台吃灰的平衡车&#xff0c;上次启…

作者头像 李华
网站建设 2026/10/23 1:53:06

GTweak 使用指南:Windows 去臃肿三步搞定

GTweak 使用指南&#xff1a;Windows 去臃肿三步搞定 【免费下载链接】GTweak Portable Tool for an Ideal Windows Setup 项目地址: https://gitcode.com/GitHub_Trending/gt/GTweak 重装完 Windows 的头几天&#xff0c;系统通常最好用&#xff1a;后台进程少&#xf…

作者头像 李华
网站建设 2026/10/23 1:53:02

第三章 其他行业创新应用:大模型重构产业核心价值链路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华